2021-06-11 14:02:28 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2022-09-26 10:02:51 +02:00
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
2021-06-11 14:02:28 +02:00
Date: Mon, 6 Apr 2020 17:53:29 -0700
2021-11-24 12:06:34 +01:00
Subject: [PATCH] Optimize GoalSelector Goal.Flag Set operations
2021-06-11 14:02:28 +02:00
2021-11-24 12:06:34 +01:00
Optimise the stream.anyMatch statement to move to a bitset
2021-06-11 14:02:28 +02:00
where we can replace the call with a single bitwise operation.
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
2021-11-24 12:06:34 +01:00
@@ -0,0 +0,0 @@ import java.util.EnumSet;
import net.minecraft.util.Mth;
2021-06-11 14:02:28 +02:00
public abstract class Goal {
- private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.class);
+ private final EnumSet<Goal.Flag> flags = EnumSet.noneOf(Goal.Flag.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.
2021-06-14 03:06:38 +02:00
+ private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
2021-06-11 14:02:28 +02:00
2021-06-14 03:06:38 +02:00
public abstract boolean canUse();
2021-06-11 14:02:28 +02:00
@@ -0,0 +0,0 @@ public abstract class Goal {
2021-06-14 03:06:38 +02:00
}
2021-06-11 14:02:28 +02:00
public void setFlags(EnumSet<Goal.Flag> controls) {
- this.flags.clear();
- this.flags.addAll(controls);
+ // Paper start - remove streams from pathfindergoalselector
+ this.goalTypes.clear();
+ this.goalTypes.addAllUnchecked(controls);
+ // Paper end - remove streams from pathfindergoalselector
}
2021-06-14 03:06:38 +02:00
@Override
@@ -0,0 +0,0 @@ public abstract class Goal {
2021-06-11 14:02:28 +02:00
return this.getClass().getSimpleName();
}
- public EnumSet<Goal.Flag> getFlags() {
- return this.flags;
+ // Paper start - remove streams from pathfindergoalselector
2021-09-09 19:12:22 +02:00
+ public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> getFlags() {
2021-06-11 14:02:28 +02:00
+ return this.goalTypes;
+ // Paper end - remove streams from pathfindergoalselector
}
2021-11-24 12:06:34 +01:00
protected int adjustedTickDelay(int ticks) {
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -0,0 +0,0 @@ public class GoalSelector {
2021-06-14 03:06:38 +02:00
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
2022-11-20 00:53:20 +01:00
private final Set<WrappedGoal> availableGoals = Sets.newLinkedHashSet();
2021-06-11 14:02:28 +02:00
private final Supplier<ProfilerFiller> profiler;
- private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
+ private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.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.
2021-06-14 03:06:38 +02:00
+ private final com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> goalTypes = new com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from pathfindergoalselector
private int tickCount;
private int newGoalRate = 3;
private int curRate;
2021-11-24 12:06:34 +01:00
+ private static final Goal.Flag[] GOAL_FLAG_VALUES = Goal.Flag.values(); // Paper - remove streams from pathfindergoalselector
2021-06-11 14:02:28 +02:00
2021-06-14 03:06:38 +02:00
public GoalSelector(Supplier<ProfilerFiller> profiler) {
this.profiler = profiler;
2021-06-11 14:02:28 +02:00
@@ -0,0 +0,0 @@ public class GoalSelector {
2021-06-14 03:06:38 +02:00
}
2021-06-11 14:02:28 +02:00
// Paper end
public void removeGoal(Goal goal) {
2021-06-14 03:06:38 +02:00
- this.availableGoals.stream().filter((wrappedGoal) -> {
- return wrappedGoal.getGoal() == goal;
2021-06-11 14:02:28 +02:00
- }).filter(WrappedGoal::isRunning).forEach(WrappedGoal::stop);
2021-06-14 03:06:38 +02:00
- this.availableGoals.removeIf((wrappedGoal) -> {
- return wrappedGoal.getGoal() == goal;
2021-06-11 14:02:28 +02:00
- });
2021-11-24 12:06:34 +01:00
- }
-
- private static boolean goalContainsAnyFlags(WrappedGoal goal, EnumSet<Goal.Flag> controls) {
- for(Goal.Flag flag : goal.getFlags()) {
- if (controls.contains(flag)) {
- return true;
2021-06-11 14:02:28 +02:00
+ // Paper start - remove streams from pathfindergoalselector
2021-06-14 03:06:38 +02:00
+ for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
2021-06-11 14:02:28 +02:00
+ WrappedGoal goalWrapped = iterator.next();
+ if (goalWrapped.getGoal() != goal) {
+ continue;
2021-11-30 09:36:30 +01:00
}
2021-06-11 14:02:28 +02:00
+ if (goalWrapped.isRunning()) {
+ goalWrapped.stop();
2021-11-30 09:36:30 +01:00
+ }
2021-06-11 14:02:28 +02:00
+ iterator.remove();
2021-11-24 12:06:34 +01:00
}
2021-06-11 14:02:28 +02:00
+ // Paper end - remove streams from pathfindergoalselector
2021-11-24 12:06:34 +01:00
+ }
- return false;
+ private static boolean goalContainsAnyFlags(WrappedGoal goal, com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> controls) {
+ return goal.getFlags().hasCommonElements(controls); // Paper
}
private static boolean goalCanBeReplacedForAllFlags(WrappedGoal goal, Map<Goal.Flag, WrappedGoal> goalsByControl) {
- for(Goal.Flag flag : goal.getFlags()) {
+ // Paper start
2021-11-30 09:36:30 +01:00
+ long flagIterator = goal.getFlags().getBackingSet();
+ int wrappedGoalSize = goal.getFlags().size();
+ for (int i = 0; i < wrappedGoalSize; ++i) {
+ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
+ flagIterator ^= io.papermc.paper.util.IntegerUtil.getTrailingBit(flagIterator);
+ // Paper end
2021-11-24 12:06:34 +01:00
if (!goalsByControl.getOrDefault(flag, NO_GOAL).canBeReplacedBy(goal)) {
2021-11-30 09:36:30 +01:00
return false;
2021-11-24 12:06:34 +01:00
}
@@ -0,0 +0,0 @@ public class GoalSelector {
2021-06-14 03:06:38 +02:00
profilerFiller.push("goalCleanup");
2021-11-24 12:06:34 +01:00
for(WrappedGoal wrappedGoal : this.availableGoals) {
- if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.disabledFlags) || !wrappedGoal.canContinueToUse())) {
+ if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) {
wrappedGoal.stop();
}
}
@@ -0,0 +0,0 @@ public class GoalSelector {
2021-06-14 03:06:38 +02:00
profilerFiller.push("goalUpdate");
2021-06-11 14:02:28 +02:00
2021-11-24 12:06:34 +01:00
for(WrappedGoal wrappedGoal2 : this.availableGoals) {
- if (!wrappedGoal2.isRunning() && !goalContainsAnyFlags(wrappedGoal2, this.disabledFlags) && goalCanBeReplacedForAllFlags(wrappedGoal2, this.lockedFlags) && wrappedGoal2.canUse()) {
- for(Goal.Flag flag : wrappedGoal2.getFlags()) {
+ // Paper start
+ if (!wrappedGoal2.isRunning() && !goalContainsAnyFlags(wrappedGoal2, this.goalTypes) && goalCanBeReplacedForAllFlags(wrappedGoal2, this.lockedFlags) && wrappedGoal2.canUse()) {
2021-11-30 09:36:30 +01:00
+ long flagIterator = wrappedGoal2.getFlags().getBackingSet();
+ int wrappedGoalSize = wrappedGoal2.getFlags().size();
+ for (int i = 0; i < wrappedGoalSize; ++i) {
+ final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)];
+ flagIterator ^= io.papermc.paper.util.IntegerUtil.getTrailingBit(flagIterator);
2021-11-24 12:06:34 +01:00
+ // Paper end
WrappedGoal wrappedGoal3 = this.lockedFlags.getOrDefault(flag, NO_GOAL);
wrappedGoal3.stop();
this.lockedFlags.put(flag, wrappedGoal2);
2021-06-11 14:02:28 +02:00
@@ -0,0 +0,0 @@ public class GoalSelector {
}
public void disableControlFlag(Goal.Flag control) {
- this.disabledFlags.add(control);
+ this.goalTypes.addUnchecked(control); // Paper - remove streams from pathfindergoalselector
}
public void enableControlFlag(Goal.Flag control) {
- this.disabledFlags.remove(control);
+ this.goalTypes.removeUnchecked(control); // Paper - remove streams from pathfindergoalselector
}
public void setControlFlag(Goal.Flag control, boolean enabled) {
diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
@@ -0,0 +0,0 @@ public class WrappedGoal extends Goal {
}
2021-11-24 12:06:34 +01:00
@Override
2021-06-11 14:02:28 +02:00
- public EnumSet<Goal.Flag> getFlags() {
+ // Paper start - remove streams from pathfindergoalselector
2021-09-09 19:12:22 +02:00
+ public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> getFlags() {
return this.goal.getFlags();
2021-06-11 14:02:28 +02:00
+ // Paper end - remove streams from pathfindergoalselector
}
2021-06-14 03:06:38 +02:00
public boolean isRunning() {