Commit c0967ef6 by Jonathan Thomas

Protect changing goalSelector to a single server thread, to prevent crash

parent 6faf3371
Pipeline #12025 passed with stage
in 26 seconds
package com.owlmaddie.goals; package com.owlmaddie.goals;
import com.owlmaddie.network.ServerPackets;
import net.minecraft.entity.ai.goal.Goal; import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.entity.ai.goal.GoalSelector; import net.minecraft.entity.ai.goal.GoalSelector;
import net.minecraft.entity.ai.goal.PrioritizedGoal;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.entity.ai.goal.PrioritizedGoal;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -37,9 +38,12 @@ public class EntityBehaviorManager { ...@@ -37,9 +38,12 @@ public class EntityBehaviorManager {
List<Goal> goals = entityGoals.computeIfAbsent(entityId, k -> new ArrayList<>()); List<Goal> goals = entityGoals.computeIfAbsent(entityId, k -> new ArrayList<>());
goals.add(goal); goals.add(goal);
GoalSelector goalSelector = GoalUtils.getGoalSelector(entity); // Ensure that the task is synced with the server thread
goalSelector.add(priority.getPriority(), goal); ServerPackets.serverInstance.execute(() -> {
LOGGER.debug("Goal of type {} added to entity UUID: {}", goal.getClass().getSimpleName(), entityId); GoalSelector goalSelector = GoalUtils.getGoalSelector(entity);
goalSelector.add(priority.getPriority(), goal);
LOGGER.debug("Goal of type {} added to entity UUID: {}", goal.getClass().getSimpleName(), entityId);
});
} }
public static void removeGoal(MobEntity entity, Class<? extends Goal> goalClass) { public static void removeGoal(MobEntity entity, Class<? extends Goal> goalClass) {
...@@ -47,48 +51,54 @@ public class EntityBehaviorManager { ...@@ -47,48 +51,54 @@ public class EntityBehaviorManager {
List<Goal> goals = entityGoals.get(entityId); List<Goal> goals = entityGoals.get(entityId);
if (goals != null) { if (goals != null) {
GoalSelector goalSelector = GoalUtils.getGoalSelector(entity); // Ensure that the task is synced with the server thread
goals.removeIf(goal -> { ServerPackets.serverInstance.execute(() -> {
if (goalClass.isInstance(goal)) { GoalSelector goalSelector = GoalUtils.getGoalSelector(entity);
goalSelector.remove(goal); goals.removeIf(goal -> {
LOGGER.debug("Goal of type {} removed for entity UUID: {}", goalClass.getSimpleName(), entityId); if (goalClass.isInstance(goal)) {
return true; goalSelector.remove(goal);
} LOGGER.debug("Goal of type {} removed for entity UUID: {}", goalClass.getSimpleName(), entityId);
return false; return true;
}
return false;
});
}); });
} }
} }
private static void moveConflictingGoals(MobEntity entity, GoalPriority newGoalPriority) { private static void moveConflictingGoals(MobEntity entity, GoalPriority newGoalPriority) {
GoalSelector goalSelector = GoalUtils.getGoalSelector(entity); // Ensure that the task is synced with the server thread
ServerPackets.serverInstance.execute(() -> {
GoalSelector goalSelector = GoalUtils.getGoalSelector(entity);
// Retrieve the existing goals // Retrieve the existing goals
Set<PrioritizedGoal> existingGoals = new HashSet<>(goalSelector.getGoals()); Set<PrioritizedGoal> existingGoals = new HashSet<>(goalSelector.getGoals());
// Flag to check if there is a goal with the same priority as the new goal // Flag to check if there is a goal with the same priority as the new goal
boolean conflictExists = existingGoals.stream() boolean conflictExists = existingGoals.stream()
.anyMatch(goal -> goal.getPriority() == newGoalPriority.getPriority()); .anyMatch(goal -> goal.getPriority() == newGoalPriority.getPriority());
if (!conflictExists) { if (!conflictExists) {
// If there's no conflict, no need to adjust priorities // If there's no conflict, no need to adjust priorities
return; return;
} }
// If there's a conflict, collect goals that need their priority incremented // If there's a conflict, collect goals that need their priority incremented
List<PrioritizedGoal> goalsToModify = new ArrayList<>(); List<PrioritizedGoal> goalsToModify = new ArrayList<>();
for (PrioritizedGoal prioritizedGoal : existingGoals) { for (PrioritizedGoal prioritizedGoal : existingGoals) {
if (prioritizedGoal.getPriority() >= newGoalPriority.getPriority()) { if (prioritizedGoal.getPriority() >= newGoalPriority.getPriority()) {
goalsToModify.add(prioritizedGoal); goalsToModify.add(prioritizedGoal);
}
} }
}
// Increment priorities and re-add goals // Increment priorities and re-add goals
for (PrioritizedGoal goalToModify : goalsToModify) { for (PrioritizedGoal goalToModify : goalsToModify) {
// Remove the original goal // Remove the original goal
goalSelector.remove(goalToModify.getGoal()); goalSelector.remove(goalToModify.getGoal());
// Increment the priority and re-add the goal // Increment the priority and re-add the goal
goalSelector.add(goalToModify.getPriority() + 1, goalToModify.getGoal()); goalSelector.add(goalToModify.getPriority() + 1, goalToModify.getGoal());
} }
});
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment