9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-19 15:09:25 +00:00

Async Data Read for Parallel World Ticking (#333)

* initial

* improve compat further

* cleanup and shit

* more cleanup

* rebase :3

* increase task queue size

* [ci skip] rebuild patches

* Optimise BlockEntity tickersInLevel

* rebase

* [ci skip] cleanup

* cleanup

* cleanup

* clear the buffer at shutdown

---------

Co-authored-by: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com>
Co-authored-by: hayanesuru <hayanesuru@outlook.jp>
This commit is contained in:
Taiyou
2025-06-02 19:18:29 +02:00
committed by GitHub
parent 2fd5e7bc12
commit bec3d4c63b
11 changed files with 1356 additions and 293 deletions

View File

@@ -265,7 +265,7 @@ index 5ab2c8333178335515e619b87ae420f948c83bd1..be3b2f023897a8823560ee059cb16ec9
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11b57ae175 100644
index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..7f791ff5bdf6c29c78f863d21af16270a74d8e7e 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -291,6 +291,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -326,7 +326,20 @@ index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11
}
@Override
@@ -1677,6 +1690,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -923,6 +936,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
serverLevel.save(null, flush, serverLevel.noSave && !forced, close); // Paper - add close param
+ // Leaf start - SparklyPaper - parallel world ticking - Shutdown handling for async reads
+ // Only prepare shutdown if 'close' is true, indicating this save is part of server shutdown
+ if (close && org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) {
+ serverLevel.prepareShutdown();
+ }
+ // Leaf end - SparklyPaper - parallel world ticking - Shutdown handling for async reads
flag = true;
}
@@ -1677,6 +1696,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}
@@ -345,7 +358,7 @@ index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11
protected void tickChildren(BooleanSupplier hasTimeLeft) {
this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing());
this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit
@@ -1743,28 +1768,50 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1743,28 +1774,50 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
this.isIteratingOverLevels = true; // Paper - Throw exception on world create while being ticked
@@ -414,7 +427,7 @@ index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
this.tickConnection();
@@ -1844,6 +1891,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1844,6 +1897,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
Map<ResourceKey<Level>, ServerLevel> oldLevels = this.levels;
Map<ResourceKey<Level>, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels);
newLevels.remove(level.dimension());
@@ -568,7 +581,7 @@ index d4048661575ebfaf128ba25da365843774364e0e..33dd16a26edd2974f04d9a868d3e58e8
// Gale start - Pufferfish - SIMD support
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d08e18122 100644
index a66e5f6652d9633c856490de36d8d8fdf8a5298a..d6524d5c442555eaeb4d90f6a101262ee669f0d9 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -182,7 +182,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -580,23 +593,173 @@ index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d
// Paper - rewrite chunk system
private final GameEventDispatcher gameEventDispatcher;
public boolean noSave;
@@ -208,6 +208,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -208,7 +208,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private double preciseTime; // Purpur - Configurable daylight cycle
private boolean forceTime; // Purpur - Configurable daylight cycle
private final RandomSequences randomSequences;
-
+ public java.util.concurrent.ExecutorService tickExecutor; // SparklyPaper - parallel world ticking
+ public final java.util.concurrent.ConcurrentLinkedQueue<org.dreeam.leaf.async.world.WorldReadRequest> asyncReadRequestQueue = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Leaf - SparklyPaper - parallel world ticking
+ private volatile boolean isShuttingDown = false; // Leaf - SparklyPaper - parallel world ticking - Shutdown handling for async reads
// CraftBukkit start
public final LevelStorageSource.LevelStorageAccess levelStorageAccess;
@@ -703,6 +704,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public final UUID uuid;
@@ -703,8 +705,26 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle
this.realPlayers = Lists.newArrayList(); // Leaves - skip
+ this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new org.dreeam.leaf.async.world.SparklyPaperServerLevelTickExecutorThreadFactory(getWorld().getName())); // SparklyPaper - parallel world ticking
+ }
+
+ // Leaf start - SparklyPaper - parallel world ticking - Shutdown handling for async reads
+ public boolean isShuttingDown() {
+ return this.isShuttingDown;
}
+ public void prepareShutdown() {
+ this.isShuttingDown = true;
+ org.dreeam.leaf.async.world.WorldReadRequest req;
+ int clearedRequests = 0;
+ while ((req = this.asyncReadRequestQueue.poll()) != null) {
+ req.future().completeExceptionally(new IllegalStateException("World " + this.getWorld().getName() + " is shutting down. Cannot process buffered read: " + req.type()));
+ clearedRequests++;
+ }
+ if (clearedRequests > 0) MinecraftServer.LOGGER.info("PWT: Cleared " + clearedRequests + " pending async read requests for world " + this.getWorld().getName() + " during shutdown.");
+ }
+ // Leaf end - SparklyPaper - parallel world ticking - Shutdown handling for async reads
+
// Paper start
@@ -1313,9 +1315,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public boolean hasChunk(int chunkX, int chunkZ) {
@@ -737,8 +757,112 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public Player[] eligibleDespawnCheckingPlayerCache = new Player[0]; // Leaf - Cache eligible players for despawn checks
+ // Leaf start - SparklyPaper - parallel world ticking
+ private void processAsyncReadRequests() {
+ // Only process if parallel ticking is enabled and buffering is active
+ if (!org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled ||
+ !org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.asyncUnsafeReadHandling.equals("BUFFERED")) {
+ // Clear queue if buffering gets disabled to prevent memory leaks
+ if (!this.asyncReadRequestQueue.isEmpty()) {
+ org.dreeam.leaf.async.world.WorldReadRequest req;
+ while ((req = this.asyncReadRequestQueue.poll()) != null) {
+ req.future().completeExceptionally(new IllegalStateException("Async read buffering disabled while request was pending."));
+ }
+ }
+ return;
+ }
+
+ org.dreeam.leaf.async.world.WorldReadRequest request;
+ int processed = 0;
+ // Limit processing per tick to avoid stalling the tick loop
+ int maxToProcess = 16384; // Consider making this configurable
+
+ while (processed < maxToProcess && (request = this.asyncReadRequestQueue.poll()) != null) {
+ processed++;
+ // Ensure we are on the correct thread before executing
+ // This check might be redundant if called correctly from tick(), but good for safety
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Processing async read request off-thread");
+
+ try {
+ Object result = executeReadRequest(request);
+ request.future().complete(result);
+ } catch (Throwable t) {
+ // Log the error from the tick thread side
+ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Exception processing buffered async world read for type " + request.type(), t);
+ request.future().completeExceptionally(t);
+ }
+ }
+ }
+
+ // Executes the actual read operation based on the request type
+ private Object executeReadRequest(org.dreeam.leaf.async.world.WorldReadRequest request) {
+ Object[] params = request.params();
+ BlockPos pos; // Declare pos outside the switch
+
+ switch (request.type()) {
+ case BLOCK_GET_NMS_STATE: { //
+ pos = (BlockPos) params[0];
+ return this.getBlockState(pos);
+ }
+ case BLOCK_GET_BIOME: {
+ pos = (BlockPos) params[0];
+ return this.getNoiseBiome(pos.getX() >> 2, pos.getY() >> 2, pos.getZ() >> 2);
+ }
+ case BLOCK_GET_COMPUTED_BIOME: {
+ pos = (BlockPos) params[0];
+ return this.getBiome(pos);
+ }
+ case BLOCK_IS_INDIRECTLY_POWERED: {
+ pos = (BlockPos) params[0];
+ return this.hasNeighborSignal(pos);
+ }
+ case BLOCK_GET_BLOCK_POWER: {
+ pos = (BlockPos) params[0];
+ org.bukkit.block.BlockFace face = (org.bukkit.block.BlockFace) params[1];
+ int power = 0;
+ Direction notchDir = org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(face);
+
+ if ((face == org.bukkit.block.BlockFace.DOWN || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.below(), Direction.DOWN)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.below()));
+ if ((face == org.bukkit.block.BlockFace.UP || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.above(), Direction.UP)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.above()));
+ if ((face == org.bukkit.block.BlockFace.EAST || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.east(), Direction.EAST)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.east()));
+ if ((face == org.bukkit.block.BlockFace.WEST || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.west(), Direction.WEST)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.west()));
+ if ((face == org.bukkit.block.BlockFace.NORTH || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.north(), Direction.NORTH)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.north()));
+ if ((face == org.bukkit.block.BlockFace.SOUTH || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.south(), Direction.SOUTH)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.south()));
+
+ boolean indirectlyPowered = (face == org.bukkit.block.BlockFace.SELF) ? this.hasNeighborSignal(pos) : (this.getSignal(pos, notchDir) > 0); // Simplified indirect check for faces
+ return power > 0 ? power : (indirectlyPowered ? 15 : 0);
+ }
+ case BLOCK_RAY_TRACE: {
+ pos = (BlockPos) params[0];
+ org.bukkit.Location start = (org.bukkit.Location) params[1];
+ org.bukkit.util.Vector direction = (org.bukkit.util.Vector) params[2];
+ double maxDistance = (double) params[3];
+ org.bukkit.FluidCollisionMode fluidCollisionMode = (org.bukkit.FluidCollisionMode) params[4];
+
+ org.bukkit.util.Vector dir = direction.clone().normalize().multiply(maxDistance);
+ Vec3 startPos = org.bukkit.craftbukkit.util.CraftLocation.toVec3D(start);
+ Vec3 endPos = startPos.add(dir.getX(), dir.getY(), dir.getZ());
+
+ return this.clip(new net.minecraft.world.level.ClipContext(startPos, endPos, net.minecraft.world.level.ClipContext.Block.OUTLINE, org.bukkit.craftbukkit.CraftFluidCollisionMode.toNMS(fluidCollisionMode), net.minecraft.world.phys.shapes.CollisionContext.empty()), pos); // Pass block pos
+ }
+ case BLOCK_CAN_PLACE: {
+ pos = (BlockPos) params[0];
+ org.bukkit.block.data.BlockData data = (org.bukkit.block.data.BlockData) params[1];
+ net.minecraft.world.level.block.state.BlockState nmsData = ((org.bukkit.craftbukkit.block.data.CraftBlockData) data).getState();
+ return nmsData.canSurvive(this, pos);
+ }
+ // Add cases for other ReadOperationType values here...
+ // case GET_ENTITIES_IN_BOX: ... (complex, needs careful list handling)
+
+ default:
+ throw new UnsupportedOperationException("Unsupported buffered read type: " + request.type());
+ }
+ }
+ // Leaf end - SparklyPaper - parallel world ticking
+
public void tick(BooleanSupplier hasTimeLeft) {
this.handlingTick = true;
+ this.processAsyncReadRequests(); // Leaf - SparklyPaper - parallel world ticking
TickRateManager tickRateManager = this.tickRateManager();
boolean runsNormally = tickRateManager.runsNormally();
if (runsNormally) {
@@ -746,6 +870,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.advanceWeatherCycle();
}
+ // Leaf start - SparklyPaper - parallel world ticking
+ if (!org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) {
+ this.moonrise$midTickTasks();
+ } else if ((++this.tickedBlocksOrFluids & 7L) != 0L) { // Keep original mid-tick logic for PWT enabled
+ this.server.moonrise$executeMidTickTasks();
+ }
+ // Leaf end - SparklyPaper - parallel world ticking
+
int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
if (this.purpurConfig.playersSkipNight && this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) { // Purpur - Config for skipping night
// Paper start - create time skip event - move up calculations
@@ -1313,9 +1445,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
fluidState.tick(this, pos, blockState);
}
// Paper start - rewrite chunk system
@@ -611,7 +774,7 @@ index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d
// Paper end - rewrite chunk system
}
@@ -1326,9 +1331,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1326,9 +1461,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
blockState.tick(this, pos, this.random);
}
// Paper start - rewrite chunk system
@@ -626,7 +789,7 @@ index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d
// Paper end - rewrite chunk system
}
@@ -1579,6 +1587,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1579,6 +1717,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
private void addPlayer(ServerPlayer player) {
@@ -635,7 +798,7 @@ index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d
Entity entity = this.getEntities().get(player.getUUID());
if (entity != null) {
LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID());
@@ -1591,7 +1601,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1591,7 +1731,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// CraftBukkit start
private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {

View File

@@ -6,10 +6,10 @@ Subject: [PATCH] SparklyPaper: Track each world MSPT
Original project: https://github.com/SparklyPower/SparklyPaper
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index ac751d460ae0c8dbb858c4047c459a11b57ae175..24926aa7ed5c78b235659daf18b224b14beb744c 100644
index 7f791ff5bdf6c29c78f863d21af16270a74d8e7e..1431a0fac3c8a846535c1bd2f60a1279d08f14ea 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1693,7 +1693,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1699,7 +1699,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Leaf start - SparklyPaper - parallel world ticking mod (move level ticking logic out for branch convergence)
private void tickLevel(ServerLevel serverLevel, BooleanSupplier hasTimeLeft) {
try {
@@ -27,10 +27,10 @@ index ac751d460ae0c8dbb858c4047c459a11b57ae175..24926aa7ed5c78b235659daf18b224b1
CrashReport crashReport = CrashReport.forThrowable(levelTickingException, "Exception ticking world");
serverLevel.fillReportDetails(crashReport);
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 31abf2da10bc9b4b7825ed4b3d4e9da52feb2e39..9ba1c29b75ba0eb545097eef4fe568c53ebd885c 100644
index d6524d5c442555eaeb4d90f6a101262ee669f0d9..5c1f99a8fd9920b30e6a80769bc306591510012a 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -573,6 +573,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -574,6 +574,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
// Paper end - chunk tick iteration

View File

@@ -9,10 +9,10 @@ Leaf: ~48ms (-36%)
This should help drastically on the farms that use actively changing fluids.
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index d21ae1a6ce307c186bc7e218b947dd1879d93b00..7f823e7f282e52b7cf918b117a5059ab3f62aef9 100644
index 5c1f99a8fd9920b30e6a80769bc306591510012a..7151c2a53687b4abef65c0a3da363ccd6c8f2f49 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1314,6 +1314,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1444,6 +1444,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.emptyTime = 0;
}

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] Micro optimizations for random tick
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 9ba1c29b75ba0eb545097eef4fe568c53ebd885c..90bdcd168ad5b1a940f81b191bd59a34d3a33070 100644
index 7151c2a53687b4abef65c0a3da363ccd6c8f2f49..fe81b2acfb51ed3335bde6f27ecfc53e339d2c7e 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -924,7 +924,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1054,7 +1054,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper start - optimise random ticking
private void optimiseRandomTick(final LevelChunk chunk, final int tickSpeed) {
final LevelChunkSection[] sections = chunk.getSections();
@@ -17,7 +17,7 @@ index 9ba1c29b75ba0eb545097eef4fe568c53ebd885c..90bdcd168ad5b1a940f81b191bd59a34
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Leaf - Faster random generator - upcasting
final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294();
@@ -933,41 +933,41 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1063,41 +1063,41 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
final int offsetZ = cpos.z << 4;
for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) {

View File

@@ -106,7 +106,7 @@ index b6af8da084c83ee38bb3ecea6a98feb0c1c74d2a..561723eeb1dd80f7fdd9aff33f6e1c4c
final EntityCollectionBySection byType = this.entitiesByType.get(entity.getType());
byType.removeEntity(entity, sectionIndex);
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 24926aa7ed5c78b235659daf18b224b14beb744c..98af1ad020a003db66d7319f33d43deec315aec5 100644
index 1431a0fac3c8a846535c1bd2f60a1279d08f14ea..c92005fcb9c6fdf63bf0854122d59d130315db85 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -292,6 +292,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -117,7 +117,7 @@ index 24926aa7ed5c78b235659daf18b224b14beb744c..98af1ad020a003db66d7319f33d43dee
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
@@ -1088,6 +1089,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1094,6 +1095,14 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
org.dreeam.leaf.async.AsyncPlayerDataSaving.IO_POOL.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS);
} catch (java.lang.InterruptedException ignored) {}
// Leaf end - Async playerdata saving
@@ -149,7 +149,7 @@ index 33dd16a26edd2974f04d9a868d3e58e8e3060032..eb0589b203bcf72cd24bb37f2c448c23
// Gale start - Pufferfish - SIMD support
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 60d5539f2a94b19281bcd8bdc2044eae1225278d..e95cbbc2757ed7f8d8aa873cec6bd49269592dae 100644
index fe81b2acfb51ed3335bde6f27ecfc53e339d2c7e..7955a8fa9c4de139b24c9d53018b055ff4008e02 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -177,7 +177,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -170,7 +170,7 @@ index 60d5539f2a94b19281bcd8bdc2044eae1225278d..e95cbbc2757ed7f8d8aa873cec6bd492
public final ServerChunkCache chunkSource;
private final MinecraftServer server;
public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type
@@ -218,6 +227,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -219,6 +228,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current)
public boolean hasRidableMoveEvent = false; // Purpur - Ridables
final List<ServerPlayer> realPlayers; // Leaves - skip
@@ -178,7 +178,7 @@ index 60d5539f2a94b19281bcd8bdc2044eae1225278d..e95cbbc2757ed7f8d8aa873cec6bd492
public LevelChunk getChunkIfLoaded(int x, int z) {
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
@@ -335,6 +345,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -336,6 +346,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks();
}
@@ -191,7 +191,7 @@ index 60d5539f2a94b19281bcd8bdc2044eae1225278d..e95cbbc2757ed7f8d8aa873cec6bd492
@Override
public final ChunkAccess moonrise$syncLoadNonFull(final int chunkX, final int chunkZ, final net.minecraft.world.level.chunk.status.ChunkStatus status) {
return this.moonrise$getChunkTaskScheduler().syncLoadNonFull(chunkX, chunkZ, status);
@@ -711,6 +727,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -712,6 +728,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle
this.realPlayers = Lists.newArrayList(); // Leaves - skip
this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new org.dreeam.leaf.async.world.SparklyPaperServerLevelTickExecutorThreadFactory(getWorld().getName())); // SparklyPaper - parallel world ticking
@@ -204,8 +204,8 @@ index 60d5539f2a94b19281bcd8bdc2044eae1225278d..e95cbbc2757ed7f8d8aa873cec6bd492
+ // Leaf end - Async target finding
}
// Paper start
@@ -855,12 +878,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Leaf start - SparklyPaper - parallel world ticking - Shutdown handling for async reads
@@ -985,12 +1008,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
this.moonrise$midTickTasks(); // Paper - rewrite chunk system
// Gale end - Airplane - remove lambda from ticking guard - copied from guardEntityTick
@@ -220,7 +220,7 @@ index 60d5539f2a94b19281bcd8bdc2044eae1225278d..e95cbbc2757ed7f8d8aa873cec6bd492
}
// Paper - rewrite chunk system
@@ -1333,6 +1358,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1463,6 +1488,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Leaf end - SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
// Paper end - rewrite chunk system
@@ -228,7 +228,7 @@ index 60d5539f2a94b19281bcd8bdc2044eae1225278d..e95cbbc2757ed7f8d8aa873cec6bd492
}
private void tickBlock(BlockPos pos, Block block) {
@@ -1349,6 +1375,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1479,6 +1505,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Leaf end - SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
// Paper end - rewrite chunk system
@@ -307,14 +307,14 @@ index 05d5cde42b7011091ef4ee874c0d9d5586ae3f10..88809afe30bb970a7de8bdfd26926880
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..22f052d02ccf22f22894a0b236af1b95c8d65e97 100644
index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..9abb8e7b0dea2cb63dad234812d773403d0716f6 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<T extends LivingEntity> extends Goal {
@Override
public boolean canUse() {
+ // Leaf start - Async target finding
+ // Leaf start - Async Avoid Entity Finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ if (!poll()) {
+ getNearestEntityAsync();
@@ -328,11 +328,11 @@ index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..22f052d02ccf22f22894a0b236af1b95
this.mob,
this.mob.getX(),
- this.mob.getY(),
+ this.mob.getEyeY(), // Leaf - Async target finding
+ this.mob.getEyeY(), // Leaf - Async Avoid Entity Finding
this.mob.getZ()
);
+ }
+ // Leaf end - Async target finding
+ // Leaf end - Async Avoid Entity Finding
if (this.toAvoid == null) {
return false;
} else {
@@ -340,7 +340,7 @@ index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..22f052d02ccf22f22894a0b236af1b95
}
}
+ // Leaf start - Async target finding
+ // Leaf start - Async Avoid Entity Finding
+ private boolean poll() {
+ if (!(this.mob.getGoalCtx().result() instanceof LivingEntity target)) return false;
+ var serverLevel = getServerLevel(this.mob);
@@ -368,25 +368,25 @@ index 4b24bb47a53a46586a642f3fb2656b1b8b670bf2..22f052d02ccf22f22894a0b236af1b95
+ z
+ );
+ }
+ // Leaf end - Async target finding
+ // Leaf end - Async Avoid Entity Finding
+
@Override
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..1c128f60adf6a72bed0ca40b98dc579cdf9d0e21 100644
index 28ef40e8a645989ea181297069cf2bbe571f3082..d011e4735cb8fd65a39a6b7a66386375b12aca78 100644
--- a/net/minecraft/world/entity/ai/goal/BegGoal.java
+++ b/net/minecraft/world/entity/ai/goal/BegGoal.java
@@ -27,8 +27,43 @@ public class BegGoal extends Goal {
this.setFlags(EnumSet.of(Goal.Flag.LOOK));
}
+ // Leaf start - Async target finding
+ // Leaf start - Async Target Finding
+ protected boolean poll() {
+ if (!(this.wolf.getGoalCtx().result() instanceof Player target)) return false;
+ if (target == null) return false;
+ ServerLevel serverLevel = getServerLevel(this.wolf);
+ if (serverLevel == null || !target.isAlive() || !playerHoldingInteresting0(target)) return false;
+ if (serverLevel == null || !target.isAlive() || !playerHoldingInteresting(target)) return false;
+ this.player = target;
+ return true;
+ }
@@ -399,17 +399,17 @@ index 28ef40e8a645989ea181297069cf2bbe571f3082..1c128f60adf6a72bed0ca40b98dc579c
+ final TargetingConditions begTargeting = this.begTargeting;
+ ctx.wake = () -> {
+ var player = serverLevel.getNearestPlayer(begTargeting, wolf);
+ if (player != null && playerHoldingInteresting0(player)) {
+ if (player != null && playerHoldingInteresting(player)) {
+ return player;
+ }
+ return null;
+ };
+ }
+ // Leaf end - Async target finding
+ // Leaf end - Async Target Finding
+
@Override
public boolean canUse() {
+ // Leaf start - Async target finding
+ // Leaf start - Async Target Finding
+ if (poll()) {
+ return true;
+ }
@@ -417,28 +417,23 @@ index 28ef40e8a645989ea181297069cf2bbe571f3082..1c128f60adf6a72bed0ca40b98dc579c
+ findTargetAsync();
+ return false;
+ }
+ // Leaf end - Async target finding
+ // Leaf end - Async Target Finding
this.player = this.level.getNearestPlayer(this.begTargeting, this.wolf);
return this.player != null && this.playerHoldingInteresting(this.player);
}
@@ -69,4 +104,17 @@ public class BegGoal extends Goal {
return false;
@@ -59,10 +94,10 @@ public class BegGoal extends Goal {
this.lookTime--;
}
+
+ // Leaf start - Async target finding - static impl
+ private static boolean playerHoldingInteresting0(Player player) {
+ for (InteractionHand interactionHand : InteractionHand.values()) {
+ ItemStack itemInHand = player.getItemInHand(interactionHand);
+ if (itemInHand.is(Items.BONE) || itemInHand.is(net.minecraft.tags.ItemTags.WOLF_FOOD)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+ // Leaf end - Async target finding - static impl
}
- private 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)) { // Leaf end - Async Target Finding
return true;
}
}
diff --git a/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java b/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java
index 4c46cd105cde3cbcde65a02ff691c3a8edd56c76..b3205c9f35687bc37124876198ec2d657ccaa96c 100644
--- a/net/minecraft/world/entity/ai/goal/CatLieOnBedGoal.java
@@ -674,7 +669,7 @@ index 3093f03d4f298bf39fec8bad2b6c22518774aea8..0a41797fd7beddce0b93d42bac6e0270
} 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..852393af4013178562940f6a0d07e5364758ec21 100644
index e82e32407cec6109b9c3b0106295217f4a3f4aa2..3c24382a3cced8dcea103ccc87cb506310de8461 100644
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -26,13 +26,23 @@ public class GoalSelector {
@@ -723,7 +718,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..852393af4013178562940f6a0d07e536
flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator);
// Paper end - Perf: optimize goal types
if (!flag.getOrDefault(flag1, NO_GOAL).canBeReplacedBy(goal)) {
@@ -85,7 +96,136 @@ public class GoalSelector {
@@ -85,7 +96,131 @@ public class GoalSelector {
return true;
}
@@ -748,12 +743,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..852393af4013178562940f6a0d07e536
+ ctx.state = true;
+ }
+
+ for (Goal.Flag flag : GOAL_FLAG_VALUES) {
+ WrappedGoal goal = this.lockedFlags.get(flag);
+ if (goal != null && !goal.isRunning()) {
+ this.lockedFlags.remove(flag);
+ }
+ }
+ this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning());
+
+ ctxIndex = 0;
+ ctx.state = true;
@@ -801,7 +791,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..852393af4013178562940f6a0d07e536
+ if (!ctx.state) {
+ switch (goal.getGoal()) {
+ case net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal t -> t.poll();
+ case net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal<?> t -> t.poll();
+ case net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal t -> t.poll();
+ default -> {}
+ }
+ }
@@ -860,7 +850,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..852393af4013178562940f6a0d07e536
for (WrappedGoal wrappedGoal : this.availableGoals) {
if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams
wrappedGoal.stop();
@@ -116,6 +256,24 @@ public class GoalSelector {
@@ -116,6 +251,18 @@ public class GoalSelector {
}
public void tickRunningGoals(boolean tickAllRunning) {
@@ -872,12 +862,6 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..852393af4013178562940f6a0d07e536
+ availableGoalsDirty = false;
+ }
+ ctxState = tickAllRunning ? 2 : 3;
+ } else {
+ for (WrappedGoal wrappedGoal : java.util.Objects.requireNonNull(this.ctxGoals)) {
+ if (wrappedGoal.isRunning() && (tickAllRunning || wrappedGoal.requiresUpdateEveryTick())) {
+ wrappedGoal.tick();
+ }
+ }
+ }
+ return;
+ }
@@ -886,7 +870,7 @@ index e82e32407cec6109b9c3b0106295217f4a3f4aa2..852393af4013178562940f6a0d07e536
if (wrappedGoal.isRunning() && (tickAllRunning || wrappedGoal.requiresUpdateEveryTick())) {
wrappedGoal.tick();
diff --git a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
index be59d0c27a83b329ec3f97c029cfb9c114e22472..5c70f33d9633326cdc59fd0812f49aa38b3d6e14 100644
index be59d0c27a83b329ec3f97c029cfb9c114e22472..86f041ff21cf44a0cded5744055654a0bff40c42 100644
--- a/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
+++ b/net/minecraft/world/entity/ai/goal/LlamaFollowCaravanGoal.java
@@ -20,20 +20,83 @@ public class LlamaFollowCaravanGoal extends Goal {
@@ -951,7 +935,7 @@ index be59d0c27a83b329ec3f97c029cfb9c114e22472..5c70f33d9633326cdc59fd0812f49aa3
+ // Leaf start - Async Target Finding
+ Llama llama = poll();
+ double d = Double.MAX_VALUE;
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled) {
+ if (llama == null) {
+ findTargetAsync();
+ return false;
@@ -1096,10 +1080,10 @@ index 6463c3c9b08d6058f2843c225b08a40fc30a960b..98c2b4a298ada4b02afa55f991791d86
@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..52e353ff7865cc187d83ada4e93dc955ead2a578 100644
index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..9b8453ce2bc2cafca7c670d79b40434e7c93afca 100644
--- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
+++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
@@ -41,14 +41,67 @@ public abstract class MoveToBlockGoal extends Goal {
@@ -41,8 +41,60 @@ public abstract class MoveToBlockGoal extends Goal {
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.JUMP));
}
@@ -1147,7 +1131,6 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..52e353ff7865cc187d83ada4e93dc955
+ Strider,
+ TurtleToWater,
+ TurtleLay,
+ Unknown,
+ }
+ // Leaf end - Async search block
+
@@ -1161,32 +1144,20 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..52e353ff7865cc187d83ada4e93dc955
if (this.nextStartTick > 0) {
this.nextStartTick--;
return false;
} else {
this.nextStartTick = this.nextStartTick(this.mob);
- return this.findNearestBlock();
+ return this.findNearestBlockAsync(); // Leaf - Async search block
}
@@ -109,6 +161,12 @@ public abstract class MoveToBlockGoal extends Goal {
}
@@ -108,6 +161,17 @@ public abstract class MoveToBlockGoal extends Goal {
return this.reachedTarget;
}
+ // Leaf start - Async search block
+ protected boolean findNearestBlockAsync() {
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchBlock
+ && this.typeToCheck() != TypeToCheck.Unknown) {
protected boolean findNearestBlock() {
+ // Leaf start - Async search block
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchBlock) {
+ getBlockAsync();
+ return false;
+ }
+ return findNearestBlock();
+ }
+ // Leaf end - Async search block
+
protected boolean findNearestBlock() {
+ // Leaf end - Async search block
int i = this.searchRange;
int i1 = this.verticalSearchRange;
@@ -133,5 +197,108 @@ public abstract class MoveToBlockGoal extends Goal {
BlockPos blockPos = this.mob.blockPosition();
@@ -133,5 +191,105 @@ public abstract class MoveToBlockGoal extends Goal {
return false;
}
@@ -1229,9 +1200,7 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..52e353ff7865cc187d83ada4e93dc955
protected abstract boolean isValidTarget(LevelReader level, BlockPos pos);
+
+ // Leaf start - Async search block
+ protected TypeToCheck typeToCheck() {
+ return TypeToCheck.Unknown;
+ }
+ protected abstract TypeToCheck typeToCheck();
+
+ private static boolean isValidTargetAsync(
+ TypeToCheck type,
@@ -1289,7 +1258,6 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..52e353ff7865cc187d83ada4e93dc955
+ case TurtleLay -> {
+ return level.isEmptyBlock(pos.above()) && net.minecraft.world.level.block.TurtleEggBlock.isSand(level, pos);
+ }
+ case Unknown -> throw new IllegalStateException();
+ case null -> throw new IllegalStateException();
+ }
+ // Leaf end - Async search block
@@ -1359,10 +1327,10 @@ index 3c274d917bca9de87abfb842f5f332e112a7a2d7..2491b84641443ecfb8afc3b179e1cf80
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 c67a88c9c77ece7c85ffb169ac96da4f28291228..93bf51c9299354be2a581618bd31d2c4cc7c1d30 100644
index c67a88c9c77ece7c85ffb169ac96da4f28291228..14d9b492ba431d534e0c6a567d0b7700b4c8a02d 100644
--- a/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
+++ b/net/minecraft/world/entity/ai/goal/RemoveBlockGoal.java
@@ -37,10 +37,17 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
@@ -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
return false;
@@ -1377,11 +1345,7 @@ index c67a88c9c77ece7c85ffb169ac96da4f28291228..93bf51c9299354be2a581618bd31d2c4
+ if (this.nextStartTick > 0) {
this.nextStartTick--;
return false;
- } else if (this.findNearestBlock()) {
+ } else if (this.findNearestBlockAsync()) { // Leaf - async search block
this.nextStartTick = reducedTickDelay(20);
return true;
} else {
} else if (this.findNearestBlock()) {
@@ -151,8 +158,15 @@ public class RemoveBlockGoal extends MoveToBlockGoal {
protected boolean isValidTarget(LevelReader level, BlockPos pos) {
ChunkAccess chunk = level.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); // Paper - Prevent AI rules from loading chunks
@@ -1400,10 +1364,10 @@ index c67a88c9c77ece7c85ffb169ac96da4f28291228..93bf51c9299354be2a581618bd31d2c4
+ // 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..22656c9ef08a65e23cabdd9f6af84f3d2279b075 100644
index f88f618d34fb343b31de3af1a875d6633703df71..754c379b42cf65c1d2278b474cdfbe50e9e62b34 100644
--- a/net/minecraft/world/entity/ai/goal/TemptGoal.java
+++ b/net/minecraft/world/entity/ai/goal/TemptGoal.java
@@ -36,14 +36,43 @@ public class TemptGoal extends Goal {
@@ -36,12 +36,51 @@ public class TemptGoal extends Goal {
this.targetingConditions = TEMPT_TARGETING.copy().selector((entity, level) -> this.shouldFollow(entity));
}
@@ -1433,22 +1397,28 @@ index f88f618d34fb343b31de3af1a875d6633703df71..22656c9ef08a65e23cabdd9f6af84f3d
this.calmDown--;
return false;
} else {
- this.player = getServerLevel(this.mob)
- .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob);
+ // Leaf start - Async Tempt Finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ if (!poll()) {
+ if (poll()) {
+ if (this.player != null) {
+ org.bukkit.event.entity.EntityTargetLivingEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(this.mob, this.player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TEMPT);
+ if (event.isCancelled()) {
+ return false;
+ }
+ this.player = (event.getTarget() == null) ? null : ((org.bukkit.craftbukkit.entity.CraftLivingEntity) event.getTarget()).getHandle();
+ }
+ if (this.player != null) {
+ return true;
+ }
+ } else {
+ getNearestPlayerAsync();
+ return false;
+ }
+ } else {
+ this.player = getServerLevel(this.mob)
+ .getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob);
+ }
+ // Leaf end - Async Tempt Finding
this.player = getServerLevel(this.mob)
.getNearestPlayer(this.targetingConditions.range(this.mob.getAttributeValue(Attributes.TEMPT_RANGE)), this.mob);
// CraftBukkit start
if (this.player != null) {
org.bukkit.event.entity.EntityTargetLivingEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTargetLivingEvent(this.mob, this.player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TEMPT);
diff --git a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java
index 4644f3f7af89623ca6218c0dd24bb6cd67db553b..c9750ad322ddaa9c457f0e652d87c7abf8559358 100644
--- a/net/minecraft/world/entity/ai/goal/target/DefendVillageTargetGoal.java
@@ -1628,10 +1598,10 @@ index 25fe78116ce01eeefe5c958423734195d27302eb..e306c1cfc44878ea130d8046b31cf617
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 85eae0a14f7a417dfd8c911079d05354a98e5834..745ef9ea16171d8dad3082878f8883031bd79a84 100644
index 85eae0a14f7a417dfd8c911079d05354a98e5834..f59d5c9be0eb10f5b5192442e1850900d71a31e9 100644
--- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
@@ -41,12 +41,52 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
@@ -41,8 +41,43 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
this.targetConditions = TargetingConditions.forCombat().range(this.getFollowDistance()).selector(selector);
}
@@ -1644,12 +1614,7 @@ index 85eae0a14f7a417dfd8c911079d05354a98e5834..745ef9ea16171d8dad3082878f888303
+ return true;
+ }
+
+ protected void findTargetAsync() {
+ if (!org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ this.findTarget();
+ return;
+ }
+
+ private void findTargetAsync() {
+ final Mob mob = this.mob;
+ final var ctx = mob.getGoalCtx();
+ if (!ctx.state) return;
@@ -1680,16 +1645,27 @@ index 85eae0a14f7a417dfd8c911079d05354a98e5834..745ef9ea16171d8dad3082878f888303
if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) {
return false;
} else {
- this.findTarget();
+ this.findTargetAsync(); // Leaf - Async target finding
return this.target != null;
}
}
@@ -57,6 +92,15 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
protected void findTarget() {
ServerLevel serverLevel = getServerLevel(this.mob);
+
+ // Leaf start - Async Target Finding
+ if (org.dreeam.leaf.config.modules.async.AsyncTargetFinding.searchEntity) {
+ this.findTargetAsync();
+ this.target = null;
+ return;
+ }
+ // Leaf end - Async Target Finding
+
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),
diff --git a/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java
index 4604a603c4ddd0a9242e859aaa5a511c2d4c4f84..84c7b89e7c894c0f544cf0ffcf9dff3f6a5919cc 100644
index 4604a603c4ddd0a9242e859aaa5a511c2d4c4f84..7274dfb52ca4a08cdebcd04294cedc73460593e5 100644
--- a/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/NearestHealableRaiderTargetGoal.java
@@ -23,12 +23,20 @@ public class NearestHealableRaiderTargetGoal<T extends LivingEntity> extends Nea
@@ -23,7 +23,15 @@ public class NearestHealableRaiderTargetGoal<T extends LivingEntity> extends Nea
@Override
public boolean canUse() {
@@ -1706,12 +1682,6 @@ index 4604a603c4ddd0a9242e859aaa5a511c2d4c4f84..84c7b89e7c894c0f544cf0ffcf9dff3f
return false;
} else if (!((Raider)this.mob).hasActiveRaid()) {
return false;
} else {
- this.findTarget();
+ this.findTargetAsync(); // Leaf - Async target finding
return this.target != null;
}
}
diff --git a/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java
index abf57494950f55bbd75f335f26736cb9e703c197..efd2418f56c36e7850edde483a2a4906dd622441 100644
--- a/net/minecraft/world/entity/ai/goal/target/NonTameRandomTargetGoal.java

View File

@@ -22,10 +22,10 @@ index 7e19dfe90a63ff26f03b95891dacb7360bba5a3c..5d0961f06c23121883c4f0b889ccdf32
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 98af1ad020a003db66d7319f33d43deec315aec5..9669036e6b7f1830888e48c99acb01d443f4e9f0 100644
index c92005fcb9c6fdf63bf0854122d59d130315db85..e3194caff68499028d61d5755edce29b5c23253f 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1839,6 +1839,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1845,6 +1845,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleTick(); // Leaves - protocol
@@ -34,7 +34,7 @@ index 98af1ad020a003db66d7319f33d43deec315aec5..9669036e6b7f1830888e48c99acb01d4
for (int i = 0; i < this.tickables.size(); i++) {
this.tickables.get(i).run();
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
index bcd569e7d12d4f453c64bf12933a72c3ca362329..b48032bc878e11518d63c128edeef6bf3770f7d1 100644
index 5351d373aa0f4450386a6b50f88052c031949f5b..ea4067be7e800b58dd59f7ffec58c1e026f68c6e 100644
--- a/net/minecraft/server/level/ServerEntity.java
+++ b/net/minecraft/server/level/ServerEntity.java
@@ -283,6 +283,7 @@ public class ServerEntity {

View File

@@ -94,10 +94,10 @@ index b1f1b596a597d559aa672a3cb46a03917ad746af..d61da0fbe7f6c181e4084ce60bfe7dab
this.tickChunks(l, list); // Gale - Purpur - remove vanilla profiler
} finally {
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index e95cbbc2757ed7f8d8aa873cec6bd49269592dae..3a5d2b16b0eccc8d6a742f70039b999a364d3516 100644
index 7955a8fa9c4de139b24c9d53018b055ff4008e02..eb849c57992658005e0f514c6f7923f8ca43bebf 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -1391,13 +1391,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1521,13 +1521,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper end - log detailed entity tick information
public void tickNonPassenger(Entity entity) {
@@ -111,7 +111,7 @@ index e95cbbc2757ed7f8d8aa873cec6bd49269592dae..3a5d2b16b0eccc8d6a742f70039b999a
entity.setOldPosAndRot();
entity.tickCount++;
entity.totalEntityAge++; // Paper - age-like counter for all entities
@@ -1410,13 +1404,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -1540,13 +1534,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
for (Entity entity1 : entity.getPassengers()) {
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
}
@@ -212,58 +212,6 @@ index 64f24d3e0ecb91e0b4df6229354aeac549234f1b..df23d80d6b18e900414aa02e5c1812f0
int floor = Mth.floor(x);
int floor1 = Mth.floor(y);
int floor2 = Mth.floor(z);
diff --git a/net/minecraft/world/level/block/state/StateHolder.java b/net/minecraft/world/level/block/state/StateHolder.java
index 098518383d2c07491e047749ce3a834e98b85b1d..3dea58dff1dea05bd4a052684cb7978b2a63e452 100644
--- a/net/minecraft/world/level/block/state/StateHolder.java
+++ b/net/minecraft/world/level/block/state/StateHolder.java
@@ -25,7 +25,7 @@ public abstract class StateHolder<O, S> implements ca.spottedleaf.moonrise.patch
return "<NULL>";
} else {
Property<?> property = propertyEntry.getKey();
- return property.getName() + "=" + this.getName(property, propertyEntry.getValue());
+ return property.getName() + "=" + this.getName(property, propertyEntry.getValue()); // Leaf - paw optimization - diff on change
}
}
@@ -73,13 +73,37 @@ public abstract class StateHolder<O, S> implements ca.spottedleaf.moonrise.patch
stringBuilder.append(this.owner);
if (!this.getValues().isEmpty()) {
stringBuilder.append('[');
- stringBuilder.append(this.getValues().entrySet().stream().map(PROPERTY_ENTRY_TO_STRING_FUNCTION).collect(Collectors.joining(",")));
+ // Leaf start - paw optimization
+ int i = 0;
+ for (Map.Entry<Property<?>, Comparable<?>> propertyEntry : this.getValues().entrySet()) {
+ if (propertyEntry == null) {
+ stringBuilder.append("<NULL>");
+ } else {
+ Property<?> property = propertyEntry.getKey();
+ Comparable<?> value = propertyEntry.getValue();
+
+ stringBuilder.append(property.getName()).append("=").append(getValueName(property, value));
+ }
+
+ if (i < this.getValues().size() - 1) {
+ stringBuilder.append(",");
+ }
+
+ i++;
+ }
+ // Leaf end - paw optimization
stringBuilder.append(']');
}
return stringBuilder.toString();
}
+ // Leaf start - paw optimization
+ private <T extends Comparable<T>> String getValueName(Property<T> property, Comparable<?> value) {
+ return property.getName((T) value);
+ }
+ // Leaf end - paw optimization
+
public Collection<Property<?>> getProperties() {
return this.optimisedTable.getProperties(); // Paper - optimise blockstate property access
}
diff --git a/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java b/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java
index 03ec2264b19e1794b609fe09d1ceaba4e0c4d669..3f38fe0140d13c7c356340ba06b55469ede0a1ad 100644
--- a/net/minecraft/world/level/levelgen/structure/structures/DesertPyramidStructure.java

View File

@@ -0,0 +1,11 @@
package org.dreeam.leaf.async.world;
public enum ReadOperationType {
BLOCK_GET_BIOME,
BLOCK_GET_COMPUTED_BIOME,
BLOCK_IS_INDIRECTLY_POWERED,
BLOCK_GET_BLOCK_POWER,
BLOCK_RAY_TRACE,
BLOCK_CAN_PLACE,
BLOCK_GET_NMS_STATE
}

View File

@@ -0,0 +1,10 @@
package org.dreeam.leaf.async.world;
import java.util.concurrent.CompletableFuture;
public record WorldReadRequest(
ReadOperationType type,
Object[] params, // Parameters for the read operation
CompletableFuture<Object> future // Future to complete with the result
) {
}

View File

@@ -8,15 +8,19 @@ import org.dreeam.leaf.config.annotations.Experimental;
public class SparklyPaperParallelWorldTicking extends ConfigModules {
public String getBasePath() {
return EnumConfigCategory.ASYNC.getBaseKeyName() + ".parallel-world-tracking";
} // TODO: Correct config key when stable
// Corrected path based on your comment
return EnumConfigCategory.ASYNC.getBaseKeyName() + ".parallel-world-ticking";
}
@Experimental
public static boolean enabled = false;
public static int threads = 8;
public static boolean logContainerCreationStacktraces = false;
public static boolean disableHardThrow = false;
@Deprecated
public static boolean runAsyncTasksSync = false;
// STRICT, BUFFERED, DISABLED
public static String asyncUnsafeReadHandling = "BUFFERED";
@Override
public void onLoaded() {
@@ -34,15 +38,30 @@ public class SparklyPaperParallelWorldTicking extends ConfigModules {
} else {
threads = 0;
}
logContainerCreationStacktraces = config.getBoolean(getBasePath() + ".log-container-creation-stacktraces", logContainerCreationStacktraces);
logContainerCreationStacktraces = enabled && logContainerCreationStacktraces;
disableHardThrow = config.getBoolean(getBasePath() + ".disable-hard-throw", disableHardThrow);
disableHardThrow = enabled && disableHardThrow;
runAsyncTasksSync = config.getBoolean(getBasePath() + ".run-async-tasks-sync", runAsyncTasksSync);
runAsyncTasksSync = enabled && runAsyncTasksSync;
asyncUnsafeReadHandling = config.getString(getBasePath() + ".async-unsafe-read-handling", asyncUnsafeReadHandling).toUpperCase();
if (!asyncUnsafeReadHandling.equals("STRICT") && !asyncUnsafeReadHandling.equals("BUFFERED") && !asyncUnsafeReadHandling.equals("DISABLED")) {
System.err.println("[Leaf] Invalid value for " + getBasePath() + ".async-unsafe-read-handling: " + asyncUnsafeReadHandling + ". Defaulting to STRICT.");
asyncUnsafeReadHandling = "STRICT";
}
if (!enabled) {
asyncUnsafeReadHandling = "DISABLED";
}
runAsyncTasksSync = config.getBoolean(getBasePath() + ".run-async-tasks-sync", false); // Default to false now
if (runAsyncTasksSync) {
System.err.println("[Leaf] WARNING: The setting '" + getBasePath() + ".run-async-tasks-sync' is deprecated. Use 'async-unsafe-read-handling: STRICT' for similar safety checks or 'BUFFERED' for buffered reads.");
}
if (enabled) {
LeafConfig.LOGGER.info("Using {} threads for Parallel World Ticking", threads);
}
runAsyncTasksSync = enabled && runAsyncTasksSync; // Auto-disable if main feature is off
}
}