Paper/patches/server/0997-Optimize-GoalSelector-Goal.Flag-Set-operations.patch

181 lines
9.4 KiB
Diff
Raw Normal View History

2021-11-24 12:06:34 +01:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
Rewrite chunk system (#8177) Patch documentation to come Issues with the old system that are fixed now: - World generation does not scale with cpu cores effectively. - Relies on the main thread for scheduling and maintaining chunk state, dropping chunk load/generate rates at lower tps. - Unreliable prioritisation of chunk gen/load calls that block the main thread. - Shutdown logic is utterly unreliable, as it has to wait for all chunks to unload - is it guaranteed that the chunk system is in a state on shutdown that it can reliably do this? Watchdog shutdown also typically failed due to thread checks, which is now resolved. - Saving of data is not unified (i.e can save chunk data without saving entity data, poses problems for desync if shutdown is really abnormal. - Entities are not loaded with chunks. This caused quite a bit of headache for Chunk#getEntities API, but now the new chunk system loads entities with chunks so that they are ready whenever the chunk loads in. Effectively brings the behavior back to 1.16 era, but still storing entities in their own separate regionfiles. The above list is not complete. The patch documentation will complete it. New chunk system hard relies on starlight and dataconverter, and most importantly the new concurrent utilities in ConcurrentUtil. Some of the old async chunk i/o interface (i.e the old file io thread reroutes _some_ calls to the new file io thread) is kept for plugin compat reasons. It will be removed in the next major version of minecraft. The old legacy chunk system patches have been moved to the removed folder in case we need them again.
2022-09-26 10:02:51 +02:00
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
2021-11-24 12:06:34 +01:00
Date: Mon, 6 Apr 2020 17:53:29 -0700
Subject: [PATCH] Optimize GoalSelector Goal.Flag Set operations
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 16f9a98b8a939e5ca7e2dc04f87134a7ed66736b..dd423302b1baa64ef86ded87a29659342e28c142 100644
2021-11-24 12:06:34 +01:00
--- a/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/Goal.java
@@ -4,7 +4,16 @@ import java.util.EnumSet;
2021-11-24 12:06:34 +01:00
import net.minecraft.util.Mth;
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
+
+ // Paper start - remove streams from pathfindergoalselector; make sure types are not empty
+ public Goal() {
+ if (this.goalTypes.size() == 0) {
+ this.goalTypes.add(Flag.UNKNOWN_BEHAVIOR);
+ }
+ }
+ // Paper end - remove streams from pathfindergoalselector
2021-11-24 12:06:34 +01:00
public abstract boolean canUse();
@@ -30,8 +39,13 @@ public abstract class Goal {
2021-11-24 12:06:34 +01: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.addAll(controls);
+ if (this.goalTypes.size() == 0) {
+ this.goalTypes.add(Flag.UNKNOWN_BEHAVIOR);
+ }
2021-11-24 12:06:34 +01:00
+ // Paper end - remove streams from pathfindergoalselector
}
@Override
@@ -39,8 +53,10 @@ public abstract class Goal {
2021-11-24 12:06:34 +01:00
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> getFlags() {
+ return this.goalTypes;
+ // Paper end - remove streams from pathfindergoalselector
}
protected int adjustedTickDelay(int ticks) {
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 e5995d0db5dcfba59a873ff439601894fdacd556..676f5485a4ca9252e911213dcda8d51776b637b6 100644
2021-11-24 12:06:34 +01:00
--- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java
2022-12-07 20:22:28 +01:00
@@ -30,10 +30,12 @@ public class GoalSelector {
2021-11-24 12:06:34 +01:00
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
private final Set<WrappedGoal> availableGoals = Sets.newLinkedHashSet();
2021-11-24 12:06:34 +01: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.
+ 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[] GOAL_FLAG_VALUES = Goal.Flag.values(); // Paper - remove streams from pathfindergoalselector
public GoalSelector(Supplier<ProfilerFiller> profiler) {
this.profiler = profiler;
2022-12-07 20:22:28 +01:00
@@ -65,26 +67,32 @@ public class GoalSelector {
2021-11-24 12:06:34 +01:00
}
// 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;
- });
2023-03-23 22:57:03 +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-11-24 12:06:34 +01:00
+ // 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;
2023-03-23 22:57:03 +01:00
}
2021-11-24 12:06:34 +01:00
+ if (goalWrapped.isRunning()) {
+ goalWrapped.stop();
2021-11-30 09:36:30 +01:00
+ }
2021-11-24 12:06:34 +01:00
+ iterator.remove();
2023-03-23 22:57:03 +01:00
}
2021-11-24 12:06:34 +01:00
+ // Paper end - remove streams from pathfindergoalselector
2023-03-23 22:57:03 +01:00
+ }
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
}
2022-12-07 20:22:28 +01:00
@@ -98,7 +106,7 @@ public class GoalSelector {
2021-11-24 12:06:34 +01:00
profilerFiller.push("goalCleanup");
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();
}
}
2022-12-07 20:22:28 +01:00
@@ -116,8 +124,14 @@ public class GoalSelector {
2021-11-24 12:06:34 +01:00
profilerFiller.push("goalUpdate");
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);
2022-12-07 20:22:28 +01:00
@@ -157,11 +171,11 @@ public class GoalSelector {
2021-11-24 12:06:34 +01:00
}
public void disableControlFlag(Goal.Flag control) {
- this.disabledFlags.add(control);
+ this.goalTypes.add(control); // Paper - remove streams from pathfindergoalselector
2021-11-24 12:06:34 +01:00
}
public void enableControlFlag(Goal.Flag control) {
- this.disabledFlags.remove(control);
+ this.goalTypes.remove(control); // Paper - remove streams from pathfindergoalselector
2021-11-24 12:06:34 +01:00
}
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
2023-09-22 19:59:56 +02:00
index 6665ce5f48316e626907e6937d5ef1bc398a7ebd..51deb4455cac055ffa455e4f34aa30858d2fb448 100644
2021-11-24 12:06:34 +01:00
--- a/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
+++ b/src/main/java/net/minecraft/world/entity/ai/goal/WrappedGoal.java
@@ -69,8 +69,10 @@ public class WrappedGoal extends Goal {
}
@Override
- public EnumSet<Goal.Flag> getFlags() {
+ // Paper start - remove streams from pathfindergoalselector
+ public com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> getFlags() {
return this.goal.getFlags();
+ // Paper end - remove streams from pathfindergoalselector
}
public boolean isRunning() {