9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-19 15:09:25 +00:00
This commit is contained in:
Dreeam
2025-04-17 02:45:56 -04:00
parent 502701329c
commit dff5b11bd9
8 changed files with 147 additions and 226 deletions

View File

@@ -424,47 +424,41 @@ index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11
} }
// CraftBukkit end // CraftBukkit end
diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java
index d2159a747fe42aa95cfc6bca0e55e3f4485847bb..a7e1c9979897a12a7a8f417545ae96f703a1b248 100644 index d2159a747fe42aa95cfc6bca0e55e3f4485847bb..abe7ffd48766c48fab091947f34db436b3c883d0 100644
--- a/net/minecraft/server/PlayerAdvancements.java --- a/net/minecraft/server/PlayerAdvancements.java
+++ b/net/minecraft/server/PlayerAdvancements.java +++ b/net/minecraft/server/PlayerAdvancements.java
@@ -19,6 +19,7 @@ import java.nio.file.Path; @@ -53,8 +53,11 @@ public class PlayerAdvancements {
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
@@ -53,8 +54,9 @@ public class PlayerAdvancements {
private AdvancementTree tree; private AdvancementTree tree;
private final Map<AdvancementHolder, AdvancementProgress> progress = new LinkedHashMap<>(); private final Map<AdvancementHolder, AdvancementProgress> progress = new LinkedHashMap<>();
private final Set<AdvancementHolder> visible = new HashSet<>(); private final Set<AdvancementHolder> visible = new HashSet<>();
- private final Set<AdvancementHolder> progressChanged = new HashSet<>(); - private final Set<AdvancementHolder> progressChanged = new HashSet<>();
- private final Set<AdvancementNode> rootsToUpdate = new HashSet<>(); - private final Set<AdvancementNode> rootsToUpdate = new HashSet<>();
+ // Leaf start - SparklyPaper - parallel world ticking
+ private final Set<AdvancementHolder> progressChanged = new HashSet<>(); // Used when PWT is disabled + private final Set<AdvancementHolder> progressChanged = new HashSet<>(); // Used when PWT is disabled
+ private final Set<AdvancementHolder> progressChangedConcurrent = ConcurrentHashMap.newKeySet(); // Used when PWT is enabled + private final Set<AdvancementHolder> progressChangedConcurrent = java.util.concurrent.ConcurrentHashMap.newKeySet(); // Used when PWT is enabled
+ private final Set<AdvancementNode> rootsToUpdate = new HashSet<>(); // Always managed on player tick thread + private final Set<AdvancementNode> rootsToUpdate = new HashSet<>(); // Always managed on player tick thread
+ // Leaf end - SparklyPaper - parallel world ticking
private ServerPlayer player; private ServerPlayer player;
@Nullable @Nullable
private AdvancementHolder lastSelectedTab; private AdvancementHolder lastSelectedTab;
@@ -88,6 +90,8 @@ public class PlayerAdvancements { @@ -88,6 +91,7 @@ public class PlayerAdvancements {
this.visible.clear(); this.visible.clear();
this.rootsToUpdate.clear(); this.rootsToUpdate.clear();
this.progressChanged.clear(); this.progressChanged.clear();
+ // PWT Fix: Also clear concurrent set on reload + this.progressChangedConcurrent.clear(); // Leaf - SparklyPaper - parallel world ticking fix - Also clear concurrent set on reload
+ this.progressChangedConcurrent.clear();
this.isFirstPacket = true; this.isFirstPacket = true;
this.lastSelectedTab = null; this.lastSelectedTab = null;
this.tree = manager.tree(); this.tree = manager.tree();
@@ -151,6 +155,7 @@ public class PlayerAdvancements { @@ -151,7 +155,7 @@ public class PlayerAdvancements {
if (org.galemc.gale.configuration.GaleGlobalConfiguration.get().logToConsole.ignoredAdvancements) LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", path, this.playerSavePath); // Gale - Purpur - do not log ignored advancements if (org.galemc.gale.configuration.GaleGlobalConfiguration.get().logToConsole.ignoredAdvancements) LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", path, this.playerSavePath); // Gale - Purpur - do not log ignored advancements
} else { } else {
this.startProgress(advancementHolder, progress); this.startProgress(advancementHolder, progress);
+ // PWT Fix: Always add to non-concurrent set during load, flushDirty will handle sync - this.progressChanged.add(advancementHolder);
this.progressChanged.add(advancementHolder); + this.progressChanged.add(advancementHolder); // Leaf - SparklyPaper - parallel world ticking fix - Always add to non-concurrent set during load, flushDirty will handle sync
this.markForVisibilityUpdate(advancementHolder); this.markForVisibilityUpdate(advancementHolder);
} }
@@ -183,25 +188,25 @@ public class PlayerAdvancements { });
@@ -183,10 +187,12 @@ public class PlayerAdvancements {
return false; return false;
} }
// Paper end - Add PlayerAdvancementCriterionGrantEvent // Paper end - Add PlayerAdvancementCriterionGrantEvent
@@ -472,65 +466,46 @@ index d2159a747fe42aa95cfc6bca0e55e3f4485847bb..a7e1c9979897a12a7a8f417545ae96f7
- this.progressChanged.add(advancement); - this.progressChanged.add(advancement);
- flag = true; - flag = true;
- if (!isDone && orStartProgress.isDone()) { - if (!isDone && orStartProgress.isDone()) {
+ // Leaf start - SparklyPaper - parallel world ticking
+ this.unregisterListeners(advancement); // Must unregister criteria listeners + this.unregisterListeners(advancement); // Must unregister criteria listeners
+ (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled ? this.progressChangedConcurrent : this.progressChanged).add(advancement); + (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled ? this.progressChangedConcurrent : this.progressChanged).add(advancement);
+ flag = true; // Mark progress changed + flag = true; // Mark progress changed
+ if (!isDone && orStartProgress.isDone()) { // If the advancement was just completed + if (!isDone && orStartProgress.isDone()) { // If the advancement was just completed
+ // Leaf end - SparklyPaper - parallel world ticking
// Paper start - Add Adventure message to PlayerAdvancementDoneEvent // Paper start - Add Adventure message to PlayerAdvancementDoneEvent
- final net.kyori.adventure.text.Component message = advancement.value().display().flatMap(info -> { final net.kyori.adventure.text.Component message = advancement.value().display().flatMap(info -> {
- return java.util.Optional.ofNullable( return java.util.Optional.ofNullable(
- info.shouldAnnounceChat() ? io.papermc.paper.adventure.PaperAdventure.asAdventure(info.getType().createAnnouncement(advancement, this.player)) : null @@ -220,12 +226,14 @@ public class PlayerAdvancements {
- );
- }).orElse(null);
- final org.bukkit.event.player.PlayerAdvancementDoneEvent event = new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancement.toBukkit(), message);
+ final net.kyori.adventure.text.Component message = advancement.value().display().flatMap(info -> { // Paper - Add Adventure message to PlayerAdvancementDoneEvent
+ return java.util.Optional.ofNullable( // Paper - Add Adventure message to PlayerAdvancementDoneEvent
+ info.shouldAnnounceChat() ? io.papermc.paper.adventure.PaperAdventure.asAdventure(info.getType().createAnnouncement(advancement, this.player)) : null // Paper - Add Adventure message to PlayerAdvancementDoneEvent
+ ); // Paper - Add Adventure message to PlayerAdvancementDoneEvent
+ }).orElse(null); // Paper - Add Adventure message to PlayerAdvancementDoneEvent
+ final org.bukkit.event.player.PlayerAdvancementDoneEvent event = new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancement.toBukkit(), message); // Paper - Add Adventure message to PlayerAdvancementDoneEvent
this.player.level().getCraftServer().getPluginManager().callEvent(event); // CraftBukkit
// Paper end
advancement.value().rewards().grant(this.player);
advancement.value().display().ifPresent(displayInfo -> {
// Paper start - Add Adventure message to PlayerAdvancementDoneEvent
- if (event.message() != null && this.player.serverLevel().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) {
- if (org.purpurmc.purpur.PurpurConfig.advancementOnlyBroadcastToAffectedPlayer) this.player.sendMessage(message); else // Purpur - Configurable broadcast settings
- this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false);
+ if (event.message() != null && this.player.serverLevel().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) { // Paper - Add Adventure message to PlayerAdvancementDoneEvent
+ if (org.purpurmc.purpur.PurpurConfig.advancementOnlyBroadcastToAffectedPlayer) this.player.sendMessage(message); else // Purpur - Configurable broadcast settings // Paper - Add Adventure message to PlayerAdvancementDoneEvent
+ this.playerList.broadcastSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false); // Paper - Add Adventure message to PlayerAdvancementDoneEvent
// Paper end
}
});
@@ -220,12 +225,12 @@ public class PlayerAdvancements {
AdvancementProgress orStartProgress = this.getOrStartProgress(advancement); AdvancementProgress orStartProgress = this.getOrStartProgress(advancement);
boolean isDone = orStartProgress.isDone(); boolean isDone = orStartProgress.isDone();
if (orStartProgress.revokeProgress(criterionKey)) { if (orStartProgress.revokeProgress(criterionKey)) {
- this.registerListeners(advancement); - this.registerListeners(advancement);
- this.progressChanged.add(advancement); - this.progressChanged.add(advancement);
+ // Leaf start - SparklyPaper - parallel world ticking
+ this.registerListeners(advancement); // Re-register listeners if it's no longer done + this.registerListeners(advancement); // Re-register listeners if it's no longer done
+ (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled ? this.progressChangedConcurrent : this.progressChanged).add(advancement); + (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled ? this.progressChangedConcurrent : this.progressChanged).add(advancement);
+ // Leaf end - SparklyPaper - parallel world ticking
flag = true; flag = true;
} }
- if (isDone && !orStartProgress.isDone()) { - if (isDone && !orStartProgress.isDone()) {
+ if (isDone && !orStartProgress.isDone()) { // If the advancement was just un-completed + if (isDone && !orStartProgress.isDone()) { // Leaf - SparklyPaper - parallel world ticking - If the advancement was just un-completed
this.markForVisibilityUpdate(advancement); this.markForVisibilityUpdate(advancement);
} }
@@ -271,7 +276,9 @@ public class PlayerAdvancements { @@ -271,7 +279,10 @@ public class PlayerAdvancements {
} }
public void flushDirty(ServerPlayer serverPlayer) { public void flushDirty(ServerPlayer serverPlayer) {
- if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !this.progressChanged.isEmpty()) { - if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !this.progressChanged.isEmpty()) {
+ // Leaf start - SparklyPaper - parallel world ticking
+ final boolean useConcurrent = org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled; + final boolean useConcurrent = org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled;
+ final Set<AdvancementHolder> relevantProgressSet = useConcurrent ? this.progressChangedConcurrent : this.progressChanged; + final Set<AdvancementHolder> relevantProgressSet = useConcurrent ? this.progressChangedConcurrent : this.progressChanged;
+ if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !relevantProgressSet.isEmpty()) { + if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !relevantProgressSet.isEmpty()) {
Map<ResourceLocation, AdvancementProgress> map = new HashMap<>(); Map<ResourceLocation, AdvancementProgress> map = new HashMap<>();
Set<AdvancementHolder> set = new java.util.TreeSet<>(java.util.Comparator.comparing(adv -> adv.id().toString())); // Paper - Changed from HashSet to TreeSet ordered alphabetically. Set<AdvancementHolder> set = new java.util.TreeSet<>(java.util.Comparator.comparing(adv -> adv.id().toString())); // Paper - Changed from HashSet to TreeSet ordered alphabetically.
Set<ResourceLocation> set1 = new HashSet<>(); Set<ResourceLocation> set1 = new HashSet<>();
@@ -279,16 +286,23 @@ public class PlayerAdvancements { @@ -279,16 +290,24 @@ public class PlayerAdvancements {
for (AdvancementNode advancementNode : this.rootsToUpdate) { for (AdvancementNode advancementNode : this.rootsToUpdate) {
this.updateTreeVisibility(advancementNode, set, set1); this.updateTreeVisibility(advancementNode, set, set1);
} }
@@ -542,13 +517,11 @@ index d2159a747fe42aa95cfc6bca0e55e3f4485847bb..a7e1c9979897a12a7a8f417545ae96f7
- for (AdvancementHolder advancementHolder : this.progressChanged) { - for (AdvancementHolder advancementHolder : this.progressChanged) {
- if (this.visible.contains(advancementHolder)) { - if (this.visible.contains(advancementHolder)) {
- map.put(advancementHolder.id(), this.progress.get(advancementHolder)); + for (AdvancementHolder advancementHolder : toProcess) {
+ for (AdvancementHolder advancementHolder : toProcess) { + if (this.visible.contains(advancementHolder)) { // Only include progress for visible advancements
+ if (this.visible.contains(advancementHolder)) { // Only include progress for visible advancements map.put(advancementHolder.id(), this.progress.get(advancementHolder));
+ map.put(advancementHolder.id(), this.progress.get(advancementHolder));
+ }
} }
- } }
- this.progressChanged.clear(); - this.progressChanged.clear();
+ if (useConcurrent) { + if (useConcurrent) {
@@ -557,22 +530,26 @@ index d2159a747fe42aa95cfc6bca0e55e3f4485847bb..a7e1c9979897a12a7a8f417545ae96f7
+ this.progressChanged.clear(); // Clear the regular set + this.progressChanged.clear(); // Clear the regular set
+ } + }
+ } + }
+ // Leaf end - SparklyPaper - parallel world ticking
if (!map.isEmpty() || !set.isEmpty() || !set1.isEmpty()) { if (!map.isEmpty() || !set.isEmpty() || !set1.isEmpty()) {
serverPlayer.connection.send(new ClientboundUpdateAdvancementsPacket(this.isFirstPacket, set, set1, map)); serverPlayer.connection.send(new ClientboundUpdateAdvancementsPacket(this.isFirstPacket, set, set1, map));
} }
@@ -331,9 +345,10 @@ public class PlayerAdvancements { @@ -331,10 +350,13 @@ public class PlayerAdvancements {
AdvancementHolder advancementHolder = node.holder(); AdvancementHolder advancementHolder = node.holder();
if (visible) { if (visible) {
if (this.visible.add(advancementHolder)) { if (this.visible.add(advancementHolder)) {
- advancementOutput.add(advancementHolder); - advancementOutput.add(advancementHolder);
+ // Leaf start - SparklyPaper - parallel world ticking
+ advancementOutput.add(advancementHolder); // Add to visible set for packet + advancementOutput.add(advancementHolder); // Add to visible set for packet
if (this.progress.containsKey(advancementHolder)) { if (this.progress.containsKey(advancementHolder)) {
- this.progressChanged.add(advancementHolder); - this.progressChanged.add(advancementHolder);
+ // If progress exists, mark it changed so the progress data is sent + // If progress exists, mark it changed so the progress data is sent
+ (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled ? this.progressChangedConcurrent : this.progressChanged).add(advancementHolder); + (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled ? this.progressChangedConcurrent : this.progressChanged).add(advancementHolder);
} }
+ // Leaf end - SparklyPaper - parallel world ticking
} }
} else if (this.visible.remove(advancementHolder)) { } else if (this.visible.remove(advancementHolder)) {
idOutput.add(advancementHolder.id());
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index d4048661575ebfaf128ba25da365843774364e0e..33dd16a26edd2974f04d9a868d3e58e8e3060032 100644 index d4048661575ebfaf128ba25da365843774364e0e..33dd16a26edd2974f04d9a868d3e58e8e3060032 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java --- a/net/minecraft/server/dedicated/DedicatedServer.java

View File

@@ -9,47 +9,23 @@ Leaf: ~48ms (-36%)
This should help drastically on the farms that use actively changing fluids. This should help drastically on the farms that use actively changing fluids.
diff --git a/net/minecraft/world/level/material/FlowingFluid.java b/net/minecraft/world/level/material/FlowingFluid.java diff --git a/net/minecraft/world/level/material/FlowingFluid.java b/net/minecraft/world/level/material/FlowingFluid.java
index 4c2c2efd5380ff1fa5ad7553b51babae20f516ae..33e5c19362de8b4002c23959661535b835eb0ce5 100644 index 4c2c2efd5380ff1fa5ad7553b51babae20f516ae..f6bc70685e846e9114f477dfd8aceca3b910a09f 100644
--- a/net/minecraft/world/level/material/FlowingFluid.java --- a/net/minecraft/world/level/material/FlowingFluid.java
+++ b/net/minecraft/world/level/material/FlowingFluid.java +++ b/net/minecraft/world/level/material/FlowingFluid.java
@@ -8,6 +8,8 @@ import it.unimi.dsi.fastutil.shorts.Short2ObjectMap; @@ -341,32 +341,81 @@ public abstract class FlowingFluid extends Fluid {
import it.unimi.dsi.fastutil.shorts.Short2ObjectOpenHashMap;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Queue;
+
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
@@ -341,31 +343,76 @@ public abstract class FlowingFluid extends Fluid {
protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state, BlockPos source) { beforeDestroyingBlock(level, pos, state); } // Paper - Add BlockBreakBlockEvent protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state, BlockPos source) { beforeDestroyingBlock(level, pos, state); } // Paper - Add BlockBreakBlockEvent
protected abstract void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state); protected abstract void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state);
- protected int getSlopeDistance(LevelReader level, BlockPos pos, int depth, Direction direction, BlockState state, FlowingFluid.SpreadContext spreadContext) { - protected int getSlopeDistance(LevelReader level, BlockPos pos, int depth, Direction direction, BlockState state, FlowingFluid.SpreadContext spreadContext) {
- int i = 1000; - int i = 1000;
+ // Leaf start - Use BFS on getSlopeDistance
+ protected int getSlopeDistance(LevelReader level, BlockPos startPos, int initialDepth, Direction excludedDirection, BlockState startState, FlowingFluid.SpreadContext spreadContext) { + protected int getSlopeDistance(LevelReader level, BlockPos startPos, int initialDepth, Direction excludedDirection, BlockState startState, FlowingFluid.SpreadContext spreadContext) {
+ it.unimi.dsi.fastutil.longs.LongSet visited = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(512); + it.unimi.dsi.fastutil.longs.LongSet visited = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(512);
+ java.util.Queue<FlowingFluid.SlopeDistanceNode> queue = new java.util.ArrayDeque<>(256); + java.util.Queue<FlowingFluid.SlopeDistanceNode> queue = new java.util.ArrayDeque<>(256);
+
- for (Direction direction1 : Direction.Plane.HORIZONTAL) {
- if (direction1 != direction) {
- BlockPos blockPos = pos.relative(direction1);
- BlockState blockState = spreadContext.getBlockStateIfLoaded(blockPos); // Paper - Prevent chunk loading from fluid flowing
- if (blockState == null) continue; // Paper - Prevent chunk loading from fluid flowing
- FluidState fluidState = blockState.getFluidState();
- if (this.canPassThrough(level, this.getFlowing(), pos, state, direction1, blockPos, blockState, fluidState)) {
- if (spreadContext.isHole(blockPos)) {
- return depth;
- }
+ for (Direction dir : Direction.Plane.HORIZONTAL) { + for (Direction dir : Direction.Plane.HORIZONTAL) {
+ if (dir == excludedDirection) continue; + if (dir == excludedDirection) continue;
+
- if (depth < this.getSlopeFindDistance(level)) {
- int slopeDistance = this.getSlopeDistance(level, blockPos, depth + 1, direction1.getOpposite(), blockState, spreadContext);
- if (slopeDistance < i) {
- i = slopeDistance;
- }
- }
+ BlockPos neighborPos = startPos.relative(dir); + BlockPos neighborPos = startPos.relative(dir);
+ BlockState neighborState = spreadContext.getBlockStateIfLoaded(neighborPos); + BlockState neighborState = spreadContext.getBlockStateIfLoaded(neighborPos);
+ if (neighborState == null) continue; + if (neighborState == null) continue;
@@ -64,10 +40,26 @@ index 4c2c2efd5380ff1fa5ad7553b51babae20f516ae..33e5c19362de8b4002c23959661535b8
+ queue.add(new FlowingFluid.SlopeDistanceNode(neighborPos, initialDepth, dir.getOpposite(), neighborState)); + queue.add(new FlowingFluid.SlopeDistanceNode(neighborPos, initialDepth, dir.getOpposite(), neighborState));
+ } + }
+ } + }
+
- for (Direction direction1 : Direction.Plane.HORIZONTAL) {
- if (direction1 != direction) {
- BlockPos blockPos = pos.relative(direction1);
- BlockState blockState = spreadContext.getBlockStateIfLoaded(blockPos); // Paper - Prevent chunk loading from fluid flowing
- if (blockState == null) continue; // Paper - Prevent chunk loading from fluid flowing
- FluidState fluidState = blockState.getFluidState();
- if (this.canPassThrough(level, this.getFlowing(), pos, state, direction1, blockPos, blockState, fluidState)) {
- if (spreadContext.isHole(blockPos)) {
- return depth;
- }
+ int slopeFindDistance = this.getSlopeFindDistance(level); + int slopeFindDistance = this.getSlopeFindDistance(level);
+ int minDistance = 1000; + int minDistance = 1000;
+
- if (depth < this.getSlopeFindDistance(level)) {
- int slopeDistance = this.getSlopeDistance(level, blockPos, depth + 1, direction1.getOpposite(), blockState, spreadContext);
- if (slopeDistance < i) {
- i = slopeDistance;
- }
- }
+ // Process the queue + // Process the queue
+ while (!queue.isEmpty()) { + while (!queue.isEmpty()) {
+ FlowingFluid.SlopeDistanceNode current = queue.poll(); + FlowingFluid.SlopeDistanceNode current = queue.poll();
@@ -76,6 +68,7 @@ index 4c2c2efd5380ff1fa5ad7553b51babae20f516ae..33e5c19362de8b4002c23959661535b8
+ } + }
+ +
+ if (current.depth >= slopeFindDistance) continue; + if (current.depth >= slopeFindDistance) continue;
+
+ for (Direction dir : Direction.Plane.HORIZONTAL) { + for (Direction dir : Direction.Plane.HORIZONTAL) {
+ if (dir == current.excludedDir) continue; + if (dir == current.excludedDir) continue;
+ +
@@ -100,7 +93,8 @@ index 4c2c2efd5380ff1fa5ad7553b51babae20f516ae..33e5c19362de8b4002c23959661535b8
+ } + }
+ +
+ private static long encodeSlopeNode(BlockPos pos, Direction excludedDir) { + private static long encodeSlopeNode(BlockPos pos, Direction excludedDir) {
+ return ((long) pos.getX() & 0xFFFFFFFFL) << 32 | ((long) pos.getZ() & 0xFFFFFFFFL) << 4 | (excludedDir.ordinal() & 0x0F);} + return ((long) pos.getX() & 0xFFFFFFFFL) << 32 | ((long) pos.getZ() & 0xFFFFFFFFL) << 4 | (excludedDir.ordinal() & 0x0F);
+ }
+ +
+ private static class SlopeDistanceNode { + private static class SlopeDistanceNode {
+ final BlockPos pos; + final BlockPos pos;
@@ -115,5 +109,7 @@ index 4c2c2efd5380ff1fa5ad7553b51babae20f516ae..33e5c19362de8b4002c23959661535b8
+ this.state = state; + this.state = state;
+ } + }
} }
+ // Leaf end - Use BFS on getSlopeDistance
boolean isWaterHole(BlockGetter level, BlockPos pos, BlockState state, BlockPos belowPos, BlockState belowState) { boolean isWaterHole(BlockGetter level, BlockPos pos, BlockState state, BlockPos belowPos, BlockState belowState) {
return canPassThroughWall(Direction.DOWN, level, pos, state, belowPos, belowState)

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Async Block Finding
diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java diff --git a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..135506968893cd164c4d416ce4d356e9f0ed3977 100644 index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..007da9cb39ff76285c52ce0abdff60997acdff0f 100644
--- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java --- a/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
+++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java +++ b/net/minecraft/world/entity/ai/goal/MoveToBlockGoal.java
@@ -20,6 +20,18 @@ public abstract class MoveToBlockGoal extends Goal { @@ -20,6 +20,18 @@ public abstract class MoveToBlockGoal extends Goal {
@@ -31,70 +31,62 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..135506968893cd164c4d416ce4d356e9
super.stop(); super.stop();
this.blockPos = BlockPos.ZERO; this.blockPos = BlockPos.ZERO;
this.mob.movingTarget = null; this.mob.movingTarget = null;
+ // Leaf start - Reset async state on goal stop + // Leaf start - Async Block Finding - Reset async state on goal stop
+ this.candidateBlocks.clear(); + this.candidateBlocks.clear();
+ this.asyncSearchInProgress = false; + this.asyncSearchInProgress = false;
+ // Leaf end + // Leaf end - Async Block Finding - Reset async state on goal stop
} }
// Paper end // Paper end
@@ -53,23 +69,28 @@ public abstract class MoveToBlockGoal extends Goal { @@ -53,23 +69,23 @@ public abstract class MoveToBlockGoal extends Goal {
} }
protected int nextStartTick(PathfinderMob creature) { protected int nextStartTick(PathfinderMob creature) {
- return reducedTickDelay(200 + creature.getRandom().nextInt(200)); - return reducedTickDelay(200 + creature.getRandom().nextInt(200));
+ // Use the static method from the Goal class directly + return Goal.reducedTickDelay(200 + creature.getRandom().nextInt(200)); // Leaf - Async Block Finding - Use the static method from the Goal class directly
+ return Goal.reducedTickDelay(200 + creature.getRandom().nextInt(200));
} }
@Override @Override
public boolean canContinueToUse() { public boolean canContinueToUse() {
- return this.tryTicks >= -this.maxStayTicks && this.tryTicks <= 1200 && this.isValidTarget(this.mob.level(), this.blockPos); - return this.tryTicks >= -this.maxStayTicks && this.tryTicks <= 1200 && this.isValidTarget(this.mob.level(), this.blockPos);
+ return this.tryTicks >= -this.maxStayTicks && this.tryTicks <= 1200 && this.blockPos != BlockPos.ZERO && this.isValidTarget(this.mob.level(), this.blockPos); + return this.tryTicks >= -this.maxStayTicks && this.tryTicks <= 1200 && this.blockPos != BlockPos.ZERO && this.isValidTarget(this.mob.level(), this.blockPos); // Leaf - Async Block Finding
} }
@Override @Override
public void start() { public void start() {
- this.moveMobToBlock(); - this.moveMobToBlock();
+ if (this.blockPos != BlockPos.ZERO) { + if (this.blockPos != BlockPos.ZERO) this.moveMobToBlock(); // Leaf - Async Block Finding
+ this.moveMobToBlock();
+ }
this.tryTicks = 0; this.tryTicks = 0;
this.maxStayTicks = this.mob.getRandom().nextInt(this.mob.getRandom().nextInt(1200) + 1200) + 1200; this.maxStayTicks = this.mob.getRandom().nextInt(this.mob.getRandom().nextInt(1200) + 1200) + 1200;
} }
protected void moveMobToBlock() { protected void moveMobToBlock() {
- this.mob.getNavigation().moveTo(this.blockPos.getX() + 0.5, this.blockPos.getY() + 1, this.blockPos.getZ() + 0.5, this.speedModifier); - this.mob.getNavigation().moveTo(this.blockPos.getX() + 0.5, this.blockPos.getY() + 1, this.blockPos.getZ() + 0.5, this.speedModifier);
+ if (this.blockPos != BlockPos.ZERO) { + if (this.blockPos != BlockPos.ZERO) this.mob.getNavigation().moveTo(this.blockPos.getX() + 0.5, this.blockPos.getY() + 1, this.blockPos.getZ() + 0.5, this.speedModifier); // Leaf - Async Block Finding
+ this.mob.getNavigation().moveTo(this.blockPos.getX() + 0.5, this.blockPos.getY() + 1, this.blockPos.getZ() + 0.5, this.speedModifier);
+ }
} }
public double acceptedDistance() { public double acceptedDistance() {
@@ -77,7 +98,7 @@ public abstract class MoveToBlockGoal extends Goal { @@ -77,7 +93,7 @@ public abstract class MoveToBlockGoal extends Goal {
} }
protected BlockPos getMoveToTarget() { protected BlockPos getMoveToTarget() {
- return this.blockPos.above(); - return this.blockPos.above();
+ return this.blockPos != BlockPos.ZERO ? this.blockPos.above() : BlockPos.ZERO; + return this.blockPos != BlockPos.ZERO ? this.blockPos.above() : BlockPos.ZERO; // Leaf - Async Block Finding
} }
@Override @Override
@@ -87,7 +108,13 @@ public abstract class MoveToBlockGoal extends Goal { @@ -87,7 +103,10 @@ public abstract class MoveToBlockGoal extends Goal {
@Override @Override
public void tick() { public void tick() {
+ if (this.blockPos == BlockPos.ZERO) { + if (this.blockPos == BlockPos.ZERO) return; // Leaf - Async Block Finding
+ return;
+ }
+
BlockPos moveToTarget = this.getMoveToTarget(); BlockPos moveToTarget = this.getMoveToTarget();
+ if (moveToTarget == BlockPos.ZERO) return; + if (moveToTarget == BlockPos.ZERO) return; // Leaf - Async Block Finding
+ +
if (!moveToTarget.closerToCenterThan(this.mob.position(), this.acceptedDistance())) { if (!moveToTarget.closerToCenterThan(this.mob.position(), this.acceptedDistance())) {
this.reachedTarget = false; this.reachedTarget = false;
this.tryTicks++; this.tryTicks++;
@@ -109,20 +136,90 @@ public abstract class MoveToBlockGoal extends Goal { @@ -109,20 +128,90 @@ public abstract class MoveToBlockGoal extends Goal {
} }
protected boolean findNearestBlock() { protected boolean findNearestBlock() {
@@ -139,7 +131,6 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..135506968893cd164c4d416ce4d356e9
+ } + }
+ +
+ return false; + return false;
+ // Leaf end - Async Block Finding
+ } + }
+ +
+ private void generateCandidateBlocks(BlockPos center, int searchRange, int verticalRange, int verticalStart) { + private void generateCandidateBlocks(BlockPos center, int searchRange, int verticalRange, int verticalStart) {
@@ -168,10 +159,11 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..135506968893cd164c4d416ce4d356e9
+ } + }
+ +
+ protected boolean findNearestBlockSync() { + protected boolean findNearestBlockSync() {
+ // Leaf end - Async Block Finding
int i = this.searchRange; int i = this.searchRange;
int i1 = this.verticalSearchRange; int i1 = this.verticalSearchRange;
- BlockPos blockPos = this.mob.blockPosition(); - BlockPos blockPos = this.mob.blockPosition();
+ BlockPos blockPosOrigin = this.mob.blockPosition(); + BlockPos blockPosOrigin = this.mob.blockPosition(); // Leaf - Async Block Finding
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
for (int i2 = this.verticalSearchStart; i2 <= i1; i2 = i2 > 0 ? -i2 : 1 - i2) { for (int i2 = this.verticalSearchStart; i2 <= i1; i2 = i2 > 0 ? -i2 : 1 - i2) {
@@ -179,19 +171,13 @@ index 3f080b15543bf8c5fa0774b62d7f12e13b82511a..135506968893cd164c4d416ce4d356e9
for (int i4 = 0; i4 <= i3; i4 = i4 > 0 ? -i4 : 1 - i4) { for (int i4 = 0; i4 <= i3; i4 = i4 > 0 ? -i4 : 1 - i4) {
for (int i5 = i4 < i3 && i4 > -i3 ? i3 : 0; i5 <= i3; i5 = i5 > 0 ? -i5 : 1 - i5) { for (int i5 = i4 < i3 && i4 > -i3 ? i3 : 0; i5 <= i3; i5 = i5 > 0 ? -i5 : 1 - i5) {
- mutableBlockPos.setWithOffset(blockPos, i4, i2 - 1, i5); - mutableBlockPos.setWithOffset(blockPos, i4, i2 - 1, i5);
+ mutableBlockPos.setWithOffset(blockPosOrigin, i4, i2 - 1, i5); + mutableBlockPos.setWithOffset(blockPosOrigin, i4, i2 - 1, i5); // Leaf - Async Block Finding
if (!this.mob.level().hasChunkAt(mutableBlockPos)) continue; // Gale - Airplane - block goal does not load chunks - if this block isn't loaded, continue if (!this.mob.level().hasChunkAt(mutableBlockPos)) continue; // Gale - Airplane - block goal does not load chunks - if this block isn't loaded, continue
if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level(), mutableBlockPos)) { if (this.mob.isWithinRestriction(mutableBlockPos) && this.isValidTarget(this.mob.level(), mutableBlockPos)) {
- this.blockPos = mutableBlockPos; - this.blockPos = mutableBlockPos;
- this.mob.movingTarget = mutableBlockPos == BlockPos.ZERO ? null : mutableBlockPos.immutable(); // Paper - this.mob.movingTarget = mutableBlockPos == BlockPos.ZERO ? null : mutableBlockPos.immutable(); // Paper
+ this.blockPos = mutableBlockPos.immutable(); + this.blockPos = mutableBlockPos.immutable(); // Leaf - Async Block Finding
+ this.mob.movingTarget = this.blockPos == BlockPos.ZERO ? null : this.blockPos; // Paper + this.mob.movingTarget = this.blockPos == BlockPos.ZERO ? null : this.blockPos; // Paper // Leaf - Async Block Finding
return true; return true;
} }
} }
@@ -134,4 +231,5 @@ public abstract class MoveToBlockGoal extends Goal {
}
protected abstract boolean isValidTarget(LevelReader level, BlockPos pos);
+
}

View File

@@ -1,44 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Taiyou06 <kaandindar21@gmail.com> From: Taiyou06 <kaandindar21@gmail.com>
Date: Sat, 29 Mar 2025 13:40:46 +0100 Date: Sat, 29 Mar 2025 13:40:46 +0100
Subject: [PATCH] AsyncTargetFinding Subject: [PATCH] Async Target Finding
diff --git a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java diff --git a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac71203d31a58f 100644 index 41ee3cdc45ecc8376a2203ed588bb544ed377294..ed731177585051abbf129a48dfe4766265cf5617 100644
--- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java --- a/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java +++ b/net/minecraft/world/entity/ai/goal/target/NearestAttackableTargetGoal.java
@@ -1,6 +1,13 @@ @@ -16,9 +16,37 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
package net.minecraft.world.entity.ai.goal.target;
import java.util.EnumSet;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Nullable;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@@ -10,15 +17,42 @@ import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.phys.AABB;
+import org.dreeam.leaf.config.modules.async.AsyncTargetFinding;
public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetGoal {
private static final int DEFAULT_RANDOM_INTERVAL = 10;
protected final Class<T> targetType; protected final Class<T> targetType;
protected final int randomInterval; protected final int randomInterval;
@Nullable @Nullable
- protected LivingEntity target; - protected LivingEntity target;
+ protected volatile LivingEntity target; + protected volatile LivingEntity target; // Leaf - Async Target Finding
protected TargetingConditions targetConditions; protected TargetingConditions targetConditions;
+ // Leaf start - Async Target Finding
+ // Single thread executor to prevent overwhelming the server + // Single thread executor to prevent overwhelming the server
+ private static final ExecutorService TARGET_FINDER_EXECUTOR = Executors.newSingleThreadExecutor(r -> { + private static final java.util.concurrent.ExecutorService TARGET_FINDER_EXECUTOR = java.util.concurrent.Executors.newSingleThreadExecutor(r -> {
+ Thread thread = new Thread(r, "Leaf - Target-Finder-Thread"); + Thread thread = new Thread(r, "Leaf - Target-Finder-Thread");
+ thread.setDaemon(true); + thread.setDaemon(true);
+ thread.setPriority(Thread.MIN_PRIORITY); // Lower priority to avoid competing with main thread + thread.setPriority(Thread.MIN_PRIORITY); // Lower priority to avoid competing with main thread
@@ -46,13 +26,13 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac7120
+ }); + });
+ +
+ // Flag to track if a search is in progress + // Flag to track if a search is in progress
+ private final AtomicBoolean isSearching = new AtomicBoolean(false); + private final java.util.concurrent.atomic.AtomicBoolean isSearching = new java.util.concurrent.atomic.AtomicBoolean(false);
+ private final AtomicReference<LivingEntity> pendingTarget = new AtomicReference<>(null); + private final java.util.concurrent.atomic.AtomicReference<LivingEntity> pendingTarget = new java.util.concurrent.atomic.AtomicReference<>(null);
+ static { + static {
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> { + Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ try { + try {
+ TARGET_FINDER_EXECUTOR.shutdown(); + TARGET_FINDER_EXECUTOR.shutdown();
+ TARGET_FINDER_EXECUTOR.awaitTermination(2, TimeUnit.SECONDS); + TARGET_FINDER_EXECUTOR.awaitTermination(2, java.util.concurrent.TimeUnit.SECONDS);
+ } catch (InterruptedException e) { + } catch (InterruptedException e) {
+ Thread.currentThread().interrupt(); + Thread.currentThread().interrupt();
+ } finally { + } finally {
@@ -62,29 +42,33 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac7120
+ } + }
+ })); + }));
+ } + }
+ // Leaf end - Async Target Finding
+ +
public NearestAttackableTargetGoal(Mob mob, Class<T> targetType, boolean mustSee) { public NearestAttackableTargetGoal(Mob mob, Class<T> targetType, boolean mustSee) {
this(mob, targetType, 10, mustSee, false, null); this(mob, targetType, 10, mustSee, false, null);
} }
@@ -46,8 +80,12 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG @@ -46,8 +74,14 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) { if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) {
return false; return false;
} else { } else {
- this.findTarget(); - this.findTarget();
- return this.target != null; - return this.target != null;
+ // Leaf start - Async Target Finding
+ findTarget(); + findTarget();
+ LivingEntity pending = pendingTarget.getAndSet(null); + LivingEntity pending = pendingTarget.getAndSet(null);
+ if (pending != null && !pending.isRemoved() && pending.isAlive()) { + if (pending != null && !pending.isRemoved() && pending.isAlive()) {
+ this.target = pending; + this.target = pending;
+ } + }
+ return this.target != null && this.target.isAlive() && !this.target.isRemoved(); + return this.target != null && this.target.isAlive() && !this.target.isRemoved();
+ // Leaf end - Async Target Finding
} }
} }
@@ -55,25 +93,235 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG @@ -55,25 +89,239 @@ public class NearestAttackableTargetGoal<T extends LivingEntity> extends TargetG
return this.mob.getBoundingBox().inflate(targetDistance, targetDistance, targetDistance); return this.mob.getBoundingBox().inflate(targetDistance, targetDistance, targetDistance);
} }
+ // Leaf start - Async Target Finding
+ // Async find target implementation with safer entity handling + // Async find target implementation with safer entity handling
protected void findTarget() { protected void findTarget() {
- ServerLevel serverLevel = getServerLevel(this.mob); - ServerLevel serverLevel = getServerLevel(this.mob);
@@ -100,10 +84,10 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac7120
- } else { - } else {
- this.target = serverLevel.getNearestPlayer(this.getTargetConditions(), this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ()); - this.target = serverLevel.getNearestPlayer(this.getTargetConditions(), this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ());
+ // If async is disabled or we're already searching, use sync method + // If async is disabled or we're already searching, use sync method
+ if (!AsyncTargetFinding.enabled || !isSearching.compareAndSet(false, true)) { + if (!org.dreeam.leaf.config.modules.async.AsyncTargetFinding.enabled || !isSearching.compareAndSet(false, true)) {
+ findTargetSync(); + findTargetSync();
+ return; + return;
+ } }
+ +
+ // Capture mutable state to avoid race conditions + // Capture mutable state to avoid race conditions
+ final Mob mob = this.mob; + final Mob mob = this.mob;
@@ -122,7 +106,7 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac7120
+ final Class<T> targetType = this.targetType; + final Class<T> targetType = this.targetType;
+ +
+ // Start async search with immutable captured state - using submit instead of runAsync + // Start async search with immutable captured state - using submit instead of runAsync
+ CompletableFuture.supplyAsync(() -> { + java.util.concurrent.CompletableFuture.supplyAsync(() -> {
+ try { + try {
+ ServerLevel serverLevel = getServerLevel(mob); + ServerLevel serverLevel = getServerLevel(mob);
+ if (serverLevel == null) { + if (serverLevel == null) {
@@ -139,7 +123,7 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac7120
+ x + followDistance, y + followDistance, z + followDistance + x + followDistance, y + followDistance, z + followDistance
+ ); + );
+ +
+ List<T> entities = null; + java.util.List<T> entities = null;
+ try { + try {
+ entities = mob.level().getEntitiesOfClass(targetType, searchArea, entity -> true); + entities = mob.level().getEntitiesOfClass(targetType, searchArea, entity -> true);
+ } catch (Exception e) { + } catch (Exception e) {
@@ -169,11 +153,11 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac7120
+ pendingTarget.set(result); + pendingTarget.set(result);
+ } + }
+ }); + });
+ } }
+
+ @Nullable + @Nullable
+ private LivingEntity findNearestEntitySafely( + private LivingEntity findNearestEntitySafely(
+ List<? extends LivingEntity> entities, + java.util.List<? extends LivingEntity> entities,
+ TargetingConditions conditions, + TargetingConditions conditions,
+ Mob source, + Mob source,
+ double x, + double x,
@@ -236,7 +220,7 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac7120
+ } + }
+ +
+ try { + try {
+ List<? extends Player> players = level.players(); + java.util.List<? extends Player> players = level.players();
+ if (players == null || players.isEmpty()) { + if (players == null || players.isEmpty()) {
+ return null; + return null;
+ } + }
@@ -310,12 +294,14 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac7120
+ } catch (Exception e) { + } catch (Exception e) {
+ System.err.println("Error in findTargetSync: " + e.getMessage()); + System.err.println("Error in findTargetSync: " + e.getMessage());
+ this.target = null; + this.target = null;
} + }
} + }
+ // Leaf end - Async Target Finding
+
@Override @Override
public void start() { public void start() {
- this.mob.setTarget(this.target, this.target instanceof ServerPlayer ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY, true); // CraftBukkit - reason - this.mob.setTarget(this.target, this.target instanceof ServerPlayer ? org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER : org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_ENTITY, true); // CraftBukkit - reason
+ // Leaf start - Async Target Finding
+ LivingEntity targetEntity = this.target; + LivingEntity targetEntity = this.target;
+ if (targetEntity != null && !targetEntity.isRemoved() && targetEntity.isAlive()) { + if (targetEntity != null && !targetEntity.isRemoved() && targetEntity.isAlive()) {
+ try { + try {
@@ -327,6 +313,7 @@ index 41ee3cdc45ecc8376a2203ed588bb544ed377294..7fe2b75e8c2718851d68429380ac7120
+ this.target = null; + this.target = null;
+ } + }
+ } + }
+ // Leaf end - Async Target Finding
super.start(); super.start();
} }

View File

@@ -6,27 +6,20 @@ Subject: [PATCH] Null handling on MultifaceSpreader
WHYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY WHYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
diff --git a/net/minecraft/world/level/block/MultifaceSpreader.java b/net/minecraft/world/level/block/MultifaceSpreader.java diff --git a/net/minecraft/world/level/block/MultifaceSpreader.java b/net/minecraft/world/level/block/MultifaceSpreader.java
index 60f47334bb855d5216f57f888f131ba41f728d21..7d54362767ec2acfcb9f8f8703ec706a1c2fd03b 100644 index 60f47334bb855d5216f57f888f131ba41f728d21..718223a54da75d000e3c3090acf6e28b4283820a 100644
--- a/net/minecraft/world/level/block/MultifaceSpreader.java --- a/net/minecraft/world/level/block/MultifaceSpreader.java
+++ b/net/minecraft/world/level/block/MultifaceSpreader.java +++ b/net/minecraft/world/level/block/MultifaceSpreader.java
@@ -10,6 +10,8 @@ import net.minecraft.world.level.BlockGetter; @@ -148,6 +148,14 @@ public class MultifaceSpreader {
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.state.BlockState;
+import static org.dreeam.leaf.config.LeafConfig.LOGGER;
+
public class MultifaceSpreader {
public static final MultifaceSpreader.SpreadType[] DEFAULT_SPREAD_ORDER = new MultifaceSpreader.SpreadType[]{
MultifaceSpreader.SpreadType.SAME_POSITION, MultifaceSpreader.SpreadType.SAME_PLANE, MultifaceSpreader.SpreadType.WRAP_AROUND
@@ -148,6 +150,12 @@ public class MultifaceSpreader {
} }
default boolean placeBlock(LevelAccessor level, MultifaceSpreader.SpreadPos pos, BlockState state, boolean markForPostprocessing) { default boolean placeBlock(LevelAccessor level, MultifaceSpreader.SpreadPos pos, BlockState state, boolean markForPostprocessing) {
+ // Leaf start - Null handling on MultifaceSpreader
+ // Check for null + // Check for null
+ if (pos.source() == null || pos.pos() == null) { + if (pos.source() == null || pos.pos() == null) {
+ LOGGER.warn("Invalid SpreadPos with null source or position: {}", pos); + org.dreeam.leaf.config.LeafConfig.LOGGER.warn("Invalid SpreadPos with null source or position: {}", pos);
+ return false; + return false;
+ } + }
+ // Leaf end - Null handling on MultifaceSpreader
+ +
BlockState stateForPlacement = this.getStateForPlacement(state, level, pos.pos(), pos.face()); BlockState stateForPlacement = this.getStateForPlacement(state, level, pos.pos(), pos.face());
if (stateForPlacement != null) { if (stateForPlacement != null) {

View File

@@ -5,50 +5,34 @@ Subject: [PATCH] More virtual threads
diff --git a/net/minecraft/Util.java b/net/minecraft/Util.java diff --git a/net/minecraft/Util.java b/net/minecraft/Util.java
index b097f685e826e70008e3a096ee5f1d4fccf25680..f374428c65e929b8795f2a0ddfe3137b4afca9bc 100644 index b097f685e826e70008e3a096ee5f1d4fccf25680..aa79e95dc93927ce224c02e4382c7246cb48d51c 100644
--- a/net/minecraft/Util.java --- a/net/minecraft/Util.java
+++ b/net/minecraft/Util.java +++ b/net/minecraft/Util.java
@@ -61,6 +61,7 @@ import java.util.concurrent.ForkJoinPool; @@ -97,7 +97,8 @@ public class Util {
import java.util.concurrent.ForkJoinWorkerThread;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiFunction;
import java.util.function.BooleanSupplier;
@@ -86,6 +87,10 @@ import net.minecraft.util.TimeSource;
import net.minecraft.util.datafix.DataFixers;
import net.minecraft.world.level.block.state.properties.Property;
import org.slf4j.Logger;
+import org.galemc.gale.virtualthread.VirtualThreadService; // Gale - virtual thread support
+import org.dreeam.leaf.config.modules.opt.VT4DownloadPool;
+import org.dreeam.leaf.config.modules.opt.VT4ProfileExecutor;
+
public class Util {
static final Logger LOGGER = LogUtils.getLogger();
@@ -97,7 +102,7 @@ public class Util {
public static final TracingExecutor DIMENSION_DATA_IO_POOL = makeExtraIoExecutor("Dimension-Data-IO-Worker-"); // Paper - Separate dimension data IO pool public static final TracingExecutor DIMENSION_DATA_IO_POOL = makeExtraIoExecutor("Dimension-Data-IO-Worker-"); // Paper - Separate dimension data IO pool
private static final TracingExecutor DOWNLOAD_POOL = makeIoExecutor("Download-", true); private static final TracingExecutor DOWNLOAD_POOL = makeIoExecutor("Download-", true);
// Paper start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread // Paper start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
- public static final ExecutorService PROFILE_EXECUTOR = Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() { - public static final ExecutorService PROFILE_EXECUTOR = Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() {
+ // Leaf start - More virtual threads
+ public static final ExecutorService PROFILE_EXECUTOR = createProfileExecutor(); /* new Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() { + public static final ExecutorService PROFILE_EXECUTOR = createProfileExecutor(); /* new Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() {
private final AtomicInteger count = new AtomicInteger(); private final AtomicInteger count = new AtomicInteger();
@@ -110,7 +115,27 @@ public class Util { @@ -110,7 +111,30 @@ public class Util {
}); });
return ret; return ret;
} }
- }); - });
+ }); */ + }); */
+
+ private static ExecutorService createProfileExecutor() { + private static ExecutorService createProfileExecutor() {
+ final ThreadFactory factory; + final java.util.concurrent.ThreadFactory factory;
+ if (VT4ProfileExecutor.enabled && VirtualThreadService.isSupported()) { + if (org.dreeam.leaf.config.modules.opt.VT4ProfileExecutor.enabled && org.galemc.gale.virtualthread.VirtualThreadService.isSupported()) {
+ factory = VirtualThreadService.get().createFactory(); + factory = org.galemc.gale.virtualthread.VirtualThreadService.get().createFactory();
+ } else { + } else {
+ factory = new ThreadFactory() { + factory = new java.util.concurrent.ThreadFactory() {
+ private final AtomicInteger count = new AtomicInteger(); + private final AtomicInteger count = new AtomicInteger();
+
+ @Override + @Override
+ public Thread newThread(Runnable run) { + public Thread newThread(Runnable run) {
+ Thread ret = new Thread(run); + Thread ret = new Thread(run);
@@ -62,10 +46,11 @@ index b097f685e826e70008e3a096ee5f1d4fccf25680..f374428c65e929b8795f2a0ddfe3137b
+ } + }
+ return Executors.newFixedThreadPool(2, factory); + return Executors.newFixedThreadPool(2, factory);
+ } + }
+ // Leaf end - More virtual threads
// Paper end - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread // Paper end - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
private static final DateTimeFormatter FILENAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT); private static final DateTimeFormatter FILENAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT);
public static final int LINEAR_LOOKUP_THRESHOLD = 8; public static final int LINEAR_LOOKUP_THRESHOLD = 8;
@@ -254,16 +279,29 @@ public class Util { @@ -254,16 +278,31 @@ public class Util {
} }
private static TracingExecutor makeIoExecutor(String name, boolean daemon) { private static TracingExecutor makeIoExecutor(String name, boolean daemon) {
@@ -79,16 +64,17 @@ index b097f685e826e70008e3a096ee5f1d4fccf25680..f374428c65e929b8795f2a0ddfe3137b
- thread.setUncaughtExceptionHandler(Util::onThreadException); - thread.setUncaughtExceptionHandler(Util::onThreadException);
- return thread; - return thread;
- })); - }));
+ final ThreadFactory factory; + // Leaf start - More virtual threads
+ final java.util.concurrent.ThreadFactory factory;
+ final boolean useVirtualThreads; // Gale - virtual thread support + final boolean useVirtualThreads; // Gale - virtual thread support
+ if (name.startsWith("Download-")) { // Gale - virtual thread support + if (name.startsWith("Download-")) { // Gale - virtual thread support
+ useVirtualThreads = VT4DownloadPool.enabled && VirtualThreadService.isSupported(); // Gale - virtual thread support + useVirtualThreads = org.dreeam.leaf.config.modules.opt.VT4DownloadPool.enabled && org.galemc.gale.virtualthread.VirtualThreadService.isSupported(); // Gale - virtual thread support
+ } else { + } else {
+ useVirtualThreads = false; + useVirtualThreads = false;
+ } + }
+ +
+ if (useVirtualThreads) { + if (useVirtualThreads) {
+ factory = VirtualThreadService.get().createFactory(); + factory = org.galemc.gale.virtualthread.VirtualThreadService.get().createFactory();
+ } else { + } else {
+ AtomicInteger atomicInteger = new AtomicInteger(1); + AtomicInteger atomicInteger = new AtomicInteger(1);
+ factory = runnable -> { + factory = runnable -> {
@@ -102,10 +88,11 @@ index b097f685e826e70008e3a096ee5f1d4fccf25680..f374428c65e929b8795f2a0ddfe3137b
+ }; + };
+ } + }
+ return new TracingExecutor(Executors.newCachedThreadPool(factory)); + return new TracingExecutor(Executors.newCachedThreadPool(factory));
+ // Leaf end - More virtual threads
} }
// Paper start - Separate dimension data IO pool // Paper start - Separate dimension data IO pool
@@ -1099,7 +1137,7 @@ public class Util { @@ -1099,7 +1138,7 @@ public class Util {
} }
public static <T> Typed<T> readTypedOrThrow(Type<T> type, Dynamic<?> data, boolean partial) { public static <T> Typed<T> readTypedOrThrow(Type<T> type, Dynamic<?> data, boolean partial) {
@@ -114,26 +101,12 @@ index b097f685e826e70008e3a096ee5f1d4fccf25680..f374428c65e929b8795f2a0ddfe3137b
try { try {
return partial ? dataResult.getPartialOrThrow(IllegalStateException::new) : dataResult.getOrThrow(IllegalStateException::new); return partial ? dataResult.getPartialOrThrow(IllegalStateException::new) : dataResult.getOrThrow(IllegalStateException::new);
@@ -1143,12 +1181,14 @@ public class Util { @@ -1148,7 +1187,7 @@ public class Util {
private final String telemetryName;
+ // Paper start - Fix warnings on build by removing client-only code
OS(final String telemetryName) {
this.telemetryName = telemetryName;
} }
public void openUri(URI uri) { public void openUri(URI uri) {
- throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper - Fix warnings on build by removing client-only code - throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper - Fix warnings on build by removing client-only code
+ // This method is not useful on dedicated servers. + // throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper - Fix warnings on build by removing client-only code // Leaf - More virtual threads - This method is not useful on dedicated servers
+ // throw new IllegalStateException("This method is not useful on dedicated servers."); // Paper - Fix warnings on build by removing client-only code
} }
public void openFile(File file) { public void openFile(File file) {
@@ -1179,5 +1219,6 @@ public class Util {
public String telemetryName() {
return this.telemetryName;
}
+ // Paper end - Fix warnings on build by removing client-only code
}
}

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Async playerdata saving
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
index f2d87c12dd19210ce7e2147fada5c10191008632..bd6608787abcd1869f66d67297c6b4252193080a 100644 index f2d87c12dd19210ce7e2147fada5c10191008632..14da4c731391f69fef104b6b3b7f2f977fe5ee95 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java --- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
@@ -207,7 +207,7 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa @@ -207,7 +207,7 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
@@ -17,7 +17,7 @@ index f2d87c12dd19210ce7e2147fada5c10191008632..bd6608787abcd1869f66d67297c6b425
} }
private CompoundTag getBukkitData() { private CompoundTag getBukkitData() {
@@ -813,16 +813,9 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa @@ -813,16 +813,7 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
* @param compoundTag * @param compoundTag
*/ */
private void save(CompoundTag compoundTag) { private void save(CompoundTag compoundTag) {
@@ -31,9 +31,7 @@ index f2d87c12dd19210ce7e2147fada5c10191008632..bd6608787abcd1869f66d67297c6b425
- } catch (java.io.IOException e) { - } catch (java.io.IOException e) {
- e.printStackTrace(); - e.printStackTrace();
- } - }
+ // Leaf start - Async playerdata saving + server.console.playerDataStorage.save(this.getName(), this.getUniqueId(), this.getUniqueId().toString(), compoundTag); // Leaf - Async playerdata saving
+ server.console.playerDataStorage.save(this.getName(), this.getUniqueId(), this.getUniqueId().toString(), compoundTag);
+ // Leaf end
} }
// Purpur end - OfflinePlayer API // Purpur end - OfflinePlayer API
} }

View File

@@ -3,6 +3,7 @@ set -e
IS_EOL=false IS_EOL=false
IS_UNSUPPORTED=false IS_UNSUPPORTED=false
IS_DEV=false
JAR_NAME="leaf-1.21.4" JAR_NAME="leaf-1.21.4"
CURRENT_TAG="ver-1.21.4" CURRENT_TAG="ver-1.21.4"
@@ -89,6 +90,16 @@ if [ $IS_UNSUPPORTED = true ]; then
} >> $RELEASE_NOTES } >> $RELEASE_NOTES
fi fi
# Dev build warning
if [ $IS_DEV = true ]; then
{
echo ""
echo "> [!WARNING]"
echo "> This is the early dev build, only for testing usage."
echo "> Do not use in the production environment!"
} >> $RELEASE_NOTES
fi
# Delete current release tag # Delete current release tag
if git show-ref --tags $CURRENT_TAG --quiet; then if git show-ref --tags $CURRENT_TAG --quiet; then
{ {