/
BreakCommand.java
163 lines (141 loc) · 6.08 KB
/
BreakCommand.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
package com.denizenscript.denizen.scripts.commands.npc;
import com.denizenscript.denizen.utilities.DenizenAPI;
import com.denizenscript.denizen.utilities.Utilities;
import com.denizenscript.denizen.utilities.debugging.Debug;
import com.denizenscript.denizen.objects.LocationTag;
import com.denizenscript.denizen.objects.MaterialTag;
import com.denizenscript.denizen.objects.NPCTag;
import com.denizenscript.denizencore.exceptions.InvalidArgumentsException;
import com.denizenscript.denizencore.objects.Argument;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.ArgumentHelper;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.scripts.ScriptEntry;
import com.denizenscript.denizencore.scripts.commands.AbstractCommand;
import com.denizenscript.denizencore.scripts.commands.Holdable;
import net.citizensnpcs.api.ai.tree.BehaviorStatus;
import net.citizensnpcs.api.npc.BlockBreaker;
import org.bukkit.Bukkit;
import java.util.HashMap;
public class BreakCommand extends AbstractCommand implements Holdable {
// <--[command]
// @Name Break
// @Syntax break [<location>] (<npc>) (radius:<#.#>)
// @Required 1
// @Plugin Citizens
// @Short Makes an NPC walk over and break a block.
// @Group npc
//
// @Description
// By itself, the 'break' command will act as an NPC command in the sense that an attached
// NPC will navigate to and break the block at the attached location. It can also accept a specified npc,
// to fulfill the command, just specify a 'fetchable' npc object. It can also accept a radius to start
// breaking the block from within. To specify the radius, prefix the radius with 'radius:'.
//
// The break command is ~waitable. Refer to <@link language ~waitable>.
//
// @Tags
// <NPCTag.is_navigating>
// <NPCTag.target_location>
//
// @Usage
// Use to make the npc break a related block.
// - break <context.location>
//
// @Usage
// Use to make a different NPC break a related block.
// - break <context.location> <[some_npc]>
//
// @Usage
// Use to make a different NPC break a related block and start digging from 5 blocks away.
// - break <context.location> <[some_npc]> radius:5
// -->
@Override
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException {
for (Argument arg : scriptEntry.getProcessedArgs()) {
if (!scriptEntry.hasObject("location")
&& arg.matchesArgumentType(LocationTag.class)) {
scriptEntry.addObject("location", arg.asType(LocationTag.class));
}
else if (!scriptEntry.hasObject("npc")
&& arg.matchesArgumentType(NPCTag.class)) {
scriptEntry.addObject("npc", arg.asType(NPCTag.class));
}
else if (!scriptEntry.hasObject("radius")
&& arg.matchesPrimitive(ArgumentHelper.PrimitiveType.Double)) {
scriptEntry.addObject("radius", arg.asElement());
}
else {
arg.reportUnhandled();
}
}
// Make sure location and entity were fulfilled
if (!scriptEntry.hasObject("location")) {
throw new InvalidArgumentsException("Must specify a location!");
}
// Use the NPC or the Player as the default entity
if (!scriptEntry.hasObject("npc")) {
if (Utilities.entryHasNPC(scriptEntry)) {
scriptEntry.addObject("npc", Utilities.getEntryNPC(scriptEntry));
}
else {
throw new InvalidArgumentsException("Must specify a valid NPC!");
}
}
scriptEntry.defaultObject("radius", new ElementTag(2));
}
// <--[action]
// @Actions
// dig
//
// @Triggers when the NPC breaks a block with the Break Command
//
// @Context
// <context.location> returns the location the NPC Dug
// <context.material> Returns the Block dug
//
// -->
@Override
public void execute(ScriptEntry scriptEntry) {
final LocationTag location = (LocationTag) scriptEntry.getObject("location");
final NPCTag npc = (NPCTag) scriptEntry.getObject("npc");
ElementTag radius = scriptEntry.getElement("radius");
final HashMap<String, ObjectTag> context = new HashMap<>();
MaterialTag material = new MaterialTag(location.getBlock());
context.put("location", location);
context.put("material", material);
if (scriptEntry.dbCallShouldDebug()) {
Debug.report(scriptEntry, getName(), location.debug() + npc.debug() + radius.debug());
}
final ScriptEntry se = scriptEntry;
BlockBreaker.BlockBreakerConfiguration config = new BlockBreaker.BlockBreakerConfiguration();
config.item(npc.getLivingEntity().getEquipment().getItemInHand());
config.radius(radius.asDouble());
config.callback(new Runnable() {
@Override
public void run() {
npc.action("dig", null, context);
se.setFinished(true);
}
});
BlockBreaker breaker = npc.getCitizen().getBlockBreaker(location.getBlock(), config);
if (breaker.shouldExecute()) {
TaskRunnable run = new TaskRunnable(breaker);
run.taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(DenizenAPI.getCurrentInstance(), run, 0, 1);
}
}
private static class TaskRunnable implements Runnable {
private int taskId;
private final BlockBreaker breaker;
public TaskRunnable(BlockBreaker breaker) {
this.breaker = breaker;
}
@Override
public void run() {
if (breaker.run() != BehaviorStatus.RUNNING) {
Bukkit.getScheduler().cancelTask(taskId);
breaker.reset();
}
}
}
}