From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Samsuik <40902469+Samsuik@users.noreply.github.com> Date: Tue, 21 Nov 2023 17:03:08 +0000 Subject: [PATCH] Configure cannon physics by version diff --git a/src/main/java/io/papermc/paper/util/CollisionUtil.java b/src/main/java/io/papermc/paper/util/CollisionUtil.java index 57ca8212991d0660dd41b70350f59830d4fd09f3..39085c2a356f575f0ef6acaa3de7d9ff560b5a87 100644 --- a/src/main/java/io/papermc/paper/util/CollisionUtil.java +++ b/src/main/java/io/papermc/paper/util/CollisionUtil.java @@ -1495,6 +1495,14 @@ public final class CollisionUtil { public static Vec3 performCollisions(final Vec3 moveVector, AABB axisalignedbb, final List voxels, final List aabbs) { + // Sakura start + return performCollisions(moveVector, axisalignedbb, voxels, aabbs, null); + } + public static Vec3 performCollisions(final Vec3 moveVector, AABB axisalignedbb, + final List voxels, + final List aabbs, + final me.samsuik.sakura.physics.PhysicsVersion physics) { + // Sakura end if (voxels.isEmpty()) { // fast track only AABBs return performAABBCollisions(moveVector, axisalignedbb, aabbs); @@ -1512,7 +1520,10 @@ public final class CollisionUtil { } } - final boolean xSmaller = Math.abs(x) < Math.abs(z); + // Sakura start - physics version api + final boolean xSmaller = physics == null || physics.afterOrEqual(1_14_0) ? Math.abs(x) < Math.abs(z) + : physics.is(1_7_0) && Math.abs(x) > Math.abs(z); + // Sakura end if (xSmaller && z != 0.0) { z = performAABBCollisionsZ(axisalignedbb, z, aabbs); diff --git a/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java b/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java index b87748ae90863abe8f85dcbdc5a202cb3c9e2037..a291516ec7bdb9d8b840f41ca52e6bbaf8e2e08a 100644 --- a/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java +++ b/src/main/java/me/samsuik/sakura/explosion/SakuraExplosion.java @@ -163,7 +163,7 @@ public class SakuraExplosion extends Explosion { // update explosion position x = source.getX(); - y = source.getY(0.0625D); + y = physics.before(1_10_0) ? source.getY() + (double) 0.49f : source.getY(0.0625D); z = source.getZ(); } @@ -256,10 +256,17 @@ public class SakuraExplosion extends Explosion { if (distanceFromBottom > 1.0) continue; double x = entity.getX() - pos.x; - double y = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - pos.y; + double y = entity.getEyeY() - pos.y; // Sakura - remove tnt special case double z = entity.getZ() - pos.z; double distance = Math.sqrt(x * x + y * y + z * z); + // Sakura start + if (this.physics.before(1_17_0)) { + distanceFromBottom = (float) distanceFromBottom; + distance = (float) distance; + } + // Sakura end + if (distance == 0.0D) continue; x /= distance; @@ -304,10 +311,17 @@ public class SakuraExplosion extends Explosion { if (distanceFromBottom <= 1.0) { double x = entity.getX() - pos.x; - double y = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - pos.y; + double y = entity.getEyeY() - pos.y; // Sakura - remove tnt special case double z = entity.getZ() - pos.z; double distance = Math.sqrt(x * x + y * y + z * z); + // Sakura start + if (this.physics.before(1_17_0)) { + distanceFromBottom = (float) distanceFromBottom; + distance = (float) distance; + } + // Sakura end + if (distance != 0.0D) { x /= distance; y /= distance; diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 4c55fe458378f2f376a8c31cec57e4751aa3d290..852276d9bedc51c3c8a28b60c85fdb23cf9cf818 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -378,7 +378,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S private final double[] pistonDeltas; private long pistonDeltasGameTime; private EntityDimensions dimensions; - private float eyeHeight; + protected float eyeHeight; // Sakura - physics version public boolean isInPowderSnow; public boolean wasInPowderSnow; public boolean wasOnFire; @@ -680,6 +680,13 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S } // Sakura end public boolean pushedByFluid = true; // Sakura + // Sakura start - physics version + protected me.samsuik.sakura.physics.PhysicsVersion physics = me.samsuik.sakura.physics.PhysicsVersion.LATEST; + + public me.samsuik.sakura.physics.PhysicsVersion physics() { + return this.physics; + } + // Sakura end public boolean isLegacyTrackingEntity = false; @@ -1162,7 +1169,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S } protected void checkSupportingBlock(boolean onGround, @Nullable Vec3 movement) { - if (onGround) { + if (onGround && this.physics.afterOrEqual(1_20_0)) { // Sakura - physics version AABB axisalignedbb = this.getBoundingBox(); AABB axisalignedbb1 = new AABB(axisalignedbb.minX, axisalignedbb.minY - 1.0E-6D, axisalignedbb.minZ, axisalignedbb.maxX, axisalignedbb.minY, axisalignedbb.maxZ); Optional optional = this.level.findSupportingBlock(this, axisalignedbb1); @@ -1224,7 +1231,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S if (this.noPhysics) { this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); } else { - if (movementType == MoverType.PISTON) { // Paper + if (movementType == MoverType.PISTON && this.physics.afterOrEqual(1_11_0)) { // Sakura - physics version api // Paper movement = this.limitPistonMovement(movement); if (movement.equals(Vec3.ZERO)) { return; @@ -1242,10 +1249,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S Vec3 vec3d1 = this.collideScan(movement); double d0 = vec3d1.lengthSqr(); - if (d0 > 1.0E-7D) { + if (d0 > 1.0E-7D || this.physics.before(1_14_0)) { // Sakura - physics version api // 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) { + if (this.fallDistance != 0.0F && d0 >= 1.0D && !isFallingBlock && this.physics.afterOrEqual(1_18_2)) { // Sakura - physics version api 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) { @@ -1281,6 +1288,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S if (this.horizontalCollision) { Vec3 vec3d2 = this.getDeltaMovement(); + // Sakura start - physics version api + if (flag && flag1 && this.physics.isWithin(1_14_0, 1_18_1)) { + flag = false; + } + // Sakura end + this.setDeltaMovement(flag ? 0.0D : vec3d2.x, vec3d2.y, flag1 ? 0.0D : vec3d2.z); } @@ -1321,7 +1334,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); } else { this.wasOnFire = this.isOnFire(); - if (movementType == MoverType.PISTON) { + if (movementType == MoverType.PISTON && this.physics.afterOrEqual(1_11_0)) { // Sakura - physics version api this.activatedTick = Math.max(this.activatedTick, MinecraftServer.currentTick + 20); // Paper this.activatedImmunityTick = Math.max(this.activatedImmunityTick, MinecraftServer.currentTick + 20); // Paper movement = this.limitPistonMovement(movement); @@ -1348,8 +1361,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S Vec3 vec3d1 = this.collide(movement); double d0 = vec3d1.lengthSqr(); - if (d0 > 1.0E-7D) { - if (this.fallDistance != 0.0F && d0 >= 1.0D) { + if (d0 > 1.0E-7D || this.physics.before(1_14_0)) { // Sakura - physics version api + if (this.fallDistance != 0.0F && d0 >= 1.0D && this.physics.afterOrEqual(1_18_2)) { // Sakura - physics version api 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) { @@ -1385,6 +1398,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S if (this.horizontalCollision) { Vec3 vec3d2 = this.getDeltaMovement(); + // Sakura start - physics version api + if (flag && flag1 && this.physics.isWithin(1_14_0, 1_18_1)) { + flag = false; + } + // Sakura end + this.setDeltaMovement(flag ? 0.0D : vec3d2.x, vec3d2.y, flag1 ? 0.0D : vec3d2.z); } @@ -1708,7 +1727,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S double y = movement.y; double z = movement.z; - final boolean xSmaller = Math.abs(x) < Math.abs(z); + // Sakura start - physics version api + final boolean xSmaller = this.physics == null || this.physics.afterOrEqual(1_14_0) ? Math.abs(x) < Math.abs(z) + : this.physics.is(1_7_0) && Math.abs(x) > Math.abs(z); + // Sakura end if (y != 0.0) { y = scanY(currBoundingBox, y, voxelList, bbList); @@ -1824,7 +1846,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S return movement; } - final Vec3 limitedMoveVector = io.papermc.paper.util.CollisionUtil.performCollisions(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB); + final Vec3 limitedMoveVector = io.papermc.paper.util.CollisionUtil.performCollisions(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB, this.physics); // Sakura - physics version api if (stepHeight > 0.0 && (onGround || (limitedMoveVector.y != movement.y && movement.y < 0.0)) @@ -1940,8 +1962,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S protected void checkInsideBlocks() { AABB axisalignedbb = this.getBoundingBox(); - BlockPos blockposition = BlockPos.containing(axisalignedbb.minX + 1.0E-7D, axisalignedbb.minY + 1.0E-7D, axisalignedbb.minZ + 1.0E-7D); - BlockPos blockposition1 = BlockPos.containing(axisalignedbb.maxX - 1.0E-7D, axisalignedbb.maxY - 1.0E-7D, axisalignedbb.maxZ - 1.0E-7D); + // Sakura start - physics version + double offset = this.physics.afterOrEqual(1_19_3) ? 1.0E-7D : 0.001D; + BlockPos blockposition = BlockPos.containing(axisalignedbb.minX + offset, axisalignedbb.minY + offset, axisalignedbb.minZ + offset); + BlockPos blockposition1 = BlockPos.containing(axisalignedbb.maxX - offset, axisalignedbb.maxY - offset, axisalignedbb.maxZ - offset); + // Sakura end if (this.level().hasChunksAt(blockposition, blockposition1)) { BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); 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 6274c005f4f53f3cec0c94b7d40cdb7070b190e0..586c957d33a4ffbdc584267e1f10c8e5b37d6b0a 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -89,6 +89,8 @@ public class FallingBlockEntity extends Entity { this.yo = y; this.zo = z; this.setStartPos(this.blockPosition()); + this.physics = world.localConfig().config(this.blockPosition()).physicsVersion; // Sakura + this.eyeHeight = this.physics.isLegacy() ? 0.49f : this.eyeHeight; // Sakura } public static FallingBlockEntity fall(Level world, BlockPos pos, BlockState state) { @@ -101,7 +103,11 @@ public class FallingBlockEntity extends Entity { FallingBlockEntity entityfallingblock = new FallingBlockEntity(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, iblockdata.hasProperty(BlockStateProperties.WATERLOGGED) ? (BlockState) iblockdata.setValue(BlockStateProperties.WATERLOGGED, false) : iblockdata); if (!CraftEventFactory.callEntityChangeBlockEvent(entityfallingblock, blockposition, iblockdata.getFluidState().createLegacyBlock())) return entityfallingblock; // CraftBukkit - world.setBlock(blockposition, iblockdata.getFluidState().createLegacyBlock(), 3); + // Sakura start - physics version api + if (entityfallingblock.physics.afterOrEqual(1_18_2)) { + world.setBlock(blockposition, iblockdata.getFluidState().createLegacyBlock(), 3); + } + // Sakura end world.addFreshEntity(entityfallingblock, spawnReason); // CraftBukkit return entityfallingblock; } @@ -188,7 +194,44 @@ public class FallingBlockEntity extends Entity { // Sakura start @Override public final double getEyeY() { - return heightParity ? getY() : super.getEyeY(); + return heightParity ? this.getY() : super.getEyeY(); + } + // Sakura end + // Sakura start - physics version api + @Override + public double distanceToSqr(Vec3 vector) { + if (!this.physics.isLegacy()) + return super.distanceToSqr(vector); + double x = this.getX() - vector.x; + double y = this.getEyeY() - vector.y; + double z = this.getZ() - vector.z; + return x * x + y * y + z * z; + } + + private BlockPos patchedBlockPosition() { + // mitigate the floating point issue for sand breaking below y-0 + // 1.0e-12 allows tech that uses indirect collision clipping to still function + return BlockPos.containing(this.getX(), this.getY() + 1.0e-12, this.getZ()); + } + + private boolean isAbleToStackOnBlock() { + BlockPos pos = BlockPos.containing(this.getX(), this.getY() - 0.001f, this.getZ()); + BlockState state = this.level().getBlockState(pos); + return !FallingBlock.isFree(state); + } + + private void removeBlockOnFall(Block block) { + BlockPos blockposition = this.blockPosition(); + BlockState blockstate = this.level().getBlockState(blockposition); + + if (blockstate.is(block) && CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, Blocks.AIR.defaultBlockState())) { + this.level().removeBlock(blockposition, false); + } else { + if (blockstate.is(block)) { + ((ServerLevel) level()).getChunkSource().blockChanged(blockposition); + } + this.discard(); + } } // Sakura end @@ -204,9 +247,16 @@ public class FallingBlockEntity extends Entity { } else { Block block = this.blockState.getBlock(); + // Sakura start - physics version api + if (this.time == 0 && this.physics.before(1_18_2)) { + this.removeBlockOnFall(block); + } + ++this.time; if (!this.isNoGravity()) { - this.addDeltaMovement(0.0D, -0.04D, 0.0D); // Sakura - reduce movement allocations + double gravity = this.physics.before(1_14_0) ? 0.04F : 0.04D; + this.addDeltaMovement(0.0D, -gravity, 0.0D); // Sakura - reduce movement allocations + // Sakura end } this.moveBasic(MoverType.SELF, this.getDeltaMovement()); // Sakura @@ -227,8 +277,16 @@ public class FallingBlockEntity extends Entity { return; } // Paper end + // Sakura start - physics version api + if (this.physics.before(1_12_0)) { + this.scaleDeltaMovement(0.98F); + } if (!this.level().isClientSide) { - BlockPos blockposition = this.blockPosition(); + // Patching the floating point issue on modern versions can break some cannons that rely on it. + // However, it makes sense for legacy versions pre-1.17 before the world height change. + BlockPos blockposition = this.physics.before(1_17_0) ? this.patchedBlockPosition() : this.blockPosition(); + // Sakura end + boolean flag = this.blockState.getBlock() instanceof ConcretePowderBlock; boolean flag1 = flag && this.level().getFluidState(blockposition).is(FluidTags.WATER); double d0 = this.getDeltaMovement().lengthSqr(); @@ -253,8 +311,11 @@ public class FallingBlockEntity extends Entity { } else { BlockState iblockdata = this.level().getBlockState(blockposition); - this.multiplyDeltaMovement(0.7D, -0.5D, 0.7D); // Sakura - reduce movement allocations - if (!iblockdata.is(Blocks.MOVING_PISTON)) { + // Sakura start - physics version api + double friction = this.physics.before(1_14_0) ? 0.7F : 0.7D; + this.multiplyDeltaMovement(friction, -0.5D, friction); // Sakura - reduce movement allocations + if (!iblockdata.is(Blocks.MOVING_PISTON) && (flag1 || !this.physics.isWithin(1_9_0, 1_12_0) || this.isAbleToStackOnBlock())) { + // Sakura end if (!this.cancelDrop) { boolean flag2 = iblockdata.canBeReplaced((BlockPlaceContext) (new DirectionalPlaceContext(this.level(), blockposition, Direction.DOWN, ItemStack.EMPTY, Direction.UP))); boolean flag3 = FallingBlock.isFree(this.level().getBlockState(blockposition.below())) && (!flag || !flag1); @@ -321,7 +382,12 @@ public class FallingBlockEntity extends Entity { } } - this.scaleDeltaMovement(0.98D); // Sakura - reduce movement allocations + // Sakura start - physics version api + if (physics.afterOrEqual(1_12_0)) { + double drag = physics.before(1_14_0) ? 0.98F : 0.98D; + this.scaleDeltaMovement(drag); // Sakura - reduce movement allocations + } + // Sakura end } } 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 8ee03ac1c824fd2476339202c073239292ef62a2..5e588332f5916355293553012c73a647b1f4bd89 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java @@ -59,6 +59,13 @@ public class PrimedTnt extends Entity implements TraceableEntity { case Y -> multiplyDeltaMovement(0, 1, 0); } // Sakura end + // Sakura start - physics version api + this.physics = world.localConfig().config(this.blockPosition()).physicsVersion; + this.eyeHeight = this.physics.isLegacy() ? 0.49f : this.eyeHeight; + if (this.physics.isLegacy()) { + multiplyDeltaMovement(0, 1, 0); + } + // Sakura end } @Override @@ -129,12 +136,30 @@ public class PrimedTnt extends Entity implements TraceableEntity { } } // Sakura end + // Sakura start - physics version api + @Override + public double getEyeY() { + return this.physics.isLegacy() ? super.getEyeY() : this.getY(); + } + + @Override + public double distanceToSqr(net.minecraft.world.phys.Vec3 vector) { + if (!this.physics.isLegacy()) + return super.distanceToSqr(vector); + double x = this.getX() - vector.x; + double y = this.getEyeY() - vector.y; + double z = this.getZ() - vector.z; + return x * x + y * y + z * z; + } + // Sakura end @Override public void tick() { // Sakura - remove max tnt per tick if (!this.isNoGravity()) { - this.addDeltaMovement(0.0D, -0.04D, 0.0D); // Sakura - reduce movement allocations + // Sakura start - physics version api + double gravity = this.physics.before(1_14_0) ? 0.04F : 0.04D; + this.addDeltaMovement(0.0D, -gravity, 0.0D); // Sakura - reduce movement allocations } this.moveBasic(MoverType.SELF, this.getDeltaMovement()); // Sakura @@ -144,15 +169,18 @@ public class PrimedTnt extends Entity implements TraceableEntity { return; } // Paper end - this.scaleDeltaMovement(0.98D); // Sakura - reduce movement allocations + double drag = this.physics.before(1_14_0) ? 0.98F : 0.98D; + this.scaleDeltaMovement(drag); // Sakura - reduce movement allocations if (this.onGround()) { - this.multiplyDeltaMovement(0.7D, -0.5D, 0.7D); // Sakura - reduce movement allocations + double friction = this.physics.before(1_14_0) ? 0.7F : 0.7D; + this.multiplyDeltaMovement(friction, -0.5D, friction); // Sakura - reduce movement allocations + // Sakura end - physics version api } int i = this.getFuse() - 1; this.setFuse(i); - if (i <= 0) { + if (this.physics.before(1_9_0) ? (i < 0) : (i <= 0)) { // Sakura - physics version api // CraftBukkit start - Need to reverse the order of the explosion and the entity death so we have a location for the event // this.discard(); this.respawnMerged(); // Sakura @@ -205,7 +233,10 @@ public class PrimedTnt extends Entity implements TraceableEntity { ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent((org.bukkit.entity.Explosive)this.getBukkitEntity()); if (!event.isCancelled()) { - this.level().explode(this, this.getX(), this.getY(0.0625D), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.TNT); + // Sakura start - physics version api + double pos = this.physics.before(1_10_0) ? this.getY() + (double) 0.49f : this.getY(0.0625D); + this.level().explode(this, this.getX(), pos, this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.TNT); + // Sakura end } // CraftBukkit end } @@ -274,7 +305,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { // Paper start - Optional prevent TNT from moving in water @Override public boolean isPushedByFluid() { - return !level().paperConfig().fixes.preventTntFromMovingInWater && level().sakuraConfig().cannons.mechanics.tntFlowsInWater && super.isPushedByFluid(); // Sakura - convenience + return !level().paperConfig().fixes.preventTntFromMovingInWater && !this.physics.isLegacy() && level().sakuraConfig().cannons.mechanics.tntFlowsInWater && super.isPushedByFluid(); // Sakura - physics version // Sakura - convenience } // Paper end } diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java index 5a10afb92fd62f433be9be6751e5222f3666c9f3..d92798d848754bb02f2de9ee91e1342ceb8e150c 100644 --- a/src/main/java/net/minecraft/world/level/Explosion.java +++ b/src/main/java/net/minecraft/world/level/Explosion.java @@ -74,6 +74,7 @@ public class Explosion { public boolean wasCanceled = false; public float yield; // CraftBukkit end + protected final me.samsuik.sakura.physics.PhysicsVersion physics; // Sakura - physics version public static DamageSource getDefaultDamageSource(Level world, @Nullable Entity source) { return world.damageSources().explosion(source, Explosion.getIndirectSourceEntityInternal(source)); @@ -111,6 +112,7 @@ public class Explosion { this.largeExplosionParticles = emitterParticle; this.explosionSound = soundEvent; this.yield = this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F; // CraftBukkit + this.physics = entity != null ? entity.physics() : world.localConfig().config(BlockPos.containing(x, y, z)).physicsVersion; // Sakura } // Paper start - optimise collisions @@ -489,9 +491,17 @@ public class Explosion { Vec3 vec3d1 = new Vec3(d8 + d3, d9, d10 + d4); // Sakura start + final net.minecraft.world.phys.HitResult.Type hitResult; if (data != null && data.isExpandable() && data.has(vec3d1)) { - i += (int) data.density(); - } else if (entity.level().clip(new ClipContext(vec3d1, source, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)).getType() == HitResult.Type.MISS) { + hitResult = data.density() == 1.0 ? net.minecraft.world.phys.HitResult.Type.MISS : net.minecraft.world.phys.HitResult.Type.BLOCK; + } else { + if (entity.physics().afterOrEqual(1_14_0)) { + hitResult = entity.level().rayTrace(vec3d1, source); + } else { + hitResult = entity.level().clip(new ClipContext(vec3d1, source, entity.physics().afterOrEqual(1_16_0) ? ClipContext.Block.COLLIDER : ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, entity)).getType(); + } + } + if (hitResult == net.minecraft.world.phys.HitResult.Type.MISS) { // Sakura end ++i; } @@ -605,6 +615,10 @@ public class Explosion { } if (cachedBlock.outOfWorld) { + // Sakura start - physics version api + if (this.physics.before(1_17_0)) + continue; + // Sakura end break; } @@ -675,10 +689,17 @@ public class Explosion { if (d7 <= 1.0D) { double d8 = entity.getX() - this.x; - double d9 = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - this.y; + double d9 = entity.getEyeY() - this.y; // Sakura - remove tnt special case double d10 = entity.getZ() - this.z; double d11 = Math.sqrt(d8 * d8 + d9 * d9 + d10 * d10); + // Sakura start + if (this.physics.before(1_17_0)) { + d7 = (float) d7; + d11 = (float) d11; + } + // Sakura end + if (d11 != 0.0D) { d8 /= d11; d9 /= d11; @@ -986,7 +1007,14 @@ public class Explosion { return data.density(); } - float blockDensity = this.getSeenFraction(vec3d, entity, data, blockCache, blockPos); // Paper - optimise explosions; + // Sakura start - physics version api + final float blockDensity; + if (this.physics.afterOrEqual(1_16_0)) { + blockDensity = this.getSeenFraction(vec3d, entity, data, blockCache, blockPos); // Paper - optimise explosions; + } else { + blockDensity = this.getSeenPercent(vec3d, entity, data); + } + // Sakura end if (data == null || !data.isExpandable() && (blockDensity == 0.0f || blockDensity == 1.0f)) { level.densityCache.createCache(key, entity, vec3d, blockDensity); diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 09ff77ec8967645df0de253f6e8ee8cb6b998c0d..5afbdbd07afc671c3c6db491a713abfa467fffa3 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -274,6 +274,205 @@ public abstract class Level implements LevelAccessor, AutoCloseable { return this.getLimitedEntities(except, box, net.minecraft.world.entity.EntitySelector.NO_SPECTATORS, limit, search); } // Sakura end + // Sakura start - physics version + public net.minecraft.world.phys.BlockHitResult.Type rayTrace(net.minecraft.world.phys.Vec3 vec3d, net.minecraft.world.phys.Vec3 vec3d1) { + // May deviate from vanilla here; I remember noticing a bug and there's no fix commit. + int i = Mth.floor(vec3d1.x); + int j = Mth.floor(vec3d1.y); + int k = Mth.floor(vec3d1.z); + int l = Mth.floor(vec3d.x); + int i1 = Mth.floor(vec3d.y); + int j1 = Mth.floor(vec3d.z); + BlockPos.MutableBlockPos blockposition = new BlockPos.MutableBlockPos(l, i1, j1); + LevelChunk chunk = this.getChunkIfLoaded(l >> 4, j1 >> 4); + + // probably a bad idea to copy this over so we don't need to do a null check + if (chunk == null) { + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + + BlockState iblockdata = chunk.getBlockState(blockposition); + net.minecraft.world.phys.shapes.VoxelShape shape = iblockdata.getShape(this, blockposition); + + for (AABB bb : shape.toAabbs()) { + if (clip(bb, blockposition, vec3d, vec3d1)) { + return net.minecraft.world.phys.BlockHitResult.Type.BLOCK; + } + } + + int k1 = 200; + + while (k1-- >= 0) { + if (l == i && i1 == j && j1 == k) { + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + + boolean flag3 = true; + boolean flag4 = true; + boolean flag5 = true; + double d0 = 999.0D; + double d1 = 999.0D; + double d2 = 999.0D; + + if (i > l) { + d0 = (double) l + 1.0D; + } else if (i < l) { + d0 = (double) l + 0.0D; + } else { + flag3 = false; + } + + if (j > i1) { + d1 = (double) i1 + 1.0D; + } else if (j < i1) { + d1 = (double) i1 + 0.0D; + } else { + flag4 = false; + } + + if (k > j1) { + d2 = (double) j1 + 1.0D; + } else if (k < j1) { + d2 = (double) j1 + 0.0D; + } else { + flag5 = false; + } + + double d3 = 999.0D; + double d4 = 999.0D; + double d5 = 999.0D; + double d6 = vec3d1.x - vec3d.x; + double d7 = vec3d1.y - vec3d.y; + double d8 = vec3d1.z - vec3d.z; + + if (flag3) { + d3 = (d0 - vec3d.x) / d6; + } + + if (flag4) { + d4 = (d1 - vec3d.y) / d7; + } + + if (flag5) { + d5 = (d2 - vec3d.z) / d8; + } + + if (d3 == -0.0D) { + d3 = -1.0E-4D; + } + + if (d4 == -0.0D) { + d4 = -1.0E-4D; + } + + if (d5 == -0.0D) { + d5 = -1.0E-4D; + } + + Direction enumdirection; + + if (d3 < d4 && d3 < d5) { + enumdirection = i > l ? Direction.WEST : Direction.EAST; + vec3d = new net.minecraft.world.phys.Vec3(d0, vec3d.y + d7 * d3, vec3d.z + d8 * d3); + } else if (d4 < d5) { + enumdirection = j > i1 ? Direction.DOWN : Direction.UP; + vec3d = new net.minecraft.world.phys.Vec3(vec3d.x + d6 * d4, d1, vec3d.z + d8 * d4); + } else { + enumdirection = k > j1 ? Direction.NORTH : Direction.SOUTH; + vec3d = new net.minecraft.world.phys.Vec3(vec3d.x + d6 * d5, vec3d.y + d7 * d5, d2); + } + + l = Mth.floor(vec3d.x) - (enumdirection == Direction.EAST ? 1 : 0); + i1 = Mth.floor(vec3d.y) - (enumdirection == Direction.UP ? 1 : 0); + j1 = Mth.floor(vec3d.z) - (enumdirection == Direction.SOUTH ? 1 : 0); + blockposition.set(l, i1, j1); + + int chunkX = l >> 4; + int chunkZ = j1 >> 4; + + if (chunkX != chunk.locX || chunkZ != chunk.locZ) { + chunk = this.getChunkIfLoaded(chunkX, chunkZ); + } + + if (chunk == null) { + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + + iblockdata = chunk.getBlockState(blockposition); + shape = iblockdata.getShape(this, blockposition); + + for (AABB bb : shape.toAabbs()) { + if (clip(bb, blockposition, vec3d, vec3d1)) { + return net.minecraft.world.phys.BlockHitResult.Type.BLOCK; + } + } + } + + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + + private boolean clip(AABB bb, BlockPos blockposition, net.minecraft.world.phys.Vec3 vec3d, net.minecraft.world.phys.Vec3 vec3d1) { + vec3d = vec3d.subtract(blockposition.getX(), blockposition.getY(), blockposition.getZ()); + vec3d1 = vec3d1.subtract(blockposition.getX(), blockposition.getY(), blockposition.getZ()); + + double x = vec3d1.x - vec3d.x; + double y = vec3d1.y - vec3d.y; + double z = vec3d1.z - vec3d.z; + + double minXd = clip(bb.minX, x, vec3d.x); + double minYd = clip(bb.minY, y, vec3d.y); + double minZd = clip(bb.minZ, z, vec3d.z); + double maxXd = clip(bb.maxX, x, vec3d.x); + double maxYd = clip(bb.maxY, y, vec3d.y); + double maxZd = clip(bb.maxZ, z, vec3d.z); + + return clipX(vec3d, bb, minXd, y, z) || clipY(vec3d, bb, minYd, x, z) || clipZ(vec3d, bb, minZd, x, y) + || clipX(vec3d, bb, maxXd, y, z) || clipY(vec3d, bb, maxYd, x, z) || clipZ(vec3d, bb, maxZd, x, y); + } + + private double clip(double bound, double axisD, double axisN) { + // This is my friend jerry, he was an epsilon. Unfortunately, once day + // he was cast to a float. Now he's spending his retirement here as a double. + if (axisD * axisD < 1.0000000116860974E-7D) { + return -1.0; + } + + return (bound - axisN) / axisD; + } + + private boolean clipX(net.minecraft.world.phys.Vec3 vec3d, AABB bb, double n, double y, double z) { + if (n < 0.0 || n > 1.0) { + return false; + } + + y = vec3d.y + y * n; + z = vec3d.z + z * n; + + return y >= bb.minY && y <= bb.maxY && z >= bb.minZ && z <= bb.maxZ; + } + + private boolean clipY(net.minecraft.world.phys.Vec3 vec3d, AABB bb, double n, double x, double z) { + if (n < 0.0 || n > 1.0) { + return false; + } + + x = vec3d.x + x * n; + z = vec3d.z + z * n; + + return x >= bb.minX && x <= bb.maxX && z >= bb.minZ && z <= bb.maxZ; + } + + private boolean clipZ(net.minecraft.world.phys.Vec3 vec3d, AABB bb, double n, double x, double y) { + if (n < 0.0 || n > 1.0) { + return false; + } + + x = vec3d.x + x * n; + y = vec3d.y + y * n; + + return x >= bb.minX && x <= bb.maxX && y >= bb.minY && y <= bb.maxY; + } + // Sakura end protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, Supplier sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura // Paper - Async-Anti-Xray - Pass executor this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot diff --git a/src/main/java/net/minecraft/world/level/block/FallingBlock.java b/src/main/java/net/minecraft/world/level/block/FallingBlock.java index 1079a99d6a6c9fba36414a863e1454bb2a7f298a..4ee105548df2a730f192d4b511a399d129824df6 100644 --- a/src/main/java/net/minecraft/world/level/block/FallingBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FallingBlock.java @@ -35,6 +35,15 @@ public abstract class FallingBlock extends Block implements Fallable { return super.updateShape(state, direction, neighborState, world, pos, neighborPos); } + // Sakura start - physics version api + @Override + public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean notify) { + if (world.localConfig().config(pos).physicsVersion.before(1_18_2)) { + world.scheduleTick(pos, this, this.getDelayAfterPlace()); + } + } + // Sakura end + @Override public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { if (isFree(world.getBlockState(pos.below())) && pos.getY() >= world.getMinBuildHeight()) { diff --git a/src/main/java/net/minecraft/world/level/block/FenceGateBlock.java b/src/main/java/net/minecraft/world/level/block/FenceGateBlock.java index 6524272aab5a876e2a2164181da72c765959b550..4c242b501e7e5c7af6676b9554b00405838c4eb0 100644 --- a/src/main/java/net/minecraft/world/level/block/FenceGateBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FenceGateBlock.java @@ -180,8 +180,13 @@ public class FenceGateBlock extends HorizontalDirectionalBlock { } // CraftBukkit end - if ((Boolean) state.getValue(FenceGateBlock.POWERED) != flag1) { - world.setBlock(pos, (BlockState) ((BlockState) state.setValue(FenceGateBlock.POWERED, flag1)).setValue(FenceGateBlock.OPEN, flag1), 2); + // Sakura start + final boolean legacy = world.localConfig().config(pos).physicsVersion.before(1_11_0); + final boolean powered = state.getValue(FenceGateBlock.POWERED); + if (legacy ? (flag1 || sourceBlock.defaultBlockState().isSignalSource()) : powered != flag1) { + final boolean openGate = legacy && (flag1 == powered || state.getValue(FenceGateBlock.OPEN) != powered) ? state.getValue(OPEN) : flag1; + world.setBlock(pos, (BlockState) ((BlockState) state.setValue(FenceGateBlock.POWERED, flag1)).setValue(FenceGateBlock.OPEN, openGate), 2); + // Sakura end if ((Boolean) state.getValue(FenceGateBlock.OPEN) != flag1) { world.playSound((Player) null, pos, flag1 ? this.type.fenceGateOpen() : this.type.fenceGateClose(), SoundSource.BLOCKS, 1.0F, world.getRandom().nextFloat() * 0.1F + 0.9F); world.gameEvent((Entity) null, flag1 ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE, pos); diff --git a/src/main/java/net/minecraft/world/level/block/LadderBlock.java b/src/main/java/net/minecraft/world/level/block/LadderBlock.java index de87b54895d5a63d32c1734ccdac63246c9f2c5f..79bced0e284430d57d4a7ec80a57d717249e7e36 100644 --- a/src/main/java/net/minecraft/world/level/block/LadderBlock.java +++ b/src/main/java/net/minecraft/world/level/block/LadderBlock.java @@ -28,6 +28,21 @@ public class LadderBlock extends Block implements SimpleWaterloggedBlock { protected static final VoxelShape WEST_AABB = Block.box(13.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D); protected static final VoxelShape SOUTH_AABB = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 3.0D); protected static final VoxelShape NORTH_AABB = Block.box(0.0D, 0.0D, 13.0D, 16.0D, 16.0D, 16.0D); + // Sakura start + protected static final VoxelShape LEGACY_EAST_AABB = Block.box(0.0D, 0.0D, 0.0D, 2.0D, 16.0D, 16.0D); + protected static final VoxelShape LEGACY_WEST_AABB = Block.box(14.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D); + protected static final VoxelShape LEGACY_SOUTH_AABB = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 2.0D); + protected static final VoxelShape LEGACY_NORTH_AABB = Block.box(0.0D, 0.0D, 14.0D, 16.0D, 16.0D, 16.0D); + + private static VoxelShape legacyShape(Direction facing) { + return switch (facing) { + case NORTH -> LEGACY_NORTH_AABB; + case SOUTH -> LEGACY_SOUTH_AABB; + case WEST -> LEGACY_WEST_AABB; + default -> LEGACY_EAST_AABB; + }; + } + // Sakura end @Override public MapCodec codec() { @@ -39,8 +54,18 @@ public class LadderBlock extends Block implements SimpleWaterloggedBlock { this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(WATERLOGGED, Boolean.valueOf(false))); } + // Sakura start + @Override + public final boolean hasDynamicShape() { + return true; + } + @Override public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { + if (world instanceof net.minecraft.world.level.Level level && level.localConfig().config(pos).physicsVersion.before(1_9_0)) { + return legacyShape(state.getValue(FACING)); + } + // Sakura end switch ((Direction)state.getValue(FACING)) { case NORTH: return NORTH_AABB; diff --git a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java index 2bd097203f1e92d3fc343f91dc37220e09dd5066..2fe44dae063eb0cd7d4813fb6b2937830d432e51 100644 --- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java +++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java @@ -192,8 +192,26 @@ public class LiquidBlock extends Block implements BucketPickup { BlockPos blockposition1 = pos.relative(enumdirection.getOpposite()); if (world.getFluidState(blockposition1).is(FluidTags.WATER)) { - Block block = world.getFluidState(pos).isSource() ? Blocks.OBSIDIAN : Blocks.COBBLESTONE; - + // Sakura start + final FluidState fluidState = state.getFluidState(); + final Block block; + + if (fluidState.isSource()) { + block = Blocks.OBSIDIAN; + } else { + final me.samsuik.sakura.physics.PhysicsVersion physics = world.localConfig().config(pos).physicsVersion; + + // SANITY: In legacy a patch by paper removes the fluid level condition from vanilla. + if (physics.afterOrEqual(1_16_0) || physics.isLegacy() + || physics.afterOrEqual(1_13_0) && fluidState.getHeight(world, pos) >= 0.44444445f + || physics.before(1_13_0) && FlowingFluid.getLegacyLevel(fluidState) <= 4 + ) { + block = Blocks.COBBLESTONE; + } else { + return true; + } + } + // Sakura end // CraftBukkit start if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(world, pos, block.defaultBlockState())) { this.fizz(world, pos); diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java index 82bde0e37971e806b19d17fbf48c663c82399739..570694ba570135542d4184ac9d03f29132b28df8 100644 --- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java @@ -685,6 +685,10 @@ public class RedStoneWireBlock extends Block { public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { if (!player.getAbilities().mayBuild) { return InteractionResult.PASS; + // Sakura start + } else if (world.localConfig().config(pos).physicsVersion.before(1_16_0)) { + return InteractionResult.PASS; + // Sakura end } else { if (RedStoneWireBlock.isCross(state) || RedStoneWireBlock.isDot(state)) { BlockState iblockdata1 = RedStoneWireBlock.isCross(state) ? this.defaultBlockState() : this.crossState; diff --git a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java index b6105d178778b326c11b7d29c5e4d8aa2c3a3875..7ff78fb671dc2791378802cda89c358eda15f2ae 100644 --- a/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java +++ b/src/main/java/net/minecraft/world/level/block/WaterlilyBlock.java @@ -21,6 +21,7 @@ public class WaterlilyBlock extends BushBlock { public static final MapCodec CODEC = simpleCodec(WaterlilyBlock::new); protected static final VoxelShape AABB = Block.box(1.0D, 0.0D, 1.0D, 15.0D, 1.5D, 15.0D); + protected static final VoxelShape LEGACY_AABB = Block.box(0.0D, 0.0D, 0.0D, 16.0D, 0.25D, 16.0D); // Sakura @Override public MapCodec codec() { @@ -46,8 +47,18 @@ public class WaterlilyBlock extends BushBlock { } + // Sakura start + @Override + public final boolean hasDynamicShape() { + return true; + } + @Override public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { + if (world instanceof net.minecraft.world.level.Level level && level.localConfig().config(pos).physicsVersion.before(1_9_0)) { + return LEGACY_AABB; + } + // Sakura end return WaterlilyBlock.AABB; } diff --git a/src/main/java/net/minecraft/world/level/block/piston/MovingPistonBlock.java b/src/main/java/net/minecraft/world/level/block/piston/MovingPistonBlock.java index d3d1ad7901411574b85b0febd1c7ddaa8ad7c9f4..cc2c601032b2a2d94aa74cc3ad7169c202b354ab 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/MovingPistonBlock.java +++ b/src/main/java/net/minecraft/world/level/block/piston/MovingPistonBlock.java @@ -111,6 +111,17 @@ public class MovingPistonBlock extends BaseEntityBlock { @Override public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { PistonMovingBlockEntity pistonMovingBlockEntity = this.getBlockEntity(world, pos); + // Sakura start - physics version api + if (pistonMovingBlockEntity != null && world instanceof Level level && level.localConfig().config(pos).physicsVersion.before(1_9_0)) { + VoxelShape shape = pistonMovingBlockEntity.getCollisionShapeFromProgress(level, pos); + + if (context.isAbove(shape, pos, false)) { + return shape; + } else { + return pistonMovingBlockEntity.getMovedState().getCollisionShape(world, pos); + } + } + // Sakura end return pistonMovingBlockEntity != null ? pistonMovingBlockEntity.getCollisionShape(world, pos) : Shapes.empty(); } diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java index b9025fcc6a4db9533cdc42034c9e77323d0785fa..fd7563a8b6ab8165c1ba7b4959a3bf9369d20e75 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java +++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java @@ -170,6 +170,11 @@ public class PistonBaseBlock extends DirectionalBlock { // } // PAIL: checkME - what happened to setTypeAndData? // CraftBukkit end + // Sakura start - physics version api + if (world.localConfig().config(pos).physicsVersion.before(1_9_0)) { + world.setBlock(pos, state.setValue(PistonBaseBlock.EXTENDED, false), 18); + } + // Sakura end world.blockEvent(pos, this, b0, enumdirection.get3DDataValue()); } diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonHeadBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonHeadBlock.java index 5301095fa3baac1bde3767153ee2343026596688..1ef830d5e34f25c08d53d693db99a6eb641ebbe5 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/PistonHeadBlock.java +++ b/src/main/java/net/minecraft/world/level/block/piston/PistonHeadBlock.java @@ -139,6 +139,11 @@ public class PistonHeadBlock extends DirectionalBlock { @Override public boolean canSurvive(BlockState state, LevelReader world, BlockPos pos) { BlockState blockState = world.getBlockState(pos.relative(state.getValue(FACING).getOpposite())); + // Sakura start - physics version api + if (world instanceof Level level && level.localConfig().config(pos).physicsVersion.before(1_9_0)) { + return this.isFittingBase(state, blockState); + } + // Sakura end return this.isFittingBase(state, blockState) || blockState.is(Blocks.MOVING_PISTON) && blockState.getValue(FACING) == state.getValue(FACING); } @@ -146,6 +151,10 @@ public class PistonHeadBlock extends DirectionalBlock { public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { if (state.canSurvive(world, pos)) { world.neighborChanged(pos.relative(state.getValue(FACING).getOpposite()), sourceBlock, sourcePos); + // Sakura start - physics version api + } else if (world.localConfig().config(pos).physicsVersion.before(1_9_0)) { + world.setBlock(pos, Blocks.AIR.defaultBlockState(), 19); + // Sakura end } } diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java index a971bb30ef8620f016a5968a9da40187ee31a3ef..68bac9ea693f4457a8ced072cae85aef076eeb71 100644 --- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java @@ -159,6 +159,13 @@ public class PistonMovingBlockEntity extends BlockEntity { double i = 0.0D; + // Sakura start - physics version api + if (entity.physics().before(1_11_0)) { + moveEntityByPistonFromDirection(direction, entity, aABB); + return; + } + // Sakura end + for(AABB aABB2 : list2) { AABB aABB3 = PistonMath.getMovementArea(moveByPositionAndProgress(pos, aABB2, blockEntity), direction, d); AABB aABB4 = entity.getBoundingBox(); @@ -280,14 +287,154 @@ public class PistonMovingBlockEntity extends BlockEntity { } } + + // Sakura start - physics version api + @javax.annotation.Nullable + private AABB getBoundsFromProgress(Level level, BlockPos pos, BlockState state, float progress, Direction dir, boolean absolute) { + if (!state.is(Blocks.MOVING_PISTON) && !state.isAir()) { + VoxelShape shape = this.movedState.getCollisionShape(level, pos); + // bounds on an empty shape causes an exception + if (shape.isEmpty()) return null; + if (absolute) shape = shape.move(pos.getX(), pos.getY(), pos.getZ()); + AABB bounds = shape.bounds(); + + double minX = bounds.minX; + double minY = bounds.minY; + double minZ = bounds.minZ; + double maxX = bounds.maxX; + double maxY = bounds.maxY; + double maxZ = bounds.maxZ; + + if (dir.getStepX() < 0) { + minX -= (float) dir.getStepX() * progress; + } else { + maxX -= (float) dir.getStepX() * progress; + } + + if (dir.getStepY() < 0) { + minY -= (float) dir.getStepY() * progress; + } else { + maxY -= (float) dir.getStepY() * progress; + } + + if (dir.getStepZ() < 0) { + minZ -= (float) dir.getStepZ() * progress; + } else { + maxZ -= (float) dir.getStepZ() * progress; + } + + return new AABB(minX, minY, minZ, maxX, maxY, maxZ); + } + + return null; + } + + public VoxelShape getCollisionShapeFromProgress(Level level, BlockPos pos) { + float progress = this.getProgress(0.0f); + + if (this.extending) { + progress = 1.0F - progress; + } + + AABB bb = this.getBoundsFromProgress(level, pos, this.movedState, progress, this.direction, false); + // will never be null, but ide seems to think so hmm thinkge + return bb == null ? Shapes.empty() : Shapes.create(bb); + } + + private void moveEntities(Level level, float f1) { + float f = this.progress; + + if (this.extending) { + f = 1.0F - f; + } else { + --f; + } + + AABB bb = this.getBoundsFromProgress(level, this.worldPosition, this.movedState, f, this.direction, true); + + if (bb == null || bb.getSize() == 0.0) { + return; + } + + List entities = level.getEntities(null, bb); + + if (entities.isEmpty()) { + return; + } + + for (Entity entity : entities) { + if (this.movedState.is(Blocks.SLIME_BLOCK) && this.extending) { + Vec3 movement = entity.getDeltaMovement(); + double x = movement.x; + double y = movement.y; + double z = movement.z; + + switch (this.direction.getAxis()) { + case X -> x = direction.getStepX(); + case Y -> y = direction.getStepY(); + case Z -> z = direction.getStepZ(); + } + + entity.setDeltaMovement(x, y, z); + } else { + entity.move(MoverType.PISTON, new Vec3(f1 * (float) this.direction.getStepX(), f1 * (float) this.direction.getStepY(), f1 * (float) this.direction.getStepZ())); + } + } + } + + private static void moveEntityByPistonFromDirection(Direction direction, Entity entity, AABB blockBB) { + AABB entityBB = entity.getBoundingBox(); + double movX = 0.0; + double movY = 0.0; + double movZ = 0.0; + + switch (direction.getAxis()) { + case X -> { + if (direction.getAxisDirection() == Direction.AxisDirection.POSITIVE) { + movX = blockBB.maxX - entityBB.minX; + } else { + movX = entityBB.maxX - blockBB.minX; + } + movX += 0.01D; + } + case Y -> { + if (direction.getAxisDirection() == Direction.AxisDirection.POSITIVE) { + movY = blockBB.maxY - entityBB.minY; + } else { + movY = entityBB.maxY - blockBB.minY; + } + movY += 0.01D; + } + case Z -> { + if (direction.getAxisDirection() == Direction.AxisDirection.POSITIVE) { + movZ = blockBB.maxZ - entityBB.minZ; + } else { + movZ = entityBB.maxZ - blockBB.minZ; + } + movZ += 0.01D; + } + } + + entity.move(MoverType.PISTON, new Vec3(movX * direction.getStepX(), movY * direction.getStepY(), movZ * direction.getStepZ())); + } + // Sakura end public static void tick(Level world, BlockPos pos, BlockState state, PistonMovingBlockEntity blockEntity) { + me.samsuik.sakura.physics.PhysicsVersion physicsVersion = world.localConfig().config(pos).physicsVersion; // Sakura blockEntity.lastTicked = world.getGameTime(); blockEntity.progressO = blockEntity.progress; if (blockEntity.progressO >= 1.0F) { if (world.isClientSide && blockEntity.deathTicks < 5) { ++blockEntity.deathTicks; } else { + // Sakura start - physics version api + if (physicsVersion.isWithin(1_9_0, 1_10_0)) { + moveCollidedEntities(world, pos, 1.0f, blockEntity); + moveStuckEntities(world, pos, 1.0f, blockEntity); + } else if (physicsVersion.before(1_9_0)) { + blockEntity.moveEntities(world, 0.25f); + } + // Sakura end world.removeBlockEntity(pos); blockEntity.setRemoved(); if (world.getBlockState(pos).is(Blocks.MOVING_PISTON)) { @@ -308,13 +455,25 @@ public class PistonMovingBlockEntity extends BlockEntity { } } else { float f = blockEntity.progress + 0.5F; + // Sakura start - physics version api + if (physicsVersion.afterOrEqual(1_11_0)) { moveCollidedEntities(world, pos, f, blockEntity); moveStuckEntities(world, pos, f, blockEntity); + } + blockEntity.progress = f; if (blockEntity.progress >= 1.0F) { blockEntity.progress = 1.0F; } + if (physicsVersion.isWithin(1_9_0, 1_10_0)) { + moveCollidedEntities(world, pos, f, blockEntity); + moveStuckEntities(world, pos, f, blockEntity); + } else if (blockEntity.extending && physicsVersion.before(1_9_0)) { + blockEntity.moveEntities(world, blockEntity.progress - blockEntity.progressO + 0.0625f); + } + // Sakura end + } } diff --git a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java index 6d59f8b68d644cb43939bcdf5239fa1caf54ed47..96ccad764cb6424ffe561c558cd11200d89ff541 100644 --- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java +++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java @@ -528,7 +528,7 @@ public abstract class FlowingFluid extends Fluid { this.spread(world, pos, state); } - protected static int getLegacyLevel(FluidState state) { + public static int getLegacyLevel(FluidState state) { // Sakura - protected -> public return state.isSource() ? 0 : 8 - Math.min(state.getAmount(), 8) + ((Boolean) state.getValue(FlowingFluid.FALLING) ? 8 : 0); } diff --git a/src/main/java/net/minecraft/world/level/material/LavaFluid.java b/src/main/java/net/minecraft/world/level/material/LavaFluid.java index c3f8e1e2dd89c168b8b4a15b589109db486bc8d7..1dab5318d8693d15ee879456dff3a1916cfad335 100644 --- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java +++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java @@ -175,7 +175,10 @@ public abstract class LavaFluid extends FlowingFluid { @Override public boolean canBeReplacedWith(FluidState state, BlockGetter world, BlockPos pos, Fluid fluid, Direction direction) { - return state.getHeight(world, pos) >= 0.44444445F && fluid.is(FluidTags.WATER); + // Sakura start + return state.getHeight(world, pos) >= 0.44444445F && fluid.is(FluidTags.WATER) + && world instanceof Level level && level.localConfig().config(pos).physicsVersion.afterOrEqual(1_13_0); + // Sakura end } @Override diff --git a/src/main/java/net/minecraft/world/level/material/WaterFluid.java b/src/main/java/net/minecraft/world/level/material/WaterFluid.java index d280c98aed5262c4ce39526c917de884f25a8584..521b8084e490d5f3ecacd1d7368dddee22647aa9 100644 --- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java +++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java @@ -104,7 +104,10 @@ public abstract class WaterFluid extends FlowingFluid { @Override public boolean canBeReplacedWith(FluidState state, BlockGetter world, BlockPos pos, Fluid fluid, Direction direction) { - return direction == Direction.DOWN && !fluid.is(FluidTags.WATER); + // Sakura start + return direction == Direction.DOWN && !fluid.is(FluidTags.WATER) + || fluid.is(FluidTags.LAVA) && world instanceof Level level && level.localConfig().config(pos).physicsVersion.before(1_13_0); + // Sakura end } @Override