diff --git a/build-data/sakura.at b/build-data/sakura.at index b5ef3a5..6608c6f 100644 --- a/build-data/sakura.at +++ b/build-data/sakura.at @@ -18,11 +18,11 @@ protected-f net.minecraft.world.entity.Entity eyeHeight protected-f net.minecraft.world.level.ServerExplosion center public net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket chunkData public net.minecraft.server.level.ServerLevel entityTickList +public net.minecraft.world.entity.Entity addMovementThisTick(Lnet/minecraft/world/entity/Entity$Movement;)V +public net.minecraft.world.entity.Entity axisStepOrder(Lnet/minecraft/world/phys/Vec3;)Ljava/lang/Iterable; public net.minecraft.world.entity.Entity stuckSpeedMultiplier +public net.minecraft.world.entity.Entity$Movement public net.minecraft.world.level.Level neighborUpdater public net.minecraft.world.level.block.RedStoneWireBlock turbo public net.minecraft.world.level.entity.EntityTickList entities public net.minecraft.world.level.material.FlowingFluid getLegacyLevel(Lnet/minecraft/world/level/material/FluidState;)I -public net.minecraft.world.entity.Entity axisStepOrder(Lnet/minecraft/world/phys/Vec3;)Ljava/lang/Iterable; -public net.minecraft.world.entity.Entity$Movement -public net.minecraft.world.entity.Entity addMovementThisTick(Lnet/minecraft/world/entity/Entity$Movement;)V \ No newline at end of file diff --git a/sakura-api/paper-patches/features/0001-Client-Visibility-Settings-API.patch b/sakura-api/paper-patches/features/0001-Client-Visibility-Settings-API.patch index 38280a6..16aeb6b 100644 --- a/sakura-api/paper-patches/features/0001-Client-Visibility-Settings-API.patch +++ b/sakura-api/paper-patches/features/0001-Client-Visibility-Settings-API.patch @@ -5,12 +5,12 @@ Subject: [PATCH] Client Visibility Settings API diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java -index 8127c961793c5a5332fbb66fa95b8a0bf3fdc4df..3b51a842e85425c84fc7d8e52f13282d2cf6b3b5 100644 +index 7f48e073173094fdee63efa0eea1cbfc4e06ba7d..8f53905e57e0905c7f75f9a457cdb9c0a7bcfafe 100644 --- a/src/main/java/org/bukkit/entity/Player.java +++ b/src/main/java/org/bukkit/entity/Player.java @@ -70,6 +70,14 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM - void setTrackingRangeModifier(double mod); + void setTrackingRangeModifier(final double modifier); // Sakura end - entity tracking range modifier + // Sakura start - client visibility settings api + /** diff --git a/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch b/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch index b5497dc..caa4cb4 100644 --- a/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch +++ b/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/Entity.java.patch @@ -17,7 +17,7 @@ + * + * @param state whether entity should be pushed by fluid + */ -+ void setPushedByFluid(boolean state); ++ void setPushedByFluid(final boolean state); + // Sakura end - entity pushed by fluid api + /** diff --git a/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/FallingBlock.java.patch b/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/FallingBlock.java.patch index d1c9100..5d9aa72 100644 --- a/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/FallingBlock.java.patch +++ b/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/FallingBlock.java.patch @@ -17,7 +17,7 @@ + * + * @param parity value + */ -+ void setHeightParity(boolean parity); ++ void setHeightParity(final boolean parity); + // Sakura end - falling block height parity api + /** diff --git a/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch b/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch index d3e32ee..6f4f2fb 100644 --- a/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch +++ b/sakura-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch @@ -7,7 +7,7 @@ + // Sakura start - entity tracking range modifier + double getTrackingRangeModifier(); + -+ void setTrackingRangeModifier(double mod); ++ void setTrackingRangeModifier(final double modifier); + // Sakura end - entity tracking range modifier + // Paper start diff --git a/sakura-api/src/main/java/me/samsuik/sakura/entity/merge/MergeLevel.java b/sakura-api/src/main/java/me/samsuik/sakura/entity/merge/MergeLevel.java index f8010a9..616ce16 100644 --- a/sakura-api/src/main/java/me/samsuik/sakura/entity/merge/MergeLevel.java +++ b/sakura-api/src/main/java/me/samsuik/sakura/entity/merge/MergeLevel.java @@ -28,15 +28,15 @@ public enum MergeLevel { private final int level; - MergeLevel(int level) { + MergeLevel(final int level) { this.level = level; } - public boolean atLeast(MergeLevel level) { + public final boolean atLeast(MergeLevel level) { return this.getLevel() >= level.getLevel(); } - public int getLevel() { + public final int getLevel() { return this.level; } } diff --git a/sakura-api/src/main/java/me/samsuik/sakura/entity/merge/Mergeable.java b/sakura-api/src/main/java/me/samsuik/sakura/entity/merge/Mergeable.java index c33c461..9e62b50 100644 --- a/sakura-api/src/main/java/me/samsuik/sakura/entity/merge/Mergeable.java +++ b/sakura-api/src/main/java/me/samsuik/sakura/entity/merge/Mergeable.java @@ -6,7 +6,7 @@ import org.jspecify.annotations.NullMarked; public interface Mergeable { MergeLevel getMergeLevel(); - void setMergeLevel(MergeLevel level); + void setMergeLevel(final MergeLevel mergeLevel); int getStacked(); diff --git a/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilitySettings.java b/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilitySettings.java index 50ba48e..65e3d77 100644 --- a/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilitySettings.java +++ b/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilitySettings.java @@ -4,45 +4,47 @@ import org.jspecify.annotations.NullMarked; @NullMarked public interface VisibilitySettings { - default boolean isEnabled(VisibilityType type) { + default boolean isEnabled(final VisibilityType type) { return this.get(type) == VisibilityState.ON; } - default boolean isDisabled(VisibilityType type) { + default boolean isDisabled(final VisibilityType type) { return this.get(type) == VisibilityState.OFF; } - default boolean isToggled(VisibilityType type) { + default boolean isToggled(final VisibilityType type) { return !type.isDefault(this.get(type)); } - default VisibilityState toggle(VisibilityType type) { - VisibilityState state = this.get(type); + default VisibilityState toggle(final VisibilityType type) { + final VisibilityState state = this.get(type); return this.set(type, toggleState(state)); } - default VisibilityState cycle(VisibilityType type) { - VisibilityState state = this.get(type); + default VisibilityState cycle(final VisibilityType type) { + final VisibilityState state = this.get(type); return this.set(type, type.cycle(state)); } default void toggleAll() { - VisibilityState state = this.currentState(); - VisibilityState newState = toggleState(state); - for (VisibilityType type : VisibilityTypes.types()) { + final VisibilityState state = this.currentState(); + final VisibilityState newState = toggleState(state); + for (final VisibilityType type : VisibilityTypes.types()) { this.set(type, newState); } } - VisibilityState get(VisibilityType type); + VisibilityState get(final VisibilityType type); - VisibilityState set(VisibilityType type, VisibilityState state); + VisibilityState set(final VisibilityType type, final VisibilityState state); VisibilityState currentState(); boolean playerModified(); - static VisibilityState toggleState(VisibilityState state) { - return state != VisibilityState.OFF ? VisibilityState.OFF : VisibilityState.ON; + static VisibilityState toggleState(final VisibilityState state) { + return state != VisibilityState.OFF + ? VisibilityState.OFF + : VisibilityState.ON; } } diff --git a/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityState.java b/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityState.java index d9cb2ea..270e8c3 100644 --- a/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityState.java +++ b/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityState.java @@ -1,5 +1,8 @@ package me.samsuik.sakura.player.visibility; +/** + * The visibility state of a {@link VisibilityType}. + */ public enum VisibilityState { ON, MODIFIED, MINIMAL, OFF; } diff --git a/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityType.java b/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityType.java index 6b6b482..d5ac4c9 100644 --- a/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityType.java +++ b/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityType.java @@ -9,27 +9,27 @@ public record VisibilityType(String key, ImmutableList states) return this.states.getFirst(); } - public boolean isDefault(VisibilityState state) { + public boolean isDefault(final VisibilityState state) { return state == this.getDefault(); } - public VisibilityState cycle(VisibilityState state) { - int index = this.states.indexOf(state); - int next = (index + 1) % this.states.size(); + public VisibilityState cycle(final VisibilityState state) { + final int index = this.states.indexOf(state); + final int next = (index + 1) % this.states.size(); return this.states.get(next); } - public static VisibilityType from(String key, boolean minimal) { + public static VisibilityType from(final String key, final boolean minimal) { return new VisibilityType(key, states(minimal)); } - private static ImmutableList states(boolean minimal) { - ImmutableList.Builder listBuilder = ImmutableList.builder(); - listBuilder.add(VisibilityState.ON); + private static ImmutableList states(final boolean minimal) { + final ImmutableList.Builder states = ImmutableList.builder(); + states.add(VisibilityState.ON); if (minimal) { - listBuilder.add(VisibilityState.MINIMAL); + states.add(VisibilityState.MINIMAL); } - listBuilder.add(VisibilityState.OFF); - return listBuilder.build(); + states.add(VisibilityState.OFF); + return states.build(); } } diff --git a/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityTypes.java b/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityTypes.java index f323cfc..9b9dca9 100644 --- a/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityTypes.java +++ b/sakura-api/src/main/java/me/samsuik/sakura/player/visibility/VisibilityTypes.java @@ -10,22 +10,19 @@ import java.util.List; public final class VisibilityTypes { private static final List TYPES = new ArrayList<>(); - public static final VisibilityType TNT = register(create("tnt", true)); - public static final VisibilityType SAND = register(create("sand", true)); - public static final VisibilityType EXPLOSIONS = register(create("explosions", true)); - public static final VisibilityType SPAWNERS = register(create("spawners", false)); - public static final VisibilityType PISTONS = register(create("pistons", false)); + public static final VisibilityType TNT = create("tnt", true); + public static final VisibilityType SAND = create("sand", true); + public static final VisibilityType EXPLOSIONS = create("explosions", true); + public static final VisibilityType SPAWNERS = create("spawners", false); + public static final VisibilityType PISTONS = create("pistons", false); public static ImmutableList types() { return ImmutableList.copyOf(TYPES); } - private static VisibilityType create(String key, boolean minimal) { - return VisibilityType.from(key, minimal); - } - - private static VisibilityType register(VisibilityType type) { - TYPES.add(type); - return type; + private static VisibilityType create(final String key, final boolean minimal) { + final VisibilityType newVisibilityType = VisibilityType.from(key, minimal); + TYPES.add(newVisibilityType); + return newVisibilityType; } } diff --git a/sakura-server/minecraft-patches/features/0001-Track-block-changes-and-level-tick-scheduler.patch b/sakura-server/minecraft-patches/features/0001-Track-block-changes-and-level-tick-scheduler.patch index 26ca7e5..a5cc69b 100644 --- a/sakura-server/minecraft-patches/features/0001-Track-block-changes-and-level-tick-scheduler.patch +++ b/sakura-server/minecraft-patches/features/0001-Track-block-changes-and-level-tick-scheduler.patch @@ -5,19 +5,19 @@ Subject: [PATCH] Track block changes and level tick scheduler diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 61d5876aa60e8e257b5cdf8d343370153d58f841..84c00a30e15a703227e6161ba7929fbf43cf59cc 100644 +index 4dabb2a689d4bceb054e819e2fd53420e95a283d..65bd8e94d7d7b815a2c8fe2a6fd1fa1ad9e60bc6 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -1750,6 +1750,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop, AutoCl @@ -25,14 +25,14 @@ index c75099957654ee65edfafab449e665ea1fcddf5b..3ecb573ea476336f367bd3abbaff8e70 } // Paper end - optimise random ticking + // Sakura start - track block changes and tick scheduler -+ public final me.samsuik.sakura.listener.LevelTickScheduler levelTickScheduler = new me.samsuik.sakura.listener.LevelTickScheduler(); ++ public final me.samsuik.sakura.listener.LevelTickScheduler levelTickScheduler = new me.samsuik.sakura.listener.LevelTickScheduler(this); + public final me.samsuik.sakura.listener.BlockChangeTracker blockChangeTracker = new me.samsuik.sakura.listener.BlockChangeTracker(this); + // Sakura end - track block changes and tick scheduler protected Level( WritableLevelData levelData, diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index 75578e6ed7233a03d9b6cd3c6d3997f1c6148392..a2185062fbb123549be21e37e84541d61ec301c9 100644 +index 75578e6ed7233a03d9b6cd3c6d3997f1c6148392..a39077ba4e1e40462ee9a96ce6f3871a5ecb85c7 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -129,6 +129,21 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @@ -42,12 +42,12 @@ index 75578e6ed7233a03d9b6cd3c6d3997f1c6148392..a2185062fbb123549be21e37e84541d6 + // Sakura start - track block changes and tick scheduler + private java.util.List blockChangeListeners; + -+ public final void updateBlockChangeListeners(java.util.List listeners) { ++ public final void updateBlockChangeListeners(final java.util.List listeners) { + this.blockChangeListeners = listeners; + } + -+ private void blockChange(BlockPos pos, BlockState newBlock, BlockState oldBlock) { -+ for (me.samsuik.sakura.listener.BlockChangeTracker.Listener listener : this.blockChangeListeners) { ++ private void blockChange(final BlockPos pos, final BlockState newBlock, final BlockState oldBlock) { ++ for (final me.samsuik.sakura.listener.BlockChangeTracker.Listener listener : this.blockChangeListeners) { + if (listener.test(this.level, pos, newBlock, oldBlock)) { + listener.call(); + } diff --git a/sakura-server/minecraft-patches/features/0002-Client-Visibility-Settings.patch b/sakura-server/minecraft-patches/features/0002-Client-Visibility-Settings.patch index b014f85..c681374 100644 --- a/sakura-server/minecraft-patches/features/0002-Client-Visibility-Settings.patch +++ b/sakura-server/minecraft-patches/features/0002-Client-Visibility-Settings.patch @@ -36,7 +36,7 @@ index 9f6d7c5dc0e591488a8a3763d8a1f1b3671d5299..0f5383dcec940db15205afbb65f1f8aa final CompoundTag tag; diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index df822f0e7c358d74737c749d6ba61ec31846a569..a88184f63f3cb539569942c5c982193973183984 100644 +index 68865b05cdb0704ed463a1765deec383eb20cf41..e164d7fbda422dbcffd753c3373b1c08fa3b5d68 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java @@ -173,6 +173,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -78,13 +78,12 @@ index df822f0e7c358d74737c749d6ba61ec31846a569..a88184f63f3cb539569942c5c9821939 + if (!settings.playerModified() || !(entity.isPrimedTNT || entity.isFallingBlock)) { + return true; + } -+ final me.samsuik.sakura.player.visibility.VisibilityType type; -+ if (entity.isPrimedTNT) { -+ type = me.samsuik.sakura.player.visibility.VisibilityTypes.TNT; -+ } else { -+ type = me.samsuik.sakura.player.visibility.VisibilityTypes.SAND; -+ } ++ ++ final me.samsuik.sakura.player.visibility.VisibilityType type = entity.isPrimedTNT ++ ? me.samsuik.sakura.player.visibility.VisibilityTypes.TNT ++ : me.samsuik.sakura.player.visibility.VisibilityTypes.SAND; + final me.samsuik.sakura.player.visibility.VisibilityState state = settings.get(type); ++ + if (state == me.samsuik.sakura.player.visibility.VisibilityState.MINIMAL) { + final long key = entity.blockPosition().asLong() ^ entity.getType().hashCode(); + final long visibleEntity = ChunkMap.this.minimalEntities.get(key); @@ -94,6 +93,7 @@ index df822f0e7c358d74737c749d6ba61ec31846a569..a88184f63f3cb539569942c5c9821939 + ChunkMap.this.minimalEntities.put(key, entity.getId()); + } + } ++ + return state != me.samsuik.sakura.player.visibility.VisibilityState.OFF; + } + // Sakura end - client visibility settings; entity visibility @@ -109,10 +109,10 @@ index df822f0e7c358d74737c749d6ba61ec31846a569..a88184f63f3cb539569942c5c9821939 if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits flag = false; diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 03a157f6c96b0f39effa24ae278eeac689c83ee8..5f38281763419123a0611cbb34d9a02a0e0302ea 100644 +index 03a157f6c96b0f39effa24ae278eeac689c83ee8..2a7c057ccfeb5dbe6b14ff660c0bb342571d88e7 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -564,6 +564,21 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -564,6 +564,22 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.playerTickingChunks.remove((LevelChunk)chunkHolder.getCurrentChunk()); } // Paper end - chunk tick iteration @@ -128,21 +128,22 @@ index 03a157f6c96b0f39effa24ae278eeac689c83ee8..5f38281763419123a0611cbb34d9a02a + final long encodedPosition = blockPosition.asLong(); + return this.explosionPositions.add(encodedPosition); + } ++ + return true; + } + // Sakura end - client visibility settings public ServerLevel( MinecraftServer server, -@@ -675,6 +690,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -675,6 +691,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler); // Paper end - rewrite chunk system this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit -+ this.levelTickScheduler.registerNewTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings ++ this.levelTickScheduler.repeatingTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings } // Paper start -@@ -1898,7 +1914,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1898,7 +1915,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe for (ServerPlayer serverPlayer : this.players) { if (serverPlayer.distanceToSqr(vec3) < 4096.0) { Optional optional = Optional.ofNullable(serverExplosion.getHitPlayers().get(serverPlayer)); @@ -163,7 +164,7 @@ index 03a157f6c96b0f39effa24ae278eeac689c83ee8..5f38281763419123a0611cbb34d9a02a } diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index eccd082f86d7b1f6d76d7bebab294527007b1f9a..3b750861b2039283028c2890593b4922f6b7d93e 100644 +index b1a0ab0958fffbd24d4e79c6840c5d7539a42142..34730f5750f335d10f04ebb557cca510a6a8adbd 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -460,6 +460,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc @@ -175,7 +176,7 @@ index eccd082f86d7b1f6d76d7bebab294527007b1f9a..3b750861b2039283028c2890593b4922 public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) { super(level, gameProfile); diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 08c59d603fca038fc2dde36384eea1b6c971e659..c1c432b5732b1e85aca5597be75e0149a333de0d 100644 +index f02800e4e941b05bde6f0d5fac76e2b6ec5b9832..4a84792f9cf17cf2b50638ce6de05dc6f40b311f 100644 --- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java @@ -57,6 +57,60 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @@ -190,6 +191,7 @@ index 08c59d603fca038fc2dde36384eea1b6c971e659..c1c432b5732b1e85aca5597be75e0149 + return bedPacket.getType() == net.minecraft.world.level.block.entity.BlockEntityType.MOB_SPAWNER; + } + } ++ + return false; + } + @@ -203,7 +205,6 @@ index 08c59d603fca038fc2dde36384eea1b6c971e659..c1c432b5732b1e85aca5597be75e0149 + + if (settings.isToggled(me.samsuik.sakura.player.visibility.VisibilityTypes.SPAWNERS)) { + net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData chunkData = null; -+ + if (packet instanceof net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket chunkPacket) { + chunkData = chunkPacket.getChunkData(); + } else if (packet instanceof net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData chunkPacket) { @@ -265,7 +266,7 @@ index ca13dd72f173be6714965c506f2d48dcd3c9e569..21134883bea2553a870ef0df32c47430 if (this.player.containerMenu != oldContainer) { this.player.containerMenu.resumeRemoteUpdates(); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 8b261c3f216e7483039d8279a75977dfb679b453..10da5ea212dcc0db2e7846c7b3207e549e9acae8 100644 +index b06d701b280d58240503a0c95c2c98fa002faa16..96988c6993360cf90c8872a1371d91e897c56582 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -533,6 +533,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -280,7 +281,7 @@ index 8b261c3f216e7483039d8279a75977dfb679b453..10da5ea212dcc0db2e7846c7b3207e54 public Entity(EntityType entityType, Level level) { this.type = entityType; diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java -index ae1f7a8b9cc6db4dd8dd3d6593a952166d35cc68..f7663d07a71582c332b38871211e648cffcf13c2 100644 +index e035e87278e02c5a234ec9fa79c009706a189561..fff6985d35ff9b37b2829b7d0639a13e150ad697 100644 --- a/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -79,6 +79,7 @@ public class FallingBlockEntity extends Entity { @@ -292,7 +293,7 @@ index ae1f7a8b9cc6db4dd8dd3d6593a952166d35cc68..f7663d07a71582c332b38871211e648c public FallingBlockEntity(Level level, double x, double y, double z, BlockState state) { diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java -index dc9c8bdc81dec07a8e457431bbd35a54236b03ef..8755c76b679adcacbdd8e2faec363745fd583e48 100644 +index f153f25a4a61a84d842ab33225c4618d464c4116..d9e2a6e02b51cd42f1226a9fb62d0b205e693eba 100644 --- a/net/minecraft/world/entity/item/PrimedTnt.java +++ b/net/minecraft/world/entity/item/PrimedTnt.java @@ -63,6 +63,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { diff --git a/sakura-server/minecraft-patches/features/0003-Load-Chunks-on-Movement.patch b/sakura-server/minecraft-patches/features/0003-Load-Chunks-on-Movement.patch index 5bfc042..684e74f 100644 --- a/sakura-server/minecraft-patches/features/0003-Load-Chunks-on-Movement.patch +++ b/sakura-server/minecraft-patches/features/0003-Load-Chunks-on-Movement.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Load Chunks on Movement diff --git a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java -index 01cd38bba2deb6cf65c82b4e4ec352a2998fd339..0f61c8877694679f590cb79f4a34cf158b8ad610 100644 +index 01cd38bba2deb6cf65c82b4e4ec352a2998fd339..5cc6fe6984d59a94c037b2c327a5d72b5a2a740d 100644 --- a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java +++ b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java @@ -1885,6 +1885,7 @@ public final class CollisionUtil { @@ -24,19 +24,18 @@ index 01cd38bba2deb6cf65c82b4e4ec352a2998fd339..0f61c8877694679f590cb79f4a34cf15 final ChunkSource chunkSource = world.getChunkSource(); for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { -@@ -1954,6 +1956,17 @@ public final class CollisionUtil { +@@ -1954,6 +1956,16 @@ public final class CollisionUtil { continue; } + // Sakura start - load chunks on movement -+ if (addTicket && chunk.movementTicketNeedsUpdate() && chunkSource instanceof net.minecraft.server.level.ServerChunkCache chunkCache) { ++ if (addTicket && chunk.refreshMovementTicket(gameTime) && chunkSource instanceof net.minecraft.server.level.ServerChunkCache chunkCache) { + final net.minecraft.world.level.ChunkPos chunkPos = new net.minecraft.world.level.ChunkPos(currChunkX, currChunkZ); + chunkCache.addTicketAtLevel( + net.minecraft.server.level.TicketType.ENTITY_MOVEMENT, + chunkPos, + net.minecraft.server.level.ChunkLevel.ENTITY_TICKING_LEVEL + ); -+ chunk.updatedMovementTicket(); + } + // Sakura end - load chunks on movement final LevelChunkSection[] sections = chunk.getSections(); @@ -55,10 +54,10 @@ index 6a7dae136691fb2476633fa12897424daa6bb5b3..372fceb03ee24f0d9c0dc970824f3b63 public static TicketType register(String name, long timeout, boolean persist, TicketType.TicketUse use) { return Registry.register(BuiltInRegistries.TICKET_TYPE, name, new TicketType(timeout, persist, use)); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index ef6f91f35d8725fa3df81b23d86adc900a5df5ce..9345d8f00496cc3becb84ab52bde2d5914911b68 100644 +index 96988c6993360cf90c8872a1371d91e897c56582..77c06f9304a895e70a695be5afbaea7b99eaec25 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -537,6 +537,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -537,6 +537,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public boolean isPrimedTNT; public boolean isFallingBlock; // Sakura end - client visibility settings @@ -67,7 +66,6 @@ index ef6f91f35d8725fa3df81b23d86adc900a5df5ce..9345d8f00496cc3becb84ab52bde2d59 + + private int getExtraCollisionFlags() { + int flags = 0; -+ + if (this.loadChunks) { + flags |= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_LOAD_CHUNKS; + flags |= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_ADD_TICKET; @@ -79,7 +77,7 @@ index ef6f91f35d8725fa3df81b23d86adc900a5df5ce..9345d8f00496cc3becb84ab52bde2d59 public Entity(EntityType entityType, Level level) { this.type = entityType; -@@ -1520,7 +1534,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1520,7 +1533,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisionsForBlocksOrWorldBorder( this.level, (Entity)(Object)this, initialCollisionBox, potentialCollisionsVoxel, potentialCollisionsBB, @@ -88,11 +86,11 @@ index ef6f91f35d8725fa3df81b23d86adc900a5df5ce..9345d8f00496cc3becb84ab52bde2d59 ); potentialCollisionsBB.addAll(entityAABBs); final Vec3 collided = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currentBox, potentialCollisionsVoxel, potentialCollisionsBB); -@@ -5183,13 +5197,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -5183,13 +5196,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @Override public boolean shouldBeSaved() { return (this.removalReason == null || this.removalReason.shouldSave()) -+ && !this.loadChunks // Sakura - load chunks on movement; this is used to check if the chunk the entity is in can be unloaded ++ && !this.loadChunks // Sakura - load chunks on movement; this is used to check if the chunk the entity is in can be unloaded && !this.isPassenger() && (!this.isVehicle() || !((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity)this).moonrise$hasAnyPlayerPassengers()); // Paper - rewrite chunk system } @@ -105,7 +103,7 @@ index ef6f91f35d8725fa3df81b23d86adc900a5df5ce..9345d8f00496cc3becb84ab52bde2d59 public boolean mayInteract(ServerLevel level, BlockPos pos) { diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java -index f7663d07a71582c332b38871211e648cffcf13c2..e4dce2b09e8e898166b355373e6a205ebeb53a25 100644 +index fff6985d35ff9b37b2829b7d0639a13e150ad697..4b9a75c677b8f553a103438c3c7813f46d64d26a 100644 --- a/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -80,6 +80,7 @@ public class FallingBlockEntity extends Entity { @@ -117,7 +115,7 @@ index f7663d07a71582c332b38871211e648cffcf13c2..e4dce2b09e8e898166b355373e6a205e public FallingBlockEntity(Level level, double x, double y, double z, BlockState state) { diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java -index 8755c76b679adcacbdd8e2faec363745fd583e48..2420999c5399333bed122ee0a1f252ac894adfcb 100644 +index d9e2a6e02b51cd42f1226a9fb62d0b205e693eba..ea017a4162d54bd7e02b801216d83e51010ef618 100644 --- a/net/minecraft/world/entity/item/PrimedTnt.java +++ b/net/minecraft/world/entity/item/PrimedTnt.java @@ -64,6 +64,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { @@ -129,22 +127,20 @@ index 8755c76b679adcacbdd8e2faec363745fd583e48..2420999c5399333bed122ee0a1f252ac public PrimedTnt(Level level, double x, double y, double z, @Nullable LivingEntity owner) { diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java -index 182c14b660f8860bed627eed4e01fd4002153e9a..c3074cdbfb584b6d033377d7407177a344f68a3c 100644 +index 182c14b660f8860bed627eed4e01fd4002153e9a..164e080fbfc4ebff99479497030294e06b658bdc 100644 --- a/net/minecraft/world/level/chunk/ChunkAccess.java +++ b/net/minecraft/world/level/chunk/ChunkAccess.java -@@ -139,6 +139,17 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh +@@ -139,6 +139,15 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh private final int minSection; private final int maxSection; // Paper end - get block chunk optimisation + // Sakura start - load chunks on movement + private long lastMovementLoadTicket = 0; + -+ public final boolean movementTicketNeedsUpdate() { -+ return net.minecraft.server.MinecraftServer.currentTick - this.lastMovementLoadTicket >= 100; -+ } -+ -+ public final void updatedMovementTicket() { -+ this.lastMovementLoadTicket = net.minecraft.server.MinecraftServer.currentTick; ++ public final boolean refreshMovementTicket(final long gameTime) { ++ final boolean refresh = gameTime - this.lastMovementLoadTicket >= 100; ++ this.lastMovementLoadTicket = gameTime; ++ return refresh; + } + // Sakura end - load chunks on movement diff --git a/sakura-server/minecraft-patches/features/0004-Slice-Packet-obfuscation-and-reduction.patch b/sakura-server/minecraft-patches/features/0004-Slice-Packet-obfuscation-and-reduction.patch index 9d1652d..6906df4 100644 --- a/sakura-server/minecraft-patches/features/0004-Slice-Packet-obfuscation-and-reduction.patch +++ b/sakura-server/minecraft-patches/features/0004-Slice-Packet-obfuscation-and-reduction.patch @@ -153,10 +153,10 @@ index e96d4dee14c05f2fa329bfb1588ec795d4e3d730..ba9393e474ae213316c693d73ef2641e if (this.entity instanceof LivingEntity) { diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 706941df21621080b70cc7d8c84d1ec7b7ddc483..4b9a0327251a54d752409021cb7a10f890f1f131 100644 +index 77c06f9304a895e70a695be5afbaea7b99eaec25..a13f7613115f08461ed6852fd35bc19f4923063d 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -3638,7 +3638,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3637,7 +3637,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.entityData.markDirty(Entity.DATA_AIR_SUPPLY_ID); return; } @@ -166,10 +166,10 @@ index 706941df21621080b70cc7d8c84d1ec7b7ddc483..4b9a0327251a54d752409021cb7a10f8 } diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java -index e4dce2b09e8e898166b355373e6a205ebeb53a25..860efa7bf6643ab9f05e97fefec280dffa76ba0e 100644 +index 4b9a75c677b8f553a103438c3c7813f46d64d26a..d35183f10362952c0c38061ccdedc1a578c91c2d 100644 --- a/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -145,7 +145,7 @@ public class FallingBlockEntity extends Entity { +@@ -144,7 +144,7 @@ public class FallingBlockEntity extends Entity { } public void setStartPos(BlockPos startPos) { @@ -179,7 +179,7 @@ index e4dce2b09e8e898166b355373e6a205ebeb53a25..860efa7bf6643ab9f05e97fefec280df public BlockPos getStartPos() { diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java -index 2420999c5399333bed122ee0a1f252ac894adfcb..2e7f6e3941b34323768e43870541c8e4156c9a8f 100644 +index ea017a4162d54bd7e02b801216d83e51010ef618..b53baca84c9022a700fbc1150264fc805af6a61e 100644 --- a/net/minecraft/world/entity/item/PrimedTnt.java +++ b/net/minecraft/world/entity/item/PrimedTnt.java @@ -228,7 +228,11 @@ public class PrimedTnt extends Entity implements TraceableEntity { @@ -196,7 +196,7 @@ index 2420999c5399333bed122ee0a1f252ac894adfcb..2e7f6e3941b34323768e43870541c8e4 public int getFuse() { diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java -index 5cacbc07ee0f6ef2f47f7e0e8f6267d82ea94501..6160c684b712742b6ce565afb043c03badb705b2 100644 +index fbb58d0dc50d1e6d90d51379acbf6822674efc46..17723bdf3f3d3c8637dee01f8f4a15b2d741e52d 100644 --- a/net/minecraft/world/entity/player/Player.java +++ b/net/minecraft/world/entity/player/Player.java @@ -701,7 +701,7 @@ public abstract class Player extends LivingEntity { diff --git a/sakura-server/minecraft-patches/features/0006-Optimise-paper-explosions.patch b/sakura-server/minecraft-patches/features/0006-Optimise-paper-explosions.patch index 38e7bdd..8574a3e 100644 --- a/sakura-server/minecraft-patches/features/0006-Optimise-paper-explosions.patch +++ b/sakura-server/minecraft-patches/features/0006-Optimise-paper-explosions.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Optimise paper explosions diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java -index b2bcfb3557a0326fd7ec1059f95d6da4568dfd80..bd2055bc89c5672b514f1f7b1ad320a2fba7cbe2 100644 +index b2bcfb3557a0326fd7ec1059f95d6da4568dfd80..8df264c86ab14f4e7aa9918a3341ef35ffaa5290 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java @@ -319,6 +319,12 @@ public final class ChunkEntitySlices { @@ -13,7 +13,7 @@ index b2bcfb3557a0326fd7ec1059f95d6da4568dfd80..bd2055bc89c5672b514f1f7b1ad320a2 } + // Sakura start - optimise paper explosions; expose slice entity list -+ public Entity[] getSectionEntities(int sectionY) { ++ public Entity[] getSectionEntities(final int sectionY) { + return this.allEntities.getSectionEntities(sectionY); + } + // Sakura end - optimise paper explosions; expose slice entity list @@ -26,10 +26,10 @@ index b2bcfb3557a0326fd7ec1059f95d6da4568dfd80..bd2055bc89c5672b514f1f7b1ad320a2 } + // Sakura start - optimise paper explosions; expose slice entity list -+ public Entity[] getSectionEntities(int sectionY) { -+ final BasicEntityList list = this.entitiesBySection[sectionY - this.slices.minSection]; -+ if (list != null) { -+ return list.storage; ++ public Entity[] getSectionEntities(final int sectionY) { ++ final BasicEntityList entityList = this.entitiesBySection[sectionY - this.slices.minSection]; ++ if (entityList != null) { ++ return entityList.storage; + } else { + return new Entity[0]; + } @@ -40,7 +40,7 @@ index b2bcfb3557a0326fd7ec1059f95d6da4568dfd80..bd2055bc89c5672b514f1f7b1ad320a2 if (this.count == 0) { return; diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 250a46dbfdf3ba751dc081fae5cbf8aa16153f4e..1e9b92454edae054c6c3c50dc844c8fc3689f6f8 100644 +index f99a254d140f96feab9436b7799eec4804500033..cc6ee993470a274cdad124b4a7befb016d9a2b6e 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java @@ -86,7 +86,7 @@ public class ServerExplosion implements Explosion { @@ -48,51 +48,11 @@ index 250a46dbfdf3ba751dc081fae5cbf8aa16153f4e..1e9b92454edae054c6c3c50dc844c8fc } - CACHED_RAYS = rayCoords.toDoubleArray(); -+ CACHED_RAYS = sortExplosionRays(rayCoords); // Sakura - optimise paper explosions ++ CACHED_RAYS = me.samsuik.sakura.explosion.SortExplosionRays.sortExplosionRays(rayCoords); // Sakura - optimise paper explosions } private static final int CHUNK_CACHE_SHIFT = 2; -@@ -304,6 +304,39 @@ public class ServerExplosion implements Explosion { - return (float)missedRays / (float)totalRays; - } - // Paper end - collisions optimisations -+ // Sakura start - optimise paper explosions -+ /* -+ * Sort the explosion rays to better utilise the chunk and block cache. -+ * x + Vanilla Sorted -+ * z @ z 8 5 -+ * - x 6 7 6 4 -+ * 4 @ 5 7 @ 3 -+ * 2 3 8 2 -+ * 1 1 -+ */ -+ private static double[] sortExplosionRays(it.unimi.dsi.fastutil.doubles.DoubleArrayList rayCoords) { -+ List explosionRays = new ArrayList<>(); -+ -+ for (int i = 0; i < rayCoords.size(); i += 3) { -+ double[] ray = new double[3]; -+ rayCoords.getElements(i, ray, 0, 3); -+ explosionRays.add(ray); -+ } -+ -+ rayCoords.clear(); -+ explosionRays.sort(java.util.Comparator.comparingDouble(vec -> { -+ double sign = Math.signum(vec[0]); -+ double dir = (sign - 1) / 2; -+ return sign + 8 + vec[2] * dir; -+ })); -+ -+ double[] rays = new double[explosionRays.size() * 3]; -+ for (int i = 0; i < explosionRays.size() * 3; i++) { -+ rays[i] = explosionRays.get(i / 3)[i % 3]; -+ } -+ return rays; -+ } -+ // Sakura end - optimise paper explosions - - public ServerExplosion( - ServerLevel level, -@@ -398,6 +431,12 @@ public class ServerExplosion implements Explosion { +@@ -398,6 +398,12 @@ public class ServerExplosion implements Explosion { initialCache = this.getOrCacheExplosionBlock(blockX, blockY, blockZ, key, true); } @@ -105,67 +65,79 @@ index 250a46dbfdf3ba751dc081fae5cbf8aa16153f4e..1e9b92454edae054c6c3c50dc844c8fc // only ~1/3rd of the loop iterations in vanilla will result in a ray, as it is iterating the perimeter of // a 16x16x16 cube // we can cache the rays and their normals as well, so that we eliminate the excess iterations / checks and -@@ -476,16 +515,55 @@ public class ServerExplosion implements Explosion { +@@ -476,16 +482,62 @@ public class ServerExplosion implements Explosion { // Paper end - collision optimisations } -- private void hurtEntities() { -- float f = this.radius * 2.0F; + // Sakura start - optimise paper explosions -+ protected final AABB getExplosionBounds(float f) { - int floor = Mth.floor(this.center.x - f - 1.0); - int floor1 = Mth.floor(this.center.x + f + 1.0); - int floor2 = Mth.floor(this.center.y - f - 1.0); - int floor3 = Mth.floor(this.center.y + f + 1.0); - int floor4 = Mth.floor(this.center.z - f - 1.0); - int floor5 = Mth.floor(this.center.z + f + 1.0); -- List list = this.level.getEntities(this.excludeSourceFromDamage ? this.source : null, new AABB(floor, floor2, floor4, floor1, floor3, floor5), entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source -- for (Entity entity : list) { // Paper - used in loop -+ return new AABB(floor, floor2, floor4, floor1, floor3, floor5); ++ protected final AABB getExplosionBounds(final float impactRadius) { ++ final int minX = Mth.floor(this.center.x - impactRadius - 1.0); ++ final int maxX = Mth.floor(this.center.x + impactRadius + 1.0); ++ final int minY = Mth.floor(this.center.y - impactRadius - 1.0); ++ final int maxY = Mth.floor(this.center.y + impactRadius + 1.0); ++ final int minZ = Mth.floor(this.center.z - impactRadius - 1.0); ++ final int maxZ = Mth.floor(this.center.z + impactRadius + 1.0); ++ return new AABB(minX, minY, minZ, maxX, maxY, maxZ); + } + -+ private void hurtEntities() { -+ float f = this.radius * 2.0F; + private void hurtEntities() { +- float f = this.radius * 2.0F; +- int floor = Mth.floor(this.center.x - f - 1.0); +- int floor1 = Mth.floor(this.center.x + f + 1.0); +- int floor2 = Mth.floor(this.center.y - f - 1.0); +- int floor3 = Mth.floor(this.center.y + f + 1.0); +- int floor4 = Mth.floor(this.center.z - f - 1.0); +- int floor5 = Mth.floor(this.center.z + f + 1.0); +- List list = this.level.getEntities(this.excludeSourceFromDamage ? this.source : null, new AABB(floor, floor2, floor4, floor1, floor3, floor5), entity -> entity.isAlive() && !entity.isSpectator()); // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source +- for (Entity entity : list) { // Paper - used in loop ++ final float impactRadius = this.radius * 2.0F; + -+ int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(this.level); -+ int maxSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxSection(this.level); ++ final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(this.level); ++ final int maxSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxSection(this.level); + -+ int minChunkX = Mth.floor(this.center.x - f) >> 4; -+ int maxChunkX = Mth.floor(this.center.x + f) >> 4; -+ int minChunkY = Mth.clamp(Mth.floor(this.center.y - f) >> 4, minSection, maxSection); -+ int maxChunkY = Mth.clamp(Mth.floor(this.center.y + f) >> 4, minSection, maxSection); -+ int minChunkZ = Mth.floor(this.center.z - f) >> 4; -+ int maxChunkZ = Mth.floor(this.center.z + f) >> 4; ++ final int minChunkX = Mth.floor(this.center.x - impactRadius) >> 4; ++ final int maxChunkX = Mth.floor(this.center.x + impactRadius) >> 4; ++ final int minChunkY = Mth.clamp(Mth.floor(this.center.y - impactRadius) >> 4, minSection, maxSection); ++ final int maxChunkY = Mth.clamp(Mth.floor(this.center.y + impactRadius) >> 4, minSection, maxSection); ++ final int minChunkZ = Mth.floor(this.center.z - impactRadius) >> 4; ++ final int maxChunkZ = Mth.floor(this.center.z + impactRadius) >> 4; + -+ ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup entityLookup = this.level.moonrise$getEntityLookup(); ++ final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup entityLookup = this.level.moonrise$getEntityLookup(); + for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) { + for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) { -+ ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices chunk = entityLookup.getChunk(chunkX, chunkZ); -+ if (chunk == null) continue; // empty slice ++ final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices chunk = entityLookup.getChunk(chunkX, chunkZ); ++ if (chunk == null) { ++ continue; // empty slice ++ } + + for (int chunkY = minChunkY; chunkY <= maxChunkY; ++chunkY) { -+ this.impactEntities(f, chunk.getSectionEntities(chunkY)); ++ this.impactEntities(impactRadius, chunk.getSectionEntities(chunkY)); + } + } + } + } + -+ protected final void impactEntities(float f, Entity[] entities) { -+ for (int i = 0; i < entities.length; i++) { -+ Entity entity = entities[i]; -+ if (entity == null) break; // end of entity section -+ this.impactEntity(f, entity); -+ if (entity != entities[i]) i--; // entities can be removed mid-explosion ++ protected final void impactEntities(final float impactRadius, final Entity[] entities) { ++ for (int index = 0; index < entities.length; index++) { ++ final Entity entity = entities[index]; ++ if (entity == null) break; // end of entity slice ++ ++ this.impactEntity(impactRadius, entity); ++ ++ // Entities can be removed from the world mid-explosion. ++ if (entity != entities[index]) { ++ index--; ++ } + } + } + -+ protected final void impactEntity(float f, Entity entity) { ++ protected final void impactEntity(final float f, final Entity entity) { + if (entity.isAlive() && !entity.isSpectator() && (!this.excludeSourceFromDamage || entity != this.source)) { // Paper - Fix lag from explosions processing dead entities, Allow explosions to damage source + // Sakura end - optimise paper explosions if (!entity.ignoreExplosion(this)) { double d = Math.sqrt(entity.distanceToSqr(this.center)) / f; if (d <= 1.0) { -@@ -510,15 +588,16 @@ public class ServerExplosion implements Explosion { +@@ -510,15 +562,16 @@ public class ServerExplosion implements Explosion { // - Damaging EnderDragon does nothing // - EnderDragon hitbox always covers the other parts and is therefore always present if (entity instanceof EnderDragonPart) { @@ -184,7 +156,7 @@ index 250a46dbfdf3ba751dc081fae5cbf8aa16153f4e..1e9b92454edae054c6c3c50dc844c8fc dragonPart.hurtServer(this.level, this.damageSource, this.damageCalculator.getEntityDamageAmount(this, dragonPart, f1)); } } -@@ -527,7 +606,7 @@ public class ServerExplosion implements Explosion { +@@ -527,7 +580,7 @@ public class ServerExplosion implements Explosion { } if (entity.lastDamageCancelled) { // SPIGOT-5339, SPIGOT-6252, SPIGOT-6777: Skip entity if damage event was cancelled diff --git a/sakura-server/minecraft-patches/features/0007-Store-Entity-Data-State.patch b/sakura-server/minecraft-patches/features/0007-Store-Entity-Data-State.patch index 61689f0..155c6dd 100644 --- a/sakura-server/minecraft-patches/features/0007-Store-Entity-Data-State.patch +++ b/sakura-server/minecraft-patches/features/0007-Store-Entity-Data-State.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Store Entity Data/State diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index ce39193b14b43c215930cde7c311f88f756b0b81..f8b1b6850013b70218aa2eefe9371774a45a6033 100644 +index a13f7613115f08461ed6852fd35bc19f4923063d..815f92176821bf4117952450e97bd5b044c78b58 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -551,6 +551,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -550,6 +550,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return flags; } // Sakura end - load chunks on movement @@ -23,7 +23,7 @@ index ce39193b14b43c215930cde7c311f88f756b0b81..f8b1b6850013b70218aa2eefe9371774 + return this.entityState; + } + -+ public final boolean compareState(Entity to) { ++ public final boolean compareState(final Entity to) { + return to.entityState() != null && to.entityState().comparePositionAndMotion(this); + } + // Sakura end - store entity data/state @@ -31,7 +31,7 @@ index ce39193b14b43c215930cde7c311f88f756b0b81..f8b1b6850013b70218aa2eefe9371774 public Entity(EntityType entityType, Level level) { this.type = entityType; diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 7aa8d68800cdec91f24f015f9b2d56e969a7be17..2fa0725a2b41517e1589e540999118f5c355e899 100644 +index 44e4c907801b934c188cf67bf3c75023a52a948f..4ff7fdc9a75e7d31170385016bf8ea75c45719a1 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -1498,6 +1498,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl diff --git a/sakura-server/minecraft-patches/features/0008-Merge-Cannon-Entities.patch b/sakura-server/minecraft-patches/features/0008-Merge-Cannon-Entities.patch index 8cc1d5c..a785468 100644 --- a/sakura-server/minecraft-patches/features/0008-Merge-Cannon-Entities.patch +++ b/sakura-server/minecraft-patches/features/0008-Merge-Cannon-Entities.patch @@ -5,18 +5,18 @@ Subject: [PATCH] Merge Cannon Entities diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 5f38281763419123a0611cbb34d9a02a0e0302ea..5ddfbddbef13b58bf509e4c60bbd72cde2a7f59d 100644 +index 2a7c057ccfeb5dbe6b14ff660c0bb342571d88e7..496e23c110cbb3b60a6565e1903545e09715f79e 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -691,6 +691,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -692,6 +692,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper end - rewrite chunk system this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit - this.levelTickScheduler.registerNewTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings -+ this.levelTickScheduler.registerNewTask(this.mergeHandler::expire, 200); // Sakura - merge cannon entities + this.levelTickScheduler.repeatingTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings ++ this.levelTickScheduler.repeatingTask(this.mergeHandler::expire, 200); // Sakura - merge cannon entities } // Paper start -@@ -805,6 +806,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -806,6 +807,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR @@ -24,12 +24,12 @@ index 5f38281763419123a0611cbb34d9a02a0e0302ea..5ddfbddbef13b58bf509e4c60bbd72cd this.entityTickList .forEach( entity -> { -@@ -823,6 +825,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -824,6 +826,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe entity.stopRiding(); } + // Sakura start - merge cannon entities -+ Entity previous = previousEntity[0]; ++ final Entity previous = previousEntity[0]; + if (this.mergeHandler.tryMerge(entity, previous)) { + return; + } else { @@ -41,15 +41,15 @@ index 5f38281763419123a0611cbb34d9a02a0e0302ea..5ddfbddbef13b58bf509e4c60bbd72cd this.guardEntityTick(this::tickNonPassenger, entity); profilerFiller.pop(); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index b0b611e641ff1b81fb9dbee31de3e8e94be08338..1dab546bcf31c4c773cff99a8f28c5c4b0da4747 100644 +index 815f92176821bf4117952450e97bd5b044c78b58..bf46bb5b61f4ec6f23aacec41426d0ffe5a265fb 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -566,6 +566,27 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -565,6 +565,27 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return to.entityState() != null && to.entityState().comparePositionAndMotion(this); } // Sakura end - store entity data/state + // Sakura start - merge cannon entities -+ public final void updateBukkitHandle(Entity entity) { ++ public final void updateBukkitHandle(final Entity entity) { + if (this.bukkitEntity != null) { + this.bukkitEntity.setHandle(entity); + } else { @@ -72,7 +72,7 @@ index b0b611e641ff1b81fb9dbee31de3e8e94be08338..1dab546bcf31c4c773cff99a8f28c5c4 public Entity(EntityType entityType, Level level) { this.type = entityType; -@@ -5177,6 +5198,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -5176,6 +5197,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess if (this.removalReason != Entity.RemovalReason.UNLOADED_TO_CHUNK) { this.getPassengers().forEach(Entity::stopRiding); } // Paper - rewrite chunk system this.levelCallback.onRemove(removalReason); this.onRemoval(removalReason); @@ -85,7 +85,7 @@ index b0b611e641ff1b81fb9dbee31de3e8e94be08338..1dab546bcf31c4c773cff99a8f28c5c4 if (!(this instanceof ServerPlayer) && removalReason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { // Players need to be special cased, because they are regularly removed from the world diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java -index 860efa7bf6643ab9f05e97fefec280dffa76ba0e..d65df5f13e038d109870d1f7fba50d2260489d49 100644 +index d35183f10362952c0c38061ccdedc1a578c91c2d..8ea534e6f49b787f5445093203f41410668e42bd 100644 --- a/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -53,7 +53,7 @@ import net.minecraft.world.phys.HitResult; @@ -110,7 +110,7 @@ index 860efa7bf6643ab9f05e97fefec280dffa76ba0e..d65df5f13e038d109870d1f7fba50d22 + } + + @Override -+ public final boolean isSafeToMergeInto(me.samsuik.sakura.entity.merge.MergeableEntity entity, boolean ticksLived) { ++ public final boolean isSafeToMergeInto(final me.samsuik.sakura.entity.merge.MergeableEntity entity, final boolean ticksLived) { + return entity instanceof FallingBlockEntity fbe + && fbe.blockState.equals(this.blockState) + && (!ticksLived || fbe.time - 1 == this.time); @@ -120,7 +120,7 @@ index 860efa7bf6643ab9f05e97fefec280dffa76ba0e..d65df5f13e038d109870d1f7fba50d22 + public final void respawnEntity(int count) { + while (count-- >= 1) { + // Unlike PrimedTnt we have to try respawn each stacked entity -+ FallingBlockEntity fallingBlock = new FallingBlockEntity(EntityType.FALLING_BLOCK, this.level()); ++ final FallingBlockEntity fallingBlock = new FallingBlockEntity(EntityType.FALLING_BLOCK, this.level()); + + // Try to stack the falling block + this.entityState().apply(fallingBlock); @@ -142,7 +142,7 @@ index 860efa7bf6643ab9f05e97fefec280dffa76ba0e..d65df5f13e038d109870d1f7fba50d22 + } + + @Override -+ public @Nullable ItemEntity spawnAtLocation(ServerLevel level, net.minecraft.world.level.ItemLike item) { // may be overridden by plugins ++ public @Nullable ItemEntity spawnAtLocation(final ServerLevel level, final net.minecraft.world.level.ItemLike item) { // may be overridden by plugins + ItemEntity itemEntity = null; + for (int i = 0; i < this.mergeData.count; ++i) { + itemEntity = super.spawnAtLocation(level, item); @@ -161,7 +161,7 @@ index 860efa7bf6643ab9f05e97fefec280dffa76ba0e..d65df5f13e038d109870d1f7fba50d22 } public FallingBlockEntity(Level level, double x, double y, double z, BlockState state) { -@@ -240,6 +291,7 @@ public class FallingBlockEntity extends Entity { +@@ -239,6 +290,7 @@ public class FallingBlockEntity extends Entity { return; } // CraftBukkit end @@ -169,7 +169,7 @@ index 860efa7bf6643ab9f05e97fefec280dffa76ba0e..d65df5f13e038d109870d1f7fba50d22 if (this.level().setBlock(blockPos, this.blockState, 3)) { ((ServerLevel)this.level()) .getChunkSource() -@@ -347,6 +399,11 @@ public class FallingBlockEntity extends Entity { +@@ -346,6 +398,11 @@ public class FallingBlockEntity extends Entity { output.putBoolean("CancelDrop", this.cancelDrop); if (!this.autoExpire) output.putBoolean("Paper.AutoExpire", false); // Paper - Expand FallingBlock API @@ -181,7 +181,7 @@ index 860efa7bf6643ab9f05e97fefec280dffa76ba0e..d65df5f13e038d109870d1f7fba50d22 } @Override -@@ -361,6 +418,7 @@ public class FallingBlockEntity extends Entity { +@@ -360,6 +417,7 @@ public class FallingBlockEntity extends Entity { this.blockData = input.read("TileEntityData", CompoundTag.CODEC).map(blockData -> this.level().paperConfig().entities.spawning.filterBadTileEntityNbtFromFallingBlocks && this.blockState.getBlock() instanceof net.minecraft.world.level.block.GameMasterBlock ? null : blockData).map(CompoundTag::copy).orElse(null); // Paper - Filter bad block entity nbt data from falling blocks this.cancelDrop = input.getBooleanOr("CancelDrop", false); this.autoExpire = input.getBooleanOr("Paper.AutoExpire", true); // Paper - Expand FallingBlock API @@ -190,7 +190,7 @@ index 860efa7bf6643ab9f05e97fefec280dffa76ba0e..d65df5f13e038d109870d1f7fba50d22 public void setHurtsEntities(float fallDamagePerDistance, int fallDamageMax) { diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java -index 2e7f6e3941b34323768e43870541c8e4156c9a8f..0c8343075f5523aa200b58f2afd313d718408ac8 100644 +index b53baca84c9022a700fbc1150264fc805af6a61e..95d57f9aea21860ff886a27cc5641d7c96882f34 100644 --- a/net/minecraft/world/entity/item/PrimedTnt.java +++ b/net/minecraft/world/entity/item/PrimedTnt.java @@ -34,7 +34,7 @@ import org.bukkit.event.entity.EntityRemoveEvent; @@ -215,7 +215,7 @@ index 2e7f6e3941b34323768e43870541c8e4156c9a8f..0c8343075f5523aa200b58f2afd313d7 + } + + @Override -+ public final boolean isSafeToMergeInto(me.samsuik.sakura.entity.merge.MergeableEntity entity, boolean ticksLived) { ++ public final boolean isSafeToMergeInto(final me.samsuik.sakura.entity.merge.MergeableEntity entity, final boolean ticksLived) { + return entity instanceof PrimedTnt tnt + && tnt.getFuse() + 1 == this.getFuse() + // required to prevent issues with powdered snow @@ -225,7 +225,7 @@ index 2e7f6e3941b34323768e43870541c8e4156c9a8f..0c8343075f5523aa200b58f2afd313d7 + + @Override + public final void respawnEntity(int count) { -+ PrimedTnt tnt = new PrimedTnt(EntityType.TNT, this.level()); ++ final PrimedTnt tnt = new PrimedTnt(EntityType.TNT, this.level()); + tnt.updateBukkitHandle(this); // update handle for plugins + while (count-- > 1) { + this.setFuse(100); // Prevent unwanted explosions while ticking @@ -280,11 +280,11 @@ index 2e7f6e3941b34323768e43870541c8e4156c9a8f..0c8343075f5523aa200b58f2afd313d7 @Nullable diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 2fa0725a2b41517e1589e540999118f5c355e899..19788e29f796efd7b1fe79c398c5532eb99add58 100644 +index 4ff7fdc9a75e7d31170385016bf8ea75c45719a1..7b9e61b2286d18f55a365eebda1fe2128023bec9 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -828,6 +828,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl - public final me.samsuik.sakura.listener.LevelTickScheduler levelTickScheduler = new me.samsuik.sakura.listener.LevelTickScheduler(); + public final me.samsuik.sakura.listener.LevelTickScheduler levelTickScheduler = new me.samsuik.sakura.listener.LevelTickScheduler(this); public final me.samsuik.sakura.listener.BlockChangeTracker blockChangeTracker = new me.samsuik.sakura.listener.BlockChangeTracker(this); // Sakura end - track block changes and tick scheduler + public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities @@ -292,7 +292,7 @@ index 2fa0725a2b41517e1589e540999118f5c355e899..19788e29f796efd7b1fe79c398c5532e protected Level( WritableLevelData levelData, diff --git a/net/minecraft/world/level/block/BasePressurePlateBlock.java b/net/minecraft/world/level/block/BasePressurePlateBlock.java -index 42ee3f32fe44c1f0680c994a69201f7bd7792673..96c977df11c660ccb9a9b32e61c865084e3776ce 100644 +index 42ee3f32fe44c1f0680c994a69201f7bd7792673..79593698d532a41c3f75c00b3452b6f0aa092845 100644 --- a/net/minecraft/world/level/block/BasePressurePlateBlock.java +++ b/net/minecraft/world/level/block/BasePressurePlateBlock.java @@ -92,7 +92,7 @@ public abstract class BasePressurePlateBlock extends Block { @@ -309,7 +309,7 @@ index 42ee3f32fe44c1f0680c994a69201f7bd7792673..96c977df11c660ccb9a9b32e61c86508 } + // Sakura start - merge cannon entities -+ protected int getSignalStrength(Level world, BlockPos pos, boolean entityInside) { ++ protected int getSignalStrength(final Level world, final BlockPos pos, final boolean entityInside) { + return this.getSignalStrength(world, pos); + } + // Sakura end - merge cannon entities @@ -318,22 +318,24 @@ index 42ee3f32fe44c1f0680c994a69201f7bd7792673..96c977df11c660ccb9a9b32e61c86508 protected abstract int getSignalForState(BlockState state); diff --git a/net/minecraft/world/level/block/WeightedPressurePlateBlock.java b/net/minecraft/world/level/block/WeightedPressurePlateBlock.java -index 5e095919828e89d12f2676b3c544842a81e047a1..e47a5010baea87ebf472ccac9ae98ede7a490b50 100644 +index 5e095919828e89d12f2676b3c544842a81e047a1..e45ceec307a4944f40d044af0369d0c598a4e9ae 100644 --- a/net/minecraft/world/level/block/WeightedPressurePlateBlock.java +++ b/net/minecraft/world/level/block/WeightedPressurePlateBlock.java -@@ -39,6 +39,11 @@ public class WeightedPressurePlateBlock extends BasePressurePlateBlock { +@@ -39,6 +39,13 @@ public class WeightedPressurePlateBlock extends BasePressurePlateBlock { @Override protected int getSignalStrength(Level level, BlockPos pos) { + // Sakura start - merge cannon entities + return this.getSignalStrength(level, pos, false); + } -+ protected final int getSignalStrength(Level level, BlockPos pos, boolean entityInside) { ++ ++ @Override ++ protected final int getSignalStrength(final Level level, final BlockPos pos, final boolean entityInside) { + // Sakura end - merge cannon entities // CraftBukkit start // int min = Math.min(getEntityCount(level, TOUCH_AABB.move(pos), Entity.class), this.maxWeight); int min = 0; -@@ -54,7 +59,7 @@ public class WeightedPressurePlateBlock extends BasePressurePlateBlock { +@@ -54,7 +61,7 @@ public class WeightedPressurePlateBlock extends BasePressurePlateBlock { // We only want to block turning the plate on if all events are cancelled if (!cancellable.isCancelled()) { diff --git a/sakura-server/minecraft-patches/features/0009-Replace-explosion-density-cache.patch b/sakura-server/minecraft-patches/features/0009-Replace-explosion-density-cache.patch index 04442bc..fa6044d 100644 --- a/sakura-server/minecraft-patches/features/0009-Replace-explosion-density-cache.patch +++ b/sakura-server/minecraft-patches/features/0009-Replace-explosion-density-cache.patch @@ -5,19 +5,19 @@ Subject: [PATCH] Replace explosion density cache diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 5ddfbddbef13b58bf509e4c60bbd72cde2a7f59d..39cf9a8af79ce4c3f1d47eaf7cf3205199b35eb6 100644 +index 496e23c110cbb3b60a6565e1903545e09715f79e..8c4b4cb9e98b8c0334bb7e247e67206bd57c3de2 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -692,6 +692,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -693,6 +693,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit - this.levelTickScheduler.registerNewTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings - this.levelTickScheduler.registerNewTask(this.mergeHandler::expire, 200); // Sakura - merge cannon entities -+ this.levelTickScheduler.registerNewTask(this.densityCache::invalidate, 0); // Sakura - explosion density cache + 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::invalidate, 0); // Sakura - explosion density cache } // Paper start diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 19788e29f796efd7b1fe79c398c5532eb99add58..c24f09cf9959310353bd0fc5a5ff7498c6ea47a0 100644 +index 7b9e61b2286d18f55a365eebda1fe2128023bec9..3e4784e7dbb264e08f944e03d1f59218fafe710b 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -829,6 +829,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @@ -29,7 +29,7 @@ index 19788e29f796efd7b1fe79c398c5532eb99add58..c24f09cf9959310353bd0fc5a5ff7498 protected Level( WritableLevelData levelData, diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 1e9b92454edae054c6c3c50dc844c8fc3689f6f8..37721d49fbb5c8914866be4a2bde29a64e3f172e 100644 +index cc6ee993470a274cdad124b4a7befb016d9a2b6e..c3c90cc17c4f1ebcaddffea4087929e3708aa22f 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java @@ -294,7 +294,12 @@ public class ServerExplosion implements Explosion { @@ -46,7 +46,7 @@ index 1e9b92454edae054c6c3c50dc844c8fc3689f6f8..37721d49fbb5c8914866be4a2bde29a6 ++missedRays; } } -@@ -385,8 +390,16 @@ public class ServerExplosion implements Explosion { +@@ -352,8 +357,16 @@ public class ServerExplosion implements Explosion { double d9 = Mth.lerp(d6, boundingBox.minY, boundingBox.maxY); double d10 = Mth.lerp(d7, boundingBox.minZ, boundingBox.maxZ); Vec3 vec3 = new Vec3(d8 + d3, d9, d10 + d4); @@ -65,7 +65,7 @@ index 1e9b92454edae054c6c3c50dc844c8fc3689f6f8..37721d49fbb5c8914866be4a2bde29a6 i++; } -@@ -682,6 +695,11 @@ public class ServerExplosion implements Explosion { +@@ -656,6 +669,11 @@ public class ServerExplosion implements Explosion { return; } // CraftBukkit end @@ -77,7 +77,7 @@ index 1e9b92454edae054c6c3c50dc844c8fc3689f6f8..37721d49fbb5c8914866be4a2bde29a6 for (BlockPos blockPos : blocks) { // CraftBukkit start - TNTPrimeEvent -@@ -848,14 +866,12 @@ public class ServerExplosion implements Explosion { +@@ -822,14 +840,12 @@ public class ServerExplosion implements Explosion { // Paper start - Optimize explosions protected float getBlockDensity(Vec3 vec3d, Entity entity) { @@ -98,7 +98,7 @@ index 1e9b92454edae054c6c3c50dc844c8fc3689f6f8..37721d49fbb5c8914866be4a2bde29a6 return blockDensity; diff --git a/net/minecraft/world/level/block/BasePressurePlateBlock.java b/net/minecraft/world/level/block/BasePressurePlateBlock.java -index 96c977df11c660ccb9a9b32e61c865084e3776ce..dc110835679dbfcb232c58c91ddac343c85ee3ab 100644 +index 79593698d532a41c3f75c00b3452b6f0aa092845..2ea14093ba70d6e0e7407c18fb0570f5a15d8c2a 100644 --- a/net/minecraft/world/level/block/BasePressurePlateBlock.java +++ b/net/minecraft/world/level/block/BasePressurePlateBlock.java @@ -107,6 +107,11 @@ public abstract class BasePressurePlateBlock extends Block { @@ -130,7 +130,7 @@ index 8a3a8b0fdf9545a41501dc992c6982d9c8ce7b66..5e2576a8b90de8a829c6136cc384f3fe notifyNeighbors(block, level, blockPosx, opposite); emitState(level, blockPosx, flag2, flag3, flag, flag1); diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java -index 84f3073444ae9e11e5d11224d6af6474ced925e2..281366d8b256a2414e20872c0cb54c9d08501887 100644 +index 84f3073444ae9e11e5d11224d6af6474ced925e2..cc0ce70aa363a5ba64c5f7eda579cd00fbb6cd4c 100644 --- a/net/minecraft/world/phys/AABB.java +++ b/net/minecraft/world/phys/AABB.java @@ -19,6 +19,30 @@ public class AABB { @@ -138,25 +138,25 @@ index 84f3073444ae9e11e5d11224d6af6474ced925e2..281366d8b256a2414e20872c0cb54c9d public final double maxZ; + // Sakura start - explosion density cache -+ public final boolean isAABBInBounds(AABB bb) { -+ return this.minX <= bb.minX && this.maxX >= bb.maxX -+ && this.minY <= bb.minY && this.maxY >= bb.maxY -+ && this.minZ <= bb.minZ && this.maxZ >= bb.maxZ; ++ public final boolean containsInclusive(final AABB other) { ++ return this.minX <= other.minX && this.maxX >= other.maxX ++ && this.minY <= other.minY && this.maxY >= other.maxY ++ && this.minZ <= other.minZ && this.maxZ >= other.maxZ; + } + -+ public final boolean isVec3InBounds(Vec3 p) { -+ return this.minX <= p.x && this.maxX >= p.x -+ && this.minY <= p.y && this.maxY >= p.y -+ && this.minZ <= p.z && this.maxZ >= p.z; ++ public final boolean containsInclusive(final Vec3 pos) { ++ return this.minX <= pos.x && this.maxX >= pos.x ++ && this.minY <= pos.y && this.maxY >= pos.y ++ && this.minZ <= pos.z && this.maxZ >= pos.z; + } + -+ public final AABB expand(Vec3 pos) { -+ double minX = Math.min(this.minX, pos.x); -+ double minY = Math.min(this.minY, pos.y); -+ double minZ = Math.min(this.minZ, pos.z); -+ double maxX = Math.max(this.maxX, pos.x); -+ double maxY = Math.max(this.maxY, pos.y); -+ double maxZ = Math.max(this.maxZ, pos.z); ++ public final AABB expand(final Vec3 pos) { ++ final double minX = Math.min(this.minX, pos.x); ++ final double minY = Math.min(this.minY, pos.y); ++ final double minZ = Math.min(this.minZ, pos.z); ++ final double maxX = Math.max(this.maxX, pos.x); ++ final double maxY = Math.max(this.maxY, pos.y); ++ final double maxZ = Math.max(this.maxZ, pos.z); + return new AABB(minX, minY, minZ, maxX, maxY, maxZ); + } + // Sakura end - explosion density cache diff --git a/sakura-server/minecraft-patches/features/0010-Optimise-explosions-in-protected-regions.patch b/sakura-server/minecraft-patches/features/0010-Optimise-explosions-in-protected-regions.patch index 3c36736..b3e663c 100644 --- a/sakura-server/minecraft-patches/features/0010-Optimise-explosions-in-protected-regions.patch +++ b/sakura-server/minecraft-patches/features/0010-Optimise-explosions-in-protected-regions.patch @@ -5,23 +5,23 @@ Subject: [PATCH] Optimise explosions in protected regions diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 37721d49fbb5c8914866be4a2bde29a64e3f172e..c1e6e27c8424483d5b7e2bce784463e9293b77a0 100644 +index c3c90cc17c4f1ebcaddffea4087929e3708aa22f..000e1ffcebd6f529133af1edbed6da80b9848e75 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java -@@ -342,6 +342,22 @@ public class ServerExplosion implements Explosion { - return rays; +@@ -309,6 +309,22 @@ public class ServerExplosion implements Explosion { + return (float)missedRays / (float)totalRays; } - // Sakura end - optimise paper explosions + // Paper end - collisions optimisations + // Sakura start - optimise explosion protected regions + protected final boolean isRegionUnprotected() { + // optimisation: We check if a plugin has cancelled the event or cleared the blockList. + // It tells us if the result was thrown away, so we can avoid the block searching logic. + // As a side effect the event is called twice which may interfere with some plugins. + if (this.source != null && this.level.sakuraConfig().cannons.explosion.optimiseProtectedRegions) { -+ Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z); -+ List blocks = new ObjectArrayList<>(1); ++ final Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z); ++ final List blocks = new ObjectArrayList<>(1); + blocks.add(location.getBlock()); -+ org.bukkit.event.entity.EntityExplodeEvent event = CraftEventFactory.callEntityExplodeEvent(this.source, blocks, 0.0f, this.blockInteraction); ++ final org.bukkit.event.entity.EntityExplodeEvent event = CraftEventFactory.callEntityExplodeEvent(this.source, blocks, 0.0f, this.blockInteraction); + return !event.isCancelled() && !event.blockList().isEmpty(); + } + @@ -31,7 +31,7 @@ index 37721d49fbb5c8914866be4a2bde29a64e3f172e..c1e6e27c8424483d5b7e2bce784463e9 public ServerExplosion( ServerLevel level, -@@ -449,6 +465,11 @@ public class ServerExplosion implements Explosion { +@@ -416,6 +432,11 @@ public class ServerExplosion implements Explosion { return ret; } // Sakura end - optimise paper explosions diff --git a/sakura-server/minecraft-patches/features/0011-Specialised-Explosions.patch b/sakura-server/minecraft-patches/features/0011-Specialised-Explosions.patch index 2554067..dd86d1b 100644 --- a/sakura-server/minecraft-patches/features/0011-Specialised-Explosions.patch +++ b/sakura-server/minecraft-patches/features/0011-Specialised-Explosions.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Specialised Explosions diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 39cf9a8af79ce4c3f1d47eaf7cf3205199b35eb6..bad69adfbc492d851a3542dc7f77884d9f933c8a 100644 +index 8c4b4cb9e98b8c0334bb7e247e67206bd57c3de2..573b1695abde0d89d5702a60a84919167ef4baab 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -1913,7 +1913,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1914,7 +1914,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe case STANDARD -> Explosion.BlockInteraction.DESTROY; // CraftBukkit - handle custom explosion type }; Vec3 vec3 = new Vec3(x, y, z); @@ -26,7 +26,7 @@ index 39cf9a8af79ce4c3f1d47eaf7cf3205199b35eb6..bad69adfbc492d851a3542dc7f77884d if (configurator != null) configurator.accept(serverExplosion);// Paper - Allow explosions to damage source serverExplosion.explode(); // CraftBukkit start -@@ -1921,6 +1930,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1922,6 +1931,19 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe return serverExplosion; } // CraftBukkit end @@ -35,14 +35,18 @@ index 39cf9a8af79ce4c3f1d47eaf7cf3205199b35eb6..bad69adfbc492d851a3542dc7f77884d + return serverExplosion; + } + -+ private void notifyPlayersOfExplosion(ServerExplosion serverExplosion, Vec3 vec3, -+ ParticleOptions smallExplosionParticles, ParticleOptions largeExplosionParticles, -+ Holder explosionSound) { ++ private void notifyPlayersOfExplosion( ++ final ServerExplosion serverExplosion, ++ final Vec3 vec3, ++ final ParticleOptions smallExplosionParticles, ++ final ParticleOptions largeExplosionParticles, ++ final Holder explosionSound ++ ) { + // Sakura end - specialised explosions ParticleOptions particleOptions = serverExplosion.isSmall() ? smallExplosionParticles : largeExplosionParticles; for (ServerPlayer serverPlayer : this.players) { -@@ -1941,7 +1959,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1942,7 +1964,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } } @@ -52,14 +56,14 @@ index 39cf9a8af79ce4c3f1d47eaf7cf3205199b35eb6..bad69adfbc492d851a3542dc7f77884d private Explosion.BlockInteraction getDestroyType(GameRules.Key decayGameRule) { diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java -index 0c8343075f5523aa200b58f2afd313d718408ac8..8986a9876f9437fd8d65f4d43df3f39a98741210 100644 +index 95d57f9aea21860ff886a27cc5641d7c96882f34..45a528169a57ecc287ae4f527d1d98b597a48f04 100644 --- a/net/minecraft/world/entity/item/PrimedTnt.java +++ b/net/minecraft/world/entity/item/PrimedTnt.java @@ -79,20 +79,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak @Override public final void respawnEntity(int count) { -- PrimedTnt tnt = new PrimedTnt(EntityType.TNT, this.level()); +- final PrimedTnt tnt = new PrimedTnt(EntityType.TNT, this.level()); - tnt.updateBukkitHandle(this); // update handle for plugins - while (count-- > 1) { - this.setFuse(100); // Prevent unwanted explosions while ticking @@ -78,10 +82,10 @@ index 0c8343075f5523aa200b58f2afd313d718408ac8..8986a9876f9437fd8d65f4d43df3f39a // Sakura end - merge cannon entities diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index c1e6e27c8424483d5b7e2bce784463e9293b77a0..d45582bdfc3fa837c5aa95f499183b60b877b7c2 100644 +index 000e1ffcebd6f529133af1edbed6da80b9848e75..d2b33fb06ce9a806466208d7afd65fa8d3da0292 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java -@@ -358,6 +358,38 @@ public class ServerExplosion implements Explosion { +@@ -325,6 +325,38 @@ public class ServerExplosion implements Explosion { return true; } // Sakura end - optimise explosion protected regions @@ -97,9 +101,9 @@ index c1e6e27c8424483d5b7e2bce784463e9293b77a0..d45582bdfc3fa837c5aa95f499183b60 + // Paper end - collision optimisations + } + -+ protected final void markBlocksInCacheAsExplodable(List explodedPositions) { -+ for (BlockPos blow : explodedPositions) { -+ ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache cache = this.blockCache.get(blow.asLong()); ++ protected final void markBlocksInCacheAsExplodable(final List explodedPositions) { ++ for (final BlockPos blow : explodedPositions) { ++ final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache cache = this.blockCache.get(blow.asLong()); + // May be null if the blockCache is cleared then retrieved from the recent block cache + if (cache != null) { + cache.shouldExplode = null; @@ -120,7 +124,7 @@ index c1e6e27c8424483d5b7e2bce784463e9293b77a0..d45582bdfc3fa837c5aa95f499183b60 public ServerExplosion( ServerLevel level, -@@ -667,7 +699,10 @@ public class ServerExplosion implements Explosion { +@@ -641,7 +673,10 @@ public class ServerExplosion implements Explosion { // CraftBukkit end entity.push(vec3); if (entity instanceof Player player && !player.isSpectator() && (!player.isCreative() || !player.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Option to disable explosion knockback @@ -132,7 +136,7 @@ index c1e6e27c8424483d5b7e2bce784463e9293b77a0..d45582bdfc3fa837c5aa95f499183b60 } entity.onExplosionHit(this.source); -@@ -772,14 +807,7 @@ public class ServerExplosion implements Explosion { +@@ -746,14 +781,7 @@ public class ServerExplosion implements Explosion { } public void explode() { @@ -148,7 +152,7 @@ index c1e6e27c8424483d5b7e2bce784463e9293b77a0..d45582bdfc3fa837c5aa95f499183b60 this.level.gameEvent(this.source, GameEvent.EXPLODE, this.center); List list = this.calculateExplodedPositions(); this.hurtEntities(); -@@ -793,13 +821,7 @@ public class ServerExplosion implements Explosion { +@@ -767,13 +795,7 @@ public class ServerExplosion implements Explosion { if (this.fire) { this.createFire(list); } diff --git a/sakura-server/minecraft-patches/features/0012-Optimise-cannon-entity-movement.patch b/sakura-server/minecraft-patches/features/0012-Optimise-cannon-entity-movement.patch index 5d54865..77ff666 100644 --- a/sakura-server/minecraft-patches/features/0012-Optimise-cannon-entity-movement.patch +++ b/sakura-server/minecraft-patches/features/0012-Optimise-cannon-entity-movement.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimise cannon entity movement diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 46843fb00310923dc4da31e4554a40696eba57b8..2f80403bb400e88395df9d46a39c4adf69e479d7 100644 +index bf46bb5b61f4ec6f23aacec41426d0ffe5a265fb..eaa57560a20841a2b218ff2fd9059f82339a678c 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -1191,7 +1191,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1190,7 +1190,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess Vec3 vec3 = this.collide(movement); double d = vec3.lengthSqr(); if (d > 1.0E-7 || movement.lengthSqr() - d < 1.0E-7) { @@ -17,19 +17,19 @@ index 46843fb00310923dc4da31e4554a40696eba57b8..2f80403bb400e88395df9d46a39c4adf BlockHitResult blockHitResult = this.level() .clip( new ClipContext(this.position(), this.position().add(vec3), ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this) -@@ -1539,6 +1539,131 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1538,6 +1538,132 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return distance; } + // Sakura start - optimise cannon entity movement -+ protected final Vec3 sakura_collide(Vec3 movement) { ++ protected final Vec3 sakura_collide(final Vec3 movement) { + if (movement.x == 0.0 && movement.y == 0.0 && movement.z == 0.0) { + return movement; + } + -+ List potentialCollisionsVoxel = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(0); -+ List potentialCollisionsBB = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(4); -+ AABB currBoundingBox = this.getBoundingBox(); ++ final List potentialCollisionsVoxel = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(0); ++ 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 + return this.collideAxisScan(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB); @@ -38,7 +38,7 @@ index 46843fb00310923dc4da31e4554a40696eba57b8..2f80403bb400e88395df9d46a39c4adf + } + } + -+ private Vec3 collideCube(Vec3 movement, AABB currBoundingBox, List voxelList, List bbList) { ++ private Vec3 collideCube(final Vec3 movement, final AABB currBoundingBox, final List voxelList, final List bbList) { + final AABB bb; + if (movement.x() == 0.0 && movement.z() == 0.0) { + if (movement.y > 0.0) { @@ -49,16 +49,17 @@ index 46843fb00310923dc4da31e4554a40696eba57b8..2f80403bb400e88395df9d46a39c4adf + } else { + bb = currBoundingBox.expandTowards(movement.x, movement.y, movement.z); + } ++ + this.collectCollisions(bb, voxelList, bbList, ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER); + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currBoundingBox, voxelList, bbList); + } + -+ private Vec3 collideAxisScan(Vec3 movement, AABB currBoundingBox, List voxelList, List bbList) { ++ private Vec3 collideAxisScan(final Vec3 movement, AABB currBoundingBox, final List voxelList, final List bbList) { + double x = movement.x; + double y = movement.y; + double z = movement.z; + -+ boolean xSmaller = Math.abs(x) < Math.abs(z); ++ final boolean xSmaller = Math.abs(x) < Math.abs(z); + + if (y != 0.0) { + y = this.scanY(currBoundingBox, y, voxelList, bbList); @@ -88,7 +89,7 @@ index 46843fb00310923dc4da31e4554a40696eba57b8..2f80403bb400e88395df9d46a39c4adf + return new Vec3(x, y, z); + } + -+ private void collectCollisions(AABB collisionBox, List voxelList, List bbList, int flags) { ++ private void collectCollisions(final AABB collisionBox, final List voxelList, final List bbList, final int flags) { + // Copied from the collide method below + ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisionsForBlocksOrWorldBorder( + this.level, this, collisionBox, voxelList, bbList, @@ -100,28 +101,28 @@ index 46843fb00310923dc4da31e4554a40696eba57b8..2f80403bb400e88395df9d46a39c4adf + ); + } + -+ private double scanX(AABB currBoundingBox, double x, List voxelList, List bbList) { -+ AABB scanBox = cutBoundingBoxX(currBoundingBox, x); ++ private double scanX(final AABB currBoundingBox, double x, final List voxelList, final List bbList) { ++ final AABB scanBox = cutBoundingBoxX(currBoundingBox, x); + this.collectCollisions(scanBox, voxelList, bbList, ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER); + x = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsX(currBoundingBox, x, bbList); + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsX(currBoundingBox, x, voxelList); + } + -+ private double scanY(AABB currBoundingBox, double y, List voxelList, List bbList) { -+ AABB scanBox = cutBoundingBoxY(currBoundingBox, y); ++ 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); + y = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsY(currBoundingBox, y, bbList); + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsY(currBoundingBox, y, voxelList); + } + -+ private double scanZ(AABB currBoundingBox, double z, List voxelList, List bbList) { -+ AABB scanBox = cutBoundingBoxZ(currBoundingBox, z); ++ private double scanZ(final AABB currBoundingBox, double z, final List voxelList, final List bbList) { ++ final AABB scanBox = cutBoundingBoxZ(currBoundingBox, z); + this.collectCollisions(scanBox, voxelList, bbList, ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER); + z = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsZ(currBoundingBox, z, bbList); + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsZ(currBoundingBox, z, voxelList); + } + -+ private static AABB cutBoundingBoxX(AABB bb, double x) { ++ private static AABB cutBoundingBoxX(final AABB bb, final double x) { + if (x > 0.0) { + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.cutRight(bb, x); + } else { @@ -129,7 +130,7 @@ index 46843fb00310923dc4da31e4554a40696eba57b8..2f80403bb400e88395df9d46a39c4adf + } + } + -+ private static AABB cutBoundingBoxY(AABB bb, double y) { ++ private static AABB cutBoundingBoxY(final AABB bb, final double y) { + if (y > 0.0) { + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.cutUpwards(bb, y); + } else { @@ -137,7 +138,7 @@ index 46843fb00310923dc4da31e4554a40696eba57b8..2f80403bb400e88395df9d46a39c4adf + } + } + -+ private static AABB cutBoundingBoxZ(AABB bb, double z) { ++ private static AABB cutBoundingBoxZ(final AABB bb, final double z) { + if (z > 0.0) { + return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.cutForwards(bb, z); + } else { @@ -150,7 +151,7 @@ index 46843fb00310923dc4da31e4554a40696eba57b8..2f80403bb400e88395df9d46a39c4adf protected Vec3 collide(Vec3 movement) { final boolean xZero = movement.x == 0.0; diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java -index d65df5f13e038d109870d1f7fba50d2260489d49..0b4cb90a6877c2af4ef1eccd502b50c863bf74b0 100644 +index 8ea534e6f49b787f5445093203f41410668e42bd..f7807b56bf935e1686ac893c0752e92e1115ffbe 100644 --- a/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -124,6 +124,12 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti @@ -159,7 +160,7 @@ index d65df5f13e038d109870d1f7fba50d2260489d49..0b4cb90a6877c2af4ef1eccd502b50c8 // Sakura end - merge cannon entities + // Sakura start - optimise cannon entity movement + @Override -+ protected final Vec3 collide(Vec3 movement) { ++ protected final Vec3 collide(final Vec3 movement) { + return this.sakura_collide(movement); + } + // Sakura end - optimise cannon entity movement @@ -167,7 +168,7 @@ index d65df5f13e038d109870d1f7fba50d2260489d49..0b4cb90a6877c2af4ef1eccd502b50c8 public FallingBlockEntity(EntityType entityType, Level level) { super(entityType, level); diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java -index 8986a9876f9437fd8d65f4d43df3f39a98741210..9a4b9be72e896ad4def7caa89716c707cfb5cc06 100644 +index 45a528169a57ecc287ae4f527d1d98b597a48f04..e476d500df5e197f87863d9fdb61065af68778dd 100644 --- a/net/minecraft/world/entity/item/PrimedTnt.java +++ b/net/minecraft/world/entity/item/PrimedTnt.java @@ -82,6 +82,12 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak @@ -176,7 +177,7 @@ index 8986a9876f9437fd8d65f4d43df3f39a98741210..9a4b9be72e896ad4def7caa89716c707 // Sakura end - merge cannon entities + // Sakura start - optimise cannon entity movement + @Override -+ protected final net.minecraft.world.phys.Vec3 collide(net.minecraft.world.phys.Vec3 movement) { ++ protected final net.minecraft.world.phys.Vec3 collide(final net.minecraft.world.phys.Vec3 movement) { + return this.sakura_collide(movement); + } + // Sakura end - optimise cannon entity movement diff --git a/sakura-server/minecraft-patches/features/0015-Explosion-Durable-Blocks.patch b/sakura-server/minecraft-patches/features/0015-Explosion-Durable-Blocks.patch index 91b7b6f..4853c35 100644 --- a/sakura-server/minecraft-patches/features/0015-Explosion-Durable-Blocks.patch +++ b/sakura-server/minecraft-patches/features/0015-Explosion-Durable-Blocks.patch @@ -40,7 +40,7 @@ index 6db566adf2d0df1d26221eda04aa01738df6d3d2..23c135a6355e920535734e946e5bd4d0 return !interactionResult.consumesAction() && context.getItemInHand().has(DataComponents.CONSUMABLE) ? super.use(context.getLevel(), context.getPlayer(), context.getHand()) diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 7a922d26952be2f19161053542fa3a4b1a3bdf80..68cc49c65c3098f0aeb2d6dfbe75262e1fff1681 100644 +index 4a258b105b4d27f214178439df1c4ee569c12895..d4b2f81aebc888e6fe041537b71ac52d8dc8b4e7 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -830,6 +830,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @@ -52,7 +52,7 @@ index 7a922d26952be2f19161053542fa3a4b1a3bdf80..68cc49c65c3098f0aeb2d6dfbe75262e protected Level( WritableLevelData levelData, diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index dfe4058155a83ec213a37553996d2dbb9744881b..7f57531254031f7134fc6d72a5077aab5b48c7f0 100644 +index d2b33fb06ce9a806466208d7afd65fa8d3da0292..f8933e198a250f2184fb64bb987575b441ae8a32 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java @@ -131,7 +131,7 @@ public class ServerExplosion implements Explosion { @@ -64,7 +64,7 @@ index dfe4058155a83ec213a37553996d2dbb9744881b..7f57531254031f7134fc6d72a5077aab ret = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache( key, pos, blockState, fluidState, -@@ -390,6 +390,20 @@ public class ServerExplosion implements Explosion { +@@ -357,6 +357,20 @@ public class ServerExplosion implements Explosion { // Paper end - collision optimisations } // Sakura end - specialised explosions @@ -85,7 +85,7 @@ index dfe4058155a83ec213a37553996d2dbb9744881b..7f57531254031f7134fc6d72a5077aab public ServerExplosion( ServerLevel level, -@@ -770,6 +784,14 @@ public class ServerExplosion implements Explosion { +@@ -744,6 +758,14 @@ public class ServerExplosion implements Explosion { } } // CraftBukkit end diff --git a/sakura-server/minecraft-patches/features/0016-Destroy-Waterlogged-Blocks.patch b/sakura-server/minecraft-patches/features/0016-Destroy-Waterlogged-Blocks.patch index 2a4815d..7a05a5f 100644 --- a/sakura-server/minecraft-patches/features/0016-Destroy-Waterlogged-Blocks.patch +++ b/sakura-server/minecraft-patches/features/0016-Destroy-Waterlogged-Blocks.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Destroy Waterlogged Blocks diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 7f57531254031f7134fc6d72a5077aab5b48c7f0..0664de8feb17805647b7de186bd4a536b17d5aa7 100644 +index f8933e198a250f2184fb64bb987575b441ae8a32..f79e8f48a1f9a6964e1449c099df39076615dd88 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java -@@ -399,6 +399,11 @@ public class ServerExplosion implements Explosion { +@@ -366,6 +366,11 @@ public class ServerExplosion implements Explosion { if (material != null && material.replaceBlastResistance() && pos.getY() > this.level.getMinY()) { return Optional.of(material.resistance()); } 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 64fd562..80ae140 100644 --- a/sakura-server/minecraft-patches/features/0017-Configure-cannon-physics.patch +++ b/sakura-server/minecraft-patches/features/0017-Configure-cannon-physics.patch @@ -5,20 +5,20 @@ Subject: [PATCH] Configure cannon physics diff --git a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java -index 0f61c8877694679f590cb79f4a34cf158b8ad610..bfb220f0808767fec561d9903955514729a7448f 100644 +index 5cc6fe6984d59a94c037b2c327a5d72b5a2a740d..432bc933c4e31dff9737748e8b81521bfc45530a 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 { } public static Vec3 performAABBCollisions(final Vec3 moveVector, AABB axisalignedbb, final List potentialCollisions) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + return performAABBCollisions(moveVector, axisalignedbb, potentialCollisions, null); + } + public static Vec3 performAABBCollisions(final Vec3 moveVector, AABB axisalignedbb, + final List potentialCollisions, + final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget) { -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics double x = moveVector.x; double y = moveVector.y; double z = moveVector.z; @@ -27,7 +27,7 @@ index 0f61c8877694679f590cb79f4a34cf158b8ad610..bfb220f0808767fec561d99039555147 } - final boolean xSmaller = Math.abs(x) < Math.abs(z); -+ final boolean xSmaller = me.samsuik.sakura.mechanics.EntityBehaviour.prioritiseXFirst(x, z, mechanicsTarget); // Sakura - configure cannon physics ++ final boolean xSmaller = me.samsuik.sakura.mechanics.EntityBehaviour.prioritiseXFirst(x, z, mechanicsTarget); // Sakura - configure server mechanics if (xSmaller && z != 0.0) { z = performAABBCollisionsZ(axisalignedbb, z, potentialCollisions); @@ -35,7 +35,7 @@ index 0f61c8877694679f590cb79f4a34cf158b8ad610..bfb220f0808767fec561d99039555147 public static Vec3 performCollisions(final Vec3 moveVector, AABB axisalignedbb, final List voxels, final List aabbs) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + return performCollisions(moveVector, axisalignedbb, voxels, aabbs, null); + } + @@ -43,11 +43,11 @@ index 0f61c8877694679f590cb79f4a34cf158b8ad610..bfb220f0808767fec561d99039555147 + final List voxels, + final List aabbs, + final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget) { -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics if (voxels.isEmpty()) { // fast track only AABBs - return performAABBCollisions(moveVector, axisalignedbb, aabbs); -+ return performAABBCollisions(moveVector, axisalignedbb, aabbs, mechanicsTarget); // Sakura - configure cannon physics ++ return performAABBCollisions(moveVector, axisalignedbb, aabbs, mechanicsTarget); // Sakura - configure server mechanics } double x = moveVector.x; @@ -56,12 +56,12 @@ index 0f61c8877694679f590cb79f4a34cf158b8ad610..bfb220f0808767fec561d99039555147 } - final boolean xSmaller = Math.abs(x) < Math.abs(z); -+ final boolean xSmaller = me.samsuik.sakura.mechanics.EntityBehaviour.prioritiseXFirst(x, z, mechanicsTarget); // Sakura - configure cannon physics ++ final boolean xSmaller = me.samsuik.sakura.mechanics.EntityBehaviour.prioritiseXFirst(x, z, mechanicsTarget); // Sakura - configure server mechanics if (xSmaller && z != 0.0) { z = performAABBCollisionsZ(axisalignedbb, z, aabbs); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index c81cc505b211f230a816f2f5988b1aa793fa32db..a8ace187724ce0e26fd9b1d289ec1db4756b85b6 100644 +index eaa57560a20841a2b218ff2fd9059f82339a678c..098b5a8cfe1ce37f5c1ed51c2bb913990a820838 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -2,7 +2,6 @@ package net.minecraft.world.entity; @@ -72,100 +72,100 @@ index c81cc505b211f230a816f2f5988b1aa793fa32db..a8ace187724ce0e26fd9b1d289ec1db4 import com.google.common.collect.ImmutableList.Builder; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; -@@ -587,6 +586,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -586,6 +585,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } // Sakura end - merge cannon entities -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + protected me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = me.samsuik.sakura.mechanics.MinecraftMechanicsTarget.latest(); + + public final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget() { + return this.mechanicsTarget; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics public Entity(EntityType entityType, Level level) { this.type = entityType; -@@ -1111,7 +1117,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1110,7 +1116,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } protected void checkSupportingBlock(boolean onGround, @Nullable Vec3 movement) { - if (onGround) { -+ if (onGround && this.mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_20)) { // Sakura - configure cannon physics ++ if (onGround && this.mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_20)) { // Sakura - configure server mechanics AABB boundingBox = this.getBoundingBox(); AABB aabb = new AABB(boundingBox.minX, boundingBox.minY - 1.0E-6, boundingBox.minZ, boundingBox.maxX, boundingBox.minY, boundingBox.maxZ); Optional optional = this.level.findSupportingBlock(this, aabb); -@@ -1161,7 +1167,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1160,7 +1166,10 @@ 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 (type == MoverType.PISTON) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = this.mechanicsTarget; + if (type == MoverType.PISTON && mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_11)) { -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics // Paper start - EAR 2 this.activatedTick = Math.max(this.activatedTick, MinecraftServer.currentTick + 20); this.activatedImmunityTick = Math.max(this.activatedImmunityTick, MinecraftServer.currentTick + 20); -@@ -1190,8 +1199,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1189,8 +1198,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess movement = this.maybeBackOffFromEdge(movement, type); Vec3 vec3 = this.collide(movement); double d = vec3.lengthSqr(); - if (d > 1.0E-7 || movement.lengthSqr() - d < 1.0E-7) { - if (this.fallDistance != 0.0 && d >= 1.0 && !this.isFallingBlock) { // Sakura - optimise cannon entity movement -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (me.samsuik.sakura.mechanics.EntityBehaviour.canMoveEntity(d, movement, mechanicsTarget)) { + if (this.fallDistance != 0.0 && d >= 1.0 && !this.isFallingBlock && mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_18_2)) { // Sakura - optimise cannon entity movement -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics BlockHitResult blockHitResult = this.level() .clip( new ClipContext(this.position(), this.position().add(vec3), ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this) -@@ -1202,9 +1213,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1201,9 +1212,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } Vec3 vec31 = this.position(); - Vec3 vec32 = vec31.add(vec3); - this.addMovementThisTick(new Entity.Movement(vec31, vec32, true)); - this.setPos(vec32); -+ // Sakura - configure cannon physics ++ // Sakura start - configure server mechanics + if (mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_6)) { -+ me.samsuik.sakura.mechanics.EntityBehaviour.pre1_21_6$changeEntityPosition(this, vec31, vec3, mechanicsTarget); ++ me.samsuik.sakura.mechanics.EntityBehaviour.changeEntityPosition(this, vec31, vec3, mechanicsTarget); + } else { + Vec3 vec32 = vec31.add(vec3); + this.addMovementThisTick(new Entity.Movement(vec31, vec32, true)); + this.setPos(vec32); + } -+ // Sakura - configure cannon physics ++ // Sakura end - configure server mechanics } profilerFiller.pop(); -@@ -1235,6 +1252,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1234,6 +1251,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } else { if (this.horizontalCollision) { Vec3 deltaMovement = this.getDeltaMovement(); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (flag && flag1 && mechanicsTarget.between(me.samsuik.sakura.mechanics.MechanicVersion.v1_14, me.samsuik.sakura.mechanics.MechanicVersion.v1_18_2)) { + flag = false; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics this.setDeltaMovement(flag ? 0.0 : deltaMovement.x, deltaMovement.y, flag1 ? 0.0 : deltaMovement.z); } @@ -1568,7 +1590,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - bb = currBoundingBox.expandTowards(movement.x, movement.y, movement.z); } + this.collectCollisions(bb, voxelList, bbList, ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER); - 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.mechanicsTarget); // Sakura - configure cannon physics ++ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currBoundingBox, voxelList, bbList, this.mechanicsTarget); // Sakura - configure server mechanics } - private Vec3 collideAxisScan(Vec3 movement, AABB currBoundingBox, List voxelList, List bbList) { + private Vec3 collideAxisScan(final Vec3 movement, AABB currBoundingBox, final List voxelList, final List bbList) { @@ -1576,7 +1598,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess double y = movement.y; double z = movement.z; -- boolean xSmaller = Math.abs(x) < Math.abs(z); -+ boolean xSmaller = me.samsuik.sakura.mechanics.EntityBehaviour.prioritiseXFirst(x, z, mechanicsTarget); // Sakura - configure cannon physics +- final boolean xSmaller = Math.abs(x) < Math.abs(z); ++ final boolean xSmaller = me.samsuik.sakura.mechanics.EntityBehaviour.prioritiseXFirst(x, z, mechanicsTarget); // Sakura - configure server mechanics if (y != 0.0) { y = this.scanY(currBoundingBox, y, voxelList, bbList); @@ -174,7 +174,7 @@ index c81cc505b211f230a816f2f5988b1aa793fa32db..a8ace187724ce0e26fd9b1d289ec1db4 ); 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.mechanicsTarget); // Sakura - configure cannon physics ++ final Vec3 collided = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currentBox, potentialCollisionsVoxel, potentialCollisionsBB, this.mechanicsTarget); // Sakura - configure server mechanics final boolean collidedX = collided.x != movement.x; final boolean collidedY = collided.y != movement.y; @@ -183,7 +183,7 @@ index c81cc505b211f230a816f2f5988b1aa793fa32db..a8ace187724ce0e26fd9b1d289ec1db4 private void checkInsideBlocks(Vec3 vec3, Vec3 vec31, InsideBlockEffectApplier.StepBasedCollector stepBasedCollector, LongSet set) { - AABB aabb = this.makeBoundingBox(vec31).deflate(1.0E-5F); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + final double margin; + if (this.mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_2)) { + margin = 1.0e-5f; @@ -193,24 +193,24 @@ index c81cc505b211f230a816f2f5988b1aa793fa32db..a8ace187724ce0e26fd9b1d289ec1db4 + margin = 0.001; + } + AABB aabb = this.makeBoundingBox(vec31).deflate(margin); -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics BlockGetter.forEachBlockIntersectedBetween( vec3, vec31, aabb, -+ this.mechanicsTarget, // Sakura - configure cannon physics ++ this.mechanicsTarget, // Sakura - configure server mechanics (pos, index) -> { if (!this.isAlive()) { return false; diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java -index 0b4cb90a6877c2af4ef1eccd502b50c863bf74b0..33e8073651099d6a3d82fe0886424d5aa3886c5d 100644 +index f7807b56bf935e1686ac893c0752e92e1115ffbe..297310605e3ed4dbd3db40ff3cddb8eee6f3f508 100644 --- a/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/net/minecraft/world/entity/item/FallingBlockEntity.java @@ -130,6 +130,25 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti return this.sakura_collide(movement); } // Sakura end - optimise cannon entity movement -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + @Override + public final double distanceToSqr(final Vec3 vector) { + if (!this.mechanicsTarget.isLegacy()) { @@ -228,7 +228,7 @@ index 0b4cb90a6877c2af4ef1eccd502b50c863bf74b0..33e8073651099d6a3d82fe0886424d5a + // L stackers and midairs may still encounter issues if they shoot too high. + return BlockPos.containing(this.getX(), this.getY() + 1.0e-12, this.getZ()); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics public FallingBlockEntity(EntityType entityType, Level level) { super(entityType, level); @@ -236,53 +236,53 @@ index 0b4cb90a6877c2af4ef1eccd502b50c863bf74b0..33e8073651099d6a3d82fe0886424d5a this.yo = y; this.zo = z; this.setStartPos(this.blockPosition()); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + this.mechanicsTarget = level.localConfig().at(this.blockPosition()).mechanicsTarget; + this.eyeHeight = this.mechanicsTarget.isLegacy() ? 0.49f : this.eyeHeight; -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics } // Sakura start - falling block height parity api -@@ -182,7 +205,11 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti +@@ -181,7 +204,11 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti blockState.hasProperty(BlockStateProperties.WATERLOGGED) ? blockState.setValue(BlockStateProperties.WATERLOGGED, false) : blockState ); if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(fallingBlockEntity, pos, blockState.getFluidState().createLegacyBlock())) return fallingBlockEntity; // CraftBukkit - level.setBlock(pos, blockState.getFluidState().createLegacyBlock(), 3); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (fallingBlockEntity.mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_18_2)) { + level.setBlock(pos, blockState.getFluidState().createLegacyBlock(), 3); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics level.addFreshEntity(fallingBlockEntity); return fallingBlockEntity; } -@@ -226,7 +253,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti +@@ -225,7 +252,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti @Override protected double getDefaultGravity() { - return 0.04; -+ return this.mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_14) ? 0.04f : 0.04; // Sakura - configure cannon physics ++ return this.mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_14) ? 0.04f : 0.04; // Sakura - configure server mechanics } @Override -@@ -235,6 +262,12 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti +@@ -234,6 +261,12 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause } else { Block block = this.blockState.getBlock(); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = this.mechanicsTarget; + if (this.time == 0 && mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_18_2)) { + me.samsuik.sakura.mechanics.FallingBlockBehaviour.removeBlockOnFall(this, block); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics this.time++; this.applyGravity(); this.move(MoverType.SELF, this.getDeltaMovement()); -@@ -249,8 +282,15 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti +@@ -248,8 +281,15 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } // Paper end - Configurable falling blocks height nerf this.handlePortal(); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_12)) { + this.setDeltaMovement(this.getDeltaMovement().scale(0.98F)); + } @@ -291,51 +291,51 @@ index 0b4cb90a6877c2af4ef1eccd502b50c863bf74b0..33e8073651099d6a3d82fe0886424d5a + BlockPos blockPos = mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_17) + ? this.patchedBlockPosition() // Mitigate MC-261789 + : this.blockPosition(); -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics boolean flag = this.level().sakuraConfig().cannons.sand.concreteSolidifyInWater && this.blockState.getBlock() instanceof ConcretePowderBlock; // Sakura - configure concrete solidifying in water boolean flag1 = flag && this.level().getFluidState(blockPos).is(FluidTags.WATER); double d = this.getDeltaMovement().lengthSqr(); -@@ -277,8 +317,13 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti +@@ -276,8 +316,13 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } } else { BlockState blockState = this.level().getBlockState(blockPos); - this.setDeltaMovement(this.getDeltaMovement().multiply(0.7, -0.5, 0.7)); - if (!blockState.is(Blocks.MOVING_PISTON)) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + final double friction = mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_14) + ? 0.7f + : 0.7; + this.setDeltaMovement(this.getDeltaMovement().multiply(friction, -0.5, friction)); + if (!blockState.is(Blocks.MOVING_PISTON) && (flag1 || me.samsuik.sakura.mechanics.FallingBlockBehaviour.isAbleToStackOnBlock(this, mechanicsTarget))) { -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics if (!this.cancelDrop) { boolean canBeReplaced = blockState.canBeReplaced( new DirectionalPlaceContext(this.level(), blockPos, Direction.DOWN, ItemStack.EMPTY, Direction.UP) -@@ -351,7 +396,14 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti +@@ -350,7 +395,14 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } } - this.setDeltaMovement(this.getDeltaMovement().scale(0.98)); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_12)) { + final double drag = mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_14) + ? 0.98f + : 0.98; + this.setDeltaMovement(this.getDeltaMovement().scale(drag)); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics } } diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java -index 9a4b9be72e896ad4def7caa89716c707cfb5cc06..c36d00d8d96f279dfd725df91a24a28894a06250 100644 +index e476d500df5e197f87863d9fdb61065af68778dd..135e1174115a7ed90245be47bd998833ddbe7d68 100644 --- a/net/minecraft/world/entity/item/PrimedTnt.java +++ b/net/minecraft/world/entity/item/PrimedTnt.java @@ -88,6 +88,23 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak return this.sakura_collide(movement); } // Sakura end - optimise cannon entity movement -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + @Override + public final double getEyeY() { + return this.mechanicsTarget.isLegacy() ? super.getEyeY() : this.getY(); @@ -351,7 +351,7 @@ index 9a4b9be72e896ad4def7caa89716c707cfb5cc06..c36d00d8d96f279dfd725df91a24a288 + final double z = this.getZ() - vector.z; + return x * x + y * y + z * z; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics public PrimedTnt(EntityType entityType, Level level) { super(entityType, level); @@ -359,13 +359,13 @@ index 9a4b9be72e896ad4def7caa89716c707cfb5cc06..c36d00d8d96f279dfd725df91a24a288 case Y -> this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0)); } // Sakura end - configure cannon mechanics -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + this.mechanicsTarget = level.localConfig().at(this.blockPosition()).mechanicsTarget; + this.eyeHeight = this.mechanicsTarget.isLegacy() ? 0.49f : this.eyeHeight; + if (this.mechanicsTarget.isLegacy()) { + this.setDeltaMovement(this.getDeltaMovement().multiply(0.0, 1.0, 0.0)); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics } // Sakura start - optimise tnt fluid state @@ -374,7 +374,7 @@ index 9a4b9be72e896ad4def7caa89716c707cfb5cc06..c36d00d8d96f279dfd725df91a24a288 @Override protected double getDefaultGravity() { - return 0.04; -+ return this.mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_14) ? 0.04f : 0.04; // Sakura - configure cannon physics ++ return this.mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_14) ? 0.04f : 0.04; // Sakura - configure server mechanics } @Override @@ -383,7 +383,7 @@ index 9a4b9be72e896ad4def7caa89716c707cfb5cc06..c36d00d8d96f279dfd725df91a24a288 } // Paper end - Configurable TNT height nerf - this.setDeltaMovement(this.getDeltaMovement().scale(0.98)); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = this.mechanicsTarget; + final double drag = mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_14) + ? 0.98f @@ -395,13 +395,13 @@ index 9a4b9be72e896ad4def7caa89716c707cfb5cc06..c36d00d8d96f279dfd725df91a24a288 + ? 0.7f + : 0.7; + this.setDeltaMovement(this.getDeltaMovement().multiply(friction, -0.5, friction)); -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics } int i = this.getFuse() - 1; this.setFuse(i); - if (i <= 0) { -+ if (mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_9) ? (i < 0) : (i <= 0)) { // Sakura - configure cannon physics ++ if (mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_9) ? (i < 0) : (i <= 0)) { // Sakura - configure server mechanics // 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.tryToRespawnEntity(); // Sakura - merge cannon entities @@ -409,12 +409,12 @@ index 9a4b9be72e896ad4def7caa89716c707cfb5cc06..c36d00d8d96f279dfd725df91a24a288 return; } // CraftBukkit end -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + // Undocumented on the minecraft wiki but the explosion position did change in 1.10 + final double explosionY = this.mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_10) + ? this.getY() + (double) 0.49f + : this.getY(0.0625D); -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics this.level() .explode( this, @@ -422,7 +422,7 @@ index 9a4b9be72e896ad4def7caa89716c707cfb5cc06..c36d00d8d96f279dfd725df91a24a288 this.usedPortal ? USED_PORTAL_DAMAGE_CALCULATOR : null, this.getX(), - this.getY(0.0625), -+ explosionY, // Sakura - configure cannon physics ++ explosionY, // Sakura - configure server mechanics this.getZ(), event.getRadius(), // CraftBukkit event.getFire(), // CraftBukkit @@ -431,19 +431,19 @@ index 9a4b9be72e896ad4def7caa89716c707cfb5cc06..c36d00d8d96f279dfd725df91a24a288 @Override public boolean isPushedByFluid() { - return !this.level().paperConfig().fixes.preventTntFromMovingInWater && this.level().sakuraConfig().cannons.mechanics.tntFlowsInWater && super.isPushedByFluid(); // Sakura - configure cannon mechanics -+ return !this.level().paperConfig().fixes.preventTntFromMovingInWater && this.level().sakuraConfig().cannons.mechanics.tntFlowsInWater && !this.mechanicsTarget.isLegacy() && super.isPushedByFluid(); // Sakura - configure cannon physics // Sakura - configure cannon mechanics ++ return !this.level().paperConfig().fixes.preventTntFromMovingInWater && this.level().sakuraConfig().cannons.mechanics.tntFlowsInWater && !this.mechanicsTarget.isLegacy() && super.isPushedByFluid(); // Sakura - configure server mechanics // Sakura - configure cannon mechanics } // Paper end - Option to prevent TNT from moving in water } diff --git a/net/minecraft/world/level/BlockGetter.java b/net/minecraft/world/level/BlockGetter.java -index 2146efa860d8323a88f3ad365c0cdb66de42154a..353ad0c1db2ee374ac5487539c77b2b067dc7c0a 100644 +index 2146efa860d8323a88f3ad365c0cdb66de42154a..b6ddb1ad889a115daeba64321d38b236033f62ff 100644 --- a/net/minecraft/world/level/BlockGetter.java +++ b/net/minecraft/world/level/BlockGetter.java @@ -213,8 +213,20 @@ public interface BlockGetter extends LevelHeightAccessor { } static boolean forEachBlockIntersectedBetween(Vec3 from, Vec3 to, AABB boundingBox, BlockGetter.BlockStepVisitor visitor) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + return forEachBlockIntersectedBetween(from, to, boundingBox, null, visitor); + } + @@ -457,35 +457,35 @@ index 2146efa860d8323a88f3ad365c0cdb66de42154a..353ad0c1db2ee374ac5487539c77b2b0 Vec3 vec3 = to.subtract(from); - if (vec3.lengthSqr() < Mth.square(0.99999F)) { + if (vec3.lengthSqr() < Mth.square(0.99999F) || mechanicsTarget != null && mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_2)) { -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics for (BlockPos blockPos : BlockPos.betweenClosed(boundingBox)) { if (!visitor.visit(blockPos, 0)) { return false; diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 0664de8feb17805647b7de186bd4a536b17d5aa7..4d62f6bf353d2c23d0b8918b728b442bfb150628 100644 +index f79e8f48a1f9a6964e1449c099df39076615dd88..e79de0fc3102c107d2c49e1b084b65d5c667e6e3 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java -@@ -409,6 +409,7 @@ public class ServerExplosion implements Explosion { +@@ -376,6 +376,7 @@ public class ServerExplosion implements Explosion { return this.damageCalculator.getBlockExplosionResistance(this, this.level, pos, blockState, fluidState); } // Sakura end - explosion durable blocks -+ protected final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget; // Sakura - configure cannon physics ++ protected final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget; // Sakura - configure server mechanics public ServerExplosion( ServerLevel level, -@@ -433,6 +434,7 @@ public class ServerExplosion implements Explosion { +@@ -400,6 +401,7 @@ public class ServerExplosion implements Explosion { this.yield = Double.isFinite(this.yield) ? this.yield : 0; // Paper - Don't allow infinite default yields // Paper end - add yield this.consistentExplosionRadius = level.localConfig().at(this.center).consistentExplosionRadius; // Sakura - consistent explosion radius -+ this.mechanicsTarget = source != null ? source.mechanicsTarget() : level.localConfig().at(this.center).mechanicsTarget; // Sakura - configure cannon physics ++ this.mechanicsTarget = source != null ? source.mechanicsTarget() : level.localConfig().at(this.center).mechanicsTarget; // Sakura - configure server mechanics } private ExplosionDamageCalculator makeDamageCalculator(@Nullable Entity entity) { -@@ -462,8 +464,15 @@ public class ServerExplosion implements Explosion { +@@ -429,8 +431,15 @@ public class ServerExplosion implements Explosion { final float density = entity.level().densityCache.getKnownDensity(vec3); 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 - configure cannon physics ++ // Sakura start - configure server mechanics + } else if (entity.mechanicsTarget().before(me.samsuik.sakura.mechanics.MechanicVersion.v1_14)) { + hitResult = me.samsuik.sakura.mechanics.LegacyExplosionBlockClipping.clip(entity.level(), vec3, explosionVector); } else { @@ -494,15 +494,15 @@ index 0664de8feb17805647b7de186bd4a536b17d5aa7..4d62f6bf353d2c23d0b8918b728b442b + ? ClipContext.Block.COLLIDER + : ClipContext.Block.OUTLINE; + hitResult = entity.level().clip(new ClipContext(vec3, explosionVector, blockContext, ClipContext.Fluid.NONE, entity)).getType(); -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics } if (hitResult == HitResult.Type.MISS) { // Sakura end - replace density cache -@@ -561,6 +570,15 @@ public class ServerExplosion implements Explosion { +@@ -528,6 +537,15 @@ public class ServerExplosion implements Explosion { } if (cachedBlock.outOfWorld) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (this.mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_17)) { + power -= 0.22500001F; + currX += incX; @@ -510,58 +510,58 @@ index 0664de8feb17805647b7de186bd4a536b17d5aa7..4d62f6bf353d2c23d0b8918b728b442b + currZ += incZ; + continue; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics break; } final BlockState iblockdata = cachedBlock.blockState; -@@ -656,6 +674,12 @@ public class ServerExplosion implements Explosion { +@@ -630,6 +648,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 squareRoot = Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (this.mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_17)) { + d = (float) d; + squareRoot = (float) squareRoot; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics if (squareRoot != 0.0) { d1 /= squareRoot; d2 /= squareRoot; -@@ -939,7 +963,7 @@ public class ServerExplosion implements Explosion { +@@ -913,7 +937,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 - configure cannon physics ++ blockDensity = this.sakura_getSeenPercent(vec3d, entity); // Sakura - configure server mechanics this.level.densityCache.putDensity(vec3d, entity, blockDensity); // Sakura end - replace density cache } -@@ -947,6 +971,16 @@ public class ServerExplosion implements Explosion { +@@ -921,6 +945,16 @@ public class ServerExplosion implements Explosion { return blockDensity; } -+ // Sakura start - configure cannon physics -+ private float sakura_getSeenPercent(Vec3 vec3d, Entity entity) { ++ // Sakura start - configure server mechanics ++ private float sakura_getSeenPercent(final Vec3 vec3d, final Entity entity) { + if (this.mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_16)) { + return this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations + } else { + return getSeenPercent(vec3d, entity); + } + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics + static class CacheKey { private final Level world; private final double posX, posY, posZ; diff --git a/net/minecraft/world/level/block/FallingBlock.java b/net/minecraft/world/level/block/FallingBlock.java -index 4fa238d1cd6b19f16c0d0a8a9a913e9e42debbed..235dbd5289165f9858727bee47a539e8d8b4eb15 100644 +index 4fa238d1cd6b19f16c0d0a8a9a913e9e42debbed..96a02601636cdf7cf6e360fc933e5764fbb7eab8 100644 --- a/net/minecraft/world/level/block/FallingBlock.java +++ b/net/minecraft/world/level/block/FallingBlock.java @@ -45,6 +45,22 @@ public abstract class FallingBlock extends Block implements Fallable { return super.updateShape(state, level, scheduledTickAccess, pos, direction, neighborPos, neighborState, random); } -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + @Override + public void neighborChanged( + final BlockState state, @@ -575,13 +575,13 @@ index 4fa238d1cd6b19f16c0d0a8a9a913e9e42debbed..235dbd5289165f9858727bee47a539e8 + level.scheduleTick(pos, this, this.getDelayAfterPlace()); + } + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics + @Override protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { if (isFree(level.getBlockState(pos.below())) && pos.getY() >= level.getMinY()) { diff --git a/net/minecraft/world/level/block/FenceGateBlock.java b/net/minecraft/world/level/block/FenceGateBlock.java -index a5e686b90e532e3b656fca411936499c2b2020c7..5a699e581dd7bd89b14b4c27996740c93240ba80 100644 +index a5e686b90e532e3b656fca411936499c2b2020c7..4e689171f7c3344442d7827e6d2aa1dea46a61a2 100644 --- a/net/minecraft/world/level/block/FenceGateBlock.java +++ b/net/minecraft/world/level/block/FenceGateBlock.java @@ -210,8 +210,15 @@ public class FenceGateBlock extends HorizontalDirectionalBlock { @@ -590,7 +590,7 @@ index a5e686b90e532e3b656fca411936499c2b2020c7..5a699e581dd7bd89b14b4c27996740c9 // CraftBukkit end - if (state.getValue(POWERED) != hasNeighborSignal) { - level.setBlock(pos, state.setValue(POWERED, hasNeighborSignal).setValue(OPEN, hasNeighborSignal), 2); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + final boolean pre1_10_0 = level.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_10); + final boolean powered = state.getValue(POWERED); + if (pre1_10_0 ? (hasNeighborSignal || neighborBlock.defaultBlockState().isSignalSource()) : powered != hasNeighborSignal) { @@ -598,12 +598,12 @@ index a5e686b90e532e3b656fca411936499c2b2020c7..5a699e581dd7bd89b14b4c27996740c9 + ? state.getValue(OPEN) + : hasNeighborSignal; + level.setBlock(pos, state.setValue(POWERED, hasNeighborSignal).setValue(OPEN, openGate), 2); -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics if (state.getValue(OPEN) != hasNeighborSignal) { level.playSound( null, diff --git a/net/minecraft/world/level/block/HoneyBlock.java b/net/minecraft/world/level/block/HoneyBlock.java -index a98c308c5febd458d6489174b94898cd4b9bae69..53de53eaba377cc25204eb11dafbbf87fdde8aa2 100644 +index a98c308c5febd458d6489174b94898cd4b9bae69..3b0afe1fdfa6f992903acf8fc56a4031d08083a1 100644 --- a/net/minecraft/world/level/block/HoneyBlock.java +++ b/net/minecraft/world/level/block/HoneyBlock.java @@ -71,11 +71,19 @@ public class HoneyBlock extends HalfTransparentBlock { @@ -611,7 +611,7 @@ index a98c308c5febd458d6489174b94898cd4b9bae69..53de53eaba377cc25204eb11dafbbf87 } - private static double getOldDeltaY(double deltaY) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + private static double getOldDeltaY(final double deltaY, final Entity entity) { + if (entity.mechanicsTarget().before(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_2)) { + return deltaY; @@ -624,7 +624,7 @@ index a98c308c5febd458d6489174b94898cd4b9bae69..53de53eaba377cc25204eb11dafbbf87 + if (entity.mechanicsTarget().before(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_2)) { + return deltaY; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics return (deltaY - 0.08) * 0.98F; } @@ -633,7 +633,7 @@ index a98c308c5febd458d6489174b94898cd4b9bae69..53de53eaba377cc25204eb11dafbbf87 } else if (entity.getY() > 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 - configure cannon physics ++ } else if (getOldDeltaY(entity.getDeltaMovement().y, entity) >= -0.08) { // Sakura - configure server mechanics return false; } else { double abs = Math.abs(pos.getX() + 0.5 - entity.getX()); @@ -644,33 +644,33 @@ index a98c308c5febd458d6489174b94898cd4b9bae69..53de53eaba377cc25204eb11dafbbf87 - if (getOldDeltaY(entity.getDeltaMovement().y) < -0.13) { - double d = -0.05 / getOldDeltaY(entity.getDeltaMovement().y); - entity.setDeltaMovement(new Vec3(deltaMovement.x * d, getNewDeltaY(-0.05), deltaMovement.z * d)); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (getOldDeltaY(entity.getDeltaMovement().y, entity) < -0.13) { + double d = -0.05 / getOldDeltaY(entity.getDeltaMovement().y, entity); + entity.setDeltaMovement(new Vec3(deltaMovement.x * d, getNewDeltaY(-0.05, entity), deltaMovement.z * d)); } else { - entity.setDeltaMovement(new Vec3(deltaMovement.x, getNewDeltaY(-0.05), deltaMovement.z)); + entity.setDeltaMovement(new Vec3(deltaMovement.x, getNewDeltaY(-0.05, entity), deltaMovement.z)); -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics } entity.resetFallDistance(); diff --git a/net/minecraft/world/level/block/LadderBlock.java b/net/minecraft/world/level/block/LadderBlock.java -index f9c305de60a323b450a26c9d7de50a824492cf5a..8ff7887089d217464649142f72cc7f2e901f9dd7 100644 +index f9c305de60a323b450a26c9d7de50a824492cf5a..c4987294763a82f5f065f726d48fa61dda097f6a 100644 --- a/net/minecraft/world/level/block/LadderBlock.java +++ b/net/minecraft/world/level/block/LadderBlock.java @@ -33,6 +33,15 @@ public class LadderBlock extends Block implements SimpleWaterloggedBlock { return CODEC; } -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + public static final Map LEGACY_SHAPES = Shapes.rotateHorizontal(Block.boxZ(16.0, 14.0, 16.0)); + + @Override + public boolean hasDynamicShape() { + return true; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics + protected LadderBlock(BlockBehaviour.Properties properties) { super(properties); @@ -679,16 +679,16 @@ index f9c305de60a323b450a26c9d7de50a824492cf5a..8ff7887089d217464649142f72cc7f2e @Override protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (level instanceof net.minecraft.world.level.Level gameLevel && gameLevel.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_9)) { + return LEGACY_SHAPES.get(state.getValue(FACING)); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics return SHAPES.get(state.getValue(FACING)); } diff --git a/net/minecraft/world/level/block/LiquidBlock.java b/net/minecraft/world/level/block/LiquidBlock.java -index 4dbbfa34c085fd9777de5b4a6bf48dedfe8603b8..e6091c252f252373481f46a3ef119ddc32baddf0 100644 +index 4dbbfa34c085fd9777de5b4a6bf48dedfe8603b8..1bf1f20235ee2d1395c94648c3d5deedf3b31bab 100644 --- a/net/minecraft/world/level/block/LiquidBlock.java +++ b/net/minecraft/world/level/block/LiquidBlock.java @@ -195,7 +195,14 @@ public class LiquidBlock extends Block implements BucketPickup { @@ -696,19 +696,19 @@ index 4dbbfa34c085fd9777de5b4a6bf48dedfe8603b8..e6091c252f252373481f46a3ef119ddc // Sakura end - configure fluid ticking outside the world border if (level.getFluidState(blockPos).is(FluidTags.WATER)) { - Block block = level.getFluidState(pos).isSource() ? Blocks.OBSIDIAN : Blocks.COBBLESTONE; -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + final FluidState fluidState = state.getFluidState(); + final Block block = fluidState.isSource() ? Blocks.OBSIDIAN : Blocks.COBBLESTONE; + final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = level.localConfig().at(pos).mechanicsTarget; -+ if (block == Blocks.COBBLESTONE && !me.samsuik.sakura.mechanics.LiquidBehaviour.canLiquidSolidify(level, pos, fluidState, mechanicsTarget)) { ++ if (block == Blocks.COBBLESTONE && !me.samsuik.sakura.mechanics.LegacyBlockFormation.canLiquidFormBlock(level, pos, fluidState, mechanicsTarget)) { + return true; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics // CraftBukkit start if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, pos, block.defaultBlockState(), 3)) { this.fizz(level, pos); diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java -index a9db955a90e0b44d3c85e39f2f7ae9ea4f68a316..16f69f37bca2304ef032370c0ce991a682c345bc 100644 +index a9db955a90e0b44d3c85e39f2f7ae9ea4f68a316..9dbd97607866f8bd356044318ab670bcc794074f 100644 --- a/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/net/minecraft/world/level/block/RedStoneWireBlock.java @@ -542,7 +542,7 @@ public class RedStoneWireBlock extends Block { @@ -716,26 +716,26 @@ index a9db955a90e0b44d3c85e39f2f7ae9ea4f68a316..16f69f37bca2304ef032370c0ce991a6 @Override protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { - if (!player.getAbilities().mayBuild) { -+ if (!player.getAbilities().mayBuild || level.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_16)) { // Sakura - configure cannon physics ++ if (!player.getAbilities().mayBuild || level.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_16)) { // Sakura - configure server mechanics return InteractionResult.PASS; } else { if (isCross(state) || isDot(state)) { diff --git a/net/minecraft/world/level/block/WaterlilyBlock.java b/net/minecraft/world/level/block/WaterlilyBlock.java -index 3b3047aa1198754e64913634f76fdc015c1fe07d..f8e2472430e4e3b79b3459d1c2de88c434a53914 100644 +index 3b3047aa1198754e64913634f76fdc015c1fe07d..4e88020dc0036145281f86b7f5eaf4620dd0dfef 100644 --- a/net/minecraft/world/level/block/WaterlilyBlock.java +++ b/net/minecraft/world/level/block/WaterlilyBlock.java @@ -24,6 +24,15 @@ public class WaterlilyBlock extends VegetationBlock { return CODEC; } -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + protected static final VoxelShape LEGACY_SHAPE = Block.column(16.0, 0.0, 0.25); + + @Override + public boolean hasDynamicShape() { + return true; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics + protected WaterlilyBlock(BlockBehaviour.Properties properties) { super(properties); @@ -744,23 +744,23 @@ index 3b3047aa1198754e64913634f76fdc015c1fe07d..f8e2472430e4e3b79b3459d1c2de88c4 @Override protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (level instanceof net.minecraft.world.level.Level gameLevel && gameLevel.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_9)) { + return LEGACY_SHAPE; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics return SHAPE; } diff --git a/net/minecraft/world/level/block/piston/MovingPistonBlock.java b/net/minecraft/world/level/block/piston/MovingPistonBlock.java -index 05bbc2e59384702439548a988e128a85f1adbe82..9c5ebb269fd434055de901bd058482b913f8c283 100644 +index 05bbc2e59384702439548a988e128a85f1adbe82..2f7d86b4d50ce4a3da6c1c4d2006c173bde66d86 100644 --- a/net/minecraft/world/level/block/piston/MovingPistonBlock.java +++ b/net/minecraft/world/level/block/piston/MovingPistonBlock.java @@ -100,6 +100,16 @@ public class MovingPistonBlock extends BaseEntityBlock { @Override protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { PistonMovingBlockEntity blockEntity = this.getBlockEntity(level, pos); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (blockEntity != null && level instanceof Level gameLevel && gameLevel.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_9)) { + final VoxelShape shape = blockEntity.getCollisionShapeFromProgress(level, pos); + if (context.isAbove(shape, pos, false)) { @@ -769,28 +769,28 @@ index 05bbc2e59384702439548a988e128a85f1adbe82..9c5ebb269fd434055de901bd058482b9 + return blockEntity.getMovedState().getCollisionShape(level, pos); + } + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics return blockEntity != null ? blockEntity.getCollisionShape(level, pos) : Shapes.empty(); } diff --git a/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/net/minecraft/world/level/block/piston/PistonBaseBlock.java -index c372c9f828f52af0d31cc9d20c00359fdb2a610a..cae08bc784f76e248573e996675beebf02ba05b0 100644 +index c372c9f828f52af0d31cc9d20c00359fdb2a610a..c890eb98a3f480e3f269ff56a81f280e7b7c100c 100644 --- a/net/minecraft/world/level/block/piston/PistonBaseBlock.java +++ b/net/minecraft/world/level/block/piston/PistonBaseBlock.java @@ -122,6 +122,11 @@ public class PistonBaseBlock extends DirectionalBlock { i = 2; } -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (level.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_9)) { + level.setBlock(pos, state.setValue(PistonBaseBlock.EXTENDED, false), Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics level.blockEvent(pos, this, i, direction.get3DDataValue()); } } diff --git a/net/minecraft/world/level/block/piston/PistonHeadBlock.java b/net/minecraft/world/level/block/piston/PistonHeadBlock.java -index 6c789e56f21f01252c21786cfeb48d88485b5636..e00611295c2b8e560e8ef7c78edbb6f952f6670c 100644 +index 6c789e56f21f01252c21786cfeb48d88485b5636..b325c24be64a3484d1084abc515599e77b535bed 100644 --- a/net/minecraft/world/level/block/piston/PistonHeadBlock.java +++ b/net/minecraft/world/level/block/piston/PistonHeadBlock.java @@ -3,6 +3,8 @@ package net.minecraft.world.level.block.piston; @@ -806,11 +806,11 @@ index 6c789e56f21f01252c21786cfeb48d88485b5636..e00611295c2b8e560e8ef7c78edbb6f9 @Override protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { BlockState blockState = level.getBlockState(pos.relative(state.getValue(FACING).getOpposite())); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (level instanceof Level gameLevel && gameLevel.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_9)) { + return this.isFittingBase(state, blockState); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics return this.isFittingBase(state, blockState) || blockState.is(Blocks.MOVING_PISTON) && blockState.getValue(FACING) == state.getValue(FACING); } @@ -818,22 +818,22 @@ index 6c789e56f21f01252c21786cfeb48d88485b5636..e00611295c2b8e560e8ef7c78edbb6f9 neighborBlock, ExperimentalRedstoneUtils.withFront(orientation, state.getValue(FACING).getOpposite()) ); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + } else if (level.localConfig().at(pos).mechanicsTarget.before(MechanicVersion.v1_9)) { + level.setBlock(pos, Blocks.AIR.defaultBlockState(), 19); -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics } } diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java -index e87b685d4a2bc31a1d7a1a31881152abc37563ba..583510a65df22926f21e0b7a98c124ae9e7b6454 100644 +index b5a17b441f046a8f2efd1b776a4620b55d99a854..dd20beab7f2ae2c804e00f822dfd6cc01aa635e1 100644 --- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java +++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java @@ -64,6 +64,163 @@ public class PistonMovingBlockEntity extends BlockEntity { this.isSourcePiston = isSourcePiston; } -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + @org.jspecify.annotations.Nullable + private AABB getBoundsFromProgress( + final BlockGetter level, @@ -988,7 +988,7 @@ index e87b685d4a2bc31a1d7a1a31881152abc37563ba..583510a65df22926f21e0b7a98c124ae + ); + entity.move(MoverType.PISTON, pistonMovement); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics + @Override public CompoundTag getUpdateTag(HolderLookup.Provider registries) { @@ -997,12 +997,12 @@ index e87b685d4a2bc31a1d7a1a31881152abc37563ba..583510a65df22926f21e0b7a98c124ae double d4 = 0.0; -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (entity.mechanicsTarget().before(me.samsuik.sakura.mechanics.MechanicVersion.v1_11)) { + moveEntityByPistonInDirection(movementDirection, entity, aabb); + return; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics for (AABB aabb1 : list) { AABB movementArea = PistonMath.getMovementArea(moveByPositionAndProgress(pos, aabb1, piston), movementDirection, d); AABB boundingBox = entity.getBoundingBox(); @@ -1010,11 +1010,11 @@ index e87b685d4a2bc31a1d7a1a31881152abc37563ba..583510a65df22926f21e0b7a98c124ae NOCLIP.set(noClipDirection); Vec3 vec3 = entity.position(); entity.move(MoverType.PISTON, new Vec3(progress * direction.getStepX(), progress * direction.getStepY(), progress * direction.getStepZ())); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (entity.mechanicsTarget().before(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_5)) { + vec3 = entity.oldPosition(); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics entity.applyEffectsFromBlocks(vec3, entity.position()); entity.removeLatestMovementRecording(); NOCLIP.set(null); @@ -1022,21 +1022,21 @@ index e87b685d4a2bc31a1d7a1a31881152abc37563ba..583510a65df22926f21e0b7a98c124ae } public static void tick(Level level, BlockPos pos, BlockState state, PistonMovingBlockEntity blockEntity) { -+ final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = level.localConfig().at(pos).mechanicsTarget; // Sakura - configure cannon physics ++ final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = level.localConfig().at(pos).mechanicsTarget; // Sakura - configure server mechanics blockEntity.lastTicked = level.getGameTime(); blockEntity.progressO = blockEntity.progress; if (blockEntity.progressO >= 1.0F) { if (level.isClientSide && blockEntity.deathTicks < 5) { blockEntity.deathTicks++; } else { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (mechanicsTarget.between(me.samsuik.sakura.mechanics.MechanicVersion.v1_9, me.samsuik.sakura.mechanics.MechanicVersion.v1_10)) { + moveCollidedEntities(level, pos, 1.0f, blockEntity); + moveStuckEntities(level, pos, 1.0f, blockEntity); + } else if (mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_9)) { + blockEntity.moveEntities(level, 0.25f); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics level.removeBlockEntity(pos); blockEntity.setRemoved(); if (level.getBlockState(pos).is(Blocks.MOVING_PISTON)) { @@ -1046,7 +1046,7 @@ index e87b685d4a2bc31a1d7a1a31881152abc37563ba..583510a65df22926f21e0b7a98c124ae float f = blockEntity.progress + 0.5F; - moveCollidedEntities(level, pos, f, blockEntity); - moveStuckEntities(level, pos, f, blockEntity); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_11)) { + moveCollidedEntities(level, pos, f, blockEntity); + moveStuckEntities(level, pos, f, blockEntity); @@ -1061,28 +1061,28 @@ index e87b685d4a2bc31a1d7a1a31881152abc37563ba..583510a65df22926f21e0b7a98c124ae + } else if (blockEntity.extending && mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_9)) { + blockEntity.moveEntities(level, blockEntity.progress - blockEntity.progressO + 0.0625f); + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics } } diff --git a/net/minecraft/world/level/material/LavaFluid.java b/net/minecraft/world/level/material/LavaFluid.java -index a5901d74f39216d770cf84b3ed3479c9195ec813..752099419e46070b42f9f2ecff1016d28a6ebf49 100644 +index 86401ba95530d10ee505d124dcbaaad6e0b800e9..1166ecc7e938341a65cbabb592fc998593afe835 100644 --- a/net/minecraft/world/level/material/LavaFluid.java +++ b/net/minecraft/world/level/material/LavaFluid.java @@ -184,6 +184,11 @@ public abstract class LavaFluid extends FlowingFluid { @Override public boolean canBeReplacedWith(FluidState fluidState, BlockGetter blockReader, BlockPos pos, Fluid fluid, Direction direction) { -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + if (blockReader instanceof Level level && level.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_13)) { + return false; + } -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics return fluidState.getHeight(blockReader, pos) >= 0.44444445F && fluid.is(FluidTags.WATER); } diff --git a/net/minecraft/world/level/material/WaterFluid.java b/net/minecraft/world/level/material/WaterFluid.java -index 10e3c644e31650b0e1aad6349a83a763cf744ec8..9fc1c56dec5201c3b700992f88b258225ceb8581 100644 +index 10e3c644e31650b0e1aad6349a83a763cf744ec8..62b90ee5c3ecdd82e0fbb7a7812cd59e8cbde567 100644 --- a/net/minecraft/world/level/material/WaterFluid.java +++ b/net/minecraft/world/level/material/WaterFluid.java @@ -124,7 +124,13 @@ public abstract class WaterFluid extends FlowingFluid { @@ -1090,13 +1090,13 @@ index 10e3c644e31650b0e1aad6349a83a763cf744ec8..9fc1c56dec5201c3b700992f88b25822 @Override public boolean canBeReplacedWith(FluidState fluidState, BlockGetter blockReader, BlockPos pos, Fluid fluid, Direction direction) { - return direction == Direction.DOWN && !fluid.is(FluidTags.WATER); -+ // Sakura start - configure cannon physics ++ // Sakura start - configure server mechanics + final boolean canReplace = direction == Direction.DOWN + || blockReader instanceof Level level + && level.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_13); + // Before 1.13 lava could replace water + return canReplace && !fluid.is(FluidTags.WATER); -+ // Sakura end - configure cannon physics ++ // Sakura end - configure server mechanics } @Override diff --git a/sakura-server/minecraft-patches/features/0018-Allow-explosions-to-destroy-lava.patch b/sakura-server/minecraft-patches/features/0018-Allow-explosions-to-destroy-lava.patch index 43b9195..a28be8f 100644 --- a/sakura-server/minecraft-patches/features/0018-Allow-explosions-to-destroy-lava.patch +++ b/sakura-server/minecraft-patches/features/0018-Allow-explosions-to-destroy-lava.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Allow explosions to destroy lava diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 26cd9559013ca2bb17b98f2675e7c43f76519d8b..3e4580903b85cb4aa4a48a9882a641f03d8a440d 100644 +index e79de0fc3102c107d2c49e1b084b65d5c667e6e3..3e4e09b886dea6642dbe86c52c5a475baad11734 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java -@@ -404,6 +404,11 @@ public class ServerExplosion implements Explosion { +@@ -371,6 +371,11 @@ public class ServerExplosion implements Explosion { return Optional.of(ZERO_RESISTANCE); } // Sakura end - destroy water logged blocks 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 d24e286..4b9a91e 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,7 +5,7 @@ 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 bfb220f0808767fec561d9903955514729a7448f..7dddc1fda846c362c0f3d0cae89e15aba37abf5a 100644 +index 432bc933c4e31dff9737748e8b81521bfc45530a..2b3f37b2c4add7fe5c5e9500cd087517fa11600b 100644 --- a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java +++ b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java @@ -1902,6 +1902,7 @@ public final class CollisionUtil { @@ -24,16 +24,16 @@ index bfb220f0808767fec561d9903955514729a7448f..7dddc1fda846c362c0f3d0cae89e15ab final ChunkSource chunkSource = world.getChunkSource(); for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { -@@ -1997,7 +1999,7 @@ public final class CollisionUtil { +@@ -1996,7 +1998,7 @@ public final class CollisionUtil { continue; } - final boolean hasSpecial = ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); -+ final boolean hasSpecial = !fullBlocks && ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); // Sakura - collide with non-solid blocks ++ final boolean hasSpecial = !fullBlocks && section.moonrise$hasSpecialCollidingBlocks(); // Sakura - collide with non-solid blocks final int sectionAdjust = !hasSpecial ? 1 : 0; final PalettedContainer blocks = section.states; -@@ -2036,6 +2038,11 @@ public final class CollisionUtil { +@@ -2035,6 +2037,11 @@ public final class CollisionUtil { mutablePos.set(blockX, blockY, blockZ); if (useEntityCollisionShape) { blockCollision = collisionShape.getCollisionShape(blockData, world, mutablePos); @@ -46,16 +46,16 @@ index bfb220f0808767fec561d9903955514729a7448f..7dddc1fda846c362c0f3d0cae89e15ab blockCollision = blockData.getCollisionShape(world, mutablePos, collisionShape); } diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index a8ace187724ce0e26fd9b1d289ec1db4756b85b6..e63a24188e07f50fc4ef67ca87866063fbc51516 100644 +index 88348c5e20041bcb1f327e601625980f4ab1392a..528d45eb5ff968ef14c3ff74a0c3bdb58ab21b86 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -547,6 +547,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -546,6 +546,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess flags |= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_ADD_TICKET; } + // Sakura start - collide with non-solid blocks + if (this.level().sakuraConfig().cannons.treatAllBlocksAsFullWhenMoving && (this.isPrimedTNT || this.isFallingBlock)) { -+ double horizontalMovementSqr = this.getDeltaMovement().horizontalDistanceSqr(); ++ final double horizontalMovementSqr = this.getDeltaMovement().horizontalDistanceSqr(); + if (horizontalMovementSqr > Math.pow(this.level().sakuraConfig().cannons.treatAllBlocksAsFullWhenMovingFasterThan, 2.0)) { + flags |= ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_FULL_BLOCKS; + } diff --git a/sakura-server/minecraft-patches/features/0020-Reduce-entity-tracker-player-updates.patch b/sakura-server/minecraft-patches/features/0020-Reduce-entity-tracker-player-updates.patch index 2f974a6..3303e0e 100644 --- a/sakura-server/minecraft-patches/features/0020-Reduce-entity-tracker-player-updates.patch +++ b/sakura-server/minecraft-patches/features/0020-Reduce-entity-tracker-player-updates.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Reduce entity tracker player updates diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index 07d8bb89ed0f9cea6353905939ba9f91c6fb64a5..684af8df952b0e58a86f6c3b72635190fdc4a938 100644 +index e164d7fbda422dbcffd753c3373b1c08fa3b5d68..98512bdd9cae7f4070587386382c0615074b122d 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java @@ -1015,7 +1015,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -30,7 +30,7 @@ index 07d8bb89ed0f9cea6353905939ba9f91c6fb64a5..684af8df952b0e58a86f6c3b72635190 + private net.minecraft.world.phys.Vec3 entityPosition; + + public final boolean shouldUpdatePlayers() { -+ // We have to always update players otherwise they can turn invisible on teleports (why?) ++ // Always update players otherwise they sometimes turn invisible when teleporting + if (this.entity instanceof net.minecraft.world.entity.player.Player || this.entity.tickCount % this.playerUpdateInterval == 0) { + return true; + } @@ -48,7 +48,7 @@ index 07d8bb89ed0f9cea6353905939ba9f91c6fb64a5..684af8df952b0e58a86f6c3b72635190 + // Sakura start - reduce entity tracker player updates + this.playerUpdateInterval = Math.min(updateInterval, 20); + this.entityPosition = entity.position(); -+ // Sakura start - reduce entity tracker player updates ++ // Sakura end - reduce entity tracker player updates } @Override diff --git a/sakura-server/minecraft-patches/features/0021-Legacy-lava-block-formation.patch b/sakura-server/minecraft-patches/features/0021-Legacy-lava-block-formation.patch index 2479152..49def34 100644 --- a/sakura-server/minecraft-patches/features/0021-Legacy-lava-block-formation.patch +++ b/sakura-server/minecraft-patches/features/0021-Legacy-lava-block-formation.patch @@ -5,11 +5,11 @@ Subject: [PATCH] Legacy lava block formation diff --git a/net/minecraft/world/level/block/LiquidBlock.java b/net/minecraft/world/level/block/LiquidBlock.java -index e6091c252f252373481f46a3ef119ddc32baddf0..cf624b29ed2b7ca2d6af24b3cac6bb316199d287 100644 +index 1bf1f20235ee2d1395c94648c3d5deedf3b31bab..7346bde5612d2d521390102fe8d7c82904b8df06 100644 --- a/net/minecraft/world/level/block/LiquidBlock.java +++ b/net/minecraft/world/level/block/LiquidBlock.java @@ -198,7 +198,14 @@ public class LiquidBlock extends Block implements BucketPickup { - // Sakura start - configure cannon physics + // Sakura start - configure server mechanics final FluidState fluidState = state.getFluidState(); final Block block = fluidState.isSource() ? Blocks.OBSIDIAN : Blocks.COBBLESTONE; - final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget = level.localConfig().at(pos).mechanicsTarget; @@ -21,21 +21,21 @@ index e6091c252f252373481f46a3ef119ddc32baddf0..cf624b29ed2b7ca2d6af24b3cac6bb31 + mechanicsTarget = level.localConfig().at(pos).mechanicsTarget; + } + // Sakura end - legacy lava block formation - if (block == Blocks.COBBLESTONE && !me.samsuik.sakura.mechanics.LiquidBehaviour.canLiquidSolidify(level, pos, fluidState, mechanicsTarget)) { + if (block == Blocks.COBBLESTONE && !me.samsuik.sakura.mechanics.LegacyBlockFormation.canLiquidFormBlock(level, pos, fluidState, mechanicsTarget)) { return true; } diff --git a/net/minecraft/world/level/material/LavaFluid.java b/net/minecraft/world/level/material/LavaFluid.java -index 752099419e46070b42f9f2ecff1016d28a6ebf49..b6f198a8ef365c0414d2560b36a9c7d13d86ccbf 100644 +index 1166ecc7e938341a65cbabb592fc998593afe835..a0666fc38f4df2293b3888224c0b85652af803bf 100644 --- a/net/minecraft/world/level/material/LavaFluid.java +++ b/net/minecraft/world/level/material/LavaFluid.java @@ -184,9 +184,16 @@ public abstract class LavaFluid extends FlowingFluid { @Override public boolean canBeReplacedWith(FluidState fluidState, BlockGetter blockReader, BlockPos pos, Fluid fluid, Direction direction) { -- // Sakura start - configure cannon physics +- // Sakura start - configure server mechanics - if (blockReader instanceof Level level && level.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_13)) { - return false; -+ // Sakura start - configure cannon physics & legacy lava block formation ++ // Sakura start - configure server mechanics & legacy lava block formation + if (blockReader instanceof Level level) { + if (level.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_13)) { + return false; @@ -46,21 +46,21 @@ index 752099419e46070b42f9f2ecff1016d28a6ebf49..b6f198a8ef365c0414d2560b36a9c7d1 + } + // Sakura end - legacy lava block formation } - // Sakura end - configure cannon physics + // Sakura end - configure server mechanics return fluidState.getHeight(blockReader, pos) >= 0.44444445F && fluid.is(FluidTags.WATER); diff --git a/net/minecraft/world/level/material/WaterFluid.java b/net/minecraft/world/level/material/WaterFluid.java -index 9fc1c56dec5201c3b700992f88b258225ceb8581..65fab5cb4af7e3357a1f65e89eb87a4c7fcd01a7 100644 +index 62b90ee5c3ecdd82e0fbb7a7812cd59e8cbde567..079bc5b40b0ebbb9b950c06adff6d4b08c5bf309 100644 --- a/net/minecraft/world/level/material/WaterFluid.java +++ b/net/minecraft/world/level/material/WaterFluid.java @@ -124,10 +124,18 @@ public abstract class WaterFluid extends FlowingFluid { @Override public boolean canBeReplacedWith(FluidState fluidState, BlockGetter blockReader, BlockPos pos, Fluid fluid, Direction direction) { -- // Sakura start - configure cannon physics +- // Sakura start - configure server mechanics - final boolean canReplace = direction == Direction.DOWN - || blockReader instanceof Level level - && level.localConfig().at(pos).mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_13); -+ // Sakura start - configure cannon physics & legacy lava block formation ++ // Sakura start - configure server mechanics & legacy lava block formation + boolean canReplace = false; + if (direction == Direction.DOWN) { + canReplace = true; @@ -74,4 +74,4 @@ index 9fc1c56dec5201c3b700992f88b258225ceb8581..65fab5cb4af7e3357a1f65e89eb87a4c + // Sakura end - legacy lava block formation // Before 1.13 lava could replace water return canReplace && !fluid.is(FluidTags.WATER); - // Sakura end - configure cannon physics + // Sakura end - configure server mechanics 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 ecc8752..3c5aa85 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 bad69adfbc492d851a3542dc7f77884d9f933c8a..9250806b12171ae4f14d8dbc9dd3d9478bc7b724 100644 +index 573b1695abde0d89d5702a60a84919167ef4baab..29e1683741241f4f1e578041371a116170f2d1d2 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -1303,6 +1303,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1304,6 +1304,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,13 +21,13 @@ index bad69adfbc492d851a3542dc7f77884d9f933c8a..9250806b12171ae4f14d8dbc9dd3d947 } 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 e63a24188e07f50fc4ef67ca87866063fbc51516..96f430c55c3cfe7791e25e4506f5fdf1ceb1b18b 100644 +index 528d45eb5ff968ef14c3ff74a0c3bdb58ab21b86..b39b2cd2f4b85535bea19752ca1ecd334531b86c 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -601,6 +601,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -600,6 +600,18 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return this.mechanicsTarget; } - // Sakura end - configure cannon physics + // Sakura end - configure server mechanics + // Sakura start - entity travel distance limits + private final double travelDistanceLimit; + @@ -35,16 +35,15 @@ index e63a24188e07f50fc4ef67ca87866063fbc51516..96f430c55c3cfe7791e25e4506f5fdf1 + if (this.origin == null) { + return false; + } -+ -+ double x = Math.pow(this.origin.x() - this.position.x(), 2); -+ double z = Math.pow(this.origin.z() - this.position.z(), 2); ++ final double x = Math.pow(this.origin.x() - this.position.x(), 2.0); ++ final double z = Math.pow(this.origin.z() - this.position.z(), 2.0); + return Math.max(x, z) >= this.travelDistanceLimit; + } + // Sakura end - entity travel distance limits public Entity(EntityType entityType, Level level) { this.type = entityType; -@@ -630,6 +643,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -629,6 +641,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.setPos(0.0, 0.0, 0.0); this.eyeHeight = this.dimensions.eyeHeight(); this.despawnTime = level == null || type == EntityType.PLAYER ? -1 : level.paperConfig().entities.spawning.despawnTime.getOrDefault(type, io.papermc.paper.configuration.type.number.IntOr.Disabled.DISABLED).or(-1); // Paper - entity despawn time limit diff --git a/sakura-server/minecraft-patches/features/0023-Protect-scaffolding-from-creepers.patch b/sakura-server/minecraft-patches/features/0023-Protect-scaffolding-from-creepers.patch index 564e829..2bc6368 100644 --- a/sakura-server/minecraft-patches/features/0023-Protect-scaffolding-from-creepers.patch +++ b/sakura-server/minecraft-patches/features/0023-Protect-scaffolding-from-creepers.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Protect scaffolding from creepers diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 3e4580903b85cb4aa4a48a9882a641f03d8a440d..9a3cf92fd767559484d3bd9f94e1c13facbfa86f 100644 +index 3e4e09b886dea6642dbe86c52c5a475baad11734..4b937ba2568a08d45541199964b3b46638f76785 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java -@@ -409,6 +409,11 @@ public class ServerExplosion implements Explosion { +@@ -376,6 +376,11 @@ public class ServerExplosion implements Explosion { return Optional.of(ZERO_RESISTANCE); } // Sakura end - allow explosions to destroy lava diff --git a/sakura-server/minecraft-patches/features/0024-Configurable-left-shooting-and-adjusting-limits.patch b/sakura-server/minecraft-patches/features/0024-Configurable-left-shooting-and-adjusting-limits.patch index 6a2cc65..4193464 100644 --- a/sakura-server/minecraft-patches/features/0024-Configurable-left-shooting-and-adjusting-limits.patch +++ b/sakura-server/minecraft-patches/features/0024-Configurable-left-shooting-and-adjusting-limits.patch @@ -5,21 +5,21 @@ Subject: [PATCH] Configurable left shooting and adjusting limits diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 96f430c55c3cfe7791e25e4506f5fdf1ceb1b18b..2304e3e33edfce64b79001d2f70d731da3114d77 100644 +index b39b2cd2f4b85535bea19752ca1ecd334531b86c..0810ca0de7035bc913c63f8c26ccd247d27957be 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -614,6 +614,46 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -612,6 +612,47 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return Math.max(x, z) >= this.travelDistanceLimit; } // Sakura end - entity travel distance limits + // Sakura start - configurable left shooting and adjusting limits + protected final void limitLeftShooting() { -+ Vec3 movement = this.getDeltaMovement(); -+ int threshold = this.level.sakuraConfig().cannons.restrictions.leftShootingThreshold.or(-1); ++ final Vec3 movement = this.getDeltaMovement(); ++ final int threshold = this.level.sakuraConfig().cannons.restrictions.leftShootingThreshold.or(-1); + if (threshold > 0 && (movement.x != 0.0 || movement.z != 0.0) && this.origin != null) { -+ double travelledX = Math.abs(this.getX() - this.origin.x()); -+ double travelledZ = Math.abs(this.getZ() - this.origin.z()); -+ boolean xSmaller = travelledX < travelledZ; // intended ++ final double travelledX = Math.abs(this.getX() - this.origin.x()); ++ final double travelledZ = Math.abs(this.getZ() - this.origin.z()); ++ final boolean xSmaller = travelledX < travelledZ; // intended // todo is it? + + // Once entities have travelled past the threshold changing direction is restricted. + if (xSmaller && travelledX > threshold) { @@ -30,8 +30,8 @@ index 96f430c55c3cfe7791e25e4506f5fdf1ceb1b18b..2304e3e33edfce64b79001d2f70d731d + } + } + -+ private void limitAdjustMovement(AABB currBoundingBox, double dir, boolean xAdjust, List shapes) { -+ int adjustDistance = this.level.sakuraConfig().cannons.restrictions.maxAdjustDistance.or(-1); ++ private void limitAdjustMovement(final AABB currBoundingBox, final double dir, final boolean xAdjust, final List shapes) { ++ final int adjustDistance = this.level.sakuraConfig().cannons.restrictions.maxAdjustDistance.or(-1); + if (adjustDistance > 0 && Math.abs(dir) > adjustDistance) { + double minX = Double.NEGATIVE_INFINITY; + double minZ = Double.NEGATIVE_INFINITY; @@ -44,7 +44,8 @@ index 96f430c55c3cfe7791e25e4506f5fdf1ceb1b18b..2304e3e33edfce64b79001d2f70d731d + minZ = Math.floor(currBoundingBox.minZ) - adjustDistance; + maxZ = Math.floor(currBoundingBox.maxZ) + adjustDistance + 1; + } -+ VoxelShape safeSpace = Shapes.box( ++ ++ final VoxelShape safeSpace = Shapes.box( + minX, Double.NEGATIVE_INFINITY, minZ, + maxX, Double.POSITIVE_INFINITY, maxZ + ); @@ -55,7 +56,7 @@ index 96f430c55c3cfe7791e25e4506f5fdf1ceb1b18b..2304e3e33edfce64b79001d2f70d731d public Entity(EntityType entityType, Level level) { this.type = entityType; -@@ -1630,6 +1670,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1629,6 +1670,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } if (xSmaller && z != 0.0) { @@ -63,7 +64,7 @@ index 96f430c55c3cfe7791e25e4506f5fdf1ceb1b18b..2304e3e33edfce64b79001d2f70d731d z = this.scanZ(currBoundingBox, z, voxelList, bbList); if (z != 0.0) { currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetZ(currBoundingBox, z); -@@ -1637,6 +1678,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1636,6 +1678,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } if (x != 0.0) { @@ -76,11 +77,11 @@ index 96f430c55c3cfe7791e25e4506f5fdf1ceb1b18b..2304e3e33edfce64b79001d2f70d731d if (x != 0.0) { currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetX(currBoundingBox, x); diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java -index 33e8073651099d6a3d82fe0886424d5aa3886c5d..38047b725ffab925ac3dd97f1470e25db74e1226 100644 +index 297310605e3ed4dbd3db40ff3cddb8eee6f3f508..f21b9e47fc35e00b9d4d8664e4bf1b9a188878a4 100644 --- a/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -270,6 +270,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti - // Sakura end - configure cannon physics +@@ -269,6 +269,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti + // Sakura end - configure server mechanics this.time++; this.applyGravity(); + this.limitLeftShooting(); // Sakura - configurable left shooting and adjusting limits 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 228ae87..601f0cd 100644 --- a/sakura-server/minecraft-patches/features/0025-Optimise-hopper-ticking.patch +++ b/sakura-server/minecraft-patches/features/0025-Optimise-hopper-ticking.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Optimise hopper ticking diff --git a/net/minecraft/world/CompoundContainer.java b/net/minecraft/world/CompoundContainer.java -index 0e9beb7f74e527a95bff064631e6d591f5775ce5..f89a8a3a1f3c87432c8816c3273c7b25b324055b 100644 +index 0e9beb7f74e527a95bff064631e6d591f5775ce5..2408e385989f19ae9591495bd9ee5af411a1e412 100644 --- a/net/minecraft/world/CompoundContainer.java +++ b/net/minecraft/world/CompoundContainer.java @@ -53,6 +53,15 @@ public class CompoundContainer implements Container { @@ -14,7 +14,7 @@ index 0e9beb7f74e527a95bff064631e6d591f5775ce5..f89a8a3a1f3c87432c8816c3273c7b25 // CraftBukkit end + // Sakura start - optimise hopper ticking + @Override -+ public final boolean addListener(net.minecraft.world.level.block.entity.BlockEntity.BlockEntityChangeListener listener) { ++ public final boolean addListener(final net.minecraft.world.level.block.entity.BlockEntity.BlockEntityChangeListener listener) { + boolean result = false; + result |= this.container1.addListener(listener); + result |= this.container2.addListener(listener); @@ -25,7 +25,7 @@ index 0e9beb7f74e527a95bff064631e6d591f5775ce5..f89a8a3a1f3c87432c8816c3273c7b25 public CompoundContainer(Container container1, Container container2) { this.container1 = container1; diff --git a/net/minecraft/world/Container.java b/net/minecraft/world/Container.java -index b382665cc125b8b5c0938e5e55984e4bf91d37ff..0c4358053076416fc2cd3f5c9b7f6d2f630cab10 100644 +index b382665cc125b8b5c0938e5e55984e4bf91d37ff..7a62a5c61474b5b0ffc581c55d35d3327c7831b6 100644 --- a/net/minecraft/world/Container.java +++ b/net/minecraft/world/Container.java @@ -14,6 +14,12 @@ import net.minecraft.world.level.block.entity.BlockEntity; @@ -33,7 +33,7 @@ index b382665cc125b8b5c0938e5e55984e4bf91d37ff..0c4358053076416fc2cd3f5c9b7f6d2f float DEFAULT_DISTANCE_BUFFER = 4.0F; + // Sakura start - optimise hopper ticking -+ default boolean addListener(BlockEntity.BlockEntityChangeListener container) { ++ default boolean addListener(final BlockEntity.BlockEntityChangeListener listener) { + return false; + } + // Sakura end - optimise hopper ticking @@ -42,7 +42,7 @@ index b382665cc125b8b5c0938e5e55984e4bf91d37ff..0c4358053076416fc2cd3f5c9b7f6d2f boolean isEmpty(); diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java -index 5aaa3f01b7e8b55742ba46dd614f1eaa233aa5c9..81378160d021a76d6fddca9c23a1a4691f48e71e 100644 +index d4b2f81aebc888e6fe041537b71ac52d8dc8b4e7..92b3a69b2f87f44cb0c797d5986d501a649f4fe4 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -1483,7 +1483,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @@ -72,7 +72,7 @@ index 46a27f60ba407dacdac190b5e292ab3f1db5a078..ec05bb86803d878867b46e437cc73a39 } } diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java -index 5986825d6a381eeb445dd424dd127864aa703163..f77a8c45602d9b30c357557e80a6a97abea99eb2 100644 +index 5986825d6a381eeb445dd424dd127864aa703163..72ed4c5b9f07be9d7149cd7f99622ec4be6d5902 100644 --- a/net/minecraft/world/level/block/entity/BlockEntity.java +++ b/net/minecraft/world/level/block/entity/BlockEntity.java @@ -50,6 +50,60 @@ public abstract class BlockEntity { @@ -99,20 +99,20 @@ index 5986825d6a381eeb445dd424dd127864aa703163..f77a8c45602d9b30c357557e80a6a97a + return this.blockEntityTicking; + } + -+ public final void setBlockEntityTicking(boolean blockEntityTicking) { ++ public final void setBlockEntityTicking(final boolean blockEntityTicking) { + this.tickCount = 0; + this.blockEntityTicking = blockEntityTicking; + } + -+ public final boolean addListener(BlockEntityChangeListener listener) { ++ public final boolean addListener(final BlockEntityChangeListener listener) { + if (this.listeners.add(listener)) { + ((BlockEntity) listener).listeningBlocks.add(this); + } + return true; + } + -+ public final void updateListeners(boolean onRemove) { -+ for (BlockEntityChangeListener listener : this.listeners) { ++ public final void updateListeners(final boolean onRemove) { ++ for (final BlockEntityChangeListener listener : this.listeners) { + if (onRemove) { + listener.neighborRemoved(); + } else { @@ -169,7 +169,7 @@ index 5986825d6a381eeb445dd424dd127864aa703163..f77a8c45602d9b30c357557e80a6a97a public void clearRemoved() { diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index 800b7e78ae989868ed0b9e060c80dcd002759412..b40c1d20d5823fe63ec34e38a315c7f1bbb5831b 100644 +index 01ed25d1f895d94485b5fecd98476534cbb26930..6ccd350a5cbe87e5cf9e66c230aced17e7ccd163 100644 --- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java +++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java @@ -28,7 +28,7 @@ import net.minecraft.world.level.storage.ValueInput; @@ -206,30 +206,30 @@ index 800b7e78ae989868ed0b9e060c80dcd002759412..b40c1d20d5823fe63ec34e38a315c7f1 + this.setBlockEntityTicking(true); + } + -+ private void waitForChange(int fullState) { ++ private void waitForChange(final int fullState) { + if ((fullState == HOPPER_IS_FULL || (this.connectedContainers & SOURCE_CONTAINER) != 0) && (this.connectedContainers & ATTACHED_CONTAINER) != 0) { + this.addListener(this); + this.setBlockEntityTicking(false); + } + } + -+ private static @Nullable Container sakura_getSourceContainer(Level level, Hopper hopper, BlockPos pos, BlockState state) { -+ Container container = getSourceContainer(level, hopper, pos, state); ++ private static @Nullable Container sakura$getSourceContainer(final Level level, final Hopper hopper, final BlockPos pos, final BlockState state) { ++ final Container container = getSourceContainer(level, hopper, pos, state); + if (hopper instanceof HopperBlockEntity hbe && org.bukkit.event.inventory.HopperInventorySearchEvent.getHandlerList().getRegisteredListeners().length == 0) { + hbe.listenForContainerChanges(container, SOURCE_CONTAINER); + } + return container; + } + -+ private static @Nullable Container sakura_getAttachedContainer(Level level, BlockPos pos, HopperBlockEntity hbe) { -+ Container container = getAttachedContainer(level, pos, hbe); ++ private static @Nullable Container sakura$getAttachedContainer(final Level level, final BlockPos pos, final HopperBlockEntity hbe) { ++ final Container container = getAttachedContainer(level, pos, hbe); + if (org.bukkit.event.inventory.HopperInventorySearchEvent.getHandlerList().getRegisteredListeners().length == 0) { + hbe.listenForContainerChanges(container, ATTACHED_CONTAINER); + } + return container; + } + -+ private void listenForContainerChanges(@Nullable Container container, int type) { ++ private void listenForContainerChanges(final @Nullable Container container, final int type) { + if (container != null && container.addListener(this)) { + this.connectedContainers |= type; // set + } else if ((this.connectedContainers & type) != 0) { @@ -258,7 +258,7 @@ index 800b7e78ae989868ed0b9e060c80dcd002759412..b40c1d20d5823fe63ec34e38a315c7f1 private static boolean ejectItems(Level level, BlockPos pos, HopperBlockEntity blockEntity) { - Container attachedContainer = getAttachedContainer(level, pos, blockEntity); -+ Container attachedContainer = sakura_getAttachedContainer(level, pos, blockEntity); // Sakura - optimise hopper ticking ++ Container attachedContainer = sakura$getAttachedContainer(level, pos, blockEntity); // Sakura - optimise hopper ticking if (attachedContainer == null) { return false; } else { @@ -267,7 +267,7 @@ index 800b7e78ae989868ed0b9e060c80dcd002759412..b40c1d20d5823fe63ec34e38a315c7f1 BlockPos blockPos = BlockPos.containing(hopper.getLevelX(), hopper.getLevelY() + 1.0, hopper.getLevelZ()); BlockState blockState = level.getBlockState(blockPos); - Container sourceContainer = getSourceContainer(level, hopper, blockPos, blockState); -+ Container sourceContainer = sakura_getSourceContainer(level, hopper, blockPos, blockState); // Sakura - optimise hopper ticking ++ Container sourceContainer = sakura$getSourceContainer(level, hopper, blockPos, blockState); // Sakura - optimise hopper ticking if (sourceContainer != null) { Direction direction = Direction.DOWN; skipPullModeEventFire = skipHopperEvents; // Paper - Perf: Optimize Hoppers @@ -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 a2185062fbb123549be21e37e84541d61ec301c9..d961788584520f5231d65cc63753da4320a48867 100644 +index a39077ba4e1e40462ee9a96ce6f3871a5ecb85c7..6edccc2452c30a56ad393ba72ba2de487078f316 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -987,6 +987,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @@ -296,7 +296,7 @@ index a2185062fbb123549be21e37e84541d61ec301c9..d961788584520f5231d65cc63753da43 + // Sakura start - optimise hopper ticking + @Override -+ public boolean isBlockEntityActive() { ++ public final boolean isBlockEntityActive() { + return this.blockEntity.isBlockEntityActive(); + } + // Sakura end - optimise hopper ticking @@ -310,7 +310,7 @@ index a2185062fbb123549be21e37e84541d61ec301c9..d961788584520f5231d65cc63753da43 + // Sakura start - optimise hopper ticking + @Override -+ public boolean isBlockEntityActive() { ++ public final boolean isBlockEntityActive() { + return this.ticker.isBlockEntityActive(); + } + // Sakura end - optimise hopper ticking 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 6560167..8144a6f 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,7 +5,7 @@ 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 2304e3e33edfce64b79001d2f70d731da3114d77..d1688f01a9564b5ef4c9e905015a174550cab6ae 100644 +index 0810ca0de7035bc913c63f8c26ccd247d27957be..5c772c05908f59b0f3d8636492685c3b853bcb47 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -1910,6 +1910,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -31,19 +31,26 @@ index 2304e3e33edfce64b79001d2f70d731da3114d77..d1688f01a9564b5ef4c9e905015a1745 } } -@@ -1932,7 +1933,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1932,8 +1933,16 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } - private void checkInsideBlocks(Vec3 vec3, Vec3 vec31, InsideBlockEffectApplier.StepBasedCollector stepBasedCollector, LongSet set) { +- // Sakura start - configure server mechanics + // Sakura start - optimise check inside blocks -+ private void checkInsideBlocks(Vec3 vec3, Vec3 vec31, InsideBlockEffectApplier.StepBasedCollector stepBasedCollector, -+ LongSet set, net.minecraft.world.level.chunk.ChunkAccess[] chunkCache) { ++ private void checkInsideBlocks( ++ final Vec3 vec3, ++ final Vec3 vec31, ++ final InsideBlockEffectApplier.StepBasedCollector stepBasedCollector, ++ final LongSet set, ++ final net.minecraft.world.level.chunk.ChunkAccess[] chunkCache ++ ) { + // Sakura end - optimise check inside blocks - // Sakura start - configure cannon physics ++ // Sakura start - configure cannon physics final double margin; if (this.mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_2)) { -@@ -1953,7 +1957,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + margin = 1.0e-5f; +@@ -1953,7 +1962,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess if (!this.isAlive()) { return false; } else { @@ -66,15 +73,15 @@ index 2304e3e33edfce64b79001d2f70d731da3114d77..d1688f01a9564b5ef4c9e905015a1745 this.debugBlockIntersection(pos, false, false); return true; diff --git a/net/minecraft/world/level/BlockGetter.java b/net/minecraft/world/level/BlockGetter.java -index 353ad0c1db2ee374ac5487539c77b2b067dc7c0a..1cdc68aab80390b5f1fb67c14c0a8aaa64f28250 100644 +index b6ddb1ad889a115daeba64321d38b236033f62ff..0d8dda4e914e7570d08f595fd20e5f45e366cd0d 100644 --- a/net/minecraft/world/level/BlockGetter.java +++ b/net/minecraft/world/level/BlockGetter.java @@ -227,7 +227,7 @@ public interface BlockGetter extends LevelHeightAccessor { Vec3 vec3 = to.subtract(from); if (vec3.lengthSqr() < Mth.square(0.99999F) || mechanicsTarget != null && mechanicsTarget.before(me.samsuik.sakura.mechanics.MechanicVersion.v1_21_2)) { - // Sakura end - configure cannon physics + // Sakura end - configure server mechanics - for (BlockPos blockPos : BlockPos.betweenClosed(boundingBox)) { -+ for (BlockPos blockPos : me.samsuik.sakura.utils.BlockPosIterator.iterable(boundingBox)) { // Sakura - optimise check inside blocks ++ for (final BlockPos blockPos : me.samsuik.sakura.utils.BlockPosIterator.iterable(boundingBox)) { // Sakura - optimise check inside blocks if (!visitor.visit(blockPos, 0)) { return false; } @@ -104,7 +111,7 @@ index 353ad0c1db2ee374ac5487539c77b2b067dc7c0a..1cdc68aab80390b5f1fb67c14c0a8aaa return false; } else { - for (BlockPos blockPos1 : BlockPos.betweenClosed(boundingBox)) { -+ for (BlockPos blockPos1 : me.samsuik.sakura.utils.BlockPosIterator.iterable(boundingBox)) { // Sakura - optimise check inside blocks ++ for (final BlockPos blockPos1 : me.samsuik.sakura.utils.BlockPosIterator.iterable(boundingBox)) { // Sakura - optimise check inside blocks if (!set.contains(blockPos1.asLong()) && !visitor.visit(blockPos1, i + 1)) { return false; } 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 41a94a6..b88fc7a 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,19 +33,19 @@ index ff747a1ecdf3c888bca0d69de4f85dcd810b6139..d90f6aa4557b5863eba6a206226f763c } diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 9250806b12171ae4f14d8dbc9dd3d9478bc7b724..a3306fcdc83bb5f0157e1d9805a4d134403ce5f9 100644 +index 29e1683741241f4f1e578041371a116170f2d1d2..fa109c801fd556e9e09dd0a81d5e05cb942082dd 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java -@@ -693,6 +693,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.levelTickScheduler.registerNewTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings - this.levelTickScheduler.registerNewTask(this.mergeHandler::expire, 200); // Sakura - merge cannon entities - this.levelTickScheduler.registerNewTask(this.densityCache::invalidate, 0); // Sakura - explosion density cache -+ this.levelTickScheduler.registerNewTask(this.redstoneWireCache::expire, 300); // Sakura - cache vanilla and eigencraft wires +@@ -694,6 +694,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::invalidate, 0); // Sakura - explosion density cache ++ 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 81378160d021a76d6fddca9c23a1a4691f48e71e..e894c404d58f95c8f54987739ad24b6a0b96dfc3 100644 +index 92b3a69b2f87f44cb0c797d5986d501a649f4fe4..c1f9d65aba951963ebb297393580df3d6969c021 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -831,6 +831,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl @@ -57,7 +57,7 @@ index 81378160d021a76d6fddca9c23a1a4691f48e71e..e894c404d58f95c8f54987739ad24b6a protected Level( WritableLevelData levelData, diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java -index 270c405a7384e3290b4eea58e0b231aa6235d85a..a1428aab6923a58c04d206d63babd93242ed1ff9 100644 +index 9dbd97607866f8bd356044318ab670bcc794074f..cc0abc586908631747ceb1c920e7c3cb3f7828dd 100644 --- a/net/minecraft/world/level/block/RedStoneWireBlock.java +++ b/net/minecraft/world/level/block/RedStoneWireBlock.java @@ -306,6 +306,12 @@ public class RedStoneWireBlock extends Block { @@ -65,7 +65,7 @@ index 270c405a7384e3290b4eea58e0b231aa6235d85a..a1428aab6923a58c04d206d63babd932 newPower = event.getNewCurrent(); + // Sakura start - cache vanilla and eigencraft wires -+ if (level.redstoneWireCache.tryApplyFromCache(pos, null, newPower, oldPower)) { ++ if (level.redstoneWireCache.applyFromCache(pos, null, newPower, oldPower)) { + return state; + } + // Sakura end - cache vanilla and eigencraft wires @@ -81,6 +81,15 @@ index 270c405a7384e3290b4eea58e0b231aa6235d85a..a1428aab6923a58c04d206d63babd932 } } return state; +@@ -398,7 +405,7 @@ public class RedStoneWireBlock extends Block { + + @Override + protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) { +- if (!level.isClientSide) { ++ if (!level.isClientSide && !level.redstoneWireCache.isApplyingCache()) { // Sakura - cache vanilla and eigencraft wires; ignore redstone updates when applying from cache + // Paper start - optimize redstone (Alternate Current) + // Alternate Current handles breaking of redstone wires in the WireHandler. + if (level.localConfig().at(pos).paperRedstoneImplementation() == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) { // Sakura - redstone implementation api @@ -432,8 +439,14 @@ public class RedStoneWireBlock extends Block { if (powerValue == 0) { return 0; @@ -91,7 +100,7 @@ index 270c405a7384e3290b4eea58e0b231aa6235d85a..a1428aab6923a58c04d206d63babd932 + if (side == Direction.UP) { + return powerValue; + } -+ final boolean updating = blockAccess instanceof Level level && level.redstoneWireCache.isWireUpdating(pos); ++ final boolean updating = blockAccess instanceof Level level && level.redstoneWireCache.isUpdatingRedstoneWire(pos); + final BlockState state = updating ? blockState : this.getConnectionState(blockAccess, blockState, pos); + return !state.getValue(PROPERTY_BY_DIRECTION.get(side.getOpposite())).isConnected() + // Sakura end - cache vanilla and eigencraft wires @@ -99,7 +108,7 @@ index 270c405a7384e3290b4eea58e0b231aa6235d85a..a1428aab6923a58c04d206d63babd932 : powerValue; } diff --git a/net/minecraft/world/level/block/state/BlockBehaviour.java b/net/minecraft/world/level/block/state/BlockBehaviour.java -index 969488021cfc462b85750f25c1c256ab6709ff89..bfc63f858b229d9ccd1827821b66ba55124d2fda 100644 +index fed11ed5ab97826915710b66395d1bdc926935b0..d6131c5ec6a4229291f7cecb9cec9251d54244ed 100644 --- a/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/net/minecraft/world/level/block/state/BlockBehaviour.java @@ -521,6 +521,13 @@ public abstract class BlockBehaviour implements FeatureElement { @@ -151,7 +160,7 @@ index 028eae2f9a459b60e92f3344091083aa93b54485..9fbf679b54088f89ac4ba727ccb645d6 this.addedThisLayer.clear(); this.count = 0; diff --git a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java -index abcc144a086a45bf4cfa4d1a33e2ae10952e0da2..3fc901aa038e65e3e219b92d0fa37e5dd620926f 100644 +index abcc144a086a45bf4cfa4d1a33e2ae10952e0da2..b76f54d9573b9f3ddd77915e9209ee8d9b497192 100644 --- a/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java +++ b/net/minecraft/world/level/redstone/DefaultRedstoneWireEvaluator.java @@ -27,7 +27,14 @@ public class DefaultRedstoneWireEvaluator extends RedstoneWireEvaluator { @@ -160,7 +169,7 @@ index abcc144a086a45bf4cfa4d1a33e2ae10952e0da2..3fc901aa038e65e3e219b92d0fa37e5d // CraftBukkit end + // Sakura start - cache vanilla and eigencraft wires + final me.samsuik.sakura.redstone.RedstoneWireCache wireCache = level.redstoneWireCache; -+ if (wireCache.tryApplyFromCache(pos, orientation, i, oldPower)) { ++ if (wireCache.applyFromCache(pos, orientation, i, oldPower)) { + return; + } if (level.getBlockState(pos) == state) { diff --git a/sakura-server/minecraft-patches/features/0029-Configure-breaking-blocks-outside-the-world-border.patch b/sakura-server/minecraft-patches/features/0029-Configure-breaking-blocks-outside-the-world-border.patch index 8672632..61d6fb0 100644 --- a/sakura-server/minecraft-patches/features/0029-Configure-breaking-blocks-outside-the-world-border.patch +++ b/sakura-server/minecraft-patches/features/0029-Configure-breaking-blocks-outside-the-world-border.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Configure breaking blocks outside the world border diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index 49dabe47bda4237df9799d3c673a40cab9f2d03e..cf8f4203c06030e36a5a5bfe210ba65582c204cb 100644 +index 4b937ba2568a08d45541199964b3b46638f76785..3b2498ab4f3da5aea22931532901a540ffb03e73 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java -@@ -540,6 +540,11 @@ public class ServerExplosion implements Explosion { +@@ -507,6 +507,11 @@ public class ServerExplosion implements Explosion { return ret; } // Sakura end - optimise protected explosions 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 b2b117a..df63fd8 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,20 +5,21 @@ 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 7dddc1fda846c362c0f3d0cae89e15aba37abf5a..68b89ee60a5dcb5f38dfbda8dd3bbbf25f92f380 100644 +index 2b3f37b2c4add7fe5c5e9500cd087517fa11600b..035008bc65c3a3a85512edc30cb4e311aab96006 100644 --- a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java +++ b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java -@@ -1937,6 +1937,7 @@ public final class CollisionUtil { +@@ -1937,6 +1937,8 @@ public final class CollisionUtil { final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); final CollisionContext collisionShape = new LazyEntityCollisionContext(entity); final boolean useEntityCollisionShape = LazyEntityCollisionContext.useEntityCollisionShape(world, entity); + final boolean cannonEntity = entity != null && (entity.isFallingBlock || entity.isPrimedTNT); // Sakura - optimise block counting for cannon entities ++ final long gameTime = world.getGameTime(); // special cases: if (minBlockY > maxBlockY) { -@@ -2001,15 +2002,19 @@ public final class CollisionUtil { +@@ -2000,15 +2002,19 @@ public final class CollisionUtil { - final boolean hasSpecial = !fullBlocks && ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks(); // Sakura - collide with non-solid blocks + final boolean hasSpecial = !fullBlocks && section.moonrise$hasSpecialCollidingBlocks(); // Sakura - collide with non-solid blocks final int sectionAdjust = !hasSpecial ? 1 : 0; + // Sakura start - optimise block counting for cannon entities + final boolean hasMovingBlocks = section.hasMovingPistonBlocks(); @@ -42,7 +43,7 @@ index 7dddc1fda846c362c0f3d0cae89e15aba37abf5a..68b89ee60a5dcb5f38dfbda8dd3bbbf2 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 1e8a69bfafebcf292140403227cc378a0b3f81a6..30b01591c9abc4dcb5d1916a782ab45af5db5daa 100644 +index c1f9d65aba951963ebb297393580df3d6969c021..02e29e2e10f399906dcc9bd7bdbabe62b1a97245 100644 --- a/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java @@ -616,6 +616,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup, AutoCl diff --git a/sakura-server/minecraft-patches/features/0031-Protect-blocks-above-a-configured-Y-level-from-explo.patch b/sakura-server/minecraft-patches/features/0031-Protect-blocks-above-a-configured-Y-level-from-explo.patch index 108fb77..5b5311f 100644 --- a/sakura-server/minecraft-patches/features/0031-Protect-blocks-above-a-configured-Y-level-from-explo.patch +++ b/sakura-server/minecraft-patches/features/0031-Protect-blocks-above-a-configured-Y-level-from-explo.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Protect blocks above a configured Y-level from explosions diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java -index d86f6f6a43584967b6e256be32c3144fbb2a326f..d0e7347f5d57e77e28fb2145552db67d67e4c25b 100644 +index 3b2498ab4f3da5aea22931532901a540ffb03e73..b5c50214830bd04d916850de6920a651b94e8463 100644 --- a/net/minecraft/world/level/ServerExplosion.java +++ b/net/minecraft/world/level/ServerExplosion.java -@@ -414,6 +414,11 @@ public class ServerExplosion implements Explosion { +@@ -381,6 +381,11 @@ public class ServerExplosion implements Explosion { return Optional.of(net.minecraft.world.level.block.Blocks.BARRIER.getExplosionResistance()); } // Sakura end - protect scaffolding from creepers diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch index 9726f95..0429ff5 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch @@ -19,7 +19,7 @@ + return this.tickInformationCollector.latestTickInformation(); + } + -+ public final ImmutableList tickHistory(long from, long to) { ++ public final ImmutableList tickHistory(final long from, final long to) { + return this.tickInformationCollector.collect(from, to); + } + // Sakura end - track tick information @@ -30,10 +30,10 @@ Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this)); // CraftBukkit end this.paperConfigurations = services.paperConfigurations(); // Paper - add paper configuration files -+ // Sakura start ++ // Sakura start - sakura configuration files + final java.nio.file.Path sakuraConfigDirPath = ((java.io.File) options.valueOf("sakura-settings-directory")).toPath(); + this.sakuraConfigurations = me.samsuik.sakura.configuration.SakuraConfigurations.setup(sakuraConfigDirPath); -+ // Sakura end ++ // Sakura end - sakura configuration files } private void readScoreboard(DimensionDataStorage dataStorage) { diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch index 3844d31..64d3660 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch @@ -15,8 +15,8 @@ int playerViewDistance = ChunkMap.this.getPlayerViewDistance(player); - double d = Math.min(this.getEffectiveRange(), playerViewDistance * 16); + // Sakura start - entity tracking range modifier -+ double visibleRange = this.getEffectiveRange() * player.trackingRangeModifier; -+ double d = Math.min(visibleRange, playerViewDistance * 16); ++ final double visibleRange = this.getEffectiveRange() * player.trackingRangeModifier; ++ final double d = Math.min(visibleRange, playerViewDistance * 16); + // Sakura end - entity tracking range modifier double d1 = vec3_dx * vec3_dx + vec3_dz * vec3_dz; // Paper double d2 = d * d; diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch index 786b96a..1d45ff1 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch @@ -160,8 +160,8 @@ + // int i = 25 - this.getArmorValue(); + // float f1 = damageAmount * (float) i; + // damageAmount = f1 / 25.0F; -+ float armorDamageModifier = 1.0f - (this.getArmorValue() / 25.0f); -+ damageAmount *= armorDamageModifier; ++ final float armorDamageModifier = 1.0f - (this.getArmorValue() / 25.0f); ++ damageAmount *= armorDamageModifier; + } + // Sakura end - legacy combat mechanics } diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/item/FallingBlockEntity.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/item/FallingBlockEntity.java.patch index 915b865..b1ec7dd 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/item/FallingBlockEntity.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/item/FallingBlockEntity.java.patch @@ -13,7 +13,7 @@ } public FallingBlockEntity(Level level, double x, double y, double z, BlockState state) { -@@ -90,6 +_,27 @@ +@@ -90,6 +_,26 @@ this.setStartPos(this.blockPosition()); } @@ -24,17 +24,16 @@ + } + // Sakura end - falling block height parity api + // Sakura start - falling block stacking restrictions -+ private static boolean isFallingBlockInBounds(Level level, BlockPos blockPosition) { ++ private static boolean isFallingBlockInBounds(final Level level, final BlockPos blockPosition) { ++ // Prevent stacking one block below build limit + if (level.sakuraConfig().cannons.sand.preventAtWorldHeight && blockPosition.getY() >= level.getMaxY() - 1) { + return false; + } + -+ Vec3 center = blockPosition.getBottomCenter(); -+ if (level.sakuraConfig().cannons.sand.preventAgainstBorder && !level.getWorldBorder().isWithinBounds(center.x(), center.z(), -1.0)) { -+ return false; -+ } -+ -+ return true; ++ final Vec3 center = blockPosition.getBottomCenter(); ++ // Prevent stacking directly against the world border ++ return !level.sakuraConfig().cannons.sand.preventAgainstBorder ++ || level.getWorldBorder().isWithinBounds(center.x(), center.z(), -1.0); + } + // Sakura end - falling block stacking restrictions + diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch index 22accbe..de963dd 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/item/PrimedTnt.java.patch @@ -15,7 +15,7 @@ + + // Sakura start - optimise tnt fluid state + @Override -+ protected boolean updateInWaterStateAndDoFluidPushing() { ++ protected final boolean updateInWaterStateAndDoFluidPushing() { + if (this.isPushedByFluid()) { + return super.updateInWaterStateAndDoFluidPushing(); + } else { diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch index c46d02e..6b3f380 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch @@ -83,8 +83,8 @@ if (f4 > 0.0F) { - if (target instanceof LivingEntity livingEntity1) { + // Sakura start - configure entity knockback; extra sprinting knockback -+ long millis = System.currentTimeMillis(); -+ long sinceLastKnockback = millis - this.lastSprintKnockback; ++ final long millis = System.currentTimeMillis(); ++ final long sinceLastKnockback = millis - this.lastSprintKnockback; + if (flag1) { // attackHasExtraKnockback + double knockbackToApply = 0.0; + if (sinceLastKnockback >= this.level().sakuraConfig().players.knockback.sprinting.knockbackDelay.value().orElse(0)) { @@ -127,11 +127,15 @@ int i = (int)(f7 * 0.5); ((ServerLevel)this.level()) .sendParticles(ParticleTypes.DAMAGE_INDICATOR, target.getX(), target.getY(0.5), target.getZ(), i, 0.1, 0.0, 0.1, 0.2); -@@ -1764,6 +_,7 @@ +@@ -1764,6 +_,11 @@ // Paper start - send while respecting visibility private static void sendSoundEffect(Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) { -+ if (fromEntity.level().sakuraConfig().players.combat.oldSoundsAndParticleEffects) return; // Sakura - old combat sounds and particles ++ // Sakura start - old combat sounds and particles ++ if (fromEntity.level().sakuraConfig().players.combat.oldSoundsAndParticleEffects) { ++ return; ++ } ++ // Sakura end - old combat sounds and particles fromEntity.level().playSound(fromEntity, x, y, z, soundEffect, soundCategory, volume, pitch); // This will not send the effect to the entity itself if (fromEntity instanceof ServerPlayer serverPlayer) { serverPlayer.connection.send(new net.minecraft.network.protocol.game.ClientboundSoundPacket(net.minecraft.core.registries.BuiltInRegistries.SOUND_EVENT.wrapAsHolder(soundEffect), soundCategory, x, y, z, volume, pitch, fromEntity.random.nextLong())); diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/AbstractThrownPotion.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/AbstractThrownPotion.java.patch index b85dfe9..1b13b17 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/AbstractThrownPotion.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/AbstractThrownPotion.java.patch @@ -1,25 +1,26 @@ --- a/net/minecraft/world/entity/projectile/AbstractThrownPotion.java +++ b/net/minecraft/world/entity/projectile/AbstractThrownPotion.java -@@ -39,6 +_,25 @@ +@@ -39,6 +_,26 @@ super(entityType, x, y, z, level, item); } + // Sakura start - configure potion mechanics + @Override -+ public void shoot(double x, double y, double z, float speed, float divergence) { ++ public void shoot(final double x, final double y, final double z, final float speed, final float divergence) { // may be overridden by plugins + super.shoot(x, y, z, speed, divergence); + -+ net.minecraft.world.phys.Vec3 movement = this.getDeltaMovement(); -+ double moveX = movement.x * this.level().sakuraConfig().entity.thrownPotion.horizontalSpeed; -+ double moveY = movement.y * this.level().sakuraConfig().entity.thrownPotion.verticalSpeed; -+ double moveZ = movement.z * this.level().sakuraConfig().entity.thrownPotion.horizontalSpeed; ++ final net.minecraft.world.phys.Vec3 movement = this.getDeltaMovement(); ++ final double moveX = movement.x * this.level().sakuraConfig().entity.thrownPotion.horizontalSpeed; ++ final double moveY = movement.y * this.level().sakuraConfig().entity.thrownPotion.verticalSpeed; ++ final double moveZ = movement.z * this.level().sakuraConfig().entity.thrownPotion.horizontalSpeed; + + this.setDeltaMovement(moveX, moveY, moveZ); + } + + @Override -+ protected boolean checkLeftOwner() { -+ return super.checkLeftOwner() || this.level().sakuraConfig().entity.thrownPotion.allowBreakingInsideEntities && this.tickCount >= 5; ++ protected boolean checkLeftOwner() { // may be overridden by plugins ++ return this.level().sakuraConfig().entity.thrownPotion.allowBreakingInsideEntities && this.tickCount >= 5 ++ || super.checkLeftOwner(); + } + // Sakura end - configure potion mechanics + diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch index d8493e6..cbe4e61 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrowableProjectile.java.patch @@ -1,7 +1,7 @@ --- a/net/minecraft/world/entity/projectile/ThrowableProjectile.java +++ b/net/minecraft/world/entity/projectile/ThrowableProjectile.java -@@ -42,12 +_,18 @@ - return true; +@@ -22,6 +_,12 @@ + this.setPos(x, y, z); } + // Sakura start - enderpearls use outline for collision @@ -11,7 +11,9 @@ + // Sakura end - enderpearls use outline for collision + @Override - public void tick() { + public boolean shouldRenderAtSqrDistance(double distance) { + if (this.tickCount < 2 && distance < 12.25) { +@@ -47,7 +_,7 @@ this.handleFirstTickBubbleColumn(); this.applyGravity(); this.applyInertia(); diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch index 062a3d5..d1d991f 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ThrownEnderpearl.java.patch @@ -1,5 +1,21 @@ --- a/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +++ b/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +@@ -39,6 +_,15 @@ + super(EntityType.ENDER_PEARL, owner, level, item); + } + ++ // Sakura start - enderpearls use outline for collision ++ @Override ++ protected final net.minecraft.world.level.ClipContext.Block getClipType() { ++ return this.level().sakuraConfig().entity.enderPearl.useOutlineForCollision ++ ? net.minecraft.world.level.ClipContext.Block.OUTLINE ++ : super.getClipType(); ++ } ++ // Sakura end - enderpearls use outline for collision ++ + @Override + public Item getDefaultItem() { + return Items.ENDER_PEARL; @@ -118,6 +_,15 @@ if (owner != null && isAllowedToTeleportOwner(owner, serverLevel)) { Vec3 vec3 = this.oldPosition(); @@ -16,17 +32,3 @@ if (serverPlayer.connection.isAcceptingMessages()) { // CraftBukkit start // Store pre teleportation position as the teleport has been moved up. -@@ -181,6 +_,13 @@ - return entity.canUsePortal(true); - } - } -+ -+ // Sakura start - enderpearls use outline for collision -+ @Override -+ protected net.minecraft.world.level.ClipContext.Block getClipType() { -+ return this.level().sakuraConfig().entity.enderPearl.useOutlineForCollision ? net.minecraft.world.level.ClipContext.Block.OUTLINE : super.getClipType(); -+ } -+ // Sakura end - enderpearls use outline for collision - - @Override - public void tick() { diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/item/BoatItem.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/item/BoatItem.java.patch index 5adc39a..9db2940 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/item/BoatItem.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/item/BoatItem.java.patch @@ -5,7 +5,7 @@ } else { boat.setYRot(player.getYRot()); - if (!level.noCollision(boat, boat.getBoundingBox())) { -+ if (!level.noCollision(boat, boat.getBoundingBox()) || !level.getWorldBorder().isWithinBounds(boat.getBoundingBox())) { // Sakura - fix boats being placed outside the world border ++ if (!level.noCollision(boat, boat.getBoundingBox()) || !level.getWorldBorder().isWithinBounds(boat.getBoundingBox())) { // Sakura - fix placing boats outside the world border return InteractionResult.FAIL; } else { if (!level.isClientSide) { diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/item/Item.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/item/Item.java.patch index cac51f4..4846ef5 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/item/Item.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/item/Item.java.patch @@ -1,14 +1,14 @@ --- a/net/minecraft/world/item/Item.java +++ b/net/minecraft/world/item/Item.java -@@ -136,6 +_,11 @@ - return this.builtInRegistryHolder; +@@ -131,6 +_,11 @@ + } } + // Sakura start - modify components sent to the client -+ public void modifyComponentsSentToClient(net.minecraft.core.component.PatchedDataComponentMap components) { ++ public void modifyComponentsSentToClient(final net.minecraft.core.component.PatchedDataComponentMap components) { + } + // Sakura end - modify components sent to the client + - public DataComponentMap components() { - return this.components; - } + @Deprecated + public Holder.Reference builtInRegistryHolder() { + return this.builtInRegistryHolder; diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/item/ItemStack.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/item/ItemStack.java.patch index 700822f..0e32341 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/item/ItemStack.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/item/ItemStack.java.patch @@ -6,8 +6,8 @@ + // Sakura start - modify components sent to the client + public ItemStack copyForPacket() { -+ ItemStack stackCopy = this.copy(); -+ Item item = stackCopy.getItem(); ++ final ItemStack stackCopy = this.copy(); ++ final Item item = stackCopy.getItem(); + item.modifyComponentsSentToClient(stackCopy.components); + return stackCopy; + } diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/BaseSpawner.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/BaseSpawner.java.patch index 7db2aac..b298871 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/BaseSpawner.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/BaseSpawner.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/level/BaseSpawner.java +++ b/net/minecraft/world/level/BaseSpawner.java -@@ -55,12 +_,24 @@ +@@ -55,6 +_,17 @@ public int spawnRange = 4; private int tickDelay = 0; // Paper - Configurable mob spawner tick rate @@ -18,13 +18,15 @@ public void setEntityId(EntityType type, @Nullable Level level, RandomSource random, BlockPos pos) { this.getOrCreateNextSpawnData(level, random, pos).getEntityToSpawn().putString("id", BuiltInRegistries.ENTITY_TYPE.getKey(type).toString()); this.spawnPotentials = WeightedList.of(); // CraftBukkit - SPIGOT-3496, MC-92282 - } - - public boolean isNearPlayer(Level level, BlockPos pos) { -+ if (!level.sakuraConfig().environment.mobSpawner.requireNearbyPlayer) return true; // Sakura - configure mob spawner behaviour - return level.hasNearbyAlivePlayerThatAffectsSpawning(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, this.requiredPlayerRange); // Paper - Affects Spawning API - } - +@@ -90,7 +_,7 @@ + tickDelay = serverLevel.paperConfig().tickRates.mobSpawner; + if (tickDelay == -1) { return; } // If disabled + // Paper end - Configurable mob spawner tick rate +- if (this.isNearPlayer(serverLevel, pos)) { ++ if (!serverLevel.sakuraConfig().environment.mobSpawner.requireNearbyPlayer || this.isNearPlayer(serverLevel, pos)) { // Sakura - configure mob spawner behaviour + if (this.spawnDelay < -tickDelay) { // Paper - Configurable mob spawner tick rate + this.delay(serverLevel, pos); + } @@ -130,7 +_,7 @@ if (!customSpawnRules.isValidPosition(blockPos, serverLevel)) { continue; diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch index 6871851..7038d54 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/CactusBlock.java.patch @@ -15,7 +15,7 @@ + } + this.ageAndGrow(state, level, pos, random); + } -+ private void ageAndGrow(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { ++ private void ageAndGrow(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + // Sakura end - use random chance for crop growth BlockPos blockPos = pos.above(); if (level.isEmptyBlock(blockPos)) { diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch index a30be3b..27a2246 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/SugarCaneBlock.java.patch @@ -15,7 +15,7 @@ + } + this.ageAndGrow(state, level, pos, random); + } -+ private void ageAndGrow(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { ++ private void ageAndGrow(final BlockState state, final ServerLevel level, final BlockPos pos, final RandomSource random) { + // Sakura end - use random chance for crop growth if (level.isEmptyBlock(pos.above())) { int i = 1; diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java.patch index 7c237aa..d6fda33 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java.patch @@ -26,7 +26,7 @@ + return this.collisionShape = this.createCollisionShape(level, pos); + } + } -+ private VoxelShape createCollisionShape(BlockGetter level, BlockPos pos) { ++ private VoxelShape createCollisionShape(final BlockGetter level, final BlockPos pos) { + // Sakura end - cache moving block entity collision shape VoxelShape collisionShape; if (!this.extending && this.isSourcePiston && this.movedState.getBlock() instanceof PistonBaseBlock) { diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch index 482a224..f8a6a8f 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/material/FlowingFluid.java.patch @@ -27,20 +27,25 @@ // CraftBukkit start org.bukkit.block.Block source = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos); org.bukkit.event.block.BlockFromToEvent event = new org.bukkit.event.block.BlockFromToEvent(source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(direction)); -@@ -213,17 +_,71 @@ +@@ -213,17 +_,83 @@ } } + // Sakura start - optimise new liquid level + private static final int FORM_LIQUID_SOURCE = 0xff; + -+ private boolean canLiquidFlowDown(final ServerLevel level, final BlockPos pos, final BlockState state, -+ final BlockPos.MutableBlockPos mutableBlockPos) { ++ private boolean canLiquidFlowDown( ++ final ServerLevel level, ++ final BlockPos pos, ++ final BlockState state, ++ final BlockPos.MutableBlockPos mutableBlockPos ++ ) { + final BlockPos abovePos = mutableBlockPos.setWithOffset(pos, Direction.UP); + final BlockState stateAbove = level.getBlockState(abovePos); + final FluidState fluidStateAbove = stateAbove.getFluidState(); + -+ return !fluidStateAbove.isEmpty() && fluidStateAbove.getType().isSame(this) ++ return !fluidStateAbove.isEmpty() ++ && fluidStateAbove.getType().isSame(this) + && canPassThroughWall(Direction.UP, level, pos, state, abovePos, stateAbove); + } + @@ -58,9 +63,12 @@ + return this.getLiquidFromSurroundings(level, pos, state, null); + } + -+ @org.jspecify.annotations.NullUnmarked -+ private FluidState getLiquidFromSurroundings(final ServerLevel level, final BlockPos pos, final BlockState state, -+ final Direction flowing) { ++ private FluidState getLiquidFromSurroundings( ++ final ServerLevel level, ++ final BlockPos pos, ++ final BlockState state, ++ final @org.jspecify.annotations.Nullable Direction flowing ++ ) { + final BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + final boolean flowingDown = flowing == Direction.DOWN || this.canLiquidFlowDown(level, pos, state, mutableBlockPos); + @@ -83,9 +91,13 @@ + } + } + -+ @org.jspecify.annotations.NullUnmarked -+ private int getLiquidLevelFromSurroundings(final ServerLevel level, final BlockPos pos, final BlockState state, -+ final BlockPos.MutableBlockPos mutableBlockPos, final Direction incoming) { ++ private int getLiquidLevelFromSurroundings( ++ final ServerLevel level, ++ final BlockPos pos, ++ final BlockState state, ++ final BlockPos.MutableBlockPos mutableBlockPos, ++ final @org.jspecify.annotations.Nullable Direction incoming ++ ) { int i = 0; int i1 = 0; - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); diff --git a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch index 5e5d11b..1404c0a 100644 --- a/sakura-server/minecraft-patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch +++ b/sakura-server/minecraft-patches/sources/net/minecraft/world/level/material/LavaFluid.java.patch @@ -11,7 +11,7 @@ + + // Sakura start - lava flow speed api + @Override -+ public final int getTickDelay(Level world, BlockPos pos) { ++ public final int getTickDelay(final Level world, final BlockPos pos) { + final int flowSpeed = world.localConfig().at(pos).lavaFlowSpeed; + return flowSpeed >= 0 ? flowSpeed : this.getTickDelay(world); + } diff --git a/sakura-server/paper-patches/features/0002-Merge-Cannon-Entities.patch b/sakura-server/paper-patches/features/0002-Merge-Cannon-Entities.patch index ac45614..0867dfd 100644 --- a/sakura-server/paper-patches/features/0002-Merge-Cannon-Entities.patch +++ b/sakura-server/paper-patches/features/0002-Merge-Cannon-Entities.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Merge Cannon Entities diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java -index e77b06c3ef9b534a8f4f160d077cf4339ee7622d..a33e91a5b35109415b8140721469217c336dfc00 100644 +index f32f1cc5ed1bf429b45bfe06c97520edd1b87ef4..9f6371864cef8cc6cc69b65b56bed9bfcd1ea245 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java @@ -25,6 +25,27 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock { @@ -19,8 +19,8 @@ index e77b06c3ef9b534a8f4f160d077cf4339ee7622d..a33e91a5b35109415b8140721469217c + } + + @Override -+ public final void setMergeLevel(me.samsuik.sakura.entity.merge.MergeLevel level) { -+ this.getHandle().getMergeEntityData().mergeLevel = level; ++ public final void setMergeLevel(final me.samsuik.sakura.entity.merge.MergeLevel mergeLevel) { ++ this.getHandle().getMergeEntityData().mergeLevel = mergeLevel; + } + + @Override @@ -29,7 +29,7 @@ index e77b06c3ef9b534a8f4f160d077cf4339ee7622d..a33e91a5b35109415b8140721469217c + } + + @Override -+ public final void setStacked(int stacked) { ++ public final void setStacked(final int stacked) { + this.getHandle().getMergeEntityData().count = stacked; + } + // Sakura end - merge cannon entities @@ -37,7 +37,7 @@ index e77b06c3ef9b534a8f4f160d077cf4339ee7622d..a33e91a5b35109415b8140721469217c @Override public FallingBlockEntity getHandle() { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java -index 4a62bd61ad3fcd59433e6cb7ddba3af39d714fef..0a5f3c51f2694ca7d05776817b2ddd40d9bc93aa 100644 +index 4a62bd61ad3fcd59433e6cb7ddba3af39d714fef..d243c2b92747ff20c275089f4bf247996c528536 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java @@ -13,6 +13,28 @@ public class CraftTNTPrimed extends CraftEntity implements TNTPrimed { @@ -51,8 +51,8 @@ index 4a62bd61ad3fcd59433e6cb7ddba3af39d714fef..0a5f3c51f2694ca7d05776817b2ddd40 + } + + @Override -+ public final void setMergeLevel(me.samsuik.sakura.entity.merge.MergeLevel level) { -+ this.getHandle().getMergeEntityData().mergeLevel = level; ++ public final void setMergeLevel(final me.samsuik.sakura.entity.merge.MergeLevel mergeLevel) { ++ this.getHandle().getMergeEntityData().mergeLevel = mergeLevel; + } + + @Override @@ -61,7 +61,7 @@ index 4a62bd61ad3fcd59433e6cb7ddba3af39d714fef..0a5f3c51f2694ca7d05776817b2ddd40 + } + + @Override -+ public final void setStacked(int stacked) { ++ public final void setStacked(final int stacked) { + this.getHandle().getMergeEntityData().count = stacked; + } + // Sakura end - merge cannon entities diff --git a/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java.patch b/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java.patch index 4cd97bb..e0e3293 100644 --- a/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java.patch +++ b/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java.patch @@ -11,7 +11,7 @@ + } + + @Override -+ public final void setPushedByFluid(boolean push) { ++ public final void setPushedByFluid(final boolean push) { + this.getHandle().pushedByFluid = push; + } + // Sakura end - entity pushed by fluid api diff --git a/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java.patch b/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java.patch index a8bdc7c..9226523 100644 --- a/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java.patch +++ b/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java.patch @@ -6,8 +6,8 @@ + // Sakura start - falling block height parity api + @Override -+ public final void setHeightParity(boolean parity) { -+ this.getHandle().heightParity = parity; ++ public final void setHeightParity(final boolean heightParity) { ++ this.getHandle().heightParity = heightParity; + } + + @Override diff --git a/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch b/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch index 207a7bb..b995de8 100644 --- a/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch +++ b/sakura-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch @@ -6,13 +6,13 @@ + // Sakura start - entity tracking range modifier + @Override -+ public double getTrackingRangeModifier() { ++ public final double getTrackingRangeModifier() { + return this.getHandle().trackingRangeModifier * 100.0; + } + + @Override -+ public void setTrackingRangeModifier(double mod) { -+ this.getHandle().trackingRangeModifier = mod / 100.0; ++ public final void setTrackingRangeModifier(final double modifier) { ++ this.getHandle().trackingRangeModifier = modifier / 100.0; + } + // Sakura end - entity tracking range modifier + diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/BaseMenuCommand.java b/sakura-server/src/main/java/me/samsuik/sakura/command/BaseMenuCommand.java index e5fedff..d4bceeb 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/BaseMenuCommand.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/BaseMenuCommand.java @@ -17,7 +17,7 @@ public abstract class BaseMenuCommand extends BaseSubCommand { private static final String HEADER_MESSAGE = "| "; private static final String COMMAND_MSG = "| * /"; - public BaseMenuCommand(String name) { + public BaseMenuCommand(final String name) { super(name); } @@ -30,7 +30,7 @@ public abstract class BaseMenuCommand extends BaseSubCommand { public abstract Iterable subCommands(); @Override - public final void execute(CommandSender sender, String[] args) { + public final void execute(final CommandSender sender, final String[] args) { if (args.length > 0) { for (final Command base : this.subCommands()) { if (base.getName().equalsIgnoreCase(args[0])) { @@ -43,7 +43,7 @@ public abstract class BaseMenuCommand extends BaseSubCommand { this.sendHelpMessage(sender); } - private void sendHelpMessage(CommandSender sender) { + private void sendHelpMessage(final CommandSender sender) { sender.sendMessage(Component.text(".", NamedTextColor.DARK_PURPLE)); for (final String header : this.header().split("\n")) { if (!header.isEmpty()) { @@ -61,7 +61,7 @@ public abstract class BaseMenuCommand extends BaseSubCommand { } @Override - public final List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { + public final List tabComplete(final CommandSender sender, final String alias, final String[] args) throws IllegalArgumentException { if (!this.testPermissionSilent(sender) || args.length == 0) { return Collections.emptyList(); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/BaseSubCommand.java b/sakura-server/src/main/java/me/samsuik/sakura/command/BaseSubCommand.java index 0fb9c8a..7cdaf4a 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/BaseSubCommand.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/BaseSubCommand.java @@ -11,19 +11,19 @@ import java.util.function.Function; @NullMarked public abstract class BaseSubCommand extends Command { - public BaseSubCommand(String name) { + public BaseSubCommand(final String name) { super(name); this.description = "Sakura Command " + name; this.setPermission("bukkit.command." + name); } - public abstract void execute(CommandSender sender, String[] args); + public abstract void execute(final CommandSender sender, final String[] args); - public void tabComplete(List list, String[] args) throws IllegalArgumentException {} + public void tabComplete(final List completions, final String[] args) throws IllegalArgumentException {} @Override @Deprecated - public final boolean execute(CommandSender sender, String label, String[] args) { + public final boolean execute(final CommandSender sender, final String label, final String[] args) { if (this.testPermission(sender)) { this.execute(sender, args); } @@ -32,8 +32,8 @@ public abstract class BaseSubCommand extends Command { } @Override - public List tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException { - List completions = new ArrayList<>(0); + public List tabComplete(final CommandSender sender, final String alias, final String[] args) throws IllegalArgumentException { + final List completions = new ArrayList<>(0); if (this.testPermissionSilent(sender)) { this.tabComplete(completions, args); @@ -42,26 +42,26 @@ public abstract class BaseSubCommand extends Command { return completions; } - protected final Optional parseInt(String[] args, int index) { + protected final Optional parseInt(final String[] args, final int index) { return this.parse(args, index, Integer::parseInt); } - protected final Optional parseLong(String[] args, int index) { + protected final Optional parseLong(final String[] args, final int index) { return this.parse(args, index, Long::parseLong); } - protected final Optional parseFloat(String[] args, int index) { + protected final Optional parseFloat(final String[] args, final int index) { return this.parse(args, index, Float::parseFloat); } - protected final Optional parseDouble(String[] args, int index) { + protected final Optional parseDouble(final String[] args, final int index) { return this.parse(args, index, Double::parseDouble); } - protected final Optional parse(String[] args, int index, Function func) { + protected final Optional parse(final String[] args, final int index, final Function parseFunction) { try { - String arg = args[index]; - return Optional.of(func.apply(arg)); + final String toParse = args[index]; + return Optional.of(parseFunction.apply(toParse)); } catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) { return Optional.empty(); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/PlayerOnlySubCommand.java b/sakura-server/src/main/java/me/samsuik/sakura/command/PlayerOnlySubCommand.java index b8acb58..c667c14 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/PlayerOnlySubCommand.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/PlayerOnlySubCommand.java @@ -6,13 +6,13 @@ import org.jspecify.annotations.NullMarked; @NullMarked public abstract class PlayerOnlySubCommand extends BaseSubCommand { - public PlayerOnlySubCommand(String name) { + public PlayerOnlySubCommand(final String name) { super(name); } - public abstract void execute(Player player, String[] args); + public abstract void execute(final Player player, final String[] args); - public final void execute(CommandSender sender, String[] args) { + public final void execute(final CommandSender sender, final String[] args) { if (sender instanceof Player player) { this.execute(player, args); } else { diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/SakuraCommand.java b/sakura-server/src/main/java/me/samsuik/sakura/command/SakuraCommand.java index 33d20a2..f6a5c8a 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/SakuraCommand.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/SakuraCommand.java @@ -9,7 +9,7 @@ import java.util.*; @NullMarked public final class SakuraCommand extends BaseMenuCommand { - public SakuraCommand(String name) { + public SakuraCommand(final String name) { super(name); this.description = ""; } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/SakuraCommands.java b/sakura-server/src/main/java/me/samsuik/sakura/command/SakuraCommands.java index 18a0b9a..08bb108 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/SakuraCommands.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/SakuraCommands.java @@ -1,6 +1,7 @@ package me.samsuik.sakura.command; import me.samsuik.sakura.command.subcommands.*; +import me.samsuik.sakura.command.subcommands.debug.DebugCommand; import me.samsuik.sakura.command.subcommands.debug.DebugLocalConfiguration; import me.samsuik.sakura.command.subcommands.debug.DebugRedstoneCache; import me.samsuik.sakura.player.visibility.VisibilityTypes; diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/ConfigCommand.java b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/ConfigCommand.java index 2c221c7..343fd49 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/ConfigCommand.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/ConfigCommand.java @@ -1,32 +1,29 @@ package me.samsuik.sakura.command.subcommands; import me.samsuik.sakura.command.BaseSubCommand; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import net.minecraft.server.MinecraftServer; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.craftbukkit.CraftServer; import org.jspecify.annotations.NullMarked; -import static net.kyori.adventure.text.Component.text; -import static net.kyori.adventure.text.format.NamedTextColor.GREEN; -import static net.kyori.adventure.text.format.NamedTextColor.RED; - @NullMarked public final class ConfigCommand extends BaseSubCommand { - public ConfigCommand(String name) { + public ConfigCommand(final String name) { super(name); this.description = "Command for reloading the sakura configuration file"; } @Override - public void execute(CommandSender sender, String[] args) { - Command.broadcastCommandMessage(sender, text("Please note that this command is not supported and may cause issues.", RED)); - Command.broadcastCommandMessage(sender, text("If you encounter any issues please use the /stop command to restart your server.", RED)); + public void execute(final CommandSender sender, final String[] args) { + sender.sendMessage(Component.text("Please note that this command is not supported and may cause issues.", NamedTextColor.RED)); + sender.sendMessage(Component.text("If you encounter any issues please use the /stop command to restart your server.", NamedTextColor.RED)); - MinecraftServer server = ((CraftServer) sender.getServer()).getServer(); + final MinecraftServer server = ((CraftServer) sender.getServer()).getServer(); server.sakuraConfigurations.reloadConfigs(server); server.server.reloadCount++; - Command.broadcastCommandMessage(sender, text("Sakura config reload complete.", GREEN)); + sender.sendMessage(Component.text("Sakura config reload complete.", NamedTextColor.GREEN)); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java index 57a0b4f..31ad781 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/FPSCommand.java @@ -9,12 +9,12 @@ import org.jspecify.annotations.NullMarked; public final class FPSCommand extends PlayerOnlySubCommand { private final VisibilityGui visibilityGui = new VisibilityGui(); - public FPSCommand(String name) { + public FPSCommand(final String name) { super(name); } @Override - public void execute(Player player, String[] args) { + public void execute(final Player player, final String[] args) { this.visibilityGui.showTo(player); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java index db6d03c..bfd70fa 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/TPSCommand.java @@ -23,23 +23,26 @@ public final class TPSCommand extends BaseSubCommand { private static final int GRAPH_HEIGHT = 10; private static final Style GRAY_WITH_STRIKETHROUGH = Style.style(NamedTextColor.GRAY, TextDecoration.STRIKETHROUGH); - public TPSCommand(String name) { + public TPSCommand(final String name) { super(name); this.description = "Displays the current ticks per second"; } @Override - public void execute(CommandSender sender, String[] args) { - ServerTickInformation tickInformation = MinecraftServer.getServer().latestTickInformation(); - long identifier = this.parseLong(args, 1).orElse(tickInformation.identifier()); + public void execute(final CommandSender sender, final String[] args) { + final ServerTickInformation tickInformation = MinecraftServer.getServer().latestTickInformation(); + final long identifier = this.parseLong(args, 1).orElse(tickInformation.identifier()); double scale = this.parseDouble(args, 0).orElse(-1.0); if (scale < 0.0) { + // Scale the tps graph to the current server tps scale = this.dynamicScale(identifier); } - ImmutableList tickHistory = MinecraftServer.getServer().tickHistory(identifier - GRAPH_WIDTH, identifier); - DetailedTPSGraph graph = new DetailedTPSGraph(GRAPH_WIDTH, GRAPH_HEIGHT, scale, tickHistory); - BuiltComponentCanvas canvas = graph.plot(); + final ImmutableList tickHistory = MinecraftServer.getServer().tickHistory(identifier - GRAPH_WIDTH, identifier); + final DetailedTPSGraph graph = new DetailedTPSGraph(GRAPH_WIDTH, GRAPH_HEIGHT, scale, tickHistory); + final BuiltComponentCanvas canvas = graph.plot(); + + // Add the sidebars, header and footer canvas.appendLeft(Component.text(":", NamedTextColor.BLACK)); canvas.appendRight(Component.text(":", NamedTextColor.BLACK)); canvas.header(this.createHeaderComponent(tickInformation, identifier)); @@ -47,24 +50,24 @@ public final class TPSCommand extends BaseSubCommand { .append(Component.text(Strings.repeat(" ", GRAPH_WIDTH - 1), GRAY_WITH_STRIKETHROUGH)) .append(Component.text("*"))); - for (Component component : canvas.components()) { + for (final Component component : canvas.components()) { sender.sendMessage(component); } } - private double dynamicScale(long identifier) { - ImmutableList tickHistory = MinecraftServer.getServer().tickHistory(identifier - 5, identifier); - double averageTps = tickHistory.stream() + private double dynamicScale(final long identifier) { + final ImmutableList tickHistory = MinecraftServer.getServer().tickHistory(identifier - 5, identifier); + final double averageTps = tickHistory.stream() .mapToDouble(ServerTickInformation::tps) .average() .orElse(0.0); - return 20 / averageTps; + return 20.0 / averageTps; } - private Component createHeaderComponent(ServerTickInformation tickInformation, long identifier) { - int scrollAmount = GRAPH_WIDTH / 3 * 2; - double memoryUsage = memoryUsage(); - TextComponent.Builder builder = Component.text(); + private Component createHeaderComponent(final ServerTickInformation tickInformation, final long identifier) { + final int scrollAmount = GRAPH_WIDTH / 3 * 2; + final double memoryUsage = memoryUsage(); + final TextComponent.Builder builder = Component.text(); builder.color(NamedTextColor.DARK_GRAY); builder.append(Component.text("< ") .clickEvent(ClickEvent.runCommand("/tps -1 " + (identifier + scrollAmount)))); @@ -83,10 +86,10 @@ public final class TPSCommand extends BaseSubCommand { } private static double memoryUsage() { - Runtime runtime = Runtime.getRuntime(); - double free = runtime.freeMemory(); - double max = runtime.maxMemory(); - double alloc = runtime.totalMemory(); + final Runtime runtime = Runtime.getRuntime(); + final double free = runtime.freeMemory(); + final double max = runtime.maxMemory(); + final double alloc = runtime.totalMemory(); return (alloc - free) / max; } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java index 7d859d5..f0551f5 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/VisualCommand.java @@ -15,21 +15,18 @@ import java.util.Arrays; public final class VisualCommand extends PlayerOnlySubCommand { private final VisibilityType type; - public VisualCommand(VisibilityType type, String... aliases) { + public VisualCommand(final VisibilityType type, final String... aliases) { super(type.key() + "visibility"); this.setAliases(Arrays.asList(aliases)); this.type = type; } @Override - public void execute(Player player, String[] args) { - VisibilitySettings settings = player.getVisibility(); - VisibilityState state = settings.toggle(type); + public void execute(final Player player, final String[] args) { + final VisibilitySettings settings = player.getVisibility(); + final VisibilityState state = settings.toggle(type); - String stateName = (state == VisibilityState.ON) ? "Enabled" : "Disabled"; - player.sendRichMessage(GlobalConfiguration.get().messages.fpsSettingChange, - Placeholder.unparsed("name", this.type.key()), - Placeholder.unparsed("state", stateName) - ); + final String stateName = (state == VisibilityState.ON) ? "Enabled" : "Disabled"; + player.sendMessage(GlobalConfiguration.get().messages.fpsSettingChangeComponent(this.type.key(), stateName)); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/DebugCommand.java b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/debug/DebugCommand.java similarity index 73% rename from sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/DebugCommand.java rename to sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/debug/DebugCommand.java index 2d2289d..dcd95b5 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/DebugCommand.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/debug/DebugCommand.java @@ -1,4 +1,4 @@ -package me.samsuik.sakura.command.subcommands; +package me.samsuik.sakura.command.subcommands.debug; import me.samsuik.sakura.command.BaseMenuCommand; import me.samsuik.sakura.command.SakuraCommands; @@ -7,13 +7,13 @@ import org.jspecify.annotations.NullMarked; @NullMarked public final class DebugCommand extends BaseMenuCommand { - public DebugCommand(String name) { + public DebugCommand(final String name) { super(name); } @Override public String header() { - return "Debug command for testing Sakura features and api"; + return "Command for debugging Sakura features and api"; } @Override diff --git a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/debug/DebugRedstoneCache.java b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/debug/DebugRedstoneCache.java index c5284ee..1041829 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/debug/DebugRedstoneCache.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/command/subcommands/debug/DebugRedstoneCache.java @@ -19,38 +19,40 @@ import java.util.concurrent.ThreadLocalRandom; @NullMarked public final class DebugRedstoneCache extends PlayerOnlySubCommand { - public DebugRedstoneCache(String name) { + public DebugRedstoneCache(final String name) { super(name); } @Override - public void execute(Player player, String[] args) { - ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); - Level level = nmsPlayer.level(); - Set locations = new HashSet<>(); - for (RedstoneNetwork network : level.redstoneWireCache.getNetworkCache().values()) { - byte randomColour = (byte) ThreadLocalRandom.current().nextInt(16); - DyeColor dyeColour = DyeColor.getByWoolData(randomColour); - Material material = Material.matchMaterial(dyeColour.name() + "_WOOL"); + public void execute(final Player player, final String[] args) { + final ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + final Level level = nmsPlayer.level(); + final Set redstoneWires = new HashSet<>(); + + // Display randomly coloured wool blocks in place of redstone wires in a network. + for (final RedstoneNetwork network : level.redstoneWireCache.getNetworkCache().values()) { + final byte randomColour = (byte) ThreadLocalRandom.current().nextInt(16); + final DyeColor dyeColour = DyeColor.getByWoolData(randomColour); + final Material material = Material.matchMaterial(dyeColour.name() + "_WOOL"); if (!network.isRegistered()) { continue; } - for (BlockPos pos : network.getWirePositions()) { - Location location = CraftLocation.toBukkit(pos, level); + for (final BlockPos pos : network.getWirePositions()) { + final Location location = CraftLocation.toBukkit(pos, level); if (player.getLocation().distance(location) >= 64.0) { continue; } player.sendBlockChange(location, material.createBlockData()); - locations.add(location); + redstoneWires.add(location); } } - player.sendRichMessage("Displaying %dx cached redstone wires".formatted(locations.size())); + player.sendRichMessage("Displaying %dx cached redstone wires".formatted(redstoneWires.size())); - level.levelTickScheduler.delayedTask(() -> { - for (Location loc : locations) { + level.levelTickScheduler.runTaskLater(() -> { + for (final Location loc : redstoneWires) { player.sendBlockChange(loc, loc.getBlock().getBlockData()); } }, 1200); diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/GlobalConfiguration.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/GlobalConfiguration.java index 04a6716..ffecdbf 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/GlobalConfiguration.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/GlobalConfiguration.java @@ -36,9 +36,17 @@ public final class GlobalConfiguration extends ConfigurationPart { public String fpsSettingChange = "(S) "; public boolean tpsShowEntityAndChunkCount = true; + public Component fpsSettingChangeComponent(final String name, final String state) { + return MiniMessage.miniMessage().deserialize( + this.fpsSettingChange, + Placeholder.unparsed("name", name), + Placeholder.unparsed("state", state) + ); + } + public Component durableBlockInteractionComponent(final int remaining, final int durability) { return MiniMessage.miniMessage().deserialize( - GlobalConfiguration.get().messages.durableBlockInteraction, + this.durableBlockInteraction, Placeholder.unparsed("remaining", String.valueOf(remaining)), Placeholder.unparsed("durability", String.valueOf(durability)) ); diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/SakuraVersionInformation.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/SakuraVersionInformation.java index fe597b9..69d29f7 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/SakuraVersionInformation.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/SakuraVersionInformation.java @@ -7,7 +7,9 @@ import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.jspecify.annotations.NullMarked; +@NullMarked public final class SakuraVersionInformation { private static final String VERSION_MESSAGE = """ . diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/serializer/MinecraftMechanicsTargetSerializer.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/serializer/MinecraftMechanicsTargetSerializer.java index a3fa11b..c2da71e 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/serializer/MinecraftMechanicsTargetSerializer.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/serializer/MinecraftMechanicsTargetSerializer.java @@ -1,20 +1,16 @@ package me.samsuik.sakura.configuration.serializer; -import io.leangen.geantyref.TypeToken; import me.samsuik.sakura.mechanics.MechanicVersion; import me.samsuik.sakura.mechanics.MinecraftMechanicsTarget; -import me.samsuik.sakura.mechanics.MinecraftVersionEncoding; import me.samsuik.sakura.mechanics.ServerType; import org.checkerframework.checker.nullness.qual.Nullable; import org.jspecify.annotations.NullMarked; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.NodePath; -import org.spongepowered.configurate.serialize.ScalarSerializer; import org.spongepowered.configurate.serialize.SerializationException; import org.spongepowered.configurate.serialize.TypeSerializer; import java.lang.reflect.Type; -import java.util.function.Predicate; @NullMarked public final class MinecraftMechanicsTargetSerializer implements TypeSerializer { diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/ConfigurationTransformations.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/ConfigurationTransformations.java index 2f95f4e..4f41696 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/ConfigurationTransformations.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/ConfigurationTransformations.java @@ -4,6 +4,7 @@ import io.papermc.paper.configuration.transformation.Transformations; import me.samsuik.sakura.configuration.transformation.global.V1_RelocateMessages; import me.samsuik.sakura.configuration.transformation.global.V2_ConvertIconToMaterial; import me.samsuik.sakura.configuration.transformation.world.*; +import org.jspecify.annotations.NullMarked; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.NodePath; @@ -13,6 +14,7 @@ import org.spongepowered.configurate.transformation.TransformAction; import java.util.List; import java.util.function.Function; +@NullMarked public final class ConfigurationTransformations { private static final List REMOVED_GLOBAL_PATHS = List.of( NodePath.path("cannons") @@ -48,6 +50,10 @@ public final class ConfigurationTransformations { versionedBuilder.build().apply(node); } + public static ConfigurationTransformation transform(final NodePath path, final TransformAction transform) { + return ConfigurationTransformation.builder().addAction(path, transform).build(); + } + public static TransformAction newValue(final Function func) { return (k, v) -> { if (!v.virtual()) { diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/global/V1_RelocateMessages.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/global/V1_RelocateMessages.java index 6c72577..ca3b3cc 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/global/V1_RelocateMessages.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/global/V1_RelocateMessages.java @@ -1,5 +1,6 @@ package me.samsuik.sakura.configuration.transformation.global; +import org.jspecify.annotations.NullMarked; import org.spongepowered.configurate.NodePath; import org.spongepowered.configurate.transformation.ConfigurationTransformation; import org.spongepowered.configurate.transformation.TransformAction; @@ -8,6 +9,7 @@ import java.util.Map; import static org.spongepowered.configurate.NodePath.path; +@NullMarked public final class V1_RelocateMessages { private static final int VERSION = 2; // targeted version is always ahead by one private static final Map RELOCATION = Map.of( @@ -17,15 +19,15 @@ public final class V1_RelocateMessages { private V1_RelocateMessages() {} - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - ConfigurationTransformation.Builder transformationBuilder = ConfigurationTransformation.builder(); - for (Map.Entry entry : RELOCATION.entrySet()) { + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + final ConfigurationTransformation.Builder transformationBuilder = ConfigurationTransformation.builder(); + for (final Map.Entry entry : RELOCATION.entrySet()) { transformationBuilder.addAction(entry.getKey(), relocate(entry.getValue())); } builder.addVersion(VERSION, transformationBuilder.build()); } - private static TransformAction relocate(NodePath path) { + private static TransformAction relocate(final NodePath path) { return (node, object) -> path.array(); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/global/V2_ConvertIconToMaterial.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/global/V2_ConvertIconToMaterial.java index c6f8bfe..21df62b 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/global/V2_ConvertIconToMaterial.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/global/V2_ConvertIconToMaterial.java @@ -1,25 +1,28 @@ package me.samsuik.sakura.configuration.transformation.global; -import org.checkerframework.checker.nullness.qual.Nullable; +import me.samsuik.sakura.configuration.transformation.ConfigurationTransformations; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.NodePath; import org.spongepowered.configurate.transformation.ConfigurationTransformation; import org.spongepowered.configurate.transformation.TransformAction; +@NullMarked public final class V2_ConvertIconToMaterial implements TransformAction { private static final int VERSION = 3; // targeted version is always ahead by one - private static final NodePath PATH = NodePath.path("fps", "material"); + private static final NodePath FPS_MATERIAL_PATH = NodePath.path("fps", "material"); private static final V2_ConvertIconToMaterial INSTANCE = new V2_ConvertIconToMaterial(); private V2_ConvertIconToMaterial() {} - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - builder.addVersion(VERSION, ConfigurationTransformation.builder().addAction(PATH, INSTANCE).build()); + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + builder.addVersion(VERSION, ConfigurationTransformations.transform(FPS_MATERIAL_PATH, INSTANCE)); } @Override - public Object @Nullable [] visitPath(NodePath path, ConfigurationNode value) throws ConfigurateException { + public Object @Nullable [] visitPath(final NodePath path, final ConfigurationNode value) throws ConfigurateException { if (value.raw() instanceof String stringValue) { value.raw(stringValue.toUpperCase()); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V10_DurableMaterialOnlyDamagedByTnt.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V10_DurableMaterialOnlyDamagedByTnt.java index d5b19df..90a6a1a 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V10_DurableMaterialOnlyDamagedByTnt.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V10_DurableMaterialOnlyDamagedByTnt.java @@ -1,6 +1,7 @@ package me.samsuik.sakura.configuration.transformation.world; -import org.checkerframework.checker.nullness.qual.Nullable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.NodePath; @@ -9,15 +10,18 @@ import org.spongepowered.configurate.transformation.TransformAction; import static org.spongepowered.configurate.NodePath.path; +@NullMarked public final class V10_DurableMaterialOnlyDamagedByTnt implements TransformAction { private static final int VERSION = 10; private static final V10_DurableMaterialOnlyDamagedByTnt INSTANCE = new V10_DurableMaterialOnlyDamagedByTnt(); private static final NodePath EXPLOSION_PATH = path("cannons", "explosion"); + private static final NodePath DURABLE_MATERIALS_PATH = EXPLOSION_PATH.plus(path("durable-materials")); + private static final NodePath REQUIRE_TNT_PATH = EXPLOSION_PATH.plus(path("require-tnt-to-damage-durable-materials")); public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { builder.addVersion(VERSION, ConfigurationTransformation.builder() - .addAction(EXPLOSION_PATH.plus(path("durable-materials")), INSTANCE) - .addAction(EXPLOSION_PATH.plus(path("require-tnt-to-damage-durable-materials")), TransformAction.remove()) + .addAction(DURABLE_MATERIALS_PATH, INSTANCE) + .addAction(REQUIRE_TNT_PATH, TransformAction.remove()) .build()); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V11_RemovePhysicsVersion.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V11_RemovePhysicsVersion.java index 3222f46..9f52566 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V11_RemovePhysicsVersion.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V11_RemovePhysicsVersion.java @@ -1,18 +1,19 @@ package me.samsuik.sakura.configuration.transformation.world; +import me.samsuik.sakura.configuration.transformation.ConfigurationTransformations; +import org.jspecify.annotations.NullMarked; import org.spongepowered.configurate.NodePath; import org.spongepowered.configurate.transformation.ConfigurationTransformation; import org.spongepowered.configurate.transformation.TransformAction; import static org.spongepowered.configurate.NodePath.path; +@NullMarked public final class V11_RemovePhysicsVersion { private static final int VERSION = 11; - private static final NodePath PATH = path("cannons", "mechanics", "physics-version"); + private static final NodePath PHYSICS_VERSION_PATH = path("cannons", "mechanics", "physics-version"); public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { - builder.addVersion(VERSION, ConfigurationTransformation.builder() - .addAction(PATH, TransformAction.remove()) - .build()); + builder.addVersion(VERSION, ConfigurationTransformations.transform(PHYSICS_VERSION_PATH, TransformAction.remove())); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V2_VerticalKnockbackUseDefault.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V2_VerticalKnockbackUseDefault.java index 0980f04..5f48b79 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V2_VerticalKnockbackUseDefault.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V2_VerticalKnockbackUseDefault.java @@ -1,7 +1,9 @@ package me.samsuik.sakura.configuration.transformation.world; import io.papermc.paper.configuration.type.number.DoubleOr; -import org.checkerframework.checker.nullness.qual.Nullable; +import me.samsuik.sakura.configuration.transformation.ConfigurationTransformations; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.NodePath; @@ -10,21 +12,20 @@ import org.spongepowered.configurate.transformation.TransformAction; import static org.spongepowered.configurate.NodePath.path; +@NullMarked public final class V2_VerticalKnockbackUseDefault implements TransformAction { private static final int VERSION = 2; - private static final NodePath PATH = path("players", "knockback", "knockback-vertical"); + private static final NodePath KNOCKBACK_VERTICAL_PATH = path("players", "knockback", "knockback-vertical"); private static final V2_VerticalKnockbackUseDefault INSTANCE = new V2_VerticalKnockbackUseDefault(); private V2_VerticalKnockbackUseDefault() {} - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - builder.addVersion(VERSION, ConfigurationTransformation.builder() - .addAction(PATH, INSTANCE) - .build()); + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + builder.addVersion(VERSION, ConfigurationTransformations.transform(KNOCKBACK_VERTICAL_PATH, INSTANCE)); } @Override - public Object @Nullable [] visitPath(NodePath path, ConfigurationNode value) throws ConfigurateException { + public Object @Nullable [] visitPath(final NodePath path, final ConfigurationNode value) throws ConfigurateException { if (value.getDouble() == 0.4) { value.set(DoubleOr.Default.USE_DEFAULT); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V3_RenameKnockback.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V3_RenameKnockback.java index efba1f8..6f4f9a9 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V3_RenameKnockback.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V3_RenameKnockback.java @@ -1,5 +1,6 @@ package me.samsuik.sakura.configuration.transformation.world; +import org.jspecify.annotations.NullMarked; import org.spongepowered.configurate.NodePath; import org.spongepowered.configurate.transformation.ConfigurationTransformation; @@ -8,6 +9,7 @@ import java.util.Map; import static org.spongepowered.configurate.NodePath.path; import static org.spongepowered.configurate.transformation.TransformAction.*; +@NullMarked public final class V3_RenameKnockback { private static final int VERSION = 3; private static final Map RENAME = Map.of( @@ -17,9 +19,9 @@ public final class V3_RenameKnockback { private V3_RenameKnockback() {} - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - ConfigurationTransformation.Builder transformationBuilder = ConfigurationTransformation.builder(); - for (Map.Entry entry : RENAME.entrySet()) { + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + final ConfigurationTransformation.Builder transformationBuilder = ConfigurationTransformation.builder(); + for (final Map.Entry entry : RENAME.entrySet()) { transformationBuilder.addAction(entry.getKey(), rename(entry.getValue())); } builder.addVersion(VERSION, transformationBuilder.build()); diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V4_RenameNonStrictMergeLevel.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V4_RenameNonStrictMergeLevel.java index de98fcb..f6f55aa 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V4_RenameNonStrictMergeLevel.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V4_RenameNonStrictMergeLevel.java @@ -1,6 +1,8 @@ package me.samsuik.sakura.configuration.transformation.world; -import org.checkerframework.checker.nullness.qual.Nullable; +import me.samsuik.sakura.configuration.transformation.ConfigurationTransformations; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.NodePath; @@ -11,24 +13,23 @@ import java.util.Locale; import static org.spongepowered.configurate.NodePath.path; +@NullMarked public final class V4_RenameNonStrictMergeLevel implements TransformAction { private static final int VERSION = 4; private static final String OLD_LEVEL_NAME = "NON_STRICT"; private static final String NEW_LEVEL_NAME = "LENIENT"; - private static final NodePath PATH = path("cannons", "merge-level"); + private static final NodePath MERGE_LEVEL_PATH = path("cannons", "merge-level"); private static final V4_RenameNonStrictMergeLevel INSTANCE = new V4_RenameNonStrictMergeLevel(); private V4_RenameNonStrictMergeLevel() {} - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - builder.addVersion(VERSION, ConfigurationTransformation.builder() - .addAction(PATH, INSTANCE) - .build()); + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + builder.addVersion(VERSION, ConfigurationTransformations.transform(MERGE_LEVEL_PATH, INSTANCE)); } @Override - public Object @Nullable [] visitPath(NodePath path, ConfigurationNode value) throws ConfigurateException { - String level = value.getString(); + public Object @Nullable [] visitPath(final NodePath path, final ConfigurationNode value) throws ConfigurateException { + final String level = value.getString(); if (level != null && OLD_LEVEL_NAME.equals(level.toUpperCase(Locale.ENGLISH))) { value.set(NEW_LEVEL_NAME); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V5_CombineLoadChunksOptions.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V5_CombineLoadChunksOptions.java index ff988e0..feb984d 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V5_CombineLoadChunksOptions.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V5_CombineLoadChunksOptions.java @@ -1,6 +1,8 @@ package me.samsuik.sakura.configuration.transformation.world; -import org.checkerframework.checker.nullness.qual.Nullable; +import me.samsuik.sakura.configuration.transformation.ConfigurationTransformations; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.NodePath; @@ -11,30 +13,29 @@ import java.util.List; import static org.spongepowered.configurate.NodePath.path; +@NullMarked public final class V5_CombineLoadChunksOptions implements TransformAction { private static final int VERSION = 5; private static final List ENTITY_PATHS = List.of("tnt", "sand"); private static final String OLD_NAME = "loads-chunks"; private static final String NAME = "load-chunks"; - private static final NodePath PATH = path("cannons"); + private static final NodePath CANNONS_PATH = path("cannons"); private static final V5_CombineLoadChunksOptions INSTANCE = new V5_CombineLoadChunksOptions(); private V5_CombineLoadChunksOptions() {} - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - builder.addVersion(VERSION, ConfigurationTransformation.builder() - .addAction(PATH, INSTANCE) - .build()); + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + builder.addVersion(VERSION, ConfigurationTransformations.transform(CANNONS_PATH, INSTANCE)); } @Override - public Object @Nullable [] visitPath(NodePath path, ConfigurationNode value) throws ConfigurateException { + public Object @Nullable [] visitPath(final NodePath path, final ConfigurationNode value) throws ConfigurateException { boolean shouldLoadChunks = false; - for (String entity : ENTITY_PATHS) { - NodePath entityPath = NodePath.path(entity, OLD_NAME); + for (final String entity : ENTITY_PATHS) { + final NodePath entityPath = NodePath.path(entity, OLD_NAME); if (value.hasChild(entityPath)) { - ConfigurationNode node = value.node(entityPath); + final ConfigurationNode node = value.node(entityPath); shouldLoadChunks |= node.getBoolean(); node.raw(null); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V6_FixIncorrectExtraKnockback.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V6_FixIncorrectExtraKnockback.java index 63d5f2d..e15a669 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V6_FixIncorrectExtraKnockback.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V6_FixIncorrectExtraKnockback.java @@ -1,6 +1,8 @@ package me.samsuik.sakura.configuration.transformation.world; -import org.checkerframework.checker.nullness.qual.Nullable; +import me.samsuik.sakura.configuration.transformation.ConfigurationTransformations; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; import org.spongepowered.configurate.ConfigurateException; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.NodePath; @@ -9,21 +11,20 @@ import org.spongepowered.configurate.transformation.TransformAction; import static org.spongepowered.configurate.NodePath.path; +@NullMarked public final class V6_FixIncorrectExtraKnockback implements TransformAction { private static final int VERSION = 6; - private static final NodePath PATH = path("players", "knockback", "sprinting", "extra-knockback"); + private static final NodePath EXTRA_KNOCKBACK_PATH = path("players", "knockback", "sprinting", "extra-knockback"); private static final V6_FixIncorrectExtraKnockback INSTANCE = new V6_FixIncorrectExtraKnockback(); private V6_FixIncorrectExtraKnockback() {} - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - builder.addVersion(VERSION, ConfigurationTransformation.builder() - .addAction(PATH, INSTANCE) - .build()); + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + builder.addVersion(VERSION, ConfigurationTransformations.transform(EXTRA_KNOCKBACK_PATH, INSTANCE)); } @Override - public Object @Nullable [] visitPath(NodePath path, ConfigurationNode value) throws ConfigurateException { + public Object @Nullable [] visitPath(final NodePath path, final ConfigurationNode value) throws ConfigurateException { if (value.getDouble() == 1.0) { value.set(0.5); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V7_FixTntDuplicationName.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V7_FixTntDuplicationName.java index 876ffe7..ec61ef5 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V7_FixTntDuplicationName.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V7_FixTntDuplicationName.java @@ -1,5 +1,6 @@ package me.samsuik.sakura.configuration.transformation.world; +import me.samsuik.sakura.configuration.transformation.ConfigurationTransformations; import org.spongepowered.configurate.NodePath; import org.spongepowered.configurate.transformation.ConfigurationTransformation; @@ -11,9 +12,7 @@ public final class V7_FixTntDuplicationName { private static final NodePath OLD_PATH = path("technical", "allow-t-n-t-duplication"); private static final String NEW_NAME = "allow-tnt-duplication"; - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - builder.addVersion(VERSION, ConfigurationTransformation.builder() - .addAction(OLD_PATH, rename(NEW_NAME)) - .build()); + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + builder.addVersion(VERSION, ConfigurationTransformations.transform(OLD_PATH, rename(NEW_NAME))); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V8_RenameExplosionResistantItems.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V8_RenameExplosionResistantItems.java index c3ab137..cfa7263 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V8_RenameExplosionResistantItems.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V8_RenameExplosionResistantItems.java @@ -1,23 +1,26 @@ package me.samsuik.sakura.configuration.transformation.world; +import org.jspecify.annotations.NullMarked; import org.spongepowered.configurate.NodePath; import org.spongepowered.configurate.transformation.ConfigurationTransformation; import static me.samsuik.sakura.configuration.transformation.ConfigurationTransformations.move; import static org.spongepowered.configurate.NodePath.path; +@NullMarked public final class V8_RenameExplosionResistantItems { private static final int VERSION = 8; - private static final NodePath BASE_PATH = path("entity", "items"); - private static final NodePath OLD_WHITELIST_PATH = BASE_PATH.plus(path("use-whitelist-for-explosion-resistant-items")); - private static final NodePath NEW_WHITELIST_PATH = BASE_PATH.plus(path("blast-resistant", "whitelist-over-blacklist")); - private static final NodePath OLD_ITEMS_PATH = BASE_PATH.plus(path("explosion-resistant-items")); - private static final NodePath NEW_ITEMS_PATH = BASE_PATH.plus(path("blast-resistant", "items")); + private static final NodePath ITEMS_PATH = path("entity", "items"); + private static final NodePath OLD_WHITELIST_PATH = ITEMS_PATH.plus(path("use-whitelist-for-explosion-resistant-items")); + private static final NodePath NEW_WHITELIST_PATH = ITEMS_PATH.plus(path("blast-resistant", "whitelist-over-blacklist")); + private static final NodePath OLD_ITEMS_PATH = ITEMS_PATH.plus(path("explosion-resistant-items")); + private static final NodePath NEW_ITEMS_PATH = ITEMS_PATH.plus(path("blast-resistant", "items")); - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - builder.addVersion(VERSION, ConfigurationTransformation.builder() + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + final ConfigurationTransformation transform = ConfigurationTransformation.builder() .addAction(OLD_WHITELIST_PATH, move(NEW_WHITELIST_PATH)) .addAction(OLD_ITEMS_PATH, move(NEW_ITEMS_PATH)) - .build()); + .build(); + builder.addVersion(VERSION, transform); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V9_RenameAllowNonTntBreakingDurableBlocks.java b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V9_RenameAllowNonTntBreakingDurableBlocks.java index 28a64c8..0fb89b6 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V9_RenameAllowNonTntBreakingDurableBlocks.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/configuration/transformation/world/V9_RenameAllowNonTntBreakingDurableBlocks.java @@ -1,5 +1,6 @@ package me.samsuik.sakura.configuration.transformation.world; +import org.jspecify.annotations.NullMarked; import org.spongepowered.configurate.NodePath; import org.spongepowered.configurate.transformation.ConfigurationTransformation; @@ -7,16 +8,18 @@ import static me.samsuik.sakura.configuration.transformation.ConfigurationTransf import static me.samsuik.sakura.configuration.transformation.ConfigurationTransformations.newValue; import static org.spongepowered.configurate.NodePath.*; +@NullMarked public final class V9_RenameAllowNonTntBreakingDurableBlocks { private static final int VERSION = 9; - private static final NodePath PARENT = path("cannons", "explosion"); - private static final NodePath OLD_PATH = PARENT.plus(path("allow-non-tnt-breaking-durable-blocks")); - private static final NodePath NEW_PATH = PARENT.plus(path("require-tnt-to-damage-durable-materials")); + private static final NodePath EXPLOSION_PATH = path("cannons", "explosion"); + private static final NodePath OLD_PATH = EXPLOSION_PATH.plus(path("allow-non-tnt-breaking-durable-blocks")); + private static final NodePath NEW_PATH = EXPLOSION_PATH.plus(path("require-tnt-to-damage-durable-materials")); - public static void apply(ConfigurationTransformation.VersionedBuilder builder) { - builder.addVersion(VERSION, ConfigurationTransformation.builder() + public static void apply(final ConfigurationTransformation.VersionedBuilder builder) { + final ConfigurationTransformation transform = ConfigurationTransformation.builder() .addAction(OLD_PATH, move(NEW_PATH)) .addAction(NEW_PATH, newValue(v -> !v.getBoolean())) - .build()); + .build(); + builder.addVersion(VERSION, transform); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/EntityState.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/EntityState.java index 35a3d95..80b03af 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/EntityState.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/EntityState.java @@ -10,16 +10,28 @@ import org.jspecify.annotations.NullMarked; import java.util.Optional; @NullMarked -public record EntityState(Vec3 position, Vec3 momentum, AABB bb, Vec3 stuckSpeed, Optional supportingPos, boolean onGround, double fallDistance) { - public static EntityState of(Entity entity) { +public record EntityState( + Vec3 position, + Vec3 momentum, + AABB bb, + Vec3 stuckSpeed, + Optional supportingPos, + boolean onGround, + double fallDistance +) { + public static EntityState of(final Entity entity) { return new EntityState( - entity.position(), entity.getDeltaMovement(), entity.getBoundingBox(), - entity.stuckSpeedMultiplier, entity.mainSupportingBlockPos, - entity.onGround(), entity.fallDistance + entity.position(), + entity.getDeltaMovement(), + entity.getBoundingBox(), + entity.stuckSpeedMultiplier, + entity.mainSupportingBlockPos, + entity.onGround(), + entity.fallDistance ); } - public void apply(Entity entity) { + public void apply(final Entity entity) { entity.setPos(this.position); entity.setDeltaMovement(this.momentum); entity.setBoundingBox(this.bb); @@ -29,11 +41,6 @@ public record EntityState(Vec3 position, Vec3 momentum, AABB bb, Vec3 stuckSpeed entity.fallDistance = this.fallDistance; } - public void applyEntityPosition(Entity entity) { - entity.setPos(this.position); - entity.setBoundingBox(this.bb); - } - public boolean comparePositionAndMotion(Entity entity) { return entity.position().equals(this.position) && entity.getDeltaMovement().equals(this.momentum); diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java index 7a8e3cb..a65cc08 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java @@ -16,11 +16,11 @@ public final class EntityMergeHandler { * @param entity the entity being merged * @return success */ - public boolean tryMerge(@Nullable Entity entity, @Nullable Entity previous) { + public boolean tryMerge(final @Nullable Entity entity, final @Nullable Entity previous) { if (entity instanceof MergeableEntity mergeEntity && previous instanceof MergeableEntity) { - MergeEntityData mergeEntityData = mergeEntity.getMergeEntityData(); - MergeStrategy strategy = MergeStrategy.from(mergeEntityData.mergeLevel); - Entity into = strategy.mergeEntity(entity, previous, this.trackedHistory); + final MergeEntityData mergeEntityData = mergeEntity.getMergeEntityData(); + final MergeStrategy strategy = MergeStrategy.from(mergeEntityData.mergeLevel); + final Entity into = strategy.mergeEntity(entity, previous, this.trackedHistory); if (into instanceof MergeableEntity intoEntity && !into.isRemoved() && mergeEntity.isSafeToMergeInto(intoEntity, strategy.trackHistory())) { return this.mergeEntity(mergeEntity, intoEntity); } @@ -34,10 +34,10 @@ public final class EntityMergeHandler { * * @param entity provided entity */ - public void removeEntity(@Nullable Entity entity) { + public void removeEntity(final @Nullable Entity entity) { if (entity instanceof MergeableEntity mergeEntity) { - MergeEntityData mergeEntityData = mergeEntity.getMergeEntityData(); - MergeStrategy strategy = MergeStrategy.from(mergeEntityData.mergeLevel); + final MergeEntityData mergeEntityData = mergeEntity.getMergeEntityData(); + final MergeStrategy strategy = MergeStrategy.from(mergeEntityData.mergeLevel); if (mergeEntityData.hasMerged() && strategy.trackHistory()) { this.trackedHistory.trackHistory(entity, mergeEntityData); } @@ -45,11 +45,13 @@ public final class EntityMergeHandler { } /** - * Called every 200 ticks and the tick is used remove any unneeded merge history. + * Remove old entries from the tracked history. + *

+ * This method is called every 200 ticks. * * @param tick server tick */ - public void expire(long tick) { + public void expire(final long tick) { this.trackedHistory.expire(tick); } @@ -62,13 +64,13 @@ public final class EntityMergeHandler { * @param into the entity to merge into * @return if successful */ - public boolean mergeEntity(MergeableEntity mergeEntity, MergeableEntity into) { - MergeEntityData entities = mergeEntity.getMergeEntityData(); - MergeEntityData mergeInto = into.getMergeEntityData(); + public boolean mergeEntity(final MergeableEntity mergeEntity, final MergeableEntity into) { + final MergeEntityData entities = mergeEntity.getMergeEntityData(); + final MergeEntityData mergeInto = into.getMergeEntityData(); mergeInto.mergeWith(entities); // merge entities together // discard the entity and update the bukkit handle - Entity nmsEntity = (Entity) mergeEntity; + final Entity nmsEntity = (Entity) mergeEntity; nmsEntity.discard(); nmsEntity.updateBukkitHandle((Entity) into); return true; diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java index 07a7e44..3952278 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java @@ -5,13 +5,13 @@ import org.jspecify.annotations.NullMarked; @NullMarked public interface MergeCondition { - default MergeCondition and(MergeCondition condition) { + default MergeCondition and(final MergeCondition condition) { return (e,c,t) -> this.accept(e,c,t) && condition.accept(e,c,t); } - default MergeCondition or(MergeCondition condition) { + default MergeCondition or(final MergeCondition condition) { return (e,c,t) -> this.accept(e,c,t) || condition.accept(e,c,t); } - boolean accept(Entity entity, int attempts, long sinceCreation); + boolean accept(final Entity entity, final int attempts, final long sinceCreation); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java index 395c198..56250bf 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java @@ -14,17 +14,17 @@ public final class MergeEntityData { public int count = 1; public MergeLevel mergeLevel = MergeLevel.NONE; - public MergeEntityData(Entity entity) { + public MergeEntityData(final Entity entity) { this.entity = entity; } - private void updateEntityHandles(Entity entity) { - for (MergeEntityData entityData : this.connected) { + private void updateEntityHandles(final Entity entity) { + for (final MergeEntityData entityData : this.connected) { entityData.entity.updateBukkitHandle(entity); } } - public void mergeWith(MergeEntityData mergeEntityData) { + public void mergeWith(final MergeEntityData mergeEntityData) { this.connected.add(mergeEntityData); this.connected.addAll(mergeEntityData.connected); this.count += mergeEntityData.count; @@ -38,7 +38,7 @@ public final class MergeEntityData { } public LongOpenHashSet getOriginPositions() { - LongOpenHashSet positions = new LongOpenHashSet(); + final LongOpenHashSet positions = new LongOpenHashSet(); this.connected.forEach(entityData -> positions.add(entityData.entity.getPackedOriginPosition())); return positions; } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java index 4e06192..7fa17b5 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java @@ -6,11 +6,11 @@ import org.jspecify.annotations.NullMarked; public interface MergeableEntity { MergeEntityData getMergeEntityData(); - boolean isSafeToMergeInto(MergeableEntity entity, boolean ticksLived); + boolean isSafeToMergeInto(final MergeableEntity entity, final boolean ticksLived); default boolean tryToRespawnEntity() { - MergeEntityData mergeData = this.getMergeEntityData(); - int originalCount = mergeData.count; + final MergeEntityData mergeData = this.getMergeEntityData(); + final int originalCount = mergeData.count; if (originalCount > 1) { mergeData.count = 0; this.respawnEntity(originalCount); @@ -19,5 +19,5 @@ public interface MergeableEntity { return false; } - void respawnEntity(int count); + void respawnEntity(final int count); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java index faffb4c..bff94a2 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java @@ -8,7 +8,6 @@ import me.samsuik.sakura.utils.TickExpiry; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.item.FallingBlockEntity; import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -16,52 +15,49 @@ import org.jspecify.annotations.Nullable; public final class TrackedMergeHistory { private final Long2ObjectMap historyMap = new Long2ObjectOpenHashMap<>(); - public boolean hasPreviouslyMergedAndMeetsCondition(Entity entity, Entity into, MergeCondition condition) { + public boolean hasPreviouslyMergedAndMeetsCondition(final Entity entity, final Entity into, final MergeCondition condition) { return this.hasPreviouslyMerged(entity, into) && this.hasMetCondition(entity, condition); } - public boolean hasPreviouslyMerged(Entity entity, Entity into) { - PositionHistory positions = this.getHistory(into, false); + public boolean hasPreviouslyMerged(final Entity entity, final Entity into) { + final PositionHistory positions = this.getHistory(into, false); return positions != null && positions.hasPosition(entity); } - public boolean hasMetCondition(Entity entity, MergeCondition condition) { - PositionHistory positions = this.getHistory(entity, false); + public boolean hasMetCondition(final Entity entity, final MergeCondition condition) { + final PositionHistory positions = this.getHistory(entity, false); return positions != null && positions.hasMetConditions(entity, condition); } - private boolean shouldTrackAllPositions(Entity entity, MergeEntityData mergeEntityData) { + private boolean shouldTrackAllPositions(final Entity entity, final MergeEntityData mergeEntityData) { return entity instanceof FallingBlockEntity || mergeEntityData.mergeLevel == MergeLevel.LENIENT || entity.level().sakuraConfig().cannons.mechanics.tntSpread == TNTSpread.ALL; } - public void trackHistory(Entity entity, MergeEntityData mergeEntityData) { - PositionHistory positions = this.getHistory(entity, true); - LongOpenHashSet originPositions = mergeEntityData.getOriginPositions(); - long gameTime = entity.level().getGameTime(); - boolean retainHistory = positions.hasTicksPassed(gameTime, 160); + public void trackHistory(final Entity entity, final MergeEntityData mergeEntityData) { + final PositionHistory positionHistory = this.getHistory(entity, true); + final LongOpenHashSet positions = mergeEntityData.getOriginPositions(); + final long gameTime = entity.level().getGameTime(); + final boolean retainHistory = positionHistory.hasTicksPassed(gameTime, 160); + if (!retainHistory && this.shouldTrackAllPositions(entity, mergeEntityData)) { - originPositions.forEach(pos -> this.historyMap.put(pos, positions)); + positions.forEach(pos -> this.historyMap.put(pos, positionHistory)); } - positions.trackPositions(originPositions, retainHistory); + + positionHistory.trackPositions(positions, retainHistory); } - public void expire(long gameTime) { - this.historyMap.values().removeIf(p -> p.expiry().isExpired(gameTime)); + public void expire(final long gameTime) { + this.historyMap.values().removeIf(history -> history.expiry().isExpired(gameTime)); } - @Nullable @Contract("_, false -> _; _, true -> !null") - private PositionHistory getHistory(Entity entity, boolean create) { - long originPosition = entity.getPackedOriginPosition(); - PositionHistory history = this.historyMap.get(originPosition); - //noinspection ConstantValue - if (create && history == null) { - history = new PositionHistory(entity.level().getGameTime()); - this.historyMap.put(originPosition, history); - } - return history; + private @Nullable PositionHistory getHistory(final Entity entity, final boolean create) { + final long position = entity.getPackedOriginPosition(); + return this.historyMap.computeIfAbsent(position, p -> { + return create ? new PositionHistory(entity.level().getGameTime()) : null; + }); } private static final class PositionHistory { @@ -70,7 +66,7 @@ public final class TrackedMergeHistory { private final long created; private int cycles = 0; - public PositionHistory(long gameTime) { + public PositionHistory(final long gameTime) { this.expiry = new TickExpiry(gameTime, 200); this.created = gameTime; } @@ -79,12 +75,12 @@ public final class TrackedMergeHistory { return this.expiry; } - public boolean hasPosition(Entity entity) { + public boolean hasPosition(final Entity entity) { this.expiry.refresh(entity.level().getGameTime()); return this.positions.contains(entity.getPackedOriginPosition()); } - public void trackPositions(LongOpenHashSet positions, boolean retain) { + public void trackPositions(final LongOpenHashSet positions, final boolean retain) { if (retain) { this.positions.retainAll(positions); } else { @@ -93,16 +89,16 @@ public final class TrackedMergeHistory { this.cycles++; } - public boolean hasMetConditions(@NotNull Entity entity, @NotNull MergeCondition condition) { - long gameTime = entity.level().getGameTime(); + public boolean hasMetConditions(final Entity entity, final MergeCondition condition) { + final long gameTime = entity.level().getGameTime(); return condition.accept(entity, this.cycles, this.timeSinceCreation(gameTime)); } - public boolean hasTicksPassed(long gameTime, int ticks) { + public boolean hasTicksPassed(final long gameTime, final int ticks) { return this.timeSinceCreation(gameTime) > ticks; } - private long timeSinceCreation(long gameTime) { + private long timeSinceCreation(final long gameTime) { return gameTime - this.created; } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/LenientStrategy.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/LenientStrategy.java index 0b0a0fe..8c82504 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/LenientStrategy.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/LenientStrategy.java @@ -1,7 +1,7 @@ package me.samsuik.sakura.entity.merge.strategy; import me.samsuik.sakura.entity.merge.TrackedMergeHistory; -import me.samsuik.sakura.utils.collections.FixedSizeCustomObjectTable; +import me.samsuik.sakura.utils.collections.BlockPosToEntityTable; import net.minecraft.world.entity.Entity; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -9,10 +9,7 @@ import org.jspecify.annotations.Nullable; @NullMarked final class LenientStrategy implements MergeStrategy { static final LenientStrategy INSTANCE = new LenientStrategy(); - - private final FixedSizeCustomObjectTable entityTable = new FixedSizeCustomObjectTable<>(512, entity -> { - return entity.blockPosition().hashCode(); - }); + private final BlockPosToEntityTable entityTable = new BlockPosToEntityTable(512); @Override public boolean trackHistory() { @@ -20,8 +17,7 @@ final class LenientStrategy implements MergeStrategy { } @Override - @Nullable - public Entity mergeEntity(Entity entity, Entity previous, TrackedMergeHistory mergeHistory) { + public @Nullable Entity mergeEntity(final Entity entity, final Entity previous, final TrackedMergeHistory mergeHistory) { if (entity.compareState(previous)) { return previous; } @@ -30,7 +26,7 @@ final class LenientStrategy implements MergeStrategy { this.entityTable.clear(); } - final Entity nextEntity = this.entityTable.getAndWrite(entity); + final Entity nextEntity = this.entityTable.put(entity); if (nextEntity == null || entity == nextEntity || !nextEntity.level().equals(entity.level())) { return null; } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/MergeStrategy.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/MergeStrategy.java index b7b727e..c5da51b 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/MergeStrategy.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/MergeStrategy.java @@ -27,8 +27,7 @@ public interface MergeStrategy { * @param previous last entity to tick * @return success */ - @Nullable - Entity mergeEntity(Entity entity, Entity previous, TrackedMergeHistory mergeHistory); + @Nullable Entity mergeEntity(final Entity entity, final Entity previous, final TrackedMergeHistory mergeHistory); /** * Gets the {@link MergeStrategy} for the {@link MergeLevel}. @@ -36,7 +35,7 @@ public interface MergeStrategy { * @param level provided level * @return strategy */ - static MergeStrategy from(MergeLevel level) { + static MergeStrategy from(final MergeLevel level) { return switch (level) { case NONE -> NoneStrategy.INSTANCE; case STRICT -> StrictStrategy.INSTANCE; diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/NoneStrategy.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/NoneStrategy.java index e885c75..25da3ff 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/NoneStrategy.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/NoneStrategy.java @@ -15,8 +15,7 @@ final class NoneStrategy implements MergeStrategy { } @Override - @Nullable - public Entity mergeEntity(Entity entity, Entity previous, TrackedMergeHistory mergeHistory) { + public @Nullable Entity mergeEntity(final Entity entity, final Entity previous, final TrackedMergeHistory mergeHistory) { return null; } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/SpawnStrategy.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/SpawnStrategy.java index e5a43d6..02404d0 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/SpawnStrategy.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/SpawnStrategy.java @@ -17,8 +17,7 @@ final class SpawnStrategy implements MergeStrategy { } @Override - @Nullable - public Entity mergeEntity(Entity entity, Entity previous, TrackedMergeHistory mergeHistory) { + public @Nullable Entity mergeEntity(final Entity entity, final Entity previous, final TrackedMergeHistory mergeHistory) { final Entity mergeInto; if (entity.tickCount == 1 && mergeHistory.hasPreviouslyMergedAndMeetsCondition(entity, previous, CONDITION)) { mergeInto = previous; diff --git a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/StrictStrategy.java b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/StrictStrategy.java index a2a956f..3d86dda 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/StrictStrategy.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/entity/merge/strategy/StrictStrategy.java @@ -15,8 +15,7 @@ final class StrictStrategy implements MergeStrategy { } @Override - @Nullable - public Entity mergeEntity(Entity entity, Entity previous, TrackedMergeHistory mergeHistory) { + public @Nullable Entity mergeEntity(final Entity entity, final Entity previous, final TrackedMergeHistory mergeHistory) { return entity.compareState(previous) ? previous : null; } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/explosion/SortExplosionRays.java b/sakura-server/src/main/java/me/samsuik/sakura/explosion/SortExplosionRays.java new file mode 100644 index 0000000..3985d69 --- /dev/null +++ b/sakura-server/src/main/java/me/samsuik/sakura/explosion/SortExplosionRays.java @@ -0,0 +1,46 @@ +package me.samsuik.sakura.explosion; + +import it.unimi.dsi.fastutil.doubles.DoubleArrayList; +import org.jspecify.annotations.NullMarked; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +/** + * Sort explosion rays for better cache utilisation. + *

+ *   x +   Vanilla     Sorted
+ * z @ z      8           5
+ * - x      6   7       6   4
+ *        4   @   5   7   @   3
+ *          2   3       8   2
+ *            1           1
+ * 
+ */ +@NullMarked +public final class SortExplosionRays { + private static final Comparator EXPLOSION_RAY_COMPARATOR = Comparator.comparingDouble(vec -> { + final double sign = Math.signum(vec[0]); + final double dir = (sign - 1) / 2; + return sign + 8 + vec[2] * dir; + }); + + public static double[] sortExplosionRays(final DoubleArrayList rayCoords) { + final List explosionRays = new ArrayList<>(); + for (int index = 0; index < rayCoords.size(); index += 3) { + final double[] vector = new double[3]; + rayCoords.getElements(index, vector, 0, 3); + explosionRays.add(vector); + } + + rayCoords.clear(); + explosionRays.sort(EXPLOSION_RAY_COMPARATOR); + + final double[] rays = new double[explosionRays.size() * 3]; + for (int i = 0; i < explosionRays.size() * 3; i++) { + rays[i] = explosionRays.get(i / 3)[i % 3]; + } + return rays; + } +} diff --git a/sakura-server/src/main/java/me/samsuik/sakura/explosion/SpecialisedExplosion.java b/sakura-server/src/main/java/me/samsuik/sakura/explosion/SpecialisedExplosion.java index 6cc6e9e..7471c9d 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/explosion/SpecialisedExplosion.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/explosion/SpecialisedExplosion.java @@ -15,11 +15,13 @@ import net.minecraft.world.level.ServerExplosion; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; import java.util.Arrays; import java.util.List; import java.util.function.Consumer; +@NullMarked public abstract class SpecialisedExplosion extends ServerExplosion { private static final double ENTITY_DISPATCH_DISTANCE = Math.pow(32.0, 2.0); @@ -28,7 +30,17 @@ public abstract class SpecialisedExplosion extends ServerExplo protected final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); private final Consumer> applyEffects; - public SpecialisedExplosion(ServerLevel level, T entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 center, float power, boolean createFire, BlockInteraction destructionType, Consumer> applyEffects) { + public SpecialisedExplosion( + final ServerLevel level, + final T entity, + final @Nullable DamageSource damageSource, + final @Nullable ExplosionDamageCalculator behavior, + final Vec3 center, + final float power, + final boolean createFire, + final BlockInteraction destructionType, + final Consumer> applyEffects + ) { super(level, entity, damageSource, behavior, center, power, createFire, destructionType); this.cause = entity; this.impactPosition = center; @@ -39,18 +51,16 @@ public abstract class SpecialisedExplosion extends ServerExplo return (double) this.cause.getBbHeight() * 0.0625D; } - protected abstract int getExplosionCount(); - - protected abstract void startExplosion(); + protected abstract void beginExplosion(); @Override public final void explode() { this.createBlockCache(); - this.startExplosion(); // search for blocks, impact entities, finalise if necessary + this.beginExplosion(); // search for blocks, impact entities, finalise if necessary this.clearBlockCache(); } - protected final boolean requiresImpactEntities(List blocks, Vec3 center) { + protected final boolean requiresImpactEntities(final List blocks, final Vec3 center) { if (this.impactPosition.distanceToSqr(center) > ENTITY_DISPATCH_DISTANCE) { this.impactPosition = center; return true; @@ -58,9 +68,9 @@ public abstract class SpecialisedExplosion extends ServerExplo return !blocks.isEmpty(); } - protected final boolean finalizeExplosionAndParticles(List blocks) { + protected final boolean finalizeExplosionAndParticles(final List blocks) { this.wasCanceled = false; - List explodedPositions = new ObjectArrayList<>(blocks); + final List explodedPositions = new ObjectArrayList<>(blocks); this.interactWithBlocks(explodedPositions); if (!this.wasCanceled) { @@ -71,11 +81,9 @@ public abstract class SpecialisedExplosion extends ServerExplo return !explodedPositions.isEmpty() && !this.wasCanceled; } - protected void postExplosion(List foundBlocks, boolean destroyedBlocks) { - // optimisation: Keep the block cache across explosions and invalidate any found blocks. - // This can help reduce block retrievals while block searching when there's a durable block, - // and when ray tracing for obstructions. This is disabled by default because plugins can - // change blocks in the explosion event. + protected void postExplosion(final List foundBlocks, final boolean destroyedBlocks) { + // Reuse the block cache between explosions. This can help a lot when searching for blocks and raytracing. + // This is disabled by default as it's incompatible with plugins that modify blocks in the explosion event. if (this.level().sakuraConfig().cannons.explosion.useBlockCacheAcrossExplosions && !foundBlocks.isEmpty() && !destroyedBlocks) { this.markBlocksInCacheAsExplodable(foundBlocks); } else { @@ -86,61 +94,77 @@ public abstract class SpecialisedExplosion extends ServerExplo } protected final void recalculateExplosionPosition() { - this.recalculateExplosionPosition(this.cause); - } - - protected final void recalculateExplosionPosition(T entity) { - double x = entity.getX(); - double y = entity.getY() + this.getExplosionOffset(); - double z = entity.getZ(); + final double x = this.cause.getX(); + final double y = this.cause.getY() + this.getExplosionOffset(); + final double z = this.cause.getZ(); this.center = new Vec3(x, y, z); } - protected final void forEachEntitySliceInBounds(AABB bb, Consumer sliceConsumer) { - int minSection = WorldUtil.getMinSection(this.level()); - int maxSection = WorldUtil.getMaxSection(this.level()); + protected final void locateAndImpactEntitiesInBounds(final AABB bounds, final List explosions) { + final double radius = this.radius() * 2.0f; + final double change = Math.max(bounds.getXsize(), Math.max(bounds.getYsize(), bounds.getZsize())); + final double maxDistanceSqr = Math.pow(radius + change, 2.0); + final boolean positionChanged = change != 0.0; - int minChunkX = Mth.floor(bb.minX) >> 4; - int minChunkY = Mth.clamp(Mth.floor(bb.minY) >> 4, minSection, maxSection); - int minChunkZ = Mth.floor(bb.minZ) >> 4; - int maxChunkX = Mth.floor(bb.maxX) >> 4; - int maxChunkY = Mth.clamp(Mth.floor(bb.maxY) >> 4, minSection, maxSection); - int maxChunkZ = Mth.floor(bb.maxZ) >> 4; + this.forEachEntitySliceInBounds(bounds.inflate(radius), entities -> { + if (positionChanged) { + this.impactEntitiesMoving(entities, explosions, bounds.getCenter(), radius, maxDistanceSqr); + } else { + this.impactEntitiesFromPosition(entities, explosions.getFirst(), explosions.size(), radius); + } + }); + } - EntityLookup entityLookup = this.level().moonrise$getEntityLookup(); - for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) { - for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) { - ChunkEntitySlices chunk = entityLookup.getChunk(chunkX, chunkZ); + protected final void impactEntitiesMoving( + final @Nullable Entity[] entities, + final List explosions, + final Vec3 center, + final double radius, + final double maxDistanceSqr + ) { + for (int index = 0; index < entities.length; ++index) { + final Entity entity = entities[index]; + if (entity == null) break; // end of the entity slice - if (chunk == null) { - continue; - } + // Check if the entity is in range + if (entity.distanceToSqr(center.x, center.y, center.z) > maxDistanceSqr) { + continue; + } - for (int chunkY = minChunkY; chunkY <= maxChunkY; ++chunkY) { - sliceConsumer.accept(chunk.getSectionEntities(chunkY)); - } + //noinspection ForLoopReplaceableByForEach + for (int count = 0; count < explosions.size(); count++) { + this.impactEntity(entity, explosions.get(count), 1, radius); + } + + // Entities can be removed from the world mid-explosion. + if (entities[index] != entity) { + index--; } } } - protected final void impactEntitiesFromPosition(Entity[] entities, Vec3 position, int potential, double radius) { - for (int i = 0; i < entities.length; ++i) { - Entity entity = entities[i]; - if (entity == null) break; + protected final void impactEntitiesFromPosition( + final @Nullable Entity[] entities, + final Vec3 position, + final int potential, + final double radius + ) { + for (int index = 0; index < entities.length; ++index) { + final Entity entity = entities[index]; + if (entity == null) break; // end of the entity slice - if (entity != this.source && !entity.ignoreExplosion(this)) { - this.impactEntity(entity, position, potential, radius); - } + this.impactEntity(entity, position, potential, radius); - if (entities[i] != entity) { - i--; + // Entities can be removed from the world mid-explosion. + if (entities[index] != entity) { + index--; } } } - protected final void impactEntity(Entity entity, Vec3 pos, int potential, double radius) { - if (this.excludeSourceFromDamage && entity == this.source) { - return; // for paper api + protected final void impactEntity(final Entity entity, final Vec3 pos, final int potential, final double radius) { + if (this.excludeSourceFromDamage && this.source == entity || entity.ignoreExplosion(this)) { + return; // Make sure the entity can be affected by explosions. } if (entity.isPrimedTNT || entity.isFallingBlock) { this.impactCannonEntity(entity, pos, potential, radius); @@ -151,27 +175,25 @@ public abstract class SpecialisedExplosion extends ServerExplo } } - protected final void impactCannonEntity(Entity entity, Vec3 pos, int potential, double radius) { + protected final void impactCannonEntity(final Entity entity, final Vec3 pos, final int potential, final double radius) { double distanceFromBottom = Math.sqrt(entity.distanceToSqr(pos)) / radius; - if (distanceFromBottom <= 1.0) { double x = entity.getX() - pos.x; - double y = entity.getEyeY() - pos.y; // Sakura - configure cannon physics + double y = entity.getEyeY() - pos.y; double z = entity.getZ() - pos.z; double distance = Math.sqrt(x * x + y * y + z * z); - // Sakura start - configure cannon physics + if (this.mechanicsTarget.before(MechanicVersion.v1_17)) { distanceFromBottom = (float) distanceFromBottom; distance = (float) distance; } - // Sakura end - configure cannon physics if (distance != 0.0D) { x /= distance; y /= distance; z /= distance; - double density = this.getBlockDensity(pos, entity); // Paper - Optimize explosions - double exposure = (1.0D - distanceFromBottom) * density; + final double density = this.getBlockDensity(pos, entity); // Paper - Optimize explosions + final double exposure = (1.0D - distanceFromBottom) * density; if (exposure == 0.0) { return; @@ -186,14 +208,13 @@ public abstract class SpecialisedExplosion extends ServerExplo } } - protected final void applyEntityVelocity(Entity entity, double x, double y, double z, int potential) { - Vec3 movement = entity.getDeltaMovement(); - + protected final void applyEntityVelocity(final Entity entity, final double x, final double y, final double z, final int potential) { + final Vec3 movement = entity.getDeltaMovement(); double moveX = movement.x(); double moveY = movement.y(); double moveZ = movement.z(); - for (int i = 0; i < potential; ++i) { + for (int count = 0; count < potential; ++count) { moveX += x; moveY += y; moveZ += z; @@ -202,4 +223,31 @@ public abstract class SpecialisedExplosion extends ServerExplo entity.setDeltaMovement(moveX, moveY, moveZ); entity.hasImpulse = true; } + + protected final void forEachEntitySliceInBounds(final AABB bb, final Consumer sliceConsumer) { + final int minSection = WorldUtil.getMinSection(this.level()); + final int maxSection = WorldUtil.getMaxSection(this.level()); + + final int minChunkX = Mth.floor(bb.minX) >> 4; + final int minChunkY = Mth.clamp(Mth.floor(bb.minY) >> 4, minSection, maxSection); + final int minChunkZ = Mth.floor(bb.minZ) >> 4; + final int maxChunkX = Mth.floor(bb.maxX) >> 4; + final int maxChunkY = Mth.clamp(Mth.floor(bb.maxY) >> 4, minSection, maxSection); + final int maxChunkZ = Mth.floor(bb.maxZ) >> 4; + + final EntityLookup entityLookup = this.level().moonrise$getEntityLookup(); + for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) { + for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) { + final ChunkEntitySlices chunk = entityLookup.getChunk(chunkX, chunkZ); + + if (chunk == null) { + continue; + } + + for (int chunkY = minChunkY; chunkY <= maxChunkY; ++chunkY) { + sliceConsumer.accept(chunk.getSectionEntities(chunkY)); + } + } + } + } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/explosion/TntExplosion.java b/sakura-server/src/main/java/me/samsuik/sakura/explosion/TntExplosion.java index 630a206..2efb18c 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/explosion/TntExplosion.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/explosion/TntExplosion.java @@ -16,10 +16,12 @@ import net.minecraft.world.level.ExplosionDamageCalculator; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NullMarked; import java.util.List; import java.util.function.Consumer; +@NullMarked public final class TntExplosion extends SpecialisedExplosion { private static final int ALL_DIRECTIONS = 0b111; private static final int FOUND_ALL_BLOCKS = ALL_DIRECTIONS + 12; @@ -30,21 +32,56 @@ public final class TntExplosion extends SpecialisedExplosion { private int swinging = 0; private boolean moved = false; - public TntExplosion(ServerLevel level, PrimedTnt tnt, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 center, float power, boolean createFire, BlockInteraction destructionType, Consumer> applyEffects) { + public TntExplosion( + final ServerLevel level, + final PrimedTnt tnt, + final @Nullable DamageSource damageSource, + final @Nullable ExplosionDamageCalculator behavior, + final Vec3 center, + final float power, + final boolean createFire, + final BlockInteraction destructionType, + final Consumer> applyEffects + ) { super(level, tnt, damageSource, behavior, center, power, createFire, destructionType, applyEffects); this.originalPosition = center; this.bounds = new AABB(center, center); } - // Sakura start - configure cannon physics @Override protected double getExplosionOffset() { - return this.mechanicsTarget.before(MechanicVersion.v1_10) ? (double) 0.49f : super.getExplosionOffset(); + return this.mechanicsTarget.before(MechanicVersion.v1_10) + ? (double) 0.49f + : super.getExplosionOffset(); } - // Sakura end - configure cannon physics - @Override - protected int getExplosionCount() { + private void mergeEntitiesBeforeExploding() { + final IteratorSafeOrderedReferenceSet entities = this.level().entityTickList.entities; + int index = entities.indexOf(this.cause); + + entities.createRawIterator(); + // iterate over the entityTickList to find entities that are exploding in the same position. + while ((index = entities.advanceRawIterator(index)) != Integer.MAX_VALUE) { + final Entity foundEntity = entities.rawGet(index); + + // Make sure the found entity is alive and it's a mergeable entity. + if (!(foundEntity instanceof MergeableEntity mergeEntity) || foundEntity.isRemoved()) { + break; + } + + // Check if the found entity is the same type and has the same state as the explosion source. + if (!foundEntity.compareState(this.cause) || !mergeEntity.isSafeToMergeInto(this.cause, true)) { + break; + } + + // Merge the found entity into the explosion source + this.level().mergeHandler.mergeEntity(mergeEntity, this.cause); + } + entities.finishRawIterator(); + } + + private int mergeAndGetExplosionPotential() { + // Try to merge entities before exploding if (this.cause.getMergeEntityData().mergeLevel == MergeLevel.NONE) { this.mergeEntitiesBeforeExploding(); } @@ -52,34 +89,31 @@ public final class TntExplosion extends SpecialisedExplosion { } @Override - protected void startExplosion() { - for (int i = this.getExplosionCount() - 1; i >= 0; --i) { - boolean lastCycle = i == 0; - List toBlow = this.midExplosion(lastCycle); // search for blocks and impact entities - boolean destroyedBlocks = this.finalizeExplosionAndParticles(toBlow); // call events, break blocks and send particles + protected void beginExplosion() { + for (int remaining = this.mergeAndGetExplosionPotential() - 1; remaining >= 0; --remaining) { + final boolean lastCycle = remaining == 0; + final List toBlow = this.midExplosion(lastCycle); // search for blocks and impact entities + final boolean destroyedBlocks = this.finalizeExplosionAndParticles(toBlow); // call events, break blocks and send particles if (!lastCycle) { - EntityState entityState = this.nextSourceVelocity(); + final EntityState entityState = this.nextSourceVelocity(); this.postExplosion(toBlow, destroyedBlocks); this.updateExplosionPosition(entityState, destroyedBlocks); } } } - private List midExplosion(boolean lastCycle) { - final List explodedPositions; - if (this.swinging < FOUND_ALL_BLOCKS) { - explodedPositions = this.calculateExplodedPositions(); - } else { - explodedPositions = List.of(); - } + private List midExplosion(final boolean lastCycle) { + final List explodedPositions = this.swinging < FOUND_ALL_BLOCKS + ? this.calculateExplodedPositions() + : List.of(); - Vec3 center = this.center; + final Vec3 center = this.center; this.bounds = this.bounds.expand(center); this.explosions.add(center); if (lastCycle || this.requiresImpactEntities(explodedPositions, center)) { - this.locateAndImpactEntitiesInBounds(); + this.locateAndImpactEntitiesInBounds(this.bounds, this.explosions); this.bounds = new AABB(center, center); this.explosions.clear(); } @@ -88,7 +122,7 @@ public final class TntExplosion extends SpecialisedExplosion { } @Override - protected void postExplosion(List foundBlocks, boolean destroyedBlocks) { + protected void postExplosion(final List foundBlocks, final boolean destroyedBlocks) { super.postExplosion(foundBlocks, destroyedBlocks); if (this.swinging >= ALL_DIRECTIONS) { // Increment "swinging" if no blocks have been found, and it has swung in every direction. @@ -101,10 +135,10 @@ public final class TntExplosion extends SpecialisedExplosion { } } - private void updateSwingingState(Vec3 momentum, Vec3 previousMomentum) { - for (Direction.Axis axis : Direction.Axis.VALUES) { - double current = momentum.get(axis); - double previous = previousMomentum.get(axis); + private void updateSwingingState(final Vec3 momentum, final Vec3 previousMomentum) { + for (final Direction.Axis axis : Direction.Axis.VALUES) { + final double current = momentum.get(axis); + final double previous = previousMomentum.get(axis); if (current == previous || current * previous <= 0.0) { this.swinging |= 1 << axis.ordinal(); } @@ -116,25 +150,26 @@ public final class TntExplosion extends SpecialisedExplosion { } private EntityState nextSourceVelocity() { - Vec3 origin = this.getCauseOrigin(); // valid position to use while creating a temporary entity - PrimedTnt tnt = new PrimedTnt(this.level(), origin.x(), origin.y(), origin.z(), null); + final Vec3 origin = this.getCauseOrigin(); // valid position to use while creating a temporary entity + final PrimedTnt tnt = new PrimedTnt(this.level(), origin.x(), origin.y(), origin.z(), null); this.cause.entityState().apply(tnt); this.impactCannonEntity(tnt, this.center, 1, this.radius() * 2.0f); return EntityState.of(tnt); } - private void updateExplosionPosition(EntityState entityState, boolean destroyedBlocks) { + private void updateExplosionPosition(final EntityState entityState, final boolean destroyedBlocks) { // Before setting entity state, otherwise we might cause issues. - Vec3 entityMomentum = this.cause.entityState().momentum(); + final Vec3 entityMomentum = this.cause.entityState().momentum(); final boolean hasMoved; if (this.moved) { hasMoved = true; } else if (this.center.equals(this.cause.position())) { hasMoved = false; } else { - double newMomentum = entityState.momentum().lengthSqr(); - double oldMomentum = entityMomentum.lengthSqr(); - hasMoved = oldMomentum <= Math.pow(this.radius() * 2.0 + 1.0, 2.0) || newMomentum <= oldMomentum; + final double newMomentumSqr = entityState.momentum().lengthSqr(); + final double oldMomentumSqr = entityMomentum.lengthSqr(); + final double maxExplosionRadiusSqr = Math.pow(this.radius() * 2.0 + 1.0, 2.0); + hasMoved = oldMomentumSqr <= maxExplosionRadiusSqr || newMomentumSqr <= oldMomentumSqr; } // Keep track of entity state @@ -156,59 +191,4 @@ public final class TntExplosion extends SpecialisedExplosion { this.swinging = ALL_DIRECTIONS; } } - - private void mergeEntitiesBeforeExploding() { - IteratorSafeOrderedReferenceSet entities = this.level().entityTickList.entities; - int index = entities.indexOf(this.cause); - - entities.createRawIterator(); - // iterate over the entityTickList to find entities that are exploding in the same position. - while ((index = entities.advanceRawIterator(index)) != Integer.MAX_VALUE) { - Entity foundEntity = entities.rawGet(index); - if (!(foundEntity instanceof MergeableEntity mergeEntity) || foundEntity.isRemoved() || !foundEntity.compareState(this.cause) || !mergeEntity.isSafeToMergeInto(this.cause, true)) - break; - this.level().mergeHandler.mergeEntity(mergeEntity, this.cause); - } - entities.finishRawIterator(); - } - - private void locateAndImpactEntitiesInBounds() { - double radius = this.radius() * 2.0f; - AABB bb = this.bounds; - - Vec3 center = bb.getCenter(); - double change = Math.max(bb.getXsize(), Math.max(bb.getYsize(), bb.getZsize())); - double maxDistanceSqr = Math.pow(radius + change, 2.0); - boolean positionChanged = change != 0.0; - - this.forEachEntitySliceInBounds(bb.inflate(radius), entities -> { - if (positionChanged) { - this.impactEntitiesSwinging(entities, center, radius, maxDistanceSqr); - } else { - this.impactEntitiesFromPosition(entities, this.explosions.getFirst(), this.explosions.size(), radius); - } - }); - } - - private void impactEntitiesSwinging(Entity[] entities, Vec3 center, double radius, double maxDistanceSqr) { - for (int i = 0; i < entities.length; ++i) { - Entity entity = entities[i]; - if (entity == null) break; - - if (entity != this.source && !entity.ignoreExplosion(this) && entity.distanceToSqr(center.x, center.y, center.z) <= maxDistanceSqr) { - this.impactEntitySwinging(entity, radius); - } - - if (entities[i] != entity) { - i--; - } - } - } - - private void impactEntitySwinging(Entity entity, double radius) { - //noinspection ForLoopReplaceableByForEach - for (int i = 0; i < this.explosions.size(); i++) { - this.impactEntity(entity, this.explosions.get(i), 1, radius); - } - } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java b/sakura-server/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java index d7e2463..72eaf37 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java @@ -28,15 +28,15 @@ public final class DensityData { } public boolean hasPosition(Vec3 explosion, AABB entity) { - return this.isExplosionPosition(explosion) && this.entity.isAABBInBounds(entity); + return this.isExplosionPosition(explosion) && this.entity.containsInclusive(entity); } public boolean isKnownPosition(Vec3 point) { - return this.entity.isVec3InBounds(point); + return this.entity.containsInclusive(point); } public boolean isExplosionPosition(Vec3 explosion) { - return this.source.isVec3InBounds(explosion); + return this.source.containsInclusive(explosion); } public void expand(Vec3 explosion, Entity entity) { diff --git a/sakura-server/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java b/sakura-server/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java index d81dce7..ad69e89 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java @@ -11,18 +11,18 @@ import java.util.concurrent.TimeUnit; public final class DurableBlockManager { private final Cache durableBlocks = CacheBuilder.newBuilder() .expireAfterAccess(1, TimeUnit.MINUTES) - .maximumSize(65534) + .maximumSize(Short.MAX_VALUE) .build(); - public boolean damage(BlockPos pos, DurableMaterial material) { - DurableBlock block = this.durableBlocks.getIfPresent(pos); + public boolean damage(final BlockPos blockPos, final DurableMaterial material) { + DurableBlock block = this.durableBlocks.getIfPresent(blockPos); if (block == null) { - this.durableBlocks.put(pos, block = new DurableBlock(material.durability())); + this.durableBlocks.put(blockPos, block = new DurableBlock(material.durability())); } return block.damage(); } - public int durability(BlockPos pos, DurableMaterial material) { + public int durability(final BlockPos pos, final DurableMaterial material) { final DurableBlock block = this.durableBlocks.getIfPresent(pos); return block != null ? block.durability() : material.durability(); } @@ -30,7 +30,7 @@ public final class DurableBlockManager { private static final class DurableBlock { private int durability; - public DurableBlock(int durability) { + public DurableBlock(final int durability) { this.durability = durability; } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/listener/BlockChangeTracker.java b/sakura-server/src/main/java/me/samsuik/sakura/listener/BlockChangeTracker.java index 8e91564..db9d114 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/listener/BlockChangeTracker.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/listener/BlockChangeTracker.java @@ -21,69 +21,68 @@ public final class BlockChangeTracker { private final Level level; private long identifier = Long.MIN_VALUE; - public BlockChangeTracker(Level level) { + public BlockChangeTracker(final Level level) { this.level = level; } - public long listenForChangesOnce(BlockChangeFilter filter, Set positions, Runnable callback) { - LongConsumer singleUseCallback = (identifier) -> { + public long listenForChangesOnce(final BlockChangeFilter filter, final Set positions, final Runnable callback) { + final LongConsumer singleUseCallback = (identifier) -> { callback.run(); this.stopListening(identifier); }; return this.listenForChanges(filter, positions, singleUseCallback); } - public long listenForChanges(BlockChangeFilter filter, Set positions, LongConsumer callback) { - long identifier = this.identifier++; - Listener listener = new Listener( - filter, positions, identifier, callback - ); - for (ChunkPos chunkPos : getChunkPositions(positions)) { + public long listenForChanges(final BlockChangeFilter filter, final Set positions, final LongConsumer callback) { + final long identifier = this.identifier++; + final Listener listener = new Listener(filter, positions, identifier, callback); + for (final ChunkPos chunkPos : getChunkPositions(positions)) { this.addListenerToChunk(chunkPos, listener); } this.identifiersInUse.put(identifier, listener); return identifier; } - public void stopListening(long identifier) { - Listener listener = this.identifiersInUse.remove(identifier); + public void stopListening(final long identifier) { + final Listener listener = this.identifiersInUse.remove(identifier); + //noinspection ConstantValue if (listener != null) { - for (ChunkPos chunkPos : getChunkPositions(listener.positions())) { + for (final ChunkPos chunkPos : getChunkPositions(listener.positions())) { this.removeListenerFronChunk(chunkPos, listener); } } } - private void removeListenerFronChunk(ChunkPos chunkPos, Listener listener) { - long chunkKey = chunkPos.toLong(); - List listeners = this.chunkListeners.computeIfPresent(chunkKey, (k, present) -> { + private void removeListenerFronChunk(final ChunkPos chunkPos, final Listener listener) { + final long chunkKey = chunkPos.toLong(); + final List listeners = this.chunkListeners.computeIfPresent(chunkKey, (k, present) -> { present.remove(listener); return present.isEmpty() ? null : present; }); this.updateListeners(chunkPos, Objects.requireNonNullElse(listeners, Collections.emptyList())); } - private void addListenerToChunk(ChunkPos chunkPos, Listener listener) { - long chunkKey = chunkPos.toLong(); - List listeners = this.chunkListeners.computeIfAbsent(chunkKey, i -> new ArrayList<>()); + private void addListenerToChunk(final ChunkPos chunkPos, final Listener listener) { + final long chunkKey = chunkPos.toLong(); + final List listeners = this.chunkListeners.computeIfAbsent(chunkKey, i -> new ArrayList<>()); listeners.add(listener); this.updateListeners(chunkPos, listeners); } - private void updateListeners(ChunkPos chunkPos, List listeners) { - LevelChunk chunk = ((ServerLevel) this.level).chunkSource.getChunkAtIfLoadedImmediately(chunkPos.x, chunkPos.z); + private void updateListeners(final ChunkPos chunkPos, final List listeners) { + final LevelChunk chunk = ((ServerLevel) this.level).chunkSource.getChunkAtIfLoadedImmediately(chunkPos.x, chunkPos.z); if (chunk != null) { chunk.updateBlockChangeListeners(List.copyOf(listeners)); } } - public List getListenersForChunk(ChunkPos chunkPos) { + public List getListenersForChunk(final ChunkPos chunkPos) { return List.copyOf(this.chunkListeners.getOrDefault(chunkPos.toLong(), Collections.emptyList())); } - private static Set getChunkPositions(Set positions) { - Set chunkPositions = new ObjectOpenHashSet<>(); - for (BlockPos pos : positions) { + private static Set getChunkPositions(final Set positions) { + final Set chunkPositions = new ObjectOpenHashSet<>(); + for (final BlockPos pos : positions) { chunkPositions.add(new ChunkPos(pos)); } return chunkPositions; @@ -97,16 +96,15 @@ public final class BlockChangeTracker { || newBlock.isSignalSource() != oldBlock.isSignalSource(); }; - boolean test(Level level, BlockPos pos, BlockState newBlock, BlockState oldBlock); + boolean test(final Level level, final BlockPos pos, final BlockState newBlock, final BlockState oldBlock); } - public record Listener(BlockChangeFilter filter, Set positions, - long identifier, LongConsumer callback) { + public record Listener(BlockChangeFilter filter, Set positions, long identifier, LongConsumer callback) { public void call() { this.callback.accept(this.identifier); } - public boolean test(Level level, BlockPos pos, BlockState newBlock, BlockState oldBlock) { + public boolean test(final Level level, final BlockPos pos, final BlockState newBlock, final BlockState oldBlock) { return this.filter.test(level, pos, newBlock, oldBlock) && this.positions.contains(pos); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/listener/LevelTickScheduler.java b/sakura-server/src/main/java/me/samsuik/sakura/listener/LevelTickScheduler.java index e827943..200af46 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/listener/LevelTickScheduler.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/listener/LevelTickScheduler.java @@ -1,82 +1,90 @@ package me.samsuik.sakura.listener; -import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.Reference2IntMap; +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; import net.minecraft.world.level.Level; import org.jspecify.annotations.NullMarked; import java.util.ArrayDeque; -import java.util.ArrayList; import java.util.Deque; import java.util.List; @NullMarked public final class LevelTickScheduler { - private final Int2ObjectMap> tickTasks = new Int2ObjectLinkedOpenHashMap<>(); - private final Object2IntMap taskIntervals = new Object2IntOpenHashMap<>(); + private final Long2ObjectMap> scheduledTasks = new Long2ObjectOpenHashMap<>(); + private final Int2ObjectMap> repeatingTasks = new Int2ObjectOpenHashMap<>(); + private final Reference2IntMap taskIntervals = new Reference2IntOpenHashMap<>(); private final Deque removeLater = new ArrayDeque<>(); + private final Level level; - public void delayedTask(Runnable runnable, int delay) { - this.registerNewTask(new TickTask() { - private int cycles = 0; - - @Override - public void run(long tick) { - if (this.cycles++ >= delay) { - runnable.run(); - LevelTickScheduler.this.removeLater.add(this); - } - } - }, 0); + public LevelTickScheduler(final Level level) { + this.level = level; } - public void registerNewTask(Runnable runnable, int interval) { - this.registerNewTask(tick -> runnable.run(), interval); + public void runTaskLater(final Runnable task, final int delay) { + this.runTaskLater(tick -> task.run(), delay); } - public void registerNewTask(TickTask task, int interval) { - int safeInterval = Math.max(interval + 1, 1); - this.tickTasks.computeIfAbsent(safeInterval, i -> new ArrayList<>()) + public void runTaskLater(final TickTask task, final int delay) { + final long runAt = this.level.getGameTime() + delay; + this.scheduledTasks.computeIfAbsent(runAt, i -> new ObjectArrayList<>()) .add(task); - this.taskIntervals.put(task, safeInterval); } - private void removeTasks() { + public void repeatingTask(final Runnable task, final int interval) { + this.repeatingTask(tick -> task.run(), interval); + } + + public void repeatingTask(final TickTask task, final int interval) { + final int taskInterval = Math.max(interval, 1); + this.repeatingTasks.computeIfAbsent(taskInterval, i -> new ObjectArrayList<>()) + .add(task); + this.taskIntervals.put(task, taskInterval); + } + + public void removeTask(final TickTask task) { + final int taskInterval = this.taskIntervals.removeInt(task); + this.repeatingTasks.computeIfPresent(taskInterval, (i, tasks) -> { + tasks.remove(task); + return tasks.isEmpty() ? null : tasks; + }); + } + + private void runTasks(final List tasks, final long gameTime) { + for (final TickTask tickTask : tasks) { + tickTask.run(gameTime); + } + } + + public void tick() { + final long gameTime = this.level.getGameTime(); + for (final long tick : this.scheduledTasks.keySet()) { + if (tick > gameTime) { + continue; + } + final List tasks = this.scheduledTasks.remove(tick); + this.runTasks(tasks, gameTime); + this.removeLater.addAll(tasks); + } + + for (final int interval : this.repeatingTasks.keySet()) { + if (gameTime % interval == 0) { + this.runTasks(this.repeatingTasks.get(interval), gameTime); + } + } + TickTask tickTask; while ((tickTask = this.removeLater.poll()) != null) { this.removeTask(tickTask); } } - private void removeTask(TickTask task) { - int interval = this.taskIntervals.removeInt(task); - if (interval > 0) { - this.tickTasks.computeIfPresent(interval, (i, tasks) -> { - tasks.remove(task); - return tasks.isEmpty() ? null : tasks; - }); - } - } - - private void runTasks(List tasks, long gameTime) { - for (TickTask tickTask : tasks) { - tickTask.run(gameTime); - } - } - - public void levelTick(Level level) { - long gameTime = level.getGameTime(); - for (int interval : this.tickTasks.keySet()) { - if (gameTime % interval == 0) { - this.runTasks(this.tickTasks.get(interval), gameTime); - } - } - this.removeTasks(); - } - public interface TickTask { - void run(long tick); + void run(final long tick); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/mechanics/EntityBehaviour.java b/sakura-server/src/main/java/me/samsuik/sakura/mechanics/EntityBehaviour.java index ab71cc8..5d8949a 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/mechanics/EntityBehaviour.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/mechanics/EntityBehaviour.java @@ -8,7 +8,7 @@ import org.jspecify.annotations.Nullable; @NullMarked public final class EntityBehaviour { - public static void pre1_21_6$changeEntityPosition( + public static void changeEntityPosition( final Entity entity, final Vec3 position, final Vec3 relativeMovement, diff --git a/sakura-server/src/main/java/me/samsuik/sakura/mechanics/LiquidBehaviour.java b/sakura-server/src/main/java/me/samsuik/sakura/mechanics/LegacyBlockFormation.java similarity index 93% rename from sakura-server/src/main/java/me/samsuik/sakura/mechanics/LiquidBehaviour.java rename to sakura-server/src/main/java/me/samsuik/sakura/mechanics/LegacyBlockFormation.java index 317f793..e0ef5bf 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/mechanics/LiquidBehaviour.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/mechanics/LegacyBlockFormation.java @@ -7,8 +7,8 @@ import net.minecraft.world.level.material.FluidState; import org.jspecify.annotations.NullMarked; @NullMarked -public final class LiquidBehaviour { - public static boolean canLiquidSolidify( +public final class LegacyBlockFormation { + public static boolean canLiquidFormBlock( final Level level, final BlockPos pos, final FluidState fluidState, diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/combat/CombatUtil.java b/sakura-server/src/main/java/me/samsuik/sakura/player/combat/CombatUtil.java index 302732f..bb5ee6f 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/combat/CombatUtil.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/combat/CombatUtil.java @@ -21,21 +21,23 @@ import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.item.enchantment.ItemEnchantments; import org.apache.commons.lang3.mutable.MutableFloat; +import org.jspecify.annotations.NullMarked; import java.util.OptionalDouble; +@NullMarked public final class CombatUtil { - public static boolean overrideBlockingAndHalveDamage(ItemStack stack, LivingEntity entity) { + public static boolean overrideBlockingAndHalveDamage(final ItemStack stack, final LivingEntity entity) { return stack.getItem() instanceof BlockableSwordItem swordItem && swordItem.isSafeToOverrideBlocking(stack) || stack.is(Items.SHIELD) && !DataComponentHelper.itemHasComponent(stack, DataComponents.BLOCKS_ATTACKS) && entity.level().sakuraConfig().players.combat.shieldDamageReduction; } - public static double getLegacyAttackDifference(ItemStack itemstack) { - ItemAttributeModifiers defaultModifiers = itemstack.getItem().components().get(DataComponents.ATTRIBUTE_MODIFIERS); + public static double getLegacyAttackDifference(final ItemStack itemstack) { + final ItemAttributeModifiers defaultModifiers = itemstack.getItem().components().get(DataComponents.ATTRIBUTE_MODIFIERS); if (defaultModifiers != null && !defaultModifiers.modifiers().isEmpty()) { // exists double baseAttack = 0.0; - for (ItemAttributeModifiers.Entry entry : defaultModifiers.modifiers()) { + for (final ItemAttributeModifiers.Entry entry : defaultModifiers.modifiers()) { if (!entry.slot().test(EquipmentSlot.MAINHAND) || !entry.attribute().is(Attributes.ATTACK_DAMAGE)) continue; if (entry.modifier().operation() != AttributeModifier.Operation.ADD_VALUE) @@ -43,19 +45,20 @@ public final class CombatUtil { baseAttack += entry.modifier().amount(); } - OptionalDouble legacyAttack = LegacyDamageMapping.itemAttackDamage(itemstack.getItem()); + final OptionalDouble legacyAttack = LegacyDamageMapping.itemAttackDamage(itemstack.getItem()); if (baseAttack != 0.0 && legacyAttack.isPresent()) { return legacyAttack.getAsDouble() - baseAttack; } } - return 0; + + return 0.0; } - public static float calculateLegacySharpnessDamage(LivingEntity entity, ItemStack itemstack, DamageSource damageSource) { - Holder enchantment = getEnchantmentHolder(Enchantments.SHARPNESS); - ItemEnchantments itemEnchantments = itemstack.getEnchantments(); - int enchantmentLevel = itemEnchantments.getLevel(enchantment); - MutableFloat damage = new MutableFloat(); + public static float calculateLegacySharpnessDamage(final LivingEntity entity, final ItemStack itemstack, final DamageSource damageSource) { + final Holder enchantment = getEnchantmentHolder(Enchantments.SHARPNESS); + final ItemEnchantments itemEnchantments = itemstack.getEnchantments(); + final int enchantmentLevel = itemEnchantments.getLevel(enchantment); + final MutableFloat damage = new MutableFloat(); if (entity.level() instanceof ServerLevel level) { enchantment.value().modifyDamage(level, enchantmentLevel, itemstack, entity, damageSource, damage); @@ -64,9 +67,9 @@ public final class CombatUtil { return enchantmentLevel * 1.25F - damage.getValue(); } - private static Holder getEnchantmentHolder(ResourceKey enchantmentKey) { - RegistryAccess registryAccess = MinecraftServer.getServer().registryAccess(); - HolderLookup.RegistryLookup enchantments = registryAccess.lookupOrThrow(Registries.ENCHANTMENT); + private static Holder getEnchantmentHolder(final ResourceKey enchantmentKey) { + final RegistryAccess registryAccess = MinecraftServer.getServer().registryAccess(); + final HolderLookup.RegistryLookup enchantments = registryAccess.lookupOrThrow(Registries.ENCHANTMENT); return enchantments.getOrThrow(enchantmentKey); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/combat/LegacyDamageMapping.java b/sakura-server/src/main/java/me/samsuik/sakura/player/combat/LegacyDamageMapping.java index eed0b3f..7de243b 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/combat/LegacyDamageMapping.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/combat/LegacyDamageMapping.java @@ -12,19 +12,21 @@ import net.minecraft.tags.TagKey; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.item.*; import net.minecraft.world.item.component.ItemAttributeModifiers; +import org.jspecify.annotations.NullMarked; import java.util.OptionalDouble; +@NullMarked public final class LegacyDamageMapping { private static final Reference2DoubleMap LEGACY_ITEM_DAMAGE_MAP = new Reference2DoubleOpenHashMap<>(); - public static OptionalDouble itemAttackDamage(Item item) { - double result = LEGACY_ITEM_DAMAGE_MAP.getDouble(item); + public static OptionalDouble itemAttackDamage(final Item item) { + final double result = LEGACY_ITEM_DAMAGE_MAP.getDouble(item); return result == Double.MIN_VALUE ? OptionalDouble.empty() : OptionalDouble.of(result); } private interface ItemDamageRemapper { - double apply(Item item, double attackDamage); + double apply(final Item item, final double attackDamage); } static { @@ -38,36 +40,30 @@ public final class LegacyDamageMapping { LEGACY_ITEM_DAMAGE_MAP.put(Items.DIAMOND_AXE, 6.0); LEGACY_ITEM_DAMAGE_MAP.put(Items.NETHERITE_AXE, 7.0); - Reference2ObjectMap, ItemDamageRemapper> remapUsingItemTags = new Reference2ObjectArrayMap<>(); + final Reference2ObjectMap, ItemDamageRemapper> remapUsingItemTags = new Reference2ObjectArrayMap<>(); remapUsingItemTags.put(ItemTags.SWORDS, (item, attack) -> 1.0); remapUsingItemTags.put(ItemTags.PICKAXES, (item, attack) -> 1.0); remapUsingItemTags.put(ItemTags.SHOVELS, (item, attack) -> -0.5); remapUsingItemTags.put(ItemTags.HOES, (item, attack) -> -attack); - for (Item item : BuiltInRegistries.ITEM) { - ItemAttributeModifiers modifiers = item.components().get(DataComponents.ATTRIBUTE_MODIFIERS); - + for (final Item item : BuiltInRegistries.ITEM) { + final ItemAttributeModifiers modifiers = item.components().get(DataComponents.ATTRIBUTE_MODIFIERS); if (modifiers == null || LEGACY_ITEM_DAMAGE_MAP.containsKey(item)) { continue; } - Holder.Reference itemHolder = item.builtInRegistryHolder(); - assert itemHolder.is(ItemTags.AXES) : "missing axe mapping"; - - double attackDamage = modifiers.modifiers().stream() + final double attackDamage = modifiers.modifiers().stream() .filter(e -> e.attribute().is(Attributes.ATTACK_DAMAGE)) .mapToDouble(e -> e.modifier().amount()) .sum(); if (attackDamage > 0.0) { - double adjustment = 0.0; - for (TagKey key : remapUsingItemTags.keySet()) { - if (itemHolder.is(key)) { - ItemDamageRemapper remapper = remapUsingItemTags.get(key); - adjustment = remapper.apply(item, attackDamage); - } - } - + final Holder.Reference itemHolder = item.builtInRegistryHolder(); + final double adjustment = remapUsingItemTags.keySet().stream() + .filter(itemHolder::is) + .mapToDouble(itemTagKey -> remapUsingItemTags.get(itemTagKey).apply(item, attackDamage)) + .findFirst() + .orElse(0.0); LEGACY_ITEM_DAMAGE_MAP.put(item, attackDamage + adjustment); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/FeatureGui.java b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/FeatureGui.java index 49f53c0..495755a 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/FeatureGui.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/FeatureGui.java @@ -13,28 +13,28 @@ public abstract class FeatureGui { private final int size; private final Component title; - public FeatureGui(int size, Component title) { + public FeatureGui(final int size, final Component title) { this.size = size; this.title = title; } - protected abstract void fillInventory(Inventory inventory); + protected abstract void fillInventory(final Inventory inventory); - protected abstract void afterFill(Player player, FeatureGuiInventory inventory); + protected abstract void afterFill(final Player player, final FeatureGuiInventory inventory); - public final void showTo(Player bukkitPlayer) { - FeatureGuiInventory featureInventory = new FeatureGuiInventory(this, this.size, this.title); + public final void showTo(final Player bukkitPlayer) { + final FeatureGuiInventory featureInventory = new FeatureGuiInventory(this, this.size, this.title); this.fillInventory(featureInventory.getInventory()); this.afterFill(bukkitPlayer, featureInventory); bukkitPlayer.openInventory(featureInventory.getInventory()); } @ApiStatus.Internal - public static void clickEvent(InventoryClickEvent event) { - Inventory clicked = event.getClickedInventory(); + public static void clickEvent(final InventoryClickEvent event) { + final Inventory clicked = event.getClickedInventory(); if (clicked != null && clicked.getHolder(false) instanceof FeatureGuiInventory featureInventory) { - event.setCancelled(true); - for (GuiComponent component : featureInventory.getComponents().reversed()) { + event.setCancelled(true); // cancel the event first to let components uncancel the event if desired. + for (final GuiComponent component : featureInventory.getComponents().reversed()) { if (component.interaction(event, featureInventory)) { break; } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/FeatureGuiInventory.java b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/FeatureGuiInventory.java index 6c86501..064b04b 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/FeatureGuiInventory.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/FeatureGuiInventory.java @@ -24,7 +24,7 @@ public final class FeatureGuiInventory implements InventoryHolder { private final Multimap componentsUnderKey = HashMultimap.create(); private final Object2ObjectMap componentKeys = new Object2ObjectLinkedOpenHashMap<>(); - public FeatureGuiInventory(FeatureGui gui, int size, Component component) { + public FeatureGuiInventory(final FeatureGui gui, final int size, final Component component) { this.inventory = Bukkit.createInventory(this, size, component); this.gui = gui; } @@ -42,36 +42,36 @@ public final class FeatureGuiInventory implements InventoryHolder { return ImmutableList.copyOf(this.componentKeys.keySet()); } - public ImmutableList findComponents(NamespacedKey key) { + public ImmutableList findComponents(final NamespacedKey key) { return ImmutableList.copyOf(this.componentsUnderKey.get(key)); } - public Optional findFirst(NamespacedKey key) { - Collection components = this.componentsUnderKey.get(key); + public Optional findFirst(final NamespacedKey key) { + final Collection components = this.componentsUnderKey.get(key); return components.stream().findFirst(); } - public void removeComponents(NamespacedKey key) { - Collection removed = this.componentsUnderKey.removeAll(key); - for (GuiComponent component : removed) { + public void removeComponents(final NamespacedKey key) { + final Collection removed = this.componentsUnderKey.removeAll(key); + for (final GuiComponent component : removed) { this.componentKeys.remove(component); } } - public void addComponent(GuiComponent component, NamespacedKey key) { + public void addComponent(final GuiComponent component, final NamespacedKey key) { Preconditions.checkArgument(!this.componentKeys.containsKey(component), "component has already been added"); this.componentKeys.put(component, key); this.componentsUnderKey.put(key, component); this.inventoryUpdate(component); } - public void removeComponent(GuiComponent component) { - NamespacedKey key = this.componentKeys.remove(component); + public void removeComponent(final GuiComponent component) { + final NamespacedKey key = this.componentKeys.remove(component); this.componentsUnderKey.remove(key, component); } - public void replaceComponent(GuiComponent component, GuiComponent replacement) { - NamespacedKey key = this.componentKeys.remove(component); + public void replaceComponent(final GuiComponent component, final GuiComponent replacement) { + final NamespacedKey key = this.componentKeys.remove(component); Preconditions.checkNotNull(key, "component does not exist"); this.componentKeys.put(replacement, key); this.componentsUnderKey.remove(key, component); @@ -84,7 +84,7 @@ public final class FeatureGuiInventory implements InventoryHolder { this.componentsUnderKey.clear(); } - private void inventoryUpdate(GuiComponent component) { + private void inventoryUpdate(final GuiComponent component) { component.creation(this.inventory); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/ItemStackUtil.java b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/ItemStackUtil.java index 1915dc9..53d6f7d 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/ItemStackUtil.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/ItemStackUtil.java @@ -7,13 +7,13 @@ import org.jspecify.annotations.NullMarked; @NullMarked public final class ItemStackUtil { - public static ItemStack itemWithBlankName(Material material) { + public static ItemStack itemWithBlankName(final Material material) { return itemWithName(material, Component.empty()); } - public static ItemStack itemWithName(Material material, Component component) { - ItemStack item = new ItemStack(material); - item.editMeta(m -> m.itemName(component)); + public static ItemStack itemWithName(final Material material, final Component component) { + final ItemStack item = new ItemStack(material); + item.editMeta(meta -> meta.itemName(component)); return item; } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/GuiClickEvent.java b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/GuiClickEvent.java index 39065d5..0f7b2f6 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/GuiClickEvent.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/GuiClickEvent.java @@ -6,5 +6,5 @@ import org.jspecify.annotations.NullMarked; @NullMarked public interface GuiClickEvent { - void doSomething(InventoryClickEvent event, FeatureGuiInventory inventory); + void doSomething(final InventoryClickEvent event, final FeatureGuiInventory inventory); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/GuiComponent.java b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/GuiComponent.java index 5a2ff0c..c4ad52c 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/GuiComponent.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/GuiComponent.java @@ -7,7 +7,7 @@ import org.jspecify.annotations.NullMarked; @NullMarked public interface GuiComponent { - boolean interaction(InventoryClickEvent event, FeatureGuiInventory featureInventory); + boolean interaction(final InventoryClickEvent event, final FeatureGuiInventory featureInventory); - void creation(Inventory inventory); + void creation(final Inventory inventory); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/ItemButton.java b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/ItemButton.java index 6d49d33..426f1b0 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/ItemButton.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/ItemButton.java @@ -12,14 +12,14 @@ public final class ItemButton implements GuiComponent { private final int slot; private final GuiClickEvent whenClicked; - public ItemButton(ItemStack bukkitItem, int slot, GuiClickEvent whenClicked) { + public ItemButton(final ItemStack bukkitItem, final int slot, final GuiClickEvent whenClicked) { this.bukkitItem = bukkitItem; this.slot = slot; this.whenClicked = whenClicked; } @Override - public boolean interaction(InventoryClickEvent event, FeatureGuiInventory featureInventory) { + public boolean interaction(final InventoryClickEvent event, final FeatureGuiInventory featureInventory) { if (event.getSlot() == this.slot) { this.whenClicked.doSomething(event, featureInventory); return true; @@ -28,7 +28,7 @@ public final class ItemButton implements GuiComponent { } @Override - public void creation(Inventory inventory) { + public void creation(final Inventory inventory) { inventory.setItem(this.slot, this.bukkitItem); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/ItemSwitch.java b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/ItemSwitch.java index 243f1cb..dba6d48 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/ItemSwitch.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/gui/components/ItemSwitch.java @@ -17,7 +17,7 @@ public final class ItemSwitch implements GuiComponent { private final int selected; private final GuiClickEvent whenClicked; - public ItemSwitch(List items, int slot, int selected, GuiClickEvent whenClicked) { + public ItemSwitch(final List items, final int slot, final int selected, final GuiClickEvent whenClicked) { Preconditions.checkArgument(!items.isEmpty()); this.items = Collections.unmodifiableList(items); this.slot = slot; @@ -26,10 +26,10 @@ public final class ItemSwitch implements GuiComponent { } @Override - public boolean interaction(InventoryClickEvent event, FeatureGuiInventory featureInventory) { + public boolean interaction(final InventoryClickEvent event, final FeatureGuiInventory featureInventory) { if (this.slot == event.getSlot()) { - int next = (this.selected + 1) % this.items.size(); - ItemSwitch itemSwitch = new ItemSwitch(this.items, this.slot, next, this.whenClicked); + final int next = (this.selected + 1) % this.items.size(); + final ItemSwitch itemSwitch = new ItemSwitch(this.items, this.slot, next, this.whenClicked); featureInventory.replaceComponent(this, itemSwitch); this.whenClicked.doSomething(event, featureInventory); return true; @@ -38,7 +38,7 @@ public final class ItemSwitch implements GuiComponent { } @Override - public void creation(Inventory inventory) { + public void creation(final Inventory inventory) { inventory.setItem(this.slot, this.items.get(this.selected)); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/item/BlockableSwordItem.java b/sakura-server/src/main/java/me/samsuik/sakura/player/item/BlockableSwordItem.java index 7b21391..7ce95b1 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/item/BlockableSwordItem.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/item/BlockableSwordItem.java @@ -24,12 +24,12 @@ public final class BlockableSwordItem extends Item { .hasConsumeParticles(false) .build(); - public BlockableSwordItem(Properties properties) { + public BlockableSwordItem(final Properties properties) { super(properties); } @Override - public void modifyComponentsSentToClient(PatchedDataComponentMap components) { + public void modifyComponentsSentToClient(final PatchedDataComponentMap components) { if (!hasCustomAnimationOrDisabled(components)) { // When updating to 1.22 change CONSUMABLE to BLOCK_ATTACKS components.set(DataComponents.CONSUMABLE, BLOCKING_ANIMATION); @@ -37,7 +37,7 @@ public final class BlockableSwordItem extends Item { } @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { final ItemStack stack = player.getItemInHand(hand); if (hasCustomAnimationOrDisabled(stack.getComponents())) { return super.use(level, player, hand); @@ -48,7 +48,7 @@ public final class BlockableSwordItem extends Item { } @Override - public int getUseDuration(ItemStack stack, LivingEntity entity) { + public int getUseDuration(final ItemStack stack, final LivingEntity entity) { if (hasCustomAnimationOrDisabled(stack.getComponents())) { return super.getUseDuration(stack, entity); } else { @@ -56,11 +56,11 @@ public final class BlockableSwordItem extends Item { } } - public boolean isSafeToOverrideBlocking(ItemStack stack) { + public boolean isSafeToOverrideBlocking(final ItemStack stack) { return !hasCustomAnimationOrDisabled(stack.getComponents()); } - private static boolean hasCustomAnimationOrDisabled(DataComponentMap componentMap) { + private static boolean hasCustomAnimationOrDisabled(final DataComponentMap componentMap) { final GlobalConfiguration config = GlobalConfiguration.get(); return (config == null || !config.players.combat.blockWithSwords) || componentMap.has(DataComponents.CONSUMABLE) diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/item/DataComponentHelper.java b/sakura-server/src/main/java/me/samsuik/sakura/player/item/DataComponentHelper.java index 19b0bbc..3317262 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/item/DataComponentHelper.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/item/DataComponentHelper.java @@ -5,19 +5,21 @@ import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentType; import net.minecraft.core.component.DataComponents; import net.minecraft.world.item.ItemStack; +import org.jspecify.annotations.NullMarked; +@NullMarked public final class DataComponentHelper { public static int bucketMaxStackSize() { - GlobalConfiguration config = GlobalConfiguration.get(); + final GlobalConfiguration config = GlobalConfiguration.get(); return config == null || !config.players.bucketStackSize.isDefined() ? -1 : config.players.bucketStackSize.intValue(); } @SuppressWarnings("OptionalAssignedToNull") - public static boolean itemHasComponent(ItemStack stack, DataComponentType component) { + public static boolean itemHasComponent(final ItemStack stack, final DataComponentType component) { return stack.getComponentsPatch().get(component) != null; } - public static DataComponentMap copyComponentsAndModifyMaxStackSize(DataComponentMap componentMap, int maxItemSize) { + public static DataComponentMap copyComponentsAndModifyMaxStackSize(final DataComponentMap componentMap, final int maxItemSize) { if (maxItemSize > 0 && maxItemSize <= 99) { return DataComponentMap.builder() .addAll(componentMap) diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/item/LegacyGoldenAppleItem.java b/sakura-server/src/main/java/me/samsuik/sakura/player/item/LegacyGoldenAppleItem.java index 2d1922a..b4451b1 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/item/LegacyGoldenAppleItem.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/item/LegacyGoldenAppleItem.java @@ -32,12 +32,12 @@ public final class LegacyGoldenAppleItem extends Item { ) .build(); - public LegacyGoldenAppleItem(Properties settings) { + public LegacyGoldenAppleItem(final Properties settings) { super(settings); } @Override - public InteractionResult use(Level level, Player player, InteractionHand hand) { + public InteractionResult use(final Level level, final Player player, final InteractionHand hand) { final ItemStack stack = player.getItemInHand(hand); if (isItemConsumableOrDisabled(stack, level)) { return super.use(level, player, hand); @@ -47,7 +47,7 @@ public final class LegacyGoldenAppleItem extends Item { } @Override - public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entity) { + public ItemStack finishUsingItem(final ItemStack stack, final Level level, final LivingEntity entity) { if (isItemConsumableOrDisabled(stack, level)) { return super.finishUsingItem(stack, level, entity); } else { @@ -55,7 +55,7 @@ public final class LegacyGoldenAppleItem extends Item { } } - private static boolean isItemConsumableOrDisabled(ItemStack stack, Level level) { + private static boolean isItemConsumableOrDisabled(final ItemStack stack, final Level level) { return DataComponentHelper.itemHasComponent(stack, DataComponents.CONSUMABLE) || !level.sakuraConfig().players.combat.oldEnchantedGoldenApple; } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/item/MilkBucketItem.java b/sakura-server/src/main/java/me/samsuik/sakura/player/item/MilkBucketItem.java index 81be9a1..f968345 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/item/MilkBucketItem.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/item/MilkBucketItem.java @@ -8,20 +8,20 @@ import org.jspecify.annotations.NullMarked; @NullMarked public final class MilkBucketItem extends Item { - public MilkBucketItem(Properties properties) { + public MilkBucketItem(final Properties properties) { super(properties); } @Override - public void verifyComponentsAfterLoad(ItemStack stack) { - int maxStackSize = DataComponentHelper.bucketMaxStackSize(); + public void verifyComponentsAfterLoad(final ItemStack stack) { + final int maxStackSize = DataComponentHelper.bucketMaxStackSize(); if (maxStackSize > 0 && maxStackSize < 100 && stackableMilkBuckets()) { stack.set(DataComponents.MAX_STACK_SIZE, maxStackSize); } } private static boolean stackableMilkBuckets() { - GlobalConfiguration config = GlobalConfiguration.get(); + final GlobalConfiguration config = GlobalConfiguration.get(); return config != null && config.players.stackableMilkBuckets; } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/item/StackableBucketItem.java b/sakura-server/src/main/java/me/samsuik/sakura/player/item/StackableBucketItem.java index f85d837..c26ff1d 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/item/StackableBucketItem.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/item/StackableBucketItem.java @@ -8,14 +8,14 @@ import org.jspecify.annotations.NullMarked; @NullMarked public final class StackableBucketItem extends BucketItem { - public StackableBucketItem(Fluid content, Properties properties) { + public StackableBucketItem(final Fluid content, final Properties properties) { super(content, properties); } @Override - public void verifyComponentsAfterLoad(ItemStack stack) { + public void verifyComponentsAfterLoad(final ItemStack stack) { // It's also possible to override the components method and modify the stack size through the DataComponentHelper - int maxStackSize = DataComponentHelper.bucketMaxStackSize(); + final int maxStackSize = DataComponentHelper.bucketMaxStackSize(); if (maxStackSize > 0 && maxStackSize < 100) { stack.set(DataComponents.MAX_STACK_SIZE, maxStackSize); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/PlayerVisibilitySettings.java b/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/PlayerVisibilitySettings.java index 1dcf6b1..ef0b067 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/PlayerVisibilitySettings.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/PlayerVisibilitySettings.java @@ -4,22 +4,22 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; +@NullMarked public final class PlayerVisibilitySettings implements VisibilitySettings { private static final String SETTINGS_COMPOUND_TAG = "clientVisibilitySettings"; private final Reference2ObjectMap visibilityStates = new Reference2ObjectOpenHashMap<>(); - @NonNull @Override - public VisibilityState get(@NonNull VisibilityType type) { - VisibilityState state = this.visibilityStates.get(type); + public VisibilityState get(final VisibilityType type) { + final VisibilityState state = this.visibilityStates.get(type); + //noinspection ConstantValue return state != null ? state : type.getDefault(); } - @NonNull @Override - public VisibilityState set(@NonNull VisibilityType type, @NonNull VisibilityState state) { + public VisibilityState set(final VisibilityType type, final VisibilityState state) { if (type.isDefault(state)) { this.visibilityStates.remove(type); } else { @@ -28,10 +28,9 @@ public final class PlayerVisibilitySettings implements VisibilitySettings { return state; } - @NonNull @Override public VisibilityState currentState() { - int modifiedCount = this.visibilityStates.size(); + final int modifiedCount = this.visibilityStates.size(); if (modifiedCount == 0) { return VisibilityState.ON; } else if (modifiedCount != VisibilityTypes.types().size()) { @@ -46,18 +45,18 @@ public final class PlayerVisibilitySettings implements VisibilitySettings { return !this.visibilityStates.isEmpty(); } - public void loadData(@NonNull ValueInput input) { + public void loadData(final ValueInput input) { input.child(SETTINGS_COMPOUND_TAG).ifPresent(settings -> { - for (VisibilityType type : VisibilityTypes.types()) { - String typeKey = type.key(); - String stateName = settings.getStringOr(typeKey, type.getDefault().name()); + for (final VisibilityType type : VisibilityTypes.types()) { + final String typeKey = type.key(); + final String stateName = settings.getStringOr(typeKey, type.getDefault().name()); this.set(type, VisibilityState.valueOf(stateName)); } }); } - public void saveData(@NonNull ValueOutput output) { - ValueOutput settings = output.child(SETTINGS_COMPOUND_TAG); + public void saveData(final ValueOutput output) { + final ValueOutput settings = output.child(SETTINGS_COMPOUND_TAG); this.visibilityStates.forEach((type, state) -> settings.putString(type.key(), state.name())); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGui.java b/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGui.java index 67b821b..a1b9d89 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGui.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGui.java @@ -25,16 +25,16 @@ public final class VisibilityGui extends FeatureGui { } @Override - protected void fillInventory(Inventory inventory) { + protected void fillInventory(final Inventory inventory) { for (int slot = 0; slot < inventory.getSize(); ++slot) { // x, y from top left of the inventory - int x = slot % 9; - int y = slot / 9; + final int x = slot % 9; + final int y = slot / 9; // from center - int rx = x - 4; - int ry = y - 2; - double d = Math.sqrt(rx * rx + ry * ry); - if (d <= 3.25) { + final int rx = x - 4; + final int ry = y - 2; + + if (Math.sqrt(rx * rx + ry * ry) <= 3.25) { inventory.setItem(slot, itemWithBlankName(GlobalConfiguration.get().fps.material)); } else if (x % 8 == 0) { inventory.setItem(slot, itemWithBlankName(Material.BLACK_STAINED_GLASS_PANE)); @@ -45,16 +45,17 @@ public final class VisibilityGui extends FeatureGui { } @Override - protected void afterFill(Player player, FeatureGuiInventory inventory) { - VisibilitySettings settings = player.getVisibility(); - IntArrayFIFOQueue slots = this.availableSlots(); + protected void afterFill(final Player player, final FeatureGuiInventory inventory) { + final VisibilitySettings settings = player.getVisibility(); + final IntArrayFIFOQueue slots = this.availableSlots(); this.updateToggleButton(settings, player, inventory); - for (VisibilityType type : VisibilityTypes.types()) { - VisibilityState state = settings.get(type); - int index = type.states().indexOf(state); - int slot = slots.dequeueInt(); + for (final VisibilityType type : VisibilityTypes.types()) { + final VisibilityState state = settings.get(type); + final int index = type.states().indexOf(state); + final int slot = slots.dequeueInt(); - ItemSwitch itemSwitch = new ItemSwitch( + // Switch between the visibility states + final ItemSwitch itemSwitch = new ItemSwitch( VisibilityGuiItems.GUI_ITEMS.get(type), slot, index, (e, inv) -> { @@ -67,10 +68,10 @@ public final class VisibilityGui extends FeatureGui { } } - private void updateToggleButton(VisibilitySettings settings, Player player, FeatureGuiInventory inventory) { + private void updateToggleButton(final VisibilitySettings settings, final Player player, final FeatureGuiInventory inventory) { inventory.removeComponents(TOGGLE_BUTTON_KEY); - VisibilityState settingsState = settings.currentState(); - ItemButton button = new ItemButton( + final VisibilityState settingsState = settings.currentState(); + final ItemButton button = new ItemButton( VisibilityGuiItems.TOGGLE_BUTTON_ITEMS.get(settingsState), (2 * 9) + 8, (e, inv) -> { @@ -83,7 +84,7 @@ public final class VisibilityGui extends FeatureGui { } private IntArrayFIFOQueue availableSlots() { - IntArrayFIFOQueue slots = new IntArrayFIFOQueue(); + final IntArrayFIFOQueue slots = new IntArrayFIFOQueue(); for (int row = 1; row < 4; ++row) { for (int column = 3; column < 6; ++column) { if ((column + row) % 2 == 0) { diff --git a/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGuiItems.java b/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGuiItems.java index 6e335f8..68bfb9a 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGuiItems.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/player/visibility/VisibilityGuiItems.java @@ -9,29 +9,28 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.apache.commons.lang3.StringUtils; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; +import org.jspecify.annotations.NullMarked; import java.util.Locale; +@NullMarked public final class VisibilityGuiItems { static final Reference2ObjectMap> GUI_ITEMS = new Reference2ObjectOpenHashMap<>(); static final Reference2ObjectMap TOGGLE_BUTTON_ITEMS = new Reference2ObjectOpenHashMap<>(); static { - Reference2ObjectMap items = new Reference2ObjectOpenHashMap<>(); - + final Reference2ObjectMap items = new Reference2ObjectOpenHashMap<>(); items.put(VisibilityTypes.TNT, ItemStackUtil.itemWithName(Material.TNT, Component.text("Tnt", NamedTextColor.RED))); items.put(VisibilityTypes.SAND, ItemStackUtil.itemWithName(Material.SAND, Component.text("Sand", NamedTextColor.YELLOW))); items.put(VisibilityTypes.EXPLOSIONS, ItemStackUtil.itemWithName(Material.COBWEB, Component.text("Explosions", NamedTextColor.WHITE))); items.put(VisibilityTypes.SPAWNERS, ItemStackUtil.itemWithName(Material.SPAWNER, Component.text("Spawners", NamedTextColor.DARK_GRAY))); items.put(VisibilityTypes.PISTONS, ItemStackUtil.itemWithName(Material.PISTON, Component.text("Pistons", NamedTextColor.GOLD))); - for (VisibilityType type : VisibilityTypes.types()) { - ItemStack item = items.get(type); - - ImmutableList stateItems = type.states().stream() - .map(s -> createItemForState(item, s)) + for (final VisibilityType type : VisibilityTypes.types()) { + final ItemStack item = items.get(type); + final ImmutableList stateItems = type.states().stream() + .map(state -> createItemForState(item, state)) .collect(ImmutableList.toImmutableList()); - GUI_ITEMS.put(type, stateItems); } @@ -40,16 +39,16 @@ public final class VisibilityGuiItems { TOGGLE_BUTTON_ITEMS.put(VisibilityState.OFF, ItemStackUtil.itemWithName(Material.RED_STAINED_GLASS_PANE, Component.text("Disabled", NamedTextColor.RED))); } - private static String lowercaseThenCapitalise(String name) { - String lowercaseName = name.toLowerCase(Locale.ENGLISH); + private static String lowercaseThenCapitalise(final String name) { + final String lowercaseName = name.toLowerCase(Locale.ENGLISH); return StringUtils.capitalize(lowercaseName); } - private static ItemStack createItemForState(ItemStack in, VisibilityState state) { - String capitalisedName = lowercaseThenCapitalise(state.name()); - Component component = Component.text(" | " + capitalisedName, NamedTextColor.GRAY); - ItemStack itemCopy = in.clone(); - itemCopy.editMeta(m -> m.itemName(m.itemName().append(component))); + private static ItemStack createItemForState(final ItemStack in, final VisibilityState state) { + final String capitalisedName = lowercaseThenCapitalise(state.name()); + final Component component = Component.text(" | " + capitalisedName, NamedTextColor.GRAY); + final ItemStack itemCopy = in.clone(); + itemCopy.editMeta(meta -> meta.itemName(meta.itemName().append(component))); return itemCopy; } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneNetwork.java b/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneNetwork.java index 37379b9..2a6765d 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneNetwork.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneNetwork.java @@ -1,6 +1,5 @@ package me.samsuik.sakura.redstone; -import io.papermc.paper.configuration.WorldConfiguration; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.objects.*; import me.samsuik.sakura.listener.BlockChangeTracker; @@ -22,15 +21,20 @@ import java.util.List; @NullMarked public final class RedstoneNetwork { private final List wireUpdates; - private final List updates; + private final List neighborUpdates; private final Object2ObjectMap originalWirePower; private final LongArrayList listeners = new LongArrayList(); private final BitSet redundantUpdates = new BitSet(); private final TickExpiry expiry; - public RedstoneNetwork(List wireUpdates, List updates, Object2ObjectMap originalWirePower, TickExpiry expiry) { + public RedstoneNetwork( + final List wireUpdates, + final List neighborUpdates, + final Object2ObjectMap originalWirePower, + final TickExpiry expiry + ) { this.wireUpdates = new ObjectArrayList<>(wireUpdates); - this.updates = new ObjectArrayList<>(updates); + this.neighborUpdates = new ObjectArrayList<>(neighborUpdates); this.originalWirePower = new Object2ObjectOpenHashMap<>(originalWirePower); this.expiry = expiry; } @@ -49,21 +53,21 @@ public final class RedstoneNetwork { return !this.listeners.isEmpty(); } - public boolean hasWire(BlockPos pos) { + public boolean hasWire(final BlockPos pos) { return this.originalWirePower.containsKey(pos); } - public void invalidate(Level level) { - for (long identifier : this.listeners) { + public void invalidate(final Level level) { + for (final long identifier : this.listeners) { level.blockChangeTracker.stopListening(identifier); } this.listeners.clear(); } - private void markNeighboringWiresForShapeUpdates(BlockPos pos, Object2ObjectMap wires) { - for (Direction direction : NeighborUpdater.UPDATE_ORDER) { - BlockPos neighborPos = pos.relative(direction); - RedstoneWireUpdate wireUpdate = wires.get(neighborPos); + private void markNeighboringWiresForShapeUpdates(final BlockPos pos, final Object2ObjectMap wires) { + for (final Direction direction : NeighborUpdater.UPDATE_ORDER) { + final BlockPos neighborPos = pos.relative(direction); + final RedstoneWireUpdate wireUpdate = wires.get(neighborPos); //noinspection ConstantValue if (wireUpdate != null) { wireUpdate.updateShapes(); @@ -71,16 +75,17 @@ public final class RedstoneNetwork { } } - public boolean prepareAndRegisterListeners(Level level, RedstoneNetworkSource networkSource) { - Object2ObjectLinkedOpenHashMap processedWires = new Object2ObjectLinkedOpenHashMap<>(); - boolean skipWireUpdates = networkSource.redstoneImplementation() != WorldConfiguration.Misc.RedstoneImplementation.VANILLA; - for (RedstoneWireUpdate wireUpdate : this.wireUpdates.reversed()) { - BlockPos wirePos = wireUpdate.getPosition(); + public boolean prepareAndRegisterListeners(final Level level, final RedstoneNetworkSource networkSource) { + final Object2ObjectLinkedOpenHashMap processedWires = new Object2ObjectLinkedOpenHashMap<>(); + final boolean skipWireUpdates = networkSource.isVanilla(); + + for (final RedstoneWireUpdate wireUpdate : this.wireUpdates.reversed()) { + final BlockPos wirePos = wireUpdate.getPosition(); //noinspection ConstantValue if (processedWires.putAndMoveToFirst(wirePos, wireUpdate) == null) { // It's possible for the block below the redstone to break while the network is updating - BlockState state = level.getBlockState(wirePos); - if (state.is(Blocks.PISTON_HEAD) || state.is(BlockTags.TRAPDOORS)) { + final BlockState blockStateBelow = level.getBlockState(wirePos.below()); + if (blockStateBelow.is(Blocks.PISTON_HEAD) || blockStateBelow.is(BlockTags.TRAPDOORS)) { return false; } } else if (skipWireUpdates && this.originalWirePower.get(wirePos).firstPower() != wireUpdate.getPower()) { @@ -90,13 +95,14 @@ public final class RedstoneNetwork { } } - for (int updateIndex = 0; updateIndex < this.updates.size(); ++updateIndex) { - BlockPos updatePos = this.updates.get(updateIndex); - BlockState state = level.getBlockState(updatePos); + for (int updateIndex = 0; updateIndex < this.neighborUpdates.size(); ++updateIndex) { + final BlockPos updatePos = this.neighborUpdates.get(updateIndex); + final BlockState state = level.getBlockState(updatePos); + final Block block = state.getBlock(); // Never apply updates to redstone wires if (state.is(Blocks.REDSTONE_WIRE)) { - this.updates.set(updateIndex, null); + this.neighborUpdates.set(updateIndex, null); continue; } @@ -106,7 +112,6 @@ public final class RedstoneNetwork { } // Look for blocks that actually need shape updates - Block block = state.getBlock(); if (state.is(Blocks.OBSERVER) || state.liquid() || block instanceof FallingBlock || block instanceof LiquidBlockContainer) { this.markNeighboringWiresForShapeUpdates(updatePos, processedWires); } @@ -116,20 +121,20 @@ public final class RedstoneNetwork { return true; } - private void allowNeighborUpdates() { - for (int updateIndex = 0; updateIndex < this.updates.size(); ++updateIndex) { + private void allowRedundantNeighborUpdates() { + for (int updateIndex = 0; updateIndex < this.neighborUpdates.size(); ++updateIndex) { if (!this.redundantUpdates.get(updateIndex)) { continue; } - BlockPos pos = this.updates.get(updateIndex); + final BlockPos pos = this.neighborUpdates.get(updateIndex); if (!this.originalWirePower.containsKey(pos)) { this.redundantUpdates.clear(updateIndex); } } } - private void addBlockListeners(Level level) { - ObjectOpenHashSet positions = new ObjectOpenHashSet<>(this.updates); + private void addBlockListeners(final Level level) { + ObjectOpenHashSet positions = new ObjectOpenHashSet<>(this.neighborUpdates); positions.addAll(this.originalWirePower.keySet()); positions.remove(null); @@ -139,13 +144,13 @@ public final class RedstoneNetwork { )); this.listeners.add(level.blockChangeTracker.listenForChangesOnce( - BlockChangeTracker.BlockChangeFilter.ANY, positions, this::allowNeighborUpdates + BlockChangeTracker.BlockChangeFilter.ANY, positions, this::allowRedundantNeighborUpdates )); } - private boolean verifyWiresInNetwork(Level level) { - for (Object2ObjectMap.Entry wireEntry : this.originalWirePower.object2ObjectEntrySet()) { - BlockState state = level.getBlockState(wireEntry.getKey()); + private boolean verifyWiresInNetwork(final Level level) { + for (final Object2ObjectMap.Entry wireEntry : this.originalWirePower.object2ObjectEntrySet()) { + final BlockState state = level.getBlockState(wireEntry.getKey()); if (!state.is(Blocks.REDSTONE_WIRE)) { this.invalidate(level); return false; @@ -159,41 +164,51 @@ public final class RedstoneNetwork { return true; } - private void performUpdates(Level level, Orientation orientation, RedStoneWireBlock wireBlock, int updateFrom, int updateTo) { + private void performUpdates( + final Level level, + final Orientation orientation, + final RedStoneWireBlock wireBlock, + final int updateFrom, + final int updateTo + ) { for (int updateIndex = updateFrom; updateIndex < updateTo; ++updateIndex) { if (this.redundantUpdates.get(updateIndex)) { continue; } - BlockPos updatePos = this.updates.get(updateIndex); + final BlockPos updatePos = this.neighborUpdates.get(updateIndex); + //noinspection ConstantValue if (updatePos != null) { level.getBlockState(updatePos).handleNeighborChanged(level, updatePos, wireBlock, orientation, false); } } } - public boolean applyFromCache(Level level) { + public boolean applyFromCache(final Level level) { this.expiry.refresh(level.getGameTime()); if (!this.isRegistered() || !this.verifyWiresInNetwork(level)) { return false; } - Orientation orientation = ExperimentalRedstoneUtils.initialOrientation(level, null, null); - RedStoneWireBlock wireBlock = (RedStoneWireBlock) Blocks.REDSTONE_WIRE; + final Orientation defaultOrientation = ExperimentalRedstoneUtils.initialOrientation(level, null, null); + final RedStoneWireBlock wireBlock = (RedStoneWireBlock) Blocks.REDSTONE_WIRE; int updateFrom = 0; - for (RedstoneWireUpdate wireUpdate : this.wireUpdates) { + // Apply all wire updates in the network + for (final RedstoneWireUpdate wireUpdate : this.wireUpdates) { if (wireUpdate.canSkipWireUpdate()) { updateFrom = wireUpdate.getUpdateIndex(); continue; } - int updateTo = wireUpdate.getUpdateIndex(); - this.performUpdates(level, orientation, wireBlock, updateFrom, updateTo); + final int updateTo = wireUpdate.getUpdateIndex(); + this.performUpdates(level, defaultOrientation, wireBlock, updateFrom, updateTo); updateFrom = updateTo; - BlockPos wirePos = wireUpdate.getPosition(); - BlockState state = level.getBlockState(wirePos); - BlockState newState = state.setValue(RedStoneWireBlock.POWER, wireUpdate.getPower()); + final BlockPos wirePos = wireUpdate.getPosition(); + final BlockState state = level.getBlockState(wirePos); + final BlockState newState = state.setValue(RedStoneWireBlock.POWER, wireUpdate.getPower()); + + // Update the wire power and apply shape updates when needed if (level.setBlock(wirePos, newState, Block.UPDATE_CLIENTS | Block.UPDATE_KNOWN_SHAPE)) { if (wireUpdate.needsShapeUpdate()) { wireBlock.turbo.updateNeighborShapes(level, wirePos, newState); @@ -201,7 +216,7 @@ public final class RedstoneNetwork { } } - this.performUpdates(level, orientation, wireBlock, updateFrom, this.updates.size()); + this.performUpdates(level, defaultOrientation, wireBlock, updateFrom, this.neighborUpdates.size()); return true; } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneNetworkSource.java b/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneNetworkSource.java index 479851c..47ed1fc 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneNetworkSource.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneNetworkSource.java @@ -9,13 +9,27 @@ import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @NullMarked -public record RedstoneNetworkSource(WorldConfiguration.Misc.RedstoneImplementation redstoneImplementation, - BlockPos position, @Nullable Orientation orientation, - int updateDepth, int newPower, int oldPower) { - - public static RedstoneNetworkSource createNetworkSource(Level level, CachedLocalConfiguration localConfiguration, BlockPos pos, - @Nullable Orientation orientation, int newPower, int oldPower) { - int updateDepth = level.neighborUpdater.getUpdateDepth(); +public record RedstoneNetworkSource( + WorldConfiguration.Misc.RedstoneImplementation redstoneImplementation, + BlockPos position, + @Nullable Orientation orientation, + int updateDepth, + int newPower, + int oldPower +) { + public static RedstoneNetworkSource createNetworkSource( + final Level level, + final CachedLocalConfiguration localConfiguration, + final BlockPos pos, + final @Nullable Orientation orientation, + final int newPower, + final int oldPower + ) { + final int updateDepth = level.neighborUpdater.getUpdateDepth(); return new RedstoneNetworkSource(localConfiguration.paperRedstoneImplementation(), pos, orientation, updateDepth, newPower, oldPower); } + + public boolean isVanilla() { + return this.redstoneImplementation == WorldConfiguration.Misc.RedstoneImplementation.VANILLA; + } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneWireCache.java b/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneWireCache.java index 19da7b9..e263b54 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneWireCache.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneWireCache.java @@ -8,6 +8,7 @@ import net.minecraft.core.Direction; import net.minecraft.world.level.Level; import net.minecraft.world.level.redstone.NeighborUpdater; import net.minecraft.world.level.redstone.Orientation; +import org.jetbrains.annotations.ApiStatus; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -24,15 +25,20 @@ public final class RedstoneWireCache { private final Level level; private @Nullable RedstoneNetwork updatingNetwork; - public RedstoneWireCache(Level level) { + public RedstoneWireCache(final Level level) { this.level = level; } + @ApiStatus.Internal public Map getNetworkCache() { return this.networkCache; } - public boolean isWireUpdating(BlockPos pos) { + public boolean isApplyingCache() { + return this.updatingNetwork != null; + } + + public boolean isUpdatingRedstoneWire(final BlockPos pos) { return this.updatingNetwork != null && this.updatingNetwork.hasWire(pos); } @@ -40,62 +46,52 @@ public final class RedstoneWireCache { return this.networkSource != null; } - public boolean tryApplyFromCache(BlockPos pos, @Nullable Orientation orientation, int newPower, int oldPower) { - final CachedLocalConfiguration localConfiguration = this.level.localConfig().at(pos); - if (!localConfiguration.redstoneBehaviour.cache() || this.isTrackingWireUpdates()) { - return false; - } - - // Ignore any wire changes while updating the network. - if (this.updatingNetwork != null) { - return true; - } - - RedstoneNetworkSource networkSource = RedstoneNetworkSource.createNetworkSource(this.level, localConfiguration, pos, orientation, newPower, oldPower); - RedstoneNetwork network = this.networkCache.get(networkSource); - if (network != null) { - try { - this.updatingNetwork = network; - return network.applyFromCache(this.level); - } finally { - this.updatingNetwork = null; - } - } else { - // Start tracking power and neighbor updates - this.networkSource = networkSource; - return false; - } - } - - public void trackWirePower(BlockPos pos, int newPower, int oldPower) { + public void trackWirePower(final BlockPos pos, final int newPower, final int oldPower) { if (this.isTrackingWireUpdates()) { this.originalWirePower.putIfAbsent(pos, new RedstoneOriginalPower(oldPower, newPower)); this.wireUpdates.add(new RedstoneWireUpdate(pos, newPower, this.updates.size())); } } - public void trackNeighbor(BlockPos pos) { + public void trackNeighbor(final BlockPos pos) { if (this.isTrackingWireUpdates()) { this.updates.add(pos); } } - public void trackNeighborsAt(BlockPos pos) { + public void trackNeighborsAt(final BlockPos pos) { if (this.isTrackingWireUpdates()) { - for (Direction neighbor : NeighborUpdater.UPDATE_ORDER) { + for (final Direction neighbor : NeighborUpdater.UPDATE_ORDER) { this.updates.add(pos.relative(neighbor)); } } } - public void expire(long tick) { - this.networkCache.values().removeIf(network -> { - if (network.getExpiry().isExpired(tick)) { - network.invalidate(this.level); - return true; - } + public boolean applyFromCache(final BlockPos pos, final @Nullable Orientation orientation, final int newPower, final int oldPower) { + final CachedLocalConfiguration localConfiguration = this.level.localConfig().at(pos); + if (!localConfiguration.redstoneBehaviour.cache() || this.isTrackingWireUpdates()) { return false; - }); + } + + final RedstoneNetworkSource networkSource = RedstoneNetworkSource.createNetworkSource( + this.level, localConfiguration, pos, orientation, newPower, oldPower + ); + final RedstoneNetwork network = this.networkCache.get(networkSource); + + // Try to apply a network cache if one does not exist then start tracking wire updates + if (network != null) { + try { + this.updatingNetwork = network; + return network.applyFromCache(this.level); + } finally { + this.updatingNetwork = null; + this.networkSource = null; // applying a cache while tracking can cause issues + } + } else { + // Start tracking wire updates + this.networkSource = networkSource; + return false; + } } public void stopTracking() { @@ -103,9 +99,9 @@ public final class RedstoneWireCache { return; } - // Cache expires if it has not been used in 600 ticks - TickExpiry expiration = new TickExpiry(this.level.getGameTime(), 600); - RedstoneNetwork redstoneNetwork = new RedstoneNetwork( + // The cache will expire if it has not been used in 600 ticks + final TickExpiry expiration = new TickExpiry(this.level.getGameTime(), 600); + final RedstoneNetwork redstoneNetwork = new RedstoneNetwork( this.wireUpdates, this.updates, this.originalWirePower, expiration ); @@ -118,4 +114,15 @@ public final class RedstoneWireCache { this.originalWirePower.clear(); this.networkSource = null; } + + public void expire(final long tick) { + this.networkCache.values().removeIf(network -> { + if (network.getExpiry().isExpired(tick)) { + network.invalidate(this.level); + return true; + } + + return false; + }); + } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneWireUpdate.java b/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneWireUpdate.java index 844576c..20089f0 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneWireUpdate.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/redstone/RedstoneWireUpdate.java @@ -11,7 +11,7 @@ public final class RedstoneWireUpdate { private boolean updateShape; private boolean skipWire; - public RedstoneWireUpdate(BlockPos position, int power, int updateIndex) { + public RedstoneWireUpdate(final BlockPos position, final int power, final int updateIndex) { this.position = position; this.power = power; this.updateIndex = updateIndex; diff --git a/sakura-server/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java b/sakura-server/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java index 20d88bf..268656d 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/tps/ServerTickInformation.java @@ -8,16 +8,24 @@ import net.kyori.adventure.text.format.TextColor; import org.jspecify.annotations.NullMarked; @NullMarked -public record ServerTickInformation(long identifier, double tps, double averageTick, long longestTick, float targetTickRate, int chunks, int entities) { - public static final ServerTickInformation FILLER = new ServerTickInformation(0, 0.0, 0.0, 0, 0.0f, 0, 0); +public record ServerTickInformation( + long identifier, + double tps, + double averageTick, + long longestTick, + float targetTickRate, + int chunks, + int entities +) { + public static final ServerTickInformation UNKNOWN = new ServerTickInformation(0, 0.0, 0.0, 0, 0.0f, 0, 0); public TextColor colour() { - float lag = (float) this.tps / this.targetTickRate; - return GraphComponents.colour(lag); + final float tpsLoss = (float) this.tps / this.targetTickRate; + return GraphComponents.colour(tpsLoss); } - public Component hoverComponent(TextColor colour) { - TextComponent.Builder builder = Component.text(); + public Component hoverComponent(final TextColor colour) { + final TextComponent.Builder builder = Component.text(); builder.append(Component.text("TPS: ") .append(Component.text("%.1f".formatted(this.tps), colour))); builder.appendNewline(); diff --git a/sakura-server/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java b/sakura-server/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java index 5f88e17..2fbdf4e 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/tps/TickInformationCollector.java @@ -21,51 +21,53 @@ public final class TickInformationCollector { return this.collectedInformation.getLast(); } - public void levelData(Collection levels, double tps) { + public void levelData(final Collection levels, final double tps) { int chunks = 0; int entities = 0; - for (ServerLevel level : levels) { + for (final ServerLevel level : levels) { chunks += level.chunkSource.getFullChunksCount(); entities += level.entityTickList.entities.size(); } - double averageTick = this.tickSamples.longStream() + final double averageTick = this.tickSamples.longStream() .average() .orElse(0.0); - long longestTick = this.tickSamples.longStream() + final long longestTick = this.tickSamples.longStream() .max() .orElse(0); - float targetTickRate = MinecraftServer.getServer().tickRateManager().tickrate(); - - ServerTickInformation tickInformation = new ServerTickInformation( + final float targetTickRate = MinecraftServer.getServer().tickRateManager().tickrate(); + final ServerTickInformation tickInformation = new ServerTickInformation( this.identifier++, tps, averageTick, longestTick, targetTickRate, chunks, entities ); this.collectedInformation.add(tickInformation); this.tickSamples.clear(); + // Keep only the last 10 minutes of tick information if (this.collectedInformation.size() > TEN_MINUTES) { this.collectedInformation.subList(0, 60).clear(); } } - public void tickDuration(long timeTaken) { + public void tickDuration(final long timeTaken) { this.tickSamples.add(timeTaken); } - public ImmutableList collect(long from, long to) { - List collected = new ObjectArrayList<>(); - for (ServerTickInformation tickInformation : this.collectedInformation.reversed()) { + public ImmutableList collect(final long from, final long to) { + final List collected = new ObjectArrayList<>(); + for (final ServerTickInformation tickInformation : this.collectedInformation.reversed()) { if (tickInformation.identifier() >= from && tickInformation.identifier() < to) { collected.add(tickInformation); } } - long ahead = to - this.identifier; - long missing = to - from - collected.size(); - for (int i = 0; i < missing; ++i) { - int ind = (i < ahead) ? 0 : collected.size(); - collected.add(ind, ServerTickInformation.FILLER); + + final long ahead = to - this.identifier; + final long missing = to - from - collected.size(); + for (int remaining = 0; remaining < missing; ++remaining) { + final int index = (remaining < ahead) ? 0 : collected.size(); + collected.add(index, ServerTickInformation.UNKNOWN); } + return ImmutableList.copyOf(collected); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java index bf3e953..d1a66ce 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/BuiltComponentCanvas.java @@ -10,23 +10,23 @@ import java.util.List; public final class BuiltComponentCanvas { private final List components; - BuiltComponentCanvas(List components) { + BuiltComponentCanvas(final List components) { this.components = components; } - public void appendLeft(Component component) { + public void appendLeft(final Component component) { this.components.replaceAll(component::append); } - public void appendRight(Component component) { + public void appendRight(final Component component) { this.components.replaceAll(row -> row.append(component)); } - public void header(Component component) { + public void header(final Component component) { this.components.addFirst(component); } - public void footer(Component component) { + public void footer(final Component component) { this.components.add(component); } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java index 4202465..5e6aaf4 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/ComponentCanvas.java @@ -14,7 +14,7 @@ public final class ComponentCanvas { private final int height; private final Component[][] components; - public ComponentCanvas(int width, int height) { + public ComponentCanvas(final int width, final int height) { this.width = width; this.height = height; // [x, y] is flipped as it makes converting the components into a list easier @@ -24,7 +24,7 @@ public final class ComponentCanvas { public void flip() { for (int y = 0; y < this.height; ++y) { if (y >= this.height / 2) { - Component[] row = this.components[y]; + final Component[] row = this.components[y]; int relocatingRow = this.height - 1 - y; this.components[y] = this.components[relocatingRow]; this.components[relocatingRow] = row; @@ -32,7 +32,7 @@ public final class ComponentCanvas { } } - public void fill(Component component) { + public void fill(final Component component) { for (int x = 0; x < this.width; ++x) { for (int y = 0; y < this.height; ++y) { this.set(x, y, component); @@ -40,12 +40,12 @@ public final class ComponentCanvas { } } - public Component get(int x, int y) { - Component component = this.components[y][x]; + public Component get(final int x, final int y) { + final Component component = this.components[y][x]; return Preconditions.checkNotNull(component, "missing component at x:{} y:{}", x, y); } - public void set(int x, int y, Component component) { + public void set(final int x, final int y, final Component component) { this.components[y][x] = component; } @@ -54,8 +54,8 @@ public final class ComponentCanvas { } private List joinComponents() { - List componentList = new ObjectArrayList<>(this.height); - for (Component[] row : this.components) { + final List componentList = new ObjectArrayList<>(this.height); + for (final Component[] row : this.components) { componentList.add(Component.join(JoinConfiguration.noSeparators(), row)); } return componentList; diff --git a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java index bebc61d..2b4ed09 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/DetailedTPSGraph.java @@ -7,13 +7,18 @@ import java.util.List; @NullMarked public final class DetailedTPSGraph extends TPSGraph { - public DetailedTPSGraph(int width, int height, double scale, List tickInformation) { + public DetailedTPSGraph( + final int width, + final int height, + final double scale, + final List tickInformation + ) { super(width, height, scale, tickInformation); } @Override public BuiltComponentCanvas plot() { - ComponentCanvas canvas = new ComponentCanvas(this.width, this.height); + final ComponentCanvas canvas = new ComponentCanvas(this.width, this.height); canvas.fill(GraphComponents.BACKGROUND); this.basicOutline(canvas); @@ -24,12 +29,12 @@ public final class DetailedTPSGraph extends TPSGraph { return canvas.build(); } - private void basicOutline(ComponentCanvas canvas) { + private void basicOutline(final ComponentCanvas canvas) { for (int x = 0; x < this.width; ++x) { - int row = this.rowFromColumn(x); - int nextRow = this.rowFromColumn(x + 1); - int minRow = Math.min(row, nextRow); - int maxRow = Math.max(row, nextRow); + final int row = this.rowFromColumn(x); + final int nextRow = this.rowFromColumn(x + 1); + final int minRow = Math.min(row, nextRow); + final int maxRow = Math.max(row, nextRow); if (maxRow - minRow >= 2) { canvas.set(x, minRow, GraphComponents.TOP_DOTTED_LINE); @@ -44,13 +49,13 @@ public final class DetailedTPSGraph extends TPSGraph { } } - private void prettifyOutline(ComponentCanvas canvas) { + private void prettifyOutline(final ComponentCanvas canvas) { for (int x = 0; x < this.width; ++x) { - int row = this.rowFromColumn(x); - int nextRow = this.rowFromColumn(x + 1); - int prevRow = this.rowFromColumn(x - 1); - int minRow = Math.min(row, nextRow); - int maxRow = Math.max(row, nextRow); + final int row = this.rowFromColumn(x); + final int nextRow = this.rowFromColumn(x + 1); + final int prevRow = this.rowFromColumn(x - 1); + final int minRow = Math.min(row, nextRow); + final int maxRow = Math.max(row, nextRow); if (maxRow - minRow >= 2) { this.prettifyVerticalOutline(canvas, x, row, nextRow, prevRow, minRow, maxRow); @@ -60,7 +65,15 @@ public final class DetailedTPSGraph extends TPSGraph { } } - private void prettifyVerticalOutline(ComponentCanvas canvas, int x, int row, int nextRow, int prevRow, int minRow, int maxRow) { + private void prettifyVerticalOutline( + final ComponentCanvas canvas, + final int x, + final int row, + final int nextRow, + final int prevRow, + final int minRow, + final int maxRow + ) { if (minRow == nextRow) { canvas.set(x, minRow, GraphComponents.CONE_BOTTOM_LEFT); } else if (prevRow <= minRow) { @@ -79,9 +92,15 @@ public final class DetailedTPSGraph extends TPSGraph { } } - private void prettifySlopes(ComponentCanvas canvas, int x, int row, int nextRow, int prevRow) { - int slopeDirection = nextRow - prevRow; - int slopeChange = Math.abs(slopeDirection); + private void prettifySlopes( + final ComponentCanvas canvas, + final int x, + final int row, + final int nextRow, + final int prevRow + ) { + final int slopeDirection = nextRow - prevRow; + final int slopeChange = Math.abs(slopeDirection); if (slopeChange >= 2 && Math.max(nextRow, prevRow) == row + 1) { canvas.set(x, row, slopeDirection < 0 ? GraphComponents.TL_TO_BR : GraphComponents.BL_TO_TR); diff --git a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java index 95d3c80..f6e4b03 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/GraphComponents.java @@ -5,9 +5,11 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; +import org.jspecify.annotations.NullMarked; import java.util.List; +@NullMarked public final class GraphComponents { private static final Style STRIKE_THROUGH_STYLE = Style.style(TextDecoration.STRIKETHROUGH); private static final Style REMOVE_STRIKE_THROUGH_STYLE = Style.style(TextDecoration.STRIKETHROUGH.withState(false)); @@ -29,14 +31,14 @@ public final class GraphComponents { NamedTextColor.RED, NamedTextColor.DARK_GRAY, TextColor.color(40, 40, 40) ); - public static TextColor colour(float num) { - float segment = 1.0f / COLOURS.size(); - float a = (1.0f - num) / segment; - float t = a % 1.0f; - int startIndex = Math.clamp((int) a, 0, COLOURS.size() - 2); - int endIndex = startIndex + 1; - TextColor startColour = COLOURS.get(startIndex); - TextColor endColour = COLOURS.get(endIndex); + public static TextColor colour(final float num) { + final float segment = 1.0f / COLOURS.size(); + final float a = (1.0f - num) / segment; + final float t = a % 1.0f; + final int startIndex = Math.clamp((int) a, 0, COLOURS.size() - 2); + final int endIndex = startIndex + 1; + final TextColor startColour = COLOURS.get(startIndex); + final TextColor endColour = COLOURS.get(endIndex); return TextColor.lerp(t, startColour, endColour); } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java index 27b6b07..826ae18 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/tps/graph/TPSGraph.java @@ -18,7 +18,7 @@ public abstract class TPSGraph { protected final int height; protected final double scale; - public TPSGraph(int width, int height, double scale, List tickInformation) { + public TPSGraph(final int width, final int height, final double scale, final List tickInformation) { Preconditions.checkArgument(tickInformation.size() == width); this.width = width; this.height = height; @@ -28,23 +28,23 @@ public abstract class TPSGraph { public abstract BuiltComponentCanvas plot(); - protected final int rowFromColumn(int x) { - int clamped = Math.clamp(x, 0, this.width - 1); - ServerTickInformation tickInformation = this.tickInformation.get(clamped); + protected final int rowFromColumn(final int x) { + final int clamped = Math.clamp(x, 0, this.width - 1); + final ServerTickInformation tickInformation = this.tickInformation.get(clamped); return this.rowFromTPS(tickInformation.tps()); } - protected final int rowFromTPS(double tps) { - int row = Mth.floor((tps / 3) * this.scale); + protected final int rowFromTPS(final double tps) { + final int row = Mth.floor((tps / 3) * this.scale); return Mth.clamp(row, 0, this.height - 1); } - protected final void addColourAndHoverInformation(ComponentCanvas canvas) { + protected final void addColourAndHoverInformation(final ComponentCanvas canvas) { for (int x = 0; x < this.width; ++x) { - ServerTickInformation tickInformation = this.tickInformation.get(x); - TextColor colourFromTPS = tickInformation.colour(); - Component hoverComponent = tickInformation.hoverComponent(colourFromTPS); - HoverEvent hoverEvent = HoverEvent.showText(hoverComponent); + final ServerTickInformation tickInformation = this.tickInformation.get(x); + final TextColor colourFromTPS = tickInformation.colour(); + final Component hoverComponent = tickInformation.hoverComponent(colourFromTPS); + final HoverEvent hoverEvent = HoverEvent.showText(hoverComponent); for (int y = 0; y < this.height; ++y) { Component component = canvas.get(x, y); diff --git a/sakura-server/src/main/java/me/samsuik/sakura/utils/BlockPosIterator.java b/sakura-server/src/main/java/me/samsuik/sakura/utils/BlockPosIterator.java index 0f287fb..6dc7f5a 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/utils/BlockPosIterator.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/utils/BlockPosIterator.java @@ -19,19 +19,19 @@ public final class BlockPosIterator extends AbstractIterator { private final int endZ; private @Nullable MutableBlockPos pos = null; - public static Iterable iterable(AABB bb) { + public static Iterable iterable(final AABB bb) { return () -> new BlockPosIterator(bb); } - public static Iterable traverseArea(Vec3 vec, AABB boundingBox) { - double toTravel = Math.min(16.0 / vec.length(), 1.0); - Vec3 movement = vec.scale(toTravel); - AABB fromBB = boundingBox.move(-vec.x, -vec.y, -vec.z); - AABB searchArea = fromBB.expandTowards(movement); - return me.samsuik.sakura.utils.BlockPosIterator.iterable(searchArea); + public static Iterable traverseArea(final Vec3 vec, final AABB boundingBox) { + final double toTravel = Math.min(16.0 / vec.length(), 1.0); + final Vec3 movement = vec.scale(toTravel); + final AABB fromBB = boundingBox.move(-vec.x, -vec.y, -vec.z); + final AABB searchArea = fromBB.expandTowards(movement); + return BlockPosIterator.iterable(searchArea); } - public BlockPosIterator(AABB bb) { + public BlockPosIterator(final AABB bb) { this.startX = Mth.floor(bb.minX); this.startY = Mth.floor(bb.minY); this.startZ = Mth.floor(bb.minZ); @@ -42,7 +42,7 @@ public final class BlockPosIterator extends AbstractIterator { @Override protected BlockPos computeNext() { - MutableBlockPos pos = this.pos; + final MutableBlockPos pos = this.pos; if (pos == null) { return this.pos = new MutableBlockPos(this.startX, this.startY, this.startZ); } else { diff --git a/sakura-server/src/main/java/me/samsuik/sakura/utils/TickExpiry.java b/sakura-server/src/main/java/me/samsuik/sakura/utils/TickExpiry.java index a77cf23..4cb6889 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/utils/TickExpiry.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/utils/TickExpiry.java @@ -8,17 +8,17 @@ public final class TickExpiry { private long tick; private final int expiration; - public TickExpiry(long tick, int expiration) { - Preconditions.checkArgument(expiration > 0, "expiration must be greater than 0"); + public TickExpiry(final long tick, final int expiration) { + Preconditions.checkArgument(expiration > 0, "Expiration cannot be lower or equal to 0"); this.tick = tick; this.expiration = expiration; } - public void refresh(long tick) { + public void refresh(final long tick) { this.tick = tick; } - public boolean isExpired(long tick) { + public boolean isExpired(final long tick) { return this.tick < tick - this.expiration; } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/BlockPosToEntityTable.java b/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/BlockPosToEntityTable.java new file mode 100644 index 0000000..b51c838 --- /dev/null +++ b/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/BlockPosToEntityTable.java @@ -0,0 +1,52 @@ +package me.samsuik.sakura.utils.collections; + +import it.unimi.dsi.fastutil.HashCommon; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +import java.util.Arrays; + +@NullMarked +public final class BlockPosToEntityTable { + private final @Nullable Entity[] entities; + private final int mask; + + public BlockPosToEntityTable(final int expectedSize) { + if (expectedSize < 0) { + throw new IllegalArgumentException("Table size cannot be negative"); + } else { + final int size = HashCommon.nextPowerOfTwo(expectedSize - 1); + this.entities = new Entity[size]; + this.mask = (size - 1); + } + } + + public @Nullable Entity get(final BlockPos blockPos) { + return this.entities[this.key(blockPos)]; + } + + public @Nullable Entity put(final Entity entity) { + return this.put(entity.blockPosition(), entity); + } + + public @Nullable Entity put(final BlockPos blockPos, final @Nullable Entity entity) { + final int index = this.key(blockPos); + final Entity present = this.entities[index]; + this.entities[index] = entity; + return present; + } + + public @Nullable Entity remove(final BlockPos blockPos) { + return this.put(blockPos, null); + } + + public void clear() { + Arrays.fill(this.entities, null); + } + + private int key(final BlockPos blockPos) { + return blockPos.hashCode() & this.mask; + } +} diff --git a/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/FixedSizeCustomObjectTable.java b/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/FixedSizeCustomObjectTable.java deleted file mode 100644 index e97f3cc..0000000 --- a/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/FixedSizeCustomObjectTable.java +++ /dev/null @@ -1,54 +0,0 @@ -package me.samsuik.sakura.utils.collections; - -import it.unimi.dsi.fastutil.HashCommon; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.ToIntFunction; - -public final class FixedSizeCustomObjectTable { - private final ToIntFunction keyFunction; - private final T[] contents; - private final int mask; - - public FixedSizeCustomObjectTable(int size, @NotNull ToIntFunction keyFunction) { - if (size < 0) { - throw new IllegalArgumentException("Table size cannot be negative"); - } else { - int n = HashCommon.nextPowerOfTwo(size - 1); - this.keyFunction = keyFunction; - this.contents = (T[]) new Object[n]; - this.mask = (n - 1); - } - } - - private int key(T value) { - return this.keyFunction.applyAsInt(value); - } - - public @Nullable T get(T value) { - return this.get(this.key(value)); - } - - public @Nullable T get(int key) { - return this.contents[key & this.mask]; - } - - public void write(int key, T value) { - this.contents[key & this.mask] = value; - } - - public @Nullable T getAndWrite(T value) { - int key = this.key(value); - T found = this.get(key); - this.write(key, value); - return found; - } - - public void clear() { - int size = this.contents.length; - for (int i = 0; i < size; ++i) { - this.contents[i] = null; - } - } -} diff --git a/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java b/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java deleted file mode 100644 index edbbf9d..0000000 --- a/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java +++ /dev/null @@ -1,49 +0,0 @@ -package me.samsuik.sakura.utils.collections; - -import it.unimi.dsi.fastutil.objects.ObjectArrayList; - -import java.util.Arrays; -import java.util.Comparator; - -public final class OrderedComparatorList extends ObjectArrayList { - private final Comparator comparator; - private boolean binarySearch = true; - - public OrderedComparatorList(int capacity, Comparator comparator) { - super(capacity); - this.comparator = Comparator.nullsLast(comparator); - } - - public OrderedComparatorList(Comparator comparator) { - this(DEFAULT_INITIAL_CAPACITY, comparator); - } - - private void validateBounds(int index, T t, boolean up) { - if (index != 0 && this.comparator.compare(get(index - 1), t) > 0) { - this.binarySearch = false; - } else if (up && index < size() - 1 && this.comparator.compare(get(index + 1), t) < 0) { - this.binarySearch = false; - } - } - - @Override - public boolean add(T t) { - this.validateBounds(size(), t, false); - return super.add(t); - } - - @Override - public void add(int index, T t) { - this.validateBounds(index, t, true); - super.add(index, t); - } - - @Override - public int indexOf(final Object k) { - if (this.binarySearch) { - return Math.max(Arrays.binarySearch(this.a, (T) k, this.comparator), -1); - } else { - return super.indexOf(k); - } - } -} diff --git a/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java b/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java index f267cd5..8c596c4 100644 --- a/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java +++ b/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/TrackedEntityChunkMap.java @@ -1,32 +1,68 @@ package me.samsuik.sakura.utils.collections; +import ca.spottedleaf.moonrise.common.list.ReferenceList; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; import net.minecraft.server.level.ChunkMap; +import org.jspecify.annotations.NullMarked; +import java.util.Iterator; + +@NullMarked public final class TrackedEntityChunkMap extends Int2ObjectOpenHashMap { - private final ObjectArrayList entityList = new UnorderedIndexedList<>(); + private final ReferenceList trackedEntityList = new ReferenceList<>(); @Override - public ChunkMap.TrackedEntity put(int k, ChunkMap.TrackedEntity trackedEntity) { - ChunkMap.TrackedEntity tracked = super.put(k, trackedEntity); + public ChunkMap.TrackedEntity put(final int index, final ChunkMap.TrackedEntity trackedEntity) { + final ChunkMap.TrackedEntity tracked = super.put(index, trackedEntity); + //noinspection ConstantValue if (tracked != null) { - this.entityList.remove(trackedEntity); + this.trackedEntityList.remove(trackedEntity); } - this.entityList.add(trackedEntity); + this.trackedEntityList.add(trackedEntity); return tracked; } @Override - public ChunkMap.TrackedEntity remove(int k) { - ChunkMap.TrackedEntity tracked = super.remove(k); - this.entityList.remove(tracked); + public ChunkMap.TrackedEntity remove(final int index) { + final ChunkMap.TrackedEntity tracked = super.remove(index); + this.trackedEntityList.remove(tracked); return tracked; } @Override public ObjectCollection values() { - return this.entityList; + return new AbstractObjectCollection<>() { + @Override + public ObjectIterator iterator() { + return new TrackedEntityIterator(); + } + + @Override + public int size() { + return TrackedEntityChunkMap.this.size(); + } + }; + } + + private final class TrackedEntityIterator implements ObjectIterator { + private final Iterator backingItr = TrackedEntityChunkMap.this.trackedEntityList.iterator(); + + @Override + public boolean hasNext() { + return this.backingItr.hasNext(); + } + + @Override + public ChunkMap.TrackedEntity next() { + return this.backingItr.next(); + } + + @Override + public void remove() { + this.backingItr.remove(); + } } } diff --git a/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/UnorderedIndexedList.java b/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/UnorderedIndexedList.java deleted file mode 100644 index 131dc69..0000000 --- a/sakura-server/src/main/java/me/samsuik/sakura/utils/collections/UnorderedIndexedList.java +++ /dev/null @@ -1,61 +0,0 @@ -package me.samsuik.sakura.utils.collections; - -import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; - -public final class UnorderedIndexedList extends ObjectArrayList { - private final Int2IntOpenHashMap elementToIndex; - - public UnorderedIndexedList() { - this(DEFAULT_INITIAL_CAPACITY); - } - - public UnorderedIndexedList(int capacity) { - super(capacity); - this.elementToIndex = new Int2IntOpenHashMap(); - this.elementToIndex.defaultReturnValue(-1); - } - - @Override - public boolean add(final T t) { - this.elementToIndex.put(t.hashCode(), size()); - return super.add(t); - } - - @Override - public T remove(final int index) { - final int tail = size() - 1; - final T at = a[index]; - - if (index != tail) { - final T tailObj = a[tail]; - if (tailObj != null) - this.elementToIndex.put(tailObj.hashCode(), index); - this.a[index] = tailObj; - } - - if (at != null) - this.elementToIndex.remove(at.hashCode()); - this.a[tail] = null; - this.size = tail; - return at; - } - - @Override - public void clear() { - this.elementToIndex.clear(); - super.clear(); - } - - @Override - public int indexOf(final Object k) { - if (k == null) return -1; - // entities uses their id as a hashcode - return this.elementToIndex.get(k.hashCode()); - } - - @Override - public void add(final int index, final T t) { - throw new UnsupportedOperationException(); - } -}