From 0a63aeaca2db9ee5645fcc49f99d073e23c4e667 Mon Sep 17 00:00:00 2001 From: MrHua269 Date: Thu, 2 May 2024 04:24:28 +0000 Subject: [PATCH] Removed useless patches --- .../0019-Kaiiju-Async-path-processing.patch | 1316 ----------------- ...ch => 0019-Petal-Reduce-sensor-work.patch} | 4 +- ...fish-Optimize-entity-coordinate-key.patch} | 0 ...Cache-climbing-check-for-activation.patch} | 0 ...ish-Improve-fluid-direction-caching.patch} | 0 ...023-Pufferfish-Optimize-suffocation.patch} | 0 ...return-optimization-for-target-find.patch} | 0 ...erfish-Reduce-chunk-loading-lookups.patch} | 0 ...per-6045-block-goal-shouldn-t-load-.patch} | 0 ...e-entity-fluid-lookups-if-no-fluids.patch} | 0 ...heck-for-spooky-season-once-an-hour.patch} | 0 ...patch => 0029-Pufferfish-Entity-TTL.patch} | 0 ...ish-Reduce-projectile-chunk-loading.patch} | 0 ...ferfish-Dynamic-Activation-of-Brain.patch} | 8 +- ...le-goal-selector-during-inactive-ti.patch} | 2 +- ...ufferfish-Reduce-entity-allocations.patch} | 0 ...ve-container-checking-with-a-bitset.patch} | 0 ...le-Variable-entity-wake-up-duration.patch} | 0 ...hunks-to-activate-climbing-entities.patch} | 0 ...=> 0037-Gale-Optimize-sun-burn-tick.patch} | 4 +- ...k-frozen-ticks-before-landing-block.patch} | 0 ...r-lootable-refresh-for-non-player-i.patch} | 0 ...40-Gale-Use-platform-math-functions.patch} | 0 ...kip-entity-move-if-movement-is-zero.patch} | 0 ...ld-generation-chunk-and-block-acces.patch} | 0 ...0043-Gale-Optimize-noise-generation.patch} | 0 ...044-Gale-Faster-chunk-serialization.patch} | 0 ...a-and-Optional-allocation-in-Entity.patch} | 0 ...-goal-set-with-optimized-collection.patch} | 0 ...ttributes-with-optimized-collection.patch} | 0 ...ttle-tracker-map-with-optimized-col.patch} | 0 ...parkly-Paper-Optimize-canSee-checks.patch} | 0 ...0-Purpur-use-alternative-keep-alive.patch} | 0 ...-start-tick-and-finished-tick-event.patch} | 0 .../server/0052-Leaves-Protocol-Core.patch | 583 -------- ...patch => 0052-Leaves-Replay-Mod-API.patch} | 12 +- ...-172047.patch => 0053-Fix-MC-172047.patch} | 0 .../0053-Leaves-Bladeren-Protocol.patch | 292 ---- ...x-MC-2025.patch => 0054-Fix-MC-2025.patch} | 0 .../0054-Leaves-Fix-Bladeren-Protocol.patch | 93 -- ...k-API.patch => 0055-KioCG-Chunk-API.patch} | 4 +- .../0055-Leaves-carpet-protocol-support.patch | 153 -- ...ch => 0056-Added-chunkhot-to-tpsbar.patch} | 0 43 files changed, 17 insertions(+), 2454 deletions(-) delete mode 100644 patches/server/0019-Kaiiju-Async-path-processing.patch rename patches/server/{0020-Petal-Reduce-sensor-work.patch => 0019-Petal-Reduce-sensor-work.patch} (93%) rename patches/server/{0021-Pufferfish-Optimize-entity-coordinate-key.patch => 0020-Pufferfish-Optimize-entity-coordinate-key.patch} (100%) rename patches/server/{0022-Pufferfish-Cache-climbing-check-for-activation.patch => 0021-Pufferfish-Cache-climbing-check-for-activation.patch} (100%) rename patches/server/{0023-Pufferfish-Improve-fluid-direction-caching.patch => 0022-Pufferfish-Improve-fluid-direction-caching.patch} (100%) rename patches/server/{0024-Pufferfish-Optimize-suffocation.patch => 0023-Pufferfish-Optimize-suffocation.patch} (100%) rename patches/server/{0025-Pufferfish-Early-return-optimization-for-target-find.patch => 0024-Pufferfish-Early-return-optimization-for-target-find.patch} (100%) rename patches/server/{0026-Pufferfish-Reduce-chunk-loading-lookups.patch => 0025-Pufferfish-Reduce-chunk-loading-lookups.patch} (100%) rename patches/server/{0027-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch => 0026-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch} (100%) rename patches/server/{0028-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch => 0027-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch} (100%) rename patches/server/{0029-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch => 0028-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch} (100%) rename patches/server/{0030-Pufferfish-Entity-TTL.patch => 0029-Pufferfish-Entity-TTL.patch} (100%) rename patches/server/{0031-Pufferfish-Reduce-projectile-chunk-loading.patch => 0030-Pufferfish-Reduce-projectile-chunk-loading.patch} (100%) rename patches/server/{0032-Pufferfish-Dynamic-Activation-of-Brain.patch => 0031-Pufferfish-Dynamic-Activation-of-Brain.patch} (98%) rename patches/server/{0033-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch => 0032-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch} (96%) rename patches/server/{0034-Pufferfish-Reduce-entity-allocations.patch => 0033-Pufferfish-Reduce-entity-allocations.patch} (100%) rename patches/server/{0035-Pufferfish-Improve-container-checking-with-a-bitset.patch => 0034-Pufferfish-Improve-container-checking-with-a-bitset.patch} (100%) rename patches/server/{0036-Gale-Variable-entity-wake-up-duration.patch => 0035-Gale-Variable-entity-wake-up-duration.patch} (100%) rename patches/server/{0037-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch => 0036-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch} (100%) rename patches/server/{0038-Gale-Optimize-sun-burn-tick.patch => 0037-Gale-Optimize-sun-burn-tick.patch} (96%) rename patches/server/{0039-Gale-Check-frozen-ticks-before-landing-block.patch => 0038-Gale-Check-frozen-ticks-before-landing-block.patch} (100%) rename patches/server/{0040-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch => 0039-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch} (100%) rename patches/server/{0041-Gale-Use-platform-math-functions.patch => 0040-Gale-Use-platform-math-functions.patch} (100%) rename patches/server/{0042-Gale-Skip-entity-move-if-movement-is-zero.patch => 0041-Gale-Skip-entity-move-if-movement-is-zero.patch} (100%) rename patches/server/{0043-Gale-Optimize-world-generation-chunk-and-block-acces.patch => 0042-Gale-Optimize-world-generation-chunk-and-block-acces.patch} (100%) rename patches/server/{0044-Gale-Optimize-noise-generation.patch => 0043-Gale-Optimize-noise-generation.patch} (100%) rename patches/server/{0045-Gale-Faster-chunk-serialization.patch => 0044-Gale-Faster-chunk-serialization.patch} (100%) rename patches/server/{0046-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch => 0045-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch} (100%) rename patches/server/{0047-Gale-Replace-AI-goal-set-with-optimized-collection.patch => 0046-Gale-Replace-AI-goal-set-with-optimized-collection.patch} (100%) rename patches/server/{0048-Gale-Replace-AI-attributes-with-optimized-collection.patch => 0047-Gale-Replace-AI-attributes-with-optimized-collection.patch} (100%) rename patches/server/{0049-Gale-Replace-throttle-tracker-map-with-optimized-col.patch => 0048-Gale-Replace-throttle-tracker-map-with-optimized-col.patch} (100%) rename patches/server/{0050-Sparkly-Paper-Optimize-canSee-checks.patch => 0049-Sparkly-Paper-Optimize-canSee-checks.patch} (100%) rename patches/server/{0051-Purpur-use-alternative-keep-alive.patch => 0050-Purpur-use-alternative-keep-alive.patch} (100%) rename patches/server/{0056-Threaded-region-start-tick-and-finished-tick-event.patch => 0051-Threaded-region-start-tick-and-finished-tick-event.patch} (100%) delete mode 100644 patches/server/0052-Leaves-Protocol-Core.patch rename patches/server/{0057-Leaves-Replay-Mod-API.patch => 0052-Leaves-Replay-Mod-API.patch} (99%) rename patches/server/{0058-Fix-MC-172047.patch => 0053-Fix-MC-172047.patch} (100%) delete mode 100644 patches/server/0053-Leaves-Bladeren-Protocol.patch rename patches/server/{0059-Fix-MC-2025.patch => 0054-Fix-MC-2025.patch} (100%) delete mode 100644 patches/server/0054-Leaves-Fix-Bladeren-Protocol.patch rename patches/server/{0060-KioCG-Chunk-API.patch => 0055-KioCG-Chunk-API.patch} (99%) delete mode 100644 patches/server/0055-Leaves-carpet-protocol-support.patch rename patches/server/{0061-Added-chunkhot-to-tpsbar.patch => 0056-Added-chunkhot-to-tpsbar.patch} (100%) diff --git a/patches/server/0019-Kaiiju-Async-path-processing.patch b/patches/server/0019-Kaiiju-Async-path-processing.patch deleted file mode 100644 index d2675d4..0000000 --- a/patches/server/0019-Kaiiju-Async-path-processing.patch +++ /dev/null @@ -1,1316 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Mon, 25 Mar 2024 13:47:32 +0000 -Subject: [PATCH] Kaiiju Async path processing - - -diff --git a/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPath.java b/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPath.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6b91852238f80d236fc44f766b115267fd7b0e7f ---- /dev/null -+++ b/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPath.java -@@ -0,0 +1,287 @@ -+package dev.kaiijumc.kaiiju.path; -+ -+import net.minecraft.core.BlockPos; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.level.pathfinder.Node; -+import net.minecraft.world.level.pathfinder.Path; -+import net.minecraft.world.phys.Vec3; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.ArrayList; -+import java.util.List; -+import java.util.Set; -+import java.util.function.Supplier; -+ -+/** -+ * i'll be using this to represent a path that not be processed yet! -+ */ -+public class AsyncPath extends Path { -+ -+ /** -+ * marks whether this async path has been processed -+ */ -+ private volatile boolean processed = false; -+ -+ /** -+ * runnables waiting for this to be processed -+ */ -+ private final List postProcessing = new ArrayList<>(0); -+ -+ /** -+ * a list of positions that this path could path towards -+ */ -+ private final Set positions; -+ -+ /** -+ * the supplier of the real processed path -+ */ -+ private final Supplier pathSupplier; -+ -+ /* -+ * Processed values -+ */ -+ -+ /** -+ * this is a reference to the nodes list in the parent `Path` object -+ */ -+ private final List nodes; -+ /** -+ * the block we're trying to path to -+ * -+ * while processing, we have no idea where this is so consumers of `Path` should check that the path is processed before checking the target block -+ */ -+ private @Nullable BlockPos target; -+ /** -+ * how far we are to the target -+ * -+ * while processing, the target could be anywhere but theoretically we're always "close" to a theoretical target so default is 0 -+ */ -+ private float distToTarget = 0; -+ /** -+ * whether we can reach the target -+ * -+ * while processing, we can always theoretically reach the target so default is true -+ */ -+ private boolean canReach = true; -+ -+ public AsyncPath(@NotNull List emptyNodeList, @NotNull Set positions, @NotNull Supplier pathSupplier) { -+ //noinspection ConstantConditions -+ super(emptyNodeList, null, false); -+ -+ this.nodes = emptyNodeList; -+ this.positions = positions; -+ this.pathSupplier = pathSupplier; -+ -+ AsyncPathProcessor.queue(this); -+ } -+ -+ @Override -+ public boolean isProcessed() { -+ return this.processed; -+ } -+ -+ /** -+ * returns the future representing the processing state of this path -+ */ -+ public synchronized void postProcessing(@NotNull Runnable runnable) { -+ if (this.processed) { -+ runnable.run(); -+ } else { -+ this.postProcessing.add(runnable); -+ } -+ } -+ -+ /** -+ * an easy way to check if this processing path is the same as an attempted new path -+ * -+ * @param positions - the positions to compare against -+ * @return true if we are processing the same positions -+ */ -+ public boolean hasSameProcessingPositions(final Set positions) { -+ if (this.positions.size() != positions.size()) { -+ return false; -+ } -+ -+ return this.positions.containsAll(positions); -+ } -+ -+ /** -+ * starts processing this path -+ */ -+ public synchronized void process() { -+ if (this.processed) { -+ return; -+ } -+ -+ final Path bestPath = this.pathSupplier.get(); -+ -+ this.nodes.addAll(bestPath.nodes); // we mutate this list to reuse the logic in Path -+ this.target = bestPath.getTarget(); -+ this.distToTarget = bestPath.getDistToTarget(); -+ this.canReach = bestPath.canReach(); -+ -+ this.processed = true; -+ -+ for (Runnable runnable : this.postProcessing) { -+ runnable.run(); -+ } -+ } -+ -+ /** -+ * if this path is accessed while it hasn't processed, just process it in-place -+ */ -+ private void checkProcessed() { -+ if (!this.processed) { -+ this.process(); -+ } -+ } -+ -+ /* -+ * overrides we need for final fields that we cannot modify after processing -+ */ -+ -+ @Override -+ public @NotNull BlockPos getTarget() { -+ this.checkProcessed(); -+ -+ return this.target; -+ } -+ -+ @Override -+ public float getDistToTarget() { -+ this.checkProcessed(); -+ -+ return this.distToTarget; -+ } -+ -+ @Override -+ public boolean canReach() { -+ this.checkProcessed(); -+ -+ return this.canReach; -+ } -+ -+ /* -+ * overrides to ensure we're processed first -+ */ -+ -+ @Override -+ public boolean isDone() { -+ return this.isProcessed() && super.isDone(); -+ } -+ -+ @Override -+ public void advance() { -+ this.checkProcessed(); -+ -+ super.advance(); -+ } -+ -+ @Override -+ public boolean notStarted() { -+ this.checkProcessed(); -+ -+ return super.notStarted(); -+ } -+ -+ @Nullable -+ @Override -+ public Node getEndNode() { -+ this.checkProcessed(); -+ -+ return super.getEndNode(); -+ } -+ -+ @Override -+ public Node getNode(int index) { -+ this.checkProcessed(); -+ -+ return super.getNode(index); -+ } -+ -+ @Override -+ public void truncateNodes(int length) { -+ this.checkProcessed(); -+ -+ super.truncateNodes(length); -+ } -+ -+ @Override -+ public void replaceNode(int index, Node node) { -+ this.checkProcessed(); -+ -+ super.replaceNode(index, node); -+ } -+ -+ @Override -+ public int getNodeCount() { -+ this.checkProcessed(); -+ -+ return super.getNodeCount(); -+ } -+ -+ @Override -+ public int getNextNodeIndex() { -+ this.checkProcessed(); -+ -+ return super.getNextNodeIndex(); -+ } -+ -+ @Override -+ public void setNextNodeIndex(int nodeIndex) { -+ this.checkProcessed(); -+ -+ super.setNextNodeIndex(nodeIndex); -+ } -+ -+ @Override -+ public Vec3 getEntityPosAtNode(Entity entity, int index) { -+ this.checkProcessed(); -+ -+ return super.getEntityPosAtNode(entity, index); -+ } -+ -+ @Override -+ public BlockPos getNodePos(int index) { -+ this.checkProcessed(); -+ -+ return super.getNodePos(index); -+ } -+ -+ @Override -+ public Vec3 getNextEntityPos(Entity entity) { -+ this.checkProcessed(); -+ -+ return super.getNextEntityPos(entity); -+ } -+ -+ @Override -+ public BlockPos getNextNodePos() { -+ this.checkProcessed(); -+ -+ return super.getNextNodePos(); -+ } -+ -+ @Override -+ public Node getNextNode() { -+ this.checkProcessed(); -+ -+ return super.getNextNode(); -+ } -+ -+ @Nullable -+ @Override -+ public Node getPreviousNode() { -+ this.checkProcessed(); -+ -+ return super.getPreviousNode(); -+ } -+ -+ @Override -+ public boolean hasNext() { -+ this.checkProcessed(); -+ -+ return super.hasNext(); -+ } -+} -diff --git a/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java b/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java -new file mode 100644 -index 0000000000000000000000000000000000000000..31f3ae25069f516255263ab50aca8ee6f1268f8f ---- /dev/null -+++ b/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java -@@ -0,0 +1,52 @@ -+package dev.kaiijumc.kaiiju.path; -+ -+import com.google.common.util.concurrent.ThreadFactoryBuilder; -+ -+import net.minecraft.world.level.pathfinder.Path; -+import net.minecraft.world.entity.Entity; -+ -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.concurrent.*; -+import java.util.function.Consumer; -+ -+/** -+ * used to handle the scheduling of async path processing -+ */ -+public class AsyncPathProcessor { -+ -+ private static final Executor pathProcessingExecutor = new ThreadPoolExecutor( -+ 1, -+ me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessingMaxThreads, -+ me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessingKeepalive, TimeUnit.SECONDS, -+ new LinkedBlockingQueue<>(), -+ new ThreadFactoryBuilder() -+ .setNameFormat("petal-path-processor-%d") -+ .setPriority(Thread.NORM_PRIORITY - 2) -+ .build() -+ ); -+ -+ protected static CompletableFuture queue(@NotNull AsyncPath path) { -+ return CompletableFuture.runAsync(path::process, pathProcessingExecutor); -+ } -+ -+ /** -+ * takes a possibly unprocessed path, and waits until it is completed -+ * the consumer will be immediately invoked if the path is already processed -+ * the consumer will always be called on the main thread -+ * -+ * @param entity affected entity -+ * @param path a path to wait on -+ * @param afterProcessing a consumer to be called -+ */ -+ public static void awaitProcessing(Entity entity, @Nullable Path path, Consumer<@Nullable Path> afterProcessing) { -+ if (path != null && !path.isProcessed() && path instanceof AsyncPath asyncPath) { -+ asyncPath.postProcessing(() -> -+ entity.getBukkitEntity().taskScheduler.schedule(nmsEntity -> afterProcessing.accept(path),null, 1) -+ ); -+ } else { -+ afterProcessing.accept(path); -+ } -+ } -+} -diff --git a/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorCache.java b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorCache.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3213fed7cea3ebfc364f4d6603b95f4263222c76 ---- /dev/null -+++ b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorCache.java -@@ -0,0 +1,45 @@ -+package dev.kaiijumc.kaiiju.path; -+ -+import net.minecraft.world.level.pathfinder.NodeEvaluator; -+ -+import org.apache.commons.lang.Validate; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.Map; -+import java.util.Queue; -+import java.util.concurrent.ConcurrentHashMap; -+import java.util.concurrent.ConcurrentLinkedQueue; -+ -+public class NodeEvaluatorCache { -+ private static final Map> threadLocalNodeEvaluators = new ConcurrentHashMap<>(); -+ private static final Map nodeEvaluatorToGenerator = new ConcurrentHashMap<>(); -+ -+ private static @NotNull Queue getQueueForFeatures(@NotNull NodeEvaluatorFeatures nodeEvaluatorFeatures) { -+ return threadLocalNodeEvaluators.computeIfAbsent(nodeEvaluatorFeatures, (key) -> new ConcurrentLinkedQueue<>()); -+ } -+ -+ public static @NotNull NodeEvaluator takeNodeEvaluator(@NotNull NodeEvaluatorGenerator generator, @NotNull NodeEvaluator localNodeEvaluator) { -+ final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(localNodeEvaluator); -+ NodeEvaluator nodeEvaluator = getQueueForFeatures(nodeEvaluatorFeatures).poll(); -+ -+ if (nodeEvaluator == null) { -+ nodeEvaluator = generator.generate(nodeEvaluatorFeatures); -+ } -+ -+ nodeEvaluatorToGenerator.put(nodeEvaluator, generator); -+ -+ return nodeEvaluator; -+ } -+ -+ public static void returnNodeEvaluator(@NotNull NodeEvaluator nodeEvaluator) { -+ final NodeEvaluatorGenerator generator = nodeEvaluatorToGenerator.remove(nodeEvaluator); -+ Validate.notNull(generator, "NodeEvaluator already returned"); -+ -+ final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(nodeEvaluator); -+ getQueueForFeatures(nodeEvaluatorFeatures).offer(nodeEvaluator); -+ } -+ -+ public static void removeNodeEvaluator(@NotNull NodeEvaluator nodeEvaluator) { -+ nodeEvaluatorToGenerator.remove(nodeEvaluator); -+ } -+} -diff --git a/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorFeatures.java b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorFeatures.java -new file mode 100644 -index 0000000000000000000000000000000000000000..446de8628ccd319a4404e07212dde1cf06241951 ---- /dev/null -+++ b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorFeatures.java -@@ -0,0 +1,21 @@ -+package dev.kaiijumc.kaiiju.path; -+ -+import net.minecraft.world.level.pathfinder.NodeEvaluator; -+import net.minecraft.world.level.pathfinder.SwimNodeEvaluator; -+ -+public record NodeEvaluatorFeatures(NodeEvaluatorType type, -+ boolean canPassDoors, -+ boolean canFloat, -+ boolean canWalkOverFences, -+ boolean canOpenDoors, -+ boolean allowBreaching) { -+ public static NodeEvaluatorFeatures fromNodeEvaluator(NodeEvaluator nodeEvaluator) { -+ NodeEvaluatorType type = NodeEvaluatorType.fromNodeEvaluator(nodeEvaluator); -+ boolean canPassDoors = nodeEvaluator.canPassDoors(); -+ boolean canFloat = nodeEvaluator.canFloat(); -+ boolean canWalkOverFences = nodeEvaluator.canWalkOverFences(); -+ boolean canOpenDoors = nodeEvaluator.canOpenDoors(); -+ boolean allowBreaching = nodeEvaluator instanceof SwimNodeEvaluator swimNodeEvaluator && swimNodeEvaluator.allowBreaching; -+ return new NodeEvaluatorFeatures(type, canPassDoors, canFloat, canWalkOverFences, canOpenDoors, allowBreaching); -+ } -+} -diff --git a/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorGenerator.java b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorGenerator.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d4646df5004d9df78992bf849a759cc6781c069d ---- /dev/null -+++ b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorGenerator.java -@@ -0,0 +1,10 @@ -+package dev.kaiijumc.kaiiju.path; -+ -+import net.minecraft.world.level.pathfinder.NodeEvaluator; -+import org.jetbrains.annotations.NotNull; -+ -+public interface NodeEvaluatorGenerator { -+ -+ @NotNull NodeEvaluator generate(NodeEvaluatorFeatures nodeEvaluatorFeatures); -+ -+} -\ No newline at end of file -diff --git a/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorType.java b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..130d61324679c8600faa52255f3ad99f3a6778e8 ---- /dev/null -+++ b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorType.java -@@ -0,0 +1,17 @@ -+package dev.kaiijumc.kaiiju.path; -+ -+import net.minecraft.world.level.pathfinder.*; -+ -+public enum NodeEvaluatorType { -+ WALK, -+ SWIM, -+ AMPHIBIOUS, -+ FLY; -+ -+ public static NodeEvaluatorType fromNodeEvaluator(NodeEvaluator nodeEvaluator) { -+ if (nodeEvaluator instanceof SwimNodeEvaluator) return SWIM; -+ if (nodeEvaluator instanceof FlyNodeEvaluator) return FLY; -+ if (nodeEvaluator instanceof AmphibiousNodeEvaluator) return AMPHIBIOUS; -+ return WALK; -+ } -+} -diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/AsyncPathProcessingConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/AsyncPathProcessingConfig.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a5472bb9d453bbeee92738c8d1a57ef4fd9bf07e ---- /dev/null -+++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/AsyncPathProcessingConfig.java -@@ -0,0 +1,35 @@ -+package me.earthme.luminol.config.modules.optimizations; -+ -+import com.electronwill.nightconfig.core.file.CommentedFileConfig; -+import me.earthme.luminol.config.ConfigInfo; -+import me.earthme.luminol.config.EnumConfigCategory; -+import me.earthme.luminol.config.IConfigModule; -+ -+public class AsyncPathProcessingConfig implements IConfigModule { -+ @ConfigInfo(baseName = "enabled") -+ public static boolean asyncPathProcessing = false; -+ @ConfigInfo(baseName = "max_threads") -+ public static int asyncPathProcessingMaxThreads = 0; -+ @ConfigInfo(baseName = "keep_alive_time") -+ public static int asyncPathProcessingKeepalive = 60; -+ -+ @Override -+ public EnumConfigCategory getCategory() { -+ return EnumConfigCategory.OPTIMIZATIONS; -+ } -+ -+ @Override -+ public String getBaseName() { -+ return "async_path_processing"; -+ } -+ -+ @Override -+ public void onLoaded(CommentedFileConfig config){ -+ if (asyncPathProcessingMaxThreads < 0) -+ asyncPathProcessingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + asyncPathProcessingMaxThreads, 1); -+ else if (asyncPathProcessingMaxThreads == 0) -+ asyncPathProcessingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() / 4, 1); -+ if (!asyncPathProcessing) -+ asyncPathProcessingMaxThreads = 0; -+ } -+} -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 54297b9dde40fe853d873d60373cd8c0a3c9466b..67210fc018349ab0a79740dee140fb60c82c431a 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -297,6 +297,7 @@ public abstract class Mob extends LivingEntity implements Targeting { - @Nullable - @Override - public LivingEntity getTarget() { -+ if (Thread.currentThread().getName().contains("petal-path-processor")) return this.target; // Kaiiju - Don't reset target when async pathfinding! - // Folia start - region threading - if (this.target != null && (!io.papermc.paper.util.TickThread.isTickThreadFor(this.target) || this.target.isRemoved())) { - this.target = null; -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index abcc3ef59475ac170fd10b4dd4a4f3371faf17e0..e1dc31deeb87d695ddf2308c27e2cf949e48e538 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -@@ -68,6 +68,40 @@ public class AcquirePoi { - io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, poiPredicate, predicate2, entity.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes); - Set, BlockPos>> set = new java.util.HashSet<>(poiposes); - // Paper end - optimise POI access -+ // Kaiiju start - petal - Async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { -+ // await on path async -+ Path possiblePath = findPathToPois(entity, set); -+ -+ // wait on the path to be processed -+ dev.kaiijumc.kaiiju.path.AsyncPathProcessor.awaitProcessing(entity, possiblePath, path -> { -+ // read canReach check -+ if (path == null || !path.canReach()) { -+ for(Pair, BlockPos> pair : set) { -+ long2ObjectMap.computeIfAbsent( -+ pair.getSecond().asLong(), -+ (m) -> new JitteredLinearRetry(entity.level().random, time) -+ ); -+ } -+ return; -+ } -+ BlockPos blockPos = path.getTarget(); -+ poiManager.getType(blockPos).ifPresent((poiType) -> { -+ poiManager.take(poiPredicate, -+ (holder, blockPos2) -> blockPos2.equals(blockPos), -+ blockPos, -+ 1 -+ ); -+ queryResult.set(GlobalPos.of(world.dimension(), blockPos)); -+ entityStatus.ifPresent((status) -> { -+ world.broadcastEntityEvent(entity, status); -+ }); -+ long2ObjectMap.clear(); -+ DebugPackets.sendPoiTicketCountPacket(world, blockPos); -+ }); -+ }); -+ } else { -+ // Kaiiju end - Path path = findPathToPois(entity, set); - if (path != null && path.canReach()) { - BlockPos blockPos = path.getTarget(); -@@ -89,6 +123,7 @@ public class AcquirePoi { - }); - } - } -+ } // Kaiiju - Async path processing - - return true; - } -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java b/src/main/java/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java -index 98bf17441da3169d49de55fe89d79ebe250a2b7e..74162661e5757bb2c732361042b5dd2c3ded43ee 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java -@@ -21,6 +21,7 @@ public class MoveToTargetSink extends Behavior { - private int remainingCooldown; - @Nullable - private Path path; -+ private boolean finishedProcessing; // Kaiiju - petal - track when path is processed - @Nullable - private BlockPos lastTargetPos; - private float speedModifier; -@@ -42,9 +43,10 @@ public class MoveToTargetSink extends Behavior { - Brain brain = entity.getBrain(); - WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get(); - boolean bl = this.reachedTarget(entity, walkTarget); -- if (!bl && this.tryComputePath(entity, walkTarget, world.getGameTime())) { -+ if (!me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing && !bl && this.tryComputePath(entity, walkTarget, world.getGameTime())) { // Kaiiju - petal - async path processing means we can't know if the path is reachable here - this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); - return true; -+ } else if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing && !bl) { return true; // Kaiiju - async pathfinding - } else { - brain.eraseMemory(MemoryModuleType.WALK_TARGET); - if (bl) { -@@ -58,6 +60,7 @@ public class MoveToTargetSink extends Behavior { - - @Override - protected boolean canStillUse(ServerLevel world, Mob entity, long time) { -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing && !this.finishedProcessing) return true; // Kaiiju - petal - wait for processing - if (this.path != null && this.lastTargetPos != null) { - Optional optional = entity.getBrain().getMemory(MemoryModuleType.WALK_TARGET); - boolean bl = optional.map(MoveToTargetSink::isWalkTargetSpectator).orElse(false); -@@ -82,12 +85,68 @@ public class MoveToTargetSink extends Behavior { - - @Override - protected void start(ServerLevel serverLevel, Mob mob, long l) { -+ // Kaiiju start - petal - start processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { -+ Brain brain = mob.getBrain(); -+ WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get(); -+ -+ this.finishedProcessing = false; -+ this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); -+ this.path = this.computePath(mob, walkTarget); -+ return; -+ } -+ // Kaiiju end - mob.getBrain().setMemory(MemoryModuleType.PATH, this.path); - mob.getNavigation().moveTo(this.path, (double)this.speedModifier); - } - - @Override - protected void tick(ServerLevel serverLevel, Mob mob, long l) { -+ // Kaiiju start - petal - Async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { -+ if (this.path != null && !this.path.isProcessed()) return; // wait for processing -+ -+ if (!this.finishedProcessing) { -+ this.finishedProcessing = true; -+ -+ Brain brain = mob.getBrain(); -+ boolean canReach = this.path != null && this.path.canReach(); -+ if (canReach) { -+ brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); -+ } else if (!brain.hasMemoryValue(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)) { -+ brain.setMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, l); -+ } -+ -+ if (!canReach) { -+ Optional walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET); -+ -+ if (!walkTarget.isPresent()) return; -+ -+ BlockPos blockPos = walkTarget.get().getTarget().currentBlockPosition(); -+ Vec3 vec3 = DefaultRandomPos.getPosTowards((PathfinderMob)mob, 10, 7, Vec3.atBottomCenterOf(blockPos), (float)Math.PI / 2F); -+ if (vec3 != null) { -+ // try recalculating the path using a random position -+ this.path = mob.getNavigation().createPath(vec3.x, vec3.y, vec3.z, 0); -+ this.finishedProcessing = false; -+ return; -+ } -+ } -+ -+ mob.getBrain().setMemory(MemoryModuleType.PATH, this.path); -+ mob.getNavigation().moveTo(this.path, this.speedModifier); -+ } -+ -+ Path path = mob.getNavigation().getPath(); -+ Brain brain = mob.getBrain(); -+ -+ if (path != null && this.lastTargetPos != null && brain.hasMemoryValue(MemoryModuleType.WALK_TARGET)) { -+ WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get(); // we know isPresent = true -+ if (walkTarget.getTarget().currentBlockPosition().distSqr(this.lastTargetPos) > 4.0D) { -+ this.start(serverLevel, mob, l); -+ } -+ } -+ } else { -+ // Kaiiju end - Path path = mob.getNavigation().getPath(); - Brain brain = mob.getBrain(); - if (this.path != path) { -@@ -103,7 +162,23 @@ public class MoveToTargetSink extends Behavior { - } - - } -+ } // Kaiiju - async path processing -+ } -+ -+ // Kaiiju start - petal - Async path processing -+ @Nullable -+ private Path computePath(Mob entity, WalkTarget walkTarget) { -+ BlockPos blockPos = walkTarget.getTarget().currentBlockPosition(); -+ // don't pathfind outside region -+ if (!io.papermc.paper.util.TickThread.isTickThreadFor((ServerLevel) entity.level(), blockPos)) return null; -+ this.speedModifier = walkTarget.getSpeedModifier(); -+ Brain brain = entity.getBrain(); -+ if (this.reachedTarget(entity, walkTarget)) { -+ brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE); -+ } -+ return entity.getNavigation().createPath(blockPos, 0); - } -+ // Kaiiju end - - private boolean tryComputePath(Mob entity, WalkTarget walkTarget, long time) { - BlockPos blockPos = walkTarget.getTarget().currentBlockPosition(); -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java b/src/main/java/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java -index 271efbb027f6f5d69ac5bc5dc51102a1eb00ab31..cd2a3edc03301286114834e721f5441e7b70474a 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java -@@ -57,6 +57,26 @@ public class SetClosestHomeAsWalkTarget { - Set, BlockPos>> set = poiManager.findAllWithType((poiType) -> { - return poiType.is(PoiTypes.HOME); - }, predicate, entity.blockPosition(), 48, PoiManager.Occupancy.ANY).collect(Collectors.toSet()); -+ // Kaiiju start - petal - Async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { -+ // await on path async -+ Path possiblePath = AcquirePoi.findPathToPois(entity, set); -+ -+ // wait on the path to be processed -+ dev.kaiijumc.kaiiju.path.AsyncPathProcessor.awaitProcessing(entity, possiblePath, path -> { -+ if (path == null || !path.canReach() || mutableInt.getValue() < 5) { // read canReach check -+ long2LongMap.long2LongEntrySet().removeIf((entry) -> entry.getLongValue() < mutableLong.getValue()); -+ return; -+ } -+ BlockPos blockPos = path.getTarget(); -+ Optional> optional2 = poiManager.getType(blockPos); -+ if (optional2.isPresent()) { -+ walkTarget.set(new WalkTarget(blockPos, speed, 1)); -+ DebugPackets.sendPoiTicketCountPacket(world, blockPos); -+ } -+ }); -+ } else { -+ // Kaiiju end - Path path = AcquirePoi.findPathToPois(entity, set); - if (path != null && path.canReach()) { - BlockPos blockPos = path.getTarget(); -@@ -70,6 +90,7 @@ public class SetClosestHomeAsWalkTarget { - return entry.getLongValue() < mutableLong.getValue(); - }); - } -+ } // Kaiiju - async path processing - - return true; - } else { -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java -index 6771f2dc974317b6b152288bf41d1a95bc78a8e4..7a641747b17164b09bb8483cda7f69d11741a94a 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java -@@ -57,7 +57,7 @@ public abstract class DoorInteractGoal extends Goal { - } else { - GroundPathNavigation groundPathNavigation = (GroundPathNavigation)this.mob.getNavigation(); - Path path = groundPathNavigation.getPath(); -- if (path != null && !path.isDone() && groundPathNavigation.canOpenDoors()) { -+ if (path != null && path.isProcessed() && !path.isDone() && groundPathNavigation.canOpenDoors()) { // Kaiiju - async pathfinding - ensure path is processed - for(int i = 0; i < Math.min(path.getNextNodeIndex() + 2, path.getNodeCount()); ++i) { - Node node = path.getNode(i); - this.doorPos = new BlockPos(node.x, node.y + 1, node.z); -diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java -index 9d3b32c852d660356e0f16d4cc10072b1c603e64..2e64fe17fb3ee1925db1fdb34dedba356aea070b 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java -+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java -@@ -12,10 +12,26 @@ public class AmphibiousPathNavigation extends PathNavigation { - super(mob, world); - } - -+ // Kaiiju start - petal - async path processing -+ private static final dev.kaiijumc.kaiiju.path.NodeEvaluatorGenerator nodeEvaluatorGenerator = (dev.kaiijumc.kaiiju.path.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { -+ AmphibiousNodeEvaluator nodeEvaluator = new AmphibiousNodeEvaluator(false); -+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); -+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); -+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences()); -+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors()); -+ return nodeEvaluator; -+ }; -+ // Kaiiju end -+ - @Override - protected PathFinder createPathFinder(int range) { - this.nodeEvaluator = new AmphibiousNodeEvaluator(false); - this.nodeEvaluator.setCanPassDoors(true); -+ // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) -+ return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); -+ else -+ // Kaiiju end - return new PathFinder(this.nodeEvaluator, range); - } - -diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java -index e35c38feb62c3345d82636081decc09db9f061ab..70f4104f8e49fd6b7df531673f3e1da123783409 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java -+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java -@@ -16,10 +16,26 @@ public class FlyingPathNavigation extends PathNavigation { - super(entity, world); - } - -+ // Kaiiju start - petal - async path processing -+ private static final dev.kaiijumc.kaiiju.path.NodeEvaluatorGenerator nodeEvaluatorGenerator = (dev.kaiijumc.kaiiju.path.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { -+ FlyNodeEvaluator nodeEvaluator = new FlyNodeEvaluator(); -+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); -+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); -+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences()); -+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors()); -+ return nodeEvaluator; -+ }; -+ // Kaiiju end -+ - @Override - protected PathFinder createPathFinder(int range) { - this.nodeEvaluator = new FlyNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); -+ // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) -+ return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); -+ else -+ // Kaiiju end - return new PathFinder(this.nodeEvaluator, range); - } - -@@ -49,6 +65,7 @@ public class FlyingPathNavigation extends PathNavigation { - if (this.hasDelayedRecomputation) { - this.recomputePath(); - } -+ if (this.path != null && !this.path.isProcessed()) return; // Kaiiju - petal - async path processing - - if (!this.isDone()) { - if (this.canUpdatePath()) { -diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java -index b31ba4e2286eaee5028cb4dc236829d1a302a25a..aaa04a4b01575495e6e01f0d83b2bb03acc93822 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java -+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java -@@ -23,10 +23,26 @@ public class GroundPathNavigation extends PathNavigation { - super(entity, world); - } - -+ // Kaiiju start - petal - async path processing -+ protected static final dev.kaiijumc.kaiiju.path.NodeEvaluatorGenerator nodeEvaluatorGenerator = (dev.kaiijumc.kaiiju.path.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { -+ WalkNodeEvaluator nodeEvaluator = new WalkNodeEvaluator(); -+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); -+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); -+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences()); -+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors()); -+ return nodeEvaluator; -+ }; -+ // Kaiiju end -+ - @Override - protected PathFinder createPathFinder(int range) { - this.nodeEvaluator = new WalkNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); -+ // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) -+ return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); -+ else -+ // Kaiiju end - return new PathFinder(this.nodeEvaluator, range); - } - -diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index 089baec30e0c16149b147a501d68958663519b96..f6484fefd28a028fbcd1a54d93c8607b65575d00 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -@@ -153,6 +153,10 @@ public abstract class PathNavigation { - return null; - } else if (!this.canUpdatePath()) { - return null; -+ // Kaiiju start - petal - catch early if it's still processing these positions let it keep processing -+ } else if (this.path instanceof dev.kaiijumc.kaiiju.path.AsyncPath asyncPath && !asyncPath.isProcessed() && asyncPath.hasSameProcessingPositions(positions)) { -+ return this.path; -+ // Kaiiju end - } else if (this.path != null && !this.path.isDone() && positions.contains(this.targetPos)) { - return this.path; - } else { -@@ -179,11 +183,29 @@ public abstract class PathNavigation { - PathNavigationRegion pathNavigationRegion = new PathNavigationRegion(this.level, blockPos.offset(-i, -i, -i), blockPos.offset(i, i, i)); - Path path = this.pathFinder.findPath(pathNavigationRegion, this.mob, positions, followRange, distance, this.maxVisitedNodesMultiplier); - this.level.getProfiler().pop(); -+ // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { -+ // assign early a target position. most calls will only have 1 position -+ if (!positions.isEmpty()) this.targetPos = positions.iterator().next(); -+ -+ dev.kaiijumc.kaiiju.path.AsyncPathProcessor.awaitProcessing(mob, path, processedPath -> { -+ // check that processing didn't take so long that we calculated a new path -+ if (processedPath != this.path) return; -+ -+ if (processedPath != null && processedPath.getTarget() != null) { -+ this.targetPos = processedPath.getTarget(); -+ this.reachRange = distance; -+ this.resetStuckTimeout(); -+ } -+ }); -+ } else { -+ // Kaiiju end - if (path != null && path.getTarget() != null) { - this.targetPos = path.getTarget(); - this.reachRange = distance; - this.resetStuckTimeout(); - } -+ } // Kaiiju - async path processing - - return path; - } -@@ -230,8 +252,8 @@ public abstract class PathNavigation { - if (this.isDone()) { - return false; - } else { -- this.trimPath(); -- if (this.path.getNodeCount() <= 0) { -+ if (path.isProcessed()) this.trimPath(); // Kaiiju - petal - only trim if processed -+ if (path.isProcessed() && this.path.getNodeCount() <= 0) { // Kaiiju - petal - only check node count if processed - return false; - } else { - this.speedModifier = speed; -@@ -254,6 +276,7 @@ public abstract class PathNavigation { - if (this.hasDelayedRecomputation) { - this.recomputePath(); - } -+ if (this.path != null && !this.path.isProcessed()) return; // Kaiiju - petal - skip pathfinding if we're still processing - - if (!this.isDone()) { - if (this.canUpdatePath()) { -@@ -280,6 +303,7 @@ public abstract class PathNavigation { - } - - protected void followThePath() { -+ if (!this.path.isProcessed()) return; // Kaiiju - petal - skip if not processed - Vec3 vec3 = this.getTempMobPos(); - this.maxDistanceToWaypoint = this.mob.getBbWidth() > 0.75F ? this.mob.getBbWidth() / 2.0F : 0.75F - this.mob.getBbWidth() / 2.0F; - Vec3i vec3i = this.path.getNextNodePos(); -@@ -435,7 +459,7 @@ public abstract class PathNavigation { - public boolean shouldRecomputePath(BlockPos pos) { - if (this.hasDelayedRecomputation) { - return false; -- } else if (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0) { -+ } else if (this.path != null && this.path.isProcessed() && !this.path.isDone() && this.path.getNodeCount() != 0) { // Kaiiju - petal - Skip if not processed - Node node = this.path.getEndNode(); - Vec3 vec3 = new Vec3(((double)node.x + this.mob.getX()) / 2.0D, ((double)node.y + this.mob.getY()) / 2.0D, ((double)node.z + this.mob.getZ()) / 2.0D); - return pos.closerToCenterThan(vec3, (double)(this.path.getNodeCount() - this.path.getNextNodeIndex())); -diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java -index ee8543afbbd681bf327a353530a7a635aa5ef592..238b5f2dc5487dcf675152b8c19a40a6e16958dc 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java -+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java -@@ -15,10 +15,26 @@ public class WaterBoundPathNavigation extends PathNavigation { - super(entity, world); - } - -+ // Kaiiju start - petal - async path processing -+ private static final dev.kaiijumc.kaiiju.path.NodeEvaluatorGenerator nodeEvaluatorGenerator = (dev.kaiijumc.kaiiju.path.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { -+ SwimNodeEvaluator nodeEvaluator = new SwimNodeEvaluator(nodeEvaluatorFeatures.allowBreaching()); -+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); -+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); -+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences()); -+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors()); -+ return nodeEvaluator; -+ }; -+ // Kaiiju end -+ - @Override - protected PathFinder createPathFinder(int range) { - this.allowBreaching = this.mob.getType() == EntityType.DOLPHIN; - this.nodeEvaluator = new SwimNodeEvaluator(this.allowBreaching); -+ // Kaiiju start - async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) -+ return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); -+ else -+ // Kaiiju end - return new PathFinder(this.nodeEvaluator, range); - } - -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -index 8db20db72cd51046213625fac46c35854c59ec5d..afa5d36f5f9e6f3a44a1e92f98a1d83c3af4d277 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -@@ -57,6 +57,25 @@ public class NearestBedSensor extends Sensor { - java.util.List, BlockPos>> poiposes = new java.util.ArrayList<>(); - // don't ask me why it's unbounded. ask mojang. - io.papermc.paper.util.PoiAccess.findAnyPoiPositions(poiManager, type -> type.is(PoiTypes.HOME), predicate, entity.blockPosition(), 48, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); -+ // Kaiiju start - await on async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { -+ Path possiblePath = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes)); -+ dev.kaiijumc.kaiiju.path.AsyncPathProcessor.awaitProcessing(entity, possiblePath, path -> { -+ // read canReach check -+ if ((path == null || !path.canReach()) && this.triedCount < 5) { -+ this.batchCache.long2LongEntrySet().removeIf((entry) -> entry.getLongValue() < this.lastUpdate); -+ return; -+ } -+ if (path == null) return; -+ -+ BlockPos blockPos = path.getTarget(); -+ Optional> optional = poiManager.getType(blockPos); -+ if (optional.isPresent()) { -+ entity.getBrain().setMemory(MemoryModuleType.NEAREST_BED, blockPos); -+ } -+ }); -+ } else { -+ // Kaiiju end - Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes)); - // Paper end - optimise POI access - if (path != null && path.canReach()) { -@@ -70,6 +89,7 @@ public class NearestBedSensor extends Sensor { - return entry.getLongValue() < this.lastUpdate; - }); - } -+ } // Kaiiju - async path processing - - } - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index 9f1791e60061934fc89a13258f3fab9f67f3a45c..489fab4847118b8ecb92e435d57d224104e7a3b6 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -1084,7 +1084,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - } else { - Bee.this.pathfindRandomlyTowards(Bee.this.hivePos); - } -- } else { -+ } else if (navigation.getPath() != null && navigation.getPath().isProcessed()) { // Kaiiju - petal - check processing - boolean flag = this.pathfindDirectlyTowards(Bee.this.hivePos); - - if (!flag) { -@@ -1146,7 +1146,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { - } else { - Path pathentity = Bee.this.navigation.getPath(); - -- return pathentity != null && pathentity.getTarget().equals(pos) && pathentity.canReach() && pathentity.isDone(); -+ return pathentity != null && pathentity.isProcessed() && pathentity.getTarget().equals(pos) && pathentity.canReach() && pathentity.isDone(); // Kaiiju - petal - ensure path is processed - } - } - } -diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -index 295769d039f2a1e4f48912a60f9dbe267d8992c1..580da502c62ec5d669cb09932d99d1c7d711c965 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -+++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -@@ -383,6 +383,17 @@ public class Frog extends Animal implements VariantHolder { - super(frog, world); - } - -+ // Kaiiju start - petal - async path processing -+ private static final dev.kaiijumc.kaiiju.path.NodeEvaluatorGenerator nodeEvaluatorGenerator = (dev.kaiijumc.kaiiju.path.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { -+ Frog.FrogNodeEvaluator nodeEvaluator = new Frog.FrogNodeEvaluator(true); -+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); -+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); -+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences()); -+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors()); -+ return nodeEvaluator; -+ }; -+ // Kaiiju end -+ - @Override - public boolean canCutCorner(BlockPathTypes nodeType) { - return nodeType != BlockPathTypes.WATER_BORDER && super.canCutCorner(nodeType); -@@ -392,6 +403,11 @@ public class Frog extends Animal implements VariantHolder { - protected PathFinder createPathFinder(int range) { - this.nodeEvaluator = new Frog.FrogNodeEvaluator(true); - this.nodeEvaluator.setCanPassDoors(true); -+ // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) -+ return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); -+ else -+ // Kaiiju end - return new PathFinder(this.nodeEvaluator, range); - } - } -diff --git a/src/main/java/net/minecraft/world/entity/monster/Drowned.java b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -index 01897af1e6253b987734a24c052daf2ce1314092..b2f3f65caa92cfd9a8c65e617fde558506ca5a95 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Drowned.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Drowned.java -@@ -216,7 +216,6 @@ public class Drowned extends Zombie implements RangedAttackMob { - this.setSwimming(false); - } - } -- - } - - @Override -@@ -227,7 +226,7 @@ public class Drowned extends Zombie implements RangedAttackMob { - protected boolean closeToNextPos() { - Path pathentity = this.getNavigation().getPath(); - -- if (pathentity != null) { -+ if (pathentity != null && pathentity.isProcessed()) { // Kaiiju - petal - ensure path is processed - BlockPos blockposition = pathentity.getTarget(); - - if (blockposition != null) { -diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java -index 61162ecd43dc5e6f7898daecdec49f444e6d869b..864215e909224d180b47798e90a3c5846fa03dbd 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Strider.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java -@@ -563,10 +563,26 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { - super(entity, world); - } - -+ // Kaiiju start - petal - async path processing -+ private static final dev.kaiijumc.kaiiju.path.NodeEvaluatorGenerator nodeEvaluatorGenerator = (dev.kaiijumc.kaiiju.path.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> { -+ WalkNodeEvaluator nodeEvaluator = new WalkNodeEvaluator(); -+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors()); -+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat()); -+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences()); -+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors()); -+ return nodeEvaluator; -+ }; -+ // Kaiiju end -+ - @Override - protected PathFinder createPathFinder(int range) { - this.nodeEvaluator = new WalkNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); -+ // Kaiiju start - async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) -+ return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); -+ else -+ // Kaiiju end - return new PathFinder(this.nodeEvaluator, range); - } - -diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index 937f81a859953498abe73bea560c86e6560e1c33..7aadd36f0fe986635b495ab8c1426644620400cf 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -+++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -@@ -602,6 +602,16 @@ public class Warden extends Monster implements VibrationSystem { - protected PathFinder createPathFinder(int range) { - this.nodeEvaluator = new WalkNodeEvaluator(); - this.nodeEvaluator.setCanPassDoors(true); -+ // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) -+ return new PathFinder(this.nodeEvaluator, range, GroundPathNavigation.nodeEvaluatorGenerator) { -+ @Override -+ protected float distance(Node a, Node b) { -+ return a.distanceToXZ(b); -+ } -+ }; -+ else -+ // Kaiiju end - return new PathFinder(this.nodeEvaluator, range) { - @Override - protected float distance(Node a, Node b) { -diff --git a/src/main/java/net/minecraft/world/level/block/ShulkerBoxBlock.java b/src/main/java/net/minecraft/world/level/block/ShulkerBoxBlock.java -index 42407c5c0c09cd9d19bc7af92af8868bb038c686..39ed19562210f1329b22c630e667578473cda7cb 100644 ---- a/src/main/java/net/minecraft/world/level/block/ShulkerBoxBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/ShulkerBoxBlock.java -@@ -254,6 +254,7 @@ public class ShulkerBoxBlock extends BaseEntityBlock { - - @Override - public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { -+ if (Thread.currentThread().getName().contains("petal-path-processor")) return Shapes.block(); // Kaiiju - async pathfinding - we cannot get block entities - BlockEntity blockEntity = world.getBlockEntity(pos); - return blockEntity instanceof ShulkerBoxBlockEntity ? Shapes.create(((ShulkerBoxBlockEntity)blockEntity).getBoundingBox(state)) : Shapes.block(); - } -diff --git a/src/main/java/net/minecraft/world/level/block/piston/MovingPistonBlock.java b/src/main/java/net/minecraft/world/level/block/piston/MovingPistonBlock.java -index d3d1ad7901411574b85b0febd1c7ddaa8ad7c9f4..850065df2b95b0967660f246cd007bf9f53e26df 100644 ---- a/src/main/java/net/minecraft/world/level/block/piston/MovingPistonBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/piston/MovingPistonBlock.java -@@ -110,6 +110,7 @@ public class MovingPistonBlock extends BaseEntityBlock { - - @Override - public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { -+ if (Thread.currentThread().getName().contains("petal-path-processor")) return Shapes.empty(); // Kaiiju - async pathfinding - we cannot get block entities - PistonMovingBlockEntity pistonMovingBlockEntity = this.getBlockEntity(world, pos); - return pistonMovingBlockEntity != null ? pistonMovingBlockEntity.getCollisionShape(world, pos) : Shapes.empty(); - } -diff --git a/src/main/java/net/minecraft/world/level/pathfinder/Path.java b/src/main/java/net/minecraft/world/level/pathfinder/Path.java -index 3049edb5a8b5967e5242a3896b23665888eb3472..0da9acd785cf785d82be7aab0a1e2bfd70c62998 100644 ---- a/src/main/java/net/minecraft/world/level/pathfinder/Path.java -+++ b/src/main/java/net/minecraft/world/level/pathfinder/Path.java -@@ -27,6 +27,17 @@ public class Path { - this.reached = reachesTarget; - } - -+ // Kaiiju start - petal - async path processing -+ /** -+ * checks if the path is completely processed in the case of it being computed async -+ * -+ * @return true if the path is processed -+ */ -+ public boolean isProcessed() { -+ return true; -+ } -+ // Kaiiju end -+ - public void advance() { - ++this.nextNodeIndex; - } -@@ -101,6 +112,7 @@ public class Path { - } - - public boolean sameAs(@Nullable Path o) { -+ if (o == this) return true; // Kaiiju - petal - short circuit - if (o == null) { - return false; - } else if (o.nodes.size() != this.nodes.size()) { -diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java -index 8aa4ac3a6affbe888d6084a27b668c58dfda6c79..d8f443af840b1a4b1d2868fefd87d70dad55a764 100644 ---- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java -+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java -@@ -24,37 +24,80 @@ public class PathFinder { - public final NodeEvaluator nodeEvaluator; - private static final boolean DEBUG = false; - private final BinaryHeap openSet = new BinaryHeap(); -+ private final @Nullable dev.kaiijumc.kaiiju.path.NodeEvaluatorGenerator nodeEvaluatorGenerator; // Kaiiju - petal - we use this later to generate an evaluator - -- public PathFinder(NodeEvaluator pathNodeMaker, int range) { -+ public PathFinder(NodeEvaluator pathNodeMaker, int range, @Nullable dev.kaiijumc.kaiiju.path.NodeEvaluatorGenerator nodeEvaluatorGenerator) { // Kaiiju - petal - add nodeEvaluatorGenerator - this.nodeEvaluator = pathNodeMaker; - this.maxVisitedNodes = range; -+ // Kaiiju start - petal - support nodeEvaluatorgenerators -+ this.nodeEvaluatorGenerator = nodeEvaluatorGenerator; -+ } -+ -+ public PathFinder(NodeEvaluator pathNodeMaker, int range) { -+ this(pathNodeMaker, range, null); -+ // Kaiiju end - } - - @Nullable - public Path findPath(PathNavigationRegion world, Mob mob, Set positions, float followRange, int distance, float rangeMultiplier) { -- this.openSet.clear(); -- this.nodeEvaluator.prepare(world, mob); -- Node node = this.nodeEvaluator.getStart(); -+ if(!me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) this.openSet.clear(); // Kaiiju - petal - it's always cleared in processPath -+ // Kaiiju start - petal - use a generated evaluator if we have one otherwise run sync -+ NodeEvaluator nodeEvaluator = this.nodeEvaluatorGenerator == null -+ ? this.nodeEvaluator -+ : dev.kaiijumc.kaiiju.path.NodeEvaluatorCache.takeNodeEvaluator(this.nodeEvaluatorGenerator, this.nodeEvaluator); -+ nodeEvaluator.prepare(world, mob); -+ Node node = nodeEvaluator.getStart(); -+ // Kaiiju end - if (node == null) { -+ dev.kaiijumc.kaiiju.path.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); // Kaiiju - petal - handle nodeEvaluatorGenerator - return null; - } else { - // Paper start - Perf: remove streams and optimize collection - List> map = Lists.newArrayList(); - for (BlockPos pos : positions) { -- map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getGoal(pos.getX(), pos.getY(), pos.getZ()), pos)); -+ map.add(new java.util.AbstractMap.SimpleEntry<>(nodeEvaluator.getGoal(pos.getX(), pos.getY(), pos.getZ()), pos)); // Kaiiju - petal - handle nodeEvaluatorGenerator - } - // Paper end - Perf: remove streams and optimize collection -- Path path = this.findPath(world.getProfiler(), node, map, followRange, distance, rangeMultiplier); -- this.nodeEvaluator.done(); -- return path; -+ // Kaiiju start - petal - async path processing -+ if (this.nodeEvaluatorGenerator == null) { -+ // run sync :( -+ dev.kaiijumc.kaiiju.path.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); -+ return this.findPath(world.getProfiler(), node, map, followRange, distance, rangeMultiplier); -+ } -+ -+ return new dev.kaiijumc.kaiiju.path.AsyncPath(Lists.newArrayList(), positions, () -> { -+ try { -+ return this.processPath(nodeEvaluator, node, map, followRange, distance, rangeMultiplier); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ return null; -+ } finally { -+ nodeEvaluator.done(); -+ dev.kaiijumc.kaiiju.path.NodeEvaluatorCache.returnNodeEvaluator(nodeEvaluator); -+ } -+ }); -+ // Kaiiju end - } - } - -- @Nullable -+ //@Nullable // Kaiiju - Always not null - // Paper start - Perf: remove streams and optimize collection - private Path findPath(ProfilerFiller profiler, Node startNode, List> positions, float followRange, int distance, float rangeMultiplier) { - profiler.push("find_path"); - profiler.markForCharting(MetricCategory.PATH_FINDING); -+ // Kaiiju start - petal - split pathfinding into the original sync method for compat and processing for delaying -+ try { -+ return this.processPath(this.nodeEvaluator, startNode, positions, followRange, distance, rangeMultiplier); -+ } catch (Exception e) { -+ e.printStackTrace(); -+ return null; -+ } finally { -+ this.nodeEvaluator.done(); -+ } -+ } -+ private synchronized @org.jetbrains.annotations.NotNull Path processPath(NodeEvaluator nodeEvaluator, Node startNode, List> positions, float followRange, int distance, float rangeMultiplier) { // sync to only use the caching functions in this class on a single thread -+ org.apache.commons.lang3.Validate.isTrue(!positions.isEmpty()); // ensure that we have at least one position, which means we'll always return a path -+ // Kaiiju end - // Set set = positions.keySet(); - startNode.g = 0.0F; - startNode.h = this.getBestH(startNode, positions); // Paper - optimize collection -@@ -91,7 +134,7 @@ public class PathFinder { - } - - if (!(node.distanceTo(startNode) >= followRange)) { -- int k = this.nodeEvaluator.getNeighbors(this.neighbors, node); -+ int k = nodeEvaluator.getNeighbors(this.neighbors, node); // Kaiiju - petal - use provided nodeEvaluator - - for(int l = 0; l < k; ++l) { - Node node2 = this.neighbors[l]; -@@ -123,7 +166,6 @@ public class PathFinder { - if (best == null || comparator.compare(path, best) < 0) - best = path; - } -- profiler.pop(); - return best; - // Paper end - Perf: remove streams and optimize collection - } -diff --git a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java -index 0e2b14e7dfedf209d63279c81723fd7955122d78..079b278e2e262af433bb5bd0c12b3d8db4fa12fc 100644 ---- a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java -+++ b/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java -@@ -16,7 +16,7 @@ import net.minecraft.world.level.block.state.BlockState; - import net.minecraft.world.level.material.FluidState; - - public class SwimNodeEvaluator extends NodeEvaluator { -- private final boolean allowBreaching; -+ public final boolean allowBreaching; // Kaiiju - make this public - private final Long2ObjectMap pathTypesByPosCache = new Long2ObjectOpenHashMap<>(); - - public SwimNodeEvaluator(boolean canJumpOutOfWater) { diff --git a/patches/server/0020-Petal-Reduce-sensor-work.patch b/patches/server/0019-Petal-Reduce-sensor-work.patch similarity index 93% rename from patches/server/0020-Petal-Reduce-sensor-work.patch rename to patches/server/0019-Petal-Reduce-sensor-work.patch index 7ac04ea..863d5e1 100644 --- a/patches/server/0020-Petal-Reduce-sensor-work.patch +++ b/patches/server/0019-Petal-Reduce-sensor-work.patch @@ -33,10 +33,10 @@ index 0000000000000000000000000000000000000000..dd45cf1fde5ee4cf8347064f106c64b8 + } +} diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 67210fc018349ab0a79740dee140fb60c82c431a..b90865dbfb3a4bd83e4cd3ba3b5b965036039f98 100644 +index 54297b9dde40fe853d873d60373cd8c0a3c9466b..7369d608c26e46e9d3a881ac14efe1d0f075b1cb 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -927,10 +927,11 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -926,10 +926,11 @@ public abstract class Mob extends LivingEntity implements Targeting { return; } // Paper end - Allow nerfed mobs to jump and float diff --git a/patches/server/0021-Pufferfish-Optimize-entity-coordinate-key.patch b/patches/server/0020-Pufferfish-Optimize-entity-coordinate-key.patch similarity index 100% rename from patches/server/0021-Pufferfish-Optimize-entity-coordinate-key.patch rename to patches/server/0020-Pufferfish-Optimize-entity-coordinate-key.patch diff --git a/patches/server/0022-Pufferfish-Cache-climbing-check-for-activation.patch b/patches/server/0021-Pufferfish-Cache-climbing-check-for-activation.patch similarity index 100% rename from patches/server/0022-Pufferfish-Cache-climbing-check-for-activation.patch rename to patches/server/0021-Pufferfish-Cache-climbing-check-for-activation.patch diff --git a/patches/server/0023-Pufferfish-Improve-fluid-direction-caching.patch b/patches/server/0022-Pufferfish-Improve-fluid-direction-caching.patch similarity index 100% rename from patches/server/0023-Pufferfish-Improve-fluid-direction-caching.patch rename to patches/server/0022-Pufferfish-Improve-fluid-direction-caching.patch diff --git a/patches/server/0024-Pufferfish-Optimize-suffocation.patch b/patches/server/0023-Pufferfish-Optimize-suffocation.patch similarity index 100% rename from patches/server/0024-Pufferfish-Optimize-suffocation.patch rename to patches/server/0023-Pufferfish-Optimize-suffocation.patch diff --git a/patches/server/0025-Pufferfish-Early-return-optimization-for-target-find.patch b/patches/server/0024-Pufferfish-Early-return-optimization-for-target-find.patch similarity index 100% rename from patches/server/0025-Pufferfish-Early-return-optimization-for-target-find.patch rename to patches/server/0024-Pufferfish-Early-return-optimization-for-target-find.patch diff --git a/patches/server/0026-Pufferfish-Reduce-chunk-loading-lookups.patch b/patches/server/0025-Pufferfish-Reduce-chunk-loading-lookups.patch similarity index 100% rename from patches/server/0026-Pufferfish-Reduce-chunk-loading-lookups.patch rename to patches/server/0025-Pufferfish-Reduce-chunk-loading-lookups.patch diff --git a/patches/server/0027-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch b/patches/server/0026-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch similarity index 100% rename from patches/server/0027-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch rename to patches/server/0026-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch diff --git a/patches/server/0028-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch b/patches/server/0027-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch similarity index 100% rename from patches/server/0028-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch rename to patches/server/0027-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch diff --git a/patches/server/0029-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch b/patches/server/0028-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch similarity index 100% rename from patches/server/0029-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch rename to patches/server/0028-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch diff --git a/patches/server/0030-Pufferfish-Entity-TTL.patch b/patches/server/0029-Pufferfish-Entity-TTL.patch similarity index 100% rename from patches/server/0030-Pufferfish-Entity-TTL.patch rename to patches/server/0029-Pufferfish-Entity-TTL.patch diff --git a/patches/server/0031-Pufferfish-Reduce-projectile-chunk-loading.patch b/patches/server/0030-Pufferfish-Reduce-projectile-chunk-loading.patch similarity index 100% rename from patches/server/0031-Pufferfish-Reduce-projectile-chunk-loading.patch rename to patches/server/0030-Pufferfish-Reduce-projectile-chunk-loading.patch diff --git a/patches/server/0032-Pufferfish-Dynamic-Activation-of-Brain.patch b/patches/server/0031-Pufferfish-Dynamic-Activation-of-Brain.patch similarity index 98% rename from patches/server/0032-Pufferfish-Dynamic-Activation-of-Brain.patch rename to patches/server/0031-Pufferfish-Dynamic-Activation-of-Brain.patch index 8fc3054..4e83c7e 100644 --- a/patches/server/0032-Pufferfish-Dynamic-Activation-of-Brain.patch +++ b/patches/server/0031-Pufferfish-Dynamic-Activation-of-Brain.patch @@ -111,7 +111,7 @@ index 8deae3e95a26f4b42b2c2134e22f9649bd7a5391..c09357c1ef84a29d972119cb496b0ae9 private String descriptionId; @Nullable diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index b90865dbfb3a4bd83e4cd3ba3b5b965036039f98..66c581585e6ca58eba0e8b7af0fa1f0c9f924f94 100644 +index 7369d608c26e46e9d3a881ac14efe1d0f075b1cb..7f6b810f175e21dbbc85d17fefbba2a7c638144d 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -234,10 +234,10 @@ public abstract class Mob extends LivingEntity implements Targeting { @@ -127,7 +127,7 @@ index b90865dbfb3a4bd83e4cd3ba3b5b965036039f98..66c581585e6ca58eba0e8b7af0fa1f0c this.targetSelector.tick(); } } -@@ -935,16 +935,20 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -934,16 +934,20 @@ public abstract class Mob extends LivingEntity implements Targeting { if (i % 2 != 0 && this.tickCount > 1) { this.level().getProfiler().push("targetSelector"); @@ -200,7 +200,7 @@ index b21e180641d17438997a80e5bcb0ec7998d24a2e..33c160994f70f71446d665e748791343 this.level().getProfiler().pop(); this.level().getProfiler().push("axolotlActivityUpdate"); diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -index 580da502c62ec5d669cb09932d99d1c7d711c965..b94d775e366f5cb251e9199ff5022ad53129da76 100644 +index 295769d039f2a1e4f48912a60f9dbe267d8992c1..e88b058c0734e436ef24bab6364b206c13e5a9c2 100644 --- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java +++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java @@ -159,9 +159,11 @@ public class Frog extends Animal implements VariantHolder { @@ -280,7 +280,7 @@ index a9813da7f2b248f98f22e0ad2e7842915025ec12..83d83e3f84bb6bd58761671c6cd4c868 this.level().getProfiler().pop(); PiglinAi.updateActivity(this); diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index 7aadd36f0fe986635b495ab8c1426644620400cf..0c947d7509d66647327bce885ad2c6051f41c56f 100644 +index 937f81a859953498abe73bea560c86e6560e1c33..0a151c679b0dc943598180942d6d4b3886211688 100644 --- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java +++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java @@ -273,11 +273,13 @@ public class Warden extends Monster implements VibrationSystem { diff --git a/patches/server/0033-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch b/patches/server/0032-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch similarity index 96% rename from patches/server/0033-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch rename to patches/server/0032-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch index 7dd4960..a1c58ce 100644 --- a/patches/server/0033-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch +++ b/patches/server/0032-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..acc032f727e605e79b688efb4873ff47 + } +} diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 66c581585e6ca58eba0e8b7af0fa1f0c9f924f94..97e099eea537aea8f8ffd031063949c363820701 100644 +index 7f6b810f175e21dbbc85d17fefbba2a7c638144d..a892ff1b3bc11df5f46269c5ae8838c4a7f91ea9 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -230,11 +230,13 @@ public abstract class Mob extends LivingEntity implements Targeting { diff --git a/patches/server/0034-Pufferfish-Reduce-entity-allocations.patch b/patches/server/0033-Pufferfish-Reduce-entity-allocations.patch similarity index 100% rename from patches/server/0034-Pufferfish-Reduce-entity-allocations.patch rename to patches/server/0033-Pufferfish-Reduce-entity-allocations.patch diff --git a/patches/server/0035-Pufferfish-Improve-container-checking-with-a-bitset.patch b/patches/server/0034-Pufferfish-Improve-container-checking-with-a-bitset.patch similarity index 100% rename from patches/server/0035-Pufferfish-Improve-container-checking-with-a-bitset.patch rename to patches/server/0034-Pufferfish-Improve-container-checking-with-a-bitset.patch diff --git a/patches/server/0036-Gale-Variable-entity-wake-up-duration.patch b/patches/server/0035-Gale-Variable-entity-wake-up-duration.patch similarity index 100% rename from patches/server/0036-Gale-Variable-entity-wake-up-duration.patch rename to patches/server/0035-Gale-Variable-entity-wake-up-duration.patch diff --git a/patches/server/0037-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch b/patches/server/0036-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch similarity index 100% rename from patches/server/0037-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch rename to patches/server/0036-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch diff --git a/patches/server/0038-Gale-Optimize-sun-burn-tick.patch b/patches/server/0037-Gale-Optimize-sun-burn-tick.patch similarity index 96% rename from patches/server/0038-Gale-Optimize-sun-burn-tick.patch rename to patches/server/0037-Gale-Optimize-sun-burn-tick.patch index 9abc3ea..1a52127 100644 --- a/patches/server/0038-Gale-Optimize-sun-burn-tick.patch +++ b/patches/server/0037-Gale-Optimize-sun-burn-tick.patch @@ -37,10 +37,10 @@ index 31f80438e82da6de1cd1ec35a2f77c45f0127722..6948342ef9fa4af0e13707e85cd788c8 this.absMoveTo(x, y, z); this.setYRot(yaw % 360.0F); diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 97e099eea537aea8f8ffd031063949c363820701..71b1f576aff8dcf51dd888280b5b7a25a387d197 100644 +index a892ff1b3bc11df5f46269c5ae8838c4a7f91ea9..aa51819373465c733d0c31ae18ef97afee550767 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -1750,13 +1750,29 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -1749,13 +1749,29 @@ public abstract class Mob extends LivingEntity implements Targeting { } diff --git a/patches/server/0039-Gale-Check-frozen-ticks-before-landing-block.patch b/patches/server/0038-Gale-Check-frozen-ticks-before-landing-block.patch similarity index 100% rename from patches/server/0039-Gale-Check-frozen-ticks-before-landing-block.patch rename to patches/server/0038-Gale-Check-frozen-ticks-before-landing-block.patch diff --git a/patches/server/0040-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch b/patches/server/0039-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch similarity index 100% rename from patches/server/0040-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch rename to patches/server/0039-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch diff --git a/patches/server/0041-Gale-Use-platform-math-functions.patch b/patches/server/0040-Gale-Use-platform-math-functions.patch similarity index 100% rename from patches/server/0041-Gale-Use-platform-math-functions.patch rename to patches/server/0040-Gale-Use-platform-math-functions.patch diff --git a/patches/server/0042-Gale-Skip-entity-move-if-movement-is-zero.patch b/patches/server/0041-Gale-Skip-entity-move-if-movement-is-zero.patch similarity index 100% rename from patches/server/0042-Gale-Skip-entity-move-if-movement-is-zero.patch rename to patches/server/0041-Gale-Skip-entity-move-if-movement-is-zero.patch diff --git a/patches/server/0043-Gale-Optimize-world-generation-chunk-and-block-acces.patch b/patches/server/0042-Gale-Optimize-world-generation-chunk-and-block-acces.patch similarity index 100% rename from patches/server/0043-Gale-Optimize-world-generation-chunk-and-block-acces.patch rename to patches/server/0042-Gale-Optimize-world-generation-chunk-and-block-acces.patch diff --git a/patches/server/0044-Gale-Optimize-noise-generation.patch b/patches/server/0043-Gale-Optimize-noise-generation.patch similarity index 100% rename from patches/server/0044-Gale-Optimize-noise-generation.patch rename to patches/server/0043-Gale-Optimize-noise-generation.patch diff --git a/patches/server/0045-Gale-Faster-chunk-serialization.patch b/patches/server/0044-Gale-Faster-chunk-serialization.patch similarity index 100% rename from patches/server/0045-Gale-Faster-chunk-serialization.patch rename to patches/server/0044-Gale-Faster-chunk-serialization.patch diff --git a/patches/server/0046-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch b/patches/server/0045-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch similarity index 100% rename from patches/server/0046-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch rename to patches/server/0045-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch diff --git a/patches/server/0047-Gale-Replace-AI-goal-set-with-optimized-collection.patch b/patches/server/0046-Gale-Replace-AI-goal-set-with-optimized-collection.patch similarity index 100% rename from patches/server/0047-Gale-Replace-AI-goal-set-with-optimized-collection.patch rename to patches/server/0046-Gale-Replace-AI-goal-set-with-optimized-collection.patch diff --git a/patches/server/0048-Gale-Replace-AI-attributes-with-optimized-collection.patch b/patches/server/0047-Gale-Replace-AI-attributes-with-optimized-collection.patch similarity index 100% rename from patches/server/0048-Gale-Replace-AI-attributes-with-optimized-collection.patch rename to patches/server/0047-Gale-Replace-AI-attributes-with-optimized-collection.patch diff --git a/patches/server/0049-Gale-Replace-throttle-tracker-map-with-optimized-col.patch b/patches/server/0048-Gale-Replace-throttle-tracker-map-with-optimized-col.patch similarity index 100% rename from patches/server/0049-Gale-Replace-throttle-tracker-map-with-optimized-col.patch rename to patches/server/0048-Gale-Replace-throttle-tracker-map-with-optimized-col.patch diff --git a/patches/server/0050-Sparkly-Paper-Optimize-canSee-checks.patch b/patches/server/0049-Sparkly-Paper-Optimize-canSee-checks.patch similarity index 100% rename from patches/server/0050-Sparkly-Paper-Optimize-canSee-checks.patch rename to patches/server/0049-Sparkly-Paper-Optimize-canSee-checks.patch diff --git a/patches/server/0051-Purpur-use-alternative-keep-alive.patch b/patches/server/0050-Purpur-use-alternative-keep-alive.patch similarity index 100% rename from patches/server/0051-Purpur-use-alternative-keep-alive.patch rename to patches/server/0050-Purpur-use-alternative-keep-alive.patch diff --git a/patches/server/0056-Threaded-region-start-tick-and-finished-tick-event.patch b/patches/server/0051-Threaded-region-start-tick-and-finished-tick-event.patch similarity index 100% rename from patches/server/0056-Threaded-region-start-tick-and-finished-tick-event.patch rename to patches/server/0051-Threaded-region-start-tick-and-finished-tick-event.patch diff --git a/patches/server/0052-Leaves-Protocol-Core.patch b/patches/server/0052-Leaves-Protocol-Core.patch deleted file mode 100644 index ef3e75d..0000000 --- a/patches/server/0052-Leaves-Protocol-Core.patch +++ /dev/null @@ -1,583 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Wed, 7 Feb 2024 08:51:49 +0000 -Subject: [PATCH] Leaves Protocol Core - - -diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java b/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java -index 1ae61bc6603dd3ac290e3ead20416f9c5b63ff02..168ed2c21aed6a10f3aca259880b1b8bdbf98b78 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java -+++ b/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java -@@ -314,6 +314,8 @@ public final class RegionizedServer { - - // player list - MinecraftServer.getServer().getPlayerList().tick(); -+ -+ top.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleTick(); //Leaves - } - - private void tickPlayerSample() { -diff --git a/src/main/java/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java b/src/main/java/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java -index af86f752c33a2990405fea058b7c41c437ba9d46..bada9fae1e7178162429e1f5a1608b9c4a680a6c 100644 ---- a/src/main/java/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java -+++ b/src/main/java/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java -@@ -20,7 +20,12 @@ public record ServerboundCustomPayloadPacket(CustomPacketPayload payload) implem - - private static CustomPacketPayload readPayload(ResourceLocation id, FriendlyByteBuf buf) { - FriendlyByteBuf.Reader packetdataserializer_a = (FriendlyByteBuf.Reader) ServerboundCustomPayloadPacket.KNOWN_TYPES.get(id); -- -+ // Leaves start - protocol -+ CustomPacketPayload leavesPayload = top.leavesmc.leaves.protocol.core.LeavesProtocolManager.getPayload(id, buf); -+ if (leavesPayload != null) { -+ return leavesPayload; -+ } -+ // Leaves end - protocol - return (CustomPacketPayload) (packetdataserializer_a != null ? (CustomPacketPayload) packetdataserializer_a.apply(buf) : readUnknownPayload(id, buf)); - } - -diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index c68910b2a2eb703406fb406a86783cf6ab48651e..f935214ed80fe54038a96a5cd668a072cdf406ec 100644 ---- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -139,6 +139,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - - @Override - public void handleCustomPayload(ServerboundCustomPayloadPacket packet) { -+ top.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePayload(player, packet.payload()); // Leaves - protocol - // Paper start - Brand support - if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.BrandPayload brandPayload) { - this.player.clientBrandName = brandPayload.brand(); -@@ -156,6 +157,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - String channels = payload.toString(com.google.common.base.Charsets.UTF_8); - for (String channel : channels.split("\0")) { - this.getCraftPlayer().addChannel(channel); -+ top.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleMinecraftRegister(channel, player); // Leaves - protocol - } - } catch (Exception ex) { - ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t register custom payload", ex); -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 90be312057221a5a78066d89783c5e22008d797d..0f172512085e9dfc0850451d2c6bbffb18221f8f 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -441,6 +441,8 @@ public abstract class PlayerList { - //return; // Folia - region threading - must still allow the player to connect, as we must add to chunk map before handling disconnect - } - -+ top.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol -+ - final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage(); - - if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure -@@ -696,6 +698,7 @@ public abstract class PlayerList { - return this.remove(entityplayer, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName()))); - } - public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer, net.kyori.adventure.text.Component leaveMessage) { -+ top.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerLeave(entityplayer); // Leaves - protocol - // Paper end - Fix kick event leave message not being sent - ServerLevel worldserver = entityplayer.serverLevel(); - -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index c70eb23d9745bdbfcc340bb554cf0bf2db71f5de..dc223b536eadd2da6cf3c758a62d0ed81b5a7b3b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -471,6 +471,7 @@ public final class CraftServer implements Server { - MapPalette.setMapColorCache(new CraftMapColorCache(this.logger)); - } - datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper -+ top.leavesmc.leaves.protocol.core.LeavesProtocolManager.init(); // Leaves - protocol - } - - public boolean getCommandBlockOverride(String command) { -@@ -1129,6 +1130,7 @@ public final class CraftServer implements Server { - io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper - this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); - this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); -+ top.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleServerReload(); // Leaves - protocol - - int pollCount = 0; - -diff --git a/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocol.java -new file mode 100644 -index 0000000000000000000000000000000000000000..64a1d25973b032e8cab64bbffa6824a131676773 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocol.java -@@ -0,0 +1,16 @@ -+package top.leavesmc.leaves.protocol.core; -+ -+import java.lang.annotation.ElementType; -+import java.lang.annotation.Retention; -+import java.lang.annotation.RetentionPolicy; -+import java.lang.annotation.Target; -+ -+@Target(ElementType.TYPE) -+@Retention(RetentionPolicy.RUNTIME) -+public @interface LeavesProtocol { -+ -+ String namespace() default "minecraft"; -+ -+ String[] namespaces() default {}; -+ -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocolManager.java b/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocolManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8b7813c442733f5d4d3b2a072902099cbe596b37 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocolManager.java -@@ -0,0 +1,344 @@ -+package top.leavesmc.leaves.protocol.core; -+ -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.level.ServerPlayer; -+import org.apache.commons.lang.ArrayUtils; -+import org.jetbrains.annotations.NotNull; -+ -+import java.io.File; -+import java.io.IOException; -+import java.lang.reflect.Constructor; -+import java.lang.reflect.InvocationTargetException; -+import java.lang.reflect.Method; -+import java.lang.reflect.Modifier; -+import java.net.JarURLConnection; -+import java.net.URL; -+import java.net.URLDecoder; -+import java.nio.charset.StandardCharsets; -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.Enumeration; -+import java.util.HashMap; -+import java.util.HashSet; -+import java.util.LinkedHashSet; -+import java.util.List; -+import java.util.Map; -+import java.util.Set; -+import java.util.jar.JarEntry; -+import java.util.jar.JarFile; -+ -+public class LeavesProtocolManager { -+ -+ private static final Map>> KNOWN_TYPES = new HashMap<>(); -+ private static final Map> KNOW_RECEIVERS = new HashMap<>(); -+ -+ private static final List TICKERS = new ArrayList<>(); -+ private static final List PLAYER_JOIN = new ArrayList<>(); -+ private static final List PLAYER_LEAVE = new ArrayList<>(); -+ private static final List RELOAD_SERVER = new ArrayList<>(); -+ private static final Map> MINECRAFT_REGISTER = new HashMap<>(); -+ -+ public static void init() { -+ //Luminol start - For the protocol supports of luminol -+ final Set> allClazz = getClasses("org.leavesmc.leaves.protocol"); -+ allClazz.addAll(getClasses("me.earthme.luminol.protocols")); -+ //Luminol end -+ for (Class clazz : allClazz) { -+ final LeavesProtocol protocol = clazz.getAnnotation(LeavesProtocol.class); -+ if (protocol != null) { -+ Set methods; -+ try { -+ Method[] publicMethods = clazz.getMethods(); -+ Method[] privateMethods = clazz.getDeclaredMethods(); -+ methods = new HashSet<>(publicMethods.length + privateMethods.length, 1.0f); -+ Collections.addAll(methods, publicMethods); -+ Collections.addAll(methods, privateMethods); -+ } catch (NoClassDefFoundError e) { -+ e.printStackTrace(); -+ return; -+ } -+ -+ Map> map = new HashMap<>(); -+ for (final Method method : methods) { -+ if (method.isBridge() || method.isSynthetic() || !Modifier.isStatic(method.getModifiers())) { -+ continue; -+ } -+ -+ method.setAccessible(true); -+ -+ final ProtocolHandler.Init init = method.getAnnotation(ProtocolHandler.Init.class); -+ if (init != null) { -+ try { -+ method.invoke(null); -+ } catch (InvocationTargetException | IllegalAccessException e) { -+ e.printStackTrace(); -+ } -+ continue; -+ } -+ -+ final ProtocolHandler.PayloadReceiver receiver = method.getAnnotation(ProtocolHandler.PayloadReceiver.class); -+ if (receiver != null) { -+ try { -+ map.put(receiver, receiver.payload().getConstructor(ResourceLocation.class, FriendlyByteBuf.class)); -+ } catch (NoSuchMethodException e) { -+ e.printStackTrace(); -+ continue; -+ } -+ -+ if (!KNOW_RECEIVERS.containsKey(protocol)) { -+ KNOW_RECEIVERS.put(protocol, new HashMap<>()); -+ } -+ -+ KNOW_RECEIVERS.get(protocol).put(receiver, method); -+ continue; -+ } -+ -+ final ProtocolHandler.Ticker ticker = method.getAnnotation(ProtocolHandler.Ticker.class); -+ if (ticker != null) { -+ TICKERS.add(method); -+ continue; -+ } -+ -+ final ProtocolHandler.PlayerJoin playerJoin = method.getAnnotation(ProtocolHandler.PlayerJoin.class); -+ if (playerJoin != null) { -+ PLAYER_JOIN.add(method); -+ continue; -+ } -+ -+ final ProtocolHandler.PlayerLeave playerLeave = method.getAnnotation(ProtocolHandler.PlayerLeave.class); -+ if (playerLeave != null) { -+ PLAYER_LEAVE.add(method); -+ continue; -+ } -+ -+ final ProtocolHandler.ReloadServer reloadServer = method.getAnnotation(ProtocolHandler.ReloadServer.class); -+ if (reloadServer != null) { -+ RELOAD_SERVER.add(method); -+ continue; -+ } -+ -+ final ProtocolHandler.MinecraftRegister minecraftRegister = method.getAnnotation(ProtocolHandler.MinecraftRegister.class); -+ if (minecraftRegister != null) { -+ if (!MINECRAFT_REGISTER.containsKey(protocol)) { -+ MINECRAFT_REGISTER.put(protocol, new HashMap<>()); -+ } -+ -+ MINECRAFT_REGISTER.get(protocol).put(minecraftRegister, method); -+ } -+ } -+ KNOWN_TYPES.put(protocol, map); -+ } -+ } -+ } -+ -+ public static CustomPacketPayload getPayload(ResourceLocation id, FriendlyByteBuf buf) { -+ for (LeavesProtocol protocol : KNOWN_TYPES.keySet()) { -+ if (!protocol.namespace().equals(id.getNamespace()) && !ArrayUtils.contains(protocol.namespaces(), id.getNamespace())) { -+ continue; -+ } -+ -+ Map> map = KNOWN_TYPES.get(protocol); -+ for (ProtocolHandler.PayloadReceiver receiver : map.keySet()) { -+ if (receiver.ignoreId() || receiver.payloadId().equals(id.getPath()) || ArrayUtils.contains(receiver.payloadIds(), id.getPath())) { -+ try { -+ return map.get(receiver).newInstance(id, buf); -+ } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ return null; -+ } -+ -+ public static void handlePayload(ServerPlayer player, CustomPacketPayload payload) { -+ for (LeavesProtocol protocol : KNOW_RECEIVERS.keySet()) { -+ if (!protocol.namespace().equals(payload.id().getNamespace()) && !ArrayUtils.contains(protocol.namespaces(), payload.id().getNamespace())) { -+ continue; -+ } -+ -+ Map map = KNOW_RECEIVERS.get(protocol); -+ for (ProtocolHandler.PayloadReceiver receiver : map.keySet()) { -+ if (payload.getClass() == receiver.payload()) { -+ if (receiver.ignoreId() || receiver.payloadId().equals(payload.id().getPath()) || -+ ArrayUtils.contains(receiver.payloadIds(), payload.id().getPath())) { -+ try { -+ map.get(receiver).invoke(null, player, payload); -+ } catch (InvocationTargetException | IllegalAccessException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ } -+ } -+ -+ public static void handleTick() { -+ if (!TICKERS.isEmpty()) { -+ try { -+ for (Method method : TICKERS) { -+ method.invoke(null); -+ } -+ } catch (InvocationTargetException | IllegalAccessException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ -+ public static void handlePlayerJoin(ServerPlayer player) { -+ if (!PLAYER_JOIN.isEmpty()) { -+ try { -+ for (Method method : PLAYER_JOIN) { -+ method.invoke(null, player); -+ } -+ } catch (InvocationTargetException | IllegalAccessException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ -+ public static void handlePlayerLeave(ServerPlayer player) { -+ if (!PLAYER_LEAVE.isEmpty()) { -+ try { -+ for (Method method : PLAYER_LEAVE) { -+ method.invoke(null, player); -+ } -+ } catch (InvocationTargetException | IllegalAccessException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ -+ public static void handleServerReload() { -+ if (!RELOAD_SERVER.isEmpty()) { -+ try { -+ for (Method method : RELOAD_SERVER) { -+ method.invoke(null); -+ } -+ } catch (InvocationTargetException | IllegalAccessException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ -+ public static void handleMinecraftRegister(String channelId, ServerPlayer player) { -+ for (LeavesProtocol protocol : MINECRAFT_REGISTER.keySet()) { -+ String[] channel = channelId.split(":"); -+ if (!protocol.namespace().equals(channel[0]) && !ArrayUtils.contains(protocol.namespaces(), channel[0])) { -+ continue; -+ } -+ -+ Map map = MINECRAFT_REGISTER.get(protocol); -+ for (ProtocolHandler.MinecraftRegister register : map.keySet()) { -+ if (register.ignoreId() || register.channelId().equals(channel[1]) || -+ ArrayUtils.contains(register.channelIds(), channel[1])) { -+ try { -+ map.get(register).invoke(null, player); -+ } catch (InvocationTargetException | IllegalAccessException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ } -+ -+ public static Set> getClasses(String pack) { -+ Set> classes = new LinkedHashSet>(); -+ String packageDirName = pack.replace('.', '/'); -+ Enumeration dirs; -+ try { -+ dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); -+ while (dirs.hasMoreElements()) { -+ URL url = dirs.nextElement(); -+ String protocol = url.getProtocol(); -+ if ("file".equals(protocol)) { -+ String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8); -+ findClassesInPackageByFile(pack, filePath, classes); -+ } else if ("jar".equals(protocol)) { -+ JarFile jar; -+ try { -+ jar = ((JarURLConnection) url.openConnection()).getJarFile(); -+ Enumeration entries = jar.entries(); -+ findClassesInPackageByJar(pack, entries, packageDirName, classes); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ return classes; -+ } -+ -+ private static void findClassesInPackageByFile(String packageName, String packagePath, Set> classes) { -+ File dir = new File(packagePath); -+ if (!dir.exists() || !dir.isDirectory()) { -+ return; -+ } -+ File[] dirfiles = dir.listFiles((file) -> file.isDirectory() || file.getName().endsWith(".class")); -+ if (dirfiles != null) { -+ for (File file : dirfiles) { -+ if (file.isDirectory()) { -+ findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), classes); -+ } else { -+ String className = file.getName().substring(0, file.getName().length() - 6); -+ try { -+ classes.add(Class.forName(packageName + '.' + className)); -+ } catch (ClassNotFoundException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ } -+ -+ private static void findClassesInPackageByJar(String packageName, Enumeration entries, String packageDirName, Set> classes) { -+ while (entries.hasMoreElements()) { -+ JarEntry entry = entries.nextElement(); -+ String name = entry.getName(); -+ if (name.charAt(0) == '/') { -+ name = name.substring(1); -+ } -+ if (name.startsWith(packageDirName)) { -+ int idx = name.lastIndexOf('/'); -+ if (idx != -1) { -+ packageName = name.substring(0, idx).replace('/', '.'); -+ } -+ if (name.endsWith(".class") && !entry.isDirectory()) { -+ String className = name.substring(packageName.length() + 1, name.length() - 6); -+ try { -+ classes.add(Class.forName(packageName + '.' + className)); -+ } catch (ClassNotFoundException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ } -+ -+ public record EmptyPayload(ResourceLocation id) implements CustomPacketPayload { -+ -+ public EmptyPayload(ResourceLocation location, FriendlyByteBuf buf) { -+ this(location); -+ } -+ -+ @Override -+ public void write(@NotNull FriendlyByteBuf buf) { -+ } -+ } -+ -+ public record LeavesPayload(FriendlyByteBuf data, ResourceLocation id) implements CustomPacketPayload { -+ -+ public LeavesPayload(ResourceLocation location, FriendlyByteBuf buf) { -+ this(new FriendlyByteBuf(buf.readBytes(buf.readableBytes())), location); -+ } -+ -+ @Override -+ public void write(FriendlyByteBuf buf) { -+ buf.writeBytes(data); -+ } -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolHandler.java b/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolHandler.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d696f001d2576d1b61cc732c81f22eb52205072b ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolHandler.java -@@ -0,0 +1,65 @@ -+package top.leavesmc.leaves.protocol.core; -+ -+import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -+ -+import java.lang.annotation.ElementType; -+import java.lang.annotation.Retention; -+import java.lang.annotation.RetentionPolicy; -+import java.lang.annotation.Target; -+ -+public class ProtocolHandler { -+ -+ @Target(ElementType.METHOD) -+ @Retention(RetentionPolicy.RUNTIME) -+ public @interface Init { -+ -+ } -+ -+ @Target(ElementType.METHOD) -+ @Retention(RetentionPolicy.RUNTIME) -+ public @interface PayloadReceiver { -+ -+ Class payload(); -+ -+ String[] payloadIds() default {}; -+ -+ String payloadId() default ""; -+ -+ boolean ignoreId() default false; -+ } -+ -+ @Target(ElementType.METHOD) -+ @Retention(RetentionPolicy.RUNTIME) -+ public @interface Ticker { -+ int delay() default 0; -+ } -+ -+ @Target(ElementType.METHOD) -+ @Retention(RetentionPolicy.RUNTIME) -+ public @interface PlayerJoin { -+ -+ } -+ -+ @Target(ElementType.METHOD) -+ @Retention(RetentionPolicy.RUNTIME) -+ public @interface PlayerLeave { -+ -+ } -+ -+ @Target(ElementType.METHOD) -+ @Retention(RetentionPolicy.RUNTIME) -+ public @interface ReloadServer { -+ -+ } -+ -+ @Target(ElementType.METHOD) -+ @Retention(RetentionPolicy.RUNTIME) -+ public @interface MinecraftRegister { -+ -+ String channelId() default ""; -+ -+ String[] channelIds() default {}; -+ -+ boolean ignoreId() default false; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolUtils.java b/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolUtils.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5282c5ad3d26d06ab685ddaaf6fd9a4d49559717 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolUtils.java -@@ -0,0 +1,36 @@ -+package top.leavesmc.leaves.protocol.core; -+ -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket; -+import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.function.Consumer; -+ -+public class ProtocolUtils { -+ -+ public static void sendEmptyPayloadPacket(ServerPlayer player, ResourceLocation id) { -+ player.connection.send(new ClientboundCustomPayloadPacket(new LeavesProtocolManager.EmptyPayload(id))); -+ } -+ -+ public static void sendPayloadPacket(ServerPlayer player, ResourceLocation id, Consumer consumer) { -+ player.connection.send(new ClientboundCustomPayloadPacket(new CustomPacketPayload() { -+ @Override -+ public void write(@NotNull FriendlyByteBuf buf) { -+ consumer.accept(buf); -+ } -+ -+ @Override -+ @NotNull -+ public ResourceLocation id() { -+ return id; -+ } -+ })); -+ } -+ -+ public static void sendPayloadPacket(ServerPlayer player, CustomPacketPayload payload) { -+ player.connection.send(new ClientboundCustomPayloadPacket(payload)); -+ } -+} diff --git a/patches/server/0057-Leaves-Replay-Mod-API.patch b/patches/server/0052-Leaves-Replay-Mod-API.patch similarity index 99% rename from patches/server/0057-Leaves-Replay-Mod-API.patch rename to patches/server/0052-Leaves-Replay-Mod-API.patch index a12b61c..af20c7f 100644 --- a/patches/server/0057-Leaves-Replay-Mod-API.patch +++ b/patches/server/0052-Leaves-Replay-Mod-API.patch @@ -242,7 +242,7 @@ index 4fc9a47745b817d9ee2da4776cab26ff9f3b0025..e0a103ed27f834f62afb3696047c7581 player.connection = this; player.getTextFilter().join(); diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 0f172512085e9dfc0850451d2c6bbffb18221f8f..291f646febc3b40e91056f268433f09b584f2b29 100644 +index 90be312057221a5a78066d89783c5e22008d797d..185a4788809c0aec69420933944b468cbdbceda5 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -13,15 +13,7 @@ import java.net.SocketAddress; @@ -412,7 +412,7 @@ index 0f172512085e9dfc0850451d2c6bbffb18221f8f..291f646febc3b40e91056f268433f09b this.playersByName.put(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT), player); // Spigot this.playersByUUID.put(player.getUUID(), player); // this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer))); // CraftBukkit - replaced with loop below -@@ -473,6 +587,12 @@ public abstract class PlayerList { +@@ -471,6 +585,12 @@ public abstract class PlayerList { continue; } @@ -425,7 +425,7 @@ index 0f172512085e9dfc0850451d2c6bbffb18221f8f..291f646febc3b40e91056f268433f09b onlinePlayers.add(entityplayer1); // Paper - Use single player info update packet on join } // Paper start - Use single player info update packet on join -@@ -693,6 +813,54 @@ public abstract class PlayerList { +@@ -691,6 +811,54 @@ public abstract class PlayerList { } @@ -480,7 +480,7 @@ index 0f172512085e9dfc0850451d2c6bbffb18221f8f..291f646febc3b40e91056f268433f09b public net.kyori.adventure.text.Component remove(ServerPlayer entityplayer) { // CraftBukkit - return string // Paper - return Component // Paper start - Fix kick event leave message not being sent return this.remove(entityplayer, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? entityplayer.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(entityplayer.getDisplayName()))); -@@ -761,6 +929,7 @@ public abstract class PlayerList { +@@ -758,6 +926,7 @@ public abstract class PlayerList { // Folia - region threading - move to onDisconnect of common packet listener entityplayer.getAdvancements().stopListening(); this.players.remove(entityplayer); @@ -489,7 +489,7 @@ index 0f172512085e9dfc0850451d2c6bbffb18221f8f..291f646febc3b40e91056f268433f09b this.server.getCustomBossEvents().onPlayerDisconnect(entityplayer); UUID uuid = entityplayer.getUUID(); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index dc223b536eadd2da6cf3c758a62d0ed81b5a7b3b..e0f49c7e941830236b92f6705cd2c4b96e943a96 100644 +index c70eb23d9745bdbfcc340bb554cf0bf2db71f5de..469e175dc87e66ce73efcc04a68b19140cb7194f 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -308,6 +308,7 @@ public final class CraftServer implements Server { @@ -509,7 +509,7 @@ index dc223b536eadd2da6cf3c758a62d0ed81b5a7b3b..e0f49c7e941830236b92f6705cd2c4b9 @Override public CraftPlayer apply(ServerPlayer player) { return player.getBukkitEntity(); -@@ -3306,4 +3307,11 @@ public final class CraftServer implements Server { +@@ -3304,4 +3305,11 @@ public final class CraftServer implements Server { } // Paper end diff --git a/patches/server/0058-Fix-MC-172047.patch b/patches/server/0053-Fix-MC-172047.patch similarity index 100% rename from patches/server/0058-Fix-MC-172047.patch rename to patches/server/0053-Fix-MC-172047.patch diff --git a/patches/server/0053-Leaves-Bladeren-Protocol.patch b/patches/server/0053-Leaves-Bladeren-Protocol.patch deleted file mode 100644 index 3ea2948..0000000 --- a/patches/server/0053-Leaves-Bladeren-Protocol.patch +++ /dev/null @@ -1,292 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Wed, 7 Feb 2024 08:59:41 +0000 -Subject: [PATCH] Leaves Bladeren Protocol - - -diff --git a/src/main/java/me/earthme/luminol/config/modules/gameplay/LeavesBladerenProtocolConfig.java b/src/main/java/me/earthme/luminol/config/modules/gameplay/LeavesBladerenProtocolConfig.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4950d33288d6bc3c4ce90ae12bbf4797e3989500 ---- /dev/null -+++ b/src/main/java/me/earthme/luminol/config/modules/gameplay/LeavesBladerenProtocolConfig.java -@@ -0,0 +1,28 @@ -+package me.earthme.luminol.config.modules.gameplay; -+ -+import me.earthme.luminol.config.ConfigInfo; -+import me.earthme.luminol.config.EnumConfigCategory; -+import me.earthme.luminol.config.HotReloadUnsupported; -+import me.earthme.luminol.config.IConfigModule; -+ -+public class LeavesBladerenProtocolConfig implements IConfigModule { -+ @HotReloadUnsupported -+ @ConfigInfo(baseName = "enable_base_protocol") -+ public static boolean enableBaseProtocol = false; -+ @HotReloadUnsupported -+ @ConfigInfo(baseName = "enable_mspt_sync_protocol") -+ public static boolean msptSyncProtocol = false; -+ @HotReloadUnsupported -+ @ConfigInfo(baseName = "mspt_sync_interval") -+ public static int msptSyncTickInterval = 20; -+ -+ @Override -+ public EnumConfigCategory getCategory() { -+ return EnumConfigCategory.GAMEPLAY; -+ } -+ -+ @Override -+ public String getBaseName() { -+ return "leaves_bladeren_protocol"; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/bladeren/BladerenProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/bladeren/BladerenProtocol.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6415f17fa6c06199e59705a29605d2aef834fc17 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/bladeren/BladerenProtocol.java -@@ -0,0 +1,150 @@ -+package top.leavesmc.leaves.protocol.bladeren; -+ -+import com.google.common.collect.Maps; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.Contract; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.core.LeavesProtocol; -+import top.leavesmc.leaves.protocol.core.ProtocolHandler; -+import top.leavesmc.leaves.protocol.core.ProtocolUtils; -+ -+import java.util.HashMap; -+import java.util.Map; -+import java.util.function.BiConsumer; -+ -+@LeavesProtocol(namespace = "bladeren") -+public class BladerenProtocol { -+ -+ public static final String PROTOCOL_ID = "bladeren"; -+ public static final String PROTOCOL_VERSION = "1.0.0"; -+ -+ private static final ResourceLocation HELLO_ID = id("hello"); -+ private static final ResourceLocation FEATURE_MODIFY_ID = id("feature_modify"); -+ -+ private static final Map> registeredFeatures = Maps.newConcurrentMap(); -+ -+ @Contract("_ -> new") -+ public static @NotNull ResourceLocation id(String path) { -+ return new ResourceLocation(PROTOCOL_ID, path); -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = BladerenHelloPayload.class, payloadId = "hello") -+ private static void handleHello(@NotNull ServerPlayer player, @NotNull BladerenHelloPayload payload) { -+ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.enableBaseProtocol) { -+ String clientVersion = payload.version; -+ CompoundTag tag = payload.nbt; -+ -+ if (tag != null) { -+ CompoundTag featureNbt = tag.getCompound("Features"); -+ for (String name : featureNbt.getAllKeys()) { -+ -+ final BiConsumer target = registeredFeatures.get(name); -+ -+ if (target != null){ -+ target.accept(player, featureNbt.getCompound(name)); -+ } -+ } -+ } -+ } -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = BladerenFeatureModifyPayload.class, payloadId = "feature_modify") -+ private static void handleModify(@NotNull ServerPlayer player, @NotNull BladerenFeatureModifyPayload payload) { -+ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.enableBaseProtocol) { -+ String name = payload.name; -+ CompoundTag tag = payload.nbt; -+ -+ final BiConsumer target = registeredFeatures.get(name); -+ -+ if (target != null){ -+ target.accept(player, tag); -+ } -+ } -+ } -+ -+ @ProtocolHandler.PlayerJoin -+ public static void onPlayerJoin(@NotNull ServerPlayer player) { -+ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.enableBaseProtocol) { -+ CompoundTag tag = new CompoundTag(); -+ LeavesFeatureSet.writeNBT(tag); -+ ProtocolUtils.sendPayloadPacket(player, new BladerenHelloPayload(PROTOCOL_VERSION, tag)); -+ } -+ } -+ -+ public static void registerFeature(String name, BiConsumer consumer) { -+ registeredFeatures.put(name, consumer); -+ } -+ -+ public static class LeavesFeatureSet { -+ -+ private static final Map features = new HashMap<>(); -+ -+ public static void writeNBT(@NotNull CompoundTag tag) { -+ CompoundTag featureNbt = new CompoundTag(); -+ features.values().forEach(feature -> feature.writeNBT(featureNbt)); -+ tag.put("Features", featureNbt); -+ } -+ -+ public static void register(LeavesFeature feature) { -+ features.put(feature.name, feature); -+ } -+ } -+ -+ public record LeavesFeature(String name, String value) { -+ -+ @NotNull -+ @Contract("_, _ -> new") -+ public static LeavesFeature of(String name, boolean value) { -+ return new LeavesFeature(name, Boolean.toString(value)); -+ } -+ -+ public void writeNBT(@NotNull CompoundTag rules) { -+ CompoundTag rule = new CompoundTag(); -+ rule.putString("Feature", name); -+ rule.putString("Value", value); -+ rules.put(name, rule); -+ } -+ } -+ -+ public record BladerenFeatureModifyPayload(String name, CompoundTag nbt) implements CustomPacketPayload { -+ -+ public BladerenFeatureModifyPayload(ResourceLocation location, FriendlyByteBuf buf) { -+ this(buf.readUtf(), buf.readNbt()); -+ } -+ -+ @Override -+ public void write(@NotNull FriendlyByteBuf buf) { -+ buf.writeUtf(name); -+ buf.writeNbt(nbt); -+ } -+ -+ @Override -+ @NotNull -+ public ResourceLocation id() { -+ return FEATURE_MODIFY_ID; -+ } -+ } -+ -+ public record BladerenHelloPayload(String version, CompoundTag nbt) implements CustomPacketPayload { -+ -+ public BladerenHelloPayload(ResourceLocation location, @NotNull FriendlyByteBuf buf) { -+ this(buf.readUtf(64), buf.readNbt()); -+ } -+ -+ @Override -+ public void write(@NotNull FriendlyByteBuf buf) { -+ buf.writeUtf(version); -+ buf.writeNbt(nbt); -+ } -+ -+ @Override -+ @NotNull -+ public ResourceLocation id() { -+ return HELLO_ID; -+ } -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java -new file mode 100644 -index 0000000000000000000000000000000000000000..db63ea1cf65e6ca06bd1c6ce978193e068a9a951 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java -@@ -0,0 +1,90 @@ -+package top.leavesmc.leaves.protocol.bladeren; -+ -+import io.papermc.paper.threadedregions.ThreadedRegionizer; -+import io.papermc.paper.threadedregions.TickData; -+import io.papermc.paper.threadedregions.TickRegions; -+import it.unimi.dsi.fastutil.objects.ObjectArrayList; -+import it.unimi.dsi.fastutil.objects.ObjectLists; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.Contract; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.core.LeavesProtocol; -+import top.leavesmc.leaves.protocol.core.ProtocolHandler; -+import top.leavesmc.leaves.protocol.core.ProtocolUtils; -+ -+import java.util.List; -+ -+@LeavesProtocol(namespace = "bladeren") -+public class MsptSyncProtocol { -+ -+ public static final String PROTOCOL_ID = "bladeren"; -+ -+ private static final ResourceLocation MSPT_SYNC = id("mspt_sync"); -+ -+ private static final List players = ObjectLists.synchronize(new ObjectArrayList<>()); -+ -+ private static int tickCounter = 0; -+ -+ @Contract("_ -> new") -+ public static @NotNull ResourceLocation id(String path) { -+ return new ResourceLocation(PROTOCOL_ID, path); -+ } -+ -+ @ProtocolHandler.Init -+ public static void init() { -+ BladerenProtocol.registerFeature("mspt_sync", (player, compoundTag) -> { -+ if (compoundTag.getString("Value").equals("true")) { -+ onPlayerSubmit(player); -+ } else { -+ onPlayerLoggedOut(player); -+ } -+ }); -+ } -+ -+ @ProtocolHandler.PlayerLeave -+ public static void onPlayerLoggedOut(@NotNull ServerPlayer player) { -+ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.msptSyncProtocol) { -+ players.remove(player); -+ } -+ } -+ -+ @ProtocolHandler.Ticker -+ public static void tick() { -+ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.msptSyncProtocol) { -+ if (players.isEmpty()) { -+ return; -+ } -+ -+ if (tickCounter++ % me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.msptSyncTickInterval == 0) { -+ for (ServerPlayer player : players){ -+ final ThreadedRegionizer.ThreadedRegion region = ((ServerLevel) player.level()).regioniser.getRegionAtUnsynchronised(player.sectionX,player.sectionZ); -+ -+ if (region == null){ -+ continue; -+ } -+ -+ final TickData.TickReportData reportData = region.getData().getRegionSchedulingHandle().getTickReport5s(System.nanoTime()); -+ -+ if (reportData != null){ -+ final TickData.SegmentData tpsData = reportData.tpsData().segmentAll(); -+ final double mspt = reportData.timePerTickData().segmentAll().average() / 1.0E6; -+ final double tps = tpsData.average(); -+ -+ ProtocolUtils.sendPayloadPacket(player, MSPT_SYNC, buf -> { -+ buf.writeDouble(mspt); -+ buf.writeDouble(tps); -+ }); -+ } -+ } -+ } -+ } -+ } -+ -+ public static void onPlayerSubmit(@NotNull ServerPlayer player) { -+ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.msptSyncProtocol) { -+ players.add(player); -+ } -+ } -+} diff --git a/patches/server/0059-Fix-MC-2025.patch b/patches/server/0054-Fix-MC-2025.patch similarity index 100% rename from patches/server/0059-Fix-MC-2025.patch rename to patches/server/0054-Fix-MC-2025.patch diff --git a/patches/server/0054-Leaves-Fix-Bladeren-Protocol.patch b/patches/server/0054-Leaves-Fix-Bladeren-Protocol.patch deleted file mode 100644 index 57fa34d..0000000 --- a/patches/server/0054-Leaves-Fix-Bladeren-Protocol.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Wed, 7 Feb 2024 09:00:10 +0000 -Subject: [PATCH] Leaves Fix Bladeren Protocol - - -diff --git a/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocol.java -index 64a1d25973b032e8cab64bbffa6824a131676773..57a563b3f2d01719d490578907411d25ea07a658 100644 ---- a/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocol.java -+++ b/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocol.java -@@ -8,9 +8,7 @@ import java.lang.annotation.Target; - @Target(ElementType.TYPE) - @Retention(RetentionPolicy.RUNTIME) - public @interface LeavesProtocol { -- -- String namespace() default "minecraft"; -- -- String[] namespaces() default {}; -+ -+ String[] namespace(); - - } -diff --git a/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocolManager.java b/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocolManager.java -index 8b7813c442733f5d4d3b2a072902099cbe596b37..1f5b37daa5cbb709eeacf3dc7a4f9b4a0dc05274 100644 ---- a/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocolManager.java -+++ b/src/main/java/top/leavesmc/leaves/protocol/core/LeavesProtocolManager.java -@@ -60,7 +60,7 @@ public class LeavesProtocolManager { - return; - } - -- Map> map = new HashMap<>(); -+ Map> map = KNOWN_TYPES.getOrDefault(protocol, new HashMap<>()); - for (final Method method : methods) { - if (method.isBridge() || method.isSynthetic() || !Modifier.isStatic(method.getModifiers())) { - continue; -@@ -135,13 +135,13 @@ public class LeavesProtocolManager { - - public static CustomPacketPayload getPayload(ResourceLocation id, FriendlyByteBuf buf) { - for (LeavesProtocol protocol : KNOWN_TYPES.keySet()) { -- if (!protocol.namespace().equals(id.getNamespace()) && !ArrayUtils.contains(protocol.namespaces(), id.getNamespace())) { -+ if (!ArrayUtils.contains(protocol.namespace(), id.getNamespace())) { - continue; - } - - Map> map = KNOWN_TYPES.get(protocol); - for (ProtocolHandler.PayloadReceiver receiver : map.keySet()) { -- if (receiver.ignoreId() || receiver.payloadId().equals(id.getPath()) || ArrayUtils.contains(receiver.payloadIds(), id.getPath())) { -+ if (receiver.ignoreId() || ArrayUtils.contains(receiver.payloadId(), id.getPath())) { - try { - return map.get(receiver).newInstance(id, buf); - } catch (InvocationTargetException | InstantiationException | IllegalAccessException e) { -@@ -155,15 +155,14 @@ public class LeavesProtocolManager { - - public static void handlePayload(ServerPlayer player, CustomPacketPayload payload) { - for (LeavesProtocol protocol : KNOW_RECEIVERS.keySet()) { -- if (!protocol.namespace().equals(payload.id().getNamespace()) && !ArrayUtils.contains(protocol.namespaces(), payload.id().getNamespace())) { -+ if (!ArrayUtils.contains(protocol.namespace(), payload.id().getNamespace())) { - continue; - } - - Map map = KNOW_RECEIVERS.get(protocol); - for (ProtocolHandler.PayloadReceiver receiver : map.keySet()) { - if (payload.getClass() == receiver.payload()) { -- if (receiver.ignoreId() || receiver.payloadId().equals(payload.id().getPath()) || -- ArrayUtils.contains(receiver.payloadIds(), payload.id().getPath())) { -+ if (receiver.ignoreId() || ArrayUtils.contains(receiver.payloadId(), payload.id().getPath())) { - try { - map.get(receiver).invoke(null, player, payload); - } catch (InvocationTargetException | IllegalAccessException e) { -@@ -226,7 +225,7 @@ public class LeavesProtocolManager { - public static void handleMinecraftRegister(String channelId, ServerPlayer player) { - for (LeavesProtocol protocol : MINECRAFT_REGISTER.keySet()) { - String[] channel = channelId.split(":"); -- if (!protocol.namespace().equals(channel[0]) && !ArrayUtils.contains(protocol.namespaces(), channel[0])) { -+ if (!ArrayUtils.contains(protocol.namespace(), channel[0])) { - continue; - } - -diff --git a/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolHandler.java b/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolHandler.java -index d696f001d2576d1b61cc732c81f22eb52205072b..92ad6e9b1c0d9640b80c1ebe739c613d989eec21 100644 ---- a/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolHandler.java -+++ b/src/main/java/top/leavesmc/leaves/protocol/core/ProtocolHandler.java -@@ -21,9 +21,7 @@ public class ProtocolHandler { - - Class payload(); - -- String[] payloadIds() default {}; -- -- String payloadId() default ""; -+ String[] payloadId(); - - boolean ignoreId() default false; - } diff --git a/patches/server/0060-KioCG-Chunk-API.patch b/patches/server/0055-KioCG-Chunk-API.patch similarity index 99% rename from patches/server/0060-KioCG-Chunk-API.patch rename to patches/server/0055-KioCG-Chunk-API.patch index 519a917..fc0344b 100644 --- a/patches/server/0060-KioCG-Chunk-API.patch +++ b/patches/server/0055-KioCG-Chunk-API.patch @@ -268,10 +268,10 @@ index 0a8a53710c693a220e9475f6f3112b91d8209c00..5053852c72b68db41a2f51a72fffa1f8 + // KioCG end } diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 71b1f576aff8dcf51dd888280b5b7a25a387d197..aa1f52ab22d4dfa0c78afb6c425376322c9dd439 100644 +index aa51819373465c733d0c31ae18ef97afee550767..94cf8625c3c15757039cf8ac295f4def703f2b26 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -1831,4 +1831,11 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -1830,4 +1830,11 @@ public abstract class Mob extends LivingEntity implements Targeting { return itemmonsteregg == null ? null : new ItemStack(itemmonsteregg); } diff --git a/patches/server/0055-Leaves-carpet-protocol-support.patch b/patches/server/0055-Leaves-carpet-protocol-support.patch deleted file mode 100644 index 521a51d..0000000 --- a/patches/server/0055-Leaves-carpet-protocol-support.patch +++ /dev/null @@ -1,153 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Thu, 8 Feb 2024 11:57:18 +0000 -Subject: [PATCH] Leaves carpet protocol support - - -diff --git a/src/main/java/me/earthme/luminol/config/modules/gameplay/LeavesCarpetProtocolSupportConfig.java b/src/main/java/me/earthme/luminol/config/modules/gameplay/LeavesCarpetProtocolSupportConfig.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0ef77515b213b74bdcf7dac70a02bfaa1c8804f5 ---- /dev/null -+++ b/src/main/java/me/earthme/luminol/config/modules/gameplay/LeavesCarpetProtocolSupportConfig.java -@@ -0,0 +1,22 @@ -+package me.earthme.luminol.config.modules.gameplay; -+ -+import me.earthme.luminol.config.ConfigInfo; -+import me.earthme.luminol.config.EnumConfigCategory; -+import me.earthme.luminol.config.HotReloadUnsupported; -+import me.earthme.luminol.config.IConfigModule; -+ -+public class LeavesCarpetProtocolSupportConfig implements IConfigModule { -+ @HotReloadUnsupported -+ @ConfigInfo(baseName = "enabled") -+ public static boolean enabled = false; -+ -+ @Override -+ public EnumConfigCategory getCategory() { -+ return EnumConfigCategory.GAMEPLAY; -+ } -+ -+ @Override -+ public String getBaseName() { -+ return "leaves_carpet_protocol"; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/CarpetServerProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/CarpetServerProtocol.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0542d66a3dfae2aa3ccb6ca3dced6b34024017ad ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/CarpetServerProtocol.java -@@ -0,0 +1,113 @@ -+package top.leavesmc.leaves.protocol; -+ -+import me.earthme.luminol.config.modules.gameplay.LeavesCarpetProtocolSupportConfig; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.Contract; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.core.LeavesProtocol; -+import top.leavesmc.leaves.protocol.core.ProtocolHandler; -+import top.leavesmc.leaves.protocol.core.ProtocolUtils; -+ -+import java.util.HashMap; -+import java.util.Locale; -+import java.util.Map; -+ -+@LeavesProtocol(namespace = "carpet") -+public class CarpetServerProtocol { -+ -+ public static final String PROTOCOL_ID = "carpet"; -+ public static final String VERSION = "leaves-carpet-1.0.0"; -+ -+ private static final ResourceLocation HELLO_ID = CarpetServerProtocol.id("hello"); -+ -+ private static final String HI = "69"; -+ private static final String HELLO = "420"; -+ -+ @Contract("_ -> new") -+ public static @NotNull ResourceLocation id(String path) { -+ return new ResourceLocation(PROTOCOL_ID, path); -+ } -+ -+ @ProtocolHandler.PlayerJoin -+ public static void onPlayerJoin(ServerPlayer player) { -+ if (LeavesCarpetProtocolSupportConfig.enabled) { -+ CompoundTag data = new CompoundTag(); -+ data.putString(HI, VERSION); -+ ProtocolUtils.sendPayloadPacket(player, new CarpetPayload(data)); -+ } -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = CarpetPayload.class, payloadId = "hello") -+ private static void handleHello(@NotNull ServerPlayer player, @NotNull CarpetServerProtocol.CarpetPayload payload) { -+ if (LeavesCarpetProtocolSupportConfig.enabled) { -+ if (payload.nbt.contains(HELLO)) { -+ MinecraftServer.LOGGER.info("Player " + player.getScoreboardName() + " joined with carpet " + payload.nbt.getString(HELLO)); -+ CompoundTag data = new CompoundTag(); -+ CarpetRules.write(data); -+ ProtocolUtils.sendPayloadPacket(player, new CarpetPayload(data)); -+ } -+ } -+ } -+ -+ public static class CarpetRules { -+ -+ private static final Map rules = new HashMap<>(); -+ -+ public static void write(@NotNull CompoundTag tag) { -+ CompoundTag rulesNbt = new CompoundTag(); -+ rules.values().forEach(rule -> rule.writeNBT(rulesNbt)); -+ -+ tag.put("Rules", rulesNbt); -+ } -+ -+ public static void register(CarpetRule rule) { -+ rules.put(rule.name, rule); -+ } -+ } -+ -+ public record CarpetRule(String identifier, String name, String value) { -+ -+ @NotNull -+ @Contract("_, _, _ -> new") -+ public static CarpetRule of(String identifier, String name, Enum value) { -+ return new CarpetRule(identifier, name, value.name().toLowerCase(Locale.ROOT)); -+ } -+ -+ @NotNull -+ @Contract("_, _, _ -> new") -+ public static CarpetRule of(String identifier, String name, boolean value) { -+ return new CarpetRule(identifier, name, Boolean.toString(value)); -+ } -+ -+ public void writeNBT(@NotNull CompoundTag rules) { -+ CompoundTag rule = new CompoundTag(); -+ rule.putString("Value", value); -+ rule.putString("Manager", identifier); -+ rule.putString("Rule", name); -+ rules.put(name, rule); -+ } -+ } -+ -+ public record CarpetPayload(CompoundTag nbt) implements CustomPacketPayload { -+ -+ public CarpetPayload(ResourceLocation location, FriendlyByteBuf buf) { -+ this(buf.readNbt()); -+ } -+ -+ @Override -+ public void write(FriendlyByteBuf buf) { -+ buf.writeNbt(nbt); -+ } -+ -+ @Override -+ @NotNull -+ public ResourceLocation id() { -+ return HELLO_ID; -+ } -+ } -+} diff --git a/patches/server/0061-Added-chunkhot-to-tpsbar.patch b/patches/server/0056-Added-chunkhot-to-tpsbar.patch similarity index 100% rename from patches/server/0061-Added-chunkhot-to-tpsbar.patch rename to patches/server/0056-Added-chunkhot-to-tpsbar.patch