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

161 lines
8.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
2024-04-25 11:42:10 +02:00
index 074ef807258139f818e30494126585262c2f33c0..74d4f653d5c7f1923c59019effd78337402f7025 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
2024-04-25 11:42:10 +02:00
@@ -25,7 +25,8 @@ public class GoalSelector {
2021-11-24 12:06:34 +01:00
private final Map<Goal.Flag, WrappedGoal> lockedFlags = new EnumMap<>(Goal.Flag.class);
2024-04-25 11:42:10 +02:00
private final Set<WrappedGoal> availableGoals = new ObjectLinkedOpenHashSet<>();
2021-11-24 12:06:34 +01:00
private final Supplier<ProfilerFiller> profiler;
- private final EnumSet<Goal.Flag> disabledFlags = EnumSet.noneOf(Goal.Flag.class);
2024-04-25 11:42:10 +02:00
+ private static final Goal.Flag[] GOAL_FLAG_VALUES = Goal.Flag.values(); // Paper - remove streams from pathfindergoalselector
2021-11-24 12:06:34 +01: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 curRate;
public GoalSelector(Supplier<ProfilerFiller> profiler) {
2024-04-25 11:42:10 +02:00
@@ -65,18 +66,18 @@ public class GoalSelector {
this.availableGoals.removeIf(wrappedGoalx -> wrappedGoalx.getGoal() == goal);
2021-11-24 12:06:34 +01:00
}
2024-04-25 11:42:10 +02:00
2023-03-23 22:57:03 +01:00
- private static boolean goalContainsAnyFlags(WrappedGoal goal, EnumSet<Goal.Flag> controls) {
- for (Goal.Flag flag : goal.getFlags()) {
2023-03-23 22:57:03 +01:00
- if (controls.contains(flag)) {
- return true;
2024-04-25 11:42:10 +02:00
- }
- }
-
2021-11-24 12:06:34 +01:00
- return false;
2024-04-25 11:42:10 +02:00
+ // Paper start
2021-11-24 12:06:34 +01:00
+ private static boolean goalContainsAnyFlags(WrappedGoal goal, com.destroystokyo.paper.util.set.OptimizedSmallEnumSet<Goal.Flag> controls) {
2024-04-25 11:42:10 +02:00
+ return goal.getFlags().hasCommonElements(controls);
2021-11-24 12:06:34 +01:00
}
private static boolean goalCanBeReplacedForAllFlags(WrappedGoal goal, Map<Goal.Flag, WrappedGoal> goalsByControl) {
- for (Goal.Flag flag : goal.getFlags()) {
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
}
2024-04-25 11:42:10 +02:00
@@ -90,7 +91,7 @@ public class GoalSelector {
2021-11-24 12:06:34 +01:00
profilerFiller.push("goalCleanup");
for (WrappedGoal wrappedGoal : this.availableGoals) {
2021-11-24 12:06:34 +01:00
- if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.disabledFlags) || !wrappedGoal.canContinueToUse())) {
+ if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams
2021-11-24 12:06:34 +01:00
wrappedGoal.stop();
}
}
2024-04-25 11:42:10 +02:00
@@ -100,11 +101,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()) {
2021-11-24 12:06:34 +01:00
+ // 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);
2024-04-25 11:42:10 +02:00
@@ -136,11 +140,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
index b02d3deb550830245c8945ef17d3073ea930fdda..65ccdbaa5230c02d44a5959bca0f6fc30237a6fd 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() {