diff options
Diffstat (limited to 'paper-server/patches/features/0015-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch')
-rw-r--r-- | paper-server/patches/features/0015-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/paper-server/patches/features/0015-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch b/paper-server/patches/features/0015-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch new file mode 100644 index 0000000000..84bcbe2f2e --- /dev/null +++ b/paper-server/patches/features/0015-Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch @@ -0,0 +1,137 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar <[email protected]> +Date: Tue, 4 Aug 2020 22:24:15 +0200 +Subject: [PATCH] Optimize Pathfinder - Remove Streams / Optimized collections + +I utilized the IDE to convert streams to non streams code, so shouldn't +be any risk of behavior change. Only did minor optimization of the +generated code set to remove unnecessary things. + +I expect us to just drop this patch on next major update and re-apply +it with the IDE again and re-apply the collections optimization. + +Optimize collection by creating a list instead of a set of the key and value. + +This lets us get faster foreach iteration, as well as avoids map lookups on +the values when needed. + +diff --git a/net/minecraft/world/level/pathfinder/PathFinder.java b/net/minecraft/world/level/pathfinder/PathFinder.java +index a6ef296f7af1f784e1f0772947a6cb3519a3bc2a..81de6c1bbef1cafd3036e736dd305fbedc8368c6 100644 +--- a/net/minecraft/world/level/pathfinder/PathFinder.java ++++ b/net/minecraft/world/level/pathfinder/PathFinder.java +@@ -43,8 +43,12 @@ public class PathFinder { + if (start == null) { + return null; + } else { +- Map<Target, BlockPos> map = targetPositions.stream() +- .collect(Collectors.toMap(pos -> this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), Function.identity())); ++ // Paper start - Perf: remove streams and optimize collection ++ List<Map.Entry<Target, BlockPos>> map = Lists.newArrayList(); ++ for (BlockPos pos : targetPositions) { ++ map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos)); ++ } ++ // Paper end - Perf: remove streams and optimize collection + Path path = this.findPath(start, map, maxRange, accuracy, searchDepthMultiplier); + this.nodeEvaluator.done(); + return path; +@@ -52,19 +56,19 @@ public class PathFinder { + } + + @Nullable +- private Path findPath(Node node, Map<Target, BlockPos> targetPositions, float maxRange, int accuracy, float searchDepthMultiplier) { ++ private Path findPath(Node node, List<Map.Entry<Target, BlockPos>> positions, float maxRange, int accuracy, float searchDepthMultiplier) { // Paper - optimize collection + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("find_path"); + profilerFiller.markForCharting(MetricCategory.PATH_FINDING); +- Set<Target> set = targetPositions.keySet(); ++ // Set<Target> set = targetPositions.keySet(); // Paper + node.g = 0.0F; +- node.h = this.getBestH(node, set); ++ node.h = this.getBestH(node, positions); // Paper - optimize collection + node.f = node.h; + this.openSet.clear(); + this.openSet.insert(node); +- Set<Node> set1 = ImmutableSet.of(); ++ // Set<Node> set1 = ImmutableSet.of(); // Paper - unused - diff on change + int i = 0; +- Set<Target> set2 = Sets.newHashSetWithExpectedSize(set.size()); ++ List<Map.Entry<Target, BlockPos>> entryList = Lists.newArrayListWithExpectedSize(positions.size()); // Paper - optimize collection + int i1 = (int)(this.maxVisitedNodes * searchDepthMultiplier); + + while (!this.openSet.isEmpty()) { +@@ -75,14 +79,18 @@ public class PathFinder { + Node node1 = this.openSet.pop(); + node1.closed = true; + +- for (Target target : set) { ++ // Paper start - optimize collection ++ for (int positionIndex = 0, size = positions.size(); positionIndex < size; positionIndex++) { ++ final Map.Entry<Target, BlockPos> entry = positions.get(positionIndex); ++ Target target = entry.getKey(); + if (node1.distanceManhattan(target) <= accuracy) { + target.setReached(); +- set2.add(target); ++ entryList.add(entry); ++ // Paper end - Perf: remove streams and optimize collection + } + } + +- if (!set2.isEmpty()) { ++ if (!entryList.isEmpty()) { // Paper - Perf: remove streams and optimize collection; rename + break; + } + +@@ -97,7 +105,7 @@ public class PathFinder { + if (node2.walkedDistance < maxRange && (!node2.inOpenSet() || f1 < node2.g)) { + node2.cameFrom = node1; + node2.g = f1; +- node2.h = this.getBestH(node2, set) * 1.5F; ++ node2.h = this.getBestH(node2, positions) * 1.5F; // Paper - Perf: remove streams and optimize collection + if (node2.inOpenSet()) { + this.openSet.changeCost(node2, node2.g + node2.h); + } else { +@@ -109,25 +117,34 @@ public class PathFinder { + } + } + +- Optional<Path> optional = !set2.isEmpty() +- ? set2.stream() +- .map(pathfinder -> this.reconstructPath(pathfinder.getBestNode(), targetPositions.get(pathfinder), true)) +- .min(Comparator.comparingInt(Path::getNodeCount)) +- : set.stream() +- .map(pathfinder -> this.reconstructPath(pathfinder.getBestNode(), targetPositions.get(pathfinder), false)) +- .min(Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount)); ++ // Paper start - Perf: remove streams and optimize collection ++ Path best = null; ++ boolean entryListIsEmpty = entryList.isEmpty(); ++ Comparator<Path> comparator = entryListIsEmpty ++ ? Comparator.comparingInt(Path::getNodeCount) ++ : Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount); ++ for (Map.Entry<Target, BlockPos> entry : entryListIsEmpty ? positions : entryList) { ++ Path path = this.reconstructPath(entry.getKey().getBestNode(), entry.getValue(), !entryListIsEmpty); ++ if (best == null || comparator.compare(path, best) < 0) { ++ best = path; ++ } ++ } + profilerFiller.pop(); +- return optional.isEmpty() ? null : optional.get(); ++ return best; ++ // Paper end - Perf: remove streams and optimize collection + } + + protected float distance(Node first, Node second) { + return first.distanceTo(second); + } + +- private float getBestH(Node node, Set<Target> targets) { ++ private float getBestH(Node node, List<Map.Entry<Target, BlockPos>> targets) { // Paper - Perf: remove streams and optimize collection; Set<Target> -> List<Map.Entry<Target, BlockPos>> + float f = Float.MAX_VALUE; + +- for (Target target : targets) { ++ // Paper start - Perf: remove streams and optimize collection ++ for (int i = 0, targetsSize = targets.size(); i < targetsSize; i++) { ++ final Target target = targets.get(i).getKey(); ++ // Paper end - Perf: remove streams and optimize collection + float f1 = node.distanceTo(target); + target.updateBest(f1, node); + f = Math.min(f1, f); |