This repository has been archived by the owner on Apr 12, 2022. It is now read-only.
/
AddAITaskCommand.java
202 lines (190 loc) · 10.7 KB
/
AddAITaskCommand.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
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>.
// 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 <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!");
}
}
}