From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Samsuik <40902469+Samsuik@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:36:19 +0100 Subject: [PATCH] Optimise Fast Movement diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index a0dc1fa70590d7fc0d88f83094a6ec2c98e748e8..e14717a39b8adb4ea4aff66c35724cea67ef14ba 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -1276,6 +1276,95 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } // Paper end - detailed watchdog information + // Sakura start - stripped back movement method for basic entities + public void moveBasic(MoverType movementType, Vec3 movement) { + io.papermc.paper.util.TickThread.ensureTickThread("Cannot move an entity off-main"); + + if (this.noPhysics) { + this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); + } else { + if (movementType == MoverType.PISTON) { // Paper + movement = this.limitPistonMovement(movement); + if (movement.equals(Vec3.ZERO)) { + return; + } + } + + this.level().getProfiler().push("move"); + if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7D) { + movement = movement.multiply(this.stuckSpeedMultiplier); + this.stuckSpeedMultiplier = Vec3.ZERO; + this.setDeltaMovement(Vec3.ZERO); + } + + // collideScan for optimised large movements + Vec3 vec3d1 = this.collideScan(movement); + double d0 = vec3d1.lengthSqr(); + + if (d0 > 1.0E-7D) { + // NOTE: if there are any blocks in the future that rely on fall distance make sure this is correct. + // The only block I am aware of is powdered snow that has a special case for falling blocks. + if (this.fallDistance != 0.0F && d0 >= 1.0D && !isFallingBlock) { + BlockHitResult movingobjectpositionblock = this.level().clip(new ClipContext(this.position(), this.position().add(vec3d1), ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this)); + + if (movingobjectpositionblock.getType() != HitResult.Type.MISS) { + this.resetFallDistance(); + } + } + + this.setPos(this.getX() + vec3d1.x, this.getY() + vec3d1.y, this.getZ() + vec3d1.z); + } + + this.level().getProfiler().pop(); + this.level().getProfiler().push("rest"); + boolean flag = !Mth.equal(movement.x, vec3d1.x); + boolean flag1 = !Mth.equal(movement.z, vec3d1.z); + + this.horizontalCollision = flag || flag1; + this.verticalCollision = movement.y != vec3d1.y; + this.verticalCollisionBelow = this.verticalCollision && movement.y < 0.0D; + if (this.horizontalCollision) { + this.minorHorizontalCollision = this.isHorizontalCollisionMinor(vec3d1); + } else { + this.minorHorizontalCollision = false; + } + + this.setOnGroundWithKnownMovement(this.verticalCollisionBelow, vec3d1); + BlockPos blockposition = this.getOnPosLegacy(); + BlockState iblockdata = this.level().getBlockState(blockposition); + + this.checkFallDamage(vec3d1.y, this.onGround(), iblockdata, blockposition); + if (this.isRemoved()) { + this.level().getProfiler().pop(); + } else { + if (this.horizontalCollision) { + Vec3 vec3d2 = this.getDeltaMovement(); + + this.setDeltaMovement(flag ? 0.0D : vec3d2.x, vec3d2.y, flag1 ? 0.0D : vec3d2.z); + } + + Block block = iblockdata.getBlock(); + + if (movement.y != vec3d1.y) { + block.updateEntityAfterFallOn(this.level(), this); + } + + if (this.onGround()) { + // used for slowing down entities on top of slime + block.stepOn(this.level(), blockposition, iblockdata, this); + } + + this.tryCheckInsideBlocks(); + + float f = this.getBlockSpeedFactor(); + + this.multiplyDeltaMovement((double) f, 1.0D, (double) f); // Sakura - reduce movement allocations + this.level().getProfiler().pop(); + } + } + } + // Sakura end + public void move(MoverType movementType, Vec3 movement) { final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity // Paper start - detailed watchdog information @@ -1654,6 +1743,95 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return offsetFactor; } + // Sakura start + private Vec3 collideScan(Vec3 movement) { + if (movement.x == 0.0 && movement.y == 0.0 && movement.z == 0.0) { + return movement; + } + + final boolean scan = movement.lengthSqr() >= 12.0; + final List potentialCollisionsBB = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(4); + final List potentialCollisionsVoxel = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(1); + final AABB currBoundingBox = getBoundingBox(); + + if (scan) { + return scanAndCollide(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB); + } else { + final AABB bb = currBoundingBox.expandTowards(movement.x, movement.y, movement.z); + collectCollisions(bb, potentialCollisionsVoxel, potentialCollisionsBB); + return io.papermc.paper.util.CollisionUtil.performCollisions(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB); + } + } + + private Vec3 scanAndCollide(Vec3 movement, AABB currBoundingBox, List voxelList, List bbList) { + double x = movement.x; + double y = movement.y; + double z = movement.z; + + final boolean xSmaller = Math.abs(x) < Math.abs(z); + + if (y != 0.0) { + y = scanY(currBoundingBox, y, voxelList, bbList); + + if (y != 0.0) { + currBoundingBox = io.papermc.paper.util.CollisionUtil.offsetY(currBoundingBox, y); + } + } + + if (xSmaller && z != 0.0) { + z = scanZ(currBoundingBox, z, voxelList, bbList); + + if (z != 0.0) { + currBoundingBox = io.papermc.paper.util.CollisionUtil.offsetZ(currBoundingBox, z); + } + } + + if (x != 0.0) { + x = scanX(currBoundingBox, x, voxelList, bbList); + + if (x != 0.0) { + currBoundingBox = io.papermc.paper.util.CollisionUtil.offsetX(currBoundingBox, x); + } + } + + if (!xSmaller && z != 0.0) { + z = scanZ(currBoundingBox, z, voxelList, bbList); + } + + return new Vec3(x, y, z); + } + + private void collectCollisions(AABB collisionBox, List voxelList, List bbList) { + // Copied from the collide method below + io.papermc.paper.util.CollisionUtil.getCollisions( + level, this, collisionBox, voxelList, bbList, + io.papermc.paper.util.CollisionUtil.COLLISION_FLAG_CHECK_BORDER | this.getExtraCollisionFlags(), // Sakura + null, null + ); + } + + private double scanX(AABB currBoundingBox, double x, List voxelList, List bbList) { + AABB scanBox = currBoundingBox.expandTowards(x, 0.0, 0.0); + collectCollisions(scanBox, voxelList, bbList); + x = io.papermc.paper.util.CollisionUtil.performAABBCollisionsX(currBoundingBox, x, bbList); + return io.papermc.paper.util.CollisionUtil.performVoxelCollisionsX(currBoundingBox, x, voxelList); + } + + private double scanY(AABB currBoundingBox, double y, List voxelList, List bbList) { + AABB scanBox = currBoundingBox.expandTowards(0.0, y, 0.0); + collectCollisions(scanBox, voxelList, bbList); + y = io.papermc.paper.util.CollisionUtil.performAABBCollisionsY(currBoundingBox, y, bbList); + return io.papermc.paper.util.CollisionUtil.performVoxelCollisionsY(currBoundingBox, y, voxelList); + } + + private double scanZ(AABB currBoundingBox, double z, List voxelList, List bbList) { + AABB scanBox = currBoundingBox.expandTowards(0.0, 0.0, z); + collectCollisions(scanBox, voxelList, bbList); + z = io.papermc.paper.util.CollisionUtil.performAABBCollisionsZ(currBoundingBox, z, bbList); + return io.papermc.paper.util.CollisionUtil.performVoxelCollisionsZ(currBoundingBox, z, voxelList); + } + // Sakura end + private Vec3 collide(Vec3 movement) { // Paper start - optimise collisions final boolean xZero = movement.x == 0.0; diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java index cdb903035dfe238ee336a76863c0ebfc78286a43..abe1f43f77a11e41c576bad8dad2ff62b5b087e6 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -201,7 +201,7 @@ public class FallingBlockEntity extends Entity { ++this.time; this.applyGravity(); - this.move(MoverType.SELF, this.getDeltaMovement()); + this.moveBasic(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise simple entity movement // Paper start - Configurable falling blocks height nerf if (this.level().paperConfig().fixes.fallingBlockHeightNerf.test(v -> this.getY() > v)) { if (this.dropItem && this.level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java index 6cfa54da058939003576025cb0512e0bcc3e715b..d3073a058e4d200b0146d7b72ef3cd56a6a1d8d8 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java @@ -96,7 +96,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { public void tick() { if (this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().spigotConfig.currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot this.applyGravity(); - this.move(MoverType.SELF, this.getDeltaMovement()); + this.moveBasic(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise simple entity movement // Paper start - Configurable TNT height nerf if (this.level().paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) { this.discard(EntityRemoveEvent.Cause.OUT_OF_WORLD);