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/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java index f6be260f942c6b9c65e8c3ed625639db75086267..27b7be52f7617a6ecd1ff7e967604424f40027bc 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java @@ -1801,6 +1801,13 @@ public final class CollisionUtil { } public static Vec3 performAABBCollisions(final Vec3 moveVector, AABB axisalignedbb, final List potentialCollisions) { + // Sakura start - physics version api + return performAABBCollisions(moveVector, axisalignedbb, potentialCollisions, null); + } + public static Vec3 performAABBCollisions(final Vec3 moveVector, AABB axisalignedbb, + final List potentialCollisions, + final me.samsuik.sakura.physics.PhysicsVersion physics) { + // Sakura end - physics version api double x = moveVector.x; double y = moveVector.y; double z = moveVector.z; @@ -1812,7 +1819,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.isLegacy() && Math.abs(x) > Math.abs(z); + // Sakura end - physics version api if (xSmaller && z != 0.0) { z = performAABBCollisionsZ(axisalignedbb, z, potentialCollisions); @@ -1838,9 +1848,18 @@ public final class CollisionUtil { public static Vec3 performCollisions(final Vec3 moveVector, AABB axisalignedbb, final List voxels, final List aabbs) { + // Sakura start - physics version api + 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 - physics version api if (voxels.isEmpty()) { // fast track only AABBs - return performAABBCollisions(moveVector, axisalignedbb, aabbs); + return performAABBCollisions(moveVector, axisalignedbb, aabbs, physics); // Sakura - physics version api } double x = moveVector.x; @@ -1855,7 +1874,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.isLegacy() && Math.abs(x) > Math.abs(z); + // Sakura end - physics version api if (xSmaller && z != 0.0) { z = performAABBCollisionsZ(axisalignedbb, z, aabbs); diff --git a/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java index ce04a5d9aaef3ca8ba8d7b988bdf0497285f90c1..c916d3037bd5920ec06213a9162223a124428d6b 100644 --- a/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java +++ b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java @@ -161,9 +161,15 @@ public abstract class SpecialisedExplosion extends ServerExplo 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 - physics version api double z = entity.getZ() - pos.z; double distance = Math.sqrt(x * x + y * y + z * z); + // Sakura start - physics version api + if (this.physics.before(1_17_0)) { + distanceFromBottom = (float) distanceFromBottom; + distance = (float) distance; + } + // Sakura end - physics version api if (distance != 0.0D) { x /= distance; diff --git a/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java b/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java index ebe5f0c8c2f09920b5f5ef734e63f5e7cd8bd3a1..320cdb1f4e655a2d093890e88476df90ed436ae5 100644 --- a/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java +++ b/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java @@ -37,6 +37,13 @@ public final class TntExplosion extends SpecialisedExplosion { this.bounds = new AABB(center, center); } + // Sakura start - physics version api + @Override + protected double getExplosionOffset() { + return this.physics.before(1_10_0) ? (double) 0.49f : super.getExplosionOffset(); + } + // Sakura end - physics version api + @Override protected int getExplosionCount() { if (this.cause.getMergeEntityData().getMergeLevel() == MergeLevel.NONE) { diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 687eb620c0ee3fc19472f830b6296862a7dcf01c..dd93bff521e8bfc72416cebed20cb3a5bce094b8 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -341,7 +341,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess private final double[] pistonDeltas; private long pistonDeltasGameTime; private EntityDimensions dimensions; - private float eyeHeight; + protected float eyeHeight; // Sakura - private -> protected public boolean isInPowderSnow; public boolean wasInPowderSnow; public Optional mainSupportingBlockPos; @@ -623,6 +623,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } // Sakura end - merge cannon entities public boolean pushedByFluid = true; // Sakura - entity pushed by fluid api + // Sakura start - physics version api + protected me.samsuik.sakura.physics.PhysicsVersion physics = me.samsuik.sakura.physics.PhysicsVersion.LATEST; + + public final me.samsuik.sakura.physics.PhysicsVersion physics() { + return this.physics; + } + // Sakura end - physics version api public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); @@ -1161,7 +1168,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } protected void checkSupportingBlock(boolean onGround, @Nullable Vec3 movement) { - if (onGround) { + if (onGround && this.physics.afterOrEqual(1_20_0)) { // Sakura - physics version api 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); @@ -1221,7 +1228,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess if (this.noPhysics) { this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); } else { - if (movementType == MoverType.PISTON) { + if (movementType == MoverType.PISTON && this.physics.afterOrEqual(1_11_0)) { // Sakura - physics version api movement = this.limitPistonMovement(movement); if (movement.equals(Vec3.ZERO)) { return; @@ -1239,8 +1246,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess Vec3 vec3d1 = this.sakura_collide(movement); double d0 = vec3d1.lengthSqr(); - if (d0 > 1.0E-7D || movement.lengthSqr() - d0 < 1.0E-7D) { - if (this.fallDistance != 0.0F && d0 >= 1.0D && !this.isFallingBlock) { + if (d0 > 1.0E-7D || this.physics.afterOrEqual(1_21_2) && movement.lengthSqr() - d0 < 1.0E-7D || this.physics.before(1_14_0)) { // Sakura - physics version api + if (this.fallDistance != 0.0F && d0 >= 1.0D && !this.isFallingBlock && this.physics.afterOrEqual(1_18_2)) { // Sakura - physics version api BlockHitResult clipResult = this.level().clip(new ClipContext(this.position(), this.position().add(vec3d1), ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this)); if (clipResult.getType() != HitResult.Type.MISS) { this.resetFallDistance(); @@ -1269,6 +1276,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } else { if (this.horizontalCollision) { Vec3 vec3d2 = this.getDeltaMovement(); + // Sakura start - physics version api + if (movedX && movedZ && this.physics.isWithin(1_14_0, 1_18_1)) { + movedX = false; + } + // Sakura end - physics version api this.setDeltaMovement(movedX ? 0.0D : vec3d2.x, vec3d2.y, movedZ ? 0.0D : vec3d2.z); } @@ -1674,7 +1686,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess bb = currBoundingBox.expandTowards(movement.x, movement.y, movement.z); } this.collectCollisions(bb, voxelList, bbList); - return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currBoundingBox, voxelList, bbList); + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currBoundingBox, voxelList, bbList, this.physics); // Sakura - physics version api } private Vec3 collideAxisScan(Vec3 movement, AABB currBoundingBox, List voxelList, List bbList) { @@ -1682,7 +1694,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess double y = movement.y; double z = movement.z; - boolean xSmaller = Math.abs(x) < Math.abs(z); + // Sakura start - physics version api + boolean xSmaller = this.physics == null || this.physics.afterOrEqual(1_14_0) ? Math.abs(x) < Math.abs(z) + : this.physics.isLegacy() && Math.abs(x) > Math.abs(z); + // Sakura end - physics version api if (y != 0.0) { y = this.scanY(currBoundingBox, y, voxelList, bbList); @@ -1780,7 +1795,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER | this.getExtraCollisionFlags(), null // Sakura - load chunks on movement ); potentialCollisionsBB.addAll(entityAABBs); - final Vec3 collided = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currentBox, potentialCollisionsVoxel, potentialCollisionsBB); + final Vec3 collided = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currentBox, potentialCollisionsVoxel, potentialCollisionsBB, this.physics); // Sakura - physics version api final boolean collidedX = collided.x != movement.x; final boolean collidedY = collided.y != movement.y; @@ -1947,7 +1962,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess private void checkInsideBlocks(List queuedCollisionChecks, Set collidedBlocks) { if (this.isAffectedByBlocks()) { - AABB axisalignedbb = this.getBoundingBox().deflate(9.999999747378752E-6D); + // Sakura start - physics version api + double offset = this.physics.afterOrEqual(1_21_2) ? 1.0E-5f : this.physics.afterOrEqual(1_19_3) ? 1.0E-7D : 0.001D; + AABB axisalignedbb = this.getBoundingBox().deflate(offset); + // Sakura end - physics version api LongSet longset = this.visitedBlocks; Iterator iterator = queuedCollisionChecks.iterator(); @@ -1955,7 +1973,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess Entity.Movement entity_b = (Entity.Movement) iterator.next(); Vec3 vec3d = entity_b.from(); Vec3 vec3d1 = entity_b.to(); - Iterator iterator1 = BlockGetter.boxTraverseBlocks(vec3d, vec3d1, axisalignedbb).iterator(); + // Sakura start - physics version api + final Iterable positions; + if (this.physics.afterOrEqual(1_21_2)) { + positions = BlockGetter.boxTraverseBlocks(vec3d, vec3d1, axisalignedbb); + } else { + positions = BlockPos.betweenClosed(axisalignedbb); + } + final Iterator iterator1 = positions.iterator(); + // Sakura end - physics version api while (iterator1.hasNext()) { BlockPos blockposition = (BlockPos) iterator1.next(); 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 890f1d6f8ad740afb0b30208f7cd42594e4c9d20..7ec7cfde4ce47a7f4a64e83fa49ed7287684d6a0 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -147,6 +147,8 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti this.yo = y; this.zo = z; this.setStartPos(this.blockPosition()); + this.physics = world.localConfig().config(this.blockPosition()).physicsVersion; // Sakura - physics version api + this.eyeHeight = this.physics.isLegacy() ? 0.49f : this.eyeHeight; // Sakura - physics version api } public static FallingBlockEntity fall(Level world, BlockPos pos, BlockState state) { @@ -159,7 +161,11 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti 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 - physics version api world.addFreshEntity(entityfallingblock, spawnReason); // CraftBukkit return entityfallingblock; } @@ -207,10 +213,47 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti return this.heightParity ? this.getY() : super.getEyeY(); } // Sakura end - configure cannon mechanics + // Sakura start - physics version api + @Override + public final 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) this.level()).getChunkSource().blockChanged(blockposition); + } + this.discard(EntityRemoveEvent.Cause.DESPAWN); + } + } + // Sakura end - physics version api @Override protected double getDefaultGravity() { - return 0.04D; + return this.physics.before(1_14_0) ? 0.04F : 0.04D; // Sakura - physics version api } @Override @@ -220,6 +263,11 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } else { Block block = this.blockState.getBlock(); + // Sakura start - physics version api + if (this.time == 0 && this.physics.before(1_18_2)) { + this.removeBlockOnFall(block); + } + // Sakura end - physics version api ++this.time; this.applyGravity(); this.moveStripped(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise cannon entity movement @@ -240,8 +288,15 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti if (world instanceof ServerLevel) { ServerLevel worldserver = (ServerLevel) world; + // Sakura start - physics version api + if (this.physics.before(1_12_0)) { + this.setDeltaMovement(this.getDeltaMovement().scale(0.98F)); + } if (this.isAlive() || this.forceTickAfterTeleportToDuplicate) { - 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 - physics version api boolean flag = this.blockState.getBlock() instanceof ConcretePowderBlock; boolean flag1 = flag && this.level().getFluidState(blockposition).is(FluidTags.WATER); double d0 = this.getDeltaMovement().lengthSqr(); @@ -266,8 +321,11 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } else { BlockState iblockdata = this.level().getBlockState(blockposition); - this.setDeltaMovement(this.getDeltaMovement().multiply(0.7D, -0.5D, 0.7D)); - if (!iblockdata.is(Blocks.MOVING_PISTON)) { + // Sakura start - physics version api + double friction = this.physics.before(1_14_0) ? 0.7F : 0.7D; + this.setDeltaMovement(this.getDeltaMovement().multiply(friction, -0.5D, friction)); + if (!iblockdata.is(Blocks.MOVING_PISTON) && (flag1 || !this.physics.isWithin(1_9_0, 1_12_0) || this.isAbleToStackOnBlock())) { + // Sakura end - physics version api 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); @@ -335,7 +393,12 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } } - this.setDeltaMovement(this.getDeltaMovement().scale(0.98D)); + // Sakura start - physics version api + if (this.physics.afterOrEqual(1_12_0)) { + double drag = this.physics.before(1_14_0) ? 0.98F : 0.98D; + this.setDeltaMovement(this.getDeltaMovement().scale(drag)); + } + // Sakura end - physics version api } } 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 3e4935f4a07fa14152d1f55f069c49fdd2f3bc02..1231d99374ffa5d988e5b240be2da95f0002947c 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java @@ -108,6 +108,13 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak case Y -> this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0)); } // Sakura end - configure cannon mechanics + // 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()) { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0)); + } + // Sakura end - physics version api } @Override @@ -140,10 +147,26 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak } } // Sakura end - optimise tnt fluid state + // Sakura start - physics version api + @Override + public final double getEyeY() { + return this.physics.isLegacy() ? super.getEyeY() : this.getY(); + } + + @Override + public final 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 - physics version api @Override protected double getDefaultGravity() { - return 0.04D; + return this.physics.before(1_14_0) ? 0.04F : 0.04D; // Sakura - physics version api } @Override @@ -159,15 +182,19 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak return; } // Paper end - Configurable TNT height nerf - this.setDeltaMovement(this.getDeltaMovement().scale(0.98D)); + // Sakura start - physics version api + double drag = this.physics.before(1_14_0) ? 0.98F : 0.98D; + this.setDeltaMovement(this.getDeltaMovement().scale(drag)); if (this.onGround()) { - this.setDeltaMovement(this.getDeltaMovement().multiply(0.7D, -0.5D, 0.7D)); + double friction = this.physics.before(1_14_0) ? 0.7F : 0.7D; + this.setDeltaMovement(this.getDeltaMovement().multiply(friction, -0.5D, friction)); + // 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.respawnEntity(); // Sakura - merge cannon entities @@ -220,7 +247,11 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak if (event.isCancelled()) { return; } - this.level().explode(this, Explosion.getDefaultDamageSource(this.level(), this), this.usedPortal ? PrimedTnt.USED_PORTAL_DAMAGE_CALCULATOR : null, this.getX(), this.getY(0.0625D), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.TNT); + + // Sakura start - physics version api + double offsetY = this.physics.before(1_10_0) ? this.getY() + (double) 0.49f : this.getY(0.0625D); + this.level().explode(this, Explosion.getDefaultDamageSource(this.level(), this), this.usedPortal ? PrimedTnt.USED_PORTAL_DAMAGE_CALCULATOR : null, this.getX(), offsetY, this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.TNT); + // Sakura end - physics version api // CraftBukkit end } @@ -307,7 +338,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak // Paper start - Option to prevent TNT from moving in water @Override public boolean isPushedByFluid() { - return !level().paperConfig().fixes.preventTntFromMovingInWater && level().sakuraConfig().cannons.mechanics.tntFlowsInWater && super.isPushedByFluid(); // Sakura - configure cannon mechanics + return !level().paperConfig().fixes.preventTntFromMovingInWater && !this.physics.isLegacy() && level().sakuraConfig().cannons.mechanics.tntFlowsInWater && super.isPushedByFluid(); // Sakura - physics version api // Sakura - configure cannon mechanics } // Paper end - Option to prevent TNT from moving in water } diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 452a9fef94d093b637245c82d36dacbb1e1d86c5..b67c4bcc7afb074134344b5f239370290416934e 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -841,6 +841,170 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl return chunk != null ? chunk.getNoiseBiome(x, y, z) : this.getUncachedNoiseBiome(x, y, z); } // Paper end - optimise random ticking + // Sakura start - physics version api + public final net.minecraft.world.phys.BlockHitResult.Type clipLegacy(Vec3 from, Vec3 to) { + int toX = Mth.floor(to.x); + int toY = Mth.floor(to.y); + int toZ = Mth.floor(to.z); + int fromX = Mth.floor(from.x); + int fromY = Mth.floor(from.y); + int fromZ = Mth.floor(from.z); + + BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos(fromX, fromY, fromZ); + LevelChunk chunk = this.getChunkIfLoaded(fromX >> 4, fromZ >> 4); + if (chunk == null) { + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + + BlockState blockstate = chunk.getBlockState(blockPos); + VoxelShape shape = blockstate.getShape(this, blockPos); + for (AABB bb : shape.toAabbs()) { + if (this.clip(bb, blockPos, from, to)) { + return net.minecraft.world.phys.BlockHitResult.Type.BLOCK; + } + } + + for (int steps = 0; steps < 16; ++steps) { + if (fromX == toX && fromY == toY && fromZ == toZ) { + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + + boolean moveX = true; + boolean moveY = true; + boolean moveZ = true; + double d0 = 999.0D; + double d1 = 999.0D; + double d2 = 999.0D; + + if (toX > fromX) { + d0 = (double) fromX + 1.0D; + } else if (toX < fromX) { + d0 = (double) fromX + 0.0D; + } else { + moveX = false; + } + + if (toY > fromY) { + d1 = (double) fromY + 1.0D; + } else if (toY < fromY) { + d1 = (double) fromY + 0.0D; + } else { + moveY = false; + } + + if (toZ > fromZ) { + d2 = (double) fromZ + 1.0D; + } else if (toZ < fromZ) { + d2 = (double) fromZ + 0.0D; + } else { + moveZ = false; + } + + double d3 = 999.0D; + double d4 = 999.0D; + double d5 = 999.0D; + double d6 = to.x - from.x; + double d7 = to.y - from.y; + double d8 = to.z - from.z; + + if (moveX) d3 = (d0 - from.x) / d6; + if (moveY) d4 = (d1 - from.y) / d7; + if (moveZ) d5 = (d2 - from.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 moveDir; + if (d3 < d4 && d3 < d5) { + moveDir = toX > fromX ? Direction.WEST : Direction.EAST; + from = new Vec3(d0, from.y + d7 * d3, from.z + d8 * d3); + } else if (d4 < d5) { + moveDir = toY > fromY ? Direction.DOWN : Direction.UP; + from = new Vec3(from.x + d6 * d4, d1, from.z + d8 * d4); + } else { + moveDir = toZ > fromZ ? Direction.NORTH : Direction.SOUTH; + from = new Vec3(from.x + d6 * d5, from.y + d7 * d5, d2); + } + + fromX = Mth.floor(from.x) - (moveDir == Direction.EAST ? 1 : 0); + fromY = Mth.floor(from.y) - (moveDir == Direction.UP ? 1 : 0); + fromZ = Mth.floor(from.z) - (moveDir == Direction.SOUTH ? 1 : 0); + blockPos.set(fromX, fromY, fromZ); + + int chunkX = fromX >> 4; + int chunkZ = fromZ >> 4; + if (chunkX != chunk.locX || chunkZ != chunk.locZ) { + chunk = this.getChunkIfLoaded(chunkX, chunkZ); + } + if (chunk == null) { + return net.minecraft.world.phys.BlockHitResult.Type.MISS; + } + + blockstate = chunk.getBlockState(blockPos); + shape = blockstate.getShape(this, blockPos); + for (AABB bb : shape.toAabbs()) { + if (this.clip(bb, blockPos, from, to)) { + 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 = this.clip(bb.minX, x, vec3d.x); + double minYd = this.clip(bb.minY, y, vec3d.y); + double minZd = this.clip(bb.minZ, z, vec3d.z); + double maxXd = this.clip(bb.maxX, x, vec3d.x); + double maxYd = this.clip(bb.maxY, y, vec3d.y); + double maxZd = this.clip(bb.maxZ, z, vec3d.z); + + return this.clipX(vec3d, bb, minXd, y, z) || this.clipY(vec3d, bb, minYd, x, z) || this.clipZ(vec3d, bb, minZd, x, y) + || this.clipX(vec3d, bb, maxXd, y, z) || this.clipY(vec3d, bb, maxYd, x, z) || this.clipZ(vec3d, bb, maxZd, x, y); + } + + private double clip(double bound, double axisD, double axisN) { + if (axisD * axisD < 1.0000000116860974E-7D) { + return -1.0; + } + return (bound - axisN) / axisD; + } + + private boolean clipX(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(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(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 - physics version api public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(); // Sakura - explosion density cache public final me.samsuik.sakura.explosion.durable.DurableBlockManager durabilityManager = new me.samsuik.sakura.explosion.durable.DurableBlockManager(); // Sakura - explosion durable blocks diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java index 85c84333614a4e0739e39cb72d8e4015ed78e7b7..bdc3ff8cbe4e5eaa9d9a34f38fdd150f7368e33b 100644 --- a/src/main/java/net/minecraft/world/level/ServerExplosion.java +++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java @@ -413,6 +413,7 @@ public class ServerExplosion implements Explosion { } // Sakura end - explosion durable blocks private final boolean consistentRadius; // Sakura - consistent explosion radius + protected final me.samsuik.sakura.physics.PhysicsVersion physics; // Sakura - physics version api public ServerExplosion(ServerLevel world, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 pos, float power, boolean createFire, Explosion.BlockInteraction destructionType) { this.level = world; @@ -425,6 +426,7 @@ public class ServerExplosion implements Explosion { this.damageCalculator = behavior == null ? this.makeDamageCalculator(entity) : behavior; this.yield = this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F; // CraftBukkit this.consistentRadius = world.localConfig().config(BlockPos.containing(this.center)).consistentRadius; // Sakura - consistent explosion radius + this.physics = entity != null ? entity.physics() : world.localConfig().config(BlockPos.containing(this.center)).physicsVersion; // Sakura - physics version api } private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity entity) { @@ -456,8 +458,12 @@ public class ServerExplosion implements Explosion { final float density = entity.level().densityCache.getKnownDensity(vec3d1); if (density != me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) { hitResult = density != 0.0f ? net.minecraft.world.phys.HitResult.Type.MISS : net.minecraft.world.phys.HitResult.Type.BLOCK; + // Sakura start - physics version api + } else if (entity.physics().before(1_14_0)) { + hitResult = entity.level().clipLegacy(vec3d1, pos); } else { - hitResult = entity.level().clip(new ClipContext(vec3d1, pos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)).getType(); + hitResult = entity.level().clip(new ClipContext(vec3d1, pos, entity.physics().afterOrEqual(1_16_0) ? ClipContext.Block.COLLIDER : ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, entity)).getType(); + // Sakura end - physics version api } if (hitResult == HitResult.Type.MISS) { // Sakura end - replace density cache @@ -556,6 +562,14 @@ public class ServerExplosion implements Explosion { } if (cachedBlock.outOfWorld) { + // Sakura start - physics version api + if (this.physics.before(1_17_0)) { + currX += incX; + currY += incY; + currZ += incZ; + continue; + } + // Sakura end - physics version api break; } final BlockState iblockdata = cachedBlock.blockState; @@ -652,6 +666,12 @@ public class ServerExplosion implements Explosion { double d2 = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - this.center.y; double d3 = entity.getZ() - this.center.z; double d4 = Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3); + // Sakura start - physics version api + if (this.physics.before(1_17_0)) { + d0 = (float) d0; + d4 = (float) d4; + } + // Sakura end - physics version api if (d4 != 0.0D) { d1 /= d4; @@ -961,7 +981,7 @@ public class ServerExplosion implements Explosion { // Sakura start - replace density cache float blockDensity = this.level.densityCache.getDensity(vec3d, entity); if (blockDensity == me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) { - blockDensity = this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations + blockDensity = this.sakura_getSeenPercent(vec3d, entity); // Sakura - physics version api this.level.densityCache.putDensity(vec3d, entity, blockDensity); // Sakura end - replace density cache } @@ -969,6 +989,16 @@ public class ServerExplosion implements Explosion { return blockDensity; } + // Sakura start - physics version api + private float sakura_getSeenPercent(Vec3 vec3d, Entity entity) { + if (this.physics.afterOrEqual(1_16_0)) { + return this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations + } else { + return getSeenPercent(vec3d, entity); + } + } + // Sakura end - physics version api + static class CacheKey { private final Level world; private final double posX, posY, posZ; 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 3b15bff00aa5889608cd0cff686c8c300127893a..788a87531b82e321317e802581758cc514a6861b 100644 --- a/src/main/java/net/minecraft/world/level/block/FallingBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FallingBlock.java @@ -45,6 +45,15 @@ public abstract class FallingBlock extends Block implements Fallable { return super.updateShape(state, world, tickView, pos, direction, neighborPos, neighborState, random); } + // Sakura start - physics version api + @Override + public void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, net.minecraft.world.level.redstone.Orientation wireOrientation, boolean notify) { + if (world.localConfig().config(pos).physicsVersion.before(1_18_2)) { + world.scheduleTick(pos, this, this.getDelayAfterPlace()); + } + } + // Sakura end - physics version api + @Override protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { if (isFree(world.getBlockState(pos.below())) && pos.getY() >= world.getMinY()) { 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 5201a11503362c2d43a9eee028613137ac9ae451..4be9bb2539f9bd4b95f3ebfcea934fdea85fdfe7 100644 --- a/src/main/java/net/minecraft/world/level/block/FenceGateBlock.java +++ b/src/main/java/net/minecraft/world/level/block/FenceGateBlock.java @@ -185,8 +185,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 - physics version api + 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, (state.setValue(FenceGateBlock.POWERED, flag1)).setValue(FenceGateBlock.OPEN, openGate), 2); + // Sakura end - physics version api 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, (Holder) (flag1 ? GameEvent.BLOCK_OPEN : GameEvent.BLOCK_CLOSE), pos); diff --git a/src/main/java/net/minecraft/world/level/block/HoneyBlock.java b/src/main/java/net/minecraft/world/level/block/HoneyBlock.java index 5c360c6768582c1a35431739613e9b406875cc21..87c3a1a17db467714eaae19436cf65a00c16fede 100644 --- a/src/main/java/net/minecraft/world/level/block/HoneyBlock.java +++ b/src/main/java/net/minecraft/world/level/block/HoneyBlock.java @@ -70,11 +70,19 @@ public class HoneyBlock extends HalfTransparentBlock { super.entityInside(state, world, pos, entity); } - private static double getOldDeltaY(double d) { + // Sakura start - physics version api + private static double getOldDeltaY(double d, Entity entity) { + if (entity.physics().before(1_21_2)) { + return d; + } return d / 0.98F + 0.08; } - private static double getNewDeltaY(double d) { + private static double getNewDeltaY(double d, Entity entity) { + if (entity.physics().before(1_21_2)) { + return d; + } + // Sakura end - physics version api return (d - 0.08) * 0.98F; } @@ -83,7 +91,7 @@ public class HoneyBlock extends HalfTransparentBlock { return false; } else if (entity.getY() > (double)pos.getY() + 0.9375 - 1.0E-7) { return false; - } else if (getOldDeltaY(entity.getDeltaMovement().y) >= -0.08) { + } else if (getOldDeltaY(entity.getDeltaMovement().y, entity) >= -0.08) { // Sakura - physics version api return false; } else { double d = Math.abs((double)pos.getX() + 0.5 - entity.getX()); @@ -101,11 +109,13 @@ public class HoneyBlock extends HalfTransparentBlock { private void doSlideMovement(Entity entity) { Vec3 vec3 = entity.getDeltaMovement(); - if (getOldDeltaY(entity.getDeltaMovement().y) < -0.13) { - double d = -0.05 / getOldDeltaY(entity.getDeltaMovement().y); - entity.setDeltaMovement(new Vec3(vec3.x * d, getNewDeltaY(-0.05), vec3.z * d)); + // Sakura start - physics version api + if (getOldDeltaY(entity.getDeltaMovement().y, entity) < -0.13) { + double d = -0.05 / getOldDeltaY(entity.getDeltaMovement().y, entity); + entity.setDeltaMovement(new Vec3(vec3.x * d, getNewDeltaY(-0.05, entity), vec3.z * d)); } else { - entity.setDeltaMovement(new Vec3(vec3.x, getNewDeltaY(-0.05), vec3.z)); + entity.setDeltaMovement(new Vec3(vec3.x, getNewDeltaY(-0.05, entity), vec3.z)); + // Sakura end - physics version api } entity.resetFallDistance(); 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 2ac96a40a6d79a6291ebe3162b1e11a1cf0a88c0..f702c88e96f1f692074dc56f2212230d49db41fb 100644 --- a/src/main/java/net/minecraft/world/level/block/LadderBlock.java +++ b/src/main/java/net/minecraft/world/level/block/LadderBlock.java @@ -29,6 +29,21 @@ public class LadderBlock extends Block implements SimpleWaterloggedBlock { protected static final VoxelShape WEST_AABB = Block.box(13.0, 0.0, 0.0, 16.0, 16.0, 16.0); protected static final VoxelShape SOUTH_AABB = Block.box(0.0, 0.0, 0.0, 16.0, 16.0, 3.0); protected static final VoxelShape NORTH_AABB = Block.box(0.0, 0.0, 13.0, 16.0, 16.0, 16.0); + // Sakura start - physics version api + protected static final VoxelShape LEGACY_EAST_AABB = Block.box(0.0, 0.0, 0.0, 2.0, 16.0, 16.0); + protected static final VoxelShape LEGACY_WEST_AABB = Block.box(14.0, 0.0, 0.0, 16.0, 16.0, 16.0); + protected static final VoxelShape LEGACY_SOUTH_AABB = Block.box(0.0, 0.0, 0.0, 16.0, 16.0, 2.0); + protected static final VoxelShape LEGACY_NORTH_AABB = Block.box(0.0, 0.0, 14.0, 16.0, 16.0, 16.0); + + 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 - physics version api @Override public MapCodec codec() { @@ -40,8 +55,18 @@ public class LadderBlock extends Block implements SimpleWaterloggedBlock { this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(WATERLOGGED, Boolean.valueOf(false))); } + // Sakura start - physics version api + @Override + public final boolean hasDynamicShape() { + return true; + } + @Override protected 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 - physics version api 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 a2d023ff011f71f80032f02430a53d6a08a23623..9e0f4517069ee3fd16a60ccc214da68d518c7f85 100644 --- a/src/main/java/net/minecraft/world/level/block/LiquidBlock.java +++ b/src/main/java/net/minecraft/world/level/block/LiquidBlock.java @@ -193,8 +193,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 - physics version api + 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 - physics version api // 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 21f2c61023fadcce30452a02f067cd5d87e5d8dc..5d847016f6ee2d6340d8b2234ed35c3b9228632b 100644 --- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java @@ -571,6 +571,10 @@ public class RedStoneWireBlock extends Block { protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) { if (!player.getAbilities().mayBuild) { return InteractionResult.PASS; + // Sakura start - physics version api + } else if (world.localConfig().config(pos).physicsVersion.before(1_16_0)) { + return InteractionResult.PASS; + // Sakura end - physics version api } else { if (isCross(state) || isDot(state)) { BlockState blockState = 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 72320c6099a4b26235bab68570e7b7efad84740f..737d4c96e9078504e1dd7c4ffd7812a37acb809e 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 - physics version api @Override public MapCodec codec() { @@ -46,8 +47,18 @@ public class WaterlilyBlock extends BushBlock { } + // Sakura start - physics version api + @Override + public final boolean hasDynamicShape() { + return true; + } + @Override protected 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 - physics version api 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 b696597540d998c52ec3207ffd8bf658fde59215..485929a4e6e5600b799943fff19ab591dbe9ddc6 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 @@ -109,6 +109,17 @@ public class MovingPistonBlock extends BaseEntityBlock { @Override protected 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 - physics version api 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 4b51472502d08ea357da437afeb4b581979e9cff..6146c786730b2cd5e5883acbe19d1eecff68e7e3 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 @@ -174,6 +174,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 - physics version api 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 c5c297b1081c9ddbb3bd0a0947401041aa8fec7d..d37c3ef71b1034ce2422c6078aa0abe79430cfac 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 @@ -151,6 +151,11 @@ public class PistonHeadBlock extends DirectionalBlock { @Override protected 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 - physics version api return this.isFittingBase(state, blockState) || blockState.is(Blocks.MOVING_PISTON) && blockState.getValue(FACING) == state.getValue(FACING); } @@ -162,6 +167,10 @@ public class PistonHeadBlock extends DirectionalBlock { sourceBlock, ExperimentalRedstoneUtils.withFront(wireOrientation, state.getValue(FACING).getOpposite()) ); + // 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 - physics version api } } 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 f873061666cf7ba30b2b5dfe3b3a1ea85d2cdd4f..0b196a9a4b37fb432c0c965ee952742d59b43a13 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 @@ -165,6 +165,12 @@ public class PistonMovingBlockEntity extends BlockEntity { double i = 0.0; + // Sakura start - physics version api + if (entity.physics().before(1_11_0)) { + moveEntityByPistonFromDirection(direction, entity, aABB); + return; + } + // Sakura end - physics version api for (AABB aABB2 : list2) { AABB aABB3 = PistonMath.getMovementArea(moveByPositionAndProgress(pos, aABB2, blockEntity), direction, d); AABB aABB4 = entity.getBoundingBox(); @@ -298,18 +304,171 @@ 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 this.fixZeroWidthBB(new AABB(minX, minY, minZ, maxX, maxY, maxZ), dir); + } + + return null; + } + + private AABB fixZeroWidthBB(AABB bb, Direction dir) { + // Legacy behaviour relied on entities being able to collide with zero width shapes + // This is no longer possible, so we have to create a difference here for it to work + double expandX = bb.getXsize() == 0.0 ? 1.0e-5 * dir.getStepX() : 0; + double expandY = bb.getYsize() == 0.0 ? 1.0e-5 * dir.getStepY() : 0; + double expandZ = bb.getZsize() == 0.0 ? 1.0e-5 * dir.getStepZ() : 0; + + if (expandX != 0 || expandY != 0 || expandZ != 0) { + bb = bb.expandTowards(expandX, expandY, expandZ); + } + + return bb; + } + + public final 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); + 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 - physics version api public Direction getPushDirection() { return this.extending ? this.direction : this.direction.getOpposite(); } public static void tick(Level world, BlockPos pos, BlockState state, PistonMovingBlockEntity blockEntity) { + me.samsuik.sakura.physics.PhysicsVersion physicsVersion = world.localConfig().config(pos).physicsVersion; // Sakura - physics version api 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 - physics version api world.removeBlockEntity(pos); blockEntity.setRemoved(); if (world.getBlockState(pos).is(Blocks.MOVING_PISTON)) { @@ -331,12 +490,23 @@ 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 - physics version api } } 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 4613162b6e716e33a838c59171c486b9c4d4b097..45127421ccbd4375c5408c27963ef2fa6e29de2a 100644 --- a/src/main/java/net/minecraft/world/level/material/FlowingFluid.java +++ b/src/main/java/net/minecraft/world/level/material/FlowingFluid.java @@ -560,7 +560,7 @@ public abstract class FlowingFluid extends Fluid { this.spread(world, pos, blockState, fluidState); } - protected static int getLegacyLevel(FluidState state) { + public static int getLegacyLevel(FluidState state) { // Sakura - physics version api; 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 884db3e64cb22ed765beec8f11ea309fcf810207..e6ed1e46a4880743b7eeb73857b4b501971d6e29 100644 --- a/src/main/java/net/minecraft/world/level/material/LavaFluid.java +++ b/src/main/java/net/minecraft/world/level/material/LavaFluid.java @@ -176,7 +176,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 - physics version api + 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 - physics version api } @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 552925ba47c7475e2e1ec2ded0966f28ed3e50a5..66b9a574eb57c6fb2964825ecca7110d079fb7cc 100644 --- a/src/main/java/net/minecraft/world/level/material/WaterFluid.java +++ b/src/main/java/net/minecraft/world/level/material/WaterFluid.java @@ -121,7 +121,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 - physics version api + 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 - physics version api } @Override