From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Fri, 15 Aug 2025 15:02:27 +0900 Subject: [PATCH] optimize goal selector diff --git a/net/minecraft/world/entity/ai/goal/Goal.java b/net/minecraft/world/entity/ai/goal/Goal.java index f54bbe2e65b18f214266769c7a64144baafa9a58..40d53e4469a71b33949ee2bd7b01783d343d4134 100644 --- a/net/minecraft/world/entity/ai/goal/Goal.java +++ b/net/minecraft/world/entity/ai/goal/Goal.java @@ -100,10 +100,12 @@ public abstract class Goal { // Paper end - Mob goal api public static enum Flag { + // Leaf - optimize goal selector - diff on change UNKNOWN_BEHAVIOR, // Paper - add UNKNOWN_BEHAVIOR MOVE, LOOK, JUMP, TARGET; + // Leaf - optimize goal selector - diff on change } } diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java index 653c58c7637c46c8b46a5082f671324a2221d431..15b6781d110b7dc95c6dfb576e5258e7457b5e2f 100644 --- a/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java @@ -20,10 +20,12 @@ public class GoalSelector { } }; private final Map lockedFlags = new EnumMap<>(Goal.Flag.class); - private final Set availableGoals = new ObjectLinkedOpenHashSet<>(); + private final org.dreeam.leaf.util.map.BinaryGoalSet leaf$availableGoals = new org.dreeam.leaf.util.map.BinaryGoalSet(); // Leaf - optimize goal selector + private final Set availableGoals = leaf$availableGoals; // Leaf - optimize goal selector private static final Goal.Flag[] GOAL_FLAG_VALUES = Goal.Flag.values(); // Paper - remove streams from GoalSelector private final ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet goalTypes = new ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet<>(Goal.Flag.class); // Paper - remove streams from GoalSelector private int curRate; // Paper - EAR 2 + private final int[] lockedPriorities = new int[GOAL_FLAG_VALUES.length]; // Leaf - optimize goal selector public void addGoal(int priority, Goal goal) { this.availableGoals.add(new WrappedGoal(priority, goal)); @@ -40,7 +42,12 @@ public class GoalSelector { } public boolean hasTasks() { - for (WrappedGoal task : this.availableGoals) { + // Leaf start - optimize goal selector + org.dreeam.leaf.util.map.BinaryGoalSet availableGoals = this.leaf$availableGoals; + WrappedGoal[] elements = availableGoals.elements(); + for (int i = 0, j = availableGoals.size(); i < j; i++) { + WrappedGoal task = elements[i]; + // Leaf end - optimize goal selector if (task.isRunning()) { return true; } @@ -50,7 +57,12 @@ public class GoalSelector { // Paper end - EAR 2 public void removeGoal(Goal goal) { - for (WrappedGoal wrappedGoal : this.availableGoals) { + // Leaf start - optimize goal selector + org.dreeam.leaf.util.map.BinaryGoalSet availableGoals = this.leaf$availableGoals; + WrappedGoal[] elements = availableGoals.elements(); + for (int i = 0, j = availableGoals.size(); i < j; i++) { + WrappedGoal wrappedGoal = elements[i]; + // Leaf end - optimize goal selector if (wrappedGoal.getGoal() == goal && wrappedGoal.isRunning()) { wrappedGoal.stop(); } @@ -80,37 +92,81 @@ public class GoalSelector { } public void tick() { - for (WrappedGoal wrappedGoal : this.availableGoals) { - if (wrappedGoal.isRunning() && (goalContainsAnyFlags(wrappedGoal, this.goalTypes) || !wrappedGoal.canContinueToUse())) { // Paper - Perf: optimize goal types by removing streams - wrappedGoal.stop(); + // Leaf start - optimize goal selector + final org.dreeam.leaf.util.map.BinaryGoalSet availableGoals = this.leaf$availableGoals; + final WrappedGoal[] elements = availableGoals.elements(); + final long disabled = this.goalTypes.getBackingSet(); + final int elemSize = availableGoals.size(); + final Map lockedFlags = this.lockedFlags; + final int[] lockedPriorities = this.lockedPriorities; + long mask = 0L; + + for (int i = 0; i < elemSize; i++) { + final WrappedGoal goal = elements[i]; + if (goal.isRunning() && ((disabled & goal.goal.getFlags().getBackingSet()) != 0 || !goal.canContinueToUse())) { + goal.stop(); } } - - this.lockedFlags.entrySet().removeIf(entry -> !entry.getValue().isRunning()); - - for (WrappedGoal wrappedGoalx : this.availableGoals) { - // Paper start - if (!wrappedGoalx.isRunning() && !goalContainsAnyFlags(wrappedGoalx, this.goalTypes) && goalCanBeReplacedForAllFlags(wrappedGoalx, this.lockedFlags) && wrappedGoalx.canUse()) { - long flagIterator = wrappedGoalx.getFlags().getBackingSet(); - int wrappedGoalSize = wrappedGoalx.getFlags().size(); - for (int i = 0; i < wrappedGoalSize; ++i) { - final Goal.Flag flag = GOAL_FLAG_VALUES[Long.numberOfTrailingZeros(flagIterator)]; - flagIterator ^= ca.spottedleaf.concurrentutil.util.IntegerUtil.getTrailingBit(flagIterator); - // Paper end - WrappedGoal wrappedGoal1 = this.lockedFlags.getOrDefault(flag, NO_GOAL); - wrappedGoal1.stop(); - this.lockedFlags.put(flag, wrappedGoalx); + for (int i = 0; i < GOAL_FLAG_VALUES.length; i++) { + final Goal.Flag flag = GOAL_FLAG_VALUES[i]; + final WrappedGoal locked = lockedFlags.get(flag); + if (locked == null) { + lockedPriorities[i] = Integer.MAX_VALUE; + } else if (!locked.isRunning()) { + lockedFlags.remove(flag); + lockedPriorities[i] = Integer.MAX_VALUE; + } else { + lockedPriorities[i] = locked.isInterruptable() + ? locked.getPriority() + : Integer.MIN_VALUE; + mask |= (1L << i); + } + } + for (int i = 0; i < elemSize; i++) { + final WrappedGoal goal = elements[i]; + if (goal.isRunning()) { + continue; + } + final long f = goal.goal.getFlags().getBackingSet(); + final int p = goal.getPriority(); + if ((disabled & f) != 0L + || (f & mask) != 0L + && ((f & 1L) != 0L && p >= lockedPriorities[0] + || (f & 2L) != 0L && p >= lockedPriorities[1] + || (f & 4L) != 0L && p >= lockedPriorities[2] + || (f & 8L) != 0L && p >= lockedPriorities[3] + || (f & 16L) != 0L && p >= lockedPriorities[4])) { + continue; + } else if (!goal.canUse()) { + continue; + } + for (long iter = f; iter != 0L; iter &= iter - 1) { + final int j = Long.numberOfTrailingZeros(iter); + final Goal.Flag flag = GOAL_FLAG_VALUES[j]; + final WrappedGoal locked = lockedFlags.get(flag); + if (locked != null) { + locked.stop(); } - - wrappedGoalx.start(); + lockedFlags.put(flag, goal); + lockedPriorities[j] = goal.isInterruptable() + ? goal.getPriority() + : Integer.MIN_VALUE; + mask |= (1L << j); } + goal.start(); } + // Leaf end - optimize goal selector this.tickRunningGoals(true); } public void tickRunningGoals(boolean tickAllRunning) { - for (WrappedGoal wrappedGoal : this.availableGoals) { + // Leaf start - optimize goal selector + org.dreeam.leaf.util.map.BinaryGoalSet availableGoals = this.leaf$availableGoals; + WrappedGoal[] elements = availableGoals.elements(); + for (int i = 0, j = availableGoals.size(); i < j; i++) { + WrappedGoal wrappedGoal = elements[i]; + // Leaf end - optimize goal selector if (wrappedGoal.isRunning() && (tickAllRunning || wrappedGoal.requiresUpdateEveryTick())) { wrappedGoal.tick(); } diff --git a/net/minecraft/world/entity/ai/goal/WrappedGoal.java b/net/minecraft/world/entity/ai/goal/WrappedGoal.java index 2c2ab6a1df9d3d23773e44ce4041cc1c21b55163..f5ef2e26ff4f9207fc56abe95fe68b3f166499bd 100644 --- a/net/minecraft/world/entity/ai/goal/WrappedGoal.java +++ b/net/minecraft/world/entity/ai/goal/WrappedGoal.java @@ -4,7 +4,7 @@ import java.util.EnumSet; import javax.annotation.Nullable; public class WrappedGoal extends Goal { - private final Goal goal; + public final Goal goal; // Leaf - optimize goal selector - private -> public private final int priority; private boolean isRunning; @@ -70,6 +70,7 @@ public class WrappedGoal extends Goal { @Override public ca.spottedleaf.moonrise.common.set.OptimizedSmallEnumSet getFlags() { // Paper - remove streams from GoalSelector + // Leaf - optimize goal selector - diff on change return this.goal.getFlags(); }