From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: BuildTools 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 pathTypeByPosCache = new Long2ObjectOpenHashMap<>(); + private final Long2ObjectMap 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 nodes = new Int2ObjectOpenHashMap<>(); + protected final Int2ObjectMap 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 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 = 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 pathTypesByPosCache = new Long2ObjectOpenHashMap<>(); + private final Long2ObjectMap 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 pathTypesByPosCache = new Long2ObjectOpenHashMap<>(); - private final Object2BooleanMap collisionCache = new Object2BooleanOpenHashMap<>(); + private final Long2ObjectMap pathTypesByPosCache = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); + private final Object2BooleanMap collisionCache = Object2BooleanMaps.synchronize(new Object2BooleanOpenHashMap<>()); @Override public void prepare(PathNavigationRegion cachedWorld, Mob entity) {