4d40e87b33
Had to drop some hunks modifying getEntities, as those methods were rewritten by Mojang in 1.17
224 lines
11 KiB
Diff
224 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() {
|