diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorCache.java b/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorCache.java index 93b1d1fb9..074a864eb 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorCache.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorCache.java @@ -1,28 +1,31 @@ package org.dreeam.leaf.async.path; -import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.world.level.pathfinder.BinaryHeap; +import net.minecraft.world.level.pathfinder.Node; import net.minecraft.world.level.pathfinder.NodeEvaluator; import org.apache.commons.lang3.Validate; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ConcurrentHashMap; +import java.util.ArrayDeque; -public class NodeEvaluatorCache { +public final class NodeEvaluatorCache { - private static final Map> threadLocalNodeEvaluators = new ConcurrentHashMap<>(); - private static final Map nodeEvaluatorToGenerator = new ConcurrentHashMap<>(); + private static final Int2ObjectOpenHashMap> nodeEvaluators = new Int2ObjectOpenHashMap<>(); + private static final Object2ObjectOpenHashMap nodeEvaluatorToGenerator = new Object2ObjectOpenHashMap<>(); - private static Queue getQueueForFeatures(NodeEvaluatorFeatures nodeEvaluatorFeatures) { - return threadLocalNodeEvaluators.computeIfAbsent(nodeEvaluatorFeatures, key -> new MultiThreadedQueue<>()); + public static final ThreadLocal HEAP_LOCAL = ThreadLocal.withInitial(BinaryHeap::new); + public static final ThreadLocal NEIGHBORS_LOCAL = ThreadLocal.withInitial(() -> new Node[32]); + + private NodeEvaluatorCache() { } - public static NodeEvaluator takeNodeEvaluator(NodeEvaluatorGenerator generator, NodeEvaluator localNodeEvaluator) { - final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(localNodeEvaluator); - NodeEvaluator nodeEvaluator = getQueueForFeatures(nodeEvaluatorFeatures).poll(); + public static synchronized NodeEvaluator takeNodeEvaluator(NodeEvaluatorGenerator generator, NodeEvaluator localNodeEvaluator) { + final int nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(localNodeEvaluator); + NodeEvaluator nodeEvaluator = nodeEvaluators.computeIfAbsent(nodeEvaluatorFeatures, key -> new ArrayDeque<>()).poll(); if (nodeEvaluator == null) { - nodeEvaluator = generator.generate(nodeEvaluatorFeatures); + nodeEvaluator = generator.generate(NodeEvaluatorFeatures.unpack(nodeEvaluatorFeatures)); } nodeEvaluatorToGenerator.put(nodeEvaluator, generator); @@ -30,15 +33,15 @@ public static NodeEvaluator takeNodeEvaluator(NodeEvaluatorGenerator generator, return nodeEvaluator; } - public static void returnNodeEvaluator(NodeEvaluator nodeEvaluator) { + public static synchronized void returnNodeEvaluator(final NodeEvaluator nodeEvaluator) { final NodeEvaluatorGenerator generator = nodeEvaluatorToGenerator.remove(nodeEvaluator); Validate.notNull(generator, "NodeEvaluator already returned"); - final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(nodeEvaluator); - getQueueForFeatures(nodeEvaluatorFeatures).offer(nodeEvaluator); + final int feature = NodeEvaluatorFeatures.fromNodeEvaluator(nodeEvaluator); + nodeEvaluators.computeIfAbsent(feature, key -> new ArrayDeque<>()).offer(nodeEvaluator); } - public static void removeNodeEvaluator(NodeEvaluator nodeEvaluator) { + public static synchronized void removeNodeEvaluator(final NodeEvaluator nodeEvaluator) { nodeEvaluatorToGenerator.remove(nodeEvaluator); } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorFeatures.java b/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorFeatures.java index c985d3574..b01f980d0 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorFeatures.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorFeatures.java @@ -11,13 +11,52 @@ public record NodeEvaluatorFeatures( boolean canOpenDoors, boolean allowBreaching ) { - public static NodeEvaluatorFeatures fromNodeEvaluator(NodeEvaluator nodeEvaluator) { + + private static final NodeEvaluatorType[] NODE_EVALUATOR_TYPES = NodeEvaluatorType.values(); + + public static int 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 pack(type, canPassDoors, canFloat, canWalkOverFences, canOpenDoors, allowBreaching); + } + + public static int pack(NodeEvaluatorType type, + boolean canPassDoors, + boolean canFloat, + boolean canWalkOverFences, + boolean canOpenDoors, + boolean allowBreaching) { + int value = 0; + value |= type.ordinal(); + if (canPassDoors) { + value |= 0b100; + } + if (canFloat) { + value |= 0b1000; + } + if (canWalkOverFences) { + value |= 0b10000; + } + if (canOpenDoors) { + value |= 0b100000; + } + if (allowBreaching) { + value |= 0b1000000; + } + return value; + } + + public static NodeEvaluatorFeatures unpack(int value) { + NodeEvaluatorType type = NODE_EVALUATOR_TYPES[value & 0b11]; + boolean canPassDoors = (value & 0b100) != 0; + boolean canFloat = (value & 0b1000) != 0; + boolean canWalkOverFences = (value & 0b10000) != 0; + boolean canOpenDoors = (value & 0b100000) != 0; + boolean allowBreaching = (value & 0b1000000) != 0; return new NodeEvaluatorFeatures(type, canPassDoors, canFloat, canWalkOverFences, canOpenDoors, allowBreaching); } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorType.java b/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorType.java index c94f4c8bf..03e5beea0 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorType.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/async/path/NodeEvaluatorType.java @@ -12,9 +12,11 @@ public enum NodeEvaluatorType { 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; + return switch (nodeEvaluator) { + case SwimNodeEvaluator ignored -> SWIM; + case FlyNodeEvaluator ignored -> FLY; + case AmphibiousNodeEvaluator ignored -> AMPHIBIOUS; + default -> WALK; + }; } }