package net.minecraft.world.entity.ai.goal; import com.google.common.annotations.VisibleForTesting; import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet; import java.util.EnumMap; import java.util.EnumSet; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import java.util.function.Predicate; import net.minecraft.util.profiling.Profiler; import net.minecraft.util.profiling.ProfilerFiller; public class GoalSelector { private static final WrappedGoal NO_GOAL = new WrappedGoal(Integer.MAX_VALUE, new Goal() { @Override public boolean canUse() { return false; } }) { @Override public boolean isRunning() { return false; } }; private final Map lockedFlags = new EnumMap<>(Goal.Flag.class); private final Set availableGoals = new ObjectLinkedOpenHashSet<>(); private final EnumSet disabledFlags = EnumSet.noneOf(Goal.Flag.class); public void addGoal(int p_25353_, Goal p_25354_) { this.availableGoals.add(new WrappedGoal(p_25353_, p_25354_)); } @VisibleForTesting public void removeAllGoals(Predicate p_262575_) { this.availableGoals.removeIf(p_262564_ -> p_262575_.test(p_262564_.getGoal())); } public void removeGoal(Goal p_25364_) { for (WrappedGoal wrappedgoal : this.availableGoals) { if (wrappedgoal.getGoal() == p_25364_ && wrappedgoal.isRunning()) { wrappedgoal.stop(); } } this.availableGoals.removeIf(p_25378_ -> p_25378_.getGoal() == p_25364_); } private static boolean goalContainsAnyFlags(WrappedGoal p_186076_, EnumSet p_186077_) { for (Goal.Flag goal$flag : p_186076_.getFlags()) { if (p_186077_.contains(goal$flag)) { return true; } } return false; } private static boolean goalCanBeReplacedForAllFlags(WrappedGoal p_186079_, Map p_186080_) { for (Goal.Flag goal$flag : p_186079_.getFlags()) { if (!p_186080_.getOrDefault(goal$flag, NO_GOAL).canBeReplacedBy(p_186079_)) { return false; } } return true; } public void tick() { ProfilerFiller profilerfiller = Profiler.get(); profilerfiller.push("goalCleanup"); for (WrappedGoal wrappedgoal : this.availableGoals) { if (wrappedgoal.isRunning() && (goalContainsAnyFlags(wrappedgoal, this.disabledFlags) || !wrappedgoal.canContinueToUse())) { wrappedgoal.stop(); } } this.lockedFlags.entrySet().removeIf(p_326929_ -> !p_326929_.getValue().isRunning()); profilerfiller.pop(); profilerfiller.push("goalUpdate"); for (WrappedGoal wrappedgoal2 : this.availableGoals) { if (!wrappedgoal2.isRunning() && !goalContainsAnyFlags(wrappedgoal2, this.disabledFlags) && goalCanBeReplacedForAllFlags(wrappedgoal2, this.lockedFlags) && wrappedgoal2.canUse()) { for (Goal.Flag goal$flag : wrappedgoal2.getFlags()) { WrappedGoal wrappedgoal1 = this.lockedFlags.getOrDefault(goal$flag, NO_GOAL); wrappedgoal1.stop(); this.lockedFlags.put(goal$flag, wrappedgoal2); } wrappedgoal2.start(); } } profilerfiller.pop(); this.tickRunningGoals(true); } public void tickRunningGoals(boolean p_186082_) { ProfilerFiller profilerfiller = Profiler.get(); profilerfiller.push("goalTick"); for (WrappedGoal wrappedgoal : this.availableGoals) { if (wrappedgoal.isRunning() && (p_186082_ || wrappedgoal.requiresUpdateEveryTick())) { wrappedgoal.tick(); } } profilerfiller.pop(); } public Set getAvailableGoals() { return this.availableGoals; } public void disableControlFlag(Goal.Flag p_25356_) { this.disabledFlags.add(p_25356_); } public void enableControlFlag(Goal.Flag p_25375_) { this.disabledFlags.remove(p_25375_); } public void setControlFlag(Goal.Flag p_25361_, boolean p_25362_) { if (p_25362_) { this.enableControlFlag(p_25361_); } else { this.disableControlFlag(p_25361_); } } }