mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-22 00:19:20 +00:00
273 lines
12 KiB
Diff
273 lines
12 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: BuildTools <unconfigured@null.spigotmc.org>
|
|
Date: Wed, 4 Jan 2023 15:19:31 +0800
|
|
Subject: [PATCH] Hearse: Pathfinding Fixes
|
|
|
|
Original license:
|
|
Original project: https://github.com/NaturalCodeClub/Hearse
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java b/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
|
|
index 27b9cefc172b391824ead382a712b8b9b1ddfe45..c949325dc9b21d8a75ee639210911c61616949c8 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/BinaryHeap.java
|
|
@@ -4,10 +4,8 @@ public class BinaryHeap {
|
|
private Node[] heap = new Node[128];
|
|
private int size;
|
|
|
|
- public Node insert(Node node) {
|
|
- if (node.heapIdx >= 0) {
|
|
- throw new IllegalStateException("OW KNOWS!");
|
|
- } else {
|
|
+ public synchronized Node insert(Node node) {
|
|
+ if (node.heapIdx < 0) {
|
|
if (this.size == this.heap.length) {
|
|
Node[] nodes = new Node[this.size << 1];
|
|
System.arraycopy(this.heap, 0, nodes, 0, this.size);
|
|
@@ -17,19 +15,19 @@ public class BinaryHeap {
|
|
this.heap[this.size] = node;
|
|
node.heapIdx = this.size;
|
|
this.upHeap(this.size++);
|
|
- return node;
|
|
}
|
|
+ return node;
|
|
}
|
|
|
|
- public void clear() {
|
|
+ public synchronized void clear() {
|
|
this.size = 0;
|
|
}
|
|
|
|
- public Node peek() {
|
|
+ public synchronized Node peek() {
|
|
return this.heap[0];
|
|
}
|
|
|
|
- public Node pop() {
|
|
+ public synchronized Node pop() {
|
|
Node node = this.heap[0];
|
|
this.heap[0] = this.heap[--this.size];
|
|
this.heap[this.size] = null;
|
|
@@ -41,7 +39,7 @@ public class BinaryHeap {
|
|
return node;
|
|
}
|
|
|
|
- public void remove(Node node) {
|
|
+ public synchronized void remove(Node node) {
|
|
this.heap[node.heapIdx] = this.heap[--this.size];
|
|
this.heap[this.size] = null;
|
|
if (this.size > node.heapIdx) {
|
|
@@ -55,7 +53,7 @@ public class BinaryHeap {
|
|
node.heapIdx = -1;
|
|
}
|
|
|
|
- public void changeCost(Node node, float weight) {
|
|
+ public synchronized void changeCost(Node node, float weight) {
|
|
float f = node.f;
|
|
node.f = weight;
|
|
if (weight < f) {
|
|
@@ -66,7 +64,7 @@ public class BinaryHeap {
|
|
|
|
}
|
|
|
|
- public int size() {
|
|
+ public synchronized int size() {
|
|
return this.size;
|
|
}
|
|
|
|
@@ -135,11 +133,11 @@ public class BinaryHeap {
|
|
node.heapIdx = index;
|
|
}
|
|
|
|
- public boolean isEmpty() {
|
|
+ public synchronized boolean isEmpty() {
|
|
return this.size == 0;
|
|
}
|
|
|
|
- public Node[] getHeap() {
|
|
+ public synchronized Node[] getHeap() {
|
|
Node[] nodes = new Node[this.size()];
|
|
System.arraycopy(this.heap, 0, nodes, 0, this.size());
|
|
return nodes;
|
|
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java
|
|
index b0bae04ab5a93dd4cf1eeeb02bed1e508e1f2913..d427735eff0056c171591709829d0bb76f7bb6f3 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/FlyNodeEvaluator.java
|
|
@@ -1,6 +1,7 @@
|
|
package net.minecraft.world.level.pathfinder;
|
|
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|
import java.util.EnumSet;
|
|
import java.util.List;
|
|
@@ -15,7 +16,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.phys.AABB;
|
|
|
|
public class FlyNodeEvaluator extends WalkNodeEvaluator {
|
|
- private final Long2ObjectMap<BlockPathTypes> pathTypeByPosCache = new Long2ObjectOpenHashMap<>();
|
|
+ private final Long2ObjectMap<BlockPathTypes> pathTypeByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
|
|
private static final float SMALL_MOB_INFLATED_START_NODE_BOUNDING_BOX = 1.5F;
|
|
private static final int MAX_START_NODE_CANDIDATES = 10;
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
|
|
index a8a2594b8f5b3ebf6a1f918c7d822ad35b051b17..7de3c41e036ddb91d951cefbd2ea093918150680 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/NodeEvaluator.java
|
|
@@ -1,6 +1,7 @@
|
|
package net.minecraft.world.level.pathfinder;
|
|
|
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
+import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
|
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.util.Mth;
|
|
@@ -11,7 +12,7 @@ import net.minecraft.world.level.PathNavigationRegion;
|
|
public abstract class NodeEvaluator {
|
|
protected PathNavigationRegion level;
|
|
protected Mob mob;
|
|
- protected final Int2ObjectMap<Node> nodes = new Int2ObjectOpenHashMap<>();
|
|
+ protected final Int2ObjectMap<Node> nodes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>());
|
|
protected int entityWidth;
|
|
protected int entityHeight;
|
|
protected int entityDepth;
|
|
@@ -39,9 +40,7 @@ public abstract class NodeEvaluator {
|
|
}
|
|
|
|
protected Node getNode(int x, int y, int z) {
|
|
- return this.nodes.computeIfAbsent(Node.createHash(x, y, z), (l) -> {
|
|
- return new Node(x, y, z);
|
|
- });
|
|
+ return this.nodes.computeIfAbsent(Node.createHash(x, y, z), (l) -> new Node(x, y, z));
|
|
}
|
|
|
|
public abstract Node getStart();
|
|
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 a8af51a25b0f99c3a64d9150fdfcd6b818aa7581..919f8c1aa52aa8c468427e850d1d4764a915320f 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java
|
|
@@ -8,6 +8,8 @@ import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
+import java.util.concurrent.locks.ReadWriteLock;
|
|
+import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|
import java.util.function.Function;
|
|
import java.util.stream.Collectors;
|
|
import javax.annotation.Nullable;
|
|
@@ -20,6 +22,7 @@ import net.minecraft.world.level.PathNavigationRegion;
|
|
public class PathFinder {
|
|
private static final float FUDGING = 1.5F;
|
|
private final Node[] neighbors = new Node[32];
|
|
+ private final ReadWriteLock evaluatorLock = new ReentrantReadWriteLock();
|
|
private final int maxVisitedNodes;
|
|
public final NodeEvaluator nodeEvaluator;
|
|
private static final boolean DEBUG = false;
|
|
@@ -33,19 +36,40 @@ public class PathFinder {
|
|
@Nullable
|
|
public Path findPath(PathNavigationRegion world, Mob mob, Set<BlockPos> positions, float followRange, int distance, float rangeMultiplier) {
|
|
this.openSet.clear();
|
|
- this.nodeEvaluator.prepare(world, mob);
|
|
- Node node = this.nodeEvaluator.getStart();
|
|
+ this.evaluatorLock.writeLock().lock();
|
|
+ try {
|
|
+ this.nodeEvaluator.prepare(world, mob);
|
|
+ }finally {
|
|
+ this.evaluatorLock.writeLock().unlock();
|
|
+ }
|
|
+ Node node;
|
|
+ this.evaluatorLock.readLock().lock();
|
|
+ try{
|
|
+ node = this.nodeEvaluator.getStart();
|
|
+ }finally {
|
|
+ this.evaluatorLock.readLock().unlock();
|
|
+ }
|
|
if (node == null) {
|
|
return null;
|
|
} else {
|
|
// Paper start - remove streams - and optimize collection
|
|
List<Map.Entry<Target, BlockPos>> map = Lists.newArrayList();
|
|
- for (BlockPos pos : positions) {
|
|
- map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getGoal(pos.getX(), pos.getY(), pos.getZ()), pos));
|
|
+ this.evaluatorLock.readLock().lock();
|
|
+ try {
|
|
+ for (BlockPos pos : positions) {
|
|
+ map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getGoal(pos.getX(), pos.getY(), pos.getZ()), pos));
|
|
+ }
|
|
+ }finally {
|
|
+ this.evaluatorLock.readLock().unlock();
|
|
}
|
|
// Paper end
|
|
Path path = this.findPath(world.getProfiler(), node, map, followRange, distance, rangeMultiplier);
|
|
- this.nodeEvaluator.done();
|
|
+ this.evaluatorLock.writeLock().lock();
|
|
+ try {
|
|
+ this.nodeEvaluator.done();
|
|
+ }finally {
|
|
+ this.evaluatorLock.writeLock().unlock();;
|
|
+ }
|
|
return path;
|
|
}
|
|
}
|
|
@@ -91,7 +115,13 @@ public class PathFinder {
|
|
}
|
|
|
|
if (!(node.distanceTo(startNode) >= followRange)) {
|
|
- int k = this.nodeEvaluator.getNeighbors(this.neighbors, node);
|
|
+ int k;
|
|
+ this.evaluatorLock.readLock().lock();
|
|
+ try {
|
|
+ k = this.nodeEvaluator.getNeighbors(this.neighbors, node);
|
|
+ }finally {
|
|
+ this.evaluatorLock.readLock().unlock();
|
|
+ }
|
|
|
|
for(int l = 0; l < k; ++l) {
|
|
Node node2 = this.neighbors[l];
|
|
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 6084631b5b502279b84f190dc62fc76b770e368e..f526adbd31e65fc74af48f6137d293a7a7ceafbb 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/SwimNodeEvaluator.java
|
|
@@ -2,6 +2,7 @@ package net.minecraft.world.level.pathfinder;
|
|
|
|
import com.google.common.collect.Maps;
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|
import java.util.Map;
|
|
import javax.annotation.Nullable;
|
|
@@ -17,7 +18,7 @@ import net.minecraft.world.level.material.FluidState;
|
|
|
|
public class SwimNodeEvaluator extends NodeEvaluator {
|
|
private final boolean allowBreaching;
|
|
- private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = new Long2ObjectOpenHashMap<>();
|
|
+ private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
|
|
|
|
public SwimNodeEvaluator(boolean canJumpOutOfWater) {
|
|
this.allowBreaching = canJumpOutOfWater;
|
|
diff --git a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
|
index 894881018c659d874f28f5744f0b8247cfecb1c1..ae06f7ef9c4b8147508984f8b46176de46171285 100644
|
|
--- a/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
|
+++ b/src/main/java/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
|
|
@@ -1,8 +1,10 @@
|
|
package net.minecraft.world.level.pathfinder;
|
|
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
|
+import it.unimi.dsi.fastutil.longs.Long2ObjectMaps;
|
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
|
|
+import it.unimi.dsi.fastutil.objects.Object2BooleanMaps;
|
|
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
|
|
import java.util.EnumSet;
|
|
import javax.annotation.Nullable;
|
|
@@ -33,8 +35,8 @@ public class WalkNodeEvaluator extends NodeEvaluator {
|
|
public static final double SPACE_BETWEEN_WALL_POSTS = 0.5D;
|
|
private static final double DEFAULT_MOB_JUMP_HEIGHT = 1.125D;
|
|
protected float oldWaterCost;
|
|
- private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = new Long2ObjectOpenHashMap<>();
|
|
- private final Object2BooleanMap<AABB> collisionCache = new Object2BooleanOpenHashMap<>();
|
|
+ private final Long2ObjectMap<BlockPathTypes> pathTypesByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
|
|
+ private final Object2BooleanMap<AABB> collisionCache = Object2BooleanMaps.synchronize(new Object2BooleanOpenHashMap<>());
|
|
|
|
@Override
|
|
public void prepare(PathNavigationRegion cachedWorld, Mob entity) {
|