Skip to content
This repository has been archived by the owner on Apr 12, 2022. It is now read-only.

Commit

Permalink
AddAITask and RemoveAITasks commands
Browse files Browse the repository at this point in the history
Note: This AI stuff will need some more testing, as well as additional checks and code improvements. It also lacks an EditAITask command. More comming soon!
  • Loading branch information
Xenmai committed Jan 27, 2018
1 parent 5d66800 commit 0c1249c
Show file tree
Hide file tree
Showing 3 changed files with 345 additions and 0 deletions.
Expand Up @@ -122,6 +122,7 @@ public void onServerStart(GamePreInitializationEvent event) {
Denizen2Core.getImplementation().getAddonsFolder().mkdirs();
Denizen2Core.getImplementation().getScriptDataFolder().mkdirs();
// Commands: Entity
Denizen2Core.register(new AddAITaskCommand());
Denizen2Core.register(new AirCommand());
Denizen2Core.register(new CastCommand());
Denizen2Core.register(new DefuseCommand());
Expand All @@ -135,6 +136,7 @@ public void onServerStart(GamePreInitializationEvent event) {
Denizen2Core.register(new LookAtCommand());
Denizen2Core.register(new MountCommand());
Denizen2Core.register(new PrimeCommand());
Denizen2Core.register(new RemoveAITasksCommand());
Denizen2Core.register(new RemoveCommand());
Denizen2Core.register(new SpawnCommand());
Denizen2Core.register(new TargetCommand());
Expand Down
@@ -0,0 +1,201 @@
package com.denizenscript.denizen2sponge.commands.entity;

import com.denizenscript.denizen2core.commands.AbstractCommand;
import com.denizenscript.denizen2core.commands.CommandEntry;
import com.denizenscript.denizen2core.commands.CommandQueue;
import com.denizenscript.denizen2core.tags.objects.*;
import com.denizenscript.denizen2core.utilities.debugging.ColorSet;
import com.denizenscript.denizen2sponge.tags.objects.EntityTag;
import com.denizenscript.denizen2sponge.tags.objects.EntityTypeTag;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.entity.EntityType;
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.living.Agent;
import org.spongepowered.api.entity.living.Creature;
import org.spongepowered.api.entity.living.Living;
import org.spongepowered.api.entity.living.Ranger;
import org.spongepowered.api.entity.living.animal.RideableHorse;

import java.util.Optional;

public class AddAITaskCommand extends AbstractCommand {


// <--[explanation]
// @Since 0.4.0
// @Name AI Goal Types
// @Group Useful Lists
// @Description
// A list of all default AI goal types can be found here:
// <@link url https://jd.spongepowered.org/7.1.0-SNAPSHOT/org/spongepowered/api/entity/ai/GoalTypes.html>AI goal types list<@/link>
// These can be used with the addaitask, removeaitasks and editaitask commands.
// Keep in mind that the goal type "normal" is available for most living entities,
// while the "target" goal type is mainly for combat related ones.
// -->

// <--[explanation]
// @Since 0.4.0
// @Name AI Task Types
// @Group Useful Lists
// @Description
// The default AI task types are "attack_living", "avoid_entity", "find_target",
// "look_idle", "range", "run_around", "swim", "wander", and "watch_closest".
// These can be used with the addaitask, removeaitasks and editaitask commands.
// -->

// <--[command]
// @Since 0.4.0
// @Name addaitask
// @Arguments <entity> <task type> <map of properties>
// @Short adds an AI task to an entity's goal.
// @Updated 2018/01/27
// @Group Entity
// @Minimum 3
// @Maximum 3
// @Named priority (IntegerTag) Sets the priority to run this task.
// @Named goal (TextTag) Sets to which goal will the task be added.
// @Description
// Adds an AI task to an entity's goal.
// Related information: <@link explanation AI Goal Types>AI goal types<@/link>.
// Related information: <@link explanation AI Task Types>AI task types<@/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 <player.target_entities[type:zombie].get[1]> swim chance:0.0 --priority -10 --goal normal
// -->

@Override
public String getName() {
return "addaitask";
}

@Override
public String getArguments() {
return "<entity> <task type> <map of properties>";
}

@Override
public int getMinimumArguments() {
return 3;
}

@Override
public int getMaximumArguments() {
return 3;
}

@Override
public void execute(CommandQueue queue, CommandEntry entry) {
EntityTag entityTag = EntityTag.getFor(queue.error, entry.getArgumentObject(queue, 0));
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<? extends Agent> 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 (memory) {
task = AttackLivingAITask.builder().speed(speed).longMemory().build((Creature) agent);
}
else {
task = AttackLivingAITask.builder().speed(speed).build((Creature) agent);
}
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();
// 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();
// 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);
break;
case "look_idle":
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();
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();
task = RunAroundLikeCrazyAITask.builder().speed(runSpeed).build((RideableHorse) agent);
break;
case "swim":
float swimChance = (float) NumberTag.getFor(queue.error, properties.getInternal().get("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();
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();
task = WatchClosestAITask.builder().chance(watchChance).maxDistance(maxDistance)
.watch(watch.getEntityClass()).build(agent);
break;
default:
queue.handleError(entry, "Invalid task type '" + type.debug() + "' in AddAITask command!");
return;
}
int priority;
if (entry.namedArgs.containsKey("priority")) {
priority = (int) IntegerTag.getFor(queue.error, entry.getNamedArgumentObject(queue, "priority")).getInternal();
}
else {
priority = 0;
}
GoalType goal;
if (entry.namedArgs.containsKey("goal")) {
TextTag goalType = TextTag.getFor(queue.error, entry.getNamedArgumentObject(queue, "goal"));
Optional<GoalType> opt = Sponge.getRegistry().getType(GoalType.class, goalType.getInternal());
if (opt.isPresent()) {
goal = opt.get();
}
else {
queue.handleError(entry, "Invalid goal type '" + goalType.debug() + "' in AddAITask command!");
return;
}
}
else {
goal = GoalTypes.NORMAL;
}
agent.getGoal(goal).get().addTask(priority, task);
if (queue.shouldShowGood()) {
queue.outGood("Added task of type '" + ColorSet.emphasis + type.debug()
+ ColorSet.good + "' to goal '" + ColorSet.emphasis + goal.getId()
+ ColorSet.good + "' of entity '" + ColorSet.emphasis + entityTag.debug()
+ ColorSet.good + "'!");
}
}
catch (ClassCastException e) {
queue.handleError(entry, "This entity doesn't support AI goals and tasks!");
}
}
}
@@ -0,0 +1,142 @@
package com.denizenscript.denizen2sponge.commands.entity;

import com.denizenscript.denizen2core.commands.AbstractCommand;
import com.denizenscript.denizen2core.commands.CommandEntry;
import com.denizenscript.denizen2core.commands.CommandQueue;
import com.denizenscript.denizen2core.tags.objects.TextTag;
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.living.Agent;

import java.util.Optional;

public class RemoveAITasksCommand extends AbstractCommand {

// <--[command]
// @Since 0.4.0
// @Name removeaitask
// @Arguments <entity> <task type>
// @Short removes AI tasks from an entity's goal.
// @Updated 2018/01/27
// @Group Entity
// @Minimum 2
// @Maximum 2
// @Named goal (TextTag) Sets to from which goal the tasks will be removed.
// @Description
// Removes all AI tasks of the specified type from an entity's goal.
// Related information: <@link explanation AI Goal Types>AI goal types<@/link>.
// Related information: <@link explanation AI Task Types>AI task types<@/link>.
// @Example
// # Makes the zombie in front of the player stop wandering around.
// - removeaitask <player.target_entities[type:zombie].get[1]> wander --goal normal
// -->

@Override
public String getName() {
return "removeaitask";
}

@Override
public String getArguments() {
return "<entity> <task type>";
}

@Override
public int getMinimumArguments() {
return 2;
}

@Override
public int getMaximumArguments() {
return 2;
}

@Override
public void execute(CommandQueue queue, CommandEntry entry) {
EntityTag entityTag = EntityTag.getFor(queue.error, entry.getArgumentObject(queue, 0));
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;
}
GoalType goal;
if (entry.namedArgs.containsKey("goal")) {
TextTag goalType = TextTag.getFor(queue.error, entry.getNamedArgumentObject(queue, "goal"));
Optional<GoalType> opt = Sponge.getRegistry().getType(GoalType.class, goalType.getInternal());
if (opt.isPresent()) {
goal = opt.get();
}
else {
queue.handleError(entry, "Invalid goal type '" + goalType.debug() + "' in RemoveAITask command!");
return;
}
}
else {
goal = GoalTypes.NORMAL;
}
Goal<Agent> agentGoal = agent.getGoal(goal).get();
for (Object obj : agentGoal.getTasks()) {
AITask<? extends Agent> task = (AITask<? extends Agent>) 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);
if (queue.shouldShowGood()) {
queue.outGood("Removed tasks of type '" + ColorSet.emphasis + type.debug()
+ ColorSet.good + "' from goal '" + ColorSet.emphasis + goal.getId()
+ ColorSet.good + "' of entity '" + ColorSet.emphasis + entityTag.debug()
+ ColorSet.good + "'!");
}
}
catch (ClassCastException e) {
queue.handleError(entry, "This entity doesn't support AI goals and tasks!");
}
}
}

0 comments on commit 0c1249c

Please sign in to comment.