diff --git a/src/main/java/com/denizenscript/denizen2sponge/commands/entity/AddAITaskCommand.java b/src/main/java/com/denizenscript/denizen2sponge/commands/entity/AddAITaskCommand.java index 516ec9b..9ac8b2e 100644 --- a/src/main/java/com/denizenscript/denizen2sponge/commands/entity/AddAITaskCommand.java +++ b/src/main/java/com/denizenscript/denizen2sponge/commands/entity/AddAITaskCommand.java @@ -57,24 +57,37 @@ public class AddAITaskCommand extends AbstractCommand { // <--[command] // @Since 0.4.0 // @Name addaitask - // @Arguments + // @Arguments // @Short adds an AI task to an entity's goal. // @Updated 2018/01/27 // @Group Entity - // @Minimum 3 - // @Maximum 3 + // @Minimum 2 + // @Maximum 2 // @Named priority (IntegerTag) Sets the priority to run this task. // @Named goal (TextTag) Sets to which goal will the task be added. + // @Named speed (NumberTag) Sets the speed parameter for task types + // 'attack_living', 'range', 'run_around' and 'wander'. + // @Named memory (BooleanTag) Sets the memory parameter for task type 'attack_living'. + // @Named close_speed (NumberTag) Sets the close_speed parameter for task type 'avoid_entity'. + // @Named far_speed (NumberTag) Sets the far_speed parameter for task type 'avoid_entity'. + // @Named distance (NumberTag) Sets the distance parameter for task types + // 'avoid_entity', 'range' and 'watch_closest'. + // @Named chance (IntegerTag/NumberTag) Sets the chance parameter for task types 'find_target' + // (IntegerTag), 'swim' (NumberTag), 'wander' (IntegerTag) and 'watch_closest' (NumberTag). + // @Named target (EntityTypeTag) Sets the target parameter for task types + // 'find_target' and 'watch_closest'. + // @Named delay (DurationTag) Sets the delay parameter for task type 'range'. // @Description - // Adds an AI task to an entity's goal. + // Adds an AI task to an entity's goal. Priority defaults to 0. The lower + // the priority is, the sooner the task will run in the goal. The default + // goal is 'normal'. // Related information: <@link explanation AI Goal Types>AI goal types<@/link>. // Related information: <@link explanation AI Task Types>AI task types<@/link>. // Related commands: <@link command removeaitasks>removeaitasks<@/link>. // TODO: Explain task priority. - // TODO: Explain properties of each task type. // @Example // # Makes the zombie in front of the player sink in water. - // - addaitask swim chance:0.0 --priority -10 --goal normal + // - addaitask swim --chance 0.0 --priority -10 --goal normal // --> @Override @@ -84,17 +97,17 @@ public String getName() { @Override public String getArguments() { - return " "; + return " "; } @Override public int getMinimumArguments() { - return 3; + return 2; } @Override public int getMaximumArguments() { - return 3; + return 2; } @Override @@ -103,12 +116,17 @@ public void execute(CommandQueue queue, CommandEntry entry) { try { Agent agent = (Agent) entityTag.getInternal(); TextTag type = TextTag.getFor(queue.error, entry.getArgumentObject(queue, 1)); - MapTag properties = MapTag.getFor(queue.error, entry.getArgumentObject(queue, 2)); AITask task; switch (type.getInternal()) { case "attack_living": - double speed = NumberTag.getFor(queue.error, properties.getInternal().get("speed")).getInternal(); - boolean memory = BooleanTag.getFor(queue.error, properties.getInternal().get("memory")).getInternal(); + if (!entry.namedArgs.containsKey("speed") || !entry.namedArgs.containsKey("memory")) { + queue.handleError(entry, + "Tasks of type attack_living require 'speed' and 'memory' arguments!"); + } + double speed = NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "speed")).getInternal(); + boolean memory = BooleanTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "memory")).getInternal(); if (memory) { task = AttackLivingAITask.builder().speed(speed).longMemory().build((Creature) agent); } @@ -117,16 +135,30 @@ public void execute(CommandQueue queue, CommandEntry entry) { } break; case "avoid_entity": - double closeSpeed = NumberTag.getFor(queue.error, properties.getInternal().get("close_speed")).getInternal(); - double farSpeed = NumberTag.getFor(queue.error, properties.getInternal().get("far_speed")).getInternal(); - float distance = (float) NumberTag.getFor(queue.error, properties.getInternal().get("distance")).getInternal(); + if (!entry.namedArgs.containsKey("close_speed") || !entry.namedArgs.containsKey("far_speed") + || !entry.namedArgs.containsKey("distance")) { + queue.handleError(entry, + "Tasks of type avoid_entity require 'close_speed', 'far_speed' and 'distance' arguments!"); + } + double closeSpeed = NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "close_speed")).getInternal(); + double farSpeed = NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "far_speed")).getInternal(); + float distance = (float) NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "distance")).getInternal(); // TODO: Allow the task to select targets based on a predicate -> .targetSelector(...) task = AvoidEntityAITask.builder().closeRangeSpeed(closeSpeed).farRangeSpeed(farSpeed) .searchDistance(distance).build((Creature) agent); break; case "find_target": - int chance = (int) IntegerTag.getFor(queue.error, properties.getInternal().get("chance")).getInternal(); - EntityType target = EntityTypeTag.getFor(queue.error, properties.getInternal().get("target")).getInternal(); + if (!entry.namedArgs.containsKey("chance") || !entry.namedArgs.containsKey("target")) { + queue.handleError(entry, + "Tasks of type find_target require 'chance' and 'target' arguments!"); + } + int chance = (int) IntegerTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "chance")).getInternal(); + EntityType target = EntityTypeTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "target")).getInternal(); // TODO: Allow the task to filter targets based on a predicate -> .filter(...) task = FindNearestAttackableTargetAITask.builder().chance(chance) .target(target.getEntityClass().asSubclass(Living.class)).build((Creature) agent); @@ -135,29 +167,61 @@ public void execute(CommandQueue queue, CommandEntry entry) { task = LookIdleAITask.builder().build(agent); break; case "range": - float radius = (float) NumberTag.getFor(queue.error, properties.getInternal().get("radius")).getInternal(); - int delay = (int) DurationTag.getFor(queue.error, properties.getInternal().get("delay")).getInternal()* 20; - double moveSpeed = NumberTag.getFor(queue.error, properties.getInternal().get("speed")).getInternal(); + if (!entry.namedArgs.containsKey("distance") || !entry.namedArgs.containsKey("delay") + || !entry.namedArgs.containsKey("speed")) { + queue.handleError(entry, + "Tasks of type range require 'distance', 'delay' and 'speed' arguments!"); + } + float radius = (float) NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "distance")).getInternal(); + int delay = (int) DurationTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "delay")).getInternal() * 20; + double moveSpeed = NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "speed")).getInternal(); task = RangeAgentAITask.builder().attackRadius(radius).delayBetweenAttacks(delay) .moveSpeed(moveSpeed).build((Ranger) agent); break; case "run_around": - double runSpeed = NumberTag.getFor(queue.error, properties.getInternal().get("speed")).getInternal(); + if (!entry.namedArgs.containsKey("speed")) { + queue.handleError(entry, + "Tasks of type run_around require a 'speed' argument!"); + } + double runSpeed = NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "speed")).getInternal(); task = RunAroundLikeCrazyAITask.builder().speed(runSpeed).build((RideableHorse) agent); break; case "swim": - float swimChance = (float) NumberTag.getFor(queue.error, properties.getInternal().get("chance")).getInternal(); + if (!entry.namedArgs.containsKey("chance")) { + queue.handleError(entry, + "Tasks of type swim require a 'chance' argument!"); + } + float swimChance = (float) NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "chance")).getInternal(); task = SwimmingAITask.builder().swimChance(swimChance).build(agent); break; case "wander": - int executionChance = (int) IntegerTag.getFor(queue.error, properties.getInternal().get("chance")).getInternal(); - double wanderSpeed = NumberTag.getFor(queue.error, properties.getInternal().get("speed")).getInternal(); + if (!entry.namedArgs.containsKey("chance") || !entry.namedArgs.containsKey("speed")) { + queue.handleError(entry, + "Tasks of type wander require 'chance' and 'speed' arguments!"); + } + int executionChance = (int) IntegerTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "chance")).getInternal(); + double wanderSpeed = NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "speed")).getInternal(); task = WanderAITask.builder().executionChance(executionChance).speed(wanderSpeed).build((Creature) agent); break; case "watch_closest": - float watchChance = (float) NumberTag.getFor(queue.error, properties.getInternal().get("chance")).getInternal(); - float maxDistance = (float) NumberTag.getFor(queue.error, properties.getInternal().get("max_distance")).getInternal(); - EntityType watch = EntityTypeTag.getFor(queue.error, properties.getInternal().get("target")).getInternal(); + if (!entry.namedArgs.containsKey("chance") || !entry.namedArgs.containsKey("distance") + || !entry.namedArgs.containsKey("target")) { + queue.handleError(entry, + "Tasks of type watch_closest require 'chance', 'distance' and 'target' arguments!"); + } + float watchChance = (float) NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "chance")).getInternal(); + float maxDistance = (float) NumberTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "distance")).getInternal(); + EntityType watch = EntityTypeTag.getFor(queue.error, + entry.getNamedArgumentObject(queue, "target")).getInternal(); task = WatchClosestAITask.builder().chance(watchChance).maxDistance(maxDistance) .watch(watch.getEntityClass()).build(agent); break; @@ -196,7 +260,7 @@ public void execute(CommandQueue queue, CommandEntry entry) { } } catch (ClassCastException e) { - queue.handleError(entry, "This entity doesn't support AI goals and tasks!"); + queue.handleError(entry, "This entity doesn't support this type of AI task!"); } } } diff --git a/src/main/java/com/denizenscript/denizen2sponge/commands/entity/RemoveAITasksCommand.java b/src/main/java/com/denizenscript/denizen2sponge/commands/entity/RemoveAITasksCommand.java index 5ee12b7..90e2421 100644 --- a/src/main/java/com/denizenscript/denizen2sponge/commands/entity/RemoveAITasksCommand.java +++ b/src/main/java/com/denizenscript/denizen2sponge/commands/entity/RemoveAITasksCommand.java @@ -7,19 +7,9 @@ import com.denizenscript.denizen2core.utilities.debugging.ColorSet; import com.denizenscript.denizen2sponge.tags.objects.EntityTag; import org.spongepowered.api.Sponge; -import org.spongepowered.api.entity.ai.Goal; import org.spongepowered.api.entity.ai.GoalType; import org.spongepowered.api.entity.ai.GoalTypes; -import org.spongepowered.api.entity.ai.task.AITask; -import org.spongepowered.api.entity.ai.task.builtin.LookIdleAITask; -import org.spongepowered.api.entity.ai.task.builtin.SwimmingAITask; -import org.spongepowered.api.entity.ai.task.builtin.WatchClosestAITask; -import org.spongepowered.api.entity.ai.task.builtin.creature.AttackLivingAITask; -import org.spongepowered.api.entity.ai.task.builtin.creature.AvoidEntityAITask; -import org.spongepowered.api.entity.ai.task.builtin.creature.RangeAgentAITask; -import org.spongepowered.api.entity.ai.task.builtin.creature.WanderAITask; -import org.spongepowered.api.entity.ai.task.builtin.creature.horse.RunAroundLikeCrazyAITask; -import org.spongepowered.api.entity.ai.task.builtin.creature.target.FindNearestAttackableTargetAITask; +import org.spongepowered.api.entity.ai.task.AITaskType; import org.spongepowered.api.entity.living.Agent; import java.util.Optional; @@ -72,45 +62,17 @@ public void execute(CommandQueue queue, CommandEntry entry) { try { Agent agent = (Agent) entityTag.getInternal(); TextTag type = TextTag.getFor(queue.error, entry.getArgumentObject(queue, 1)); - Class clazz; - switch (type.getInternal()) { - case "attack_living": - clazz = AttackLivingAITask.class; - break; - case "avoid_entity": - clazz = AvoidEntityAITask.class; - break; - case "find_target": - clazz = FindNearestAttackableTargetAITask.class; - break; - case "look_idle": - clazz = LookIdleAITask.class; - break; - case "range": - clazz = RangeAgentAITask.class; - break; - case "run_around": - clazz = RunAroundLikeCrazyAITask.class; - break; - case "swim": - clazz = SwimmingAITask.class; - break; - case "wander": - clazz = WanderAITask.class; - break; - case "watch_closest": - clazz = WatchClosestAITask.class; - break; - default: - queue.handleError(entry, "Invalid task type '" + type.debug() + "' in RemoveAITask command!"); - return; + Optional opt = Sponge.getRegistry().getType(AITaskType.class, type.getInternal()); + if (!opt.isPresent()) { + queue.handleError(entry, "Invalid task type '" + type.debug() + "' in RemoveAITask command!"); + return; } GoalType goal; if (entry.namedArgs.containsKey("goal")) { TextTag goalType = TextTag.getFor(queue.error, entry.getNamedArgumentObject(queue, "goal")); - Optional opt = Sponge.getRegistry().getType(GoalType.class, goalType.getInternal()); - if (opt.isPresent()) { - goal = opt.get(); + Optional goalOpt = Sponge.getRegistry().getType(GoalType.class, goalType.getInternal()); + if (goalOpt.isPresent()) { + goal = goalOpt.get(); } else { queue.handleError(entry, "Invalid goal type '" + goalType.debug() + "' in RemoveAITask command!"); @@ -120,17 +82,9 @@ public void execute(CommandQueue queue, CommandEntry entry) { else { goal = GoalTypes.NORMAL; } - Goal agentGoal = agent.getGoal(goal).get(); - for (Object obj : agentGoal.getTasks()) { - AITask task = (AITask) obj; - if (clazz.isInstance(task)) { - agentGoal.removeTask(task); - } - } - // TODO: Change the current method of removing once Sponge has proper AITaskTypes. - // agent.getGoal(goal).get().removeTasks(typeHere); + agent.getGoal(goal).get().removeTasks(opt.get()); if (queue.shouldShowGood()) { - queue.outGood("Removed tasks of type '" + ColorSet.emphasis + type.debug() + queue.outGood("Removed tasks of type '" + ColorSet.emphasis + opt.get().getId() + ColorSet.good + "' from goal '" + ColorSet.emphasis + goal.getId() + ColorSet.good + "' of entity '" + ColorSet.emphasis + entityTag.debug() + ColorSet.good + "'!");