From 3f20ea5c714303aa8700a511fd9c1165d2cba9cd Mon Sep 17 00:00:00 2001 From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Date: Fri, 2 May 2025 22:22:53 -0400 Subject: [PATCH] Cleanup --- build-data/leaf.at | 2 + ...-SparklyPaper-Parallel-world-ticking.patch | 11 +- ...hunk-retrieving-in-entity-fluid-push.patch | 6 +- ...ntLong2ReferenceChainedHashTable-wit.patch | 43 +- .../features/0154-Async-target-finding.patch | 600 ++++++++---------- ...timize-ThreadedTicketLevelPropagator.patch | 22 +- ...bEffectUtil-getDigSpeedAmplification.patch | 24 +- .../features/0157-Optimise-chunkUnloads.patch | 45 +- ...58-Optimize-BlockEntityType-isValid.patch} | 14 +- ...004-Pufferfish-Optimize-mob-spawning.patch | 33 +- .../leaf/async/ai/AsyncGoalExecutor.java | 18 +- .../dreeam/leaf/async/ai/AsyncGoalThread.java | 1 + .../java/org/dreeam/leaf/async/ai/Waker.java | 1 + .../leaf/async/world/PWTEventScheduler.java | 2 + .../config/modules/async/AsyncChunkSend.java | 3 +- .../modules/async/AsyncPathfinding.java | 9 +- .../modules/async/AsyncPlayerDataSave.java | 3 +- .../modules/async/AsyncTargetFinding.java | 1 + .../modules/async/MultithreadedTracker.java | 6 +- .../SparklyPaperParallelWorldTicking.java | 3 +- .../modules/gameplay/SmoothTeleport.java | 3 +- .../modules/network/ChatMessageSignature.java | 3 +- .../OptimizeNonFlushPacketSending.java | 6 +- .../config/modules/opt/DontSaveEntity.java | 3 +- .../leaf/util/map/BlockPosIterator.java | 1 + ...currentLong2ReferenceChainedHashTable.java | 500 ++++++++++----- .../dreeam/leaf/util/queue/SpscIntQueue.java | 1 + 27 files changed, 730 insertions(+), 634 deletions(-) rename leaf-server/minecraft-patches/features/{0158-optimize-BlockEntityType-isValid.patch => 0158-Optimize-BlockEntityType-isValid.patch} (79%) diff --git a/build-data/leaf.at b/build-data/leaf.at index 272f5d5a..227aec3d 100644 --- a/build-data/leaf.at +++ b/build-data/leaf.at @@ -1,6 +1,8 @@ # This file is auto generated, any changes may be overridden! # See CONTRIBUTING.md on how to add access transformers. protected net.minecraft.world.entity.Entity dimensions +protected net.minecraft.world.entity.ai.goal.RemoveBlockGoal blockToRemove +protected net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal getTargetConditions()Lnet/minecraft/world/entity/ai/targeting/TargetingConditions; protected-f net.minecraft.world.level.block.state.BlockBehaviour$BlockStateBase$Cache largeCollisionShape public net.minecraft.util.Mth SIN public net.minecraft.world.entity.Entity updateInWaterStateAndDoWaterCurrentPushing()V diff --git a/leaf-server/minecraft-patches/features/0134-SparklyPaper-Parallel-world-ticking.patch b/leaf-server/minecraft-patches/features/0134-SparklyPaper-Parallel-world-ticking.patch index 505f0d9c..35e26162 100644 --- a/leaf-server/minecraft-patches/features/0134-SparklyPaper-Parallel-world-ticking.patch +++ b/leaf-server/minecraft-patches/features/0134-SparklyPaper-Parallel-world-ticking.patch @@ -743,10 +743,10 @@ index b17c8a2f5294ac28cc05fb05c84a041b2c6c8721..0b8b4658dbbad1bacc13e97b4fc0cdce serverPlayer.connection = player.connection; serverPlayer.restoreFrom(player, keepInventory); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 9bc978ca290ca772b0367e89b69fe16b502b0cd2..2f98d035b32d3a9b3366dbea0ac52b24d06dd373 100644 +index 9bc978ca290ca772b0367e89b69fe16b502b0cd2..334a47659ba75fade062bc79df3731d1e449114b 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -3370,15 +3370,41 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3370,15 +3370,40 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess if (this.portalProcess != null) { if (this.portalProcess.processPortalTeleportation(serverLevel, this, this.canUsePortal(false))) { this.setPortalCooldown(); @@ -760,12 +760,11 @@ index 9bc978ca290ca772b0367e89b69fe16b502b0cd2..2f98d035b32d3a9b3366dbea0ac52b24 + // TCRF SparklyPaper (Pathothingi) start - parallel world ticking + java.util.function.Consumer portalEntityTask = entity -> { + assert entity.portalProcess != null; -+ // Leaf start - Fix NPE when portalProcess becomes null before task execution ++ // Fix NPE when portalProcess becomes null before task execution ++ // Portal process was likely nulled out (e.g., expired) between scheduling and execution. + if (entity.portalProcess == null) { -+ // Portal process was likely nulled out (e.g., expired) between scheduling and execution. + return; + } -+ // Leaf end - Fix NPE + + if (entity.portalProcess.isParallelCancelledByPlugin()) { + entity.portalProcess = null; @@ -795,7 +794,7 @@ index 9bc978ca290ca772b0367e89b69fe16b502b0cd2..2f98d035b32d3a9b3366dbea0ac52b24 } else if (this.portalProcess.hasExpired()) { this.portalProcess = null; } -@@ -3908,6 +3934,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3908,6 +3933,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } private Entity teleportCrossDimension(ServerLevel level, TeleportTransition teleportTransition) { diff --git a/leaf-server/minecraft-patches/features/0150-Prevent-double-chunk-retrieving-in-entity-fluid-push.patch b/leaf-server/minecraft-patches/features/0150-Prevent-double-chunk-retrieving-in-entity-fluid-push.patch index 069ad7ae..0e910c03 100644 --- a/leaf-server/minecraft-patches/features/0150-Prevent-double-chunk-retrieving-in-entity-fluid-push.patch +++ b/leaf-server/minecraft-patches/features/0150-Prevent-double-chunk-retrieving-in-entity-fluid-push.patch @@ -11,10 +11,10 @@ As part of: Airplane (https://github.com/TECHNOVE/Airplane) Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 2f98d035b32d3a9b3366dbea0ac52b24d06dd373..90879616842cc61d15854b07f56f6fcb89f11074 100644 +index 334a47659ba75fade062bc79df3731d1e449114b..0903508d2cd3c78602e62dbcff4aa70285bc4c4f 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java -@@ -4622,10 +4622,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4621,10 +4621,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess // Paper start - optimise collisions public boolean updateFluidHeightAndDoFluidPushing(final TagKey fluid, final double flowScale) { @@ -26,7 +26,7 @@ index 2f98d035b32d3a9b3366dbea0ac52b24d06dd373..90879616842cc61d15854b07f56f6fcb final AABB boundingBox = this.getBoundingBox().deflate(1.0E-3); final Level world = this.level; -@@ -4661,7 +4658,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4660,7 +4657,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) { diff --git a/leaf-server/minecraft-patches/features/0153-Replace-ConcurrentLong2ReferenceChainedHashTable-wit.patch b/leaf-server/minecraft-patches/features/0153-Replace-ConcurrentLong2ReferenceChainedHashTable-wit.patch index 209b1f89..a0b98b40 100644 --- a/leaf-server/minecraft-patches/features/0153-Replace-ConcurrentLong2ReferenceChainedHashTable-wit.patch +++ b/leaf-server/minecraft-patches/features/0153-Replace-ConcurrentLong2ReferenceChainedHashTable-wit.patch @@ -6,7 +6,7 @@ Subject: [PATCH] Replace ConcurrentLong2ReferenceChainedHashTable with custom diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java b/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java -index 7eafc5b7cba23d8dec92ecc1050afe3fd8c9e309..7a299490d502147ddfd533637da36ea0d2ac918a 100644 +index 7eafc5b7cba23d8dec92ecc1050afe3fd8c9e309..9b421f0681fe740520457951b1a1632ada59438a 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java @@ -16,7 +16,7 @@ public final class ChunkUnloadQueue { @@ -14,61 +14,58 @@ index 7eafc5b7cba23d8dec92ecc1050afe3fd8c9e309..7a299490d502147ddfd533637da36ea0 public final int coordinateShift; private final AtomicLong orderGenerator = new AtomicLong(); - private final ConcurrentLong2ReferenceChainedHashTable unloadSections = new ConcurrentLong2ReferenceChainedHashTable<>(); -+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable unloadSections = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); ++ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable unloadSections = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map /* * Note: write operations do not occur in parallel for any given section. -@@ -32,8 +32,8 @@ public final class ChunkUnloadQueue { +@@ -32,8 +32,10 @@ public final class ChunkUnloadQueue { public List retrieveForAllRegions() { final List ret = new ArrayList<>(); - for (final Iterator> iterator = this.unloadSections.entryIterator(); iterator.hasNext();) { - final ConcurrentLong2ReferenceChainedHashTable.TableEntry entry = iterator.next(); ++ // Leaf start - Replace ConcurrentLong2ReferenceChainedHashTable with custom map + for (final Iterator> iterator = this.unloadSections.entryIterator(); iterator.hasNext(); ) { + final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.TableEntry entry = iterator.next(); ++ // Leaf end - Replace ConcurrentLong2ReferenceChainedHashTable with custom map final long key = entry.getKey(); final UnloadSection section = entry.getValue(); final int sectionX = CoordinateUtils.getChunkX(key); -@@ -141,4 +141,4 @@ public final class ChunkUnloadQueue { - this.order = order; - } - } --} -\ No newline at end of file -+} diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -index 06ac3537f5655d048d770bb004243f207fad9faa..647354efeb18694ac56a542bf4a88be61136f6a8 100644 +index 06ac3537f5655d048d770bb004243f207fad9faa..e399fa14e4a28b4fd93d06c603fd70b6fadeb6b0 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -@@ -71,11 +71,11 @@ public final class ChunkHolderManager { +@@ -71,11 +71,13 @@ public final class ChunkHolderManager { private static final long PROBE_MARKER = Long.MIN_VALUE + 1; public final ReentrantAreaLock ticketLockArea; - private final ConcurrentLong2ReferenceChainedHashTable>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>(); - private final ConcurrentLong2ReferenceChainedHashTable sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>(); ++ // Leaf start - Replace ConcurrentLong2ReferenceChainedHashTable with custom map + private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable>> tickets = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); + private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable sectionToChunkToExpireCount = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); ++ // Leaf end - Replace ConcurrentLong2ReferenceChainedHashTable with custom map final ChunkUnloadQueue unloadQueue; - private final ConcurrentLong2ReferenceChainedHashTable chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f); -+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable chunkHolders = org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f); ++ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable chunkHolders = org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map private final ServerLevel world; private final ChunkTaskScheduler taskScheduler; private long currentTick; -@@ -1422,9 +1422,9 @@ public final class ChunkHolderManager { +@@ -1422,9 +1424,9 @@ public final class ChunkHolderManager { final JsonArray allTicketsJson = new JsonArray(); ret.add("tickets", allTicketsJson); - for (final Iterator>>> iterator = this.tickets.entryIterator(); -+ for (final Iterator>>> iterator = this.tickets.entryIterator(); ++ for (final Iterator>>> iterator = this.tickets.entryIterator(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map iterator.hasNext();) { - final ConcurrentLong2ReferenceChainedHashTable.TableEntry>> coordinateTickets = iterator.next(); -+ final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.TableEntry>> coordinateTickets = iterator.next(); ++ final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable.TableEntry>> coordinateTickets = iterator.next(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map final long coordinate = coordinateTickets.getKey(); final SortedArraySet> tickets = coordinateTickets.getValue(); diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java -index 310a8f80debadd64c2d962ebf83b7d0505ce6e42..01598347ea545f2ff2ac337086345d7369a64520 100644 +index 310a8f80debadd64c2d962ebf83b7d0505ce6e42..3a7fad46465cac8d2c1b0933b457f5b075586709 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java @@ -35,11 +35,11 @@ public abstract class ThreadedTicketLevelPropagator { @@ -76,17 +73,17 @@ index 310a8f80debadd64c2d962ebf83b7d0505ce6e42..01598347ea545f2ff2ac337086345d73 private final UpdateQueue updateQueue; - private final ConcurrentLong2ReferenceChainedHashTable
sections; -+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable
sections; ++ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable
sections; // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map public ThreadedTicketLevelPropagator() { this.updateQueue = new UpdateQueue(); - this.sections = new ConcurrentLong2ReferenceChainedHashTable<>(); -+ this.sections = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); ++ this.sections = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map } // must hold ticket lock for: diff --git a/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java b/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java -index 1487b7d8be435b3fbad2aabd05796965b4775a87..a1459e3bc2076575e3f52d9e2b7d49630afeb799 100644 +index 1487b7d8be435b3fbad2aabd05796965b4775a87..57a702bafb36858979427809f8ae4fc1b001c8d6 100644 --- a/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java +++ b/ca/spottedleaf/moonrise/patches/starlight/light/StarLightInterface.java @@ -740,7 +740,7 @@ public final class StarLightInterface { @@ -94,12 +91,12 @@ index 1487b7d8be435b3fbad2aabd05796965b4775a87..a1459e3bc2076575e3f52d9e2b7d4963 public static final class ServerLightQueue extends LightQueue { - private final ConcurrentLong2ReferenceChainedHashTable chunkTasks = new ConcurrentLong2ReferenceChainedHashTable<>(); -+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable chunkTasks = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); ++ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable chunkTasks = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map public ServerLightQueue(final StarLightInterface lightInterface) { super(lightInterface); diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index b1f1b596a597d559aa672a3cb46a03917ad746af..d75f85208da0c7424fc95ae0d8ebb0a725dda0a7 100644 +index b1f1b596a597d559aa672a3cb46a03917ad746af..0860a700106e8c1afe58c77150a0f3aee8393fdd 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -72,7 +72,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -107,7 +104,7 @@ index b1f1b596a597d559aa672a3cb46a03917ad746af..d75f85208da0c7424fc95ae0d8ebb0a7 private NaturalSpawner.SpawnState lastSpawnState; // Paper start - private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>(); -+ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable fullChunks = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); ++ private final org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable fullChunks = new org.dreeam.leaf.util.map.spottedleaf.LeafConcurrentLong2ReferenceChainedHashTable<>(); // Leaf - Replace ConcurrentLong2ReferenceChainedHashTable with custom map public int getFullChunksCount() { return this.fullChunks.size(); } diff --git a/leaf-server/minecraft-patches/features/0154-Async-target-finding.patch b/leaf-server/minecraft-patches/features/0154-Async-target-finding.patch index 63d3116c..7d340622 100644 --- a/leaf-server/minecraft-patches/features/0154-Async-target-finding.patch +++ b/leaf-server/minecraft-patches/features/0154-Async-target-finding.patch @@ -32,16 +32,18 @@ index 24926aa7ed5c78b235659daf18b224b14beb744c..98af1ad020a003db66d7319f33d43dee public String getLocalIp() { diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 33dd16a26edd2974f04d9a868d3e58e8e3060032..0817ad4e16d8858b7d92e028d551e9184f357eb6 100644 +index 33dd16a26edd2974f04d9a868d3e58e8e3060032..eb0589b203bcf72cd24bb37f2c448c23cb8d6f2b 100644 --- a/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -255,6 +255,9 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -255,6 +255,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface DedicatedServer.LOGGER.info("Using " + serverLevelTickingSemaphore.availablePermits() + " permits for parallel world ticking"); // SparklyPaper - parallel world ticking } // Leaf end - SparklyPaper - parallel world ticking mod (make configurable) ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { + asyncGoalThread = new org.dreeam.leaf.async.ai.AsyncGoalThread(this); + } ++ // Leaf end - Async target finding com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now // Gale start - Pufferfish - SIMD support @@ -134,80 +136,85 @@ index 90bdcd168ad5b1a940f81b191bd59a34d3a33070..fbfb35dad8b07c31f967d33fb04cfcfc // Paper start - log detailed entity tick information diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 90879616842cc61d15854b07f56f6fcb89f11074..f114a8f5143799d72e36e0a535888c5fb25213e1 100644 +index 0903508d2cd3c78602e62dbcff4aa70285bc4c4f..e99fd55a90c68cc96701e5291219d1d056ed266b 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -243,6 +243,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess protected Vec3 stuckSpeedMultiplier = Vec3.ZERO; @Nullable private Entity.RemovalReason removalReason; -+ private volatile boolean isRemoved = false; // Leaf - volatile removal check ++ private volatile boolean isRemoved = false; // Leaf - Async target finding - volatile removal check public static final float DEFAULT_BB_WIDTH = 0.6F; public static final float DEFAULT_BB_HEIGHT = 1.8F; public float moveDist; -@@ -5036,7 +5037,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -5035,7 +5036,14 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public final boolean isRemoved() { - return this.removalReason != null; -+ // Leaf start - volatile removal check ++ // Leaf start - Async target finding ++ // Volatile removal check + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { + return this.isRemoved; + } else { + return this.removalReason != null; + } -+ // Leaf end - volatile removal check ++ // Leaf end - Async target finding } @Nullable -@@ -5063,6 +5070,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -5062,6 +5070,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers if (this.removalReason == null) { this.removalReason = removalReason; -+ // Leaf start - volatile removal check ++ // Leaf start - Async target finding ++ // Volatile removal check + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled && this.removalReason != null) { + this.isRemoved = true; + } -+ // Leaf end - volatile removal check ++ // Leaf end - Async target finding } if (this.removalReason.shouldDestroy()) { -@@ -5082,6 +5094,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -5081,6 +5095,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public void unsetRemoved() { this.removalReason = null; -+ // Leaf start - volatile removal check ++ // Leaf start - Async target finding ++ // Volatile removal check + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { + this.isRemoved = false; + } -+ // Leaf end - volatile removal check ++ // Leaf end - Async target finding } // Paper start - Folia schedulers diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java -index 05d5cde42b7011091ef4ee874c0d9d5586ae3f10..bf021604e0c345ef72cbc55d4f8fe996d2d561f7 100644 +index 05d5cde42b7011091ef4ee874c0d9d5586ae3f10..7b4330c15a2bdf63882c4ed025f2b426592a9bba 100644 --- a/net/minecraft/world/entity/Mob.java +++ b/net/minecraft/world/entity/Mob.java -@@ -144,6 +144,10 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab +@@ -144,6 +144,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab private float restrictRadius = -1.0F; public boolean aware = true; // CraftBukkit public int ticksSinceLastInteraction; // Purpur - Entity lifespan -+ public boolean tickingTarget; // Leaf - Async target finding ++ // Leaf start - Async target finding ++ public boolean tickingTarget; + public final org.dreeam.leaf.async.ai.Waker getGoalCtx() { + return tickingTarget ? this.targetSelector.ctx : this.goalSelector.ctx; + } ++ // Leaf end - Async target finding protected Mob(EntityType entityType, Level level) { super(entityType, level); -@@ -225,12 +229,21 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab +@@ -225,12 +231,21 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab } // Paper end - Skip AI during inactive ticks for non-aware mobs boolean isThrottled = org.dreeam.leaf.config.modules.opt.ThrottleInactiveGoalSelectorTick.enabled && _pufferfish_inactiveTickDisableCounter++ % 20 != 0; // Pufferfish - throttle inactive goal selector ticking -+ this.tickingTarget = false; // Leaf ++ this.tickingTarget = false; // Leaf - Async target finding if (this.goalSelector.inactiveTick(this.activatedPriority, true) && !isThrottled) { // Pufferfish - pass activated priroity // Pufferfish - throttle inactive goal selector ticking this.goalSelector.tick(); } -+ this.tickingTarget = true; // Leaf ++ this.tickingTarget = true; // Leaf - Async target finding if (this.targetSelector.inactiveTick(this.activatedPriority, true)) { // Pufferfish - pass activated priority this.targetSelector.tick(); } @@ -217,11 +224,11 @@ index 05d5cde42b7011091ef4ee874c0d9d5586ae3f10..bf021604e0c345ef72cbc55d4f8fe996 + ((ServerLevel) this.level()).asyncGoalExecutor.submit(this.getId()); + } + } -+ // Leaf start - Async target finding ++ // Leaf end - Async target finding } // Paper end -@@ -914,17 +927,28 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab +@@ -914,17 +929,28 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab // Paper end - Allow nerfed mobs to jump and float this.sensing.tick(); int i = this.tickCount + this.getId(); @@ -251,22 +258,13 @@ index 05d5cde42b7011091ef4ee874c0d9d5586ae3f10..bf021604e0c345ef72cbc55d4f8fe996 this.navigation.tick(); this.customServerAiStep((ServerLevel)this.level()); diff --git a/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java b/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java -index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..5239f4dfeaed8adccceb2a6d6578308261f46628 100644 +index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..776f18287b6b431b6b33d370b124825798cf103a 100644 --- a/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java +++ b/net/minecraft/world/entity/ai/goal/AvoidEntityGoal.java @@ -67,15 +67,24 @@ public class AvoidEntityGoal extends Goal { @Override public boolean canUse() { -- this.toAvoid = getServerLevel(this.mob) -- .getNearestEntity( -- this.mob.level().getEntitiesOfClass(this.avoidClass, this.mob.getBoundingBox().inflate(this.maxDist, 3.0, this.maxDist), livingEntity -> true), -- this.avoidEntityTargeting, -- this.mob, -- this.mob.getX(), -- this.mob.getY(), -- this.mob.getZ() -- ); + // Leaf start - Async Avoid Entity Finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + if (!poll()) { @@ -274,32 +272,31 @@ index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..5239f4dfeaed8adccceb2a6d65783082 + return false; + } + } else { -+ this.toAvoid = getServerLevel(this.mob) -+ .getNearestEntity( -+ this.mob.level().getEntitiesOfClass(this.avoidClass, this.mob.getBoundingBox().inflate(this.maxDist, 3.0, this.maxDist), livingEntity -> true), -+ this.avoidEntityTargeting, -+ this.mob, -+ this.mob.getX(), -+ this.mob.getEyeY(), -+ this.mob.getZ() -+ ); + this.toAvoid = getServerLevel(this.mob) + .getNearestEntity( + this.mob.level().getEntitiesOfClass(this.avoidClass, this.mob.getBoundingBox().inflate(this.maxDist, 3.0, this.maxDist), livingEntity -> true), + this.avoidEntityTargeting, + this.mob, + this.mob.getX(), +- this.mob.getY(), ++ this.mob.getEyeY(), // Leaf - Async Avoid Entity Finding + this.mob.getZ() + ); + } + // Leaf end - Async Avoid Entity Finding if (this.toAvoid == null) { return false; } else { -@@ -91,6 +100,47 @@ public class AvoidEntityGoal extends Goal { +@@ -91,6 +100,45 @@ public class AvoidEntityGoal extends Goal { } } + // Leaf start - Async Avoid Entity Finding + private boolean poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity entity)) { return false; } ++ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + var serverLevel = getServerLevel(this.mob); -+ if (serverLevel == null || !entity.isAlive() || !this.avoidEntityTargeting.test(serverLevel, this.mob, entity)) { -+ return false; -+ } -+ this.toAvoid = (T) entity; ++ if (serverLevel == null || !target.isAlive() || !this.avoidEntityTargeting.test(serverLevel, this.mob, target)) return false; ++ this.toAvoid = (T) target; + return true; + } + @@ -337,24 +334,20 @@ index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..5239f4dfeaed8adccceb2a6d65783082 public boolean canContinueToUse() { return !this.pathNav.isDone(); diff --git a/net/minecraft/world/entity/ai/goal/BegGoal.java b/net/minecraft/world/entity/ai/goal/BegGoal.java -index 28ef40e8a645989ea181297069cf2bbe571f3082..5f1a0ccaed29324a24bfbea96c9dc3adfeb11ad5 100644 +index 28ef40e8a645989ea181297069cf2bbe571f3082..4db188a08c1d13f77fb268ba03ac5d7fb9b71ad0 100644 --- a/net/minecraft/world/entity/ai/goal/BegGoal.java +++ b/net/minecraft/world/entity/ai/goal/BegGoal.java -@@ -27,8 +27,54 @@ public class BegGoal extends Goal { +@@ -27,8 +27,50 @@ public class BegGoal extends Goal { this.setFlags(EnumSet.of(Goal.Flag.LOOK)); } + // Leaf start - Async Target Finding + protected boolean poll() { -+ if (!(this.wolf.getGoalCtx().result() instanceof Player t)) { return false; } -+ if (t == null) { -+ return false; -+ } ++ if (!(this.wolf.getGoalCtx().result() instanceof Player target)) return false; ++ if (target == null) return false; + ServerLevel serverLevel = getServerLevel(this.wolf); -+ if (serverLevel == null || !t.isAlive() || !playerHoldingInteresting(t)) { -+ return false; -+ } -+ this.player = t; ++ if (serverLevel == null || !target.isAlive() || !playerHoldingInteresting(target)) return false; ++ this.player = target; + return true; + } + @@ -395,35 +388,29 @@ index 28ef40e8a645989ea181297069cf2bbe571f3082..5f1a0ccaed29324a24bfbea96c9dc3ad this.player = this.level.getNearestPlayer(this.begTargeting, this.wolf); return this.player != null && this.playerHoldingInteresting(this.player); } -@@ -59,14 +105,16 @@ public class BegGoal extends Goal { +@@ -59,10 +101,10 @@ public class BegGoal extends Goal { this.lookTime--; } - private boolean playerHoldingInteresting(Player player) { -+ // Leaf start - static -+ private static boolean playerHoldingInteresting(Player player) { ++ private static boolean playerHoldingInteresting(Player player) { // Leaf start - Async Target Finding - static for (InteractionHand interactionHand : InteractionHand.values()) { ItemStack itemInHand = player.getItemInHand(interactionHand); - if (itemInHand.is(Items.BONE) || this.wolf.isFood(itemInHand)) { -+ if (itemInHand.is(Items.BONE) || itemInHand.is(net.minecraft.tags.ItemTags.WOLF_FOOD)) { ++ if (itemInHand.is(Items.BONE) || itemInHand.is(net.minecraft.tags.ItemTags.WOLF_FOOD)) { // Leaf end - Async Target Finding return true; } } - - return false; - } -+ // Leaf end - static - } diff --git a/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java b/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java -index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..d26bebdc66bf30a30fba5c1ba70e71479aff68a1 100644 +index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..b3205c9f35687bc37124876198ec2d657ccaa96c 100644 --- a/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java +++ b/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java -@@ -52,6 +52,14 @@ public class CatLieOnBedGoal extends MoveToBlockGoal { +@@ -52,6 +52,13 @@ public class CatLieOnBedGoal extends MoveToBlockGoal { @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { -+ // Leaf - Async search block - return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(BlockTags.BEDS); +- return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(BlockTags.BEDS); ++ return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(BlockTags.BEDS); // Leaf - Async search block - diff on change } + + // Leaf start - Async search block @@ -434,22 +421,22 @@ index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..d26bebdc66bf30a30fba5c1ba70e7147 + // Leaf end - Async search block } diff --git a/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java b/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java -index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..b0a93215a7d5e8fe58331f261d7b4f87852cd4b2 100644 +index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..057090e3134048e75dbaefb703e8f2d35a172a3b 100644 --- a/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/CatSitOnBlockGoal.java -@@ -44,9 +44,11 @@ public class CatSitOnBlockGoal extends MoveToBlockGoal { +@@ -44,14 +44,21 @@ public class CatSitOnBlockGoal extends MoveToBlockGoal { @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { -+ // Leaf - Async search block - if (!level.isEmptyBlock(pos.above())) { +- if (!level.isEmptyBlock(pos.above())) { ++ if (!level.isEmptyBlock(pos.above())) { // Leaf - Async search block - diff on change return false; } else { -+ // Leaf - Async search block - BlockState blockState = level.getBlockState(pos); +- BlockState blockState = level.getBlockState(pos); ++ BlockState blockState = level.getBlockState(pos); // Leaf - Async search block - diff on change return blockState.is(Blocks.CHEST) ? ChestBlockEntity.getOpenCount(level, pos) < 1 -@@ -54,4 +56,11 @@ public class CatSitOnBlockGoal extends MoveToBlockGoal { + : blockState.is(Blocks.FURNACE) && blockState.getValue(FurnaceBlock.LIT) || blockState.is(BlockTags.BEDS, state -> state.getOptionalValue(BedBlock.PART).map(bedPart -> bedPart != BedPart.HEAD).orElse(true)); } } @@ -462,7 +449,7 @@ index 9954f49bc364969c7ccb37f4186fa2ab8710f6ae..b0a93215a7d5e8fe58331f261d7b4f87 + // Leaf end - Async search block } diff --git a/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java b/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java -index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..ec52e6c8110876eb915485c54a8102c4afe460f6 100644 +index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..2d2ffa9e89f4954e096c48cba96db995a92433e5 100644 --- a/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowBoatGoal.java @@ -23,8 +23,54 @@ public class FollowBoatGoal extends Goal { @@ -471,9 +458,9 @@ index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..ec52e6c8110876eb915485c54a8102c4 + // Leaf start - Async Target Finding + private boolean poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof Player t)) { return false; } ++ if (!(this.mob.getGoalCtx().result() instanceof Player target)) return false; + var serverLevel = getServerLevel(this.mob); -+ return serverLevel != null && t.isAlive() && !t.isSpectator() && (Mth.abs(t.xxa) > 0.0F || Mth.abs(t.zza) > 0.0F); ++ return serverLevel != null && target.isAlive() && !target.isSpectator() && (Mth.abs(target.xxa) > 0.0F || Mth.abs(target.zza) > 0.0F); + } + + private void findTargetAsync() { @@ -525,12 +512,12 @@ index 1fe4d1877ed52017d4d22ddb9b77f78e2b93dff9..ec52e6c8110876eb915485c54a8102c4 } - return this.following != null && (Mth.abs(this.following.xxa) > 0.0F || Mth.abs(this.following.zza) > 0.0F) || flag; -+ return flag; // Leaf - move above ++ return flag; // Leaf - Async Target Finding - move above } @Override diff --git a/net/minecraft/world/entity/ai/goal/FollowMobGoal.java b/net/minecraft/world/entity/ai/goal/FollowMobGoal.java -index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..0d123e6bac5748b6c5efd76f4c1e086cbf749783 100644 +index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..911ceddb4ded974a02355c76e5d4133632ae4487 100644 --- a/net/minecraft/world/entity/ai/goal/FollowMobGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowMobGoal.java @@ -38,6 +38,15 @@ public class FollowMobGoal extends Goal { @@ -549,18 +536,16 @@ index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..0d123e6bac5748b6c5efd76f4c1e086c List entitiesOfClass = this.mob.level().getEntitiesOfClass(Mob.class, this.mob.getBoundingBox().inflate(this.areaSize), this.followPredicate); if (!entitiesOfClass.isEmpty()) { for (Mob mob : entitiesOfClass) { -@@ -51,6 +60,45 @@ public class FollowMobGoal extends Goal { +@@ -51,6 +60,43 @@ public class FollowMobGoal extends Goal { return false; } + // Leaf start - Async Follow Mob Finding + private boolean poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof Mob t)) { return false; } ++ if (!(this.mob.getGoalCtx().result() instanceof Mob target)) return false; + var serverLevel = getServerLevel(this.mob); -+ if (serverLevel == null || !t.isAlive() || t.isInvisible()) { -+ return false; -+ } -+ this.followingMob = t; ++ if (serverLevel == null || !target.isAlive() || target.isInvisible()) return false; ++ this.followingMob = target; + return true; + } + @@ -596,20 +581,18 @@ index c9cf985173d3da9e84ce178f161e2fd5fb8ce472..0d123e6bac5748b6c5efd76f4c1e086c public boolean canContinueToUse() { return this.followingMob != null && !this.navigation.isDone() && this.mob.distanceToSqr(this.followingMob) > this.stopDistance * this.stopDistance; diff --git a/net/minecraft/world/entity/ai/goal/FollowParentGoal.java b/net/minecraft/world/entity/ai/goal/FollowParentGoal.java -index 3093f03d4f298bf39fec8bad2b6c22518774aea8..ee42674761653cacc5045fcb60e314fbe25f390f 100644 +index 3093f03d4f298bf39fec8bad2b6c22518774aea8..80f9de7b2c03c1477dae0f42b328e0100f78e58b 100644 --- a/net/minecraft/world/entity/ai/goal/FollowParentGoal.java +++ b/net/minecraft/world/entity/ai/goal/FollowParentGoal.java -@@ -19,11 +19,68 @@ public class FollowParentGoal extends Goal { +@@ -19,11 +19,66 @@ public class FollowParentGoal extends Goal { this.speedModifier = speedModifier; } + // Leaf start - Async Target Finding + protected boolean poll() { -+ if (!(this.animal.getGoalCtx().result() instanceof Animal t)) { return false; } ++ if (!(this.animal.getGoalCtx().result() instanceof Animal target)) return false; + var serverLevel = getServerLevel(animal); -+ if (serverLevel == null || !t.isAlive() || animal.distanceToSqr(t) < 9.0) { -+ return false; -+ } ++ if (serverLevel == null || !target.isAlive() || animal.distanceToSqr(target) < 9.0) return false; + this.parent = animal; + return true; + } @@ -668,16 +651,16 @@ index 3093f03d4f298bf39fec8bad2b6c22518774aea8..ee42674761653cacc5045fcb60e314fb List entitiesOfClass = this.animal .level() .getEntitiesOfClass((Class)this.animal.getClass(), this.animal.getBoundingBox().inflate(8.0, 4.0, 8.0)); -@@ -43,6 +100,7 @@ public class FollowParentGoal extends Goal { +@@ -43,6 +98,7 @@ public class FollowParentGoal extends Goal { if (animal == null) { return false; } else if (d < 9.0) { -+ // Leaf - Async Target Finding ++ // Leaf - Async Target Finding - diff on change return false; } else { this.parent = animal; diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java -index e82e32407cec6109b9c3b0106295217f4a3f4aa2..32463fae3d3a58e71c4aae2d81b2a1b60fee7d69 100644 +index e82e32407cec6109b9c3b0106295217f4a3f4aa2..ec56b4e8acd2dad23a94b1fe9145e6256da54493 100644 --- a/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java @@ -26,6 +26,13 @@ public class GoalSelector { @@ -694,10 +677,11 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..32463fae3d3a58e71c4aae2d81b2a1b6 public void addGoal(int priority, Goal goal) { this.availableGoals.add(new WrappedGoal(priority, goal)); } -@@ -85,7 +92,107 @@ public class GoalSelector { +@@ -85,7 +92,111 @@ public class GoalSelector { return true; } ++ // Leaf start - Async target finding + public final boolean poll() { + if (this.ctxGoals == null || ctx.wake != null) { + return false; @@ -790,42 +774,35 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..32463fae3d3a58e71c4aae2d81b2a1b6 + } + ctx.wake = null; + } ++ // Leaf end - Async target finding + public void tick() { ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { + if (this.ctxGoals == null) { + this.ctxGoals = this.availableGoals.toArray(new WrappedGoal[0]); + } + return; + } ++ // Leaf end - Async target finding + for (WrappedGoal wrappedGoal : this.availableGoals) { if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams wrappedGoal.stop(); -@@ -94,6 +201,7 @@ public class GoalSelector { - - this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning()); - -+ - for (WrappedGoal wrappedGoalx : this.availableGoals) { - // Paper start - if (!wrappedGoalx.isRunning() && !goalContainsAnyFlags(wrappedGoalx, this.goalTypes) && goalCanBeReplacedForAllFlags(wrappedGoalx, this.lockedFlags) && wrappedGoalx.canUse()) { diff --git a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -index be59d0c27a83b329ec3f97c029cfb9c114e22472..239567f1ac82e17ec8f0624f1a33c1faa7ad13fe 100644 +index be59d0c27a83b329ec3f97c029cfb9c114e22472..7c54964a5329e12a9a4a1fdb2417ccbd3f0bfae2 100644 --- a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java +++ b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java -@@ -20,19 +20,94 @@ public class LlamaFollowCaravanGoal extends Goal { +@@ -20,20 +20,93 @@ public class LlamaFollowCaravanGoal extends Goal { this.setFlags(EnumSet.of(Goal.Flag.MOVE)); } + // Leaf start - Async Target Finding + private @javax.annotation.Nullable Llama poll() { -+ if (!(this.llama.getGoalCtx().result() instanceof Llama t)) { return null; } ++ if (!(this.llama.getGoalCtx().result() instanceof Llama target)) return null; + var serverLevel = getServerLevel(this.llama); -+ if (serverLevel == null || !t.isAlive()) { -+ return null; -+ } -+ return t; ++ if (serverLevel == null || !target.isAlive()) return null; ++ return target; + } + + private void findTargetAsync() { @@ -849,7 +826,7 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..239567f1ac82e17ec8f0624f1a33c1fa + double d = Double.MAX_VALUE; + + for (Entity entity : entities) { -+ Llama llama1 = (Llama)entity; ++ Llama llama1 = (Llama) entity; + if (llama1.inCaravan() && !llama1.hasCaravanTail()) { + double d1 = llama1.distanceToSqr(pos); + if (!(d1 > d)) { @@ -861,7 +838,7 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..239567f1ac82e17ec8f0624f1a33c1fa + + if (target == null) { + for (Entity entityx : entities) { -+ Llama llama1 = (Llama)entityx; ++ Llama llama1 = (Llama) entityx; + if (llama1.isLeashed() && !llama1.hasCaravanTail()) { + double d1 = llama1.distanceToSqr(pos); + if (!(d1 > d)) { @@ -880,6 +857,7 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..239567f1ac82e17ec8f0624f1a33c1fa + }; + } + // Leaf end - Async Target Finding ++ @Override public boolean canUse() { if (!this.llama.level().purpurConfig.llamaJoinCaravans || !this.llama.shouldJoinCaravan) return false; // Purpur - Llama API // Purpur - Config to disable Llama caravans @@ -902,36 +880,38 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..239567f1ac82e17ec8f0624f1a33c1fa }); - Llama llama = null; - double d = Double.MAX_VALUE; -+ // Llama llama = null; // Leaf -+ // double d = Double.MAX_VALUE; // Leaf ++ // Llama llama = null; // Leaf - Async Target Finding ++ // double d = Double.MAX_VALUE; // Leaf - Async Target Finding for (Entity entity : entities) { Llama llama1 = (Llama)entity; -+ // Leaf - Async Target Finding - if (llama1.inCaravan() && !llama1.hasCaravanTail()) { +- if (llama1.inCaravan() && !llama1.hasCaravanTail()) { ++ if (llama1.inCaravan() && !llama1.hasCaravanTail()) { // Leaf - Async Target Finding - diff on change double d1 = this.llama.distanceToSqr(llama1); if (!(d1 > d)) { -@@ -45,6 +120,7 @@ public class LlamaFollowCaravanGoal extends Goal { + d = d1; +@@ -45,7 +118,7 @@ public class LlamaFollowCaravanGoal extends Goal { if (llama == null) { for (Entity entityx : entities) { Llama llama1 = (Llama)entityx; -+ // Leaf - Async Target Finding - if (llama1.isLeashed() && !llama1.hasCaravanTail()) { +- if (llama1.isLeashed() && !llama1.hasCaravanTail()) { ++ if (llama1.isLeashed() && !llama1.hasCaravanTail()) { // Leaf - Async Target Finding - diff on change double d1 = this.llama.distanceToSqr(llama1); if (!(d1 > d)) { -@@ -54,6 +130,7 @@ public class LlamaFollowCaravanGoal extends Goal { + d = d1; +@@ -54,6 +127,7 @@ public class LlamaFollowCaravanGoal extends Goal { } } } -+ } // Leaf ++ } // Leaf - Async Target Finding if (llama == null) { return false; diff --git a/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java b/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java -index 6463c3c9b08d6058f2843c225b08a40fc30a960b..819f7947b0c9c546cf45b2effe72cfb597a99ce6 100644 +index 6463c3c9b08d6058f2843c225b08a40fc30a960b..0afad8ddb0e9d083d47b96627d999f0ee28b9446 100644 --- a/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java +++ b/net/minecraft/world/entity/ai/goal/LookAtPlayerGoal.java -@@ -48,32 +48,94 @@ public class LookAtPlayerGoal extends Goal { +@@ -48,32 +48,87 @@ public class LookAtPlayerGoal extends Goal { @Override public boolean canUse() { @@ -939,19 +919,16 @@ index 6463c3c9b08d6058f2843c225b08a40fc30a960b..819f7947b0c9c546cf45b2effe72cfb5 + if (poll()) { + return true; + } -+ if (this.mob.getRandom().nextFloat() >= this.probability) { return false; + } + if (this.mob.getTarget() != null) { + this.lookAt = this.mob.getTarget(); + } -+ + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { + getLookAsync(); + return false; + } -+ + ServerLevel serverLevel = getServerLevel(this.mob); + if (this.lookAtType == Player.class) { + this.lookAt = serverLevel.getNearestPlayer(this.lookAtContext, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ()); @@ -987,22 +964,18 @@ index 6463c3c9b08d6058f2843c225b08a40fc30a960b..819f7947b0c9c546cf45b2effe72cfb5 - ); - } + return this.lookAt != null; -+ // Leaf end - Async look finding + } - return this.lookAt != null; -+ // Leaf start - Async look finding + protected boolean poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity t)) { return false; } ++ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + if (this.mob.getTarget() != null) { + this.lookAt = this.mob.getTarget(); + return true; -+ } -+ ServerLevel serverLevel = getServerLevel(this.mob); -+ if (!t.isAlive() || !this.lookAtContext.test(serverLevel, this.mob, t)) { -+ return false; } -+ this.lookAt = t; ++ ServerLevel serverLevel = getServerLevel(this.mob); ++ if (!target.isAlive() || !this.lookAtContext.test(serverLevel, this.mob, target)) return false; ++ this.lookAt = target; + return true; + } + @@ -1046,7 +1019,7 @@ index 6463c3c9b08d6058f2843c225b08a40fc30a960b..819f7947b0c9c546cf45b2effe72cfb5 @Override public boolean canContinueToUse() { diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java -index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..99e6e7bac2b5af1b1abb1de6b51aed1f44e5e8b0 100644 +index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..292749c786b85f86fa5f65c49fa83539fd0603b4 100644 --- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java @@ -41,8 +41,69 @@ public abstract class MoveToBlockGoal extends Goal { @@ -1055,7 +1028,7 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..99e6e7bac2b5af1b1abb1de6b51aed1f + // Leaf start - Async search block + protected boolean poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof BlockPos blockPos1)) { return false; } ++ if (!(this.mob.getGoalCtx().result() instanceof BlockPos blockPos1)) return false; + if (!this.mob.level().hasChunkAt(blockPos1) + || !this.mob.isWithinRestriction(blockPos1) + || !this.isValidTarget(this.mob.level(), blockPos1)) { @@ -1119,21 +1092,24 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..99e6e7bac2b5af1b1abb1de6b51aed1f if (this.nextStartTick > 0) { this.nextStartTick--; return false; -@@ -109,6 +170,10 @@ public abstract class MoveToBlockGoal extends Goal { +@@ -109,6 +170,12 @@ public abstract class MoveToBlockGoal extends Goal { } protected boolean findNearestBlock() { ++ // Leaf start - Async search block + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchBlock) { + getBlockAsync(); + return false; + } ++ // Leaf end - Async search block int i = this.searchRange; int i1 = this.verticalSearchRange; BlockPos blockPos = this.mob.blockPosition(); -@@ -133,5 +198,104 @@ public abstract class MoveToBlockGoal extends Goal { +@@ -133,5 +200,108 @@ public abstract class MoveToBlockGoal extends Goal { return false; } ++ // Leaf start - Async search block + protected static boolean findNearestBlockAsync( + final org.dreeam.leaf.async.ai.Waker ctx, + final TypeToCheck ty, @@ -1170,19 +1146,21 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..99e6e7bac2b5af1b1abb1de6b51aed1f + private static boolean isWithinRestriction(float restrictRadius, BlockPos restrictCenter, BlockPos pos) { + return restrictRadius == -1.0F || restrictCenter.distSqr(pos) < restrictRadius * restrictRadius; + } ++ // Leaf end - Async search block + protected abstract boolean isValidTarget(LevelReader level, BlockPos pos); + ++ // Leaf start - Async search block + protected abstract TypeToCheck typeToCheck(); + + private static boolean isValidTargetAsync( -+ TypeToCheck ty, ++ TypeToCheck type, + @org.jetbrains.annotations.Nullable net.minecraft.world.level.block.Block blockToRemoveTy, + PathfinderMob mob, + LevelReader level, + BlockPos pos + ) { -+ switch (ty) { ++ switch (type) { + case CatLie -> { + return level.isEmptyBlock(pos.above()) && level.getBlockState(pos).is(net.minecraft.tags.BlockTags.BEDS); + } @@ -1233,10 +1211,11 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..99e6e7bac2b5af1b1abb1de6b51aed1f + } + case null -> throw new IllegalStateException(); + } ++ // Leaf end - Async search block + } } diff --git a/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java b/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java -index 3c274d917bca9de87abfb842f5f332e112a7a2d7..aa743d8f4ec0c1d78e5e58a7b5e36bca08b8b2ef 100644 +index 3c274d917bca9de87abfb842f5f332e112a7a2d7..e1d185b2f5e7eb7a00501ff85b4e16d3540066f4 100644 --- a/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java +++ b/net/minecraft/world/entity/ai/goal/OfferFlowerGoal.java @@ -19,10 +19,20 @@ public class OfferFlowerGoal extends Goal { @@ -1261,19 +1240,17 @@ index 3c274d917bca9de87abfb842f5f332e112a7a2d7..aa743d8f4ec0c1d78e5e58a7b5e36bca } else { this.villager = getServerLevel(this.golem) .getNearestEntity( -@@ -38,6 +48,47 @@ public class OfferFlowerGoal extends Goal { +@@ -38,6 +48,45 @@ public class OfferFlowerGoal extends Goal { } } + + // Leaf start - Async look finding + protected boolean poll() { -+ if (!(this.golem.getGoalCtx().result() instanceof Villager t)) { return false; } ++ if (!(this.golem.getGoalCtx().result() instanceof Villager target)) return false; + var serverLevel = getServerLevel(this.golem); -+ if (!t.isAlive() || !OFFER_TARGER_CONTEXT.test(serverLevel, this.golem, t)) { -+ return false; -+ } -+ this.villager = t; ++ if (!target.isAlive() || !OFFER_TARGER_CONTEXT.test(serverLevel, this.golem, target)) return false; ++ this.villager = target; + return true; + } + @@ -1310,18 +1287,9 @@ index 3c274d917bca9de87abfb842f5f332e112a7a2d7..aa743d8f4ec0c1d78e5e58a7b5e36bca public boolean canContinueToUse() { return this.tick > 0; diff --git a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -index 95fa516910a3834bbd4db6d11279e13a1f0dac41..f7ddae601abbe9e22a35c7cb4f9763e61fa7ff81 100644 +index c67a88c9c77ece7c85ffb169ac96da4f28291228..14d9b492ba431d534e0c6a567d0b7700b4c8a02d 100644 --- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java -@@ -22,7 +22,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; - import net.minecraft.world.phys.Vec3; - - public class RemoveBlockGoal extends MoveToBlockGoal { -- private final Block blockToRemove; -+ protected final Block blockToRemove; // Leaf - Async search block - private final Mob removerMob; - private int ticksSinceReachedGoal; - private static final int WAIT_AFTER_BLOCK_FOUND = 20; @@ -37,7 +37,14 @@ public class RemoveBlockGoal extends MoveToBlockGoal { public boolean canUse() { if (!getServerLevel(this.removerMob).purpurConfig.zombieBypassMobGriefing == !getServerLevel(this.removerMob).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { // Purpur - Add mobGriefing bypass to everything affected @@ -1338,14 +1306,12 @@ index 95fa516910a3834bbd4db6d11279e13a1f0dac41..f7ddae601abbe9e22a35c7cb4f9763e6 this.nextStartTick--; return false; } else if (this.findNearestBlock()) { -@@ -149,10 +156,18 @@ public class RemoveBlockGoal extends MoveToBlockGoal { - - @Override +@@ -151,8 +158,15 @@ public class RemoveBlockGoal extends MoveToBlockGoal { protected boolean isValidTarget(LevelReader level, BlockPos pos) { -+ // Leaf - Async search block ChunkAccess chunk = level.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); // Paper - Prevent AI rules from loading chunks return chunk != null - && chunk.getBlockState(pos).is(this.blockToRemove) +- && chunk.getBlockState(pos).is(this.blockToRemove) ++ && chunk.getBlockState(pos).is(this.blockToRemove) // Leaf - Async search block - diff on change && chunk.getBlockState(pos.above()).isAir() && chunk.getBlockState(pos.above(2)).isAir(); } @@ -1358,21 +1324,19 @@ index 95fa516910a3834bbd4db6d11279e13a1f0dac41..f7ddae601abbe9e22a35c7cb4f9763e6 + // Leaf end - Async search block } diff --git a/net/minecraft/world/entity/ai/goal/TemptGoal.java b/net/minecraft/world/entity/ai/goal/TemptGoal.java -index f88f618d34fb343b31de3af1a875d6633703df71..37aa00347e9cf391e447cff775e4493b36e05beb 100644 +index f88f618d34fb343b31de3af1a875d6633703df71..e42f77fc6d04a900fd8adb4682678f9218561aa8 100644 --- a/net/minecraft/world/entity/ai/goal/TemptGoal.java +++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java -@@ -36,12 +36,62 @@ public class TemptGoal extends Goal { +@@ -36,12 +36,60 @@ public class TemptGoal extends Goal { this.targetingConditions = TEMPT_TARGETING.copy().selector((entity, level) -> this.shouldFollow(entity)); } + // Leaf start - Async Tempt Finding + private boolean poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof Player t)) { return false; } ++ if (!(this.mob.getGoalCtx().result() instanceof Player target)) return false; + var serverLevel = getServerLevel(this.mob); -+ if (!t.isAlive() || !this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)).test(serverLevel, this.mob, t)) { -+ return false; -+ } -+ this.player = t; ++ if (!target.isAlive() || !this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)).test(serverLevel, this.mob, target)) return false; ++ this.player = target; + return true; + } + @@ -1425,7 +1389,7 @@ index f88f618d34fb343b31de3af1a875d6633703df71..37aa00347e9cf391e447cff775e4493b .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob); // CraftBukkit start diff --git a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java -index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..921418da5f026edad4c78ba51127bb758c34bb9a 100644 +index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..941131fd448216afe2bf46dc6aab1d4b95c586fc 100644 --- a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java @@ -16,7 +16,7 @@ public class DefendVillageTargetGoal extends TargetGoal { @@ -1433,26 +1397,21 @@ index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..921418da5f026edad4c78ba51127bb75 @Nullable private LivingEntity potentialTarget; - private final TargetingConditions attackTargeting = TargetingConditions.forCombat().range(64.0); -+ private static final TargetingConditions attackTargeting = TargetingConditions.forCombat().range(64.0); // Leaf - static ++ private static final TargetingConditions attackTargeting = TargetingConditions.forCombat().range(64.0); // Leaf - Async Target Finding - static public DefendVillageTargetGoal(IronGolem golem) { super(golem, false, true); -@@ -24,8 +24,63 @@ public class DefendVillageTargetGoal extends TargetGoal { +@@ -24,8 +24,58 @@ public class DefendVillageTargetGoal extends TargetGoal { this.setFlags(EnumSet.of(Goal.Flag.TARGET)); } + // Leaf start - Async Target Finding + protected boolean poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity t)) { return false; } ++ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + ServerLevel serverLevel = getServerLevel(this.mob); -+ if (serverLevel == null || !t.isAlive() || !attackTargeting.test(serverLevel, golem, t)) { -+ return false; -+ } -+ if ((t instanceof Player player && (player.isSpectator() || player.isCreative()))) { -+ return false; -+ } -+ this.potentialTarget = t; -+ ++ if (serverLevel == null || !target.isAlive() || !attackTargeting.test(serverLevel, golem, target)) return false; ++ if ((target instanceof Player player && (player.isSpectator() || player.isCreative()))) return false; ++ this.potentialTarget = target; + return true; + } + @@ -1501,16 +1460,17 @@ index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..921418da5f026edad4c78ba51127bb75 AABB aabb = this.golem.getBoundingBox().inflate(10.0, 8.0, 10.0); ServerLevel serverLevel = getServerLevel(this.golem); List nearbyEntities = serverLevel.getNearbyEntities(Villager.class, this.attackTargeting, this.golem, aabb); -@@ -42,6 +97,7 @@ public class DefendVillageTargetGoal extends TargetGoal { - } +@@ -43,7 +93,7 @@ public class DefendVillageTargetGoal extends TargetGoal { } -+ // Leaf - Async target finding return this.potentialTarget != null - && (!(this.potentialTarget instanceof Player) || !this.potentialTarget.isSpectator() && !((Player)this.potentialTarget).isCreative()); +- && (!(this.potentialTarget instanceof Player) || !this.potentialTarget.isSpectator() && !((Player)this.potentialTarget).isCreative()); ++ && (!(this.potentialTarget instanceof Player) || !this.potentialTarget.isSpectator() && !((Player)this.potentialTarget).isCreative()); // Leaf - Async target finding - diff on change } + + @Override diff --git a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java -index 25fe78116ce01eeefe5c958423734195d27302eb..e19f2cb98c9669deb3a19114264668fbb29d3cc5 100644 +index 25fe78116ce01eeefe5c958423734195d27302eb..6998e7a102b711152d78f4dc590812168dd24cd6 100644 --- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java @@ -73,6 +73,56 @@ public class HurtByTargetGoal extends TargetGoal { @@ -1518,7 +1478,7 @@ index 25fe78116ce01eeefe5c958423734195d27302eb..e19f2cb98c9669deb3a19114264668fb double followDistance = this.getFollowDistance(); AABB aabb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(followDistance, 10.0, followDistance); + -+ // Leaf start - async alert other ++ // Leaf start - Async alert other + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) { + final var self = this.mob; + final var ctx = self.getGoalCtx(); @@ -1565,59 +1525,59 @@ index 25fe78116ce01eeefe5c958423734195d27302eb..e19f2cb98c9669deb3a19114264668fb + }; + return; + } -+ // Leaf end - async alert other ++ // Leaf end - Async alert other + List entitiesOfClass = this.mob .level() .getEntitiesOfClass((Class)this.mob.getClass(), aabb, EntitySelector.NO_SPECTATORS); -@@ -86,6 +136,7 @@ public class HurtByTargetGoal extends TargetGoal { - } +@@ -87,7 +137,7 @@ public class HurtByTargetGoal extends TargetGoal { mob = (Mob)var5.next(); -+ // Leaf - async alert other if (this.mob != mob - && mob.getTarget() == null +- && mob.getTarget() == null ++ && mob.getTarget() == null // Leaf - Async alert other - diff on change && (!(this.mob instanceof TamableAnimal) || ((TamableAnimal)this.mob).getOwner() == ((TamableAnimal)mob).getOwner()) -@@ -96,6 +147,7 @@ public class HurtByTargetGoal extends TargetGoal { + && !mob.isAlliedTo(this.mob.getLastHurtByMob())) { + if (this.toIgnoreAlert == null) { +@@ -96,7 +146,7 @@ public class HurtByTargetGoal extends TargetGoal { boolean flag = false; -+ // Leaf - async alert other - for (Class clazz : this.toIgnoreAlert) { +- for (Class clazz : this.toIgnoreAlert) { ++ for (Class clazz : this.toIgnoreAlert) { // Leaf - Async alert other - diff on change if (mob.getClass() == clazz) { flag = true; -@@ -113,6 +165,15 @@ public class HurtByTargetGoal extends TargetGoal { + break; +@@ -113,6 +163,15 @@ public class HurtByTargetGoal extends TargetGoal { } } -+ // Leaf start - async alert other ++ // Leaf start - Async alert other + public void poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof List toAlert)) { return; } ++ if (!(this.mob.getGoalCtx().result() instanceof List toAlert)) return; + for (var livingEntity : toAlert) { + alertOther((Mob) livingEntity, this.mob.getLastHurtByMob()); + } + } -+ // Leaf end - async alert other ++ // Leaf end - Async alert other + protected void alertOther(Mob mob, LivingEntity target) { mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit - reason } diff --git a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java -index 41ee3cdc45ecc8376a2203ed588bb544ed377294..f07d0db481aecb8260c09eafef2c1cd582a8502c 100644 +index 85eae0a14f7a417dfd8c911079d05354a98e5834..3d0c28caa646286be79cefee4710b15f9aad928c 100644 --- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java -@@ -41,8 +41,53 @@ public class NearestAttackableTargetGoal extends TargetG +@@ -41,8 +41,51 @@ public class NearestAttackableTargetGoal extends TargetG this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(selector); } + // Leaf start - Async Target Finding + protected boolean poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity t)) { return false; } ++ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false; + ServerLevel serverLevel = getServerLevel(this.mob); -+ if (serverLevel == null || !t.isAlive() || !this.getTargetConditions().test(serverLevel, this.mob, t)) { -+ return false; -+ } -+ this.target = t; ++ if (serverLevel == null || !target.isAlive() || !this.getTargetConditions().test(serverLevel, this.mob, target)) return false; ++ this.target = target; + return true; + } + @@ -1660,7 +1620,7 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..f07d0db481aecb8260c09eafef2c1cd5 if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) { return false; } else { -@@ -57,6 +102,15 @@ public class NearestAttackableTargetGoal extends TargetG +@@ -57,6 +100,15 @@ public class NearestAttackableTargetGoal extends TargetG protected void findTarget() { ServerLevel serverLevel = getServerLevel(this.mob); @@ -1676,15 +1636,6 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..f07d0db481aecb8260c09eafef2c1cd5 if (this.targetType != Player.class && this.targetType != ServerPlayer.class) { this.target = serverLevel.getNearestEntity( this.mob.level().getEntitiesOfClass(this.targetType, this.getTargetSearchArea(this.getFollowDistance()), entity -> true), -@@ -81,7 +135,7 @@ public class NearestAttackableTargetGoal extends TargetG - this.target = target; - } - -- private TargetingConditions getTargetConditions() { -+ protected TargetingConditions getTargetConditions() { - return this.targetConditions.range(this.getFollowDistance()); - } - } diff --git a/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java index 4604a603c4ddd0a9242e859aaa5a511c2d4c4f84..7274dfb52ca4a08cdebcd04294cedc73460593e5 100644 --- a/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java @@ -1707,7 +1658,7 @@ index 4604a603c4ddd0a9242e859aaa5a511c2d4c4f84..7274dfb52ca4a08cdebcd04294cedc73 } else if (!((Raider)this.mob).hasActiveRaid()) { return false; diff --git a/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java -index abf57494950f55bbd75f335f26736cb9e703c197..683722fbd07fcae9cdd72928ed25fd084202b57e 100644 +index abf57494950f55bbd75f335f26736cb9e703c197..efd2418f56c36e7850edde483a2a4906dd622441 100644 --- a/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java @@ -20,6 +20,15 @@ public class NonTameRandomTargetGoal extends NearestAtta @@ -1715,7 +1666,7 @@ index abf57494950f55bbd75f335f26736cb9e703c197..683722fbd07fcae9cdd72928ed25fd08 @Override public boolean canContinueToUse() { - return this.targetConditions != null ? this.targetConditions.test(getServerLevel(this.mob), this.mob, this.target) : super.canContinueToUse(); -+ // Leaf start ++ // Leaf start - Async target finding + if (this.target == null || !this.target.isAlive() || this.target.isRemoved()) { + return false; + } @@ -1724,18 +1675,18 @@ index abf57494950f55bbd75f335f26736cb9e703c197..683722fbd07fcae9cdd72928ed25fd08 + return false; + } + return this.getTargetConditions().test(serverLevel, this.mob, this.target) && super.canContinueToUse(); -+ // Leaf end ++ // Leaf end - Async target finding } } diff --git a/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java -index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..93da18d921a1cf7d72f441d9415435ff9c417f1f 100644 +index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..15da909b4db3d7a7532aed550208ecbb76144b37 100644 --- a/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/ResetUniversalAngerTargetGoal.java @@ -37,6 +37,34 @@ public class ResetUniversalAngerTargetGoal extends G this.lastHurtByPlayerTimestamp = this.mob.getLastHurtByMobTimestamp(); this.mob.forgetCurrentTargetAndRefreshUniversalAnger(); if (this.alertOthersOfSameType) { -+ // Leaf start - async alert other ++ // Leaf start - Async alert other + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.alertOther) { + final var mob = this.mob; + final var ctx = mob.getGoalCtx(); @@ -1762,7 +1713,7 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..93da18d921a1cf7d72f441d9415435ff + }; + return; + } -+ // Leaf end - async alert other ++ // Leaf end - Async alert other this.getNearbyMobsOfSameType() .stream() .filter(mob -> mob != this.mob) @@ -1770,80 +1721,73 @@ index 61a7bb5f1760d47a13b6aafc123bcf3dff420860..93da18d921a1cf7d72f441d9415435ff super.start(); } -+ // Leaf start - async alert other ++ // Leaf start - Async alert other + public void poll() { -+ if (!(this.mob.getGoalCtx().result() instanceof List toStop)) { return; } ++ if (!(this.mob.getGoalCtx().result() instanceof List toStop)) return; + for (var neutralMob : toStop) { + ((NeutralMob)neutralMob).forgetCurrentTargetAndRefreshUniversalAnger(); + } + } -+ // Leaf end - async alert other ++ // Leaf end - Async alert other + private List getNearbyMobsOfSameType() { -+ // Leaf - async alert other ++ // Leaf - Async alert other - diff on change double attributeValue = this.mob.getAttributeValue(Attributes.FOLLOW_RANGE); AABB aabb = AABB.unitCubeFromLowerCorner(this.mob.position()).inflate(attributeValue, 10.0, attributeValue); return this.mob.level().getEntitiesOfClass((Class)this.mob.getClass(), aabb, EntitySelector.NO_SPECTATORS); diff --git a/net/minecraft/world/entity/ai/sensing/Sensing.java b/net/minecraft/world/entity/ai/sensing/Sensing.java -index 002d3c0d8b1107a275020d5c582c37e9a5c536ee..3f8c18f4040f4929df79ba85906330b150720cb0 100644 +index 002d3c0d8b1107a275020d5c582c37e9a5c536ee..6fa0b8defbd1d06b3bf5d9b32ffd08f32c1fb707 100644 --- a/net/minecraft/world/entity/ai/sensing/Sensing.java +++ b/net/minecraft/world/entity/ai/sensing/Sensing.java -@@ -32,9 +32,21 @@ public class Sensing { - // Gale end - Petal - reduce line of sight updates - expiring entity id lists +@@ -33,6 +33,17 @@ public class Sensing { } -+ // Leaf start - async target finding public void tick() { ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { + synchronized (this) { -+ tick1(); ++ tickInternal(); + } + } else { -+ tick1(); ++ tickInternal(); + } + } -+ -+ private void tick1() { -+ // Leaf end - async target finding ++ private void tickInternal() { ++ // Leaf end - Async target finding if (this.expiring == null) { // Gale - Petal - reduce line of sight updates -- this.seen.clear(); -+ this.seen.clear(); + this.seen.clear(); // Gale start - Petal - reduce line of sight updates - } else { - var expiringNow = this.expiring[this.nextToExpireIndex]; -@@ -62,7 +74,19 @@ public class Sensing { - // Gale end - Petal - reduce line of sight updates +@@ -63,6 +74,17 @@ public class Sensing { } -+ // Leaf start - async target finding public boolean hasLineOfSight(Entity entity) { ++ // Leaf start - Async target finding + if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) { + synchronized (this) { -+ return hasLineOfSight1(entity); ++ return hasLineOfSightInternal(entity); + } + } else { -+ return hasLineOfSight1(entity); ++ return hasLineOfSightInternal(entity); + } + } -+ -+ private boolean hasLineOfSight1(Entity entity) { -+ // Leaf end - async target finding ++ private boolean hasLineOfSightInternal(Entity entity) { ++ // Leaf end - Async target finding int id = entity.getId(); // Gale start - Petal - reduce line of sight cache lookups - merge sets int cached = this.seen.get(id); diff --git a/net/minecraft/world/entity/animal/Fox.java b/net/minecraft/world/entity/animal/Fox.java -index 90452f0945e761077608692877677f522d38bccd..9e380f5b4dcedb115f8893dd382f28ea05fab121 100644 +index 90452f0945e761077608692877677f522d38bccd..5c0f0ae7bb1aa379487816b115e43140dd27aadc 100644 --- a/net/minecraft/world/entity/animal/Fox.java +++ b/net/minecraft/world/entity/animal/Fox.java @@ -849,13 +849,18 @@ public class Fox extends Animal implements VariantHolder { return false; } else { ServerLevel serverLevel = getServerLevel(Fox.this.level()); -+ // Leaf start ++ // Leaf start - Async target finding + if (serverLevel == null) { + return false; + } -+ // Leaf end ++ // Leaf end - Async target finding for (UUID uuid : Fox.this.getTrustedUUIDs()) { if (serverLevel.getEntity(uuid) instanceof LivingEntity livingEntity) { @@ -1851,19 +1795,20 @@ index 90452f0945e761077608692877677f522d38bccd..9e380f5b4dcedb115f8893dd382f28ea this.trustedLastHurtBy = livingEntity.getLastHurtByMob(); int lastHurtByMobTimestamp = livingEntity.getLastHurtByMobTimestamp(); - return lastHurtByMobTimestamp != this.timestamp && this.canAttack(this.trustedLastHurtBy, this.targetConditions); -+ return lastHurtByMobTimestamp != this.timestamp && this.canAttack(this.trustedLastHurtBy, this.getTargetConditions()); // Leaf ++ return lastHurtByMobTimestamp != this.timestamp && this.canAttack(this.trustedLastHurtBy, this.getTargetConditions()); // Leaf - Async target finding - diff on change } } -@@ -1032,6 +1037,7 @@ public class Fox extends Animal implements VariantHolder { - +@@ -1033,7 +1038,7 @@ public class Fox extends Animal implements VariantHolder { @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { -+ // Leaf - Async search block BlockState blockState = level.getBlockState(pos); - return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState); +- return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState); ++ return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState); // Leaf - Async search block - diff on change } -@@ -1097,6 +1103,13 @@ public class Fox extends Animal implements VariantHolder { + + @Override +@@ -1097,6 +1102,13 @@ public class Fox extends Animal implements VariantHolder { Fox.this.setSitting(false); super.start(); } @@ -1878,10 +1823,10 @@ index 90452f0945e761077608692877677f522d38bccd..9e380f5b4dcedb115f8893dd382f28ea class FoxFloatGoal extends FloatGoal { diff --git a/net/minecraft/world/entity/animal/Panda.java b/net/minecraft/world/entity/animal/Panda.java -index 0a6a3060f3690ab2d8439d66e6fd6f0c5dc20688..d3466ebc9d0a57d0dcefa98d65fe42d8c827e6d3 100644 +index 0a6a3060f3690ab2d8439d66e6fd6f0c5dc20688..d99a1f6baebdc7c4a700e3fee30d1b52f3c1ac3d 100644 --- a/net/minecraft/world/entity/animal/Panda.java +++ b/net/minecraft/world/entity/animal/Panda.java -@@ -991,31 +991,39 @@ public class Panda extends Animal { +@@ -991,9 +991,18 @@ public class Panda extends Animal { @Override public boolean canUse() { @@ -1891,59 +1836,17 @@ index 0a6a3060f3690ab2d8439d66e6fd6f0c5dc20688..d3466ebc9d0a57d0dcefa98d65fe42d8 + } if (this.mob.getRandom().nextFloat() >= this.probability) { return false; -- } else { -- if (this.lookAt == null) { -- ServerLevel serverLevel = getServerLevel(this.mob); -- if (this.lookAtType == Player.class) { -- this.lookAt = serverLevel.getNearestPlayer(this.lookAtContext, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ()); -- } else { -- this.lookAt = serverLevel.getNearestEntity( -- this.mob -- .level() -- .getEntitiesOfClass( -- this.lookAtType, this.mob.getBoundingBox().inflate(this.lookDistance, 3.0, this.lookDistance), entity -> true -- ), -- this.lookAtContext, -- this.mob, -- this.mob.getX(), -- this.mob.getEyeY(), -- this.mob.getZ() -- ); -- } -+ } -+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { -+ getLookAsync(); -+ return false; -+ } -+ if (this.lookAt == null) { -+ ServerLevel serverLevel = getServerLevel(this.mob); -+ if (this.lookAtType == Player.class) { -+ this.lookAt = serverLevel.getNearestPlayer(this.lookAtContext, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ()); -+ } else { -+ this.lookAt = serverLevel.getNearestEntity( -+ this.mob -+ .level() -+ .getEntitiesOfClass( -+ this.lookAtType, this.mob.getBoundingBox().inflate(this.lookDistance, 3.0, this.lookDistance), entity -> true -+ ), -+ this.lookAtContext, -+ this.mob, -+ this.mob.getX(), -+ this.mob.getEyeY(), -+ this.mob.getZ() -+ ); - } -- -- return this.panda.canPerformAction() && this.lookAt != null; - } -+ -+ return this.panda.canPerformAction() && this.lookAt != null; -+ // Leaf end - Async look finding - } - - @Override + } else { ++ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) { ++ getLookAsync(); ++ return false; ++ } ++ // Leaf end - Async look finding + if (this.lookAt == null) { + ServerLevel serverLevel = getServerLevel(this.mob); + if (this.lookAtType == Player.class) { diff --git a/net/minecraft/world/entity/animal/Rabbit.java b/net/minecraft/world/entity/animal/Rabbit.java -index da5b32a17283e540615373097acc511d928aeff5..a9cc92d2ae2b1548b27288c190a3f99799dcefbe 100644 +index da5b32a17283e540615373097acc511d928aeff5..cdab995c86978f0a789c85d14151abf19d89b673 100644 --- a/net/minecraft/world/entity/animal/Rabbit.java +++ b/net/minecraft/world/entity/animal/Rabbit.java @@ -642,7 +642,13 @@ public class Rabbit extends Animal implements VariantHolder { @@ -1951,29 +1854,26 @@ index da5b32a17283e540615373097acc511d928aeff5..a9cc92d2ae2b1548b27288c190a3f997 } - return super.canUse(); -+ // Leaf start ++ // Leaf start - Async search block + if (this.wantsToRaid && !this.canRaid) { + return super.canUse(); + } else { + return false; + } -+ // Leaf end ++ // Leaf end - Async search block } @Override -@@ -684,6 +690,7 @@ public class Rabbit extends Animal implements VariantHolder { - +@@ -685,7 +691,7 @@ public class Rabbit extends Animal implements VariantHolder { @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { -+ // Leaf - Async search block BlockState blockState = level.getBlockState(pos); - if (blockState.is(Blocks.FARMLAND) && this.wantsToRaid && !this.canRaid) { +- if (blockState.is(Blocks.FARMLAND) && this.wantsToRaid && !this.canRaid) { ++ if (blockState.is(Blocks.FARMLAND) && this.wantsToRaid && !this.canRaid) { // Leaf - Async search block - diff on change blockState = level.getBlockState(pos.above()); -@@ -692,9 +699,17 @@ public class Rabbit extends Animal implements VariantHolder { - return true; - } - } -+ // Leaf - Async search block + if (blockState.getBlock() instanceof CarrotBlock && ((CarrotBlock)blockState.getBlock()).isMaxAge(blockState)) { + this.canRaid = true; +@@ -695,6 +701,13 @@ public class Rabbit extends Animal implements VariantHolder { return false; } @@ -1988,15 +1888,15 @@ index da5b32a17283e540615373097acc511d928aeff5..a9cc92d2ae2b1548b27288c190a3f997 public static enum Variant implements StringRepresentable { diff --git a/net/minecraft/world/entity/animal/Turtle.java b/net/minecraft/world/entity/animal/Turtle.java -index 10477fea8fcd70bf0c1ba4b6e1113625be690e68..65bbfc7d0078465faa6f18ff2f611d813fea310a 100644 +index 10477fea8fcd70bf0c1ba4b6e1113625be690e68..c5f626dcfe724f8ed19303d305f6eb5cfcc0f0af 100644 --- a/net/minecraft/world/entity/animal/Turtle.java +++ b/net/minecraft/world/entity/animal/Turtle.java -@@ -527,8 +527,16 @@ public class Turtle extends Animal { +@@ -527,8 +527,15 @@ public class Turtle extends Animal { @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { -+ // Leaf - Async search block - return level.getBlockState(pos).is(Blocks.WATER); +- return level.getBlockState(pos).is(Blocks.WATER); ++ return level.getBlockState(pos).is(Blocks.WATER); // Leaf - Async search block - diff on change } + + // Leaf start - Async search block @@ -2008,48 +1908,50 @@ index 10477fea8fcd70bf0c1ba4b6e1113625be690e68..65bbfc7d0078465faa6f18ff2f611d81 } static class TurtleLayEggGoal extends MoveToBlockGoal { -@@ -584,8 +592,16 @@ public class Turtle extends Animal { +@@ -584,8 +591,15 @@ public class Turtle extends Animal { @Override protected boolean isValidTarget(LevelReader level, BlockPos pos) { -+ // Leaf - Async search block - return level.isEmptyBlock(pos.above()) && TurtleEggBlock.isSand(level, pos); - } +- return level.isEmptyBlock(pos.above()) && TurtleEggBlock.isSand(level, pos); ++ return level.isEmptyBlock(pos.above()) && TurtleEggBlock.isSand(level, pos); // Leaf - Async search block - diff on change ++ } + + // Leaf start - Async search block + @Override + protected TypeToCheck typeToCheck() { + return TypeToCheck.TurtleLay; -+ } + } + // Leaf end - Async search block } static class TurtleMoveControl extends org.purpurmc.purpur.controller.MoveControllerWASD { // Purpur - Ridables diff --git a/net/minecraft/world/entity/animal/Wolf.java b/net/minecraft/world/entity/animal/Wolf.java -index 7cb292de6b27fa4ba3c5fce526a4e939c576789f..856bfeaa91a476c1008909ac35f76dfe0b792c9c 100644 +index 7cb292de6b27fa4ba3c5fce526a4e939c576789f..68852158e2fd3c4ce241d722ac414d73ea3b8836 100644 --- a/net/minecraft/world/entity/animal/Wolf.java +++ b/net/minecraft/world/entity/animal/Wolf.java -@@ -672,6 +672,7 @@ public class Wolf extends TamableAnimal implements NeutralMob, VariantHolder list = Lists.newArrayList(); // Leaf - unused ++ // List list = Lists.newArrayList(); // Leaf - Async target finding - unused ++ // Leaf end - Async target finding // Paper start - rewrite chunk system final List ret = new java.util.ArrayList<>(); diff --git a/leaf-server/minecraft-patches/features/0155-Optimize-ThreadedTicketLevelPropagator.patch b/leaf-server/minecraft-patches/features/0155-Optimize-ThreadedTicketLevelPropagator.patch index ce2f704e..9c5503b2 100644 --- a/leaf-server/minecraft-patches/features/0155-Optimize-ThreadedTicketLevelPropagator.patch +++ b/leaf-server/minecraft-patches/features/0155-Optimize-ThreadedTicketLevelPropagator.patch @@ -5,33 +5,36 @@ Subject: [PATCH] Optimize ThreadedTicketLevelPropagator diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java -index 01598347ea545f2ff2ac337086345d7369a64520..fbea9d83b7458760d4b1b5e1c8bd77ff46072b97 100644 +index 3a7fad46465cac8d2c1b0933b457f5b075586709..a2d76e6fabf2749a1a9f21fe6bdf6524af8bb9b7 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ThreadedTicketLevelPropagator.java @@ -998,6 +998,7 @@ public abstract class ThreadedTicketLevelPropagator { final int decodeOffsetZ = -this.encodeOffsetZ; final int encodeOffset = this.coordinateOffset; final int sectionOffset = this.sectionIndexOffset; -+ final Section[] sectionsArray = this.sections; ++ final Section[] sectionsArray = this.sections; // Leaf - Optimize ThreadedTicketLevelPropagator final Long2ByteLinkedOpenHashMap updatedPositions = this.updatedPositions; -@@ -1012,13 +1013,23 @@ public abstract class ThreadedTicketLevelPropagator { +@@ -1012,13 +1013,27 @@ public abstract class ThreadedTicketLevelPropagator { int propagateDirectionBitset = (int)(queueValue >>> (COORDINATE_BITS + COORDINATE_BITS + LEVEL_BITS)) & ((1 << 16) - 1); if ((queueValue & FLAG_RECHECK_LEVEL) != 0L) { - if (this.getLevel(posX, posZ) != propagatedLevel) { ++ // Leaf start - Optimize ThreadedTicketLevelPropagator + final int sectionX = posX >> SECTION_SHIFT; + final int sectionZ = posZ >> SECTION_SHIFT; + final Section section = sectionsArray[sectionX + (sectionZ * SECTION_CACHE_WIDTH) + sectionOffset]; + final int localIdx = (posX & (SECTION_SIZE - 1)) | ((posZ & (SECTION_SIZE - 1)) << SECTION_SHIFT); + if ((section.levels[localIdx] & 0xFF) != propagatedLevel) { ++ // Leaf end - Optimize ThreadedTicketLevelPropagator // not at the level we expect, so something changed. continue; } } else if ((queueValue & FLAG_WRITE_LEVEL) != 0L) { // these are used to restore sources after a propagation decrease - this.setLevel(posX, posZ, propagatedLevel); ++ // Leaf start - Optimize ThreadedTicketLevelPropagator + final int sectionX = posX >> SECTION_SHIFT; + final int sectionZ = posZ >> SECTION_SHIFT; + final Section section = sectionsArray[sectionX + (sectionZ * SECTION_CACHE_WIDTH) + sectionOffset]; @@ -39,32 +42,33 @@ index 01598347ea545f2ff2ac337086345d7369a64520..fbea9d83b7458760d4b1b5e1c8bd77ff + final short currentLevel = section.levels[localIdx]; + section.levels[localIdx] = (short) ((currentLevel & ~0xFF) | (propagatedLevel & 0xFF)); + updatedPositions.put(CoordinateUtils.getChunkKey(posX, posZ), (byte) propagatedLevel); ++ // Leaf end - Optimize ThreadedTicketLevelPropagator } // this bitset represents the values that we have not propagated to -@@ -1093,7 +1104,7 @@ public abstract class ThreadedTicketLevelPropagator { +@@ -1093,7 +1108,7 @@ public abstract class ThreadedTicketLevelPropagator { currentPropagation ^= (bitsetLine1 | bitsetLine2 | bitsetLine3); // now try to propagate - final Section section = this.sections[sectionIndex]; -+ final Section section = sectionsArray[sectionIndex]; ++ final Section section = sectionsArray[sectionIndex]; // Leaf - Optimize ThreadedTicketLevelPropagator // lower 8 bits are current level, next upper 7 bits are source level, next 1 bit is updated source flag final short currentStoredLevel = section.levels[localIndex]; -@@ -1144,6 +1155,7 @@ public abstract class ThreadedTicketLevelPropagator { +@@ -1144,6 +1159,7 @@ public abstract class ThreadedTicketLevelPropagator { final int decodeOffsetZ = -this.encodeOffsetZ; final int encodeOffset = this.coordinateOffset; final int sectionOffset = this.sectionIndexOffset; -+ final Section[] sectionsArray = this.sections; ++ final Section[] sectionsArray = this.sections; // Leaf - Optimize ThreadedTicketLevelPropagator final Long2ByteLinkedOpenHashMap updatedPositions = this.updatedPositions; -@@ -1227,7 +1239,7 @@ public abstract class ThreadedTicketLevelPropagator { +@@ -1227,7 +1243,7 @@ public abstract class ThreadedTicketLevelPropagator { final long bitsetLine3 = currentPropagation & (7L << (start + (8 + 8))); // now try to propagate - final Section section = this.sections[sectionIndex]; -+ final Section section = sectionsArray[sectionIndex]; ++ final Section section = sectionsArray[sectionIndex]; // Leaf - Optimize ThreadedTicketLevelPropagator // lower 8 bits are current level, next upper 7 bits are source level, next 1 bit is updated source flag final short currentStoredLevel = section.levels[localIndex]; diff --git a/leaf-server/minecraft-patches/features/0156-Optimise-MobEffectUtil-getDigSpeedAmplification.patch b/leaf-server/minecraft-patches/features/0156-Optimise-MobEffectUtil-getDigSpeedAmplification.patch index 3550d539..dc4502f7 100644 --- a/leaf-server/minecraft-patches/features/0156-Optimise-MobEffectUtil-getDigSpeedAmplification.patch +++ b/leaf-server/minecraft-patches/features/0156-Optimise-MobEffectUtil-getDigSpeedAmplification.patch @@ -5,25 +5,35 @@ Subject: [PATCH] Optimise MobEffectUtil#getDigSpeedAmplification diff --git a/net/minecraft/world/effect/MobEffectUtil.java b/net/minecraft/world/effect/MobEffectUtil.java -index cbf1b6af928aa439c3264b302e5f1a1ddd4c14f0..c59a503ef8bc2dabcf9f7c85c8d93fb1fcadf71f 100644 +index cbf1b6af928aa439c3264b302e5f1a1ddd4c14f0..e4126bbfb46f2d3df9aac4c9362b9d81b3ecb713 100644 --- a/net/minecraft/world/effect/MobEffectUtil.java +++ b/net/minecraft/world/effect/MobEffectUtil.java -@@ -29,12 +29,14 @@ public final class MobEffectUtil { +@@ -27,17 +27,21 @@ public final class MobEffectUtil { + } + public static int getDigSpeedAmplification(LivingEntity entity) { - int i = 0; - int i1 = 0; +- int i = 0; +- int i1 = 0; - if (entity.hasEffect(MobEffects.DIG_SPEED)) { - i = entity.getEffect(MobEffects.DIG_SPEED).getAmplifier(); ++ // Leaf start - Optimise MobEffectUtil#getDigSpeedAmplification ++ int digAmplifier = 0; ++ int conduitAmplifier = 0; + MobEffectInstance digEffect = entity.getEffect(MobEffects.DIG_SPEED); + if (digEffect != null) { -+ i = digEffect.getAmplifier(); ++ digAmplifier = digEffect.getAmplifier(); } - if (entity.hasEffect(MobEffects.CONDUIT_POWER)) { - i1 = entity.getEffect(MobEffects.CONDUIT_POWER).getAmplifier(); + MobEffectInstance conduitEffect = entity.getEffect(MobEffects.CONDUIT_POWER); + if (conduitEffect != null) { -+ i1 = conduitEffect.getAmplifier(); ++ conduitAmplifier = conduitEffect.getAmplifier(); } - return Math.max(i, i1); +- return Math.max(i, i1); ++ return Math.max(digAmplifier, conduitAmplifier); ++ // Leaf end - Optimise MobEffectUtil#getDigSpeedAmplification + } + + public static boolean hasWaterBreathing(LivingEntity entity) { diff --git a/leaf-server/minecraft-patches/features/0157-Optimise-chunkUnloads.patch b/leaf-server/minecraft-patches/features/0157-Optimise-chunkUnloads.patch index 61b8d35b..1e8b498c 100644 --- a/leaf-server/minecraft-patches/features/0157-Optimise-chunkUnloads.patch +++ b/leaf-server/minecraft-patches/features/0157-Optimise-chunkUnloads.patch @@ -212,10 +212,10 @@ index b8ac6a9ba7b56ccd034757f7d135d272b8e69e90..dc158e981199b507531af810ff9ced3c } } diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -index e9ece9b618b0a9eb82b9f07a09ee6cb60cf7ec16..18d2ec110fc6670edb079eccf448389dc365eb88 100644 +index e9ece9b618b0a9eb82b9f07a09ee6cb60cf7ec16..dff2fed559a274ee7896ee136999eaf288cf82bb 100644 --- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -@@ -526,14 +526,14 @@ public record SerializableChunkData( +@@ -526,14 +526,16 @@ public record SerializableChunkData( throw new IllegalArgumentException("Chunk can't be serialized: " + chunk); } else { ChunkPos pos = chunk.getPos(); @@ -227,16 +227,19 @@ index e9ece9b618b0a9eb82b9f07a09ee6cb60cf7ec16..18d2ec110fc6670edb079eccf448389d final int minLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinLightSection(level); final int maxLightSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMaxLightSection(level); final int minBlockSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(level); ++ // Leaf start - Optimize chunkUnload + // Pre-allocate with correct capacity to avoid resizing + final int expectedSectionCount = maxLightSection - minLightSection + 1; + List list = new ArrayList<>(expectedSectionCount); ++ // Leaf end - Optimize chunkUnload final LevelChunkSection[] chunkSections = chunk.getSections(); final ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] blockNibbles = ((ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk)chunk).starlight$getBlockNibbles(); -@@ -551,10 +551,18 @@ public record SerializableChunkData( +@@ -551,10 +553,20 @@ public record SerializableChunkData( continue; } ++ // Leaf start - Optimize chunkUnload + DataLayer blockDataLayer = null; + if (blockNibble != null && blockNibble.data != null) { + blockDataLayer = new DataLayer(blockNibble.data); @@ -246,50 +249,48 @@ index e9ece9b618b0a9eb82b9f07a09ee6cb60cf7ec16..18d2ec110fc6670edb079eccf448389d + if (skyNibble != null && skyNibble.data != null) { + skyDataLayer = new DataLayer(skyNibble.data); + } ++ // Leaf end - Optimize chunkUnload + final SerializableChunkData.SectionData sectionData = new SerializableChunkData.SectionData( - lightSection, chunkSection, - blockNibble == null ? null : (blockNibble.data == null ? null : new DataLayer(blockNibble.data)), - skyNibble == null ? null : (skyNibble.data == null ? null : new DataLayer(skyNibble.data)) -+ lightSection, chunkSection, blockDataLayer, skyDataLayer ++ lightSection, chunkSection, blockDataLayer, skyDataLayer // Leaf - Optimize chunkUnload ); if (blockNibble != null) { -@@ -565,28 +573,42 @@ public record SerializableChunkData( +@@ -565,12 +577,16 @@ public record SerializableChunkData( ((ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData)(Object)sectionData).starlight$setSkyLightState(skyNibble.state); } - sectionsList.add(sectionData); -+ list.add(sectionData); ++ list.add(sectionData); // Leaf - Optimize chunkUnload } // Paper end - starlight - List list1 = new ArrayList<>(chunk.getBlockEntitiesPos().size()); ++ // Leaf start - Optimize chunkUnload + // Pre-allocate block entities list with exact size needed + final int blockEntityCount = chunk.getBlockEntitiesPos().size(); + List list1 = blockEntityCount > 0 ? new ArrayList<>(blockEntityCount) : java.util.Collections.emptyList(); -- for (BlockPos blockPos : chunk.getBlockEntitiesPos()) { -- CompoundTag blockEntityNbtForSaving = chunk.getBlockEntityNbtForSaving(blockPos, level.registryAccess()); -- if (blockEntityNbtForSaving != null) { -- list1.add(blockEntityNbtForSaving); -+ if (blockEntityCount > 0) { -+ for (BlockPos blockPos : chunk.getBlockEntitiesPos()) { -+ CompoundTag blockEntityNbtForSaving = chunk.getBlockEntityNbtForSaving(blockPos, level.registryAccess()); -+ if (blockEntityNbtForSaving != null) { -+ list1.add(blockEntityNbtForSaving); -+ } ++ if (blockEntityCount > 0) // Leaf - Optimize chunkUnload + for (BlockPos blockPos : chunk.getBlockEntitiesPos()) { + CompoundTag blockEntityNbtForSaving = chunk.getBlockEntityNbtForSaving(blockPos, level.registryAccess()); + if (blockEntityNbtForSaving != null) { +@@ -578,15 +594,27 @@ public record SerializableChunkData( } } - List list2 = new ArrayList<>(); ++ // Leaf start - Optimize chunkUnload + // For entities, use an initial estimated capacity if it's a ProtoChunk + List list2; long[] longs = null; -+ if (chunk.getPersistedStatus().getChunkType() == ChunkType.PROTOCHUNK) { ProtoChunk protoChunk = (ProtoChunk)chunk; - list2.addAll(protoChunk.getEntities()); ++ // Leaf start - Optimize chunkUnload + int entitySize = protoChunk.getEntities().size(); + if (entitySize > 0) { + list2 = new ArrayList<>(Math.max(16, entitySize)); @@ -297,21 +298,22 @@ index e9ece9b618b0a9eb82b9f07a09ee6cb60cf7ec16..18d2ec110fc6670edb079eccf448389d + } else { + list2 = java.util.Collections.emptyList(); + } ++ // Leaf end - Optimize chunkUnload CarvingMask carvingMask = protoChunk.getCarvingMask(); if (carvingMask != null) { longs = carvingMask.toArray(); } + } else { -+ list2 = java.util.Collections.emptyList(); ++ list2 = java.util.Collections.emptyList(); // Leaf - Optimize chunkUnload } Map map = new EnumMap<>(Heightmap.Types.class); -@@ -594,14 +616,25 @@ public record SerializableChunkData( +@@ -594,14 +622,26 @@ public record SerializableChunkData( for (Entry entry : chunk.getHeightmaps()) { if (chunk.getPersistedStatus().heightmapsAfter().contains(entry.getKey())) { long[] rawData = entry.getValue().getRawData(); - map.put(entry.getKey(), (long[])rawData.clone()); -+ map.put(entry.getKey(), Arrays.copyOf(rawData, rawData.length)); ++ map.put(entry.getKey(), Arrays.copyOf(rawData, rawData.length)); // Leaf - Optimize chunkUnload } } @@ -319,7 +321,7 @@ index e9ece9b618b0a9eb82b9f07a09ee6cb60cf7ec16..18d2ec110fc6670edb079eccf448389d - ShortList[] lists = Arrays.stream(chunk.getPostProcessing()) - .map(list3 -> list3 != null ? new ShortArrayList(list3) : null) - .toArray(ShortList[]::new); -+ // Leaf start - Some Optimizations on SerializableChunkData ++ // Leaf start - Optimize chunkUnload - remove stream + ShortList[] postProcessing = chunk.getPostProcessing(); + ShortList[] lists = new ShortList[postProcessing.length]; + for (int i = 0; i < postProcessing.length; i++) { @@ -333,6 +335,7 @@ index e9ece9b618b0a9eb82b9f07a09ee6cb60cf7ec16..18d2ec110fc6670edb079eccf448389d + } + } + } ++ // Leaf end - Optimize chunkUnload - remove stream CompoundTag compoundTag = packStructureData( StructurePieceSerializationContext.fromLevel(level), pos, chunk.getAllStarts(), chunk.getAllReferences() ); diff --git a/leaf-server/minecraft-patches/features/0158-optimize-BlockEntityType-isValid.patch b/leaf-server/minecraft-patches/features/0158-Optimize-BlockEntityType-isValid.patch similarity index 79% rename from leaf-server/minecraft-patches/features/0158-optimize-BlockEntityType-isValid.patch rename to leaf-server/minecraft-patches/features/0158-Optimize-BlockEntityType-isValid.patch index d1814b1c..7f0720d6 100644 --- a/leaf-server/minecraft-patches/features/0158-optimize-BlockEntityType-isValid.patch +++ b/leaf-server/minecraft-patches/features/0158-Optimize-BlockEntityType-isValid.patch @@ -1,25 +1,25 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Sat, 19 Apr 2025 22:12:19 +0800 -Subject: [PATCH] optimize BlockEntityType#isValid +Subject: [PATCH] Optimize BlockEntityType#isValid diff --git a/net/minecraft/world/level/block/entity/BlockEntityType.java b/net/minecraft/world/level/block/entity/BlockEntityType.java -index a2a674f18d7f2c2e50a6b25f9ac3bf4534275976..073b2ca9f1af94934afc39104e0916c97b84ef0e 100644 +index a2a674f18d7f2c2e50a6b25f9ac3bf4534275976..6be69dcd9faa76ef999daaecc237ee3b4d04c182 100644 --- a/net/minecraft/world/level/block/entity/BlockEntityType.java +++ b/net/minecraft/world/level/block/entity/BlockEntityType.java @@ -252,6 +252,14 @@ public class BlockEntityType { private BlockEntityType(BlockEntityType.BlockEntitySupplier factory, Set validBlocks) { this.factory = factory; this.validBlocks = validBlocks; -+ // Leaf start ++ // Leaf start - Optimize BlockEntityType#isValid + for (Block validBlock : validBlocks) { + if (validBlock.blockEntityType != null) { + throw new IllegalStateException("Duplicate block entity type"); + } + validBlock.blockEntityType = this; + } -+ // Leaf end ++ // Leaf end - Optimize BlockEntityType#isValid } @Nullable @@ -28,19 +28,19 @@ index a2a674f18d7f2c2e50a6b25f9ac3bf4534275976..073b2ca9f1af94934afc39104e0916c9 public boolean isValid(BlockState state) { - return this.validBlocks.contains(state.getBlock()); -+ return state.getBlock().blockEntityType == this; // Leaf - remove hash lookup ++ return state.getBlock().blockEntityType == this; // Leaf - Optimize BlockEntityType#isValid - remove hash lookup } @Deprecated diff --git a/net/minecraft/world/level/block/state/BlockBehaviour.java b/net/minecraft/world/level/block/state/BlockBehaviour.java -index d35211b0cae66b1a40e89539507e55973313f46f..fa6d4217f222e8d9decde18e967e951dd833a1c7 100644 +index d35211b0cae66b1a40e89539507e55973313f46f..3a49690672bc49259e863e5cde7f14d57c89fcd5 100644 --- a/net/minecraft/world/level/block/state/BlockBehaviour.java +++ b/net/minecraft/world/level/block/state/BlockBehaviour.java @@ -100,6 +100,7 @@ public abstract class BlockBehaviour implements FeatureElement { protected final BlockBehaviour.Properties properties; protected final Optional> drops; protected final String descriptionId; -+ @Nullable public net.minecraft.world.level.block.entity.BlockEntityType blockEntityType = null; // Leaf ++ @Nullable public net.minecraft.world.level.block.entity.BlockEntityType blockEntityType = null; // Leaf - Optimize BlockEntityType#isValid public BlockBehaviour(BlockBehaviour.Properties properties) { this.hasCollision = properties.hasCollision; diff --git a/leaf-server/paper-patches/features/0004-Pufferfish-Optimize-mob-spawning.patch b/leaf-server/paper-patches/features/0004-Pufferfish-Optimize-mob-spawning.patch index e9697ac3..9850f3b4 100644 --- a/leaf-server/paper-patches/features/0004-Pufferfish-Optimize-mob-spawning.patch +++ b/leaf-server/paper-patches/features/0004-Pufferfish-Optimize-mob-spawning.patch @@ -23,7 +23,7 @@ and, in my opinion, worth the low risk of minor mob-spawning-related inconsistencies. diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java -index c21e00812f1aaa1279834a0562d360d6b89e146c..19e0bf50cf8863f42ce19c3d0d8911c0c9b8ad4a 100644 +index c21e00812f1aaa1279834a0562d360d6b89e146c..4a6bfc2a09401b4c96d6f368ead7b060dae2a08b 100644 --- a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java @@ -10,7 +10,7 @@ public final class IteratorSafeOrderedReferenceSet { @@ -44,22 +44,7 @@ index c21e00812f1aaa1279834a0562d360d6b89e146c..19e0bf50cf8863f42ce19c3d0d8911c0 public IteratorSafeOrderedReferenceSet() { this(16, 0.75f, 16, 0.2); -@@ -74,16 +74,26 @@ public final class IteratorSafeOrderedReferenceSet { - } - */ - -+ // Pufferfish start - async mob spawning -+ // TODO: backup plan if the issue persists, don't run -+ // this.set.finishRawIterator() or defrag() off-main -+ /* -+ protected final boolean allowSafeIteration() { -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThread(); -+ } -+ */ -+ // Pufferfish end - async mob spawning -+ - private double getFragFactor() { - return 1.0 - ((double)this.indexMap.size() / (double)this.listSize); +@@ -79,11 +79,11 @@ public final class IteratorSafeOrderedReferenceSet { } public int createRawIterator() { @@ -73,7 +58,7 @@ index c21e00812f1aaa1279834a0562d360d6b89e146c..19e0bf50cf8863f42ce19c3d0d8911c0 } } -@@ -100,7 +110,7 @@ public final class IteratorSafeOrderedReferenceSet { +@@ -100,7 +100,7 @@ public final class IteratorSafeOrderedReferenceSet { } public void finishRawIterator() { @@ -82,7 +67,7 @@ index c21e00812f1aaa1279834a0562d360d6b89e146c..19e0bf50cf8863f42ce19c3d0d8911c0 if (this.getFragFactor() >= this.maxFragFactor) { this.defrag(); } -@@ -110,14 +120,17 @@ public final class IteratorSafeOrderedReferenceSet { +@@ -110,14 +110,17 @@ public final class IteratorSafeOrderedReferenceSet { public boolean remove(final E element) { final int index = this.indexMap.removeInt(element); if (index >= 0) { @@ -103,7 +88,7 @@ index c21e00812f1aaa1279834a0562d360d6b89e146c..19e0bf50cf8863f42ce19c3d0d8911c0 this.defrag(); } //this.check(); -@@ -149,14 +162,17 @@ public final class IteratorSafeOrderedReferenceSet { +@@ -149,14 +152,17 @@ public final class IteratorSafeOrderedReferenceSet { } private void defrag() { @@ -123,7 +108,7 @@ index c21e00812f1aaa1279834a0562d360d6b89e146c..19e0bf50cf8863f42ce19c3d0d8911c0 //this.check(); return; } -@@ -166,11 +182,11 @@ public final class IteratorSafeOrderedReferenceSet { +@@ -166,11 +172,11 @@ public final class IteratorSafeOrderedReferenceSet { int lastValidIndex; java.util.Iterator> iterator; @@ -137,7 +122,7 @@ index c21e00812f1aaa1279834a0562d360d6b89e146c..19e0bf50cf8863f42ce19c3d0d8911c0 final E key = backingArray[lastValidIndex - 1]; iterator = this.indexMap.reference2IntEntrySet().fastIterator(new Reference2IntMap.Entry() { @Override -@@ -201,7 +217,7 @@ public final class IteratorSafeOrderedReferenceSet { +@@ -201,7 +207,7 @@ public final class IteratorSafeOrderedReferenceSet { // cleanup end Arrays.fill(backingArray, lastValidIndex, this.listSize, null); this.listSize = lastValidIndex; @@ -146,7 +131,7 @@ index c21e00812f1aaa1279834a0562d360d6b89e146c..19e0bf50cf8863f42ce19c3d0d8911c0 //this.check(); } -@@ -219,7 +235,7 @@ public final class IteratorSafeOrderedReferenceSet { +@@ -219,7 +225,7 @@ public final class IteratorSafeOrderedReferenceSet { } public IteratorSafeOrderedReferenceSet.Iterator iterator(final int flags) { @@ -155,7 +140,7 @@ index c21e00812f1aaa1279834a0562d360d6b89e146c..19e0bf50cf8863f42ce19c3d0d8911c0 return new BaseIterator<>(this, true, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize); } -@@ -306,7 +322,7 @@ public final class IteratorSafeOrderedReferenceSet { +@@ -306,7 +312,7 @@ public final class IteratorSafeOrderedReferenceSet { } this.lastReturned = null; this.finished = true; diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java index 5ac7e6cb..b6a4c632 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalExecutor.java @@ -11,9 +11,11 @@ import org.dreeam.leaf.util.queue.SpscIntQueue; import java.util.concurrent.locks.LockSupport; public class AsyncGoalExecutor { + public static final Logger LOGGER = LogManager.getLogger("Leaf Async Goal"); - final SpscIntQueue queue; - final SpscIntQueue wake; + + protected final SpscIntQueue queue; + protected final SpscIntQueue wake; private final AsyncGoalThread thread; private final ServerLevel serverLevel; private boolean dirty = false; @@ -22,18 +24,18 @@ public class AsyncGoalExecutor { public AsyncGoalExecutor(AsyncGoalThread thread, ServerLevel serverLevel) { this.serverLevel = serverLevel; - queue = new SpscIntQueue(AsyncTargetFinding.queueSize); - wake = new SpscIntQueue(AsyncTargetFinding.queueSize); + this.queue = new SpscIntQueue(AsyncTargetFinding.queueSize); + this.wake = new SpscIntQueue(AsyncTargetFinding.queueSize); this.thread = thread; } boolean wake(int id) { Entity entity = this.serverLevel.getEntities().get(id); - if (entity == null || entity.isRemoved() || !(entity instanceof Mob m)) { + if (entity == null || entity.isRemoved() || !(entity instanceof Mob mob)) { return false; } - m.goalSelector.wake(); - m.targetSelector.wake(); + mob.goalSelector.wake(); + mob.targetSelector.wake(); return true; } @@ -42,7 +44,7 @@ public class AsyncGoalExecutor { int spinCount = 0; while (!this.queue.send(entityId)) { spinCount++; - // Unpark thread after some spinning to help clear the queue + // Unpark the thread after some spinning to help clear the queue if (spinCount > SPIN_LIMIT) { unpark(); spinCount = 0; diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java index 12b78169..d3d236c2 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/AsyncGoalThread.java @@ -7,6 +7,7 @@ import net.minecraft.server.level.ServerLevel; import java.util.concurrent.locks.LockSupport; public class AsyncGoalThread extends Thread { + private static final int SPIN_TRIES = 1000; public AsyncGoalThread(final MinecraftServer server) { diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/Waker.java b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/Waker.java index 82560379..0f064e5e 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/ai/Waker.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/ai/Waker.java @@ -3,6 +3,7 @@ package org.dreeam.leaf.async.ai; import org.jetbrains.annotations.Nullable; public class Waker { + @Nullable public volatile Runnable wake = null; @Nullable diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/world/PWTEventScheduler.java b/leaf-server/src/main/java/org/dreeam/leaf/async/world/PWTEventScheduler.java index eef0d654..c74d8909 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/world/PWTEventScheduler.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/world/PWTEventScheduler.java @@ -6,8 +6,10 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class PWTEventScheduler { + private static volatile PWTEventScheduler instance; private final ExecutorService executor; + private PWTEventScheduler() { this.executor = Executors.newCachedThreadPool( new ThreadFactoryBuilder() diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncChunkSend.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncChunkSend.java index 34fae012..89ef74ed 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncChunkSend.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncChunkSend.java @@ -13,8 +13,7 @@ public class AsyncChunkSend extends ConfigModules { @Override public void onLoaded() { - config.addCommentRegionBased(getBasePath(), - """ + config.addCommentRegionBased(getBasePath(), """ Makes chunk packet preparation and sending asynchronous to improve server performance. This can significantly reduce main thread load when many players are loading chunks.""", """ diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncPathfinding.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncPathfinding.java index 5b19711e..f24fc20f 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncPathfinding.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncPathfinding.java @@ -20,8 +20,7 @@ public class AsyncPathfinding extends ConfigModules { @Override public void onLoaded() { - config.addCommentRegionBased(getBasePath() + ".reject-policy", - """ + config.addCommentRegionBased(getBasePath() + ".reject-policy", """ The policy to use when the queue is full and a new task is submitted. FLUSH_ALL: All pending tasks will be run on server thread. CALLER_RUNS: Newly submitted task will be run on server thread. @@ -56,6 +55,10 @@ public class AsyncPathfinding extends ConfigModules { if (asyncPathfindingQueueSize <= 0) asyncPathfindingQueueSize = asyncPathfindingMaxThreads * 256; - asyncPathfindingRejectPolicy = PathfindTaskRejectPolicy.fromString(config.getString(getBasePath() + ".reject-policy", availableProcessors >= 12 && asyncPathfindingQueueSize < 512 ? PathfindTaskRejectPolicy.FLUSH_ALL.toString() : PathfindTaskRejectPolicy.CALLER_RUNS.toString())); + asyncPathfindingRejectPolicy = PathfindTaskRejectPolicy.fromString(config.getString(getBasePath() + ".reject-policy", + availableProcessors >= 12 && asyncPathfindingQueueSize < 512 + ? PathfindTaskRejectPolicy.FLUSH_ALL.toString() + : PathfindTaskRejectPolicy.CALLER_RUNS.toString()) + ); } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncPlayerDataSave.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncPlayerDataSave.java index ebdad7ae..7b8fecfe 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncPlayerDataSave.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncPlayerDataSave.java @@ -14,8 +14,7 @@ public class AsyncPlayerDataSave extends ConfigModules { @Override public void onLoaded() { - config.addCommentRegionBased(getBasePath(), - """ + config.addCommentRegionBased(getBasePath(), """ Make PlayerData saving asynchronously.""", """ 异步保存玩家数据."""); diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java index eb2a5aaf..478f132c 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/AsyncTargetFinding.java @@ -37,6 +37,7 @@ public class AsyncTargetFinding extends ConfigModules { searchBlock = config.getBoolean(getBasePath() + ".async-search-block", true); searchEntity = config.getBoolean(getBasePath() + ".async-search-entity", true); queueSize = config.getInt(getBasePath() + ".queue-size", 4096); + if (queueSize <= 0) { queueSize = 4096; } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/MultithreadedTracker.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/MultithreadedTracker.java index e18028b4..a6b42058 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/MultithreadedTracker.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/MultithreadedTracker.java @@ -19,15 +19,13 @@ public class MultithreadedTracker extends ConfigModules { @Override public void onLoaded() { - config.addCommentRegionBased(getBasePath(), - """ + config.addCommentRegionBased(getBasePath(), """ Make entity tracking saving asynchronously, can improve performance significantly, especially in some massive entities in small area situations.""", """ 异步实体跟踪, 在实体数量多且密集的情况下效果明显."""); - config.addCommentRegionBased(getBasePath() + ".compat-mode", - """ + config.addCommentRegionBased(getBasePath() + ".compat-mode", """ Enable compat mode ONLY if Citizens or NPC plugins using real entity has installed, Compat mode fixed visible issue with player type NPCs of Citizens, But still recommend to use packet based / virtual entity NPC plugin, e.g. ZNPC Plus, Adyeshach, Fancy NPC or else.""", diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/SparklyPaperParallelWorldTicking.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/SparklyPaperParallelWorldTicking.java index 811cb169..1c1c4efc 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/SparklyPaperParallelWorldTicking.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/async/SparklyPaperParallelWorldTicking.java @@ -20,8 +20,7 @@ public class SparklyPaperParallelWorldTicking extends ConfigModules { @Override public void onLoaded() { - config.addCommentRegionBased(getBasePath(), - """ + config.addCommentRegionBased(getBasePath(), """ **Experimental feature** Enables parallel world ticking to improve performance on multi-core systems.""", """ diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/gameplay/SmoothTeleport.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/gameplay/SmoothTeleport.java index fb739c28..b9e6dfca 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/gameplay/SmoothTeleport.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/gameplay/SmoothTeleport.java @@ -15,8 +15,7 @@ public class SmoothTeleport extends ConfigModules { @Override public void onLoaded() { - enabled = config.getBoolean(getBasePath(), enabled, config.pickStringRegionBased( - """ + enabled = config.getBoolean(getBasePath(), enabled, config.pickStringRegionBased(""" **Experimental feature** Whether to make a "smooth teleport" when players changing dimension. This requires original world and target world have same logical height to work.""", diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/network/ChatMessageSignature.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/network/ChatMessageSignature.java index 08e6a5e0..2abfda55 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/network/ChatMessageSignature.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/network/ChatMessageSignature.java @@ -17,8 +17,7 @@ public class ChatMessageSignature extends ConfigModules { Whether or not enable chat message signature, disable will prevent players to report chat messages. And also disables the popup when joining a server without - 'secure chat', such as offline-mode servers. - """, + 'secure chat', such as offline-mode servers.""", """ 是否启用聊天签名, 禁用后玩家无法进行聊天举报.""")); } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/network/OptimizeNonFlushPacketSending.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/network/OptimizeNonFlushPacketSending.java index 1bf43512..6855d709 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/network/OptimizeNonFlushPacketSending.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/network/OptimizeNonFlushPacketSending.java @@ -20,8 +20,7 @@ public class OptimizeNonFlushPacketSending extends ConfigModules { Optimizes non-flush packet sending by using Netty's lazyExecute method to avoid expensive thread wakeup calls when scheduling packet operations. - Requires server restart to take effect. - """, + Requires server restart to take effect.""", """ 警告: 此选项与 ProtocolLib 不兼容, 并可能导致与其他修改数据包 处理的插件出现问题. @@ -29,7 +28,6 @@ public class OptimizeNonFlushPacketSending extends ConfigModules { 通过使用 Netty 的 lazyExecute 方法来优化非刷新数据包的发送, 避免在调度数据包操作时进行昂贵的线程唤醒调用. - 需要重启服务器才能生效. - """)); + 需要重启服务器才能生效.""")); } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/DontSaveEntity.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/DontSaveEntity.java index 903f1776..4e3323a8 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/DontSaveEntity.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/DontSaveEntity.java @@ -15,8 +15,7 @@ public class DontSaveEntity extends ConfigModules { @Override public void onLoaded() { dontSavePrimedTNT = config.getBoolean(getBasePath() + ".dont-save-primed-tnt", dontSavePrimedTNT, - config.pickStringRegionBased( - """ + config.pickStringRegionBased(""" Disable save primed tnt on chunk unloads. Useful for redstone/technical servers, can prevent machines from being exploded by TNT, when player disconnected caused by Internet issue.""", diff --git a/leaf-server/src/main/java/org/dreeam/leaf/util/map/BlockPosIterator.java b/leaf-server/src/main/java/org/dreeam/leaf/util/map/BlockPosIterator.java index bf269d54..b867cc3b 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/util/map/BlockPosIterator.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/util/map/BlockPosIterator.java @@ -11,6 +11,7 @@ import org.jspecify.annotations.Nullable; @NullMarked public final class BlockPosIterator extends AbstractIterator { + private final int startX; private final int startY; private final int startZ; diff --git a/leaf-server/src/main/java/org/dreeam/leaf/util/map/spottedleaf/LeafConcurrentLong2ReferenceChainedHashTable.java b/leaf-server/src/main/java/org/dreeam/leaf/util/map/spottedleaf/LeafConcurrentLong2ReferenceChainedHashTable.java index 2e6719b8..27698be1 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/util/map/spottedleaf/LeafConcurrentLong2ReferenceChainedHashTable.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/util/map/spottedleaf/LeafConcurrentLong2ReferenceChainedHashTable.java @@ -8,12 +8,18 @@ import ca.spottedleaf.concurrentutil.util.ThrowUtil; import ca.spottedleaf.concurrentutil.util.Validate; import java.lang.invoke.VarHandle; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.PrimitiveIterator; +import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.LongAdder; import java.util.function.BiFunction; import java.util.function.Consumer; -import java.util.function.Function; import java.util.function.LongConsumer; import java.util.function.LongFunction; import java.util.function.Predicate; @@ -47,8 +53,9 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable protected static final int DEFAULT_CAPACITY = 16; protected static final float DEFAULT_LOAD_FACTOR = 0.75f; - /** The maximum capacity, used if a higher value is implicitly specified by either - * of the constructors with arguments. MUST be a power of two <= 1<<30. + /** + * The maximum capacity, used if a higher value is implicitly specified by either + * of the constructors with arguments. MUST be a power of two <= 1<<30. */ protected static final int MAXIMUM_CAPACITY = 1 << 30; // 2^30 @@ -57,13 +64,19 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable // --- Instance Fields --- - /** Tracks the number of mappings, using LongAdder for better high-contention performance. */ + /** + * Tracks the number of mappings, using LongAdder for better high-contention performance. + */ protected final LongAdder size = new LongAdder(); - /** The load factor for the hash table. */ + /** + * The load factor for the hash table. + */ protected final float loadFactor; - /** The hash table array. Elements are accessed using VarHandles. */ + /** + * The hash table array. Elements are accessed using VarHandles. + */ protected volatile TableEntry[] table; /** @@ -75,6 +88,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable // --- VarHandles --- protected static final VarHandle THRESHOLD_HANDLE; + static { try { THRESHOLD_HANDLE = ConcurrentUtil.getVarHandle(LeafConcurrentLong2ReferenceChainedHashTable.class, "threshold", int.class); @@ -135,7 +149,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable /** * Creates a new, empty map with the specified initial capacity and load factor. * - * @param capacity The initial capacity. + * @param capacity The initial capacity. * @param loadFactor The load factor threshold. * @throws IllegalArgumentException if the initial capacity is negative or the load factor is non-positive/NaN. */ @@ -158,7 +172,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * Creates a new, empty map with an initial capacity sufficient to hold the specified number of elements * without resizing, using the specified load factor. * - * @param expected The expected number of elements. + * @param expected The expected number of elements. * @param loadFactor The load factor threshold. * @throws IllegalArgumentException if the expected size is negative or the load factor is non-positive/NaN. */ @@ -176,7 +190,9 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable // --- Internal Helper Methods --- - /** Calculates the target resize threshold. */ + /** + * Calculates the target resize threshold. + */ protected static int getTargetThreshold(final int capacity, final float loadFactor) { if (capacity >= MAXIMUM_CAPACITY) { return THRESHOLD_NO_RESIZE; // Max capacity reached, no more resizing @@ -191,7 +207,9 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable } - /** Calculates the power-of-two capacity for a given initial capacity request. */ + /** + * Calculates the power-of-two capacity for a given initial capacity request. + */ protected static int getCapacityFor(final int requestedCapacity) { if (requestedCapacity <= 0) { // Default capacity if non-positive requested, could also throw exception @@ -204,12 +222,16 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable return IntegerUtil.roundCeilLog2(Math.max(DEFAULT_CAPACITY, requestedCapacity)); } - /** Computes the hash code for the key. Uses mixing to spread keys more evenly. */ + /** + * Computes the hash code for the key. Uses mixing to spread keys more evenly. + */ protected static int getHash(final long key) { return (int) HashUtil.mix(key); // Assumes HashUtil.mix provides good distribution } - /** Returns the load factor associated with this map. */ + /** + * Returns the load factor associated with this map. + */ public final float getLoadFactor() { return this.loadFactor; } @@ -269,7 +291,6 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * Returns null if the key is not found. * The returned node's value might be null if it's a placeholder during a compute operation. */ - @SuppressWarnings("unchecked") protected final TableEntry getNode(final long key) { final int hash = getHash(key); TableEntry[] currentTable = this.table; // Volatile read @@ -364,7 +385,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * Returns the value to which the specified key is mapped, or * {@code defaultValue} if this map contains no mapping for the key. * - * @param key the key whose associated value is to be returned + * @param key the key whose associated value is to be returned * @param defaultValue the default mapping of the key * @return the value mapped to the key, or {@code defaultValue} if none */ @@ -405,7 +426,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable TableEntry node; while ((node = iterator.findNext()) != null) { // findNext safely iterates through nodes V nodeValue = node.getValueVolatile(); // Volatile read for visibility - if (nodeValue != null && value.equals(nodeValue)) { + if (value.equals(nodeValue)) { return true; } } @@ -541,10 +562,12 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable int hash = getHash(current.key); if ((hash & oldCapacity) == 0) { // Low bin (index i) - if (lowT == null) lowH = current; else lowT.setNextPlain(current); + if (lowT == null) lowH = current; + else lowT.setNextPlain(current); lowT = current; } else { // High bin (index i + oldCapacity) - if (highT == null) highH = current; else highT.setNextPlain(current); + if (highT == null) highH = current; + else highT.setNextPlain(current); highT = current; } current = next; @@ -575,20 +598,24 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with {@code key}, or - * {@code null} if there was no mapping for {@code key}. + * {@code null} if there was no mapping for {@code key}. * @throws NullPointerException if the specified value is null */ public V put(final long key, final V value) { Validate.notNull(value, "Value may not be null"); final int hash = getHash(key); - int sizeDelta = 0; - V oldValue = null; + int sizeDelta; + V oldValue; TableEntry[] currentTable = this.table; table_loop: for (;;) { final int tableLength = currentTable.length; - if (tableLength == 0) { currentTable = this.table; if (currentTable.length == 0) continue; } // Init check + // Init check + if (tableLength == 0) { + currentTable = this.table; + if (currentTable.length == 0) continue; + } final int index = hash & (tableLength - 1); TableEntry head = getAtIndexVolatile(currentTable, index); @@ -653,8 +680,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable sizeDelta = 1; oldValue = null; } else { - // Should not happen if head was non-null/non-marker. Retry. - continue table_loop; + continue table_loop; // Should not happen if head was non-null/non-marker. Retry. } } // End synchronized break table_loop; // Operation completed within lock @@ -674,20 +700,23 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with the specified key, or - * {@code null} if there was no mapping for the key. + * {@code null} if there was no mapping for the key. * @throws NullPointerException if the specified value is null */ public V putIfAbsent(final long key, final V value) { Validate.notNull(value, "Value may not be null"); final int hash = getHash(key); int sizeDelta = 0; - V existingValue = null; + V existingValue; TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; - if (tableLength == 0) { currentTable = this.table; continue; } + if (tableLength == 0) { + currentTable = this.table; + continue; + } final int index = hash & (tableLength - 1); TableEntry head = getAtIndexVolatile(currentTable, index); @@ -710,7 +739,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable // Case 3: Lock-free check (optimistic) TableEntry node = head; - while(node != null) { + while (node != null) { if (node.key == key) { existingValue = node.getValueVolatile(); // Volatile read if (existingValue != null) { @@ -774,17 +803,17 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * @param key key with which the specified value is associated * @param value value to be associated with the specified key * @return the previous value associated with the specified key, or - * {@code null} if there was no mapping for the key. + * {@code null} if there was no mapping for the key. * @throws NullPointerException if the specified value is null */ public V replace(final long key, final V value) { Validate.notNull(value, "Value may not be null"); final int hash = getHash(key); - V oldValue = null; + V oldValue; TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; if (tableLength == 0) return null; @@ -859,7 +888,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; if (tableLength == 0) return false; @@ -922,7 +951,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * * @param key key whose mapping is to be removed from the map * @return the previous value associated with {@code key}, or - * {@code null} if there was no mapping for {@code key} + * {@code null} if there was no mapping for {@code key} */ public V remove(final long key) { final int hash = getHash(key); @@ -931,7 +960,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; if (tableLength == 0) return null; @@ -986,7 +1015,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable /** * Removes the entry for a key only if currently mapped to a given value. * - * @param key key with which the specified value is associated + * @param key key with which the specified value is associated * @param expect value expected to be associated with the specified key * @return {@code true} if the value was removed */ @@ -997,7 +1026,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; if (tableLength == 0) return false; @@ -1056,10 +1085,10 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable /** * Removes the entry for the specified key only if its value satisfies the given predicate. * - * @param key key whose mapping is to be removed from the map + * @param key key whose mapping is to be removed from the map * @param predicate the predicate to apply to the value associated with the key * @return the value associated with the key before removal if the predicate was satisfied and the entry was removed, - * otherwise {@code null}. + * otherwise {@code null}. * @throws NullPointerException if the specified predicate is null */ public V removeIf(final long key, final Predicate predicate) { @@ -1071,7 +1100,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; if (tableLength == 0) return null; @@ -1134,7 +1163,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * (or {@code null} if there is no current mapping). The function is * applied atomically. * - * @param key key with which the specified value is to be associated + * @param key key with which the specified value is to be associated * @param function the function to compute a value * @return the new value associated with the specified key, or null if none * @throws NullPointerException if the specified function is null @@ -1143,13 +1172,16 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable Validate.notNull(function, "Function cannot be null"); final int hash = getHash(key); int sizeDelta = 0; - V finalValue = null; + V finalValue; TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; - if (tableLength == 0) { currentTable = this.table; continue; } + if (tableLength == 0) { + currentTable = this.table; + continue; + } final int index = hash & (tableLength - 1); TableEntry head = getAtIndexVolatile(currentTable, index); @@ -1162,7 +1194,10 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable if (getAtIndexVolatile(currentTable, index) == null) { // Re-check bin try { computedValue = function.apply(key, null); // Compute with null old value - } catch (Throwable t) { ThrowUtil.throwUnchecked(t); return null; } + } catch (Throwable t) { + ThrowUtil.throwUnchecked(t); + return null; + } if (computedValue != null) { placeholder.setValuePlain(computedValue); // Set value before CAS @@ -1205,7 +1240,10 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable V computedValue; try { computedValue = function.apply(key, oldValue); - } catch (Throwable t) { ThrowUtil.throwUnchecked(t); return null; } + } catch (Throwable t) { + ThrowUtil.throwUnchecked(t); + return null; + } if (computedValue != null) { node.setValueVolatile(computedValue); // Update value (volatile write) @@ -1229,7 +1267,10 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable V computedValue; try { computedValue = function.apply(key, null); - } catch (Throwable t) { ThrowUtil.throwUnchecked(t); return null; } + } catch (Throwable t) { + ThrowUtil.throwUnchecked(t); + return null; + } if (computedValue != null) { // Add new mapping @@ -1237,7 +1278,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable sizeDelta = 1; TableEntry newNode = new TableEntry<>(key, computedValue); if (prev != null) prev.setNextRelease(newNode); // Release write - else { continue table_loop; } // Should not happen + else continue table_loop; // Should not happen } else { finalValue = null; sizeDelta = 0; @@ -1257,23 +1298,26 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * compute its value using the given mapping function and enters it into * this map unless {@code null}. * - * @param key key with which the specified value is to be associated + * @param key key with which the specified value is to be associated * @param function the function to compute a value * @return the current (existing or computed) value associated with the specified key, - * or null if the computed value is null + * or null if the computed value is null * @throws NullPointerException if the specified function is null */ public V computeIfAbsent(final long key, final LongFunction function) { Validate.notNull(function, "Function cannot be null"); final int hash = getHash(key); int sizeDelta = 0; - V finalValue = null; + V finalValue; TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; - if (tableLength == 0) { currentTable = this.table; continue; } + if (tableLength == 0) { + currentTable = this.table; + continue; + } final int index = hash & (tableLength - 1); TableEntry head = getAtIndexVolatile(currentTable, index); @@ -1286,7 +1330,10 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable if (getAtIndexVolatile(currentTable, index) == null) { try { computedValue = function.apply(key); - } catch (Throwable t) { ThrowUtil.throwUnchecked(t); return null; } + } catch (Throwable t) { + ThrowUtil.throwUnchecked(t); + return null; + } if (computedValue != null) { placeholder.setValuePlain(computedValue); @@ -1344,7 +1391,10 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable V computedValue; try { computedValue = function.apply(key); - } catch (Throwable t) { ThrowUtil.throwUnchecked(t); return null; } + } catch (Throwable t) { + ThrowUtil.throwUnchecked(t); + return null; + } if (computedValue != null) { node.setValueVolatile(computedValue); // Volatile write @@ -1364,14 +1414,17 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable V computedValue; try { computedValue = function.apply(key); - } catch (Throwable t) { ThrowUtil.throwUnchecked(t); return null; } + } catch (Throwable t) { + ThrowUtil.throwUnchecked(t); + return null; + } if (computedValue != null) { finalValue = computedValue; sizeDelta = 1; TableEntry newNode = new TableEntry<>(key, computedValue); if (prev != null) prev.setNextRelease(newNode); // Release write - else { continue table_loop; } // Should not happen + else continue table_loop; // Should not happen } else { finalValue = null; sizeDelta = 0; @@ -1389,7 +1442,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * If the value for the specified key is present, attempts to compute a new * mapping given the key and its current mapped value. * - * @param key key with which the specified value is to be associated + * @param key key with which the specified value is to be associated * @param function the function to compute a value * @return the new value associated with the specified key, or null if none * @throws NullPointerException if the specified function is null @@ -1397,12 +1450,12 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable public V computeIfPresent(final long key, final BiLong1Function function) { Validate.notNull(function, "Function cannot be null"); final int hash = getHash(key); - int sizeDelta = 0; - V finalValue = null; + int sizeDelta; + V finalValue; TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; if (tableLength == 0) return null; @@ -1432,7 +1485,10 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable V computedValue; try { computedValue = function.apply(key, oldValue); - } catch (Throwable t) { ThrowUtil.throwUnchecked(t); return null; } + } catch (Throwable t) { + ThrowUtil.throwUnchecked(t); + return null; + } if (computedValue != null) { node.setValueVolatile(computedValue); // Update (volatile write) @@ -1474,25 +1530,28 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable * Otherwise, replaces the associated value with the results of the given * remapping function, or removes if the result is {@code null}. * - * @param key key with which the resulting value is to be associated - * @param value the non-null value to be merged with the existing value + * @param key key with which the resulting value is to be associated + * @param value the non-null value to be merged with the existing value * @param function the function to recompute a value if present * @return the new value associated with the specified key, or null if no - * value is associated with the key + * value is associated with the key * @throws NullPointerException if the specified value or function is null */ public V merge(final long key, final V value, final BiFunction function) { Validate.notNull(value, "Value cannot be null"); Validate.notNull(function, "Function cannot be null"); final int hash = getHash(key); - int sizeDelta = 0; - V finalValue = null; + int sizeDelta; + V finalValue; TableEntry[] currentTable = this.table; table_loop: - for(;;) { + for (;;) { final int tableLength = currentTable.length; - if (tableLength == 0) { currentTable = this.table; continue; } + if (tableLength == 0) { + currentTable = this.table; + continue; + } final int index = hash & (tableLength - 1); TableEntry head = getAtIndexVolatile(currentTable, index); @@ -1531,7 +1590,10 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable if (oldValue != null) { try { computedValue = function.apply(oldValue, value); // Apply function - } catch (Throwable t) { ThrowUtil.throwUnchecked(t); return null; } + } catch (Throwable t) { + ThrowUtil.throwUnchecked(t); + return null; + } } else { computedValue = value; // Use provided value if old was placeholder } @@ -1559,7 +1621,7 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable sizeDelta = 1; TableEntry newNode = new TableEntry<>(key, value); if (prev != null) prev.setNextRelease(newNode); // Release write - else { continue table_loop; } // Should not happen + else continue table_loop; // Should not happen break table_loop; // Done } // End synchronized(head) } // End table_loop @@ -1612,17 +1674,34 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable // --- Iterators and Views --- - /** Returns an iterator over the map entries. */ - public Iterator> entryIterator() { return new EntryIterator<>(this); } + /** + * Returns an iterator over the map entries. + */ + public Iterator> entryIterator() { + return new EntryIterator<>(this); + } - /** Returns an iterator over the map entries (implements Iterable). */ - @Override public final Iterator> iterator() { return this.entryIterator(); } + /** + * Returns an iterator over the map entries (implements Iterable). + */ + @Override + public final Iterator> iterator() { + return this.entryIterator(); + } - /** Returns an iterator over the keys. */ - public PrimitiveIterator.OfLong keyIterator() { return new KeyIterator<>(this); } + /** + * Returns an iterator over the keys. + */ + public PrimitiveIterator.OfLong keyIterator() { + return new KeyIterator<>(this); + } - /** Returns an iterator over the values. */ - public Iterator valueIterator() { return new ValueIterator<>(this); } + /** + * Returns an iterator over the values. + */ + public Iterator valueIterator() { + return new ValueIterator<>(this); + } /** * Returns a {@link Collection} view of the values contained in this map. @@ -1666,52 +1745,95 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable private volatile TableEntry next; private final boolean resizeMarker; - /** Constructor for regular map entries. */ + /** + * Constructor for regular map entries. + */ TableEntry(final long key, final V value) { this(key, value, false); } - /** Constructor for potentially creating resize markers. */ + /** + * Constructor for potentially creating resize markers. + */ TableEntry(final long key, final V value, final boolean resize) { this.key = key; this.resizeMarker = resize; this.setValuePlain(value); // Initial plain set } - public long getKey() { return this.key; } - public V getValue() { return getValueVolatile(); } + public long getKey() { + return this.key; + } + + public V getValue() { + return getValueVolatile(); + } public V setValue(V newValue) { throw new UnsupportedOperationException("Direct setValue on TableEntry is not supported; use map methods."); } - @SuppressWarnings("unchecked") final V getValuePlain() { return (V) VALUE_HANDLE.get(this); } - @SuppressWarnings("unchecked") final V getValueAcquire() { return (V) VALUE_HANDLE.getAcquire(this); } - @SuppressWarnings("unchecked") final V getValueVolatile() { return (V) VALUE_HANDLE.getVolatile(this); } - - final void setValuePlain(final V value) { VALUE_HANDLE.set(this, value); } - final void setValueRelease(final V value) { VALUE_HANDLE.setRelease(this, value); } - final void setValueVolatile(final V value) { VALUE_HANDLE.setVolatile(this, value); } + @SuppressWarnings("unchecked") + V getValuePlain() { + return (V) VALUE_HANDLE.get(this); + } @SuppressWarnings("unchecked") - final boolean compareAndSetValueVolatile(final V expect, final V update) { + V getValueAcquire() { + return (V) VALUE_HANDLE.getAcquire(this); + } + + @SuppressWarnings("unchecked") + V getValueVolatile() { + return (V) VALUE_HANDLE.getVolatile(this); + } + + void setValuePlain(final V value) { + VALUE_HANDLE.set(this, value); + } + + void setValueRelease(final V value) { + VALUE_HANDLE.setRelease(this, value); + } + + void setValueVolatile(final V value) { + VALUE_HANDLE.setVolatile(this, value); + } + + boolean compareAndSetValueVolatile(final V expect, final V update) { return VALUE_HANDLE.compareAndSet(this, expect, update); } - @SuppressWarnings("unchecked") final TableEntry getNextPlain() { return (TableEntry) NEXT_HANDLE.get(this); } - @SuppressWarnings("unchecked") final TableEntry getNextVolatile() { return (TableEntry) NEXT_HANDLE.getVolatile(this); } + @SuppressWarnings("unchecked") + TableEntry getNextPlain() { + return (TableEntry) NEXT_HANDLE.get(this); + } - final void setNextPlain(final TableEntry next) { NEXT_HANDLE.set(this, next); } - final void setNextRelease(final TableEntry next) { NEXT_HANDLE.setRelease(this, next); } - final void setNextVolatile(final TableEntry next) { NEXT_HANDLE.setVolatile(this, next); } + @SuppressWarnings("unchecked") + TableEntry getNextVolatile() { + return (TableEntry) NEXT_HANDLE.getVolatile(this); + } - final boolean isResizeMarker() { return this.resizeMarker; } + void setNextPlain(final TableEntry next) { + NEXT_HANDLE.set(this, next); + } + + void setNextRelease(final TableEntry next) { + NEXT_HANDLE.setRelease(this, next); + } + + void setNextVolatile(final TableEntry next) { + NEXT_HANDLE.setVolatile(this, next); + } + + boolean isResizeMarker() { + return this.resizeMarker; + } @Override public boolean equals(Object o) { if (this == o) return true; - if (o == null || !(o instanceof LeafConcurrentLong2ReferenceChainedHashTable.TableEntry)) return false; - TableEntry that = (TableEntry) o; + if (!(o instanceof TableEntry that)) return false; return key == that.key && Objects.equals(getValueVolatile(), that.getValueVolatile()); // Use volatile read for value } @@ -1824,7 +1946,9 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable return this.nextNode != null; } - /** Internal method to get the next node and advance. */ + /** + * Internal method to get the next node and advance. + */ final TableEntry findNext() { TableEntry e = this.nextNode; if (e == null) { @@ -1847,7 +1971,9 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable this.lastReturned = null; } - /** Gets the next node, updates lastReturned, advances iterator. */ + /** + * Gets the next node, updates lastReturned, advances iterator. + */ protected final TableEntry nextNode() throws NoSuchElementException { TableEntry node = this.nextNode; // Node pre-fetched by advance() if (node == null) { @@ -1880,35 +2006,48 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable } } - /** Iterator over map entries (TableEntry objects). */ + /** + * Iterator over map entries (TableEntry objects). + */ protected static final class EntryIterator extends BaseIteratorImpl> { - EntryIterator(final LeafConcurrentLong2ReferenceChainedHashTable map) { super(map); } + EntryIterator(final LeafConcurrentLong2ReferenceChainedHashTable map) { + super(map); + } - @Override public TableEntry next() throws NoSuchElementException { + @Override + public TableEntry next() throws NoSuchElementException { return nextNode(); } } - /** Iterator over map keys (long primitives). */ + /** + * Iterator over map keys (long primitives). + */ protected static final class KeyIterator extends BaseIteratorImpl implements PrimitiveIterator.OfLong { - KeyIterator(final LeafConcurrentLong2ReferenceChainedHashTable map) { super(map); } + KeyIterator(final LeafConcurrentLong2ReferenceChainedHashTable map) { + super(map); + } - @Override public long nextLong() throws NoSuchElementException { + @Override + public long nextLong() throws NoSuchElementException { return nextNode().key; } - @Override public Long next() throws NoSuchElementException { + @Override + public Long next() throws NoSuchElementException { return nextLong(); // Autoboxing } - @Override public void forEachRemaining(final LongConsumer action) { + @Override + public void forEachRemaining(final LongConsumer action) { Validate.notNull(action, "Action may not be null"); while (hasNext()) { action.accept(nextLong()); } } - @Override public void forEachRemaining(final Consumer action) { + @Override + public void forEachRemaining(final Consumer action) { if (action instanceof LongConsumer) { forEachRemaining((LongConsumer) action); } else { @@ -1920,18 +2059,25 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable } } - /** Iterator over map values. */ + /** + * Iterator over map values. + */ protected static final class ValueIterator extends BaseIteratorImpl { - ValueIterator(final LeafConcurrentLong2ReferenceChainedHashTable map) { super(map); } + ValueIterator(final LeafConcurrentLong2ReferenceChainedHashTable map) { + super(map); + } - @Override public V next() throws NoSuchElementException { + @Override + public V next() throws NoSuchElementException { return nextNode().getValueVolatile(); // Volatile read for value } } // --- Collection Views --- - /** Base class for Collection views (Values, EntrySet). */ + /** + * Base class for Collection views (Values, EntrySet). + */ protected static abstract class BaseCollection implements Collection { protected final LeafConcurrentLong2ReferenceChainedHashTable map; @@ -1939,11 +2085,21 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable this.map = Validate.notNull(map); } - @Override public int size() { return map.size(); } - @Override public boolean isEmpty() { return map.isEmpty(); } - @Override public abstract boolean contains(Object o); // Subclass responsibility + @Override + public int size() { + return map.size(); + } - @Override public boolean containsAll(Collection c) { + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public abstract boolean contains(Object o); // Subclass responsibility + + @Override + public boolean containsAll(Collection c) { Validate.notNull(c); for (Object e : c) { if (!contains(e)) return false; @@ -1951,13 +2107,14 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable return true; } - @Override public Object[] toArray() { + @Override + public Object[] toArray() { List list = new ArrayList<>(map.size()); for (E e : this) list.add(e); // Uses iterator() from subclass return list.toArray(); } - @Override @SuppressWarnings("unchecked") + @Override public T[] toArray(T[] a) { Validate.notNull(a); List list = new ArrayList<>(map.size()); @@ -1965,11 +2122,23 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable return list.toArray(a); } - @Override public void clear() { map.clear(); } - @Override public boolean add(E e) { throw new UnsupportedOperationException(); } - @Override public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } + @Override + public void clear() { + map.clear(); + } - @Override public boolean remove(Object o) { + @Override + public boolean add(E e) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { Iterator it = iterator(); // Subclass provides iterator while (it.hasNext()) { if (Objects.equals(o, it.next())) { @@ -1980,7 +2149,8 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable return false; } - @Override public boolean removeAll(Collection c) { + @Override + public boolean removeAll(Collection c) { Validate.notNull(c); boolean modified = false; Iterator it = iterator(); @@ -1993,7 +2163,8 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable return modified; } - @Override public boolean retainAll(Collection c) { + @Override + public boolean retainAll(Collection c) { Validate.notNull(c); boolean modified = false; Iterator it = iterator(); @@ -2006,7 +2177,8 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable return modified; } - @Override public boolean removeIf(Predicate filter) { + @Override + public boolean removeIf(Predicate filter) { Validate.notNull(filter); boolean removed = false; Iterator it = iterator(); @@ -2019,19 +2191,21 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable return removed; } - @Override public String toString() { + @Override + public String toString() { Iterator it = iterator(); - if (! it.hasNext()) return "[]"; + if (!it.hasNext()) return "[]"; StringBuilder sb = new StringBuilder("["); for (;;) { E e = it.next(); sb.append(e == this ? "(this Collection)" : e); - if (! it.hasNext()) return sb.append(']').toString(); + if (!it.hasNext()) return sb.append(']').toString(); sb.append(',').append(' '); } } - @Override public void forEach(Consumer action) { + @Override + public void forEach(Consumer action) { Validate.notNull(action); for (E e : this) { // Uses iterator() from subclass action.accept(e); @@ -2039,46 +2213,64 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable } } - /** Collection view for the map's values. */ + /** + * Collection view for the map's values. + */ protected static final class Values extends BaseCollection { - Values(LeafConcurrentLong2ReferenceChainedHashTable map) { super(map); } - - @Override public boolean contains(Object o) { - try { - return o != null && map.containsValue((V)o); - } catch (ClassCastException cce) { return false; } + Values(LeafConcurrentLong2ReferenceChainedHashTable map) { + super(map); } - @Override public Iterator iterator() { return map.valueIterator(); } + @Override + public boolean contains(Object o) { + try { + return o != null && map.containsValue((V) o); + } catch (ClassCastException cce) { + return false; + } + } + + @Override + public Iterator iterator() { + return map.valueIterator(); + } } - /** Set view for the map's entries (TableEntry objects). */ + /** + * Set view for the map's entries (TableEntry objects). + */ protected static final class EntrySet extends BaseCollection> implements Set> { - EntrySet(LeafConcurrentLong2ReferenceChainedHashTable map) { super(map); } + EntrySet(LeafConcurrentLong2ReferenceChainedHashTable map) { + super(map); + } - @Override public boolean contains(Object o) { - if (!(o instanceof LeafConcurrentLong2ReferenceChainedHashTable.TableEntry)) return false; - TableEntry entry = (TableEntry) o; + @Override + public boolean contains(Object o) { + if (!(o instanceof LeafConcurrentLong2ReferenceChainedHashTable.TableEntry entry)) return false; V mappedValue = map.get(entry.getKey()); // Concurrent read // Use volatile read on entry's value for consistent comparison return mappedValue != null && Objects.equals(mappedValue, entry.getValueVolatile()); } - @Override public Iterator> iterator() { return map.entryIterator(); } + @Override + public Iterator> iterator() { + return map.entryIterator(); + } - @Override public boolean remove(Object o) { - if (!(o instanceof LeafConcurrentLong2ReferenceChainedHashTable.TableEntry)) return false; - TableEntry entry = (TableEntry) o; + @Override + public boolean remove(Object o) { + if (!(o instanceof LeafConcurrentLong2ReferenceChainedHashTable.TableEntry entry)) return false; try { // Use map's atomic remove(key, value) // Use volatile read for the expected value - return map.remove(entry.getKey(), (V)entry.getValueVolatile()); - } catch(ClassCastException | NullPointerException cce) { // Handle potential type/null issues + return map.remove(entry.getKey(), (V) entry.getValueVolatile()); + } catch (ClassCastException | NullPointerException cce) { // Handle potential type/null issues return false; } } - @Override public int hashCode() { + @Override + public int hashCode() { int h = 0; for (TableEntry e : this) { h += e.hashCode(); // Uses entry's hashCode @@ -2086,10 +2278,10 @@ public class LeafConcurrentLong2ReferenceChainedHashTable implements Iterable return h; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { if (o == this) return true; - if (!(o instanceof Set)) return false; - Set c = (Set) o; + if (!(o instanceof Set c)) return false; if (c.size() != size()) return false; try { // relies on containsAll checking entry equality correctly diff --git a/leaf-server/src/main/java/org/dreeam/leaf/util/queue/SpscIntQueue.java b/leaf-server/src/main/java/org/dreeam/leaf/util/queue/SpscIntQueue.java index 9afc72df..3368c34e 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/util/queue/SpscIntQueue.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/util/queue/SpscIntQueue.java @@ -2,6 +2,7 @@ package org.dreeam.leaf.util.queue; /// Lock-free Single Producer Single Consumer Queue public class SpscIntQueue { + private final int[] data; private final PaddedAtomicInteger producerIdx = new PaddedAtomicInteger(); private final PaddedAtomicInteger producerCachedIdx = new PaddedAtomicInteger();