From 15237645d51b8954cd3ac7dadbf89a375114debd Mon Sep 17 00:00:00 2001 From: Taiyou06 Date: Sat, 5 Apr 2025 16:30:48 +0200 Subject: [PATCH] fix a regression caused by advencement fixing for PWT --- ...-SparklyPaper-Parallel-world-ticking.patch | 157 ++++++++++++------ 1 file changed, 102 insertions(+), 55 deletions(-) diff --git a/leaf-server/minecraft-patches/features/0139-SparklyPaper-Parallel-world-ticking.patch b/leaf-server/minecraft-patches/features/0139-SparklyPaper-Parallel-world-ticking.patch index 7a21b0cb..6d404852 100644 --- a/leaf-server/minecraft-patches/features/0139-SparklyPaper-Parallel-world-ticking.patch +++ b/leaf-server/minecraft-patches/features/0139-SparklyPaper-Parallel-world-ticking.patch @@ -424,7 +424,7 @@ index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11 } // CraftBukkit end diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java -index d2159a747fe42aa95cfc6bca0e55e3f4485847bb..8b74e9abba806a311f52b82732ce3c92638d50c4 100644 +index d2159a747fe42aa95cfc6bca0e55e3f4485847bb..a7e1c9979897a12a7a8f417545ae96f703a1b248 100644 --- a/net/minecraft/server/PlayerAdvancements.java +++ b/net/minecraft/server/PlayerAdvancements.java @@ -19,6 +19,7 @@ import java.nio.file.Path; @@ -435,94 +435,141 @@ index d2159a747fe42aa95cfc6bca0e55e3f4485847bb..8b74e9abba806a311f52b82732ce3c92 import java.util.Map; import java.util.Set; import java.util.Map.Entry; -@@ -53,7 +54,8 @@ public class PlayerAdvancements { +@@ -53,8 +54,9 @@ public class PlayerAdvancements { private AdvancementTree tree; private final Map progress = new LinkedHashMap<>(); private final Set visible = new HashSet<>(); - private final Set progressChanged = new HashSet<>(); -+ private final Set progressChanged = new HashSet<>(); // Default implementation -+ private final Set progressChangedConcurrent = ConcurrentHashMap.newKeySet(); // Thread-safe implementation for parallel world ticking - private final Set rootsToUpdate = new HashSet<>(); +- private final Set rootsToUpdate = new HashSet<>(); ++ private final Set progressChanged = new HashSet<>(); // Used when PWT is disabled ++ private final Set progressChangedConcurrent = ConcurrentHashMap.newKeySet(); // Used when PWT is enabled ++ private final Set rootsToUpdate = new HashSet<>(); // Always managed on player tick thread private ServerPlayer player; @Nullable -@@ -184,7 +186,13 @@ public class PlayerAdvancements { + private AdvancementHolder lastSelectedTab; +@@ -88,6 +90,8 @@ public class PlayerAdvancements { + this.visible.clear(); + this.rootsToUpdate.clear(); + this.progressChanged.clear(); ++ // PWT Fix: Also clear concurrent set on reload ++ this.progressChangedConcurrent.clear(); + this.isFirstPacket = true; + this.lastSelectedTab = null; + this.tree = manager.tree(); +@@ -151,6 +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 + } else { + this.startProgress(advancementHolder, progress); ++ // PWT Fix: Always add to non-concurrent set during load, flushDirty will handle sync + this.progressChanged.add(advancementHolder); + this.markForVisibilityUpdate(advancementHolder); + } +@@ -183,25 +188,25 @@ public class PlayerAdvancements { + return false; } // Paper end - Add PlayerAdvancementCriterionGrantEvent - this.unregisterListeners(advancement); +- this.unregisterListeners(advancement); - this.progressChanged.add(advancement); -+ -+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) { -+ this.progressChangedConcurrent.add(advancement); -+ } else { -+ this.progressChanged.add(advancement); -+ } -+ - flag = true; - if (!isDone && orStartProgress.isDone()) { +- flag = true; +- if (!isDone && orStartProgress.isDone()) { ++ this.unregisterListeners(advancement); // Must unregister criteria listeners ++ (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled ? this.progressChangedConcurrent : this.progressChanged).add(advancement); ++ flag = true; // Mark progress changed ++ if (!isDone && orStartProgress.isDone()) { // If the advancement was just completed // Paper start - Add Adventure message to PlayerAdvancementDoneEvent -@@ -221,7 +229,11 @@ public class PlayerAdvancements { +- final net.kyori.adventure.text.Component message = advancement.value().display().flatMap(info -> { +- return java.util.Optional.ofNullable( +- info.shouldAnnounceChat() ? io.papermc.paper.adventure.PaperAdventure.asAdventure(info.getType().createAnnouncement(advancement, this.player)) : null +- ); +- }).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); boolean isDone = orStartProgress.isDone(); if (orStartProgress.revokeProgress(criterionKey)) { - this.registerListeners(advancement); +- this.registerListeners(advancement); - this.progressChanged.add(advancement); -+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) { -+ this.progressChangedConcurrent.add(advancement); -+ } else { -+ this.progressChanged.add(advancement); -+ } ++ 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); flag = true; } -@@ -271,7 +283,11 @@ public class PlayerAdvancements { +- if (isDone && !orStartProgress.isDone()) { ++ if (isDone && !orStartProgress.isDone()) { // If the advancement was just un-completed + this.markForVisibilityUpdate(advancement); + } + +@@ -271,7 +276,9 @@ public class PlayerAdvancements { } public void flushDirty(ServerPlayer serverPlayer) { - if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !this.progressChanged.isEmpty()) { -+ boolean hasProgressChanges = org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled -+ ? !this.progressChangedConcurrent.isEmpty() -+ : !this.progressChanged.isEmpty(); -+ -+ if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || hasProgressChanges) { ++ final boolean useConcurrent = org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled; ++ final Set relevantProgressSet = useConcurrent ? this.progressChangedConcurrent : this.progressChanged; ++ if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !relevantProgressSet.isEmpty()) { Map map = new HashMap<>(); Set set = new java.util.TreeSet<>(java.util.Comparator.comparing(adv -> adv.id().toString())); // Paper - Changed from HashSet to TreeSet ordered alphabetically. Set set1 = new HashSet<>(); -@@ -280,6 +296,19 @@ public class PlayerAdvancements { +@@ -279,16 +286,23 @@ public class PlayerAdvancements { + for (AdvancementNode advancementNode : this.rootsToUpdate) { this.updateTreeVisibility(advancementNode, set, set1); } ++ this.rootsToUpdate.clear(); // Roots processed, clear the set -+ // Process advancements with changed progress -+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) { -+ // Using concurrent set - create a copy to avoid possible ConcurrentModificationException -+ // during visualization and packet sending -+ Set copy = new HashSet<>(this.progressChangedConcurrent); -+ for (AdvancementHolder advancementHolder : copy) { -+ if (this.visible.contains(advancementHolder)) { +- this.rootsToUpdate.clear(); ++ if (!relevantProgressSet.isEmpty()) { ++ Set toProcess = useConcurrent ? new HashSet<>(relevantProgressSet) : relevantProgressSet; + +- for (AdvancementHolder advancementHolder : this.progressChanged) { +- if (this.visible.contains(advancementHolder)) { +- map.put(advancementHolder.id(), this.progress.get(advancementHolder)); ++ for (AdvancementHolder advancementHolder : toProcess) { ++ if (this.visible.contains(advancementHolder)) { // Only include progress for visible advancements + map.put(advancementHolder.id(), this.progress.get(advancementHolder)); + } + } +- } + +- this.progressChanged.clear(); ++ if (useConcurrent) { ++ this.progressChangedConcurrent.removeAll(toProcess); // Remove processed items from concurrent set ++ } else { ++ this.progressChanged.clear(); // Clear the regular set + } -+ this.progressChangedConcurrent.removeAll(copy); -+ } else { -+ // Original logic using non-concurrent set - this.rootsToUpdate.clear(); - - for (AdvancementHolder advancementHolder : this.progressChanged) { -@@ -289,6 +318,7 @@ public class PlayerAdvancements { - } - - this.progressChanged.clear(); + } if (!map.isEmpty() || !set.isEmpty() || !set1.isEmpty()) { serverPlayer.connection.send(new ClientboundUpdateAdvancementsPacket(this.isFirstPacket, set, set1, map)); } -@@ -334,6 +364,11 @@ public class PlayerAdvancements { - advancementOutput.add(advancementHolder); +@@ -331,9 +345,10 @@ public class PlayerAdvancements { + AdvancementHolder advancementHolder = node.holder(); + if (visible) { + if (this.visible.add(advancementHolder)) { +- advancementOutput.add(advancementHolder); ++ advancementOutput.add(advancementHolder); // Add to visible set for packet if (this.progress.containsKey(advancementHolder)) { - this.progressChanged.add(advancementHolder); -+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) { -+ this.progressChangedConcurrent.add(advancementHolder); -+ } else { -+ this.progressChanged.add(advancementHolder); -+ } +- this.progressChanged.add(advancementHolder); ++ // 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); } } } else if (this.visible.remove(advancementHolder)) {