├── .gitattributes ├── .github ├── FUNDING.yml └── issue_template.md ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── denizenscript │ └── denizencore │ ├── DenizenCore.java │ ├── DenizenImplementation.java │ ├── events │ ├── ScriptEvent.java │ ├── ScriptEventCouldMatcher.java │ └── core │ │ ├── ConsoleOutputScriptEvent.java │ │ ├── CustomScriptEvent.java │ │ ├── DeltaTimeScriptEvent.java │ │ ├── PreScriptReloadScriptEvent.java │ │ ├── RedisPubSubMessageScriptEvent.java │ │ ├── ReloadScriptsScriptEvent.java │ │ ├── ScriptGeneratesErrorScriptEvent.java │ │ ├── ScriptsLoadedScriptEvent.java │ │ ├── ServerGeneratesExceptionScriptEvent.java │ │ ├── ShutdownScriptEvent.java │ │ ├── SystemTimeScriptEvent.java │ │ ├── TickScriptEvent.java │ │ └── WebserverWebRequestScriptEvent.java │ ├── exceptions │ ├── InvalidArgumentsException.java │ ├── InvalidArgumentsRuntimeException.java │ ├── TagProcessingException.java │ └── Unreachable.java │ ├── flags │ ├── AbstractFlagTracker.java │ ├── FlaggableObject.java │ ├── MapTagBasedFlagTracker.java │ ├── MapTagFlagTracker.java │ ├── RedirectionFlagTracker.java │ └── SavableMapFlagTracker.java │ ├── objects │ ├── Adjustable.java │ ├── Argument.java │ ├── ArgumentHelper.java │ ├── Fetchable.java │ ├── Mechanism.java │ ├── ObjectFetcher.java │ ├── ObjectTag.java │ ├── ObjectType.java │ ├── core │ │ ├── BinaryTag.java │ │ ├── ColorTag.java │ │ ├── CustomObjectTag.java │ │ ├── DurationTag.java │ │ ├── ElementTag.java │ │ ├── ImageTag.java │ │ ├── JavaReflectedObjectTag.java │ │ ├── ListTag.java │ │ ├── MapTag.java │ │ ├── QuaternionTag.java │ │ ├── QueueTag.java │ │ ├── ScriptTag.java │ │ ├── SecretTag.java │ │ ├── TimeTag.java │ │ └── VectorObject.java │ ├── notable │ │ ├── Notable.java │ │ ├── Note.java │ │ └── NoteManager.java │ └── properties │ │ ├── ObjectProperty.java │ │ ├── Property.java │ │ └── PropertyParser.java │ ├── scripts │ ├── ScriptBuilder.java │ ├── ScriptEntry.java │ ├── ScriptEntryData.java │ ├── ScriptEntrySet.java │ ├── ScriptHelper.java │ ├── ScriptRegistry.java │ ├── commands │ │ ├── AbstractCommand.java │ │ ├── BracedCommand.java │ │ ├── CommandExecutor.java │ │ ├── CommandRegistry.java │ │ ├── Comparable.java │ │ ├── Holdable.java │ │ ├── core │ │ │ ├── AdjustCommand.java │ │ │ ├── CustomEventCommand.java │ │ │ ├── DebugCommand.java │ │ │ ├── DebugInvalidCommand.java │ │ │ ├── DrawCommand.java │ │ │ ├── FlagCommand.java │ │ │ ├── ImageCommand.java │ │ │ ├── MongoCommand.java │ │ │ ├── NoteCommand.java │ │ │ ├── RedisCommand.java │ │ │ ├── ReflectionSetCommand.java │ │ │ ├── ReloadCommand.java │ │ │ ├── SQLCommand.java │ │ │ ├── WebGetCommand.java │ │ │ └── WebServerCommand.java │ │ ├── file │ │ │ ├── FileCopyCommand.java │ │ │ ├── FileReadCommand.java │ │ │ ├── FileWriteCommand.java │ │ │ ├── LogCommand.java │ │ │ └── YamlCommand.java │ │ ├── generator │ │ │ ├── ArgDefaultNull.java │ │ │ ├── ArgDefaultText.java │ │ │ ├── ArgLinear.java │ │ │ ├── ArgName.java │ │ │ ├── ArgNoDebug.java │ │ │ ├── ArgPrefixed.java │ │ │ ├── ArgRaw.java │ │ │ ├── ArgSubType.java │ │ │ ├── ArgUnparsed.java │ │ │ └── CommandExecutionGenerator.java │ │ └── queue │ │ │ ├── ChooseCommand.java │ │ │ ├── DefineCommand.java │ │ │ ├── DefineMapCommand.java │ │ │ ├── DetermineCommand.java │ │ │ ├── ElseCommand.java │ │ │ ├── ForeachCommand.java │ │ │ ├── GotoCommand.java │ │ │ ├── IfCommand.java │ │ │ ├── InjectCommand.java │ │ │ ├── MarkCommand.java │ │ │ ├── QueueCommand.java │ │ │ ├── RandomCommand.java │ │ │ ├── RateLimitCommand.java │ │ │ ├── RepeatCommand.java │ │ │ ├── RunCommand.java │ │ │ ├── RunLaterCommand.java │ │ │ ├── StopCommand.java │ │ │ ├── WaitCommand.java │ │ │ ├── WaitUntilCommand.java │ │ │ └── WhileCommand.java │ ├── containers │ │ ├── ScriptContainer.java │ │ └── core │ │ │ ├── CustomScriptContainer.java │ │ │ ├── DataScriptContainer.java │ │ │ ├── ProcedureScriptContainer.java │ │ │ ├── TaskScriptContainer.java │ │ │ └── WorldScriptContainer.java │ └── queues │ │ ├── ContextSource.java │ │ ├── DeterminationTarget.java │ │ ├── ScriptEngine.java │ │ ├── ScriptQueue.java │ │ └── core │ │ ├── InstantQueue.java │ │ └── TimedQueue.java │ ├── tags │ ├── Attribute.java │ ├── CoreObjectTags.java │ ├── ObjectTagProcessor.java │ ├── ParseableTag.java │ ├── PseudoObjectTagBase.java │ ├── ReplaceableTagEvent.java │ ├── TagContext.java │ ├── TagManager.java │ ├── TagRunnable.java │ └── core │ │ ├── ContextTagBase.java │ │ ├── CoreTextTagBases.java │ │ ├── DefinitionTagBase.java │ │ ├── EscapeTagUtil.java │ │ ├── ListSingleTagBase.java │ │ ├── ListTagBase.java │ │ ├── MapTagBase.java │ │ ├── ProcedureScriptTagBase.java │ │ ├── QueueTagBase.java │ │ ├── ScriptTagBase.java │ │ ├── StaticTagBase.java │ │ ├── TernaryTagBase.java │ │ └── UtilTagBase.java │ └── utilities │ ├── AsciiMatcher.java │ ├── CoreConfiguration.java │ ├── CoreUtilities.java │ ├── DefinitionProvider.java │ ├── DenizenJedisPubSub.java │ ├── Deprecations.java │ ├── EnumHelper.java │ ├── ExCommandHelper.java │ ├── ListQueue.java │ ├── NaturalOrderComparator.java │ ├── PropertyMatchHelper.java │ ├── QueueWordList.java │ ├── RedisHelper.java │ ├── ReflectionHelper.java │ ├── ReflectionRefuse.java │ ├── RomanNumerals.java │ ├── SQLEscaper.java │ ├── ScriptUtilities.java │ ├── SimpleDefinitionProvider.java │ ├── SimplexNoise.java │ ├── YamlConfiguration.java │ ├── codegen │ ├── CodeGenUtil.java │ ├── DenizenCodeGenException.java │ ├── MethodGenerator.java │ ├── TagCodeGenerator.java │ └── TagNamer.java │ ├── data │ ├── ActionableDataProvider.java │ ├── DataAction.java │ ├── DataActionException.java │ ├── DataActionHelper.java │ └── DataActionType.java │ ├── debugging │ ├── Debug.java │ ├── DebugInternals.java │ ├── DebugLog.java │ ├── DebugSubmitter.java │ ├── Debuggable.java │ ├── FutureWarning.java │ ├── LogInterceptor.java │ ├── SlowWarning.java │ ├── StrongWarning.java │ ├── VerySlowWarning.java │ └── Warning.java │ ├── math │ ├── Quaternion.java │ └── Vector3.java │ ├── scheduling │ ├── AsyncSchedulable.java │ ├── OneTimeSchedulable.java │ ├── RepeatingSchedulable.java │ └── Schedulable.java │ └── text │ ├── ConfigUpdater.java │ └── StringHolder.java └── resources └── denizencore.properties /.gitattributes: -------------------------------------------------------------------------------- 1 | # Disable LF normalization for all files 2 | * -text 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: mcmonkey4eva 2 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Use The Denizen Repo Or Discord 3 | about: Use the Denizen GitHub repo or join the Discord. 4 | 5 | --- 6 | 7 | HEY! Most Denizen issues should start on Discord: https://discord.gg/Q6pZGSR 8 | 9 | If you're 100% sure GitHub issues is the place to be, use the Denizen repo: https://github.com/DenizenScript/Denizen/issues 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target/ 3 | dependency-reduced-pom.xml 4 | 5 | # IntelliJ 6 | .idea/ 7 | *.iml 8 | 9 | # Temporary/etc. 10 | *.bak 11 | *.exe 12 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contribution to Denizen 2 | ----------------------- 3 | 4 | Refer to the Denizen contribution guide: https://github.com/DenizenScript/Denizen/blob/dev/CONTRIBUTING.md 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019-2024 The Denizen Script Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DenizenCore 2 | =========== 3 | 4 | The core Denizen engine 5 | 6 | To be implemented and extended by separate DenizenScript projects. 7 | 8 | Please posts issues to the [Denizen Repo](https://github.com/DenizenScript/Denizen/issues). 9 | 10 | For API usage, refer to the [Denizen README](https://github.com/DenizenScript/Denizen). 11 | 12 | If you are implementing your own version of Denizen using this core, this topic is not yet fully documented, but talk to us on [Discord](https://discord.gg/Q6pZGSR). 13 | 14 | ### Licensing pre-note: 15 | 16 | This is an open source project, provided entirely freely, for everyone to use and contribute to. 17 | 18 | If you make any changes that could benefit the community as a whole, please contribute upstream. 19 | 20 | ### The short of the license is: 21 | 22 | You can do basically whatever you want, except you may not hold any developer liable for what you do with the software. 23 | 24 | ### Previous License 25 | 26 | Copyright (C) 2014-2019 The Denizen Script Team, All Rights Reserved. 27 | 28 | ### The long version of the license follows: 29 | 30 | The MIT License (MIT) 31 | 32 | Copyright (c) 2019-2024 The Denizen Script Team 33 | 34 | Permission is hereby granted, free of charge, to any person obtaining a copy 35 | of this software and associated documentation files (the "Software"), to deal 36 | in the Software without restriction, including without limitation the rights 37 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 38 | copies of the Software, and to permit persons to whom the Software is 39 | furnished to do so, subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all 42 | copies or substantial portions of the Software. 43 | 44 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 48 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 49 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 50 | SOFTWARE. 51 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/DenizenImplementation.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore; 2 | 3 | import com.denizenscript.denizencore.flags.FlaggableObject; 4 | import com.denizenscript.denizencore.objects.Argument; 5 | import com.denizenscript.denizencore.objects.ObjectTag; 6 | import com.denizenscript.denizencore.objects.core.VectorObject; 7 | import com.denizenscript.denizencore.scripts.ScriptEntry; 8 | import com.denizenscript.denizencore.scripts.ScriptEntryData; 9 | import com.denizenscript.denizencore.scripts.containers.ScriptContainer; 10 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 11 | import com.denizenscript.denizencore.tags.TagContext; 12 | 13 | import java.io.File; 14 | 15 | /** 16 | * Interface representing all the information that an implementation must provide to the engine. 17 | */ 18 | public interface DenizenImplementation { 19 | 20 | /** 21 | * Return a list of all folders that the implementation has scripts within. 22 | * Note: can be called async 23 | */ 24 | File getScriptFolder(); 25 | 26 | /** 27 | * Return the current version of the implementation. 28 | * EG, "Gamey Game 1.0 Denizen 0.9" 29 | */ 30 | String getImplementationVersion(); 31 | 32 | /** 33 | * Return the name of the implementation. 34 | * EG, "Gamey Game". 35 | */ 36 | String getImplementationName(); 37 | 38 | /** 39 | * Run any code that fires before a script reload goes through, 40 | * EG, clearing custom data. 41 | */ 42 | void preScriptReload(); 43 | 44 | /** 45 | * Run any code that fires after a script reload goes through, 46 | * EG, running a public Reload event. 47 | */ 48 | void onScriptReload(); 49 | 50 | /** 51 | * Return an empty ScriptEntryData object of the implementation's variety. 52 | * This is to avoid casting issues when ScriptEntry's use generic data objects. 53 | */ 54 | ScriptEntryData getEmptyScriptEntryData(); 55 | 56 | boolean handleCustomArgs(ScriptEntry entry, Argument arg); 57 | 58 | void refreshScriptContainers(); 59 | 60 | TagContext getTagContext(ScriptContainer container); 61 | 62 | TagContext getTagContext(ScriptEntry entry); 63 | 64 | String cleanseLogString(String str); 65 | 66 | void preTagExecute(); 67 | 68 | void postTagExecute(); 69 | 70 | boolean needsHandleArgPrefix(String prefix); 71 | 72 | boolean canWriteToFile(File f); 73 | 74 | String getRandomColor(); 75 | 76 | boolean canReadFile(File f); 77 | 78 | File getDataFolder(); 79 | 80 | String queueHeaderInfo(ScriptEntry entry); 81 | 82 | FlaggableObject simpleWordToFlaggable(String word, ScriptEntry entry); 83 | 84 | ObjectTag getSpecialDef(String def, ScriptQueue queue); 85 | 86 | boolean setSpecialDef(String def, ScriptQueue queue, ObjectTag value); 87 | 88 | void addExtraErrorHeaders(StringBuilder headerBuilder, ScriptEntry source); 89 | 90 | String applyDebugColors(String uncolored); 91 | 92 | void doFinalDebugOutput(String rawText); 93 | 94 | String stripColor(String message); 95 | 96 | void reloadConfig(); 97 | 98 | void reloadSaves(); 99 | 100 | VectorObject getVector(double x, double y, double z); 101 | 102 | VectorObject vectorize(ObjectTag input, TagContext context); 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/ConsoleOutputScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | import com.denizenscript.denizencore.objects.core.ElementTag; 5 | import com.denizenscript.denizencore.objects.ObjectTag; 6 | 7 | public class ConsoleOutputScriptEvent extends ScriptEvent { 8 | 9 | // <--[event] 10 | // @Events 11 | // console output 12 | // 13 | // @Group Core 14 | // 15 | // @Cancellable true 16 | // 17 | // @Triggers when any message is printed to console. (Requires <@link mechanism system.redirect_logging> be set true.) 18 | // 19 | // @Context 20 | // returns the message that is being printed to console. 21 | // 22 | // --> 23 | 24 | public static ConsoleOutputScriptEvent instance; 25 | 26 | public ConsoleOutputScriptEvent() { 27 | instance = this; 28 | registerCouldMatcher("console output"); 29 | } 30 | 31 | public String message = null; 32 | 33 | @Override 34 | public ObjectTag getContext(String name) { 35 | switch (name) { 36 | case "message": return new ElementTag(message); 37 | } 38 | return super.getContext(name); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/DeltaTimeScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | import com.denizenscript.denizencore.objects.core.ElementTag; 5 | import com.denizenscript.denizencore.objects.ObjectTag; 6 | import com.denizenscript.denizencore.DenizenCore; 7 | 8 | public class DeltaTimeScriptEvent extends ScriptEvent { 9 | 10 | // <--[event] 11 | // @Events 12 | // delta time hourly|minutely|secondly 13 | // 14 | // @Switch every: to only run the event every *count* times (like "on delta time secondly every:5" for every 5 seconds). 15 | // 16 | // @Group Core 17 | // 18 | // @Triggers every seconds, minutes, or hours of game calculation time. Default repetitions count of 1. 19 | // This is specifically based on the rate of time advancement in the game server, 20 | // which is not necessarily equivalent to the real passage of time (for example, this event may fire slower if the server is lagging). 21 | // For real time, see <@link event system time>. 22 | // 23 | // @Context 24 | // returns the exact delta time since system start. 25 | // 26 | // --> 27 | 28 | public static DeltaTimeScriptEvent instance; 29 | 30 | public DeltaTimeScriptEvent() { 31 | instance = this; 32 | registerCouldMatcher("delta time hourly|minutely|secondly"); 33 | registerSwitches("every"); 34 | } 35 | 36 | @Override 37 | public boolean matches(ScriptPath path) { 38 | String time = path.rawEventArgAt(2); 39 | long seconds = DenizenCore.serverTimeMillis / 1000; 40 | String countString = path.switches.get("every"); 41 | int count = countString == null ? 1 : Integer.parseInt(countString); 42 | switch (time) { 43 | case "secondly": 44 | if (seconds % count != 0) { 45 | return false; 46 | } 47 | break; 48 | case "minutely": 49 | if (seconds % 60 != 0) { 50 | return false; 51 | } 52 | long minutes = seconds / 60; 53 | if (minutes % count != 0) { 54 | return false; 55 | } 56 | break; 57 | case "hourly": 58 | if (seconds % 3600 != 0) { 59 | return false; 60 | } 61 | long hours = seconds / 3600; 62 | if (hours % count != 0) { 63 | return false; 64 | } 65 | break; 66 | default: 67 | return false; 68 | } 69 | return super.matches(path); 70 | } 71 | 72 | public ElementTag second; 73 | 74 | @Override 75 | public ObjectTag getContext(String name) { 76 | switch (name) { 77 | case "second": return second; 78 | } 79 | return super.getContext(name); 80 | } 81 | 82 | public void checkTime() { 83 | if (!eventData.isEnabled) { 84 | return; 85 | } 86 | second = new ElementTag(DenizenCore.serverTimeMillis / 1000); 87 | fire(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/PreScriptReloadScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | 5 | public class PreScriptReloadScriptEvent extends ScriptEvent { 6 | 7 | // <--[event] 8 | // @Events 9 | // pre script reload 10 | // 11 | // @Group Core 12 | // 13 | // @Triggers immediately before Denizen scripts are reloaded. 14 | // 15 | // --> 16 | 17 | public static PreScriptReloadScriptEvent instance; 18 | 19 | public PreScriptReloadScriptEvent() { 20 | instance = this; 21 | registerCouldMatcher("pre script reload"); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/RedisPubSubMessageScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | import com.denizenscript.denizencore.objects.ObjectTag; 5 | import com.denizenscript.denizencore.objects.core.ElementTag; 6 | 7 | public class RedisPubSubMessageScriptEvent extends ScriptEvent { 8 | 9 | // <--[event] 10 | // @Events 11 | // redis pubsub message 12 | // 13 | // @Switch channel: to only fire on events advanced-matching the given channel. 14 | // 15 | // @Group Core 16 | // 17 | // @Triggers when a subscribed redis connection receives a published message, see <@link command Redis>. 18 | // 19 | // @Context 20 | // returns the connection id that saw this message. 21 | // returns the redis pattern that matched the channel. 22 | // returns the actual channel matched. 23 | // returns the published message. 24 | // 25 | // --> 26 | 27 | public static RedisPubSubMessageScriptEvent instance; 28 | 29 | public String redisID; 30 | public String pattern; 31 | public String channel; 32 | public String message; 33 | 34 | public RedisPubSubMessageScriptEvent() { 35 | instance = this; 36 | registerCouldMatcher("redis pubsub message"); 37 | registerSwitches("channel"); 38 | } 39 | 40 | @Override 41 | public boolean matches(ScriptPath path) { 42 | if (!runGenericSwitchCheck(path, "channel", channel)) { 43 | return false; 44 | } 45 | return super.matches(path); 46 | } 47 | 48 | @Override 49 | public ObjectTag getContext(String name) { 50 | switch (name) { 51 | case "redis_id": return new ElementTag(redisID); 52 | case "pattern": return new ElementTag(pattern); 53 | case "channel": return new ElementTag(channel); 54 | case "message": return new ElementTag(message); 55 | } 56 | return super.getContext(name); 57 | } 58 | 59 | public void handle(String redisID, String pattern, String channel, String message) { 60 | this.redisID = redisID; 61 | this.pattern = pattern; 62 | this.channel = channel; 63 | this.message = message; 64 | fire(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/ReloadScriptsScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | import com.denizenscript.denizencore.objects.core.ElementTag; 5 | import com.denizenscript.denizencore.objects.ObjectTag; 6 | 7 | public class ReloadScriptsScriptEvent extends ScriptEvent { 8 | 9 | // <--[event] 10 | // @Events 11 | // reload scripts 12 | // script reload 13 | // 14 | // @Switch had_error:true/false to only process the event if there either was or was not an error message. 15 | // 16 | // @Group Core 17 | // 18 | // @Triggers when Denizen scripts are reloaded. Not triggered on initial load. 19 | // 20 | // @Context 21 | // returns an ElementTag(Boolean) whether there was an error. 22 | // 23 | // --> 24 | 25 | public static ReloadScriptsScriptEvent instance; 26 | 27 | public ReloadScriptsScriptEvent() { 28 | instance = this; 29 | registerCouldMatcher("reload scripts"); 30 | registerCouldMatcher("script reload"); 31 | registerSwitches("had_error"); 32 | } 33 | 34 | public boolean hadError = false; 35 | 36 | @Override 37 | public ObjectTag getContext(String name) { 38 | switch (name) { 39 | case "had_error": 40 | return new ElementTag(hadError); 41 | } 42 | return super.getContext(name); 43 | } 44 | 45 | @Override 46 | public boolean matches(ScriptPath path) { 47 | if (!path.checkSwitch("had_error", hadError ? "true" : "false")) { 48 | return false; 49 | } 50 | return super.matches(path); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/ScriptGeneratesErrorScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | import com.denizenscript.denizencore.objects.ObjectTag; 5 | import com.denizenscript.denizencore.objects.core.ElementTag; 6 | import com.denizenscript.denizencore.objects.core.QueueTag; 7 | import com.denizenscript.denizencore.objects.core.ScriptTag; 8 | import com.denizenscript.denizencore.scripts.ScriptEntryData; 9 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 10 | 11 | public class ScriptGeneratesErrorScriptEvent extends ScriptEvent { 12 | 13 | // <--[event] 14 | // @Events 15 | // script generates error 16 | // 17 | // @Group Core 18 | // 19 | // @Cancellable true 20 | // 21 | // @Warning Abusing this event can cause significant failures in the Denizen debug system. Use only with extreme caution. 22 | // 23 | // @Triggers when a script generates an error. 24 | // 25 | // @Context 26 | // returns the error message. 27 | // returns the queue that caused the error, if any. 28 | // returns the script that caused the error, if any. 29 | // returns the line number within the script file that caused the error, if any. 30 | // 31 | // --> 32 | 33 | public static ScriptGeneratesErrorScriptEvent instance; 34 | 35 | public ScriptGeneratesErrorScriptEvent() { 36 | instance = this; 37 | registerCouldMatcher("script generates error"); 38 | } 39 | 40 | public ScriptQueue queue; 41 | public String message; 42 | public int line; 43 | public ScriptTag script; 44 | public static boolean cancelledTracker = false; 45 | 46 | @Override 47 | public ScriptEntryData getScriptEntryData() { 48 | if (queue != null && queue.getLastEntryExecuted() != null) { 49 | return queue.getLastEntryExecuted().entryData; 50 | } 51 | return super.getScriptEntryData(); 52 | } 53 | 54 | @Override 55 | public ObjectTag getContext(String name) { 56 | switch (name) { 57 | case "message": return new ElementTag(message); 58 | case "script": return script; 59 | case "line": 60 | if (line != -1) { 61 | return new ElementTag(line); 62 | } 63 | break; 64 | case "queue": 65 | if (queue != null) { 66 | return new QueueTag(queue); 67 | } 68 | break; 69 | } 70 | return super.getContext(name); 71 | } 72 | 73 | @Override 74 | public void cancellationChanged() { 75 | cancelledTracker = cancelled; 76 | super.cancellationChanged(); 77 | } 78 | 79 | public boolean handle(String message, ScriptQueue queue, ScriptTag script, int line) { 80 | this.queue = queue; 81 | this.message = message; 82 | this.line = line; 83 | this.script = script; 84 | cancelledTracker = false; 85 | fire(); 86 | return cancelledTracker; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/ScriptsLoadedScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | import com.denizenscript.denizencore.objects.ObjectTag; 5 | import com.denizenscript.denizencore.objects.core.ElementTag; 6 | 7 | public class ScriptsLoadedScriptEvent extends ScriptEvent { 8 | 9 | // <--[event] 10 | // @Events 11 | // scripts loaded 12 | // 13 | // @Switch had_error:true/false to only process the event if there either was or was not an error message. 14 | // 15 | // @Group Core 16 | // 17 | // @Triggers when Denizen scripts are loaded, but on reloaded and on initial load. 18 | // 19 | // @Context 20 | // returns an ElementTag(Boolean) whether there was an error. 21 | // 22 | // --> 23 | 24 | public static ScriptsLoadedScriptEvent instance; 25 | 26 | public ScriptsLoadedScriptEvent() { 27 | instance = this; 28 | registerCouldMatcher("scripts loaded"); 29 | registerSwitches("had_error"); 30 | } 31 | 32 | public boolean hadError = false; 33 | 34 | @Override 35 | public ObjectTag getContext(String name) { 36 | switch (name) { 37 | case "had_error": 38 | return new ElementTag(hadError); 39 | } 40 | return super.getContext(name); 41 | } 42 | 43 | @Override 44 | public boolean matches(ScriptPath path) { 45 | if (!path.checkSwitch("had_error", hadError ? "true" : "false")) { 46 | return false; 47 | } 48 | return super.matches(path); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/ServerGeneratesExceptionScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | import com.denizenscript.denizencore.objects.ObjectTag; 5 | import com.denizenscript.denizencore.objects.core.ElementTag; 6 | import com.denizenscript.denizencore.objects.core.QueueTag; 7 | import com.denizenscript.denizencore.objects.core.ScriptTag; 8 | import com.denizenscript.denizencore.scripts.ScriptEntryData; 9 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 10 | import com.denizenscript.denizencore.utilities.debugging.DebugInternals; 11 | 12 | public class ServerGeneratesExceptionScriptEvent extends ScriptEvent { 13 | 14 | // <--[event] 15 | // @Events 16 | // server generates exception 17 | // 18 | // @Group Core 19 | // 20 | // @Cancellable true 21 | // 22 | // @Warning Abusing this event can cause significant failures in the Denizen debug system. Use only with extreme caution. 23 | // 24 | // @Triggers when an exception occurs on the server. 25 | // 26 | // @Context 27 | // returns the Exception message. 28 | // returns the full exception trace+message output details. 29 | // returns the type of the error. (EG, NullPointerException). 30 | // returns the queue that caused the exception, if any. 31 | // returns the script that caused the exception, if any. 32 | // returns the line number within the script file that caused the exception, if any. 33 | // --> 34 | 35 | public static ServerGeneratesExceptionScriptEvent instance; 36 | 37 | public ServerGeneratesExceptionScriptEvent() { 38 | instance = this; 39 | registerCouldMatcher("server generates exception"); 40 | } 41 | 42 | public Throwable exception; 43 | public ScriptQueue queue; 44 | public String fullTrace; 45 | public int line; 46 | public ScriptTag script; 47 | public static boolean cancelledTracker = false; 48 | 49 | @Override 50 | public ScriptEntryData getScriptEntryData() { 51 | if (queue != null && queue.getLastEntryExecuted() != null) { 52 | return queue.getLastEntryExecuted().entryData; 53 | } 54 | return super.getScriptEntryData(); 55 | } 56 | 57 | @Override 58 | public ObjectTag getContext(String name) { 59 | switch (name) { 60 | case "message": return new ElementTag(exception.getMessage()); 61 | case "full_trace": return new ElementTag(fullTrace); 62 | case "type": return new ElementTag(DebugInternals.getClassNameOpti(exception.getClass())); 63 | case "queue": 64 | if (queue != null) { 65 | return new QueueTag(queue); 66 | } 67 | break; 68 | case "script": return script; 69 | case "line": 70 | if (line != -1) { 71 | return new ElementTag(line); 72 | } 73 | break; 74 | } 75 | return super.getContext(name); 76 | } 77 | 78 | @Override 79 | public void cancellationChanged() { 80 | cancelledTracker = cancelled; 81 | super.cancellationChanged(); 82 | } 83 | 84 | public boolean handle(Throwable ex, String trace, ScriptQueue queue, ScriptTag script, int line) { 85 | this.queue = queue; 86 | this.fullTrace = trace; 87 | this.exception = ex; 88 | this.line = line; 89 | this.script = script; 90 | cancelledTracker = false; 91 | fire(); 92 | return cancelledTracker; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/ShutdownScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | 5 | public class ShutdownScriptEvent extends ScriptEvent { 6 | 7 | // <--[event] 8 | // @Events 9 | // shutdown 10 | // 11 | // @Group Server 12 | // 13 | // @Warning not all plugins will be loaded and delayed scripts will be dropped. 14 | // Also note that this event is not guaranteed to always run (eg if the server crashes). 15 | // 16 | // @Triggers when the server is shutting down. 17 | // 18 | // @Example 19 | // # This *might* show a message in logs during shutdown. No guarantee. 20 | // on shutdown: 21 | // - announce to_console "Last message in the logs from Denizen probably!" 22 | // 23 | // --> 24 | 25 | public static ShutdownScriptEvent instance; 26 | 27 | public ShutdownScriptEvent() { 28 | instance = this; 29 | registerCouldMatcher("shutdown"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/events/core/TickScriptEvent.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.events.core; 2 | 3 | import com.denizenscript.denizencore.events.ScriptEvent; 4 | import com.denizenscript.denizencore.objects.core.ElementTag; 5 | import com.denizenscript.denizencore.objects.ObjectTag; 6 | 7 | public class TickScriptEvent extends ScriptEvent { 8 | 9 | // <--[event] 10 | // @Events 11 | // tick 12 | // 13 | // @Switch every: to only run the event every *count* times (like "every:5" for every 5 ticks). 14 | // 15 | // @Group Core 16 | // 17 | // @Warning This event fires very rapidly and is usually not the most ideal way to handle things. Generally, prefer <@link event delta time>. 18 | // 19 | // @Triggers every single tick. 20 | // 21 | // @Context 22 | // how many ticks have passed since the server started. 23 | // 24 | // --> 25 | 26 | public static TickScriptEvent instance; 27 | 28 | public TickScriptEvent() { 29 | instance = this; 30 | registerCouldMatcher("tick"); 31 | registerSwitches("every"); 32 | } 33 | 34 | public long ticks = 0; 35 | 36 | @Override 37 | public ObjectTag getContext(String name) { 38 | if (name.equals("tick")) { 39 | return new ElementTag(ticks); 40 | } 41 | return super.getContext(name); 42 | } 43 | 44 | @Override 45 | public boolean matches(ScriptPath path) { 46 | String countString = path.switches.get("every"); 47 | int count = countString == null ? 1 : Integer.parseInt(countString); 48 | if (ticks % count != 0) { 49 | return false; 50 | } 51 | return super.matches(path); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/exceptions/InvalidArgumentsException.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.exceptions; 2 | 3 | public class InvalidArgumentsException extends Exception { 4 | 5 | private static final long serialVersionUID = 3159108944857792078L; 6 | public String message; 7 | 8 | public InvalidArgumentsException(String msg) { 9 | message = msg; 10 | } 11 | 12 | @Override 13 | public String getMessage() { 14 | return message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/exceptions/InvalidArgumentsRuntimeException.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.exceptions; 2 | 3 | public class InvalidArgumentsRuntimeException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 3159108944857792088L; 6 | public String message; 7 | 8 | public InvalidArgumentsRuntimeException(String msg) { 9 | message = msg; 10 | } 11 | 12 | @Override 13 | public String getMessage() { 14 | return message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/exceptions/TagProcessingException.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.exceptions; 2 | 3 | public class TagProcessingException extends Exception { 4 | 5 | private static final long serialVersionUID = 3159108944857792098L; 6 | public String message; 7 | 8 | public TagProcessingException(String msg) { 9 | message = msg; 10 | } 11 | 12 | @Override 13 | public String getMessage() { 14 | return message; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/exceptions/Unreachable.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.exceptions; 2 | 3 | public class Unreachable extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 3159108944857792168L; 6 | 7 | /** 8 | * Indicates that a code section is known to be unreachable at runtime, but the compiler does not know this. 9 | */ 10 | public Unreachable() { 11 | } 12 | 13 | @Override 14 | public String getMessage() { 15 | return "This code is unreachable."; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/flags/FlaggableObject.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.flags; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectTag; 4 | 5 | public interface FlaggableObject extends ObjectTag { 6 | 7 | // <--[ObjectType] 8 | // @name FlaggableObject 9 | // @prefix None 10 | // @base None 11 | // @format 12 | // N/A 13 | // 14 | // @description 15 | // "FlaggableObject" is a pseudo-ObjectType that represents any type of object that can hold flags, 16 | // for use with <@link command flag> or any other flag related tags and mechanisms. 17 | // 18 | // Just because an ObjectType implements FlaggableObject, does not mean a specific instance of that object type is flaggable. 19 | // For example, LocationTag implements FlaggableObject, but a LocationTag-Vector (a location without a world) cannot hold a flag. 20 | // 21 | // --> 22 | 23 | AbstractFlagTracker getFlagTracker(); 24 | 25 | default AbstractFlagTracker getFlagTrackerForTag() { 26 | return getFlagTracker(); 27 | } 28 | 29 | void reapplyTracker(AbstractFlagTracker tracker); 30 | 31 | default String getReasonNotFlaggable() { 32 | return "unknown reason - something went wrong"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/flags/MapTagFlagTracker.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.flags; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectTag; 4 | import com.denizenscript.denizencore.objects.core.MapTag; 5 | import com.denizenscript.denizencore.tags.TagContext; 6 | import com.denizenscript.denizencore.utilities.text.StringHolder; 7 | 8 | import java.util.*; 9 | 10 | public class MapTagFlagTracker extends MapTagBasedFlagTracker { 11 | 12 | public MapTag map; 13 | 14 | public MapTagFlagTracker() { 15 | this.map = new MapTag(); 16 | } 17 | 18 | public MapTagFlagTracker(MapTag map) { 19 | this.map = map; 20 | doClean(map); 21 | } 22 | 23 | public MapTagFlagTracker(String mapTagValue, TagContext context) { 24 | this(MapTag.valueOf(mapTagValue, context)); 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return map.toString(); 30 | } 31 | 32 | @Override 33 | public Collection listAllFlags() { 34 | ArrayList keys = new ArrayList<>(map.size()); 35 | for (StringHolder string : map.keySet()) { 36 | keys.add(string.str); 37 | } 38 | return keys; 39 | } 40 | 41 | @Override 42 | public MapTag getRootMap(String key) { 43 | ObjectTag subObj = map.getObject(key); 44 | if (subObj == null) { 45 | return null; 46 | } 47 | if (subObj instanceof MapTag) { 48 | return (MapTag) subObj; 49 | } 50 | MapTag toReturn = new MapTag(); 51 | toReturn.putObject(valueString, subObj); 52 | return toReturn; 53 | } 54 | 55 | @Override 56 | public void setRootMap(String key, MapTag value) { 57 | if (value == null) { 58 | map.remove(key); 59 | } 60 | else { 61 | ObjectTag subValue = value.getObject(valueString); 62 | if (value.containsKey(expirationString) || subValue instanceof MapTag) { 63 | map.putObject(key, value); 64 | } 65 | else { 66 | map.putObject(key, subValue); 67 | } 68 | } 69 | } 70 | 71 | @Override 72 | public MapTag getFlagMap() { 73 | return map; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/flags/RedirectionFlagTracker.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.flags; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectTag; 4 | import com.denizenscript.denizencore.objects.core.MapTag; 5 | import com.denizenscript.denizencore.objects.core.TimeTag; 6 | import com.denizenscript.denizencore.utilities.CoreUtilities; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Collection; 10 | import java.util.List; 11 | 12 | public class RedirectionFlagTracker extends AbstractFlagTracker { 13 | 14 | public RedirectionFlagTracker(AbstractFlagTracker original, String prefix) { 15 | this.original = original; 16 | this.prefix = prefix; 17 | } 18 | 19 | public AbstractFlagTracker original; 20 | 21 | public String prefix; 22 | 23 | @Override 24 | public MapTag getRootMap(String key) { 25 | List parts = CoreUtilities.split(prefix, '.'); 26 | parts.add(key); 27 | MapTag target = original.getRootMap(parts.get(0)); 28 | if (target == null) { 29 | return null; 30 | } 31 | for (int i = 1; i < parts.size(); i++) { 32 | target = (MapTag) target.getObject(MapTagBasedFlagTracker.valueString); 33 | if (target == null) { 34 | return null; 35 | } 36 | target = (MapTag) target.getObject(parts.get(i)); 37 | if (target == null) { 38 | return null; 39 | } 40 | } 41 | return target; 42 | } 43 | 44 | @Override 45 | public void setRootMap(String key, MapTag map) { 46 | original.setFlag(prefix + "." + key, map, null, false); 47 | } 48 | 49 | @Override 50 | public ObjectTag getFlagValue(String key) { 51 | return original.getFlagValue(prefix + "." + key); 52 | } 53 | 54 | @Override 55 | public TimeTag getFlagExpirationTime(String key) { 56 | return original.getFlagExpirationTime(prefix + "." + key); 57 | } 58 | 59 | @Override 60 | public Collection listAllFlags() { 61 | MapTag map = getFlagMap(); 62 | if (map == null) { 63 | return new ArrayList<>(); 64 | } 65 | return map.keys(); 66 | } 67 | 68 | @Override 69 | public void setFlag(String key, ObjectTag value, TimeTag expiration, boolean doFlaggify) { 70 | original.setFlag(prefix + "." + key, value, expiration, doFlaggify); 71 | } 72 | 73 | @Override 74 | public MapTag getFlagMap() { 75 | ObjectTag obj = original.getFlagValue(prefix); 76 | if (!(obj instanceof MapTag)) { 77 | return null; 78 | } 79 | return (MapTag) obj; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/objects/Adjustable.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.objects; 2 | 3 | import com.denizenscript.denizencore.utilities.CoreConfiguration; 4 | import com.denizenscript.denizencore.utilities.debugging.Debug; 5 | 6 | public interface Adjustable extends ObjectTag { 7 | 8 | /** 9 | * Sets a specific attribute using this object to modify the necessary data. 10 | * 11 | * @param mechanism the mechanism to gather change information from 12 | */ 13 | void adjust(Mechanism mechanism); 14 | 15 | default void safeAdjust(Mechanism mechanism) { 16 | mechanism.adjusting = this; 17 | mechanism.isProperty = false; 18 | if (mechanism.shouldDebug()) { 19 | Debug.echoDebug(mechanism.context, "Adjust mechanism '" + mechanism.getName() + "' on object of type '" + getDenizenObjectType() + "'..."); 20 | } 21 | adjust(mechanism); 22 | mechanism.autoReport(); 23 | } 24 | 25 | default void safeAdjustDuplicate(Mechanism mechanism) { 26 | safeAdjust(new Mechanism(mechanism.getName(), mechanism.value, mechanism.context)); 27 | } 28 | 29 | /** 30 | * Applies a property, passing it to 'adjust' or throwing an error, depending on whether 31 | * the mechanism may be used as a property. 32 | * 33 | * @param mechanism the mechanism to gather change information from 34 | */ 35 | void applyProperty(Mechanism mechanism); 36 | 37 | default void safeApplyProperty(Mechanism mechanism) { 38 | mechanism.adjusting = this; 39 | mechanism.isProperty = true; 40 | if (mechanism.shouldDebug()) { 41 | Debug.echoDebug(mechanism.context, "Applying property '" + mechanism.getName() + "' on object of type '" + getDenizenObjectType() + "'..."); 42 | if (CoreConfiguration.debugVerbose) { 43 | try { 44 | throw new Exception("Stack trace of property"); 45 | } 46 | catch (Exception ex) { 47 | Debug.echoError(ex); 48 | } 49 | } 50 | } 51 | applyProperty(mechanism); 52 | mechanism.autoReport(); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/objects/Fetchable.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.objects; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | 11 | public @interface Fetchable { 12 | String value(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/objects/ObjectType.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.objects; 2 | 3 | import com.denizenscript.denizencore.objects.core.ElementTag; 4 | import com.denizenscript.denizencore.tags.ObjectTagProcessor; 5 | import com.denizenscript.denizencore.tags.TagContext; 6 | import com.denizenscript.denizencore.tags.TagManager; 7 | import com.denizenscript.denizencore.utilities.CoreUtilities; 8 | 9 | public class ObjectType { 10 | 11 | @FunctionalInterface 12 | public interface MatchesInterface { 13 | 14 | boolean matches(String str); 15 | } 16 | 17 | public interface ValueOfInterface { 18 | 19 | T valueOf(String str, TagContext context); 20 | } 21 | 22 | @FunctionalInterface 23 | public interface TypeComparisonRunnable { 24 | boolean doesCompare(ObjectTag inp); 25 | 26 | TypeComparisonRunnable trueAlways = (o) -> true; 27 | } 28 | 29 | @FunctionalInterface 30 | public interface TagTypeConverter { 31 | T convert(ObjectTag inp, TagContext context); 32 | } 33 | 34 | public Class clazz; 35 | 36 | public MatchesInterface matches; 37 | 38 | public ValueOfInterface valueOf; 39 | 40 | public ObjectTagProcessor tagProcessor; 41 | 42 | public String prefix; 43 | 44 | public boolean isAdjustable; 45 | 46 | public String longName, shortName; 47 | 48 | public TagTypeConverter typeConverter; 49 | 50 | public TypeComparisonRunnable typeChecker, typeShouldBeChecker; 51 | 52 | public boolean canConvertStatic; 53 | 54 | public ObjectType setAsNOtherCode() { 55 | typeChecker = (inp) -> { 56 | if (inp == null) { 57 | return false; 58 | } 59 | Class inpType = inp.getClass(); 60 | if (inpType == clazz) { 61 | return true; 62 | } 63 | if (inpType == ElementTag.class) { 64 | String simple = inp.toString(); 65 | int atIndex = simple.indexOf('@'); 66 | if (atIndex != -1) { 67 | String code = simple.substring(0, atIndex); 68 | if (!code.equals(prefix) && !code.equals("el")) { 69 | if (ObjectFetcher.objectsByPrefix.containsKey(code)) { 70 | return false; 71 | } 72 | } 73 | } 74 | return true; 75 | } 76 | return false; 77 | }; 78 | return this; 79 | } 80 | 81 | public ObjectType setCanConvertStatic() { 82 | canConvertStatic = true; 83 | return this; 84 | } 85 | 86 | public ObjectType generateBaseTag() { 87 | TagManager.internalRegisterTagHandler(clazz, clazz, CoreUtilities.toLowerCase(shortName), (attribute, param) -> param, canConvertStatic); 88 | return this; 89 | } 90 | 91 | @Override 92 | public String toString() { 93 | return longName; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/objects/notable/Notable.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.objects.notable; 2 | 3 | public interface Notable { 4 | 5 | boolean isUnique(); 6 | 7 | Object getSaveObject(); 8 | 9 | void makeUnique(String id); 10 | 11 | void forget(); 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/objects/notable/Note.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.objects.notable; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.METHOD) 10 | 11 | public @interface Note { 12 | String value(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/objects/properties/ObjectProperty.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.objects.properties; 2 | 3 | import com.denizenscript.denizencore.objects.Mechanism; 4 | import com.denizenscript.denizencore.objects.ObjectTag; 5 | import com.denizenscript.denizencore.tags.Attribute; 6 | import com.denizenscript.denizencore.utilities.debugging.DebugInternals; 7 | 8 | public abstract class ObjectProperty implements Property { 9 | 10 | public TObj object; 11 | 12 | public abstract TData getPropertyValue(); 13 | 14 | public TData getTagValue(Attribute attribute) { 15 | return getPropertyValue(); 16 | } 17 | 18 | public boolean isDefaultValue(TData data) { 19 | return false; 20 | } 21 | 22 | @Override 23 | public TData getPropertyValueNoDefault() { 24 | TData res = getPropertyValue(); 25 | return res == null || isDefaultValue(res) ? null : getPropertyValue(); 26 | } 27 | 28 | @Override 29 | public String getPropertySavableValue() { 30 | TData res = getPropertyValue(); 31 | return res == null || isDefaultValue(res) ? null : getPropertyValue().savable(); 32 | } 33 | 34 | @Deprecated @Override 35 | public String getPropertyString() { 36 | TData res = getPropertyValue(); 37 | return res == null || isDefaultValue(res) ? null : getPropertyValue().identify(); 38 | } 39 | 40 | public abstract void setPropertyValue(TData data, Mechanism mechanism); 41 | 42 | public static > 43 | void autoRegister(String name, Class propClass, Class dataClass, boolean isStatic, String... deprecatedVariants) { 44 | PropertyParser.registerTagInternal(propClass, dataClass, name, (attribute, prop) -> prop.getTagValue(attribute), deprecatedVariants, isStatic); 45 | PropertyParser.registerMechanism(propClass, dataClass, name, (prop, mechanism, param) -> prop.setPropertyValue(param, mechanism), deprecatedVariants); 46 | } 47 | 48 | public static > 49 | void autoRegisterNullable(String name, Class propClass, Class dataClass, boolean isStatic, String... deprecatedVariants) { 50 | PropertyParser.registerTagInternal(propClass, dataClass, name, (attribute, prop) -> prop.getTagValue(attribute), deprecatedVariants, isStatic); 51 | PropertyParser.registerMechanism(propClass, name, (prop, mechanism) -> { 52 | if (!mechanism.hasValue()) { 53 | prop.setPropertyValue(null, mechanism); 54 | return; 55 | } 56 | TData param = mechanism.value.asType(dataClass, mechanism.context); 57 | if (param == null) { 58 | mechanism.echoError("Invalid " + DebugInternals.getClassNameOpti(dataClass) + " specified."); 59 | return; 60 | } 61 | prop.setPropertyValue(param, mechanism); 62 | }, deprecatedVariants); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/objects/properties/Property.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.objects.properties; 2 | 3 | import com.denizenscript.denizencore.objects.Mechanism; 4 | import com.denizenscript.denizencore.objects.ObjectTag; 5 | import com.denizenscript.denizencore.objects.core.ElementTag; 6 | import com.denizenscript.denizencore.tags.Attribute; 7 | 8 | public interface Property { 9 | 10 | default ObjectTag getPropertyValue() { 11 | String str = getPropertyString(); 12 | return str == null ? null : new ElementTag(str); 13 | } 14 | 15 | default ObjectTag getPropertyValueNoDefault() { 16 | return getPropertyValue(); 17 | } 18 | 19 | @Deprecated // TODO: This is for legacy compatibility, can be removed when getPropertyString is 20 | default String getPropertySavableValue() { 21 | return getPropertyString(); 22 | } 23 | 24 | @Deprecated 25 | String getPropertyString(); 26 | 27 | String getPropertyId(); 28 | 29 | @Deprecated 30 | default ObjectTag getObjectAttribute(Attribute attribute) { 31 | return null; 32 | } 33 | 34 | @Deprecated 35 | default void adjust(Mechanism mechanism) { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/ScriptBuilder.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts; 2 | 3 | import com.denizenscript.denizencore.scripts.containers.ScriptContainer; 4 | import com.denizenscript.denizencore.utilities.CoreConfiguration; 5 | import com.denizenscript.denizencore.utilities.debugging.Debug; 6 | import com.denizenscript.denizencore.objects.ArgumentHelper; 7 | 8 | import java.util.ArrayList; 9 | import java.util.Arrays; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | public class ScriptBuilder { 14 | 15 | public static final char LINE_PREFIX_CHAR = '^'; // This would be an invisible special character... if SnakeYAML allowed them! 16 | 17 | public static String stripLinePrefix(String rawLine) { 18 | if (!rawLine.startsWith(String.valueOf(LINE_PREFIX_CHAR))) { 19 | return rawLine; 20 | } 21 | int infoEnd = rawLine.indexOf(LINE_PREFIX_CHAR, 1); 22 | return rawLine.substring(infoEnd + 2); // Skip the symbol and the space after. 23 | } 24 | 25 | public static List buildScriptEntries(List contents, ScriptContainer parent, ScriptEntryData data) { 26 | if (contents == null || contents.isEmpty()) { 27 | if (CoreConfiguration.debugScriptBuilder) { 28 | Debug.echoError("Building script entries... no entries to build!"); 29 | } 30 | return null; 31 | } 32 | if (CoreConfiguration.debugScriptBuilder) { 33 | Debug.echoDebug(parent, "Building script entries:"); 34 | } 35 | List scriptCommands = new ArrayList<>(contents.size()); 36 | for (Object ientry : contents) { 37 | if (ientry == null) { 38 | ientry = "null"; 39 | } 40 | String entry; 41 | Object inside; 42 | if (ientry instanceof Map) { 43 | Object key = ((Map) ientry).keySet().toArray()[0]; 44 | entry = key.toString(); 45 | Object rawValue = ((Map) ientry).get(key); 46 | if (!(rawValue instanceof List) && !(rawValue instanceof Map)) { 47 | Debug.echoError("Script '" + parent.getName() + "' has invalid line " + ientry + ": line ends with ':' but no script body inside."); 48 | return null; 49 | } 50 | inside = rawValue; 51 | } 52 | else { 53 | entry = ientry.toString(); 54 | inside = null; 55 | } 56 | int lineNum = 1; 57 | if (entry.startsWith(String.valueOf(LINE_PREFIX_CHAR))) { 58 | int infoEnd = entry.indexOf(LINE_PREFIX_CHAR, 1); 59 | String lineNumStr = entry.substring(1, infoEnd); 60 | entry = entry.substring(infoEnd + 2); // Skip the symbol and the space after. 61 | lineNum = Integer.parseInt(lineNumStr); 62 | } 63 | String[] scriptEntry = entry.split(" ", 2); 64 | try { 65 | /* Build new script commands */ 66 | String[] args = scriptEntry.length > 1 ? ArgumentHelper.buildArgs(scriptEntry[1], true) : null; 67 | if (CoreConfiguration.debugScriptBuilder) { 68 | Debug.echoDebug(parent, "Adding '" + scriptEntry[0] + "' Args: " + Arrays.toString(args)); 69 | } 70 | ScriptEntry newEntry = new ScriptEntry(scriptEntry[0], args, parent, inside, lineNum); 71 | newEntry.internal.originalLine = entry; 72 | newEntry.entryData.transferDataFrom(data); 73 | scriptCommands.add(newEntry); 74 | } 75 | catch (Exception e) { 76 | Debug.echoError("Exception while building script '" + (parent == null ? "(null)" : parent.getName()) + "'..."); 77 | Debug.echoError(e); 78 | } 79 | } 80 | return scriptCommands; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/ScriptEntryData.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts; 2 | 3 | import com.denizenscript.denizencore.utilities.YamlConfiguration; 4 | import com.denizenscript.denizencore.utilities.debugging.Debug; 5 | import com.denizenscript.denizencore.tags.TagContext; 6 | 7 | public abstract class ScriptEntryData implements Cloneable { 8 | 9 | public ScriptEntry scriptEntry; 10 | 11 | @Override 12 | public ScriptEntryData clone() { 13 | try { 14 | return (ScriptEntryData) super.clone(); 15 | } 16 | catch (Exception e) { 17 | Debug.echoError(e); 18 | return null; 19 | } 20 | } 21 | 22 | public abstract void transferDataFrom(ScriptEntryData data); 23 | 24 | public abstract TagContext getTagContext(); 25 | 26 | @Override 27 | public String toString() { 28 | return "{{ Unimplemented toString method in ScriptEntryData! }}"; 29 | } 30 | 31 | public abstract YamlConfiguration save(); 32 | 33 | public abstract void load(YamlConfiguration config); 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/ScriptEntrySet.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class ScriptEntrySet { 7 | 8 | public List entries; 9 | 10 | public ScriptEntrySet(List baseEntries) { 11 | entries = baseEntries; 12 | } 13 | 14 | public ScriptEntrySet duplicate() { 15 | List newEntries = new ArrayList<>(entries.size()); 16 | for (ScriptEntry entry : entries) { 17 | newEntries.add(entry.clone()); 18 | } 19 | return new ScriptEntrySet(newEntries); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/Holdable.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands; 2 | 3 | /** 4 | * Simply used to indicate that a command can be 'held', so we don't wait for 5 | * commands that will never mark themselves 'finished'. 6 | */ 7 | public interface Holdable { 8 | 9 | // <--[language] 10 | // @name ~Waitable 11 | // @group Script Command System 12 | // @description 13 | // A command that is "~Waitable" (or "Holdable", or that can be "~waited for") is a command that: 14 | // - Might potentially take a while to execute 15 | // - Is able to perform a slowed execution (that doesn't freeze the server) 16 | // - And so supports the "~" prefix. 17 | // 18 | // This is written, for example, like: - ~run MySlowScript 19 | // 20 | // When a command is ~waited for, the queue it's in will wait for it to complete, but the rest of the server will continue running. 21 | // This is of course similar to the "wait" command, but waits for the action to complete instead of simply for a period of time. 22 | // 23 | // Some commands, particularly those related to file operation, when ~waited for will move the file operation off-thread. 24 | // Others may need to be on the server thread, and may split the operation into smaller segments spread out over 1 tick each or similar logic. 25 | // Some of these commands, when NOT waited for, will freeze the server thread until the operation completes. 26 | // Others, however, may still perform the action in a delayed/slow/off-thread manner, but simply not hold the queue. 27 | // --> 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/core/CustomEventCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.core; 2 | 3 | import com.denizenscript.denizencore.events.core.CustomScriptEvent; 4 | import com.denizenscript.denizencore.objects.core.ElementTag; 5 | import com.denizenscript.denizencore.objects.core.ListTag; 6 | import com.denizenscript.denizencore.objects.core.MapTag; 7 | import com.denizenscript.denizencore.scripts.ScriptEntry; 8 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 9 | import com.denizenscript.denizencore.scripts.commands.generator.ArgDefaultNull; 10 | import com.denizenscript.denizencore.scripts.commands.generator.ArgName; 11 | import com.denizenscript.denizencore.scripts.commands.generator.ArgPrefixed; 12 | 13 | public class CustomEventCommand extends AbstractCommand { 14 | 15 | public CustomEventCommand() { 16 | setName("customevent"); 17 | setSyntax("customevent [id:] (context:)"); 18 | setRequiredArguments(1, 2); 19 | isProcedural = false; 20 | autoCompile(); 21 | } 22 | 23 | // <--[command] 24 | // @Name CustomEvent 25 | // @Syntax customevent [id:] (context:) 26 | // @Required 1 27 | // @Maximum 2 28 | // @Short Fires a custom world script event. 29 | // @Group core 30 | // 31 | // @Description 32 | // Fires a custom world script event. 33 | // 34 | // Input is an ID (the name of your custom event, choose a constant name to use), and an optional MapTag of context data. 35 | // 36 | // Linked data (player, npc, ...) is automatically sent across to the event. 37 | // 38 | // Use with <@link event custom event> 39 | // 40 | // @Tags 41 | // returns a boolean indicating whether any events ran as a result of this command. 42 | // returns a boolean indicating whether the event was cancelled. 43 | // returns a ListTag of determinations to this event. Will be an empty list if 'determine output:' is never used. 44 | // 45 | // @Usage 46 | // Use to call a custom event with path "on custom event id:things_happened:" 47 | // - customevent id:things_happened 48 | // 49 | // @Usage 50 | // Use to call a custom event with path "on custom event id:things_happened:" and supply a context map of basic data. 51 | // - customevent id:things_happened context:[a=1;b=2;c=3] 52 | // 53 | // @Usage 54 | // Use to call a custom event with a path such as "on custom event id:things_happened data:item:stone:" and supply a context map of more interesting data. 55 | // - definemap context: 56 | // waffle: hello world 57 | // item: 58 | // - customevent id:things_happened context:<[context]> 59 | // 60 | // @Usage 61 | // Use to call a custom event and allow cancelling or replacing a value. 62 | // - definemap context: 63 | // message: hello world 64 | // - customevent id:custom_message context:<[context]> save:event 65 | // - if : 66 | // - stop 67 | // - define message ]> 68 | // - narrate "Final message is: <[message]>" 69 | // 70 | // --> 71 | 72 | public static void autoExecute(ScriptEntry scriptEntry, 73 | @ArgPrefixed @ArgName("id") ElementTag id, 74 | @ArgDefaultNull @ArgPrefixed @ArgName("context") MapTag context) { 75 | CustomScriptEvent ranEvent = CustomScriptEvent.runCustomEvent(scriptEntry.entryData, id.asLowerString(), context); 76 | scriptEntry.saveObject("any_ran", new ElementTag(ranEvent != null && ranEvent.anyMatched)); 77 | scriptEntry.saveObject("was_cancelled", new ElementTag(ranEvent != null && ranEvent.cancelled)); 78 | scriptEntry.saveObject("determination_list", ranEvent == null ? new ListTag() : new ListTag(ranEvent.determinations)); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/core/DebugInvalidCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.core; 2 | 3 | import com.denizenscript.denizencore.DenizenCore; 4 | import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; 5 | import com.denizenscript.denizencore.scripts.ScriptEntry; 6 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 7 | import com.denizenscript.denizencore.utilities.debugging.Debug; 8 | 9 | /** 10 | * This command exists for technical reasons, to handle invalid commands. 11 | */ 12 | public class DebugInvalidCommand extends AbstractCommand { 13 | 14 | public DebugInvalidCommand() { 15 | setName("debug-invalid-command"); 16 | setSyntax(""); 17 | setRequiredArguments(0, Integer.MAX_VALUE); 18 | isProcedural = true; 19 | } 20 | 21 | @Override 22 | public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { 23 | } 24 | 25 | public static void informBrokenArgs(AbstractCommand command, ScriptEntry scriptEntry) { 26 | if (scriptEntry.getOriginalArguments().size() > command.maximumArguments) { 27 | Debug.echoError(scriptEntry, scriptEntry + " cannot be executed! Too many arguments - did you forget to use quotes?\nUsage: " + command.getUsageHint()); 28 | } 29 | else if (command.generatedExecutor != null && scriptEntry.internal.arguments_to_use.length > command.linearHandledCount) { 30 | String badPrefix = null; 31 | for (ScriptEntry.InternalArgument arg : scriptEntry.internal.arguments_to_use) { 32 | if (arg.prefix != null) { 33 | badPrefix = arg.prefix.fullOriginalRawValue; 34 | break; 35 | } 36 | } 37 | if (badPrefix == null) { 38 | Debug.echoError(scriptEntry, scriptEntry + " cannot be executed! Too many linear arguments - did you forget to use quotes, or forget a prefix?\nUsage: " + command.getUsageHint()); 39 | } 40 | else { 41 | Debug.echoError(scriptEntry, scriptEntry + " cannot be executed! Too many linear arguments... Prefix '" + badPrefix + "' given is unrecognized. Possible typo?\nUsage: " + command.getUsageHint()); 42 | } 43 | } 44 | else { 45 | Debug.echoError(scriptEntry, scriptEntry + " cannot be executed! Too few arguments - did you forget a required input?\nUsage: " + command.getUsageHint()); 46 | } 47 | } 48 | 49 | @Override 50 | public void execute(ScriptEntry scriptEntry) { 51 | Debug.echoDebug(scriptEntry, Debug.DebugElement.Header, "Executing command: " + scriptEntry.getCommandName()); 52 | AbstractCommand command = DenizenCore.commandRegistry.get(scriptEntry.internal.command); 53 | if (scriptEntry.internal.brokenArgs) { 54 | informBrokenArgs(command, scriptEntry); 55 | return; 56 | } 57 | else { 58 | if (command != null) { 59 | int argCount = scriptEntry.getOriginalArguments().size(); 60 | if (argCount < command.minimumArguments || argCount > command.maximumArguments) { 61 | scriptEntry.internal.brokenArgs = true; 62 | } 63 | else { 64 | scriptEntry.internal.actualCommand = command; 65 | } 66 | scriptEntry.getResidingQueue().injectEntryAtStart(scriptEntry); 67 | return; 68 | } 69 | Debug.echoError(scriptEntry, scriptEntry.getCommandName() + " is an invalid command! Are you sure it loaded?"); 70 | } 71 | Debug.echoDebug(scriptEntry, Debug.DebugElement.Footer); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/core/NoteCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.core; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectFetcher; 4 | import com.denizenscript.denizencore.objects.ObjectTag; 5 | import com.denizenscript.denizencore.objects.core.ElementTag; 6 | import com.denizenscript.denizencore.objects.notable.Notable; 7 | import com.denizenscript.denizencore.objects.notable.NoteManager; 8 | import com.denizenscript.denizencore.scripts.ScriptEntry; 9 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 10 | import com.denizenscript.denizencore.scripts.commands.generator.ArgLinear; 11 | import com.denizenscript.denizencore.scripts.commands.generator.ArgName; 12 | import com.denizenscript.denizencore.scripts.commands.generator.ArgPrefixed; 13 | import com.denizenscript.denizencore.utilities.debugging.Debug; 14 | 15 | public class NoteCommand extends AbstractCommand { 16 | 17 | public NoteCommand() { 18 | setName("note"); 19 | setSyntax("note [/remove] [as:]"); 20 | setRequiredArguments(2, 2); 21 | isProcedural = false; 22 | autoCompile(); 23 | addRemappedPrefixes("as", "id", "i"); 24 | } 25 | 26 | // <--[command] 27 | // @Name Note 28 | // @Syntax note [/remove] [as:] 29 | // @Required 2 30 | // @Maximum 2 31 | // @Short Adds or removes a named note of an object to the server. 32 | // @Synonyms Notable 33 | // @Group core 34 | // @Guide https://guide.denizenscript.com/guides/advanced/notables.html 35 | // 36 | // @Description 37 | // Add or remove a 'note' to the server, persistently naming an object that can be referenced in events or scripts. 38 | // Only works for object types that are 'notable'. 39 | // Noted objects are "permanent" versions of other ObjectTags. (See: <@link language ObjectTags>) 40 | // Noted objects keep their properties when added. 41 | // 42 | // Notable object types: CuboidTag, EllipsoidTag, PolygonTag, LocationTag, InventoryTag 43 | // 44 | // @Tags 45 | // ]> 46 | // 47 | // 48 | // 49 | // 50 | // 51 | // 52 | // @Usage 53 | // Use to note a cuboid. 54 | // - note <[some_cuboid]> as:mycuboid 55 | // 56 | // @Usage 57 | // Use to remove a noted cuboid. 58 | // - note remove as:mycuboid 59 | // 60 | // @Usage 61 | // Use to note a location. 62 | // - note as:mylocation 63 | // --> 64 | 65 | public static void autoExecute(ScriptEntry scriptEntry, 66 | @ArgLinear @ArgName("object") ObjectTag object, 67 | @ArgPrefixed @ArgName("as") String id) { 68 | boolean remove = object instanceof ElementTag && object.asElement().asLowerString().equals("remove"); 69 | if (remove) { 70 | Notable note = NoteManager.getSavedObject(id); 71 | if (note != null) { 72 | note.forget(); 73 | Debug.echoDebug(scriptEntry, "Note '" + id + "' removed"); 74 | } 75 | else { 76 | Debug.echoDebug(scriptEntry, id + " is not saved"); 77 | } 78 | return; 79 | } 80 | if (object instanceof ElementTag) { 81 | String stringified = object.toString(); 82 | object = ObjectFetcher.pickObjectFor(stringified, scriptEntry.context); 83 | if (object == null) { 84 | Debug.echoError("Failed to read the object '" + stringified + "' into a real object value."); 85 | return; 86 | } 87 | } 88 | if (!(object instanceof Notable)) { 89 | Debug.echoError("Object '" + object + "' has type '" + object.getDenizenObjectType() + "' which is not a notable object type."); 90 | return; 91 | } 92 | try { 93 | ((Notable) object).makeUnique(id); 94 | } 95 | catch (Throwable ex) { 96 | Debug.echoError("Something went wrong converting that object!"); 97 | Debug.echoError(ex); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/core/ReloadCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.core; 2 | 3 | import com.denizenscript.denizencore.objects.notable.NoteManager; 4 | import com.denizenscript.denizencore.scripts.ScriptEntry; 5 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 6 | import com.denizenscript.denizencore.DenizenCore; 7 | import com.denizenscript.denizencore.scripts.commands.Holdable; 8 | import com.denizenscript.denizencore.scripts.commands.generator.ArgDefaultText; 9 | import com.denizenscript.denizencore.scripts.commands.generator.ArgName; 10 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 11 | import com.denizenscript.denizencore.utilities.debugging.DebugInternals; 12 | 13 | import java.util.function.Consumer; 14 | 15 | public class ReloadCommand extends AbstractCommand implements Holdable { 16 | 17 | public ReloadCommand() { 18 | setName("reload"); 19 | setSyntax("reload ({scripts}/scripts_now/config/saves/notes)"); 20 | setRequiredArguments(0, 1); 21 | isProcedural = false; 22 | autoCompile(); 23 | } 24 | 25 | // <--[command] 26 | // @Name Reload 27 | // @Syntax reload ({scripts}/scripts_now/config/saves/notes) 28 | // @Required 0 29 | // @Maximum 1 30 | // @Short Reloads all Denizen scripts. Primarily for use as an in-game command. 31 | // @Group core 32 | // 33 | // @Description 34 | // Reloads all Denizen scripts. 35 | // Primarily for use as an in-game command, like "/ex reload". 36 | // 37 | // By default, reloads scripts in a way that may delay a few ticks to avoid interrupting the server on large reloads. 38 | // 39 | // Optionally, specify "scripts_now" to force a locked reload (server freezes until reloaded). 40 | // 41 | // You can specify "config", "saves", or "notes" to reload that data instead of scripts. 42 | // 43 | // When using 'scripts' (default), the reload command is ~waitable. Refer to <@link language ~waitable>. 44 | // 45 | // @Tags 46 | // None 47 | // 48 | // @Usage 49 | // Use to reload scripts automatically 50 | // - reload 51 | // 52 | // --> 53 | 54 | public enum ReloadType { SCRIPTS, SCRIPTS_NOW, CONFIG, SAVES, NOTES } 55 | 56 | public static void autoExecute(ScriptEntry scriptEntry, ScriptQueue queue, 57 | @ArgName("type") @ArgDefaultText("scripts") ReloadType type) { 58 | switch (type) { 59 | case SCRIPTS: 60 | Consumer altDebug = queue.debugOutput; 61 | if (altDebug != null) { 62 | DebugInternals.specialBackupSender = (s) -> DenizenCore.runOnMainThread(() -> altDebug.accept(s)); 63 | } 64 | DenizenCore.reloadScripts(true, () -> { 65 | DebugInternals.specialBackupSender = null; 66 | scriptEntry.setFinished(true); 67 | }); 68 | break; 69 | case SCRIPTS_NOW: 70 | scriptEntry.setFinished(true); 71 | DenizenCore.reloadScripts(false, null); 72 | break; 73 | case CONFIG: 74 | scriptEntry.setFinished(true); 75 | DenizenCore.implementation.reloadConfig(); 76 | break; 77 | case SAVES: 78 | scriptEntry.setFinished(true); 79 | DenizenCore.implementation.reloadSaves(); 80 | break; 81 | case NOTES: 82 | scriptEntry.setFinished(true); 83 | NoteManager.reload(); 84 | break; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/file/FileReadCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.file; 2 | 3 | import com.denizenscript.denizencore.DenizenCore; 4 | import com.denizenscript.denizencore.objects.core.BinaryTag; 5 | import com.denizenscript.denizencore.scripts.ScriptEntry; 6 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 7 | import com.denizenscript.denizencore.scripts.commands.Holdable; 8 | import com.denizenscript.denizencore.scripts.commands.generator.ArgName; 9 | import com.denizenscript.denizencore.scripts.commands.generator.ArgPrefixed; 10 | import com.denizenscript.denizencore.utilities.CoreConfiguration; 11 | import com.denizenscript.denizencore.utilities.debugging.Debug; 12 | 13 | import java.io.File; 14 | import java.io.FileInputStream; 15 | 16 | public class FileReadCommand extends AbstractCommand implements Holdable { 17 | 18 | public FileReadCommand() { 19 | setName("fileread"); 20 | setSyntax("fileread [path:]"); 21 | setRequiredArguments(1, 1); 22 | isProcedural = false; 23 | autoCompile(); 24 | } 25 | 26 | // <--[command] 27 | // @Name FileRead 28 | // @Syntax fileread [path:] 29 | // @Required 1 30 | // @Maximum 1 31 | // @Short Reads the file at the given path. 32 | // @Group file 33 | // 34 | // @Description 35 | // Reads the file at the given path. 36 | // 37 | // The starting directory is server/plugins/Denizen. 38 | // 39 | // Note that in most cases this command should be ~waited for (like "- ~fileread ..."). Refer to <@link language ~waitable>. 40 | // 41 | // This command must be enabled by setting Denizen config option "Commands.File.Allow read" to true. 42 | // 43 | // @Tags 44 | // returns a BinaryTag of the raw file content. 45 | // 46 | // @Usage 47 | // Use to read 'myfile' and narrate the text content. 48 | // - ~fileread path:data/myfile.dat save:read 49 | // - narrate "Read data: " 50 | // 51 | // --> 52 | 53 | public static void autoExecute(final ScriptEntry scriptEntry, 54 | @ArgPrefixed @ArgName("path") final String path) { 55 | File file = getFileIfSafe(path, scriptEntry); 56 | if (file == null) { 57 | return; 58 | } 59 | Runnable runme = () -> { 60 | try { 61 | FileInputStream stream = new FileInputStream(file); 62 | byte[] data = stream.readAllBytes(); 63 | stream.close(); 64 | scriptEntry.saveObject("data", new BinaryTag(data)); 65 | scriptEntry.setFinished(true); 66 | } 67 | catch (Exception e) { 68 | Debug.echoError(scriptEntry, e); 69 | scriptEntry.setFinished(true); 70 | } 71 | }; 72 | if (scriptEntry.shouldWaitFor()) { 73 | DenizenCore.runAsync(runme); 74 | } 75 | else { 76 | runme.run(); 77 | } 78 | } 79 | 80 | public static File getFileIfSafe(String path, ScriptEntry scriptEntry) { 81 | if (!CoreConfiguration.allowFileRead) { 82 | Debug.echoError(scriptEntry, "FileRead disabled in Denizen/config.yml (refer to command documentation)."); 83 | scriptEntry.setFinished(true); 84 | return null; 85 | } 86 | File file = new File(DenizenCore.implementation.getDataFolder(), path); 87 | if (!DenizenCore.implementation.canReadFile(file)) { 88 | Debug.echoError("Cannot read from that file path due to security settings in Denizen/config.yml."); 89 | scriptEntry.setFinished(true); 90 | return null; 91 | } 92 | try { 93 | if (!CoreConfiguration.filePathLimit.equals("none")) { 94 | File root = new File(DenizenCore.implementation.getDataFolder(), CoreConfiguration.filePathLimit); 95 | if (!file.getCanonicalPath().startsWith(root.getCanonicalPath())) { 96 | Debug.echoError("File path '" + path + "' is not within the config's restricted data file path."); 97 | scriptEntry.setFinished(true); 98 | return null; 99 | } 100 | } 101 | if (!file.exists()) { 102 | Debug.echoError(scriptEntry, "File read failed, file does not exist!"); 103 | scriptEntry.setFinished(true); 104 | return null; 105 | } 106 | } 107 | catch (Exception e) { 108 | Debug.echoError(scriptEntry, e); 109 | scriptEntry.setFinished(true); 110 | return null; 111 | } 112 | return file; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/file/FileWriteCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.file; 2 | 3 | import com.denizenscript.denizencore.DenizenCore; 4 | import com.denizenscript.denizencore.objects.core.BinaryTag; 5 | import com.denizenscript.denizencore.scripts.ScriptEntry; 6 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 7 | import com.denizenscript.denizencore.scripts.commands.Holdable; 8 | import com.denizenscript.denizencore.scripts.commands.generator.ArgName; 9 | import com.denizenscript.denizencore.scripts.commands.generator.ArgPrefixed; 10 | import com.denizenscript.denizencore.utilities.CoreConfiguration; 11 | import com.denizenscript.denizencore.utilities.debugging.Debug; 12 | 13 | import java.io.File; 14 | import java.io.FileOutputStream; 15 | 16 | public class FileWriteCommand extends AbstractCommand implements Holdable { 17 | 18 | public FileWriteCommand() { 19 | setName("filewrite"); 20 | setSyntax("filewrite [path:] [data:]"); 21 | setRequiredArguments(2, 2); 22 | isProcedural = false; 23 | autoCompile(); 24 | } 25 | 26 | // <--[command] 27 | // @Name FileWrite 28 | // @Syntax filewrite [path:] [data:] 29 | // @Required 2 30 | // @Maximum 2 31 | // @Short Writes the given raw data to the file at the given path. 32 | // @Group file 33 | // 34 | // @Description 35 | // Writes the given raw data to the file at the given path. 36 | // 37 | // Will overwrite any existing file at the path. 38 | // 39 | // The starting directory is server/plugins/Denizen. 40 | // 41 | // Directories will automatically be generated as-needed. 42 | // 43 | // Note that in most cases this command should be ~waited for (like "- ~filewrite ..."). Refer to <@link language ~waitable>. 44 | // 45 | // This command must be enabled by setting Denizen config option "Commands.File.Allow write" to true. 46 | // 47 | // @Tags 48 | // None 49 | // 50 | // @Usage 51 | // Use to write some simple text to 'myfile' 52 | // - ~filewrite path:data/myfile.dat data: 53 | // 54 | // --> 55 | 56 | public static void autoExecute(final ScriptEntry scriptEntry, 57 | @ArgPrefixed @ArgName("path") final String path, 58 | @ArgPrefixed @ArgName("data") BinaryTag data) { 59 | File file = getFileIfSafe(path, scriptEntry); 60 | if (file == null) { 61 | return; 62 | } 63 | Runnable runme = () -> { 64 | try { 65 | if (!file.getParentFile().exists()) { 66 | file.getParentFile().mkdirs(); 67 | } 68 | FileOutputStream stream = new FileOutputStream(file); 69 | stream.write(data.data); 70 | stream.close(); 71 | scriptEntry.setFinished(true); 72 | } 73 | catch (Exception e) { 74 | Debug.echoError(scriptEntry, e); 75 | scriptEntry.setFinished(true); 76 | } 77 | }; 78 | if (scriptEntry.shouldWaitFor()) { 79 | DenizenCore.runAsync(runme); 80 | } 81 | else { 82 | runme.run(); 83 | } 84 | } 85 | 86 | public static File getFileIfSafe(String path, ScriptEntry scriptEntry) { 87 | if (!CoreConfiguration.allowFileWrite) { 88 | Debug.echoError(scriptEntry, "File write disabled in Denizen/config.yml (refer to command documentation)."); 89 | scriptEntry.setFinished(true); 90 | return null; 91 | } 92 | File file = new File(DenizenCore.implementation.getDataFolder(), path); 93 | if (!DenizenCore.implementation.canWriteToFile(file)) { 94 | Debug.echoError("Cannot write to that file path due to security settings in Denizen/config.yml."); 95 | scriptEntry.setFinished(true); 96 | return null; 97 | } 98 | try { 99 | if (!CoreConfiguration.filePathLimit.equals("none")) { 100 | File root = new File(DenizenCore.implementation.getDataFolder(), CoreConfiguration.filePathLimit); 101 | if (!file.getCanonicalPath().startsWith(root.getCanonicalPath())) { 102 | Debug.echoError("File path '" + path + "' is not within the config's restricted data file path."); 103 | scriptEntry.setFinished(true); 104 | return null; 105 | } 106 | } 107 | } 108 | catch (Exception ex) { 109 | Debug.echoError(ex); 110 | scriptEntry.setFinished(true); 111 | return null; 112 | } 113 | return file; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/generator/ArgDefaultNull.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Specifies that an argument is optional and defaults to null. */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.PARAMETER) 11 | public @interface ArgDefaultNull { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/generator/ArgDefaultText.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Specifies that an argument is optional and defaults to the given value. */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.PARAMETER) 11 | public @interface ArgDefaultText { 12 | String value(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/generator/ArgLinear.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Specifies that an argument is located by its linear order in the set of arguments not otherwise taken. */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.PARAMETER) 11 | public @interface ArgLinear { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/generator/ArgName.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Specifies the name of an argument. */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.PARAMETER) 11 | public @interface ArgName { 12 | String value(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/generator/ArgNoDebug.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Specifies that an argument doesn't debug output. */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.PARAMETER) 11 | public @interface ArgNoDebug { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/generator/ArgPrefixed.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Specifies that an argument must have its prefix specified in the script command. */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.PARAMETER) 11 | public @interface ArgPrefixed { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/generator/ArgRaw.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Specifies that the argument should use a raw element, ignoring prefix-parsing. */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.PARAMETER) 11 | public @interface ArgRaw { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/generator/ArgSubType.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Specifies that an argument should not be pre-parsed. */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.PARAMETER) 11 | public @interface ArgSubType { 12 | 13 | Class value(); 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/generator/ArgUnparsed.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.generator; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** Specifies that an argument should not be pre-parsed. */ 9 | @Retention(RetentionPolicy.RUNTIME) 10 | @Target(ElementType.PARAMETER) 11 | public @interface ArgUnparsed { 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/queue/DefineMapCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.queue; 2 | 3 | import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; 4 | import com.denizenscript.denizencore.objects.Argument; 5 | import com.denizenscript.denizencore.objects.core.ElementTag; 6 | import com.denizenscript.denizencore.objects.core.MapTag; 7 | import com.denizenscript.denizencore.objects.core.QueueTag; 8 | import com.denizenscript.denizencore.scripts.ScriptEntry; 9 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 10 | import com.denizenscript.denizencore.utilities.CoreUtilities; 11 | import com.denizenscript.denizencore.utilities.debugging.Debug; 12 | 13 | import java.util.Map; 14 | 15 | public class DefineMapCommand extends AbstractCommand { 16 | 17 | public DefineMapCommand() { 18 | setName("definemap"); 19 | setSyntax("definemap [] [: ...]"); 20 | setRequiredArguments(1, -1); 21 | isProcedural = true; 22 | allowedDynamicPrefixes = true; 23 | anyPrefixSymbolAllowed = true; 24 | } 25 | 26 | // <--[command] 27 | // @Name DefineMap 28 | // @Syntax definemap [] [: ...] 29 | // @Required 1 30 | // @Maximum -1 31 | // @Short Creates a MapTag definition with key/value pairs constructed from the input arguments. 32 | // @Group queue 33 | // @Guide https://guide.denizenscript.com/guides/basics/definitions.html 34 | // 35 | // @Description 36 | // Creates a MapTag definition with key/value pairs constructed from the input arguments. 37 | // 38 | // @Tags 39 | // <[]> to get the value assigned to an ID 40 | // 41 | // @Usage 42 | // Use to make a MapTag definition with three inputs. 43 | // - definemap my_map count:5 type:Taco smell:Tasty 44 | // 45 | // @Usage 46 | // Use to make a MapTag definition with complex input. 47 | // - definemap my_map: 48 | // count: 5 49 | // some_list: 50 | // - a 51 | // - b 52 | // some_submap: 53 | // some_subkey: taco 54 | // 55 | // --> 56 | 57 | @Override 58 | public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { 59 | MapTag value = new MapTag(); 60 | for (Argument arg : scriptEntry) { 61 | if (!scriptEntry.hasObject("definition") 62 | && !arg.hasPrefix()) { 63 | scriptEntry.addObject("definition", new ElementTag(CoreUtilities.toLowerCase(arg.getValue()))); 64 | } 65 | else if (arg.hasPrefix()) { 66 | value.putObject(arg.getPrefix().getRawValue(), arg.object); 67 | } 68 | else if (!arg.hasPrefix() && arg.getRawValue().contains(":")) { 69 | int colon = arg.getRawValue().indexOf(':'); 70 | value.putObject(arg.getRawValue().substring(0, colon), new ElementTag(arg.getRawValue().substring(colon + 1))); 71 | } 72 | else { 73 | arg.reportUnhandled(); 74 | } 75 | } 76 | if (scriptEntry.internal.yamlSubcontent instanceof Map) { 77 | MapTag map = (MapTag) CoreUtilities.objectToTagForm(scriptEntry.internal.yamlSubcontent, scriptEntry.getContext(), true, true); 78 | value.putAll(map); 79 | } 80 | scriptEntry.addObject("map", value); 81 | if (!scriptEntry.hasObject("definition") || !scriptEntry.hasObject("map")) { 82 | throw new InvalidArgumentsException("Must specify a definition and value!"); 83 | } 84 | } 85 | 86 | @Override 87 | public void execute(ScriptEntry scriptEntry) { 88 | ElementTag definition = scriptEntry.getElement("definition"); 89 | MapTag value = scriptEntry.getObjectTag("map"); 90 | if (scriptEntry.dbCallShouldDebug()) { 91 | Debug.report(scriptEntry, getName(), new QueueTag(scriptEntry.getResidingQueue()), definition, value); 92 | } 93 | scriptEntry.getResidingQueue().addDefinition(definition.asString(), value.duplicate()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/queue/DetermineCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.queue; 2 | 3 | import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; 4 | import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException; 5 | import com.denizenscript.denizencore.objects.Argument; 6 | import com.denizenscript.denizencore.objects.core.ListTag; 7 | import com.denizenscript.denizencore.objects.core.QueueTag; 8 | import com.denizenscript.denizencore.scripts.ScriptEntry; 9 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 10 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 11 | import com.denizenscript.denizencore.utilities.debugging.Debug; 12 | 13 | public class DetermineCommand extends AbstractCommand { 14 | 15 | public DetermineCommand() { 16 | setName("determine"); 17 | setSyntax("determine (passively) []"); 18 | setRequiredArguments(1, 2); 19 | isProcedural = true; 20 | setBooleanHandled("passively"); 21 | } 22 | 23 | // <--[command] 24 | // @Name Determine 25 | // @Syntax determine (passively) [] 26 | // @Required 1 27 | // @Maximum 2 28 | // @Short Sets the outcome of a script. 29 | // @Group queue 30 | // @Synonyms Return 31 | // @Guide https://guide.denizenscript.com/guides/first-steps/world-script.html 32 | // 33 | // @Description 34 | // Sets the outcome of a script. 35 | // The most common use case is within script events (for example, to cancel the event). 36 | // This is also required for all procedure scripts. 37 | // It may be useful in other cases (such as a task script that returns a result, via the save argument). 38 | // 39 | // By default, the determine command will end the queue (similar to <@link command stop>). 40 | // If you wish to prevent this, specify the "passively" argument. 41 | // 42 | // To make multiple determines, simply use the determine command multiple times in a row, with the "passively" argument on each. 43 | // 44 | // @Tags 45 | // 46 | // 47 | // @Usage 48 | // Use to modify the result of an event. 49 | // - determine message: 50 | // 51 | // @Usage 52 | // Use to cancel an event, but continue running script commands. 53 | // - determine passively cancelled 54 | // 55 | // --> 56 | 57 | @Override 58 | public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { 59 | for (Argument arg : scriptEntry) { 60 | if (!scriptEntry.hasObject("outcome")) { 61 | scriptEntry.addObject("outcome", arg); 62 | } 63 | else { 64 | arg.reportUnhandled(); 65 | } 66 | } 67 | } 68 | 69 | @Override 70 | public void execute(ScriptEntry scriptEntry) { 71 | Argument outcomeArg = (Argument) scriptEntry.getObject("outcome"); 72 | if (outcomeArg == null) { 73 | throw new InvalidArgumentsRuntimeException("Must specify a value to determine."); 74 | } 75 | boolean passively = scriptEntry.argAsBoolean("passively"); 76 | if (scriptEntry.dbCallShouldDebug()) { 77 | Debug.report(scriptEntry, getName(), db("outcome", outcomeArg), db("passively", passively), new QueueTag(scriptEntry.getResidingQueue())); 78 | } 79 | ScriptQueue queue = scriptEntry.getResidingQueue(); 80 | ListTag determines = queue.determinations; 81 | if (determines == null) { 82 | determines = new ListTag(); 83 | queue.determinations = determines; 84 | } 85 | determines.addObject(outcomeArg.hasPrefix() ? outcomeArg.getRawElement() : outcomeArg.object); 86 | if (queue.determinationTarget != null) { 87 | queue.determinationTarget.applyDetermination(outcomeArg.prefix, outcomeArg.object); 88 | } 89 | 90 | if (!passively) { 91 | scriptEntry.getResidingQueue().clear(); 92 | scriptEntry.getResidingQueue().stop(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/queue/ElseCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.queue; 2 | 3 | import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; 4 | import com.denizenscript.denizencore.utilities.debugging.Debug; 5 | import com.denizenscript.denizencore.scripts.ScriptEntry; 6 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 7 | 8 | public class ElseCommand extends AbstractCommand { 9 | 10 | public ElseCommand() { 11 | setName("else"); 12 | setSyntax("else (if )"); 13 | setRequiredArguments(0, -1); 14 | isProcedural = true; 15 | } 16 | 17 | // <--[command] 18 | // @Name Else 19 | // @Syntax else (if ) 20 | // @Required 0 21 | // @Maximum -1 22 | // @Short Helper command for usage with the if command. 23 | // @Group queue 24 | // @Guide https://guide.denizenscript.com/guides/basics/if-command.html 25 | // 26 | // @Description 27 | // A helper command to use with if commands. 28 | // See <@link command if> command documentation. 29 | // 30 | // @Tags 31 | // See IF command documentation. 32 | // 33 | // @Usage 34 | // See IF command documentation. 35 | // --> 36 | 37 | @Override 38 | public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { 39 | } 40 | 41 | @Override 42 | public void execute(ScriptEntry scriptEntry) { 43 | 44 | // If this command executes normally, it's misplaced. It should always be skipped past under normal execution. 45 | Debug.echoError(scriptEntry, "Misplaced ELSE command."); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/queue/GotoCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.queue; 2 | 3 | import com.denizenscript.denizencore.scripts.commands.generator.ArgLinear; 4 | import com.denizenscript.denizencore.scripts.commands.generator.ArgName; 5 | import com.denizenscript.denizencore.scripts.commands.generator.ArgRaw; 6 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 7 | import com.denizenscript.denizencore.utilities.CoreUtilities; 8 | import com.denizenscript.denizencore.utilities.debugging.Debug; 9 | import com.denizenscript.denizencore.scripts.ScriptEntry; 10 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 11 | 12 | import java.util.List; 13 | 14 | public class GotoCommand extends AbstractCommand { 15 | 16 | public GotoCommand() { 17 | setName("goto"); 18 | setSyntax("goto []"); 19 | setRequiredArguments(1, 1); 20 | isProcedural = true; 21 | autoCompile(); 22 | } 23 | 24 | // <--[command] 25 | // @Name Goto 26 | // @Syntax goto [] 27 | // @Required 1 28 | // @Maximum 1 29 | // @Short Jump forward to a location marked by <@link command mark>. 30 | // @Group queue 31 | // 32 | // @Description 33 | // Jumps forward to a marked location in the script. 34 | // For example: 35 | // 36 | // - goto potato 37 | // - narrate "This will never show" 38 | // - mark potato 39 | // 40 | // 41 | // Most scripters should never use this. This is only for certain special cases. 42 | // 43 | // @Tags 44 | // None 45 | // 46 | // @Usage 47 | // Use to jump forward to a location. 48 | // - goto potato 49 | // --> 50 | 51 | public static void autoExecute(ScriptQueue queue, 52 | @ArgRaw @ArgLinear @ArgName("mark_name") String markName) { 53 | boolean hasmark = false; 54 | for (int i = 0; i < queue.getQueueSize(); i++) { 55 | ScriptEntry entry = queue.getEntry(i); 56 | List args = entry.getOriginalArguments(); 57 | if (CoreUtilities.equalsIgnoreCase(entry.getCommandName(), "mark") && args.size() > 0 && CoreUtilities.equalsIgnoreCase(args.get(0), markName)) { 58 | hasmark = true; 59 | break; 60 | } 61 | } 62 | if (hasmark) { 63 | while (queue.getQueueSize() > 0) { 64 | ScriptEntry entry = queue.getEntry(0); 65 | List args = entry.getOriginalArguments(); 66 | if (CoreUtilities.equalsIgnoreCase(entry.getCommandName(), "mark") && args.size() > 0 && CoreUtilities.equalsIgnoreCase(args.get(0), markName)) { 67 | break; 68 | } 69 | queue.removeFirst(); 70 | } 71 | } 72 | else { 73 | Debug.echoError("Cannot go to that location - doesn't seem to exist!"); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/queue/MarkCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.queue; 2 | 3 | import com.denizenscript.denizencore.scripts.commands.generator.ArgLinear; 4 | import com.denizenscript.denizencore.scripts.commands.generator.ArgName; 5 | import com.denizenscript.denizencore.scripts.commands.generator.ArgRaw; 6 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 7 | 8 | public class MarkCommand extends AbstractCommand { 9 | 10 | public MarkCommand() { 11 | setName("mark"); 12 | setSyntax("mark []"); 13 | setRequiredArguments(1, 1); 14 | isProcedural = true; 15 | autoCompile(); 16 | } 17 | 18 | // <--[command] 19 | // @Name Mark 20 | // @Syntax mark [] 21 | // @Required 1 22 | // @Maximum 1 23 | // @Short Marks a location for <@link command goto>. 24 | // @Group queue 25 | // 26 | // @Description 27 | // Marks a location for the goto command. See <@link command goto> for details. 28 | // 29 | // @Tags 30 | // 31 | // None 32 | // 33 | // @Usage 34 | // Use to mark a location. 35 | // - mark potato 36 | // 37 | // --> 38 | 39 | public static void autoExecute(@ArgRaw @ArgLinear @ArgName("mark_name") String markName) { 40 | // Do nothing, this is just a marker. 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/queue/RateLimitCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.queue; 2 | 3 | import com.denizenscript.denizencore.DenizenCore; 4 | import com.denizenscript.denizencore.exceptions.InvalidArgumentsException; 5 | import com.denizenscript.denizencore.objects.Argument; 6 | import com.denizenscript.denizencore.objects.core.DurationTag; 7 | import com.denizenscript.denizencore.objects.core.ElementTag; 8 | import com.denizenscript.denizencore.scripts.ScriptEntry; 9 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 10 | import com.denizenscript.denizencore.utilities.Deprecations; 11 | import com.denizenscript.denizencore.utilities.debugging.Debug; 12 | 13 | import java.util.HashMap; 14 | 15 | public class RateLimitCommand extends AbstractCommand { 16 | 17 | public RateLimitCommand() { 18 | setName("ratelimit"); 19 | setSyntax("ratelimit [] []"); 20 | setRequiredArguments(2, 2); 21 | isProcedural = true; 22 | } 23 | 24 | // <--[command] 25 | // @Name RateLimit 26 | // @Syntax ratelimit [] [] 27 | // @Required 2 28 | // @Maximum 2 29 | // @Short Limits the rate that queues may process a script at. 30 | // @Group queue 31 | // 32 | // @Description 33 | // Limits the rate that queues may process a script at. 34 | // If another queue tries to run the same script faster than the duration, that second queue will be stopped. 35 | // 36 | // Note that the rate limiting is tracked based on two unique factors: the object input, and the specific script line. 37 | // That is to say: if you have a 'ratelimit 10s', and then a few lines down a 'ratelimit 10s', 38 | // those are two separate rate limiters. 39 | // Additionally, if you have a 'ratelimit 10s' and two different players run it, they each have a separate rate limit applied. 40 | // 41 | // Note that this uses game delta tick time, not system realtime. 42 | // 43 | // @Tags 44 | // None 45 | // 46 | // @Usage 47 | // Use to show a message to a player no faster than once every ten seconds. 48 | // - ratelimit 10s 49 | // - narrate "Wow!" 50 | // --> 51 | 52 | @Override 53 | public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { 54 | for (Argument arg : scriptEntry) { 55 | if (arg.matchesArgumentType(DurationTag.class) 56 | && !scriptEntry.hasObject("duration") 57 | && arg.limitToOnlyPrefix("duration")) { 58 | if (!scriptEntry.hasObject("object")) { 59 | Deprecations.outOfOrderArgs.warn(scriptEntry); 60 | } 61 | scriptEntry.addObject("duration", arg.asType(DurationTag.class)); 62 | } 63 | else if (!scriptEntry.hasObject("object") 64 | && arg.limitToOnlyPrefix("object")) { 65 | scriptEntry.addObject("object", arg.getRawElement()); 66 | } 67 | else { 68 | arg.reportUnhandled(); 69 | } 70 | } 71 | } 72 | 73 | @Override 74 | public void execute(ScriptEntry scriptEntry) { 75 | DurationTag duration = scriptEntry.getObjectTag("duration"); 76 | ElementTag object = scriptEntry.getElement("object"); 77 | if (scriptEntry.dbCallShouldDebug()) { 78 | Debug.report(scriptEntry, getName(), duration, object); 79 | } 80 | if (scriptEntry.internal.specialProcessedData == null) { 81 | scriptEntry.internal.specialProcessedData = new HashMap<>(2); 82 | } 83 | HashMap map = (HashMap) scriptEntry.internal.specialProcessedData; 84 | String key = object.asLowerString(); 85 | Long endTime = map.get(key); 86 | long curTime = DenizenCore.serverTimeMillis; 87 | if (endTime != null && curTime < endTime) { 88 | Debug.echoDebug(scriptEntry, "Rate limit applied with " + (endTime - curTime) + "ms left."); 89 | scriptEntry.getResidingQueue().clear(); 90 | scriptEntry.getResidingQueue().stop(); 91 | return; 92 | } 93 | map.put(key, curTime + duration.getMillis()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/queue/StopCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.queue; 2 | 3 | import com.denizenscript.denizencore.scripts.ScriptEntry; 4 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 5 | 6 | public class StopCommand extends AbstractCommand { 7 | 8 | public StopCommand() { 9 | setName("stop"); 10 | setSyntax("stop"); 11 | setRequiredArguments(0, 0); 12 | isProcedural = true; 13 | autoCompile(); 14 | } 15 | 16 | // <--[command] 17 | // @Name Stop 18 | // @Syntax stop 19 | // @Required 0 20 | // @Maximum 0 21 | // @Short Stops the current queue. 22 | // @Group queue 23 | // 24 | // @Description 25 | // This will immediately stop the current queue, preventing it from processing any further. 26 | // 27 | // @Tags 28 | // to get the current queue. 29 | // 30 | // @Usage 31 | // Use to stop the current queue. 32 | // - stop 33 | // --> 34 | 35 | public static void autoExecute(ScriptEntry scriptEntry) { 36 | scriptEntry.getResidingQueue().clear(); 37 | scriptEntry.getResidingQueue().stop(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/commands/queue/WaitCommand.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.commands.queue; 2 | 3 | import com.denizenscript.denizencore.objects.core.QueueTag; 4 | import com.denizenscript.denizencore.scripts.commands.generator.*; 5 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 6 | import com.denizenscript.denizencore.scripts.queues.core.TimedQueue; 7 | import com.denizenscript.denizencore.utilities.CoreUtilities; 8 | import com.denizenscript.denizencore.objects.core.DurationTag; 9 | import com.denizenscript.denizencore.scripts.ScriptEntry; 10 | import com.denizenscript.denizencore.scripts.commands.AbstractCommand; 11 | 12 | public class WaitCommand extends AbstractCommand { 13 | 14 | public WaitCommand() { 15 | setName("wait"); 16 | setSyntax("wait () (queue:) (system/{delta})"); 17 | setRequiredArguments(0, 3); 18 | isProcedural = false; // A procedure can't wait 19 | autoCompile(); 20 | } 21 | 22 | // <--[command] 23 | // @Name Wait 24 | // @Syntax wait () (queue:) (system/{delta}) 25 | // @Required 0 26 | // @Maximum 3 27 | // @Short Delays a script for a specified amount of time. 28 | // @Synonyms Delay 29 | // @Group queue 30 | // 31 | // @Description 32 | // Pauses the script queue for the duration specified. If no duration is specified it defaults to 3 seconds. 33 | // Accepts the 'queue:' argument which allows the delay of a different queue. 34 | // 35 | // Accepts a 'system' argument to delay based on system time (real-world time on a clock). 36 | // When that argument is not used, waits based on delta time (in-game time tracking, which tends to vary by small amounts, especially when the server is lagging). 37 | // Generally, do not use the 'system' argument unless you have a specific good reason you need it. 38 | // 39 | // @Tags 40 | // 41 | // 42 | // @Usage 43 | // Use to delay the current queue for 1 minute. 44 | // - wait 1m 45 | // 46 | // @Usage 47 | // Use to delay the current queue until 1 hour of system time passes. 48 | // - wait 1h system 49 | // --> 50 | 51 | public static class SystemTimeDelayTracker implements TimedQueue.DelayTracker { 52 | 53 | public long systemTimeEnd; 54 | 55 | public SystemTimeDelayTracker(long millis) { 56 | systemTimeEnd = CoreUtilities.monotonicMillis() + millis; 57 | } 58 | 59 | @Override 60 | public boolean isDelayed() { 61 | return systemTimeEnd > CoreUtilities.monotonicMillis(); 62 | } 63 | } 64 | 65 | public enum Mode {SYSTEM, DELTA} 66 | 67 | public static void autoExecute(ScriptEntry scriptEntry, ScriptQueue backingQueue, 68 | @ArgLinear @ArgName("delay") DurationTag delay, 69 | @ArgName("mode") @ArgDefaultText("delta") Mode mode, 70 | @ArgPrefixed @ArgName("queue") @ArgDefaultNull QueueTag queue) { 71 | if (queue == null) { 72 | queue = new QueueTag(backingQueue); 73 | } 74 | TimedQueue.DelayTracker tracker; 75 | if (mode == Mode.SYSTEM) { 76 | tracker = new SystemTimeDelayTracker(delay.getMillis()); 77 | } 78 | else { 79 | tracker = new TimedQueue.DeltaTimeDelayTracker(delay.getMillis()); 80 | } 81 | if (queue.queue instanceof TimedQueue) { 82 | ((TimedQueue) queue.queue).delay = tracker; 83 | } 84 | else { 85 | scriptEntry.setInstant(false); 86 | queue.queue.forceToTimed(tracker); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/containers/core/DataScriptContainer.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.containers.core; 2 | 3 | import com.denizenscript.denizencore.scripts.containers.ScriptContainer; 4 | import com.denizenscript.denizencore.utilities.Deprecations; 5 | import com.denizenscript.denizencore.utilities.YamlConfiguration; 6 | 7 | public class DataScriptContainer extends ScriptContainer { 8 | 9 | // <--[language] 10 | // @name Data Script Containers 11 | // @group Script Container System 12 | // @description 13 | // Data script containers are generic script containers for information that will be referenced by other scripts. 14 | // 15 | // No part of a 'data' script container is ever run as commands. 16 | // 17 | // There are no required keys. 18 | // 19 | // Generally, data is read using the <@link tag ScriptTag.data_key> tag. 20 | // 21 | // 22 | // data_script_name: 23 | // 24 | // type: data 25 | // 26 | // # Your data here 27 | // some_key: some value 28 | // some_list_key: 29 | // - some list value 30 | // some_map_key: 31 | // some_subkey: some value 32 | // 33 | // 34 | // 35 | // --> 36 | 37 | public DataScriptContainer(YamlConfiguration configurationSection, String scriptContainerName) { 38 | super(configurationSection, scriptContainerName); 39 | canRunScripts = false; 40 | if (configurationSection.get("type").toString().equalsIgnoreCase("yaml data")) { 41 | Deprecations.yamlDataContainer.warn(this); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/containers/core/ProcedureScriptContainer.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.containers.core; 2 | 3 | import com.denizenscript.denizencore.DenizenCore; 4 | import com.denizenscript.denizencore.scripts.containers.ScriptContainer; 5 | import com.denizenscript.denizencore.utilities.YamlConfiguration; 6 | 7 | public class ProcedureScriptContainer extends ScriptContainer { 8 | 9 | // <--[language] 10 | // @name Procedure Script Containers 11 | // @group Script Container System 12 | // @description 13 | // Procedure script containers are used to define a script that can be ran through a tag. 14 | // 15 | // Generally called via <@link tag proc> or <@link tag proc.context>. 16 | // 17 | // The only required key is 'script:'. 18 | // 19 | // Note that procedure scripts must NEVER change external state. 20 | // That is, a procedure script cannot change anything at all, ONLY determine a value. 21 | // Setting a flag, loading a YAML document, placing a block, etc. are all examples of external changes that are NOT allowed. 22 | // 23 | // This restriction comes from two main reasons: 24 | // - Tags run in arbitrary conditions. They may be read asynchronously or in other weird circumstances that can result 25 | // in applied changes crashing your server or other unexpected side effects. 26 | // - Tags can run for a variety of reasons. 27 | // If you were to make a proc script 'spawn_entity' that actually spawns an entity into the world, 28 | // you would likely end up with a *lot* of unintentional entity spawns. 29 | // Some tags will be read multiple times when theoretically ran once, 30 | // in some circumstances a tag read might even be based on user input! (Particularly if you ever make use of the '.parsed' tag, 31 | // or the list.parse/filter/sort_by_number tags). 32 | // Imagine if for example, a tag can be read when users input a specific custom command, 33 | // and a clever user finds out they can type "/testcommand 32 " 34 | // to spawn a creeper ... that would be a major problem! 35 | // In general, maximum caution is the best for situations like this... simply *never* make a procedure 36 | // that executes external changes. 37 | // 38 | // 39 | // Proc_Script_Name: 40 | // 41 | // type: procedure 42 | // 43 | // # Optionally specify definition names to use with the 'context' input of the proc tag. 44 | // definitions: def|names|here 45 | // 46 | // script: 47 | // 48 | // # Put any logic, then determine the result. 49 | // - determine 5 50 | // 51 | // 52 | // 53 | // --> 54 | 55 | public ProcedureScriptContainer(YamlConfiguration configurationSection, String scriptContainerName) { 56 | super(configurationSection, scriptContainerName); 57 | } 58 | 59 | @Override 60 | public void postCheck() { 61 | // Trigger load + cache 62 | if (shouldEnable() && contains("script")) { 63 | getBaseEntries(DenizenCore.implementation.getEmptyScriptEntryData()); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/containers/core/TaskScriptContainer.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.containers.core; 2 | 3 | import com.denizenscript.denizencore.DenizenCore; 4 | import com.denizenscript.denizencore.scripts.ScriptEntryData; 5 | import com.denizenscript.denizencore.scripts.containers.ScriptContainer; 6 | import com.denizenscript.denizencore.scripts.queues.ContextSource; 7 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 8 | import com.denizenscript.denizencore.utilities.ScriptUtilities; 9 | import com.denizenscript.denizencore.utilities.YamlConfiguration; 10 | 11 | import java.util.function.Consumer; 12 | 13 | public class TaskScriptContainer extends ScriptContainer { 14 | 15 | // <--[language] 16 | // @name Task Script Containers 17 | // @group Script Container System 18 | // @description 19 | // Task script containers are generic script containers for commands that can be run at 20 | // any time by command. 21 | // 22 | // Generally tasks will be ran by <@link command run> or <@link command inject>. 23 | // 24 | // The only required key on a task script container is the 'script:' key. 25 | // 26 | // 27 | // Task_Script_Name: 28 | // 29 | // type: task 30 | // 31 | // # When intending to run a task script via the run command with the "def:" argument to pass data through, 32 | // # use this "definitions" key to specify the names of the definitions (in the same order as the "def:" argument will use). 33 | // # You can optionally document a definition with [square brackets] 34 | // definitions: name1|name2[description here]|... 35 | // 36 | // script: 37 | // 38 | // - your commands here 39 | // 40 | // 41 | // 42 | // --> 43 | 44 | public TaskScriptContainer(YamlConfiguration configurationSection, String scriptContainerName) { 45 | super(configurationSection, scriptContainerName); 46 | } 47 | 48 | @Override 49 | public void postCheck() { 50 | // Trigger load + cache 51 | if (shouldEnable() && contains("script")) { 52 | getBaseEntries(DenizenCore.implementation.getEmptyScriptEntryData()); 53 | } 54 | } 55 | 56 | /** 57 | * Runs the task script. 58 | * @return the new queue. 59 | */ 60 | public ScriptQueue run() { 61 | return run(null, null, null); 62 | } 63 | 64 | /** 65 | * Runs the task script. 66 | * @param data the player/npc/other data to attach. 67 | * @return the new queue. 68 | */ 69 | public ScriptQueue run(ScriptEntryData data) { 70 | return run(data, null, null); 71 | } 72 | 73 | /** 74 | * Runs the task script. 75 | * @param data the player/npc/other data to attach. 76 | * @param context the provider for <context> data. 77 | * @return the new queue. 78 | */ 79 | public ScriptQueue run(ScriptEntryData data, ContextSource context) { 80 | return run(data, context, null); 81 | } 82 | 83 | /** 84 | * Runs the task script. 85 | * @param data the player/npc/other data to attach. 86 | * @param context the provider for <context> data. 87 | * @param configure a function to configure the queue (eg add definitions) before starting. 88 | * @return the new queue. 89 | */ 90 | public ScriptQueue run(ScriptEntryData data, ContextSource context, Consumer configure) { 91 | return ScriptUtilities.createAndStartQueue(this, null, data, context, configure, null, null, null, null); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/containers/core/WorldScriptContainer.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.containers.core; 2 | 3 | import com.denizenscript.denizencore.scripts.containers.ScriptContainer; 4 | import com.denizenscript.denizencore.utilities.YamlConfiguration; 5 | import com.denizenscript.denizencore.events.ScriptEvent; 6 | 7 | public class WorldScriptContainer extends ScriptContainer { 8 | 9 | // <--[language] 10 | // @name World Script Containers 11 | // @group Script Container System 12 | // @description 13 | // World script containers are generic script containers for commands that are automatically 14 | // ran when some given event happens in the server. 15 | // 16 | // The only required key is 'events:', within which you can list any events to handle. 17 | // 18 | // World scripts can be automatically disabled by adding "enabled: false" as a root key (supports any load-time-parseable tags). 19 | // 20 | // 21 | // World_Script_Name: 22 | // 23 | // type: world 24 | // 25 | // events: 26 | // 27 | // # Any event label can be placed here 28 | // # This includes generic labels like 'on entity death:', 29 | // # Specified labels like 'on player death:', 30 | // # And detailed labels like 'on player death ignorecancelled:true priority:5:' 31 | // some event label: 32 | // # Write any logic that should fire when the event runs. 33 | // # Optionally 'determine' any results to the event. 34 | // - some commands 35 | // 36 | // # List additional events here 37 | // 38 | // 39 | // 40 | // --> 41 | 42 | public WorldScriptContainer(YamlConfiguration configurationSection, String scriptContainerName) { 43 | super(configurationSection, scriptContainerName); 44 | ScriptEvent.worldContainers.add(this); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/queues/ContextSource.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.queues; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectTag; 4 | 5 | import java.util.Map; 6 | 7 | /** 8 | * Provides contexts to a queue. 9 | */ 10 | public interface ContextSource { 11 | 12 | ObjectTag getContext(String name); 13 | 14 | class SimpleMap implements ContextSource { 15 | 16 | public Map contexts; 17 | 18 | @Override 19 | public ObjectTag getContext(String name) { 20 | return contexts.get(name); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/queues/DeterminationTarget.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.queues; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectTag; 4 | 5 | public interface DeterminationTarget { 6 | 7 | void applyDetermination(String prefix, ObjectTag value); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/queues/ScriptEngine.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.queues; 2 | 3 | import com.denizenscript.denizencore.scripts.commands.CommandExecutor; 4 | import com.denizenscript.denizencore.scripts.queues.core.TimedQueue; 5 | import com.denizenscript.denizencore.utilities.debugging.Debug; 6 | import com.denizenscript.denizencore.scripts.ScriptEntry; 7 | 8 | public class ScriptEngine { 9 | 10 | static boolean shouldHold(ScriptQueue scriptQueue) { 11 | if (scriptQueue instanceof TimedQueue && ((TimedQueue) scriptQueue).isPaused()) { 12 | return true; 13 | } 14 | ScriptEntry last = scriptQueue.getLastEntryExecuted(); 15 | if (last == null || !last.shouldWaitFor()) { 16 | return false; 17 | } 18 | if (!(scriptQueue instanceof TimedQueue)) { 19 | scriptQueue.forceToTimed(null); 20 | } 21 | return true; 22 | } 23 | 24 | public static void revolveOnceForce(ScriptQueue scriptQueue) { 25 | ScriptEntry scriptEntry = scriptQueue.getNext(); 26 | if (scriptEntry == null) { 27 | return; 28 | } 29 | scriptEntry.setSendingQueue(scriptQueue); 30 | scriptEntry.updateContext(); 31 | scriptQueue.setLastEntryExecuted(scriptEntry); 32 | if (scriptEntry.internal.waitfor) { 33 | scriptQueue.holdingOn = scriptEntry; 34 | } 35 | try { 36 | CommandExecutor.execute(scriptEntry); 37 | } 38 | catch (Throwable e) { 39 | Debug.echoError(scriptEntry, "An exception has been called with this command (while revolving the queue forcefully)!"); 40 | Debug.echoError(scriptEntry, e); 41 | } 42 | } 43 | 44 | public static void revolve(ScriptQueue scriptQueue) { 45 | if (shouldHold(scriptQueue)) { 46 | return; 47 | } 48 | ScriptEntry scriptEntry = scriptQueue.getNext(); 49 | while (scriptEntry != null) { 50 | scriptEntry.setSendingQueue(scriptQueue); 51 | scriptEntry.updateContext(); 52 | scriptQueue.setLastEntryExecuted(scriptEntry); 53 | if (scriptEntry.internal.waitfor) { 54 | scriptQueue.holdingOn = scriptEntry; 55 | } 56 | CommandExecutor.execute(scriptEntry); 57 | if (scriptQueue instanceof TimedQueue) { 58 | TimedQueue delayedQueue = (TimedQueue) scriptQueue; 59 | if (delayedQueue.isDelayed() || delayedQueue.isPaused()) { 60 | break; 61 | } 62 | if (delayedQueue.isInstantSpeed() || scriptEntry.isInstant()) { 63 | if (shouldHold(scriptQueue)) { 64 | return; 65 | } 66 | scriptEntry = scriptQueue.getNext(); 67 | } 68 | else { 69 | break; 70 | } 71 | } 72 | else if (scriptEntry.isInstant()) { 73 | if (shouldHold(scriptQueue)) { 74 | return; 75 | } 76 | scriptEntry = scriptQueue.getNext(); 77 | } 78 | else { 79 | break; 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/queues/core/InstantQueue.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.queues.core; 2 | 3 | import com.denizenscript.denizencore.scripts.queues.ScriptEngine; 4 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 5 | 6 | public class InstantQueue extends ScriptQueue { 7 | 8 | public InstantQueue(String id) { 9 | super(id); 10 | } 11 | 12 | @Override 13 | public void onStart() { 14 | while (is_started) { 15 | if (script_entries.isEmpty() && holdingOn == null) { 16 | stop(); 17 | return; 18 | } 19 | ScriptEngine.revolve(this); 20 | } 21 | } 22 | 23 | @Override 24 | public String getName() { 25 | return "InstantQueue"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/scripts/queues/core/TimedQueue.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.scripts.queues.core; 2 | 3 | import com.denizenscript.denizencore.scripts.queues.ScriptEngine; 4 | import com.denizenscript.denizencore.utilities.CoreConfiguration; 5 | import com.denizenscript.denizencore.DenizenCore; 6 | import com.denizenscript.denizencore.objects.core.DurationTag; 7 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 8 | 9 | public class TimedQueue extends ScriptQueue { 10 | 11 | @FunctionalInterface 12 | public interface DelayTracker { 13 | 14 | boolean isDelayed(); 15 | } 16 | 17 | public static class DeltaTimeDelayTracker implements DelayTracker { 18 | 19 | public long serverTimeEnd; 20 | 21 | public DeltaTimeDelayTracker(long millis) { 22 | serverTimeEnd = DenizenCore.serverTimeMillis + millis; 23 | } 24 | 25 | @Override 26 | public boolean isDelayed() { 27 | return serverTimeEnd > DenizenCore.serverTimeMillis; 28 | } 29 | } 30 | 31 | private long ticks; 32 | 33 | protected boolean paused = false; 34 | 35 | public DelayTracker delay; 36 | 37 | public void delayFor(DurationTag duration) { 38 | delay = new DeltaTimeDelayTracker(duration.getMillis()); 39 | } 40 | 41 | public boolean isDelayed() { 42 | return delay != null && delay.isDelayed(); 43 | } 44 | 45 | public TimedQueue(String id) { 46 | this(id, new DurationTag(CoreConfiguration.scriptQueueSpeed)); 47 | } 48 | 49 | public TimedQueue(String id, long ticks) { 50 | super(id); 51 | this.ticks = ticks; 52 | } 53 | 54 | public TimedQueue(String id, DurationTag timing) { 55 | super(id); 56 | ticks = timing.getTicks(); 57 | } 58 | 59 | public boolean isInstantSpeed() { 60 | return ticks <= 0; 61 | } 62 | 63 | /** 64 | * Gets the speed of the queue. This is the 65 | * time in between each revolution. 66 | * 67 | * @return a DurationTag of the speed. 68 | */ 69 | public DurationTag getSpeed() { 70 | return new DurationTag(ticks); 71 | } 72 | 73 | /** 74 | * Pauses the queue. Paused queues will check 75 | * to be re-resumed every 'rotation', defined 76 | * by the speed of the queue. 77 | * 78 | * @param paused whether the queue should be paused 79 | */ 80 | public TimedQueue setPaused(boolean paused) { 81 | this.paused = paused; 82 | return this; 83 | } 84 | 85 | /** 86 | * Checks if the queue is currently paused. 87 | * 88 | * @return true if paused. 89 | */ 90 | public boolean isPaused() { 91 | return paused; 92 | } 93 | 94 | /** 95 | * Sets the speed of a queue. Uses bukkit's 'ticks', which is 96 | * 20 ticks per second. 97 | * 98 | * @param ticks the number of ticks between each rotation. 99 | */ 100 | public TimedQueue setSpeed(long ticks) { 101 | this.ticks = ticks; 102 | return this; 103 | } 104 | 105 | @Override 106 | public void onStart() { 107 | revolve(); 108 | if (script_entries.isEmpty() && holdingOn == null) { 109 | return; 110 | } 111 | DenizenCore.timedQueues.add(this); 112 | } 113 | 114 | /** 115 | * Tick counter for 'tryRevolveOnce'. 116 | */ 117 | public int tickCounter = 0; 118 | 119 | /** 120 | * Tries to revolve the timedqueue, incrementing the tick counter and only revolving if it's time to. 121 | */ 122 | public final void tryRevolveOnce() { 123 | if (tickCounter++ >= ticks) { 124 | tickCounter = 0; 125 | revolve(); 126 | } 127 | } 128 | 129 | public void revolve() { 130 | if (script_entries.isEmpty() && holdingOn == null) { 131 | if (!waitWhenEmpty) { 132 | stop(); 133 | } 134 | return; 135 | } 136 | if (paused || isDelayed()) { 137 | return; 138 | } 139 | ScriptEngine.revolve(this); 140 | if (script_entries.isEmpty() && holdingOn == null && !waitWhenEmpty) { 141 | stop(); 142 | } 143 | } 144 | 145 | @Override 146 | public String getName() { 147 | return "TimedQueue"; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/ParseableTag.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags; 2 | 3 | 4 | import com.denizenscript.denizencore.objects.ObjectTag; 5 | import com.denizenscript.denizencore.objects.core.ElementTag; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Simple core representation of a section of user input that may contain tags, with methods to parse the tags inside. 11 | */ 12 | public class ParseableTag { 13 | 14 | public ObjectTag rawObject; 15 | 16 | public List pieces; 17 | 18 | public TagManager.ParseableTagPiece singleTag; 19 | 20 | public boolean hasTag; 21 | 22 | /** 23 | * Get the object represented by this tag. 24 | * If the user input was plaintext (ie not a tag, or text mixed with a tag), with return an ElementTag. 25 | */ 26 | public final ObjectTag parse(TagContext context) { 27 | if (rawObject != null) { 28 | return rawObject; 29 | } 30 | else if (singleTag != null) { 31 | return TagManager.readSingleTagObject(singleTag, context); 32 | } 33 | return TagManager.parseChainObject(pieces, context); 34 | } 35 | 36 | public ParseableTag() { 37 | } 38 | 39 | public ParseableTag(String text) { 40 | ElementTag rawElement = new ElementTag(text, true); 41 | rawElement.isRawInput = true; 42 | rawObject = rawElement; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | if (rawObject != null) { 48 | return rawObject.toString(); 49 | } 50 | else { 51 | return "(ParseableTag: non-static value)"; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/PseudoObjectTagBase.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectFetcher; 4 | import com.denizenscript.denizencore.objects.ObjectTag; 5 | import com.denizenscript.denizencore.objects.ObjectType; 6 | import com.denizenscript.denizencore.objects.core.ElementTag; 7 | import com.denizenscript.denizencore.utilities.debugging.DebugInternals; 8 | 9 | public abstract class PseudoObjectTagBase implements ObjectTag { 10 | 11 | @Override 12 | public String getPrefix() { 13 | return identify(); 14 | } 15 | 16 | @Override 17 | public boolean isUnique() { 18 | return true; 19 | } 20 | 21 | @Override 22 | public String identify() { 23 | return "(Base-Object)"; 24 | } 25 | 26 | @Override 27 | public String toString() { 28 | return identify(); 29 | } 30 | 31 | @Override 32 | public String identifySimple() { 33 | return identify(); 34 | } 35 | 36 | @Override 37 | public ObjectTag setPrefix(String prefix) { 38 | return this; 39 | } 40 | 41 | @Override 42 | public ObjectTag getNextObjectTypeDown() { 43 | return new ElementTag.FailedObjectTag(); 44 | } 45 | 46 | public ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); 47 | 48 | public ObjectType type = new ObjectType<>(); 49 | 50 | public abstract void register(); 51 | 52 | @Override 53 | public ObjectTag getObjectAttribute(Attribute attribute) { 54 | return tagProcessor.getObjectAttribute((T) this, attribute); 55 | } 56 | 57 | public PseudoObjectTagBase() { 58 | tagProcessor.type = (Class) getClass(); 59 | type.tagProcessor = tagProcessor; 60 | type.clazz = tagProcessor.type; 61 | type.longName = DebugInternals.getClassNameOpti(getClass()); 62 | ObjectFetcher.objectsByClass.put(type.clazz, type); 63 | register(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/TagContext.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags; 2 | 3 | import com.denizenscript.denizencore.objects.core.ScriptTag; 4 | import com.denizenscript.denizencore.scripts.ScriptEntry; 5 | import com.denizenscript.denizencore.scripts.ScriptEntryData; 6 | import com.denizenscript.denizencore.scripts.queues.ContextSource; 7 | import com.denizenscript.denizencore.utilities.DefinitionProvider; 8 | import com.denizenscript.denizencore.utilities.SimpleDefinitionProvider; 9 | import com.denizenscript.denizencore.utilities.debugging.Debug; 10 | import com.denizenscript.denizencore.utilities.debugging.Debuggable; 11 | 12 | public abstract class TagContext implements Debuggable, Cloneable { 13 | 14 | @FunctionalInterface 15 | public interface ShowErrorsMethod { 16 | boolean showErrors(); 17 | } 18 | 19 | private static boolean defaultShowErrors() { 20 | return true; 21 | } 22 | 23 | public boolean debug; 24 | public ShowErrorsMethod showErrors = TagContext::defaultShowErrors; 25 | public ScriptEntry entry; 26 | public ScriptTag script; 27 | public DefinitionProvider definitionProvider; 28 | public ContextSource contextSource; 29 | 30 | @Override 31 | public TagContext clone() { 32 | try { 33 | return (TagContext) super.clone(); 34 | } 35 | catch (CloneNotSupportedException ex) { 36 | Debug.echoError(ex); 37 | return null; 38 | } 39 | } 40 | 41 | public boolean showErrors() { 42 | return debug || (showErrors != null && showErrors.showErrors()); 43 | } 44 | 45 | @Override 46 | public boolean shouldDebug() { 47 | return debug; 48 | } 49 | 50 | public TagContext(ScriptEntry entry) { 51 | if (entry != null) { 52 | this.entry = entry; 53 | this.script = entry.getScript(); 54 | this.debug = entry.shouldDebug(); 55 | if (entry.getResidingQueue() != null) { 56 | definitionProvider = entry.getResidingQueue(); 57 | contextSource = entry.getResidingQueue().contextSource; 58 | } 59 | } 60 | else { 61 | debug = true; 62 | } 63 | } 64 | 65 | public TagContext(boolean debug, ScriptEntry entry, ScriptTag script) { 66 | this(debug, entry, script, null); 67 | } 68 | 69 | public TagContext(boolean debug, ScriptEntry entry, ScriptTag script, DefinitionProvider definitionProvider) { 70 | this.debug = debug; 71 | this.entry = entry; 72 | this.script = script; 73 | this.definitionProvider = definitionProvider != null ? definitionProvider : 74 | (entry != null ? entry.getResidingQueue() : new SimpleDefinitionProvider()); 75 | if (entry != null && entry.getResidingQueue() != null) { 76 | this.contextSource = entry.getResidingQueue().contextSource; 77 | } 78 | } 79 | 80 | public abstract ScriptEntryData getScriptEntryData(); 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/TagRunnable.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectTag; 4 | import com.denizenscript.denizencore.utilities.debugging.Debug; 5 | 6 | public abstract class TagRunnable implements Cloneable { 7 | 8 | @FunctionalInterface 9 | public interface ObjectInterface { 10 | 11 | R run(Attribute attribute, T object); 12 | } 13 | 14 | @FunctionalInterface 15 | public interface ObjectWithParamInterface { 16 | 17 | R run(Attribute attribute, T object, P param); 18 | } 19 | 20 | @FunctionalInterface 21 | public interface BaseInterface { 22 | 23 | R run(Attribute attribute); 24 | } 25 | 26 | @FunctionalInterface 27 | public interface BaseWithParamInterface { 28 | 29 | R run(Attribute attribute, P param); 30 | } 31 | 32 | @Deprecated 33 | public static abstract class RootForm implements Cloneable { 34 | 35 | @Override 36 | public RootForm clone() { 37 | try { 38 | return (RootForm) super.clone(); 39 | } 40 | catch (Exception ex) { 41 | Debug.echoError(ex); 42 | return null; 43 | } 44 | } 45 | 46 | public String name = null; 47 | 48 | public abstract void run(ReplaceableTagEvent event); 49 | } 50 | 51 | @Override 52 | public TagRunnable clone() { 53 | try { 54 | return (TagRunnable) super.clone(); 55 | } 56 | catch (Exception ex) { 57 | Debug.echoError(ex); 58 | return null; 59 | } 60 | } 61 | 62 | public String name = null; 63 | 64 | /** 65 | * Calculates the tag. 66 | * 67 | * @param attribute the tag input. 68 | * @param object the object being calculated against. 69 | * @return null if this tag is invalid or a string of the return value if it is valid. 70 | */ 71 | public abstract String run(Attribute attribute, ObjectTag object); 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/core/ContextTagBase.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags.core; 2 | 3 | import com.denizenscript.denizencore.objects.core.ElementTag; 4 | import com.denizenscript.denizencore.tags.TagRunnable; 5 | import com.denizenscript.denizencore.objects.ObjectTag; 6 | import com.denizenscript.denizencore.tags.Attribute; 7 | import com.denizenscript.denizencore.tags.ReplaceableTagEvent; 8 | import com.denizenscript.denizencore.utilities.CoreUtilities; 9 | import com.denizenscript.denizencore.utilities.DefinitionProvider; 10 | import com.denizenscript.denizencore.utilities.Deprecations; 11 | import com.denizenscript.denizencore.tags.TagManager; 12 | 13 | public class ContextTagBase { 14 | 15 | public ContextTagBase() { 16 | // Intentionally no docs 17 | TagManager.registerTagHandler(new TagRunnable.RootForm() { 18 | @Override 19 | public void run(ReplaceableTagEvent event) { 20 | contextTags(event); 21 | } 22 | }, "context", "c"); 23 | // Intentionally no docs 24 | TagManager.registerTagHandler(ObjectTag.class, ElementTag.class, "entry", (attribute, heldId) -> { 25 | attribute.fulfill(1); 26 | String saveEntryKey = attribute.getAttributeWithoutParam(1); 27 | DefinitionProvider definitionProvider = attribute.context.definitionProvider; 28 | if (definitionProvider == null) { 29 | attribute.echoError("No definitions are provided in this tag's context!"); 30 | return null; 31 | } 32 | ObjectTag def = definitionProvider.getDefinitionObject("__save_entries." + heldId.toString() + "." + saveEntryKey); 33 | if (def == null) { 34 | attribute.echoError("Invalid saved entry ID '" + heldId + "." + saveEntryKey + "'"); 35 | return null; 36 | } 37 | return def; 38 | }); 39 | } 40 | 41 | public void contextTags(ReplaceableTagEvent event) { 42 | Attribute attribute = event.getAttributes(); 43 | if (!event.matches("context", "c") || attribute.context.contextSource == null) { 44 | return; 45 | } 46 | if (event.matches("c")) { 47 | Deprecations.contextShorthand.warn(event.getScriptEntry()); 48 | } 49 | String contextName = attribute.getAttributeWithoutParam(2); 50 | ObjectTag obj = event.getAttributes().context.contextSource.getContext(contextName); 51 | if (obj != null) { 52 | event.setReplacedObject(CoreUtilities.autoAttrib(obj, attribute.fulfill(2))); 53 | return; 54 | } 55 | if (!event.hasAlternative()) { 56 | attribute.echoError("Invalid context ID '" + contextName + "'!"); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/core/DefinitionTagBase.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags.core; 2 | 3 | import com.denizenscript.denizencore.objects.core.ElementTag; 4 | import com.denizenscript.denizencore.tags.TagRunnable; 5 | import com.denizenscript.denizencore.objects.ObjectTag; 6 | import com.denizenscript.denizencore.tags.TagManager; 7 | import com.denizenscript.denizencore.utilities.CoreUtilities; 8 | import com.denizenscript.denizencore.utilities.DefinitionProvider; 9 | 10 | public class DefinitionTagBase { 11 | 12 | public DefinitionTagBase() { 13 | 14 | // <--[tag] 15 | // @attribute ]> 16 | // @returns ObjectTag 17 | // @description 18 | // Returns a definition from the current queue. 19 | // The object will be returned as the most-valid type based on the input. 20 | // In most usages, the tag name is left blank, like "<[defhere]>". 21 | // You can use "." in a definition name to read a submapped key if the root definition is a MapTag. 22 | // @example 23 | // - define x 3 24 | // # Narrates '3' 25 | // - narrate <[x]> 26 | // @example 27 | // - definemap mymap: 28 | // mykey: example 29 | // # Narrates 'example' 30 | // - narrate <[mymap.mykey]> 31 | // --> 32 | TagRunnable.BaseWithParamInterface defTag = (attribute, defName) -> { 33 | DefinitionProvider definitionProvider = attribute.context.definitionProvider; 34 | if (definitionProvider == null) { 35 | attribute.echoError("No definitions are provided in this tag's context!"); 36 | return null; 37 | } 38 | ObjectTag def = definitionProvider.getDefinitionObject(defName.asLowerString()); 39 | if (def == null) { 40 | attribute.echoError("Invalid definition name '" + defName + "'."); 41 | return null; 42 | } 43 | if (attribute.attributes.length == 1) { 44 | return def.refreshState(); 45 | } 46 | return CoreUtilities.fixType(def, attribute.context); 47 | }; 48 | TagManager.registerTagHandler(ObjectTag.class, ElementTag.class, "def", defTag); 49 | TagManager.registerTagHandler(ObjectTag.class, ElementTag.class, "definition", defTag); 50 | TagManager.registerTagHandler(ObjectTag.class, ElementTag.class, "", defTag); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/core/ListSingleTagBase.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags.core; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectTag; 4 | import com.denizenscript.denizencore.objects.core.ListTag; 5 | import com.denizenscript.denizencore.tags.TagManager; 6 | 7 | public class ListSingleTagBase { 8 | 9 | public ListSingleTagBase() { 10 | 11 | // <--[tag] 12 | // @attribute ]> 13 | // @returns ListTag 14 | // @description 15 | // Returns a ListTag object with exactly 1 entry: whatever the input value is (even if that input is a list). 16 | // This is primarily useful for creating lists-within-lists. 17 | // --> 18 | TagManager.registerStaticTagBaseHandler(ListTag.class, ObjectTag.class, "list_single", (attribute, param) -> { 19 | ListTag list = new ListTag(); 20 | list.addObject(param); 21 | return list; 22 | }); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/core/ListTagBase.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags.core; 2 | 3 | import com.denizenscript.denizencore.objects.core.ListTag; 4 | import com.denizenscript.denizencore.tags.TagManager; 5 | 6 | public class ListTagBase { 7 | 8 | public ListTagBase() { 9 | 10 | // <--[tag] 11 | // @attribute )]> 12 | // @returns ListTag 13 | // @description 14 | // Returns a list object constructed from the input value. 15 | // Give no input to create an empty list. 16 | // Refer to <@link ObjectType ListTag>. 17 | // --> 18 | TagManager.registerStaticTagBaseHandler(ListTag.class, "list", (attribute) -> { 19 | if (!attribute.hasParam()) { 20 | return new ListTag(); 21 | } 22 | return ListTag.getListFor(attribute.getParamObject(), attribute.context); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/core/MapTagBase.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags.core; 2 | 3 | import com.denizenscript.denizencore.objects.core.MapTag; 4 | import com.denizenscript.denizencore.tags.TagManager; 5 | 6 | public class MapTagBase { 7 | 8 | public MapTagBase() { 9 | 10 | // <--[tag] 11 | // @attribute )]> 12 | // @returns MapTag 13 | // @description 14 | // Returns a map object constructed from the input value. 15 | // Give no input to create an empty map. 16 | // Refer to <@link ObjectType MapTag>. 17 | // For example: 18 | // --> 19 | TagManager.registerStaticTagBaseHandler(MapTag.class, "map", (attribute) -> { 20 | if (!attribute.hasParam()) { 21 | return new MapTag(); 22 | } 23 | return MapTag.getMapFor(attribute.getParamObject(), attribute.context); 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/core/ProcedureScriptTagBase.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags.core; 2 | 3 | import com.denizenscript.denizencore.objects.ObjectTag; 4 | import com.denizenscript.denizencore.objects.core.*; 5 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 6 | import com.denizenscript.denizencore.scripts.containers.core.ProcedureScriptContainer; 7 | import com.denizenscript.denizencore.utilities.ScriptUtilities; 8 | import com.denizenscript.denizencore.tags.TagManager; 9 | import com.denizenscript.denizencore.utilities.text.StringHolder; 10 | 11 | import java.util.Map; 12 | 13 | public class ProcedureScriptTagBase { 14 | 15 | public ProcedureScriptTagBase() { 16 | 17 | // <--[tag] 18 | // @attribute ]> 19 | // @returns ObjectTag 20 | // @description 21 | // Returns the 'determine' result of a procedure script. 22 | // --> 23 | TagManager.registerTagHandler(ObjectTag.class, ElementTag.class, "proc", (attribute, param) -> { 24 | ScriptTag script; 25 | String path = null; 26 | if (param.asString().indexOf('.') > 0) { 27 | String[] split = param.asString().split("\\.", 2); 28 | path = split[1]; 29 | script = ScriptTag.valueOf(split[0], attribute.context); 30 | } 31 | else { 32 | script = param.asType(ScriptTag.class, attribute.context); 33 | } 34 | if (script == null) { 35 | attribute.echoError("Missing script for procedure script tag '" + param.asString() + "'!"); 36 | return null; 37 | } 38 | if (!(script.getContainer() instanceof ProcedureScriptContainer)) { 39 | attribute.echoError("Chosen script is not a procedure script!"); 40 | return null; 41 | } 42 | ListTag definitions = null; 43 | MapTag mappedDefinitions; 44 | 45 | // <--[tag] 46 | // @attribute ].context[|...]> 47 | // @returns ObjectTag 48 | // @description 49 | // Returns the 'determine' result of a procedure script with the given context. 50 | // --> 51 | if (attribute.startsWith("context", 2)) { 52 | mappedDefinitions = null; 53 | definitions = attribute.contextAsType(2, ListTag.class); 54 | attribute.fulfill(1); 55 | } 56 | 57 | // <--[tag] 58 | // @attribute ].context_map[]> 59 | // @returns ObjectTag 60 | // @description 61 | // Returns the 'determine' result of a procedure script with the given context. 62 | // --> 63 | else if (attribute.startsWith("context_map", 2)) { 64 | mappedDefinitions = attribute.contextAsType(2, MapTag.class); 65 | attribute.fulfill(1); 66 | } 67 | else { 68 | mappedDefinitions = null; 69 | } 70 | ScriptQueue queue = ScriptUtilities.createAndStartQueue(script.getContainer(), path, attribute.context.getScriptEntryData(), null, (q) -> { 71 | if (mappedDefinitions != null) { 72 | for (Map.Entry val : mappedDefinitions.entrySet()) { 73 | q.addDefinition(val.getKey().str, val.getValue()); 74 | } 75 | } 76 | q.procedural = true; 77 | }, new DurationTag(0), null, definitions, script.getContainer()); 78 | if (queue == null) { 79 | attribute.echoError("Procedure queue start failed."); 80 | return null; 81 | } 82 | if (queue.determinations == null || queue.determinations.isEmpty()) { 83 | attribute.echoError("Procedure call did not determine any value."); 84 | return null; 85 | } 86 | return queue.determinations.getObject(0); 87 | }); 88 | 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/core/QueueTagBase.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags.core; 2 | 3 | import com.denizenscript.denizencore.objects.core.ElementTag; 4 | import com.denizenscript.denizencore.objects.core.ListTag; 5 | import com.denizenscript.denizencore.objects.core.QueueTag; 6 | import com.denizenscript.denizencore.scripts.queues.ScriptQueue; 7 | import com.denizenscript.denizencore.tags.Attribute; 8 | import com.denizenscript.denizencore.tags.ReplaceableTagEvent; 9 | import com.denizenscript.denizencore.tags.TagManager; 10 | import com.denizenscript.denizencore.tags.TagRunnable; 11 | import com.denizenscript.denizencore.utilities.CoreUtilities; 12 | import com.denizenscript.denizencore.utilities.Deprecations; 13 | 14 | public class QueueTagBase { 15 | 16 | public QueueTagBase() { 17 | 18 | // <--[tag] 19 | // @attribute )]> 20 | // @returns QueueTag 21 | // @description 22 | // Returns a queue object constructed from the input value. 23 | // Refer to <@link ObjectType QueueTag>. 24 | // If no input is given, returns the current queue. 25 | // --> 26 | TagManager.registerTagHandler(new TagRunnable.RootForm() { 27 | @Override 28 | public void run(ReplaceableTagEvent event) { 29 | queueTag(event); 30 | } 31 | }, "queue"); 32 | } 33 | 34 | public void queueTag(ReplaceableTagEvent event) { 35 | if (!event.matches("queue")) { 36 | return; 37 | } 38 | Attribute attribute = event.getAttributes(); 39 | // Historical queue.xxx tags: 40 | if (attribute.startsWith("exists", 2) && attribute.hasContext(2)) { 41 | Deprecations.queueExists.warn(attribute.context); 42 | event.setReplacedObject(CoreUtilities.autoAttrib(new ElementTag(ScriptQueue.queueExists(attribute.getContext(2))), attribute.fulfill(2))); 43 | return; 44 | } 45 | if (attribute.startsWith("stats", 2)) { 46 | Deprecations.queueStats.warn(attribute.context); 47 | event.setReplacedObject(CoreUtilities.autoAttrib(new ElementTag(ScriptQueue.getStats()), attribute.fulfill(2))); 48 | return; 49 | } 50 | if (attribute.startsWith("list", 2)) { 51 | Deprecations.queueStats.warn(attribute.context); 52 | event.setReplacedObject(CoreUtilities.autoAttrib(new ListTag(ScriptQueue.getQueues(), QueueTag::new), attribute.fulfill(2))); 53 | return; 54 | } 55 | // Modern tag: 56 | if (attribute.hasParam()) { 57 | QueueTag queue = attribute.paramAsType(QueueTag.class); 58 | if (queue == null) { 59 | return; 60 | } 61 | event.setReplacedObject(CoreUtilities.autoAttrib(queue, event.getAttributes().fulfill(1))); 62 | return; 63 | } 64 | ScriptQueue queue = event.getScriptEntry().getResidingQueue(); 65 | if (queue == null) { 66 | return; 67 | } 68 | event.setReplacedObject(CoreUtilities.autoAttrib(new QueueTag(event.getScriptEntry().getResidingQueue()), attribute.fulfill(1))); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/denizenscript/denizencore/tags/core/ScriptTagBase.java: -------------------------------------------------------------------------------- 1 | package com.denizenscript.denizencore.tags.core; 2 | 3 | import com.denizenscript.denizencore.objects.core.ScriptTag; 4 | import com.denizenscript.denizencore.tags.TagManager; 5 | 6 | public class ScriptTagBase { 7 | 8 | public ScriptTagBase() { 9 | 10 | // <--[tag] 11 | // @attribute )]> 12 | // @returns ScriptTag 13 | // @description 14 | // Returns a script object constructed from the input value. 15 | // If no input is given, will return the current script that the tag is within. 16 | // Refer to <@link ObjectType ScriptTag>. 17 | // --> 18 | TagManager.registerTagHandler(ScriptTag.class, "script", (attribute) -> { 19 | ScriptTag script = null; 20 | if (attribute.hasParam()) { 21 | script = attribute.paramAsType(ScriptTag.class); 22 | if (script == null) { 23 | attribute.echoError("Script '" + attribute.getParam() + "' does not exist."); 24 | return null; 25 | } 26 | } 27 | else if (attribute.context.script != null) { 28 | script = attribute.context.script; 29 | } 30 | else if (attribute.context.entry == null) { 31 | attribute.echoError("No applicable script for