Compare commits
1 Commits
ver/1.20.1
...
build-224
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3a6c53f66 |
@@ -5,7 +5,7 @@ Subject: [PATCH] Async path processing
|
|||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
|
diff --git a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
|
||||||
index ebfa9e1dcca5ea8272e796f0409902d92b59ee76..6be4abdd16f2d57a80dbe175a91ff304fd17a7db 100644
|
index 6df1720159383c2f536b40ded1092a437c1a20af..fc88b9f1e7e8f5858a91deeca2a5d51266a79a93 100644
|
||||||
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
|
--- a/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
|
||||||
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
|
+++ b/src/main/java/dev/kaiijumc/kaiiju/KaiijuConfig.java
|
||||||
@@ -12,6 +12,7 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
@@ -12,6 +12,7 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
@@ -16,14 +16,13 @@ index ebfa9e1dcca5ea8272e796f0409902d92b59ee76..6be4abdd16f2d57a80dbe175a91ff304
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
@@ -213,12 +214,28 @@ public class KaiijuConfig {
|
@@ -218,12 +219,26 @@ public class KaiijuConfig {
|
||||||
public static boolean disablePlayerStats = false;
|
public static boolean disablePlayerStats = false;
|
||||||
public static boolean disableArmSwingEvent = false;
|
public static boolean disableArmSwingEvent = false;
|
||||||
public static boolean disableEnsureTickThreadChecks = false;
|
public static boolean disableEnsureTickThreadChecks = false;
|
||||||
+ public static boolean asyncPathProcessing = false;
|
+ public static boolean asyncPathProcessing = false;
|
||||||
+ public static int asyncPathProcessingMaxThreads = 0;
|
+ public static int asyncPathProcessingMaxThreads = 0;
|
||||||
+ public static int asyncPathProcessingKeepalive = 60;
|
+ public static int asyncPathProcessingKeepalive = 60;
|
||||||
+ public static int asyncPathProcessingQueueCapacity = 4096;
|
|
||||||
|
|
||||||
private static void optimizationSettings() {
|
private static void optimizationSettings() {
|
||||||
disableVanishApi = getBoolean("optimization.disable-vanish-api", disableVanishApi);
|
disableVanishApi = getBoolean("optimization.disable-vanish-api", disableVanishApi);
|
||||||
@@ -33,7 +32,6 @@ index ebfa9e1dcca5ea8272e796f0409902d92b59ee76..6be4abdd16f2d57a80dbe175a91ff304
|
|||||||
+ asyncPathProcessing = getBoolean("optimization.async-path-processing.enable", asyncPathProcessing);
|
+ asyncPathProcessing = getBoolean("optimization.async-path-processing.enable", asyncPathProcessing);
|
||||||
+ asyncPathProcessingMaxThreads = getInt("optimization.async-path-processing.max-threads", asyncPathProcessingMaxThreads);
|
+ asyncPathProcessingMaxThreads = getInt("optimization.async-path-processing.max-threads", asyncPathProcessingMaxThreads);
|
||||||
+ asyncPathProcessingKeepalive = getInt("optimization.async-path-processing.keepalive", asyncPathProcessingKeepalive);
|
+ asyncPathProcessingKeepalive = getInt("optimization.async-path-processing.keepalive", asyncPathProcessingKeepalive);
|
||||||
+ asyncPathProcessingQueueCapacity = getInt("optimization.async-path-processing.queue-capacity", asyncPathProcessingQueueCapacity);
|
|
||||||
+ if (asyncPathProcessingMaxThreads < 0)
|
+ if (asyncPathProcessingMaxThreads < 0)
|
||||||
+ asyncPathProcessingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + asyncPathProcessingMaxThreads, 1);
|
+ asyncPathProcessingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + asyncPathProcessingMaxThreads, 1);
|
||||||
+ else if (asyncPathProcessingMaxThreads == 0)
|
+ else if (asyncPathProcessingMaxThreads == 0)
|
||||||
@@ -340,10 +338,10 @@ index 0000000000000000000000000000000000000000..6b91852238f80d236fc44f766b115267
|
|||||||
+}
|
+}
|
||||||
diff --git a/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java b/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java
|
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
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..a6de8906d1629c60523c02681379ccdcaa22b588
|
index 0000000000000000000000000000000000000000..acdb210e706ea85355f971d73aed92b071410abf
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java
|
+++ b/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java
|
||||||
@@ -0,0 +1,53 @@
|
@@ -0,0 +1,48 @@
|
||||||
+package dev.kaiijumc.kaiiju.path;
|
+package dev.kaiijumc.kaiiju.path;
|
||||||
+
|
+
|
||||||
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
@@ -362,12 +360,7 @@ index 0000000000000000000000000000000000000000..a6de8906d1629c60523c02681379ccdc
|
|||||||
+ */
|
+ */
|
||||||
+public class AsyncPathProcessor {
|
+public class AsyncPathProcessor {
|
||||||
+
|
+
|
||||||
+ private static final Executor pathProcessingExecutor = new ThreadPoolExecutor(
|
+ private static final Executor pathProcessingExecutor = Executors.newCachedThreadPool(
|
||||||
+ 1,
|
|
||||||
+ dev.kaiijumc.kaiiju.KaiijuConfig.asyncPathProcessingMaxThreads,
|
|
||||||
+ dev.kaiijumc.kaiiju.KaiijuConfig.asyncPathProcessingKeepalive,
|
|
||||||
+ TimeUnit.SECONDS,
|
|
||||||
+ new ArrayBlockingQueue<>(dev.kaiijumc.kaiiju.KaiijuConfig.asyncPathProcessingQueueCapacity),
|
|
||||||
+ new ThreadFactoryBuilder()
|
+ new ThreadFactoryBuilder()
|
||||||
+ .setNameFormat("petal-path-processor-%d")
|
+ .setNameFormat("petal-path-processor-%d")
|
||||||
+ .setPriority(Thread.NORM_PRIORITY - 2)
|
+ .setPriority(Thread.NORM_PRIORITY - 2)
|
||||||
@@ -399,10 +392,10 @@ index 0000000000000000000000000000000000000000..a6de8906d1629c60523c02681379ccdc
|
|||||||
+}
|
+}
|
||||||
diff --git a/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorCache.java b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorCache.java
|
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
|
new file mode 100644
|
||||||
index 0000000000000000000000000000000000000000..121eda164714650f76bb6c8495ef375d8a00d812
|
index 0000000000000000000000000000000000000000..3213fed7cea3ebfc364f4d6603b95f4263222c76
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorCache.java
|
+++ b/src/main/java/dev/kaiijumc/kaiiju/path/NodeEvaluatorCache.java
|
||||||
@@ -0,0 +1,42 @@
|
@@ -0,0 +1,45 @@
|
||||||
+package dev.kaiijumc.kaiiju.path;
|
+package dev.kaiijumc.kaiiju.path;
|
||||||
+
|
+
|
||||||
+import net.minecraft.world.level.pathfinder.NodeEvaluator;
|
+import net.minecraft.world.level.pathfinder.NodeEvaluator;
|
||||||
@@ -419,13 +412,13 @@ index 0000000000000000000000000000000000000000..121eda164714650f76bb6c8495ef375d
|
|||||||
+ private static final Map<NodeEvaluatorFeatures, ConcurrentLinkedQueue<NodeEvaluator>> threadLocalNodeEvaluators = new ConcurrentHashMap<>();
|
+ private static final Map<NodeEvaluatorFeatures, ConcurrentLinkedQueue<NodeEvaluator>> threadLocalNodeEvaluators = new ConcurrentHashMap<>();
|
||||||
+ private static final Map<NodeEvaluator, NodeEvaluatorGenerator> nodeEvaluatorToGenerator = new ConcurrentHashMap<>();
|
+ private static final Map<NodeEvaluator, NodeEvaluatorGenerator> nodeEvaluatorToGenerator = new ConcurrentHashMap<>();
|
||||||
+
|
+
|
||||||
+ private static @NotNull Queue<NodeEvaluator> getDequeForGenerator(@NotNull NodeEvaluatorFeatures nodeEvaluatorFeatures) {
|
+ private static @NotNull Queue<NodeEvaluator> getQueueForFeatures(@NotNull NodeEvaluatorFeatures nodeEvaluatorFeatures) {
|
||||||
+ return threadLocalNodeEvaluators.computeIfAbsent(nodeEvaluatorFeatures, (key) -> new ConcurrentLinkedQueue<>());
|
+ return threadLocalNodeEvaluators.computeIfAbsent(nodeEvaluatorFeatures, (key) -> new ConcurrentLinkedQueue<>());
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ public static @NotNull NodeEvaluator takeNodeEvaluator(@NotNull NodeEvaluatorGenerator generator, @NotNull NodeEvaluator localNodeEvaluator) {
|
+ public static @NotNull NodeEvaluator takeNodeEvaluator(@NotNull NodeEvaluatorGenerator generator, @NotNull NodeEvaluator localNodeEvaluator) {
|
||||||
+ final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(localNodeEvaluator);
|
+ final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(localNodeEvaluator);
|
||||||
+ NodeEvaluator nodeEvaluator = getDequeForGenerator(nodeEvaluatorFeatures).poll();
|
+ NodeEvaluator nodeEvaluator = getQueueForFeatures(nodeEvaluatorFeatures).poll();
|
||||||
+
|
+
|
||||||
+ if (nodeEvaluator == null) {
|
+ if (nodeEvaluator == null) {
|
||||||
+ nodeEvaluator = generator.generate(nodeEvaluatorFeatures);
|
+ nodeEvaluator = generator.generate(nodeEvaluatorFeatures);
|
||||||
@@ -437,13 +430,16 @@ index 0000000000000000000000000000000000000000..121eda164714650f76bb6c8495ef375d
|
|||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ public static void returnNodeEvaluator(@NotNull NodeEvaluator nodeEvaluator) {
|
+ public static void returnNodeEvaluator(@NotNull NodeEvaluator nodeEvaluator) {
|
||||||
+ final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(nodeEvaluator);
|
+ final NodeEvaluatorGenerator generator = nodeEvaluatorToGenerator.remove(nodeEvaluator);
|
||||||
+ final var generator = nodeEvaluatorToGenerator.remove(nodeEvaluator);
|
|
||||||
+ Validate.notNull(generator, "NodeEvaluator already returned");
|
+ Validate.notNull(generator, "NodeEvaluator already returned");
|
||||||
+
|
+
|
||||||
+ getDequeForGenerator(nodeEvaluatorFeatures).offer(nodeEvaluator);
|
+ 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
|
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
|
new file mode 100644
|
||||||
@@ -1171,10 +1167,10 @@ index 2a335f277bd0e4b8ad0f60d8226eb8aaa80a871f..b2c3c459fae7d0cb5ef0fcbc2ff0e61c
|
|||||||
return false;
|
return false;
|
||||||
} else if (o.nodes.size() != this.nodes.size()) {
|
} 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
|
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 d23481453717f715124156b5d83f6448f720d049..d4cc2a5f99f8445be9a63c279e28032f11a91304 100644
|
index d23481453717f715124156b5d83f6448f720d049..bab740b11e4cc20f924fcf9e33779cdc811b6e8f 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||||
@@ -24,37 +24,77 @@ public class PathFinder {
|
@@ -24,37 +24,82 @@ public class PathFinder {
|
||||||
public final NodeEvaluator nodeEvaluator;
|
public final NodeEvaluator nodeEvaluator;
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
private final BinaryHeap openSet = new BinaryHeap();
|
private final BinaryHeap openSet = new BinaryHeap();
|
||||||
@@ -1207,11 +1203,7 @@ index d23481453717f715124156b5d83f6448f720d049..d4cc2a5f99f8445be9a63c279e28032f
|
|||||||
+ Node node = nodeEvaluator.getStart();
|
+ Node node = nodeEvaluator.getStart();
|
||||||
+ // Kaiiju end
|
+ // Kaiiju end
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
+ // Kaiiju start - petal - handle nodeEvaluatorGenerator
|
+ dev.kaiijumc.kaiiju.path.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); // Kaiiju - petal - handle nodeEvaluatorGenerator
|
||||||
+ if (this.nodeEvaluatorGenerator != null) {
|
|
||||||
+ dev.kaiijumc.kaiiju.path.NodeEvaluatorCache.returnNodeEvaluator(nodeEvaluator);
|
|
||||||
+ }
|
|
||||||
+ // Kaiiju end
|
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
// Paper start - remove streams - and optimize collection
|
// Paper start - remove streams - and optimize collection
|
||||||
@@ -1227,13 +1219,22 @@ index d23481453717f715124156b5d83f6448f720d049..d4cc2a5f99f8445be9a63c279e28032f
|
|||||||
+ // Kaiiju start - petal - async path processing
|
+ // Kaiiju start - petal - async path processing
|
||||||
+ if (this.nodeEvaluatorGenerator == null) {
|
+ if (this.nodeEvaluatorGenerator == null) {
|
||||||
+ // run sync :(
|
+ // run sync :(
|
||||||
+ return this.findPath(nodeEvaluator, world.getProfiler(), node, map, followRange, distance, rangeMultiplier);
|
+ dev.kaiijumc.kaiiju.path.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator);
|
||||||
|
+ return this.findPath(world.getProfiler(), node, map, followRange, distance, rangeMultiplier);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ if (mob != null && mob.hasCustomName() && mob.getCustomName().getString().contains("1o")) org.bukkit.Bukkit.getLogger().info("Positions " + positions);
|
||||||
+ return new dev.kaiijumc.kaiiju.path.AsyncPath(Lists.newArrayList(), positions, () -> {
|
+ return new dev.kaiijumc.kaiiju.path.AsyncPath(Lists.newArrayList(), positions, () -> {
|
||||||
+ try {
|
+ try {
|
||||||
+ return this.processPath(nodeEvaluator, node, map, followRange, distance, rangeMultiplier);
|
+ Path path = this.processPath(nodeEvaluator, node, map, followRange, distance, rangeMultiplier);
|
||||||
|
+ if (mob != null && mob.hasCustomName() && mob.getCustomName().getString().contains("1o")) org.bukkit.Bukkit.getLogger().info("path " + path);
|
||||||
|
+ return path;
|
||||||
|
+ } catch (Exception e) {
|
||||||
|
+ if (mob != null && mob.hasCustomName() && mob.getCustomName().getString().contains("1o")) org.bukkit.Bukkit.getLogger().info("error path: " + e);
|
||||||
|
+ e.printStackTrace();
|
||||||
|
+ return null;
|
||||||
+ } finally {
|
+ } finally {
|
||||||
|
+ if (mob != null && mob.hasCustomName() && mob.getCustomName().getString().contains("1o")) org.bukkit.Bukkit.getLogger().info("NE " + nodeEvaluator);
|
||||||
+ nodeEvaluator.done();
|
+ nodeEvaluator.done();
|
||||||
+ dev.kaiijumc.kaiiju.path.NodeEvaluatorCache.returnNodeEvaluator(nodeEvaluator);
|
+ dev.kaiijumc.kaiiju.path.NodeEvaluatorCache.returnNodeEvaluator(nodeEvaluator);
|
||||||
+ }
|
+ }
|
||||||
@@ -1245,24 +1246,23 @@ index d23481453717f715124156b5d83f6448f720d049..d4cc2a5f99f8445be9a63c279e28032f
|
|||||||
- @Nullable
|
- @Nullable
|
||||||
+ //@Nullable // Kaiiju - Always not null
|
+ //@Nullable // Kaiiju - Always not null
|
||||||
// Paper start - optimize collection
|
// Paper start - optimize collection
|
||||||
- private Path findPath(ProfilerFiller profiler, Node startNode, List<Map.Entry<Target, BlockPos>> positions, float followRange, int distance, float rangeMultiplier) {
|
private Path findPath(ProfilerFiller profiler, Node startNode, List<Map.Entry<Target, BlockPos>> positions, float followRange, int distance, float rangeMultiplier) {
|
||||||
+ private Path findPath(NodeEvaluator nodeEvaluator, ProfilerFiller profiler, Node startNode, List<Map.Entry<Target, BlockPos>> positions, float followRange, int distance, float rangeMultiplier) {
|
|
||||||
profiler.push("find_path");
|
profiler.push("find_path");
|
||||||
profiler.markForCharting(MetricCategory.PATH_FINDING);
|
profiler.markForCharting(MetricCategory.PATH_FINDING);
|
||||||
+ // Kaiiju start - petal - split pathfinding into the original sync method for compat and processing for delaying
|
+ // Kaiiju start - petal - split pathfinding into the original sync method for compat and processing for delaying
|
||||||
+ try {
|
+ try {
|
||||||
+ return this.processPath(this.nodeEvaluator, startNode, positions, followRange, distance, rangeMultiplier);
|
+ return this.processPath(this.nodeEvaluator, startNode, positions, followRange, distance, rangeMultiplier);
|
||||||
+ } finally {
|
+ } finally {
|
||||||
+ nodeEvaluator.done();
|
+ this.nodeEvaluator.done();
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ private synchronized Path processPath(NodeEvaluator nodeEvaluator, Node startNode, List<Map.Entry<Target, BlockPos>> positions, float followRange, int distance, float rangeMultiplier) { // sync to only use the caching functions in this class on a single thread
|
+ private synchronized @org.jetbrains.annotations.NotNull Path processPath(NodeEvaluator nodeEvaluator, Node startNode, List<Map.Entry<Target, BlockPos>> 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
|
+ 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
|
+ // Kaiiju end
|
||||||
// Set<Target> set = positions.keySet();
|
// Set<Target> set = positions.keySet();
|
||||||
startNode.g = 0.0F;
|
startNode.g = 0.0F;
|
||||||
startNode.h = this.getBestH(startNode, positions); // Paper - optimize collection
|
startNode.h = this.getBestH(startNode, positions); // Paper - optimize collection
|
||||||
@@ -91,7 +131,7 @@ public class PathFinder {
|
@@ -91,7 +136,7 @@ public class PathFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(node.distanceTo(startNode) >= followRange)) {
|
if (!(node.distanceTo(startNode) >= followRange)) {
|
||||||
@@ -1271,6 +1271,14 @@ index d23481453717f715124156b5d83f6448f720d049..d4cc2a5f99f8445be9a63c279e28032f
|
|||||||
|
|
||||||
for(int l = 0; l < k; ++l) {
|
for(int l = 0; l < k; ++l) {
|
||||||
Node node2 = this.neighbors[l];
|
Node node2 = this.neighbors[l];
|
||||||
|
@@ -123,6 +168,7 @@ public class PathFinder {
|
||||||
|
if (best == null || comparator.compare(path, best) < 0)
|
||||||
|
best = path;
|
||||||
|
}
|
||||||
|
+ //noinspection ConstantConditions // Kaiiju - petal - ignore this warning, we know that the above loop always runs at least once since positions is not empty
|
||||||
|
return best;
|
||||||
|
// Paper end
|
||||||
|
}
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
|
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
|
index 0e2b14e7dfedf209d63279c81723fd7955122d78..079b278e2e262af433bb5bd0c12b3d8db4fa12fc 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
|
||||||
|
|||||||
Reference in New Issue
Block a user