From 23bd3875597f54925fe543ec755856735d6385d0 Mon Sep 17 00:00:00 2001 From: Jeremy Schroeder Date: Wed, 18 Sep 2013 07:38:57 -0400 Subject: [PATCH] Add some 'language' meta. --- .../aufdemrand/denizen/CommandHandler.java | 10 +- .../net/aufdemrand/denizen/objects/aH.java | 53 ++++- .../aufdemrand/denizen/objects/dScript.java | 196 +++++++++++++++--- .../denizen/scripts/ScriptRegistry.java | 3 +- .../scripts/containers/ScriptContainer.java | 137 +++++++++++- .../core/PlayerListenerScriptContainer.java | 28 +++ .../denizen/tags/core/ContextTags.java | 4 +- 7 files changed, 382 insertions(+), 49 deletions(-) create mode 100644 src/main/java/net/aufdemrand/denizen/scripts/containers/core/PlayerListenerScriptContainer.java diff --git a/src/main/java/net/aufdemrand/denizen/CommandHandler.java b/src/main/java/net/aufdemrand/denizen/CommandHandler.java index 32f916c311..b8093127f9 100644 --- a/src/main/java/net/aufdemrand/denizen/CommandHandler.java +++ b/src/main/java/net/aufdemrand/denizen/CommandHandler.java @@ -891,17 +891,17 @@ public void scripts(CommandContext args, CommandSender sender, NPC npc) throws C ScriptContainer scriptContainer = ScriptRegistry.getScriptContainer(script); // If a --type has been specified... if (type != null) { - if (scriptContainer.getType().equalsIgnoreCase(type)) + if (scriptContainer.getContainerType().equalsIgnoreCase(type)) if (filter != null) { if (script.contains(filter.toUpperCase())) - paginator.addLine("" + scriptContainer.getType().substring(0, 4) + " " + script); + paginator.addLine("" + scriptContainer.getContainerType().substring(0, 4) + " " + script); } - else paginator.addLine("" + scriptContainer.getType().substring(0, 4) + " " + script); + else paginator.addLine("" + scriptContainer.getContainerType().substring(0, 4) + " " + script); // If a --filter has been specified... } else if (filter != null) { if (script.contains(filter.toUpperCase())) - paginator.addLine("" + scriptContainer.getType().substring(0, 4) + " " + script); - } else paginator.addLine("" + scriptContainer.getType().substring(0, 4) + " " + script); + paginator.addLine("" + scriptContainer.getContainerType().substring(0, 4) + " " + script); + } else paginator.addLine("" + scriptContainer.getContainerType().substring(0, 4) + " " + script); } // Send the contents of the Paginator to the Player (or Console) if (!paginator.sendPage(sender, args.getInteger(1, 1))) diff --git a/src/main/java/net/aufdemrand/denizen/objects/aH.java b/src/main/java/net/aufdemrand/denizen/objects/aH.java index 5df508f386..e210b78aa8 100644 --- a/src/main/java/net/aufdemrand/denizen/objects/aH.java +++ b/src/main/java/net/aufdemrand/denizen/objects/aH.java @@ -11,6 +11,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; + /** * The dScript Argument Helper will aid you in parsing and formatting arguments from a * dScript argument string (such as those found in a ScriptEntry.getArguments() method). @@ -20,16 +21,43 @@ */ public class aH { + + //////////////////// + // Patterns and Enumerations + ///////////////// + public enum PrimitiveType { Float, Double, Integer, Boolean, String, Word, Percentage } final static Pattern floatPrimitive = Pattern.compile("^[-+]?[0-9]+[.]?[0-9]*([eE][-+]?[0-9]+)?$"); + // <--[language] + // @name number + // @description + // Many arguments in Denizen require the use of a 'number', or 'double'. Sometimes referred to as #.# or , + // this kind of hint can generally be filled with any reasonable positive or negative number with or without a + // decimal point. Numbers can be verified with the 'if' commands' 'matches' functionality. + // For example: - if matches double ... will return true if is a valid number. + // + // Denizen uses the regular expression pattern (-)?(?:(?:\d+)|)(?:(?:\.\d+)|) for number matching. + // --> final static Pattern doublePrimitive = Pattern.compile("(-)?(?:(?:\\d+)|)(?:(?:\\.\\d+)|)"); + // <--[language] + // @name percentage + // @description + // Promotes the usage of a 'percentage' format to be used in applicable arguments. The 'percentage' in Denizen is + // much like the 'number', except arguments which utilize percentages instead of numbers can also include a %. + // Percentage arguments can generally be filled with any reasonable positive or negative number with or without a + // decimal point and/or percentage sign. Argument hints and other usages will typically refer to a percentage as + // #.#% or . Percentages can be verified with the 'if' commands' 'matches' functionality. + // For example: - if matches percentage ... will return true if is a valid percentage. + // + // Denizen uses the regular expression pattern (?:(?:\d+)|)(?:(?:\.\d+)|)(%)? for percentage matching. + // --> final static Pattern percentagePrimitive = - Pattern.compile("(?:(?:\\d+)|)(?:(?:\\.\\d+)|)(%|)"); + Pattern.compile("(?:(?:\\d+)|)(?:(?:\\.\\d+)|)(%)?"); final static Pattern integerPrimitive = Pattern.compile("(-)?\\d+"); @@ -40,6 +68,11 @@ public enum PrimitiveType { Float, Double, Integer, Boolean, String, Word, Perce final static Pattern wordPrimitive = Pattern.compile("\\w+"); + + //////////////////// + // Argument Object + ////////////////// + public static class Argument { public String raw_value; String prefix = null; @@ -64,14 +97,17 @@ public Argument(String string) { // dB.log("Constructed Argument: " + prefix + ":" + value); } + public static Argument valueOf(String string) { return new Argument(string); } + public boolean startsWith(String string) { return value.toLowerCase().startsWith(string.toLowerCase()); } + public boolean hasPrefix() { return has_prefix; } @@ -82,6 +118,7 @@ public Argument getPrefix() { return valueOf(prefix); } + public boolean matches(String values) { for (String value : values.split(",")) if (value.trim().equalsIgnoreCase(this.value)) @@ -90,14 +127,17 @@ public boolean matches(String values) { return false; } + public void replaceValue(String string) { value = string; } + public String getValue() { return value; } + public boolean matchesEnum(Enum[] values) { for (Enum value : values) if (value.name().replace("_", "").equalsIgnoreCase(this.value.replace("_", ""))) @@ -106,6 +146,7 @@ public boolean matchesEnum(Enum[] values) { return false; } + public boolean matchesPrefix(String values) { if (!hasPrefix()) return false; for (String value : values.split(",")) @@ -115,6 +156,7 @@ public boolean matchesPrefix(String values) { return false; } + public boolean matchesPrimitive(PrimitiveType argumentType) { if (value == null) return false; @@ -144,6 +186,7 @@ public boolean matchesPrimitive(PrimitiveType argumentType) { return false; } + public boolean matchesArgumentType(Class dClass) { try { @@ -155,6 +198,7 @@ public boolean matchesArgumentType(Class dClass) { return false; } + // Check if this argument matches a dList of a certain dObject public boolean matchesArgumentList(Class dClass) { @@ -163,6 +207,7 @@ public boolean matchesArgumentList(Class dClass) { return list.filter(dClass) != null; } + public Element asElement() { return new Element(prefix, value); } @@ -193,6 +238,12 @@ public T asType(Class clazz) { } + + ///////////////// + // Static Methods + /////////////// + + /** * Turns a list of string arguments (separated by buildArgs) into Argument * Objects for easy matching and dObject creation throughout Denizen. diff --git a/src/main/java/net/aufdemrand/denizen/objects/dScript.java b/src/main/java/net/aufdemrand/denizen/objects/dScript.java index b94933258b..314a3a2333 100644 --- a/src/main/java/net/aufdemrand/denizen/objects/dScript.java +++ b/src/main/java/net/aufdemrand/denizen/objects/dScript.java @@ -11,6 +11,54 @@ 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 + // @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 prefix '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@script_name + // @description + // s@script_name refers to the object type and 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 + + final public static Pattern CONTAINER_PATTERN = Pattern.compile("(s@|)(.+)", Pattern.CASE_INSENSITIVE); @@ -43,10 +91,12 @@ public static boolean matches(String string) { return false; } - private ScriptContainer container; - private String prefix = "Container"; - private String name = null; - private boolean valid = false; + + + ////////////////// + // Constructor + //////////////// + /** * Creates a script object from a script name. If the script is valid, {@link #isValid()} will retrun true. @@ -54,8 +104,6 @@ public static boolean matches(String string) { * @param scriptName */ public dScript(String scriptName) { - // Required for tests - if (DenizenAPI.getCurrentInstance() == null) return; if (ScriptRegistry.getScriptContainer(scriptName) != null) { container = ScriptRegistry.getScriptContainer(scriptName); name = scriptName.toUpperCase(); @@ -63,6 +111,18 @@ public dScript(String scriptName) { } } + + + /////////////////////// + // Instance fields and methods + ///////////////////// + + private ScriptContainer container; + private String prefix = "Container"; + private String name = null; + private boolean valid = false; + + /** * Confirms that the script references a valid name and type in current loaded ScriptsContainers. * @@ -72,29 +132,16 @@ 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.getType() : "invalid"); + return (container != null ? container.getContainerType() : "invalid"); } - @Override - public String getObjectType() { - return "Container"; - } - - @Override - public String identify() { - return "s@" + name; - } - - @Override - public String toString() { - return identify(); - } /** * Gets the name of the ScriptContainer. @@ -105,6 +152,7 @@ public String getName() { return name; } + /** * Gets the contents of the scriptContainer. * @@ -114,11 +162,38 @@ 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 "" + prefix + "='" + name + "(" + getType() + ")' "; @@ -129,10 +204,8 @@ public boolean isUnique() { return true; } - @Override - public dObject setPrefix(String prefix) { - this.prefix = prefix; - return this; + public String colorless_debug() { + return prefix + "='" + name + "(" + getType() + ")'"; } @Override @@ -143,24 +216,28 @@ public String getAttribute(Attribute attribute) { // @attribute // @returns Element // @description - // Returns the container type of a dScript. + // Returns the type of script container that is associated with this dScript object. For example: 'task', or + // 'world' // --> - if (attribute.startsWith("container_type")) - return new Element(container.getType()) + if (attribute.startsWith("type")) + return new Element(container.getContainerType()) .getAttribute(attribute.fulfill(1)); // <--[tag] // @attribute ]> // @returns Element(Boolean) // @description - // Returns true if the script has been cooled down for the - // player (defaults to current). Otherwise, returns false. + // Returns true if the script is currently cooled down for the player, otherwise returns false. 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()); - return new Element(container.checkCooldown(player)) - .getAttribute(attribute.fulfill(1)); + if (player != null && player.isValid()) + return new Element(container.checkCooldown(player)) + .getAttribute(attribute.fulfill(1)); + else return "null"; } // <--[tag] @@ -194,6 +271,61 @@ public String getAttribute(Attribute attribute) { } + // <--[tag] + // @attribute + // @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 + // @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(colorless_debug()).getAttribute(attribute.fulfill(1)); + } + + // <--[tag] + // @attribute + // @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 + // @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); } diff --git a/src/main/java/net/aufdemrand/denizen/scripts/ScriptRegistry.java b/src/main/java/net/aufdemrand/denizen/scripts/ScriptRegistry.java index 204ad81216..d0ef7830ed 100644 --- a/src/main/java/net/aufdemrand/denizen/scripts/ScriptRegistry.java +++ b/src/main/java/net/aufdemrand/denizen/scripts/ScriptRegistry.java @@ -33,6 +33,7 @@ public static void _registerCoreTypes() { _registerType("world", WorldScriptContainer.class); _registerType("format", FormatScriptContainer.class); _registerType("inventory", InventoryScriptContainer.class); + _registerType("player listener", PlayerListenerScriptContainer.class); } public static boolean containsScript(String id) { @@ -47,7 +48,7 @@ public static boolean containsScript(String id, Class scriptContainerType) { if (entry.getValue() == scriptContainerType) type = entry.getKey(); } - return type != null && (script.getType().equalsIgnoreCase(type)); + return type != null && (script.getContainerType().equalsIgnoreCase(type)); } public static void _buildCoreYamlScriptContainers(FileConfiguration yamlScripts) { diff --git a/src/main/java/net/aufdemrand/denizen/scripts/containers/ScriptContainer.java b/src/main/java/net/aufdemrand/denizen/scripts/containers/ScriptContainer.java index ecd37cfb16..96e51d52eb 100644 --- a/src/main/java/net/aufdemrand/denizen/scripts/containers/ScriptContainer.java +++ b/src/main/java/net/aufdemrand/denizen/scripts/containers/ScriptContainer.java @@ -16,60 +16,181 @@ public class ScriptContainer { + // <--[language] + // @name Script Container + // @description + // Script Containers are the basic structure that Denizen uses inside its YAML-based scripting files found in your + // plugins/Denizen/scripts/ folder. Regardless of type, all script containers have basic parts that can usually be + // described as keys, list keys, parent keys, child keys, values, and list values. While specific container types + // probably have more specific names, just remember that no matter how complicated a script, this basic structure + // still applies. + // + // It’s important to keep in mind that all child keys, including all the main keys of the script, must line up with + // one another, hierarchically. If you are familiar with YAML, great, because all script containers use it at the + // core. Every value, in one way or another, belongs to some kind of ‘key’. To define a key, use a string value plus + // a colon (:). Keys can have a single value, a list value, or own another key: + // + // + // script name: + // key: value + // list key: + // - list value + // - ... + // parent key: + // child key: value + // + // + // And here's a container, put into a more familiar context: + // + // + // a haiku script: + // type: task + // script: + // - narrate "A simple script," + // - narrate "with a key value relationship." + // - narrate "Oh look, a list!" + // + // + // --> + + public ScriptContainer(ConfigurationSection configurationSection, String scriptContainerName) { contents = configurationSection; this.name = scriptContainerName.toUpperCase(); } + + // The contents of the script container ConfigurationSection contents; + /** + * Gets the contents of the container. + * + * @return a ConfigurationSection object + */ public ConfigurationSection getContents() { return contents; } + + /** + * Casts this container to a specify type of script container. Must be a valid + * container type of the type casting to. + * + * @param type the class of the ScriptContainer casting to + * @param the ScriptContainer object + * @return a ScriptContainer of the type specified + */ public T getAsContainerType(Class type) { return (T) type.cast(this); } + + // <--[language] + // @name Script Name + // @description + // Typically refers to the name of a script container. When using the object fetcher with dScript objects, + // (s@script_name), the script_name referred to is the name of the container. + // + // + // script name: <--- script name + // type: script_type + // script: <--- base script + // - script entries + // - ... + // local script: <--- local script path + // - script entries + // - ... + // + // + // --> + + // The name of the script container private String name; + /** + * Gets the name of the script container. + * + * @return the script container name. + */ + public String getName() { + return name; + } + + + /** + * Gets a dScript object that represents this container. + * + * @return a dScript object linking this script container. + */ public dScript getAsScriptArg() { return dScript.valueOf(name); } - public String getType() { - if (contents.contains("TYPE")) - return contents.getString("TYPE").toUpperCase(); - else return null; - } + // <--[language] + // @name Script Type + // @description + // The type of container that a script is in. For example, 'task script' is a script type that has some sort of + // utility script or + // + // + // script name: + // type: script_type <--- script type + // script: + // - script entries + // - ... + // + // + // --> + + /** + * Gets the value of the type: node specified in the script container structure. + * + * @return the type of container + */ + public String getContainerType() { + return contents.contains("TYPE") + ? contents.getString("TYPE").toUpperCase() + : null; + } + + + /** + * Checks the ConfigurationSection for the key/path to key specified. + * + * @param path the path of the key + * @return true if the key exists + */ public boolean contains(String path) { return contents.contains(path.toUpperCase()); } + public String getString(String path) { return contents.getString(path.toUpperCase()); } + public String getString(String path, String def) { return contents.getString(path.toUpperCase(), def); } + public List getStringList(String path) { return contents.getStringList(path.toUpperCase()); } + public ConfigurationSection getConfigurationSection(String path) { return contents.getConfigurationSection(path.toUpperCase()); } + public void set(String path, Object object) { contents.set(path.toUpperCase(), object); } - public String getName() { - return name; - } public boolean checkBaseRequirements(dPlayer player, dNPC npc) { return checkRequirements(player, npc, ""); diff --git a/src/main/java/net/aufdemrand/denizen/scripts/containers/core/PlayerListenerScriptContainer.java b/src/main/java/net/aufdemrand/denizen/scripts/containers/core/PlayerListenerScriptContainer.java new file mode 100644 index 0000000000..d2e840b583 --- /dev/null +++ b/src/main/java/net/aufdemrand/denizen/scripts/containers/core/PlayerListenerScriptContainer.java @@ -0,0 +1,28 @@ +package net.aufdemrand.denizen.scripts.containers.core; + +import net.aufdemrand.denizen.Settings; +import net.aufdemrand.denizen.objects.Duration; +import net.aufdemrand.denizen.objects.dNPC; +import net.aufdemrand.denizen.objects.dPlayer; +import net.aufdemrand.denizen.scripts.ScriptBuilder; +import net.aufdemrand.denizen.scripts.ScriptEntry; +import net.aufdemrand.denizen.scripts.containers.ScriptContainer; +import net.aufdemrand.denizen.scripts.queues.ScriptQueue; +import net.aufdemrand.denizen.scripts.queues.core.InstantQueue; +import net.aufdemrand.denizen.scripts.queues.core.TimedQueue; +import org.bukkit.configuration.ConfigurationSection; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class PlayerListenerScriptContainer extends ScriptContainer { + + public PlayerListenerScriptContainer(ConfigurationSection configurationSection, String scriptContainerName) { + super(configurationSection, scriptContainerName); + } + + // WIP + +} diff --git a/src/main/java/net/aufdemrand/denizen/tags/core/ContextTags.java b/src/main/java/net/aufdemrand/denizen/tags/core/ContextTags.java index 866831270f..7b1f550b47 100644 --- a/src/main/java/net/aufdemrand/denizen/tags/core/ContextTags.java +++ b/src/main/java/net/aufdemrand/denizen/tags/core/ContextTags.java @@ -47,7 +47,7 @@ public void scriptTags(ReplaceableTagEvent event) { } else if (type.equalsIgnoreCase("TYPE")) { - event.setReplaced(script.getType()); + event.setReplaced(script.getContainerType()); } else if (type.equalsIgnoreCase("SPEED")) { @@ -129,4 +129,4 @@ public void savedEntryTags(ReplaceableTagEvent event) { else event.setReplaced("null"); } -} +}