225 lines
11 KiB
Diff
225 lines
11 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/Goal.java b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
|
|
index d92ddc8a4c0f5249b7ff4f97af1ea3db413b2983..8c2ec30a35e86f2b30863045b586a67e485c624b 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
|
|
@@ -3,7 +3,8 @@ package net.minecraft.world.entity.ai.goal;
|
|
import java.util.EnumSet;
|
|
|
|
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.
|
|
+ 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
|
|
|
|
public abstract boolean canUse();
|
|
|
|
@@ -25,8 +26,10 @@ public abstract class Goal {
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
@Override
|
|
@@ -34,8 +37,10 @@ public abstract class Goal {
|
|
return this.getClass().getSimpleName();
|
|
}
|
|
|
|
- public EnumSet<Goal.Flag> getFlags() {
|
|
- return this.flags;
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> getGoalTypes() {
|
|
+ return this.goalTypes;
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
}
|
|
|
|
public static enum Flag {
|
|
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 69bf112655615337e0df3ea56b9e42fa5ff70430..faa53d08a12cc7441c670cae6d301de3f498ffe7 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
|
|
@@ -28,10 +28,12 @@ public class GoalSelector {
|
|
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
|
|
public final Set<WrappedGoal> availableGoals = Sets.newLinkedHashSet();
|
|
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.
|
|
+ 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;
|
|
+ private static final Goal.Flag[] PATHFINDER_GOAL_TYPES = Goal.Flag.values(); // Paper - remove streams from pathfindergoalselector
|
|
|
|
public GoalSelector(Supplier<ProfilerFiller> profiler) {
|
|
this.profiler = profiler;
|
|
@@ -61,47 +63,95 @@ public class GoalSelector {
|
|
}
|
|
// Paper end
|
|
public void removeGoal(Goal goal) {
|
|
- this.availableGoals.stream().filter((wrappedGoal) -> {
|
|
- return wrappedGoal.getGoal() == goal;
|
|
- }).filter(WrappedGoal::isRunning).forEach(WrappedGoal::stop);
|
|
- this.availableGoals.removeIf((wrappedGoal) -> {
|
|
- return wrappedGoal.getGoal() == goal;
|
|
- });
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
|
|
+ WrappedGoal goalWrapped = iterator.next();
|
|
+ if (goalWrapped.getGoal() != goal) {
|
|
+ continue;
|
|
+ }
|
|
+ if (goalWrapped.isRunning()) {
|
|
+ goalWrapped.stop();
|
|
+ }
|
|
+ iterator.remove();
|
|
+ }
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
}
|
|
|
|
public void tick() {
|
|
ProfilerFiller profilerFiller = this.profiler.get();
|
|
profilerFiller.push("goalCleanup");
|
|
- this.getRunningGoals().filter((wrappedGoal) -> {
|
|
- return !wrappedGoal.isRunning() || wrappedGoal.getFlags().stream().anyMatch(this.disabledFlags::contains) || !wrappedGoal.canContinueToUse();
|
|
- }).forEach(Goal::stop);
|
|
- this.lockedFlags.forEach((flag, wrappedGoal) -> {
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
|
|
+ WrappedGoal wrappedGoal = iterator.next();
|
|
if (!wrappedGoal.isRunning()) {
|
|
- this.lockedFlags.remove(flag);
|
|
+ continue;
|
|
+ }
|
|
+ if (!this.goalTypes.hasCommonElements(wrappedGoal.getGoalTypes()) && wrappedGoal.canContinueToUse()) {
|
|
+ continue;
|
|
+ }
|
|
+ wrappedGoal.stop();
|
|
+ }
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
+ this.lockedFlags.forEach((pathfindergoal_type, pathfindergoalwrapped) -> {
|
|
+ if (!pathfindergoalwrapped.isRunning()) {
|
|
+ this.lockedFlags.remove(pathfindergoal_type);
|
|
}
|
|
|
|
});
|
|
profilerFiller.pop();
|
|
profilerFiller.push("goalUpdate");
|
|
- this.availableGoals.stream().filter((wrappedGoal) -> {
|
|
- return !wrappedGoal.isRunning();
|
|
- }).filter((wrappedGoal) -> {
|
|
- return wrappedGoal.getFlags().stream().noneMatch(this.disabledFlags::contains);
|
|
- }).filter((wrappedGoal) -> {
|
|
- return wrappedGoal.getFlags().stream().allMatch((flag) -> {
|
|
- return this.lockedFlags.getOrDefault(flag, NO_GOAL).canBeReplacedBy(wrappedGoal);
|
|
- });
|
|
- }).filter(WrappedGoal::canUse).forEach((wrappedGoal) -> {
|
|
- wrappedGoal.getFlags().forEach((flag) -> {
|
|
- WrappedGoal wrappedGoal2 = this.lockedFlags.getOrDefault(flag, NO_GOAL);
|
|
- wrappedGoal2.stop();
|
|
- this.lockedFlags.put(flag, wrappedGoal);
|
|
- });
|
|
+
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ goal_update_loop: for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
|
|
+ WrappedGoal wrappedGoal = iterator.next();
|
|
+ if (wrappedGoal.isRunning()) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<net.minecraft.world.entity.ai.goal.Goal.Flag> wrappedGoalSet = wrappedGoal.getGoalTypes();
|
|
+
|
|
+ if (this.goalTypes.hasCommonElements(wrappedGoalSet)) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ long iterator1 = wrappedGoalSet.getBackingSet();
|
|
+ int wrappedGoalSize = wrappedGoalSet.size();
|
|
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
|
+ Goal.Flag type = PATHFINDER_GOAL_TYPES[Long.numberOfTrailingZeros(iterator1)];
|
|
+ iterator1 ^= com.destroystokyo.paper.util.math.IntegerUtil.getTrailingBit(iterator1);
|
|
+ WrappedGoal wrapped = this.lockedFlags.getOrDefault(type, GoalSelector.NO_GOAL);
|
|
+ if (!wrapped.canBeReplacedBy(wrappedGoal)) {
|
|
+ continue goal_update_loop;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!wrappedGoal.canUse()) {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ iterator1 = wrappedGoalSet.getBackingSet();
|
|
+ wrappedGoalSize = wrappedGoalSet.size();
|
|
+ for (int i = 0; i < wrappedGoalSize; ++i) {
|
|
+ Goal.Flag type = PATHFINDER_GOAL_TYPES[Long.numberOfTrailingZeros(iterator1)];
|
|
+ iterator1 ^= com.destroystokyo.paper.util.math.IntegerUtil.getTrailingBit(iterator1);
|
|
+ WrappedGoal wrapped = this.lockedFlags.getOrDefault(type, GoalSelector.NO_GOAL);
|
|
+
|
|
+ wrapped.stop();
|
|
+ this.lockedFlags.put(type, wrappedGoal);
|
|
+ }
|
|
wrappedGoal.start();
|
|
- });
|
|
+ }
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
profilerFiller.pop();
|
|
profilerFiller.push("goalTick");
|
|
- this.getRunningGoals().forEach(WrappedGoal::tick);
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ for (java.util.Iterator<WrappedGoal> iterator = this.availableGoals.iterator(); iterator.hasNext();) {
|
|
+ WrappedGoal wrappedGoal = iterator.next();
|
|
+ if (wrappedGoal.isRunning()) {
|
|
+ wrappedGoal.tick();
|
|
+ }
|
|
+ }
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
profilerFiller.pop();
|
|
}
|
|
|
|
@@ -118,11 +168,11 @@ 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 1e915b999f4261fb27846a0e559ea22e4b09b4db..037cc5d2b41161e040fc9b264a0dd04827c29681 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
|
|
@@ -58,9 +58,10 @@ public class WrappedGoal extends Goal {
|
|
this.goal.setFlags(controls);
|
|
}
|
|
|
|
- @Override
|
|
- public EnumSet<Goal.Flag> getFlags() {
|
|
- return this.goal.getFlags();
|
|
+ // Paper start - remove streams from pathfindergoalselector
|
|
+ public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> getGoalTypes() {
|
|
+ return this.goal.getGoalTypes();
|
|
+ // Paper end - remove streams from pathfindergoalselector
|
|
}
|
|
|
|
public boolean isRunning() {
|