From b1d4b8361571400d676ee3cb9b074b2519f4b540 Mon Sep 17 00:00:00 2001 From: Samsuik Date: Sun, 26 Oct 2025 00:14:37 +0100 Subject: [PATCH] Add sake mechanics server type --- .../mechanics/MinecraftMechanicsTarget.java | 1 + .../samsuik/sakura/mechanics/ServerType.java | 2 + .../0017-Configure-cannon-physics.patch | 100 +++++++++++++-- .../0019-Collide-with-non-solid-blocks.patch | 22 ++-- ...22-Add-entity-travel-distance-limits.patch | 6 +- .../0025-Optimise-hopper-ticking.patch | 10 +- ...ck-inside-blocks-and-traverse-blocks.patch | 14 +-- ...anilla-and-eigencraft-redstone-wires.patch | 12 +- ...e-block-counting-for-cannon-entities.patch | 12 +- .../dispensing/DispenseRelocationHandler.java | 118 ++++++++++++++++++ .../entity/dispensing/DispenserGroup.java | 15 +++ 11 files changed, 264 insertions(+), 48 deletions(-) create mode 100644 sakura-server/src/main/java/me/samsuik/sakura/entity/dispensing/DispenseRelocationHandler.java create mode 100644 sakura-server/src/main/java/me/samsuik/sakura/entity/dispensing/DispenserGroup.java diff --git a/sakura-api/src/main/java/me/samsuik/sakura/mechanics/MinecraftMechanicsTarget.java b/sakura-api/src/main/java/me/samsuik/sakura/mechanics/MinecraftMechanicsTarget.java index 8f6084a..ae4ec2b 100644 --- a/sakura-api/src/main/java/me/samsuik/sakura/mechanics/MinecraftMechanicsTarget.java +++ b/sakura-api/src/main/java/me/samsuik/sakura/mechanics/MinecraftMechanicsTarget.java @@ -76,6 +76,7 @@ public record MinecraftMechanicsTarget(short mechanicVersion, byte serverType) { final byte serverType = switch (serverPart.toLowerCase(Locale.ENGLISH)) { case "vanilla" -> ServerType.VANILLA; case "spigot" -> ServerType.SPIGOT; + case "sake" -> ServerType.SAKE; default -> ServerType.PAPER; }; diff --git a/sakura-api/src/main/java/me/samsuik/sakura/mechanics/ServerType.java b/sakura-api/src/main/java/me/samsuik/sakura/mechanics/ServerType.java index 90cd1d6..f58477a 100644 --- a/sakura-api/src/main/java/me/samsuik/sakura/mechanics/ServerType.java +++ b/sakura-api/src/main/java/me/samsuik/sakura/mechanics/ServerType.java @@ -10,12 +10,14 @@ public final class ServerType { public static final byte VANILLA = 0; public static final byte SPIGOT = 1; public static final byte PAPER = 2; + public static final byte SAKE = 32; public static String name(final byte serverType) { return switch (serverType) { case 0 -> "vanilla"; case 1 -> "spigot"; case 2 -> "paper"; + case 33 -> "sake"; default -> "unknown"; }; } diff --git a/sakura-server/minecraft-patches/features/0017-Configure-cannon-physics.patch b/sakura-server/minecraft-patches/features/0017-Configure-cannon-physics.patch index 5808ef7..540796f 100644 --- a/sakura-server/minecraft-patches/features/0017-Configure-cannon-physics.patch +++ b/sakura-server/minecraft-patches/features/0017-Configure-cannon-physics.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Configure cannon physics diff --git a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java -index 82dac4fbaf3572391dad61356ba5351b725194ff..046f8f2e9b78a7286347713727d29150b318c1a9 100644 +index 82dac4fbaf3572391dad61356ba5351b725194ff..4c18fcd50c79e767bfea908ca6660b667f9d359b 100644 --- a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java +++ b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java @@ -1774,6 +1774,13 @@ public final class CollisionUtil { @@ -63,11 +63,36 @@ index 82dac4fbaf3572391dad61356ba5351b725194ff..046f8f2e9b78a7286347713727d29150 if (xSmaller && z != 0.0) { z = performAABBCollisionsZ(axisalignedbb, z, aabbs); +@@ -1886,6 +1905,7 @@ public final class CollisionUtil { + public static final int COLLISION_FLAG_CHECK_BORDER = 1 << 2; + public static final int COLLISION_FLAG_CHECK_ONLY = 1 << 3; + public static final int COLLISION_FLAG_ADD_TICKET = 1 << 4; // Sakura - load chunks on movement ++ public static final int COLLISION_FLAG_SKIP_EDGES = 1 << 5; // Sakura - configure server mechanics + + public static boolean getCollisionsForBlocksOrWorldBorder(final Level world, final Entity entity, final AABB aabb, + final List intoVoxel, final List intoAABB, +@@ -1939,6 +1959,7 @@ public final class CollisionUtil { + + final boolean loadChunks = (collisionFlags & COLLISION_FLAG_LOAD_CHUNKS) != 0; + final boolean addTicket = (collisionFlags & COLLISION_FLAG_ADD_TICKET) != 0; // Sakura - load chunks on movement ++ final boolean skipEdges = (collisionFlags & COLLISION_FLAG_SKIP_EDGES) != 0; // Sakura - configure server mechanics + final ChunkSource chunkSource = world.getChunkSource(); + + for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { +@@ -1981,7 +2002,7 @@ public final class CollisionUtil { + continue; + } + +- final boolean hasSpecial = ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); ++ final boolean hasSpecial = !skipEdges && ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); // Sakura - configure server mechanics + final int sectionAdjust = !hasSpecial ? 1 : 0; + + final PalettedContainer blocks = section.states; diff --git a/net/minecraft/core/dispenser/DispenseItemBehavior.java b/net/minecraft/core/dispenser/DispenseItemBehavior.java -index 703a75c7c6cd05a95afb630973250898dbc7223d..b35d9435c88a212151bb46fb35cf172637f72066 100644 +index 703a75c7c6cd05a95afb630973250898dbc7223d..b6ad2d3475ae28103d2bd0fb869da962ba6148ce 100644 --- a/net/minecraft/core/dispenser/DispenseItemBehavior.java +++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -471,6 +471,14 @@ public interface DispenseItemBehavior { +@@ -471,6 +471,22 @@ public interface DispenseItemBehavior { } } @@ -78,12 +103,32 @@ index 703a75c7c6cd05a95afb630973250898dbc7223d..b35d9435c88a212151bb46fb35cf1726 + && !mechanicTarget.isLegacy()) { + event.setVelocity(event.getVelocity().setY(event.getVelocity().getY() + 0.5)); + } ++ ++ if (mechanicTarget.isServerType(me.samsuik.sakura.mechanics.ServerType.SAKE)) { ++ final BlockPos originalSpawnPos = org.bukkit.craftbukkit.util.CraftVector.toBlockPos(event.getVelocity()); ++ final BlockPos spawnPos = serverLevel.dispenseRelocationHandler.relocatePosition(originalSpawnPos, blockSource.pos(), blockSource.state()); ++ final net.minecraft.world.phys.Vec3 centeredPos = net.minecraft.world.phys.Vec3.atBottomCenterOf(spawnPos); ++ ++ event.setVelocity(org.bukkit.craftbukkit.util.CraftVector.toBukkit(centeredPos)); ++ } + // Sakura end - configure server mechanics PrimedTnt primedTnt = new PrimedTnt(serverLevel, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), null); // CraftBukkit end serverLevel.addFreshEntity(primedTnt); +diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java +index f6e3cc7659175b29b238f7a0ff12f96d035a7b6a..b199cc18e72bfa011f6dc3a7a9e846252011d268 100644 +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -718,6 +718,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.levelTickScheduler.repeatingTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings + this.levelTickScheduler.repeatingTask(this.mergeHandler::expire, 200); // Sakura - merge cannon entities + this.levelTickScheduler.repeatingTask(this.densityCache::expire, 0); // Sakura - explosion density cache ++ this.levelTickScheduler.repeatingTask(this.dispenseRelocationHandler::clear, 0); // Sakura - configure server mechanics + } + + // Paper start diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 31fa5bb8a9d0076ea8072177f298f55ae3e2ee59..e19de1e6c38ec2375a24808d22525ec3f9178461 100644 +index 31fa5bb8a9d0076ea8072177f298f55ae3e2ee59..57e2f0ffa70808e646c3a54c6d11eff10c0a94cd 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -588,6 +588,13 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name @@ -192,6 +237,15 @@ index 31fa5bb8a9d0076ea8072177f298f55ae3e2ee59..e19de1e6c38ec2375a24808d22525ec3 this.finalMovementsThisTick.add(new Entity.Movement(this.oldPosition(), this.position())); } else if (this.finalMovementsThisTick.getLast().to.distanceToSqr(this.position()) > 9.9999994E-11F) { this.finalMovementsThisTick.add(new Entity.Movement(this.finalMovementsThisTick.getLast().to, this.position())); +@@ -1568,7 +1596,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name + final List potentialCollisionsBB = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(4); + final AABB currBoundingBox = this.getBoundingBox(); + +- if (movement.lengthSqr() >= 12.0) { // axis scan on large movement ++ if (movement.lengthSqr() >= 12.0 || this.mechanicsTarget.isServerType(me.samsuik.sakura.mechanics.ServerType.SAKE)) { // axis scan on large movement // Sakura - configure server mechanics + return this.collideAxisScan(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB); + } else { + return this.collideCube(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB); @@ -1588,7 +1616,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } @@ -210,7 +264,21 @@ index 31fa5bb8a9d0076ea8072177f298f55ae3e2ee59..e19de1e6c38ec2375a24808d22525ec3 if (y != 0.0) { y = this.scanY(currBoundingBox, y, voxelList, bbList); -@@ -1718,7 +1746,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1647,7 +1675,12 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name + + private double scanY(final AABB currBoundingBox, double y, final List voxelList, final List bbList) { + final AABB scanBox = cutBoundingBoxY(currBoundingBox, y); +- this.collectCollisions(scanBox, voxelList, bbList, 0); ++ // Sakura start - configure server mechanics ++ final int flags = this.mechanicsTarget.isServerType(me.samsuik.sakura.mechanics.ServerType.SAKE) ++ ? ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_SKIP_EDGES ++ : 0; ++ this.collectCollisions(scanBox, voxelList, bbList, flags); ++ // Sakura end - configure server mechanics + y = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsY(currBoundingBox, y, bbList); + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsY(currBoundingBox, y, voxelList); + } +@@ -1718,7 +1751,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER | this.getExtraCollisionFlags(), null // Sakura - load chunks on movement ); potentialCollisionsBB.addAll(entityAABBs); @@ -219,7 +287,7 @@ index 31fa5bb8a9d0076ea8072177f298f55ae3e2ee59..e19de1e6c38ec2375a24808d22525ec3 final boolean collidedX = collided.x != movement.x; final boolean collidedY = collided.y != movement.y; -@@ -1841,25 +1869,37 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1841,25 +1874,37 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name private void checkInsideBlocks(List movements, InsideBlockEffectApplier.StepBasedCollector stepBasedCollector) { if (this.isAffectedByBlocks()) { LongSet set = this.visitedBlocks; @@ -262,7 +330,7 @@ index 31fa5bb8a9d0076ea8072177f298f55ae3e2ee59..e19de1e6c38ec2375a24808d22525ec3 this.checkInsideBlocks(movement.to(), movement.to(), stepBasedCollector, set, 1); } } -@@ -1869,8 +1909,20 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1869,8 +1914,20 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } private int checkInsideBlocks(Vec3 from, Vec3 to, InsideBlockEffectApplier.StepBasedCollector stepBasedCollector, LongSet visited, int maxSteps) { @@ -285,7 +353,7 @@ index 31fa5bb8a9d0076ea8072177f298f55ae3e2ee59..e19de1e6c38ec2375a24808d22525ec3 boolean flag1 = this.level instanceof ServerLevel serverLevel && serverLevel.getServer().debugSubscribers().hasAnySubscriberFor(DebugSubscriptions.ENTITY_BLOCK_INTERSECTIONS); AtomicInteger atomicInteger = new AtomicInteger(); -@@ -1878,6 +1930,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1878,6 +1935,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name from, to, aabb, @@ -293,7 +361,7 @@ index 31fa5bb8a9d0076ea8072177f298f55ae3e2ee59..e19de1e6c38ec2375a24808d22525ec3 (pos, index) -> { if (!this.isAlive()) { return false; -@@ -1897,7 +1950,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1897,7 +1955,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name boolean flag2 = entityInsideCollisionShape == Shapes.block() || this.collidedWithShapeMovingFrom(from, to, entityInsideCollisionShape.move(new Vec3(pos)).toAabbs()); boolean flag3 = this.collidedWithFluid(blockState.getFluidState(), pos, from, to); @@ -302,7 +370,7 @@ index 31fa5bb8a9d0076ea8072177f298f55ae3e2ee59..e19de1e6c38ec2375a24808d22525ec3 if (flag2) { try { boolean flag4 = flag || aabb.intersects(pos); -@@ -1953,6 +2006,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1953,6 +2011,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } public boolean collidedWithShapeMovingFrom(Vec3 from, Vec3 to, List boxes) { @@ -609,6 +677,18 @@ index 867846ce62ffc5440d07084c79b2dd752bbe82c9..bf232ac4a4933c125535f8ea959d07fb if (i < 0) { return false; } else { +diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java +index 807d88528e22117b7fb4090c859c48e38c8be385..5a8826584fd02886a9ffc624c61ad26086f07a80 100644 +--- a/net/minecraft/world/level/Level.java ++++ b/net/minecraft/world/level/Level.java +@@ -836,6 +836,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + 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(this); // Sakura - optimise explosion density cache + public final me.samsuik.sakura.explosion.durable.DurableBlockManager durabilityManager = new me.samsuik.sakura.explosion.durable.DurableBlockManager(); // Sakura - explosion durable blocks ++ public final me.samsuik.sakura.entity.dispensing.DispenseRelocationHandler dispenseRelocationHandler = new me.samsuik.sakura.entity.dispensing.DispenseRelocationHandler(this); // Sakura - configure server mechanics + + protected Level( + WritableLevelData levelData, diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java index b13aae809e974b42bc1b17f4f4455999adca6f5f..0a279388e965a8d059189a8dfdbec3ff951af876 100644 --- a/net/minecraft/world/level/ServerExplosion.java diff --git a/sakura-server/minecraft-patches/features/0019-Collide-with-non-solid-blocks.patch b/sakura-server/minecraft-patches/features/0019-Collide-with-non-solid-blocks.patch index fa0712d..3b3190e 100644 --- a/sakura-server/minecraft-patches/features/0019-Collide-with-non-solid-blocks.patch +++ b/sakura-server/minecraft-patches/features/0019-Collide-with-non-solid-blocks.patch @@ -5,35 +5,35 @@ Subject: [PATCH] Collide with non-solid blocks diff --git a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java -index 0f0f1cb55bc167071e84ec998469001374995e8f..54d561e1b4069df7115457accb0763fa7586dddc 100644 +index 4c18fcd50c79e767bfea908ca6660b667f9d359b..5d95d8747c4816d27bab6455b3bdfb7b50ae265f 100644 --- a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java +++ b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java -@@ -1905,6 +1905,7 @@ public final class CollisionUtil { - public static final int COLLISION_FLAG_CHECK_BORDER = 1 << 2; +@@ -1906,6 +1906,7 @@ public final class CollisionUtil { public static final int COLLISION_FLAG_CHECK_ONLY = 1 << 3; public static final int COLLISION_FLAG_ADD_TICKET = 1 << 4; // Sakura - load chunks on movement -+ public static final int COLLISION_FLAG_FULL_BLOCKS = 1 << 5; // Sakura - collide with non-solid blocks + public static final int COLLISION_FLAG_SKIP_EDGES = 1 << 5; // Sakura - configure server mechanics ++ public static final int COLLISION_FLAG_FULL_BLOCKS = 1 << 6; // Sakura - collide with non-solid blocks public static boolean getCollisionsForBlocksOrWorldBorder(final Level world, final Entity entity, final AABB aabb, final List intoVoxel, final List intoAABB, -@@ -1958,6 +1959,7 @@ public final class CollisionUtil { - +@@ -1960,6 +1961,7 @@ public final class CollisionUtil { final boolean loadChunks = (collisionFlags & COLLISION_FLAG_LOAD_CHUNKS) != 0; final boolean addTicket = (collisionFlags & COLLISION_FLAG_ADD_TICKET) != 0; // Sakura - load chunks on movement + final boolean skipEdges = (collisionFlags & COLLISION_FLAG_SKIP_EDGES) != 0; // Sakura - configure server mechanics + final boolean fullBlocks = (collisionFlags & COLLISION_FLAG_FULL_BLOCKS) != 0; // Sakura - collide with non-solid blocks final ChunkSource chunkSource = world.getChunkSource(); for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { -@@ -2000,7 +2002,7 @@ public final class CollisionUtil { +@@ -2002,7 +2004,7 @@ public final class CollisionUtil { continue; } -- final boolean hasSpecial = ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); -+ final boolean hasSpecial = !fullBlocks && section.moonrise$hasSpecialCollidingBlocks(); // Sakura - collide with non-solid blocks +- final boolean hasSpecial = !skipEdges && ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); // Sakura - configure server mechanics ++ final boolean hasSpecial = !fullBlocks && !skipEdges && ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); // Sakura - configure server mechanics final int sectionAdjust = !hasSpecial ? 1 : 0; final PalettedContainer blocks = section.states; -@@ -2039,6 +2041,11 @@ public final class CollisionUtil { +@@ -2041,6 +2043,11 @@ public final class CollisionUtil { mutablePos.set(blockX, blockY, blockZ); if (useEntityCollisionShape) { blockCollision = collisionShape.getCollisionShape(blockData, world, mutablePos); @@ -46,7 +46,7 @@ index 0f0f1cb55bc167071e84ec998469001374995e8f..54d561e1b4069df7115457accb0763fa blockCollision = blockData.getCollisionShape(world, mutablePos, collisionShape); } diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 87948a1f3ff9b9e5ac2de8e4eb033e31a6818a2e..6d1edbfd851737d19ce0a3ffa4914c6beecaa440 100644 +index 57e2f0ffa70808e646c3a54c6d11eff10c0a94cd..f0e6cd81d358fa90d99d2123b77a56bc6936a34e 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -549,6 +549,14 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name diff --git a/sakura-server/minecraft-patches/features/0022-Add-entity-travel-distance-limits.patch b/sakura-server/minecraft-patches/features/0022-Add-entity-travel-distance-limits.patch index 99da53d..2e44e9a 100644 --- a/sakura-server/minecraft-patches/features/0022-Add-entity-travel-distance-limits.patch +++ b/sakura-server/minecraft-patches/features/0022-Add-entity-travel-distance-limits.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add entity travel distance limits diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index f6e3cc7659175b29b238f7a0ff12f96d035a7b6a..d68056892cf9f41be819e76535e6cbe553958867 100644 +index b199cc18e72bfa011f6dc3a7a9e846252011d268..e7e5932235a4af05106e87a48f3df261fc33d96b 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -1343,6 +1343,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1344,6 +1344,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe final boolean isActive = io.papermc.paper.entity.activation.ActivationRange.checkIfActive(entity); // Paper - EAR 2 if (isActive) { // Paper - EAR 2 entity.tick(); @@ -21,7 +21,7 @@ index f6e3cc7659175b29b238f7a0ff12f96d035a7b6a..d68056892cf9f41be819e76535e6cbe5 } else {entity.inactiveTick();} // Paper - EAR 2 profilerFiller.pop(); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 0ff02180233e72266f6997aa6edb7878881c0ba1..2d54ee2493f03af8fb5cb1a44a2e802742675042 100644 +index f0e6cd81d358fa90d99d2123b77a56bc6936a34e..43b16fcacf05872e394594d35b34930316fc1917 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -603,6 +603,18 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name diff --git a/sakura-server/minecraft-patches/features/0025-Optimise-hopper-ticking.patch b/sakura-server/minecraft-patches/features/0025-Optimise-hopper-ticking.patch index 9156b83..fb7554d 100644 --- a/sakura-server/minecraft-patches/features/0025-Optimise-hopper-ticking.patch +++ b/sakura-server/minecraft-patches/features/0025-Optimise-hopper-ticking.patch @@ -42,10 +42,10 @@ index 8e6f097b4d17aaaf8eccc16e11ce2bd01ad63322..4baa578a2d277676647ca60487a104f8 boolean isEmpty(); diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 1da42c11174bb7eae9a827a17a57d5e7f1d80f09..7aa5ffc32835fab4a91db464d9112785475a67e9 100644 +index 5a8826584fd02886a9ffc624c61ad26086f07a80..037afee0806646ae813bc4f067f4d7600d624b18 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -1434,7 +1434,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1435,7 +1435,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl // Spigot end if (tickingBlockEntity.isRemoved()) { toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll @@ -55,7 +55,7 @@ index 1da42c11174bb7eae9a827a17a57d5e7f1d80f09..7aa5ffc32835fab4a91db464d9112785 // Paper start - rewrite chunk system if ((++tickedEntities & 7) == 0) { diff --git a/net/minecraft/world/level/block/HopperBlock.java b/net/minecraft/world/level/block/HopperBlock.java -index 73b602eee0da94f657b4b4cb654147f7ba41c1a4..caa1f6dfafd7466e12efcc99aa447d285b938fe3 100644 +index 2a6d5790ac3bc4984937c5b6d70f8f49f2c59116..bc247852e06ca4b488cdb6a44051dc7733ce0fdd 100644 --- a/net/minecraft/world/level/block/HopperBlock.java +++ b/net/minecraft/world/level/block/HopperBlock.java @@ -121,6 +121,12 @@ public class HopperBlock extends BaseEntityBlock { @@ -72,7 +72,7 @@ index 73b602eee0da94f657b4b4cb654147f7ba41c1a4..caa1f6dfafd7466e12efcc99aa447d28 } } diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java -index 39691f6ff8dc08c7d4ebff0612cb9777d809c6ed..037534185be3afd434f0a19f4a4e6de43e947ca0 100644 +index bd038bdaa00fb1e09b098b4d2809d17e2382288b..37b0e4463660fd4a6830df6047f271ea0c70a091 100644 --- a/net/minecraft/world/level/block/entity/BlockEntity.java +++ b/net/minecraft/world/level/block/entity/BlockEntity.java @@ -52,6 +52,60 @@ public abstract class BlockEntity implements DebugValueSource { @@ -287,7 +287,7 @@ index 28e3b73507b988f7234cbf29c4024c88180d0aef..a0d247aa883553708c4b921582324255 + // Sakura end - optimise hopper ticking } diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index c7454fc77f7b269608edf6d6f3e39d9d96e037a0..4b9efc2843bb090871374f0a0bc9d8298760b7ec 100644 +index 7d62bc664ec6d26a41571c78ec3229604ac625f5..a0afed8dcf0c215ba3f79d6dbff1eb55c97dac15 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -1017,6 +1017,13 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot diff --git a/sakura-server/minecraft-patches/features/0026-Optimise-check-inside-blocks-and-traverse-blocks.patch b/sakura-server/minecraft-patches/features/0026-Optimise-check-inside-blocks-and-traverse-blocks.patch index 5ffafec..e2aeac6 100644 --- a/sakura-server/minecraft-patches/features/0026-Optimise-check-inside-blocks-and-traverse-blocks.patch +++ b/sakura-server/minecraft-patches/features/0026-Optimise-check-inside-blocks-and-traverse-blocks.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimise check inside blocks and traverse blocks diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 5aa283ac6eb9f3690f9df1938ac08da77d29142e..438013200908d3cdb0677b551c3890c7f87b5dc1 100644 +index f2d4e2e8b5b53fea5966999dc75b15833205f139..d0d75402c8e0647abccfa1597a94faeb6f89e9f6 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -1938,6 +1938,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1943,6 +1943,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name if (this.isAffectedByBlocks()) { LongSet set = this.visitedBlocks; final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = this.mechanicsTarget; // Sakura - configure server mechanics @@ -16,7 +16,7 @@ index 5aa283ac6eb9f3690f9df1938ac08da77d29142e..438013200908d3cdb0677b551c3890c7 for (Entity.Movement movement : movements) { Vec3 vec3 = movement.from; -@@ -1955,7 +1956,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1960,7 +1961,7 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name double d = vec31.get(axis); if (d != 0.0) { Vec3 vec32 = vec3.relative(axis.getPositive(), d); @@ -25,7 +25,7 @@ index 5aa283ac6eb9f3690f9df1938ac08da77d29142e..438013200908d3cdb0677b551c3890c7 if (mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_9)) { i -= stepsTaken; } -@@ -1963,12 +1964,12 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1968,12 +1969,12 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } } } else if (mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_2)) { @@ -40,7 +40,7 @@ index 5aa283ac6eb9f3690f9df1938ac08da77d29142e..438013200908d3cdb0677b551c3890c7 } } -@@ -1976,7 +1977,16 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -1981,7 +1982,16 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name } } @@ -58,7 +58,7 @@ index 5aa283ac6eb9f3690f9df1938ac08da77d29142e..438013200908d3cdb0677b551c3890c7 // Sakura start - configure server mechanics final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = this.mechanicsTarget; final double margin; -@@ -2006,7 +2016,20 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name +@@ -2011,7 +2021,20 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name return false; } else { atomicInteger.set(index); @@ -81,7 +81,7 @@ index 5aa283ac6eb9f3690f9df1938ac08da77d29142e..438013200908d3cdb0677b551c3890c7 if (flag1) { this.debugBlockIntersection((ServerLevel)this.level(), pos.immutable(), false, false); diff --git a/net/minecraft/world/level/BlockGetter.java b/net/minecraft/world/level/BlockGetter.java -index 3c2f5d40bccaf6582a41079d1c47eb228c72a6ff..32663495d8ac10e76f0995850adf908b4a8258d3 100644 +index bf232ac4a4933c125535f8ea959d07fbcca58336..8928285530038a89781682230929d51157a3516f 100644 --- a/net/minecraft/world/level/BlockGetter.java +++ b/net/minecraft/world/level/BlockGetter.java @@ -231,7 +231,7 @@ public interface BlockGetter extends LevelHeightAccessor { diff --git a/sakura-server/minecraft-patches/features/0028-Cache-vanilla-and-eigencraft-redstone-wires.patch b/sakura-server/minecraft-patches/features/0028-Cache-vanilla-and-eigencraft-redstone-wires.patch index b4b2868..2a23f4f 100644 --- a/sakura-server/minecraft-patches/features/0028-Cache-vanilla-and-eigencraft-redstone-wires.patch +++ b/sakura-server/minecraft-patches/features/0028-Cache-vanilla-and-eigencraft-redstone-wires.patch @@ -33,25 +33,25 @@ index ff747a1ecdf3c888bca0d69de4f85dcd810b6139..d90f6aa4557b5863eba6a206226f763c } diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index d68056892cf9f41be819e76535e6cbe553958867..c00d922188a11a90902bb51cd73977855c3fb6ca 100644 +index e7e5932235a4af05106e87a48f3df261fc33d96b..92d315bcb54a0b72dc0befc6550cc46174ad290b 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -718,6 +718,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.levelTickScheduler.repeatingTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings +@@ -719,6 +719,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.levelTickScheduler.repeatingTask(this.mergeHandler::expire, 200); // Sakura - merge cannon entities this.levelTickScheduler.repeatingTask(this.densityCache::expire, 0); // Sakura - explosion density cache + this.levelTickScheduler.repeatingTask(this.dispenseRelocationHandler::clear, 0); // Sakura - configure server mechanics + this.levelTickScheduler.repeatingTask(this.redstoneWireCache::expire, 300); // Sakura - cache vanilla and eigencraft wires } // Paper start diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 89e89f79a56098c5bcf33dea874fcf0234a071e8..859986b30af1ed33ebebfa99bef168b3bccb60e9 100644 +index 037afee0806646ae813bc4f067f4d7600d624b18..378a88bbb605e22c74e5f2eea30dd9a3431c2c12 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java -@@ -836,6 +836,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities +@@ -837,6 +837,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(this); // Sakura - optimise explosion density cache public final me.samsuik.sakura.explosion.durable.DurableBlockManager durabilityManager = new me.samsuik.sakura.explosion.durable.DurableBlockManager(); // Sakura - explosion durable blocks + public final me.samsuik.sakura.entity.dispensing.DispenseRelocationHandler dispenseRelocationHandler = new me.samsuik.sakura.entity.dispensing.DispenseRelocationHandler(this); // Sakura - configure server mechanics + public final me.samsuik.sakura.redstone.cache.RedstoneWireCache redstoneWireCache = new me.samsuik.sakura.redstone.cache.RedstoneWireCache(this); // Sakura - cache vanilla and eigencraft wires protected Level( diff --git a/sakura-server/minecraft-patches/features/0030-Optimise-block-counting-for-cannon-entities.patch b/sakura-server/minecraft-patches/features/0030-Optimise-block-counting-for-cannon-entities.patch index 88b37fd..5fefdca 100644 --- a/sakura-server/minecraft-patches/features/0030-Optimise-block-counting-for-cannon-entities.patch +++ b/sakura-server/minecraft-patches/features/0030-Optimise-block-counting-for-cannon-entities.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimise block counting for cannon entities diff --git a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java -index 3231c86488806376b086bc26ceba77a509105b81..7bb7eba143f294955eb6b4033b518ea99e428466 100644 +index 5d95d8747c4816d27bab6455b3bdfb7b50ae265f..079e887cac1a903af23c1a9ace47b9e388324909 100644 --- a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java +++ b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java -@@ -1941,6 +1941,7 @@ public final class CollisionUtil { +@@ -1942,6 +1942,7 @@ public final class CollisionUtil { final CollisionContext collisionShape = new LazyEntityCollisionContext(entity); final boolean useEntityCollisionShape = LazyEntityCollisionContext.useEntityCollisionShape(world, entity); final long gameTime = world.getGameTime(); // Sakura - load chunks on movement @@ -16,9 +16,9 @@ index 3231c86488806376b086bc26ceba77a509105b81..7bb7eba143f294955eb6b4033b518ea9 // special cases: if (minBlockY > maxBlockY) { -@@ -2004,15 +2005,19 @@ public final class CollisionUtil { +@@ -2006,15 +2007,19 @@ public final class CollisionUtil { - final boolean hasSpecial = !fullBlocks && section.moonrise$hasSpecialCollidingBlocks(); // Sakura - collide with non-solid blocks + final boolean hasSpecial = !fullBlocks && !skipEdges && ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); // Sakura - configure server mechanics final int sectionAdjust = !hasSpecial ? 1 : 0; + // Sakura start - optimise block counting for cannon entities + final boolean hasMovingBlocks = section.hasMovingPistonBlocks(); @@ -42,7 +42,7 @@ index 3231c86488806376b086bc26ceba77a509105b81..7bb7eba143f294955eb6b4033b518ea9 for (int currY = minYIterate; currY <= maxYIterate; ++currY) { final int blockY = currY | (currChunkY << 4); diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index a760757da12210b315baad6c3a3d6f52450e78b2..07352f9ca3e801de5cad99bb31317bc508a011cd 100644 +index 378a88bbb605e22c74e5f2eea30dd9a3431c2c12..ac83b2d1b0a7973fc128cf8b54421d5c8393405b 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -621,6 +621,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @@ -79,7 +79,7 @@ index a760757da12210b315baad6c3a3d6f52450e78b2..07352f9ca3e801de5cad99bb31317bc5 for (int currY = minYIterate; currY <= maxYIterate; ++currY) { final int blockY = currY | (currChunkY << 4); diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java -index 512835828f65f496c730122091d9bd117ca5eb78..6699f03354449f01291b1acaf334bfb24729f38a 100644 +index 955f97ea45c7b980f0f2c4321d27050bec1eabe5..db0b34e0e6b132715dd81a185a3401d80ec40708 100644 --- a/net/minecraft/world/level/chunk/LevelChunkSection.java +++ b/net/minecraft/world/level/chunk/LevelChunkSection.java @@ -63,6 +63,13 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_ diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/dispensing/DispenseRelocationHandler.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/dispensing/DispenseRelocationHandler.java new file mode 100644 index 0000000..08a76d3 --- /dev/null +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/dispensing/DispenseRelocationHandler.java @@ -0,0 +1,118 @@ +package me.samsuik.sakura.entity.dispensing; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.Container; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.DispenserBlock; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.*; + +/** + * Adjusts the dispense position when using the Sake mechanics server type. + *

+ * This attempts to replicate the behaviour found on Kore jars (Wine and Tequila). + */ +public final class DispenseRelocationHandler { + private final Level level; + private final Map groups = new HashMap<>(); + + public DispenseRelocationHandler(final Level level) { + this.level = level; + } + + public BlockPos relocatePosition(final BlockPos pos, final BlockPos sourcePos, final BlockState sourceState) { + DispenserGroup group = this.groups.get(sourcePos); + if (group == null) { + final Set connected = this.getConnectedDispensers(sourcePos, sourceState); + final DispenserGroup newGroup = new DispenserGroup(); + connected.forEach(dispenserPos -> groups.put(dispenserPos, newGroup)); + group = newGroup; + } + + return group.getSpawnPosition(pos); + } + + public void clear() { + this.groups.clear(); + } + + private Set getConnectedDispensers(final BlockPos pos, final BlockState state) { + // from testing in-game the expected behaviour is as follows: + // it checks horizontally then vertically for dispensers that meet the conditions + // - must be facing the same direction & powered + // - must be scheduled in the same tick + // - the block in front or the block below cannot have a collision shape + // - must have tnt in the first occupied slot + final Set dispensers = new HashSet<>(List.of(pos)); + final Direction facing = state.getValue(DispenserBlock.FACING); + + // if the source doesn't meet the conditions then don't search + if (!this.doesDispenserMeetConditions(pos, state, facing, true)) { + return dispensers; + } + + for (final Direction horizontalDirection : facing.getClockWise().getAxis().getDirections()) { + for (int distance = 1; distance < 64; ++distance) { + final BlockPos adjacentPos = pos.relative(horizontalDirection, distance); + final BlockState adjacentState = this.level.getBlockState(adjacentPos); + + if (state != adjacentState || !this.doesDispenserMeetConditions(adjacentPos, adjacentState, facing, false)) { + break; + } + + dispensers.add(adjacentPos); + } + } + + for (final BlockPos horizontalPos : List.copyOf(dispensers)) { + for (final Direction verticalDirection : Direction.Plane.VERTICAL) { + for (int distance = 1; distance < 384; ++distance) { + final BlockPos adjacentPos = horizontalPos.relative(verticalDirection, distance); + final BlockState adjacentState = this.level.getBlockState(adjacentPos); + + if (state != adjacentState || !this.doesDispenserMeetConditions(adjacentPos, adjacentState, facing, false)) { + break; + } + + dispensers.add(adjacentPos); + } + } + } + + return dispensers; + } + + private boolean doesDispenserMeetConditions(final BlockPos pos, final BlockState state, final Direction facing, final boolean source) { + if (!source && !this.level.getBlockTicks().willTickThisTick(pos, state.getBlock())) { + return false; + } + + final BlockState stateInFront = this.level.getBlockState(pos.relative(facing)); + final BlockState stateBeneath = this.level.getBlockState(pos.relative(facing).below()); + + if (!stateInFront.getCollisionShape(this.level, pos).isEmpty() && !stateBeneath.getCollisionShape(this.level, pos).isEmpty()) { + return false; + } + + final Container container = (Container) this.level.getBlockEntity(pos); + if (container == null) { + return false; // we should never get here, but you never know with FAWE + } + + for (int slot = 0; slot < container.getContainerSize(); ++slot) { + if (!isSlotEmptyOrHasTnt(container.getItem(slot))) { + return false; + } + } + + return true; + } + + private static boolean isSlotEmptyOrHasTnt(final ItemStack itemstack) { + return itemstack.isEmpty() || itemstack.is(Items.TNT); + } +} diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/dispensing/DispenserGroup.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/dispensing/DispenserGroup.java new file mode 100644 index 0000000..65ed0f3 --- /dev/null +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/dispensing/DispenserGroup.java @@ -0,0 +1,15 @@ +package me.samsuik.sakura.entity.dispensing; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; + +public final class DispenserGroup { + private final Long2ObjectMap columns = new Long2ObjectOpenHashMap<>(); + + public BlockPos getSpawnPosition(final BlockPos pos) { + final long column = ChunkPos.asLong(pos.getX(), pos.getZ()); + return this.columns.computeIfAbsent(column, c -> pos); + } +}