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 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 5784be69098805e4d550a0923ac8daa5aada73f9..76e19f3a4ae988f6f3b59763d639fa5e084fa0bf 100644 --- a/src/main/java/net/minecraft/world/level/pathfinder/Pathfinder.java +++ b/src/main/java/net/minecraft/world/level/pathfinder/Pathfinder.java @@ -33,9 +33,12 @@ public class Pathfinder { this.d.a(); this.c.a(chunkcache, entityinsentient); PathPoint pathpoint = this.c.b(); - Map map = (Map) set.stream().collect(Collectors.toMap((blockposition) -> { - return this.c.a((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ()); - }, Function.identity())); + // Paper start - remove streams - and optimize collection + List> map = Lists.newArrayList(); + for (BlockPosition blockposition : set) { + map.add(new java.util.AbstractMap.SimpleEntry<>(this.c.a((double) blockposition.getX(), blockposition.getY(), blockposition.getZ()), blockposition)); + } + // Paper end PathEntity pathentity = this.a(pathpoint, map, f, i, f1); this.c.a(); @@ -43,17 +46,17 @@ public class Pathfinder { } @Nullable - private PathEntity a(PathPoint pathpoint, Map map, float f, int i, float f1) { - Set set = map.keySet(); + private PathEntity a(PathPoint pathpoint, List> list, float f, int i, float f1) { // Paper - optimize collection + //Set set = map.keySet(); // Paper pathpoint.e = 0.0F; - pathpoint.f = this.a(pathpoint, set); + pathpoint.f = this.a(pathpoint, list); // Paper - optimize collection pathpoint.g = pathpoint.f; this.d.a(); this.d.a(pathpoint); Set set1 = ImmutableSet.of(); int j = 0; - Set set2 = Sets.newHashSetWithExpectedSize(set.size()); + List> set2 = Lists.newArrayListWithExpectedSize(list.size()); // Paper - optimize collection int k = (int) ((float) this.b * f1); while (!this.d.e()) { @@ -65,14 +68,15 @@ public class Pathfinder { PathPoint pathpoint1 = this.d.c(); pathpoint1.i = true; - Iterator iterator = set.iterator(); - - while (iterator.hasNext()) { - PathDestination pathdestination = (PathDestination) iterator.next(); + // Paper start - optimize collection + for (int i1 = 0; i1 < list.size(); i1++) { + Map.Entry entry = list.get(i1); + PathDestination pathdestination = entry.getKey(); if (pathpoint1.c((PathPoint) pathdestination) <= (float) i) { pathdestination.e(); - set2.add(pathdestination); + set2.add(entry); + // Paper end } } @@ -93,7 +97,7 @@ public class Pathfinder { if (pathpoint2.j < f && (!pathpoint2.c() || f3 < pathpoint2.e)) { pathpoint2.h = pathpoint1; pathpoint2.e = f3; - pathpoint2.f = this.a(pathpoint2, set) * 1.5F; + pathpoint2.f = this.a(pathpoint2, list) * 1.5F; // Paper - list instead of set if (pathpoint2.c()) { this.d.a(pathpoint2, pathpoint2.e + pathpoint2.f); } else { @@ -105,28 +109,29 @@ public class Pathfinder { } } - Optional optional = !set2.isEmpty() ? set2.stream().map((pathdestination1) -> { - return this.a(pathdestination1.d(), (BlockPosition) map.get(pathdestination1), true); - }).min(Comparator.comparingInt(PathEntity::e)) : set.stream().map((pathdestination1) -> { - return this.a(pathdestination1.d(), (BlockPosition) map.get(pathdestination1), false); - }).min(Comparator.comparingDouble(PathEntity::n).thenComparingInt(PathEntity::e)); - - if (!optional.isPresent()) { - return null; - } else { - PathEntity pathentity = (PathEntity) optional.get(); - - return pathentity; + // Paper start - remove streams - and optimize collection + PathEntity best = null; + boolean useSet1 = set2.isEmpty(); + Comparator comparator = useSet1 ? Comparator.comparingInt(PathEntity::e) + : Comparator.comparingDouble(PathEntity::n).thenComparingInt(PathEntity::e); + for (Map.Entry entry : useSet1 ? list : set2) { + PathEntity pathEntity = this.a(entry.getKey().d(), entry.getValue(), !useSet1); + if (best == null || comparator.compare(pathEntity, best) < 0) + best = pathEntity; } + return best; + // Paper end } - private float a(PathPoint pathpoint, Set set) { + private float a(PathPoint pathpoint, List> list) { // Paper - optimize collection float f = Float.MAX_VALUE; float f1; - for (Iterator iterator = set.iterator(); iterator.hasNext(); f = Math.min(f1, f)) { - PathDestination pathdestination = (PathDestination) iterator.next(); + // Paper start - optimize collection + for (int i = 0, listSize = list.size(); i < listSize; f = Math.min(f1, f), i++) { // Paper + PathDestination pathdestination = list.get(i).getKey(); // Paper + // Paper end f1 = pathpoint.a(pathdestination); pathdestination.a(f1, pathpoint);