254 lines
12 KiB
Diff
254 lines
12 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
|
Date: Mon, 6 Apr 2020 17:53:29 -0700
|
|
Subject: [PATCH] Remove streams from Mob AI System
|
|
|
|
The streams hurt performance and allocate tons of garbage, so
|
|
replace them with the standard iterator.
|
|
|
|
Also optimise the stream.anyMatch statement to move to a bitset
|
|
where we can replace the call with a single bitwise operation.
|
|
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoal.java
|
|
index b505c23c57a4b84faf5906c6295455b4720c4426..5c32cbe81c47fcb9ae347faa6fc007c5d28d79bf 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoal.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoal.java
|
|
@@ -1,10 +1,12 @@
|
|
package net.minecraft.world.entity.ai.goal;
|
|
|
|
+import com.destroystokyo.paper.util.set.OptimizedSmallEnumSet; // Paper - remove streams from pathfindergoalselector
|
|
import java.util.EnumSet;
|
|
|
|
public abstract class PathfinderGoal {
|
|
|
|
- private final EnumSet<PathfinderGoal.Type> a = EnumSet.noneOf(PathfinderGoal.Type.class);
|
|
+ private final EnumSet<PathfinderGoal.Type> a = EnumSet.noneOf(PathfinderGoal.Type.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
|
|
+ private final OptimizedSmallEnumSet<Type> goalTypes = new OptimizedSmallEnumSet<>(PathfinderGoal.Type.class); // Paper - remove streams from pathfindergoalselector
|
|
|
|
public PathfinderGoal() {}
|
|
|
|
@@ -28,16 +30,20 @@ public abstract class PathfinderGoal {
|
|
public void e() {}
|
|
|
|
public void a(EnumSet<PathfinderGoal.Type> enumset) {
|
|
- this.a.clear();
|
|
- this.a.addAll(enumset);
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ this.goalTypes.clear();
|
|
+ this.goalTypes.addAllUnchecked(enumset);
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
}
|
|
|
|
public String toString() {
|
|
return this.getClass().getSimpleName();
|
|
}
|
|
|
|
- public EnumSet<PathfinderGoal.Type> i() {
|
|
- return this.a;
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<PathfinderGoal.Type> getGoalTypes() {
|
|
+ return this.goalTypes;
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
}
|
|
|
|
public static enum Type {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalSelector.java
|
|
index 8c234c09a4d9ada83e36e3cdbcc1f2f5c6202f28..385cd079e264a7e66e91ab3b70b90afb59688dcd 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalSelector.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalSelector.java
|
|
@@ -1,8 +1,10 @@
|
|
package net.minecraft.world.entity.ai.goal;
|
|
|
|
+import com.destroystokyo.paper.util.set.OptimizedSmallEnumSet; // Paper - remove streams from pathfindergoalselector
|
|
import com.google.common.collect.Sets;
|
|
import java.util.EnumMap;
|
|
import java.util.EnumSet;
|
|
+import java.util.Iterator; // Paper - remove streams from pathfindergoalselector
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.function.Supplier;
|
|
@@ -28,7 +30,8 @@ public class PathfinderGoalSelector {
|
|
private final Map<PathfinderGoal.Type, PathfinderGoalWrapped> c = new EnumMap(PathfinderGoal.Type.class);
|
|
private final Set<PathfinderGoalWrapped> d = Sets.newLinkedHashSet(); private Set<PathfinderGoalWrapped> getTasks() { return d; }// Paper - OBFHELPER
|
|
private final Supplier<GameProfilerFiller> e;
|
|
- private final EnumSet<PathfinderGoal.Type> f = EnumSet.noneOf(PathfinderGoal.Type.class);
|
|
+ private final EnumSet<PathfinderGoal.Type> f = EnumSet.noneOf(PathfinderGoal.Type.class); // Paper unused, but dummy to prevent plugins from crashing as hard. Theyll need to support paper in a special case if this is super important, but really doesn't seem like it would be.
|
|
+ private final OptimizedSmallEnumSet<PathfinderGoal.Type> goalTypes = new OptimizedSmallEnumSet<>(PathfinderGoal.Type.class); // Paper - remove streams from pathfindergoalselector
|
|
private int g = 3;private int getTickRate() { return g; } // Paper - OBFHELPER
|
|
private int curRate;private int getCurRate() { return curRate; } private void incRate() { this.curRate++; } // Paper TODO
|
|
|
|
@@ -56,35 +59,38 @@ public class PathfinderGoalSelector {
|
|
// Paper end
|
|
|
|
public void a(PathfinderGoal pathfindergoal) {
|
|
- this.d.stream().filter((pathfindergoalwrapped) -> {
|
|
- return pathfindergoalwrapped.j() == pathfindergoal;
|
|
- }).filter(PathfinderGoalWrapped::g).forEach(PathfinderGoalWrapped::d);
|
|
- this.d.removeIf((pathfindergoalwrapped) -> {
|
|
- return pathfindergoalwrapped.j() == pathfindergoal;
|
|
- });
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ for (Iterator<PathfinderGoalWrapped> iterator = this.d.iterator(); iterator.hasNext();) {
|
|
+ PathfinderGoalWrapped goalWrapped = iterator.next();
|
|
+ if (goalWrapped.j() != pathfindergoal) {
|
|
+ continue;
|
|
+ }
|
|
+ if (goalWrapped.g()) {
|
|
+ goalWrapped.d();
|
|
+ }
|
|
+ iterator.remove();
|
|
+ }
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
}
|
|
|
|
+ private static final PathfinderGoal.Type[] PATHFINDER_GOAL_TYPES = PathfinderGoal.Type.values(); // Paper - remove streams from pathfindergoalselector
|
|
+
|
|
public void doTick() {
|
|
GameProfilerFiller gameprofilerfiller = (GameProfilerFiller) this.e.get();
|
|
|
|
gameprofilerfiller.enter("goalCleanup");
|
|
- this.d().filter((pathfindergoalwrapped) -> {
|
|
- boolean flag;
|
|
-
|
|
- if (pathfindergoalwrapped.g()) {
|
|
- Stream stream = pathfindergoalwrapped.i().stream();
|
|
- EnumSet enumset = this.f;
|
|
-
|
|
- this.f.getClass();
|
|
- if (!stream.anyMatch(enumset::contains) && pathfindergoalwrapped.b()) {
|
|
- flag = false;
|
|
- return flag;
|
|
- }
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ for (Iterator<PathfinderGoalWrapped> iterator = this.d.iterator(); iterator.hasNext();) {
|
|
+ PathfinderGoalWrapped wrappedGoal = iterator.next();
|
|
+ if (!wrappedGoal.g()) {
|
|
+ continue;
|
|
}
|
|
-
|
|
- flag = true;
|
|
- return flag;
|
|
- }).forEach(PathfinderGoal::d);
|
|
+ if (!this.goalTypes.hasCommonElements(wrappedGoal.getGoalTypes()) && wrappedGoal.b()) {
|
|
+ continue;
|
|
+ }
|
|
+ wrappedGoal.d();
|
|
+ }
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
this.c.forEach((pathfindergoal_type, pathfindergoalwrapped) -> {
|
|
if (!pathfindergoalwrapped.g()) {
|
|
this.c.remove(pathfindergoal_type);
|
|
@@ -93,30 +99,58 @@ public class PathfinderGoalSelector {
|
|
});
|
|
gameprofilerfiller.exit();
|
|
gameprofilerfiller.enter("goalUpdate");
|
|
- this.d.stream().filter((pathfindergoalwrapped) -> {
|
|
- return !pathfindergoalwrapped.g();
|
|
- }).filter((pathfindergoalwrapped) -> {
|
|
- Stream stream = pathfindergoalwrapped.i().stream();
|
|
- EnumSet enumset = this.f;
|
|
-
|
|
- this.f.getClass();
|
|
- return stream.noneMatch(enumset::contains);
|
|
- }).filter((pathfindergoalwrapped) -> {
|
|
- return pathfindergoalwrapped.i().stream().allMatch((pathfindergoal_type) -> {
|
|
- return ((PathfinderGoalWrapped) this.c.getOrDefault(pathfindergoal_type, PathfinderGoalSelector.b)).a(pathfindergoalwrapped);
|
|
- });
|
|
- }).filter(PathfinderGoalWrapped::a).forEach((pathfindergoalwrapped) -> {
|
|
- pathfindergoalwrapped.i().forEach((pathfindergoal_type) -> {
|
|
- PathfinderGoalWrapped pathfindergoalwrapped1 = (PathfinderGoalWrapped) this.c.getOrDefault(pathfindergoal_type, PathfinderGoalSelector.b);
|
|
-
|
|
- pathfindergoalwrapped1.d();
|
|
- this.c.put(pathfindergoal_type, pathfindergoalwrapped);
|
|
- });
|
|
- pathfindergoalwrapped.c();
|
|
- });
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ goal_update_loop: for (Iterator<PathfinderGoalWrapped> iterator = this.d.iterator(); iterator.hasNext();) {
|
|
+ PathfinderGoalWrapped wrappedGoal = iterator.next();
|
|
+ if (wrappedGoal.g()) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ OptimizedSmallEnumSet<PathfinderGoal.Type> wrappedGoalSet = wrappedGoal.getGoalTypes();
|
|
+
|
|
+ if (this.goalTypes.hasCommonElements(wrappedGoalSet)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ long iterator1 = wrappedGoalSet.getBackingSet();
|
|
+ int wrappedGoalSize = wrappedGoalSet.size();
|
|
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
|
+ PathfinderGoal.Type type = PATHFINDER_GOAL_TYPES[Long.numberOfTrailingZeros(iterator1)];
|
|
+ iterator1 ^= com.destroystokyo.paper.util.math.IntegerUtil.getTrailingBit(iterator1);
|
|
+ PathfinderGoalWrapped wrapped = this.c.getOrDefault(type, PathfinderGoalSelector.b);
|
|
+ if (!wrapped.a(wrappedGoal)) {
|
|
+ continue goal_update_loop;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!wrappedGoal.a()) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ iterator1 = wrappedGoalSet.getBackingSet();
|
|
+ wrappedGoalSize = wrappedGoalSet.size();
|
|
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
|
+ PathfinderGoal.Type type = PATHFINDER_GOAL_TYPES[Long.numberOfTrailingZeros(iterator1)];
|
|
+ iterator1 ^= com.destroystokyo.paper.util.math.IntegerUtil.getTrailingBit(iterator1);
|
|
+ PathfinderGoalWrapped wrapped = this.c.getOrDefault(type, PathfinderGoalSelector.b);
|
|
+
|
|
+ wrapped.d();
|
|
+ this.c.put(type, wrappedGoal);
|
|
+ }
|
|
+
|
|
+ wrappedGoal.c();
|
|
+ }
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
gameprofilerfiller.exit();
|
|
gameprofilerfiller.enter("goalTick");
|
|
- this.d().forEach(PathfinderGoalWrapped::e);
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ for (Iterator<PathfinderGoalWrapped> iterator = this.d.iterator(); iterator.hasNext();) {
|
|
+ PathfinderGoalWrapped wrappedGoal = iterator.next();
|
|
+ if (wrappedGoal.g()) {
|
|
+ wrappedGoal.e();
|
|
+ }
|
|
+ }
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
gameprofilerfiller.exit();
|
|
}
|
|
|
|
@@ -125,11 +159,11 @@ public class PathfinderGoalSelector {
|
|
}
|
|
|
|
public void a(PathfinderGoal.Type pathfindergoal_type) {
|
|
- this.f.add(pathfindergoal_type);
|
|
+ this.goalTypes.addUnchecked(pathfindergoal_type); // Paper - remove streams from pathfindergoalselector
|
|
}
|
|
|
|
public void b(PathfinderGoal.Type pathfindergoal_type) {
|
|
- this.f.remove(pathfindergoal_type);
|
|
+ this.goalTypes.removeUnchecked(pathfindergoal_type); // Paper - remove streams from pathfindergoalselector
|
|
}
|
|
|
|
public void a(PathfinderGoal.Type pathfindergoal_type, boolean flag) {
|
|
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalWrapped.java b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalWrapped.java
|
|
index 7bb531e47668cf445083c4dedb03ccafe6a9c96b..8c8e39d35fb56aa6cf7d456adab01dff5d13a60d 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalWrapped.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/PathfinderGoalWrapped.java
|
|
@@ -59,9 +59,10 @@ public class PathfinderGoalWrapped extends PathfinderGoal {
|
|
this.a.a(enumset);
|
|
}
|
|
|
|
- @Override
|
|
- public EnumSet<PathfinderGoal.Type> i() {
|
|
- return this.a.i();
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<PathfinderGoal.Type> getGoalTypes() {
|
|
+ return this.a.getGoalTypes();
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
}
|
|
|
|
public boolean isRunning() { return this.g(); } // Paper - OBFHELPER
|