-
-
Notifications
You must be signed in to change notification settings - Fork 104
/
dScript.java
339 lines (272 loc) · 11.4 KB
/
dScript.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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
package net.aufdemrand.denizen.objects;
import net.aufdemrand.denizen.scripts.ScriptRegistry;
import net.aufdemrand.denizen.scripts.commands.core.CooldownCommand;
import net.aufdemrand.denizen.scripts.containers.ScriptContainer;
import net.aufdemrand.denizen.tags.Attribute;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class dScript implements dObject {
// <--[language]
// @name Script
// @description
// A somewhat vague term used to describe a collection of script entries and other script parts.
//
// For example, 'Hey, check out this script I just wrote!', probably refers to a collection of script entries
// that make up some kind of script container. Perhaps it is a NPC Assignment Script Container that provides
// waypoint functionality, or a world script that implements and keeps track of a new player stat. 'Script' can
// refer to a single container, as well as a collection of containers that share a common theme.
//
// Scripts that contain a collection of containers are typically kept to a single file. Multiple containers are
// permitted inside a single file, but it should be noted that container names are stored on a global level. That
// is, naming scripts should be done with care to avoid duplicate script names.
//
// -->
// <--[language]
// @name dScript
// @group Object System
// @description
// 1) A dObject that represents a script container. dScripts contain all information inside the script, and can be
// used in a variety of commands that require script arguments. For example, run and inject will 'execute'
// script entries inside of a script container when given a matching dScript object.
//
// dScripts also provide a way to access attributes accessed by the replaceable tag system by using the object
// fetcher or any other entry point to a dScript object. dScript objects have the object identifier of 's@'.
// For example: s@script_name
//
// 2) The overall 'scripting language' that Denizen implements is referred to as 'dScripting', or 'dScript'.
// dScripts use YAML + Denizen's Scripting API to parse scripts that are stored as .yml or .dscript files. Scripts
// go in the .../plugins/Denizen/scripts folder.
//
// -->
///////////////
// Object Fetcher
/////////////
// <--[language]
// @name s@
// @group Object Fetcher System
// @description
// s@ refers to the 'object identifier' of a dScript. The 's@' is notation for Denizen's Object
// Fetcher. The only valid constructor for a dScript is the name of the script container that it should be
// associated with. For example, if my script container is called 'cool_script', the dScript object for that script
// would be able to be referenced (fetched) with s@cool_script.
// -->
final public static Pattern CONTAINER_PATTERN = Pattern.compile("(s@|)(.+)",
Pattern.CASE_INSENSITIVE);
/**
* Gets a dContainer Object from a dScript argument.
*
* @param string the dScript argument String
* @return a Script, or null if incorrectly formatted
*/
@Fetchable("s")
public static dScript valueOf(String string) {
Matcher m = CONTAINER_PATTERN.matcher(string);
if (m.matches()) {
dScript script = new dScript(m.group(2));
// Make sure it's valid.
if (script.isValid()) return script;
}
return null;
}
public static boolean matches(String string) {
if (string.toLowerCase().startsWith("s@")) return true;
Matcher m = CONTAINER_PATTERN.matcher(string);
if (m.matches()) {
dScript script = new dScript(m.group(2));
// Make sure it's valid.
if (script.isValid()) return true;
}
return false;
}
//////////////////
// Constructor
////////////////
/**
* Creates a script object from a script name. If the script is valid, {@link #isValid()} will retrun true.
*
* @param scriptName
*/
public dScript(String scriptName) {
if (ScriptRegistry.getScriptContainer(scriptName) != null) {
container = ScriptRegistry.getScriptContainer(scriptName);
name = scriptName.toUpperCase();
valid = true;
}
}
///////////////////////
// Instance fields and methods
/////////////////////
// Keep track of the corresponding ScriptContainer
private ScriptContainer container;
// Make the default prefix "Container"
private String prefix = "Container";
private boolean valid = false;
/**
* Confirms that the script references a valid name and type in current loaded ScriptsContainers.
*
* @return true if the script is valid, false if the script was not found, or the type is missing
*/
public boolean isValid() {
return valid;
}
/**
* Gets the type of the ScriptContainer, as defined by the TYPE: key.
*
* @return the type of the Script Container
*/
public String getType() {
return (container != null ? container.getContainerType() : "invalid");
}
private String name = null;
/**
* Gets the name of the ScriptContainer.
*
* @return script name
*/
public String getName() {
return name;
}
/**
* Gets the contents of the scriptContainer.
*
* @return ConfigurationSection of the script contents
*/
public ScriptContainer getContainer() {
return container;
}
///////////////
// dObject Methods
////////////
@Override
public String getObjectType() {
return "Container";
}
@Override
public String identify() {
return "s@" + name;
}
@Override
public String toString() {
return identify();
}
@Override
public String getPrefix() {
return prefix;
}
@Override
public dObject setPrefix(String prefix) {
this.prefix = prefix;
return this;
}
@Override
public String debug() {
return "<G>" + prefix + "='<A>" + name + "<Y>(" + getType() + ")<G>' ";
}
@Override
public boolean isUnique() {
return true;
}
@Override
public String getAttribute(Attribute attribute) {
if (attribute == null) return "null";
// <--[tag]
// @attribute <s@script.container_type>
// @returns Element
// @description
// Returns the type of script container that is associated with this dScript object. For example: 'task', or
// 'world'.
// -->
if (attribute.startsWith("container_type") || attribute.startsWith("type"))
return new Element(container.getContainerType())
.getAttribute(attribute.fulfill(1));
// <--[tag]
// @attribute <s@script.cooled_down[<player>]>
// @returns Element(Boolean)
// @description
// Returns whether the script is currently cooled down for the player. Any global
// cooldown present on the script will also be taken into account. Not specifying a player will result in
// using the attached player available in the script entry. Not having a valid player will result in 'null'.
// -->
if (attribute.startsWith("cooled_down")) {
dPlayer player = (attribute.hasContext(1) ? dPlayer.valueOf(attribute.getContext(1))
: attribute.getScriptEntry().getPlayer());
if (player != null && player.isValid())
return new Element(container.checkCooldown(player))
.getAttribute(attribute.fulfill(1));
else return "null";
}
// <--[tag]
// @attribute <s@script.requirements[<player>].check[<path>]>
// @returns Element
// @description
// Returns whether the player specified (defaults to current) has the requirement.
// -->
if (attribute.startsWith("requirements.check")) {
dPlayer player = (attribute.hasContext(1) ? dPlayer.valueOf(attribute.getContext(1))
: attribute.getScriptEntry().getPlayer());
if (attribute.hasContext(2))
return new Element(container.checkRequirements(player,
attribute.getScriptEntry().getNPC(),
attribute.getContext(2)))
.getAttribute(attribute.fulfill(2));
}
// <--[tag]
// @attribute <s@script.cooldown[<player>]>
// @returns Duration
// @description
// Returns the time left for the player to cooldown for the script.
// -->
if (attribute.startsWith("cooldown")) {
dPlayer player = (attribute.hasContext(1) ? dPlayer.valueOf(attribute.getContext(1))
: attribute.getScriptEntry().getPlayer());
return CooldownCommand.getCooldownDuration((player != null ? player.getName() : null), container.getName())
.getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <s@script.name>
// @returns Element
// @description
// Returns the name of the script container.
// -->
if (attribute.startsWith("name")) {
return new Element(name)
.getAttribute(attribute.fulfill(1));
}
/////////////////
// dObject attributes
///////////////
// <--[tag]
// @attribute <s@script.debug>
// @returns Element
// @description
// Returns the debug entry for this object. This contains the prefix, the name of the dScript object, and the
// type of ScriptContainer is held within. All objects fetchable by the Object Fetcher will return a valid
// debug entry for the object that is fulfilling this attribute.
// -->
if (attribute.startsWith("debug")) {
return new Element(debug()).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <s@script.prefix>
// @returns Element
// @description
// Returns the prefix for this object. By default this will return 'Script', however certain situations will
// return a finer scope. All objects fetchable by the Object Fetcher will return a valid prefix for the object
// that is fulfilling this attribute.
// -->
if (attribute.startsWith("prefix")) {
return new Element(prefix).getAttribute(attribute.fulfill(1));
}
// <--[tag]
// @attribute <s@script.object_type>
// @returns Element
// @description
// Always returns 'Script' for dScript objects. All objects fetchable by the Object Fetcher will return a the
// type of object that is fulfilling this attribute.
// -->
if (attribute.startsWith("object_type")) {
return new Element(getObjectType()).getAttribute(attribute.fulfill(1));
}
return new Element(identify()).getAttribute(attribute);
}
}