diff --git a/src/net/citizensnpcs/npc/ai/CitizensAI.java b/src/net/citizensnpcs/npc/ai/CitizensAI.java index f4b36371f..f104723f3 100644 --- a/src/net/citizensnpcs/npc/ai/CitizensAI.java +++ b/src/net/citizensnpcs/npc/ai/CitizensAI.java @@ -1,17 +1,28 @@ package net.citizensnpcs.npc.ai; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + import net.citizensnpcs.api.npc.ai.AI; import net.citizensnpcs.api.npc.ai.Goal; import net.citizensnpcs.api.npc.ai.NavigationCallback; +import net.citizensnpcs.api.npc.ai.NavigationCallback.PathCancelReason; import net.citizensnpcs.npc.CitizensNPC; import net.citizensnpcs.util.Messaging; import org.bukkit.Location; import org.bukkit.entity.LivingEntity; +import com.google.common.collect.Lists; + public class CitizensAI implements AI { - private PathStrategy executing; private Runnable ai; + private boolean paused; + private final List callbacks = Lists.newArrayList(); + private PathStrategy executing; + private final List executingGoals = Lists.newArrayList(); + private final List goals = Lists.newArrayList(); private final CitizensNPC npc; public CitizensAI(CitizensNPC npc) { @@ -20,12 +31,32 @@ public class CitizensAI implements AI { @Override public void addGoal(int priority, Goal goal) { - // TODO Auto-generated method stub + if (goals.contains(goal)) + return; + goals.add(new GoalEntry(priority, goal)); + Collections.sort(goals); + } + private boolean isGoalAllowable(GoalEntry test) { + for (GoalEntry item : goals) { + if (item == test) + continue; + if (test.priority >= item.priority) { + if (executingGoals.contains(item) && !test.goal.isCompatibleWith(item.goal)) { + return false; + } + } /*else if (executingGoals.contains(item) && !item.goal.requiresUpdates()) { + return false; + }*/ + } + + return true; } @Override public void registerNavigationCallback(NavigationCallback callback) { + if (!callbacks.contains(callback)) + callbacks.add(callback); } @Override @@ -35,16 +66,54 @@ public class CitizensAI implements AI { @Override public void setDestination(Location destination) { + if (executing != null) { + Iterator itr = callbacks.iterator(); + while (itr.hasNext()) { + if (itr.next().onCancel(this, PathCancelReason.PLUGIN)) { + itr.remove(); + } + } + } executing = new MoveStrategy(npc, destination); } @Override public void setTarget(LivingEntity target, boolean aggressive) { + if (executing != null) { + Iterator itr = callbacks.iterator(); + while (itr.hasNext()) { + if (itr.next().onCancel(this, PathCancelReason.PLUGIN)) { + itr.remove(); + } + } + } executing = new TargetStrategy(npc, target, aggressive); + Iterator itr = callbacks.iterator(); + while (itr.hasNext()) { + if (itr.next().onBegin(this)) { + itr.remove(); + } + } + } + + public void pause() { + paused = true; + } + + public void resume() { + paused = false; } public void update() { + if (paused) + return; if (executing != null && executing.update()) { + Iterator itr = callbacks.iterator(); + while (itr.hasNext()) { + if (itr.next().onCompletion(this)) { + itr.remove(); + } + } executing = null; } @@ -56,5 +125,38 @@ public class CitizensAI implements AI { ex.printStackTrace(); } } + + for (GoalEntry entry : goals) { + boolean executing = executingGoals.contains(entry); + + if (executing) { + if (!entry.goal.continueExecuting() || !isGoalAllowable(entry)) { + entry.goal.reset(); + executingGoals.remove(entry); + } + } else if (entry.goal.continueExecuting() && isGoalAllowable(entry)) { + entry.goal.start(); + executingGoals.add(entry); + } + } + + for (GoalEntry entry : executingGoals) { + entry.goal.update(); + } + } + + private class GoalEntry implements Comparable { + final Goal goal; + final int priority; + + GoalEntry(int priority, Goal goal) { + this.priority = priority; + this.goal = goal; + } + + @Override + public int compareTo(GoalEntry o) { + return o.priority > priority ? 1 : o.priority < priority ? -1 : 0; + } } } \ No newline at end of file