/
ZapCommand.java
170 lines (144 loc) · 8.13 KB
/
ZapCommand.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
package net.aufdemrand.denizen.scripts.commands.core;
import net.aufdemrand.denizen.exceptions.CommandExecutionException;
import net.aufdemrand.denizen.exceptions.InvalidArgumentsException;
import net.aufdemrand.denizen.objects.Element;
import net.aufdemrand.denizen.objects.dScript;
import net.aufdemrand.denizen.scripts.ScriptEntry;
import net.aufdemrand.denizen.scripts.commands.AbstractCommand;
import net.aufdemrand.denizen.scripts.containers.core.InteractScriptHelper;
import net.aufdemrand.denizen.objects.Duration;
import net.aufdemrand.denizen.objects.aH;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.aufdemrand.denizen.utilities.debugging.dB.Messages;
import org.bukkit.event.Listener;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* <p>Changes a Player's current step for a script. Reminder: ZAP does NOT trigger anything. It merely
* tells Denizen's ScriptEngine which step should be used WHEN interacting.</p>
*
* <b>dScript Usage:</b><br>
* <pre>ZAP [#|STEP:step_name] (SCRIPT:script_name{current_script}) (DURATION:#{0})</pre>
*
* <ol><tt>Arguments: [] - Required () - Optional {} - Default</ol></tt>
*
* <ol><tt>[#|STEP:step_name]</tt><br>
* The name of the step that should be enabled. If using numbered steps, an plain integer will
* suffice.</ol>
*
* <ol><tt>(SCRIPT:script_name{current_script})</tt><br>
* Specifies which script should be affected. If not specified, the current interact script will
* be used.</ol>
*
* <ol><tt>(DURATION:#{0})</tt><br>
* Optional. If not specified, no duration is used. If specified, after the duration period,
* Denizen will automatically reset the step to the original step. Note: If another ZAP command
* is utilized for the same Player and Script during a duration period, the reset in progress
* is cancelled.</ol>
*
* <br><b>Example Usage:</b><br>
* <ol><tt>
* - ZAP SCRIPT:OtherScript 6<br>
* - ZAP 'STEP:Just for a minute' DURATION:1m<br>
* </ol></tt>
*
* @author Jeremy Schroeder
*/
public class ZapCommand extends AbstractCommand implements Listener{
@Override
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException {
for (aH.Argument arg : aH.interpret(scriptEntry.getArguments())) {
// If the scripter uses the 'script:step' format, handle it.
if (!scriptEntry.hasObject("script")
&& !scriptEntry.hasObject("step")
&& arg.hasPrefix()
&& arg.getPrefix().matchesArgumentType(dScript.class)) {
scriptEntry.addObject("script", arg.getPrefix().asType(dScript.class));
scriptEntry.addObject("step", arg.asElement());
}
// If a script is found, use that to ZAP
else if (!scriptEntry.hasObject("script")
&& arg.matchesArgumentType(dScript.class)
&& !arg.matchesPrefix("step"))
scriptEntry.addObject("script", arg.asType(dScript.class));
// Add argument as step
else if (!scriptEntry.hasObject("step"))
scriptEntry.addObject("step", arg.asElement());
// Lastly duration
else if (!scriptEntry.hasObject("duration")
&& arg.matchesArgumentType(Duration.class))
scriptEntry.addObject("duration", arg.asType(Duration.class));
}
// Add default script if none was specified.
scriptEntry.defaultObject("script", scriptEntry.getScript());
// Check if player is valid
if (!scriptEntry.hasPlayer() || !scriptEntry.getPlayer().isValid())
throw new InvalidArgumentsException("Must have player context!");
}
//"PlayerName,ScriptName", TaskID
private static Map<String, Integer> durations = new ConcurrentHashMap<String, Integer>(8, 0.9f, 1);
@Override
public void execute(final ScriptEntry scriptEntry) throws CommandExecutionException {
final dScript script = (dScript) scriptEntry.getObject("script");
Duration duration = (Duration) scriptEntry.getObject("duration");
dB.report(getName(), scriptEntry.getPlayer().debug() + script.debug()
+ (scriptEntry.hasObject("step")
? scriptEntry.getElement("step").debug() : aH.debugObj("step", "++ (inc)"))
+ (duration != null ? duration.debug() : ""));
String step = scriptEntry.hasObject("step") ? scriptEntry.getElement("step").asString() : null;
// Let's get the current step for reference.
String currentStep = InteractScriptHelper.getCurrentStep(scriptEntry.getPlayer(), script.getName());
// Special-case for backwards compatibility: ability to use ZAP to count up steps.
if (step == null) {
// Okay, no step was identified.. that means we should count up,
// ie. if currentStep = 1, new step should = 2
// If the currentStep is a number, increment it. If not, set it
// to '1' so it can be incremented next time.
if (aH.matchesInteger(currentStep)) {
step = String.valueOf(aH.getIntegerFrom(currentStep) + 1);
} else step = "1";
}
// If the durationsMap already contains an entry for this player/script combination,
// cancel the task since it's probably not desired to change back anymore if another
// ZAP for this script is taking place.
if (durations.containsKey(scriptEntry.getPlayer().getName() + "," + script.getName()))
try {
denizen.getServer().getScheduler().cancelTask(durations.get(scriptEntry.getPlayer().getName() + "," + script.getName()));
} catch (Exception e) { }
// One last thing... check for duration.
if (duration != null && duration.getSeconds() > 0) {
// If a DURATION is specified, the currentStep should be remembered and
// restored after the duration.
scriptEntry.addObject("step", new Element(currentStep));
// And let's take away the duration that was set to avoid a re-duration
// inception-ion-ion-ion-ion... ;)
scriptEntry.addObject("duration", Duration.ZERO);
// Now let's add a delayed task to set it back after the duration
// Delays are in ticks, so let's multiply our duration (which is in seconds) by 20.
// 20 ticks per second.
long delay = (long) (duration.getSeconds() * 20);
// Set delayed task and put id in a map
dB.echoDebug(Messages.DEBUG_SETTING_DELAYED_TASK, "RESET ZAP for '" + script + "'");
durations.put(scriptEntry.getPlayer().getName() + "," + script.getName(),
denizen.getServer().getScheduler().scheduleSyncDelayedTask(denizen,
new Runnable() {
@Override
public void run() {
dB.log(Messages.DEBUG_RUNNING_DELAYED_TASK, "RESET ZAP for '" + script.getName() + "'");
try {
durations.remove(scriptEntry.getPlayer().getName() + "," + script.getName().toUpperCase());
execute(scriptEntry);
} catch (CommandExecutionException e) {
dB.echoError("Could not run delayed task!");
if (dB.showStackTraces) e.printStackTrace();
}
}
}, delay));
}
//
// FINALLY! ZAP! Change the step in Saves... your step is now ZAPPED!
// Fun fact: ZAP is named in homage of ZZT-OOPs ZAP command. Google it.
//
denizen.getSaves().set("Players." + scriptEntry.getPlayer().getName() + ".Scripts." + script.getName().toUpperCase() + "." + "Current Step", step);
}
}