From e73e1393f42107c683280c1f06217208acd65b9c Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Tue, 15 Jun 2021 00:43:03 -0700 Subject: [PATCH] update Optimize Pathfinder - Remove Streams / Optimized collections --- ...der-Remove-Streams-Optimized-collect.patch | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch diff --git a/patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch b/patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch new file mode 100644 index 0000000000..9740b36521 --- /dev/null +++ b/patches/server/Optimize-Pathfinder-Remove-Streams-Optimized-collect.patch @@ -0,0 +1,130 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Tue, 4 Aug 2020 22:24:15 +0200 +Subject: [PATCH] Optimize Pathfinder - Remove Streams / Optimized collections + +1.17 Update: Please do this k thx bb +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/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java ++++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java +@@ -0,0 +0,0 @@ public class PathFinder { + this.openSet.clear(); + this.nodeEvaluator.prepare(world, mob); + Node node = this.nodeEvaluator.getStart(); +- Map map = positions.stream().collect(Collectors.toMap((blockPos) -> { +- return this.nodeEvaluator.getGoal((double)blockPos.getX(), (double)blockPos.getY(), (double)blockPos.getZ()); +- }, Function.identity())); ++ // Paper start - remove streams - and optimize collection ++ List> map = Lists.newArrayList(); ++ for (BlockPos blockPos : positions) { ++ map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getGoal(blockPos.getX(), blockPos.getY(), blockPos.getZ()), blockPos)); ++ } ++ // Paper end + Path path = this.findPath(world.getProfiler(), node, map, followRange, distance, rangeMultiplier); + this.nodeEvaluator.done(); + return path; + } + + @Nullable +- private Path findPath(ProfilerFiller profiler, Node startNode, Map positions, float followRange, int distance, float rangeMultiplier) { ++ // Paper start - optimize collection ++ private Path findPath(ProfilerFiller profiler, Node startNode, List> positions, float followRange, int distance, float rangeMultiplier) { + profiler.push("find_path"); + profiler.markForCharting(MetricCategory.PATH_FINDING); +- Set set = positions.keySet(); ++ //Set set = positions.keySet(); + startNode.g = 0.0F; +- startNode.h = this.getBestH(startNode, set); ++ startNode.h = this.getBestH(startNode, positions); // Paper - optimize collection + startNode.f = startNode.h; + this.openSet.clear(); + this.openSet.insert(startNode); +- Set set2 = ImmutableSet.of(); ++ //Set set2 = ImmutableSet.of(); // Paper - unused - diff on change + int i = 0; +- Set set3 = Sets.newHashSetWithExpectedSize(set.size()); ++ List> entryList = Lists.newArrayListWithExpectedSize(positions.size()); // Paper - optimize collection + int j = (int)((float)this.maxVisitedNodes * rangeMultiplier); + + while(!this.openSet.isEmpty()) { +@@ -0,0 +0,0 @@ public class PathFinder { + Node node = this.openSet.pop(); + node.closed = true; + +- for(Target target : set) { ++ // Paper start - optimize collection ++ for(int i1 = 0; i1 < positions.size(); i1++) { ++ final Map.Entry entry = positions.get(i1); ++ Target target = entry.getKey(); + if (node.distanceManhattan(target) <= (float)distance) { + target.setReached(); +- set3.add(target); ++ entryList.add(entry); ++ // Paper end + } + } + +- if (!set3.isEmpty()) { ++ if (!entryList.isEmpty()) { // Paper - rename variable + break; + } + +@@ -0,0 +0,0 @@ public class PathFinder { + if (node2.walkedDistance < followRange && (!node2.inOpenSet() || g < node2.g)) { + node2.cameFrom = node; + node2.g = g; +- node2.h = this.getBestH(node2, set) * 1.5F; ++ node2.h = this.getBestH(node2, positions) * 1.5F; // Paper - list instead of set + if (node2.inOpenSet()) { + this.openSet.changeCost(node2, node2.g + node2.h); + } else { +@@ -0,0 +0,0 @@ public class PathFinder { + } + } + +- Optional optional = !set3.isEmpty() ? set3.stream().map((target) -> { +- return this.reconstructPath(target.getBestNode(), positions.get(target), true); +- }).min(Comparator.comparingInt(Path::getNodeCount)) : set.stream().map((target) -> { +- return this.reconstructPath(target.getBestNode(), positions.get(target), false); +- }).min(Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount)); +- profiler.pop(); +- return !optional.isPresent() ? null : optional.get(); ++ // Paper start - remove streams - and optimize collection ++ Path best = null; ++ boolean entryListIsEmpty = entryList.isEmpty(); ++ Comparator comparator = entryListIsEmpty ? Comparator.comparingInt(Path::getNodeCount) ++ : Comparator.comparingDouble(Path::getDistToTarget).thenComparingInt(Path::getNodeCount); ++ for (Map.Entry entry : entryListIsEmpty ? positions : entryList) { ++ Path path = this.reconstructPath(entry.getKey().getBestNode(), entry.getValue(), !entryListIsEmpty); ++ if (best == null || comparator.compare(path, best) < 0) ++ best = path; ++ } ++ return best; ++ // Paper end + } + +- private float getBestH(Node node, Set targets) { ++ private float getBestH(Node node, List> targets) { // Paper - optimize collection - Set -> List> + float f = Float.MAX_VALUE; + +- for(Target target : targets) { ++ // Paper start - optimize collection ++ for (int i = 0, targetsSize = targets.size(); i < targetsSize; i++) { ++ final Target target = targets.get(i).getKey(); ++ // Paper end + float g = node.distanceTo(target); + target.updateBest(g, node); + f = Math.min(g, f);