From a60bc386cb53028d0e7766fbdfcf4f606490e270 Mon Sep 17 00:00:00 2001 From: altrisi Date: Tue, 17 May 2022 20:11:49 +0200 Subject: [PATCH] Refactor `Module` into a single record type and fix system globals (#1383) --- .../java/carpet/script/CarpetEventServer.java | 10 +- .../java/carpet/script/CarpetExpression.java | 1 - .../java/carpet/script/CarpetScriptHost.java | 68 +++++------ .../carpet/script/CarpetScriptServer.java | 84 ++++++------- src/main/java/carpet/script/Expression.java | 3 +- src/main/java/carpet/script/Module.java | 110 ++++++++++++++++++ src/main/java/carpet/script/ScriptHost.java | 21 ++-- src/main/java/carpet/script/ScriptServer.java | 11 ++ .../carpet/script/annotation/Locator.java | 2 +- .../java/carpet/script/api/Auxiliary.java | 8 +- src/main/java/carpet/script/api/Entities.java | 2 +- .../carpet/script/argument/FileArgument.java | 12 +- .../script/argument/FunctionArgument.java | 2 +- .../carpet/script/bundled/BundledModule.java | 63 +++++----- .../carpet/script/bundled/FileModule.java | 46 -------- .../java/carpet/script/bundled/Module.java | 35 ++---- .../carpet/script/language/ControlFlow.java | 2 +- src/main/java/carpet/script/language/Sys.java | 8 +- .../java/carpet/script/utils/SystemInfo.java | 2 +- .../carpet/script/value/FunctionValue.java | 4 +- 20 files changed, 279 insertions(+), 215 deletions(-) create mode 100644 src/main/java/carpet/script/Module.java create mode 100644 src/main/java/carpet/script/ScriptServer.java delete mode 100644 src/main/java/carpet/script/bundled/FileModule.java diff --git a/src/main/java/carpet/script/CarpetEventServer.java b/src/main/java/carpet/script/CarpetEventServer.java index f0b4e90f..14272715 100644 --- a/src/main/java/carpet/script/CarpetEventServer.java +++ b/src/main/java/carpet/script/CarpetEventServer.java @@ -1066,13 +1066,13 @@ public class CarpetEventServer public static void removeAllHostEvents(CarpetScriptHost host) { byName.values().forEach((e) -> e.handler.removeAllCalls(host)); - host.getScriptServer().events.customEvents.values().forEach((e) -> e.handler.removeAllCalls(host)); + host.scriptServer().events.customEvents.values().forEach((e) -> e.handler.removeAllCalls(host)); } public static void transferAllHostEventsToChild(CarpetScriptHost host) { byName.values().forEach((e) -> e.handler.createChildEvents(host)); - host.getScriptServer().events.customEvents.values().forEach((e) -> e.handler.createChildEvents(host)); + host.scriptServer().events.customEvents.values().forEach((e) -> e.handler.createChildEvents(host)); } public static void clearAllBuiltinEvents() @@ -1258,7 +1258,7 @@ public class CarpetEventServer public int signalEvent(String event, CarpetContext cc, ServerPlayer optionalTarget, List callArgs) { - Event ev = Event.getEvent(event, ((CarpetScriptHost)cc.host).getScriptServer()); + Event ev = Event.getEvent(event, ((CarpetScriptHost)cc.host).scriptServer()); if (ev == null) return -1; return ev.handler.signal(cc.s, optionalTarget, callArgs); } @@ -1285,7 +1285,7 @@ public class CarpetEventServer } public boolean removeBuiltInEvent(String event, CarpetScriptHost host) { - Event ev = Event.getEvent(event, host.getScriptServer()); + Event ev = Event.getEvent(event, host.scriptServer()); if (ev == null) return false; ev.handler.removeAllCalls(host); return true; @@ -1293,7 +1293,7 @@ public class CarpetEventServer public void removeBuiltInEvent(String event, CarpetScriptHost host, String funName) { - Event ev = Event.getEvent(event, host.getScriptServer()); + Event ev = Event.getEvent(event, host.scriptServer()); if (ev != null) ev.handler.removeEventCall(host.getName(), host.user, funName); } diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 05989076..6873ff6e 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -10,7 +10,6 @@ import carpet.script.api.Monitoring; import carpet.script.api.Scoreboards; import carpet.script.api.Threading; import carpet.script.api.WorldAccess; -import carpet.script.bundled.Module; import carpet.script.exception.CarpetExpressionException; import carpet.script.exception.ExpressionException; import carpet.script.value.BlockValue; diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java index a5fd09e6..bc878309 100644 --- a/src/main/java/carpet/script/CarpetScriptHost.java +++ b/src/main/java/carpet/script/CarpetScriptHost.java @@ -5,7 +5,6 @@ import carpet.CarpetSettings; import carpet.script.api.Auxiliary; import carpet.script.argument.FileArgument; import carpet.script.argument.FunctionArgument; -import carpet.script.bundled.Module; import carpet.script.command.CommandArgument; import carpet.script.command.CommandToken; import carpet.script.exception.CarpetExpressionException; @@ -71,7 +70,6 @@ import static net.minecraft.commands.Commands.literal; public class CarpetScriptHost extends ScriptHost { - private final CarpetScriptServer scriptServer; public CommandSourceStack responsibleSource; private Tag globalState; @@ -87,9 +85,8 @@ public class CarpetScriptHost extends ScriptHost private CarpetScriptHost(CarpetScriptServer server, Module code, boolean perUser, ScriptHost parent, Map config, Map argTypes, Predicate commandValidator, boolean isRuleApp) { - super(code, perUser, parent); + super(code, server, perUser, parent); this.saveTimeout = 0; - this.scriptServer = server; persistenceRequired = true; if (parent == null && code != null) // app, not a global host { @@ -115,13 +112,8 @@ public class CarpetScriptHost extends ScriptHost { try { - String code = module.getCode(); - if (code == null) - { - throw new LoadException("Code not found"); - } host.setChatErrorSnooper(source); - CarpetExpression ex = new CarpetExpression(host.main, code, source, new BlockPos(0, 0, 0)); + CarpetExpression ex = new CarpetExpression(host.main, module.code(), source, new BlockPos(0, 0, 0)); ex.getExpr().asATextSource(); host.storeSource = storeSource; ex.scriptRunCommand(host, new BlockPos(source.getPosition())); @@ -175,7 +167,7 @@ public class CarpetScriptHost extends ScriptHost FunctionArgument functionSpec ) throws CommandSyntaxException { - String hostName = main.getName(); + String hostName = main.name(); List commandArgs = path.stream().filter(t -> t.isArgument).map(t -> t.surface).collect(Collectors.toList()); if (commandArgs.size() != (functionSpec.function.getNumParams()-functionSpec.args.size()) ) throw CommandArgument.error("Number of parameters in function "+functionSpec.function.fullName()+" doesn't match parameters for a command"); @@ -197,7 +189,7 @@ public class CarpetScriptHost extends ScriptHost List,FunctionArgument>> entries, Predicate useValidator ) throws CommandSyntaxException { - String hostName = main.getName(); + String hostName = main.name(); Predicate configValidator = getCommandConfigPermissions(); LiteralArgumentBuilder command = literal(hostName). requires((player) -> CarpetServer.scriptServer.modules.containsKey(hostName) && useValidator.test(player) && configValidator.test(player)); @@ -257,7 +249,7 @@ public class CarpetScriptHost extends ScriptHost @Override protected ScriptHost duplicate() { - return new CarpetScriptHost(scriptServer, main, false, this, appConfig, appArgTypes, commandValidator, isRuleApp); + return new CarpetScriptHost(scriptServer(), main, false, this, appConfig, appArgTypes, commandValidator, isRuleApp); } @Override @@ -283,7 +275,7 @@ public class CarpetScriptHost extends ScriptHost // this is nasty, we have the host and function, yet we add it via names, but hey - works for now String event = funName.replaceFirst("__on_", ""); if (CarpetEventServer.Event.byName.containsKey(event)) - scriptServer.events.addBuiltInEvent(event, this, function, null); + scriptServer().events.addBuiltInEvent(event, this, function, null); } else if (funName.equals("__config")) { @@ -402,7 +394,7 @@ public class CarpetScriptHost extends ScriptHost LiteralArgumentBuilder command = readCommands(commandValidator); if (command != null) { - scriptServer.server.getCommands().getDispatcher().register(command); + scriptServer().server.getCommands().getDispatcher().register(command); return true; } else { @@ -457,7 +449,7 @@ public class CarpetScriptHost extends ScriptHost if (main == null) return false; if (getFunction("__command") == null) return false; - if (scriptServer.isInvalidCommandRoot(getName())) + if (scriptServer().isInvalidCommandRoot(getName())) { notifier.accept(Messenger.c("gi Tried to mask vanilla command.")); return null; @@ -475,10 +467,10 @@ public class CarpetScriptHost extends ScriptHost } String hostName = getName(); LiteralArgumentBuilder command = literal(hostName). - requires((player) -> scriptServer.modules.containsKey(hostName) && commandValidator.test(player) && configValidator.test(player)). + requires((player) -> scriptServer().modules.containsKey(hostName) && commandValidator.test(player) && configValidator.test(player)). executes( (c) -> { - CarpetScriptHost targetHost = scriptServer.modules.get(hostName).retrieveOwnForExecution(c.getSource()); + CarpetScriptHost targetHost = scriptServer().modules.get(hostName).retrieveOwnForExecution(c.getSource()); Value response = targetHost.handleCommandLegacy(c.getSource(),"__command", null, ""); if (!response.isNull()) Messenger.m(c.getSource(), "gi "+response.getString()); return (int)response.readInteger(); @@ -508,23 +500,23 @@ public class CarpetScriptHost extends ScriptHost { command = command. then(literal(function). - requires((player) -> scriptServer.modules.containsKey(hostName) && scriptServer.modules.get(hostName).getFunction(function) != null). + requires((player) -> scriptServer().modules.containsKey(hostName) && scriptServer().modules.get(hostName).getFunction(function) != null). executes((c) -> { - CarpetScriptHost targetHost = scriptServer.modules.get(hostName).retrieveOwnForExecution(c.getSource()); + CarpetScriptHost targetHost = scriptServer().modules.get(hostName).retrieveOwnForExecution(c.getSource()); Value response = targetHost.handleCommandLegacy(c.getSource(),function, null, ""); if (!response.isNull()) Messenger.m(c.getSource(), "gi " + response.getString()); return (int) response.readInteger(); }). then(argument("args...", StringArgumentType.greedyString()). executes( (c) -> { - CarpetScriptHost targetHost = scriptServer.modules.get(hostName).retrieveOwnForExecution(c.getSource()); + CarpetScriptHost targetHost = scriptServer().modules.get(hostName).retrieveOwnForExecution(c.getSource()); Value response = targetHost.handleCommandLegacy(c.getSource(),function, null, StringArgumentType.getString(c, "args...")); if (!response.isNull()) Messenger.m(c.getSource(), "gi "+response.getString()); return (int)response.readInteger(); }))); } } - scriptServer.server.getCommands().getDispatcher().register(command); + scriptServer().server.getCommands().getDispatcher().register(command); return true; } @@ -570,8 +562,8 @@ public class CarpetScriptHost extends ScriptHost @Override protected Module getModuleOrLibraryByName(String name) { - Module module = scriptServer.getModule(name, true); - if (module == null || module.getCode() == null) + Module module = scriptServer().getModule(name, true); + if (module == null) throw new InternalExpressionException("Unable to locate package: "+name); return module; } @@ -580,7 +572,7 @@ public class CarpetScriptHost extends ScriptHost protected void runModuleCode(Context c, Module module) { CarpetContext cc = (CarpetContext)c; - CarpetExpression ex = new CarpetExpression(module, module.getCode(), cc.s, cc.origin); + CarpetExpression ex = new CarpetExpression(module, module.code(), cc.s, cc.origin); ex.getExpr().asATextSource(); ex.scriptRunCommand(this, cc.origin); } @@ -594,7 +586,7 @@ public class CarpetScriptHost extends ScriptHost { // this is nasty, we have the host and function, yet we add it via names, but hey - works for now String event = funName.replaceFirst("__on_",""); - scriptServer.events.removeBuiltInEvent(event, this, funName); + scriptServer().events.removeBuiltInEvent(event, this, funName); } } @@ -663,7 +655,7 @@ public class CarpetScriptHost extends ScriptHost { try { - return scriptServer.events.handleEvents.getWhileDisabled(() -> call(source, function, args)); + return scriptServer().events.handleEvents.getWhileDisabled(() -> call(source, function, args)); } catch (CarpetExpressionException exc) { @@ -768,7 +760,7 @@ public class CarpetScriptHost extends ScriptHost // TODO: this is just for now - invoke would be able to invoke other hosts scripts assertAppIntegrity(function.getModule()); Context context = new CarpetContext(this, source, BlockPos.ZERO); - return scriptServer.events.handleEvents.getWhileDisabled(() -> function.getExpression().evalValue( + return scriptServer().events.handleEvents.getWhileDisabled(() -> function.getExpression().evalValue( () -> function.lazyEval(context, Context.VOID, function.getExpression(), function.getToken(), argv), context, Context.VOID @@ -842,9 +834,9 @@ public class CarpetScriptHost extends ScriptHost public Value callNow(FunctionValue fun, List arguments) { - ServerPlayer player = (user==null)?null:scriptServer.server.getPlayerList().getPlayerByName(user); - CommandSourceStack source = (player != null)?player.createCommandSourceStack():scriptServer.server.createCommandSourceStack(); - return scriptServer.events.handleEvents.getWhileDisabled(()->{ + ServerPlayer player = (user==null)?null:scriptServer().server.getPlayerList().getPlayerByName(user); + CommandSourceStack source = (player != null)?player.createCommandSourceStack():scriptServer().server.createCommandSourceStack(); + return scriptServer().events.handleEvents.getWhileDisabled(()->{ try { return callUDF(BlockPos.ZERO, source, fun, arguments); @@ -872,7 +864,7 @@ public class CarpetScriptHost extends ScriptHost { String markerName = Auxiliary.MARKER_STRING + "_" + ((getName() == null) ? "" : getName()); - for (ServerLevel world : scriptServer.server.getAllLevels()) + for (ServerLevel world : scriptServer().server.getAllLevels()) { for (Entity e : world.getEntities(EntityType.ARMOR_STAND, (as) -> as.getTags().contains(markerName))) { @@ -1101,9 +1093,19 @@ public class CarpetScriptHost extends ScriptHost handleErrorWithStack(message, new CarpetExpressionException(exc.getMessage(), exc.stack)); } + /** + * @deprecated Use {@link #scriptServer()} instead + */ + @Deprecated(forRemoval = true) public CarpetScriptServer getScriptServer() { - return scriptServer; + return scriptServer(); + } + + @Override + public CarpetScriptServer scriptServer() + { + return (CarpetScriptServer)super.scriptServer(); } @Override diff --git a/src/main/java/carpet/script/CarpetScriptServer.java b/src/main/java/carpet/script/CarpetScriptServer.java index 6dc71d43..11b0518f 100644 --- a/src/main/java/carpet/script/CarpetScriptServer.java +++ b/src/main/java/carpet/script/CarpetScriptServer.java @@ -8,10 +8,7 @@ import carpet.script.api.Entities; import carpet.script.api.Inventories; import carpet.script.api.Scoreboards; import carpet.script.api.WorldAccess; -import carpet.script.bundled.BundledModule; import carpet.CarpetServer; -import carpet.script.bundled.FileModule; -import carpet.script.bundled.Module; import carpet.script.exception.ExpressionException; import carpet.script.exception.LoadException; import carpet.script.language.Arithmetic; @@ -54,7 +51,7 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; -public class CarpetScriptServer +public class CarpetScriptServer extends ScriptServer { //make static for now, but will change that later: public static final Logger LOG = LoggerFactory.getLogger("Scarpet"); @@ -72,41 +69,54 @@ public class CarpetScriptServer private static final List ruleModuleData = new ArrayList<>(); /** - * Registers a Scarpet App to be always available to be loaded - * in the /script load list. - * @see BundledModule#fromPath(String, String, boolean) - * - * @param app The {@link BundledModule} of the app + * @deprecated Use {@link #registerBuiltInApp(Module)} instead */ - public static void registerBuiltInScript(BundledModule app) + @Deprecated(forRemoval = true) + public static void registerBuiltInScript(carpet.script.bundled.BundledModule app) { - bundledModuleData.add(app); + registerBuiltInApp(app.toModule()); } /** - * Registers a Scarpet App to be used as a Rule App - * (to be controlled with the value of a Carpet rule). - * Libraries should be registered with {@link #registerBuiltInScript(BundledModule)} instead - * @see BundledModule#fromPath(String, String, boolean) - * - * @param app The {@link BundledModule} of the app. + * @deprecated Use {@link #registerSettingsApp(Module)} instead */ - public static void registerSettingsApp(BundledModule app) { + @Deprecated(forRemoval = true) + public static void registerSettingsApp(carpet.script.bundled.BundledModule app) { + registerSettingsApp(app.toModule()); + } + /** + * Registers a Scarpet App to be always available under the {@code /script load} list. + * @see Module#fromJarPath(String, String, boolean) + * + * @param app The {@link Module} of the app + */ + public static void registerBuiltInApp(Module app) { + bundledModuleData.add(app); + } + + /** + * Registers a Scarpet App to be used as a Rule App (to be controlled with the value of a Carpet rule). + * Libraries should be registered with {@link #registerBuiltInScript(BundledModule)} instead + * @see Module#fromJarPath(String, String, boolean) + * + * @param app The {@link Module} of the app. + */ + public static void registerSettingsApp(Module app) { ruleModuleData.add(app); } static { - registerBuiltInScript(BundledModule.carpetNative("camera", false)); - registerBuiltInScript(BundledModule.carpetNative("overlay", false)); - registerBuiltInScript(BundledModule.carpetNative("event_test", false)); - registerBuiltInScript(BundledModule.carpetNative("stats_test", false)); - registerBuiltInScript(BundledModule.carpetNative("math", true)); - registerBuiltInScript(BundledModule.carpetNative("chunk_display", false)); - registerBuiltInScript(BundledModule.carpetNative("ai_tracker", false)); - registerBuiltInScript(BundledModule.carpetNative("draw_beta", false)); - registerBuiltInScript(BundledModule.carpetNative("shapes", true)); - registerBuiltInScript(BundledModule.carpetNative("distance_beta", false)); + registerBuiltInApp(Module.carpetNative("camera", false)); + registerBuiltInApp(Module.carpetNative("overlay", false)); + registerBuiltInApp(Module.carpetNative("event_test", false)); + registerBuiltInApp(Module.carpetNative("stats_test", false)); + registerBuiltInApp(Module.carpetNative("math", true)); + registerBuiltInApp(Module.carpetNative("chunk_display", false)); + registerBuiltInApp(Module.carpetNative("ai_tracker", false)); + registerBuiltInApp(Module.carpetNative("draw_beta", false)); + registerBuiltInApp(Module.carpetNative("shapes", true)); + registerBuiltInApp(Module.carpetNative("distance_beta", false)); } public CarpetScriptServer(MinecraftServer server) @@ -117,7 +127,6 @@ public class CarpetScriptServer private void init() { - ScriptHost.systemGlobals.clear(); events = new CarpetEventServer(this); modules = new HashMap<>(); unloadableModules = new HashSet<>(); @@ -158,7 +167,7 @@ public class CarpetScriptServer (allowLibraries && script.getFileName().toString().equalsIgnoreCase(name+".scl")) ).findFirst(); if (scriptPath.isPresent()) - return new FileModule(scriptPath.get()); + return Module.fromPath(scriptPath.get()); if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { @@ -170,14 +179,14 @@ public class CarpetScriptServer (allowLibraries && script.getFileName().toString().equalsIgnoreCase(name + ".scl"))) .findFirst(); if (scriptPath.isPresent()) - return new FileModule(scriptPath.get()); + return Module.fromPath(scriptPath.get()); } } catch (IOException e) { CarpetSettings.LOG.error("Exception while loading the app: ", e); } for (Module moduleData : bundledModuleData) { - if (moduleData.getName().equalsIgnoreCase(name) && (allowLibraries || !moduleData.isLibrary())) + if (moduleData.name().equalsIgnoreCase(name) && (allowLibraries || !moduleData.library())) { return moduleData; } @@ -189,7 +198,7 @@ public class CarpetScriptServer { for (Module moduleData : ruleModuleData) { - if (moduleData.getName().equalsIgnoreCase(name)) + if (moduleData.name().equalsIgnoreCase(name)) { return moduleData; } @@ -204,7 +213,7 @@ public class CarpetScriptServer { for (Module mi : bundledModuleData) { - if (!mi.isLibrary() && !mi.getName().endsWith("_beta")) moduleNames.add(mi.getName()); + if (!mi.library() && !mi.name().endsWith("_beta")) moduleNames.add(mi.name()); } } try { @@ -254,7 +263,7 @@ public class CarpetScriptServer Module module = isRuleApp ? getRuleModule(name) : getModule(name, false); if (module == null) { - Messenger.m(source, "r Failed to add "+name+" app"); + Messenger.m(source, "r Failed to add "+name+" app: App not found"); return false; } CarpetScriptHost newHost; @@ -273,11 +282,6 @@ public class CarpetScriptServer // Messenger.m(source, "r Failed to add "+name+" app: invalid app config (via '__config()' function)"); // return false; //} - if (module.getCode() == null) - { - Messenger.m(source, "r Unable to load "+name+" app - not found"); - return false; - } modules.put(name, newHost); if (!isRuleApp) unloadableModules.add(name); diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 7ba73179..17af5b65 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -12,7 +12,6 @@ import carpet.script.Fluff.QuadFunction; import carpet.script.Fluff.QuinnFunction; import carpet.script.Fluff.SexFunction; import carpet.script.Fluff.TriFunction; -import carpet.script.bundled.Module; import carpet.script.exception.BreakStatement; import carpet.script.exception.ContinueStatement; import carpet.script.exception.ExitStatement; @@ -64,7 +63,7 @@ public class Expression public String getModuleName() { - return module == null?"system chat":module.getName(); + return module == null ? "system chat" : module.name(); } public void asATextSource() diff --git a/src/main/java/carpet/script/Module.java b/src/main/java/carpet/script/Module.java new file mode 100644 index 00000000..495b305d --- /dev/null +++ b/src/main/java/carpet/script/Module.java @@ -0,0 +1,110 @@ +package carpet.script; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Locale; +import java.util.Objects; + +import org.apache.commons.io.IOUtils; + +import carpet.CarpetServer; +import carpet.script.argument.FileArgument; +import net.minecraft.nbt.Tag; +import net.minecraft.world.level.storage.LevelResource; + +public record Module(String name, String code, boolean library) { + public Module + { + Objects.requireNonNull(name); + Objects.requireNonNull(code); + } + + public static Module fromPath(Path path) + { + boolean library = path.getFileName().toString().endsWith(".scl"); + try + { + String name = path.getFileName().toString().replaceFirst("\\.scl?","").toLowerCase(Locale.ROOT); + String code = new String(Files.readAllBytes(path), StandardCharsets.UTF_8); + return new Module(name, code, library); + } + catch (IOException e) + { + throw new IllegalArgumentException("Failed to load scarpet module", e); + } + } + + /** + * Creates a new {@link Module} with an app located in Carpet's JAR. + * @param scriptName A {@link String} being the name of the script. The extension will be autocompleted + * @param isLibrary A {@link boolean} indicating whether or not the script is a library + * @return The created {@link BundledModule} + */ + public static Module carpetNative(String scriptName, boolean isLibrary) + { + return fromJarPath("assets/carpet/scripts/", scriptName, isLibrary); + } + + /** + * Creates a new {@link Module} with an app located at a specified path inside some mod's JAR. + * @see #fromJarPathWithCustomName(String, String, boolean) + * + * @param path A {@link String} being the path to the directory where the app is located. + * @param scriptName A {@link String} being the name of the script. The extension will be autocompleted + * @param isLibrary A {@link boolean} indicating whether or not the script is a library + * @return The created {@link BundledModule} + */ + public static Module fromJarPath(String path, String scriptName, boolean isLibrary) { + return fromJarPathWithCustomName(path + scriptName + (isLibrary ? ".scl":".sc"), scriptName, isLibrary); + } + + /** + * Creates a new {@link Module} with an app located at the specified fullPath (inside a mod jar)with a custom name. + * @see #fromJarPath(String, String, boolean) + * + * @param fullPath A {@link String} being the full path to the app's code, including file and extension. + * @param customName A {@link String} being the custom name for the script. + * @param isLibrary A {@link boolean} indicating whether or not the script is a library + * @return The created {@link Module} + */ + public static Module fromJarPathWithCustomName(String fullPath, String customName, boolean isLibrary) { + try + { + String name = customName.toLowerCase(Locale.ROOT); + String code = IOUtils.toString( + Module.class.getClassLoader().getResourceAsStream(fullPath), + StandardCharsets.UTF_8 + ); + return new Module(name, code, isLibrary); + } + catch (IOException e) + { + throw new IllegalArgumentException("Failed to load bundled module", e); + } + } + + public static Tag getData(Module module) + { + Path dataFile = resolveResource(module); + if (dataFile == null) return null; + if (!Files.exists(dataFile) || !(dataFile.toFile().isFile())) return null; + synchronized (FileArgument.writeIOSync) { return FileArgument.readTag(dataFile); } + } + + public static void saveData(Module module, Tag globalState) + { + Path dataFile = resolveResource(module); + if (dataFile == null) return; + if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return; + synchronized (FileArgument.writeIOSync) { FileArgument.writeTagDisk(globalState, dataFile, false); } + } + + private static Path resolveResource(Module module) + { + if (module == null) return null; // commandline app + return CarpetServer.minecraft_server.getWorldPath(LevelResource.ROOT).resolve("scripts/"+module.name()+".data.nbt"); + } + +} diff --git a/src/main/java/carpet/script/ScriptHost.java b/src/main/java/carpet/script/ScriptHost.java index 976172a7..a8eb3e85 100644 --- a/src/main/java/carpet/script/ScriptHost.java +++ b/src/main/java/carpet/script/ScriptHost.java @@ -1,6 +1,5 @@ package carpet.script; -import carpet.script.bundled.Module; import carpet.script.exception.ExpressionException; import carpet.script.exception.IntegrityException; import carpet.script.exception.InternalExpressionException; @@ -28,12 +27,12 @@ import java.util.stream.Stream; public abstract class ScriptHost { - public static Map systemGlobals = new ConcurrentHashMap<>(); private static final Map randomizers = new Long2ObjectOpenHashMap<>(); public static Thread mainThread = null; private final Map executorServices = new HashMap<>(); private final Map locks = new ConcurrentHashMap<>(); + private final ScriptServer scriptServer; protected boolean inTermination = false; public boolean strict; @@ -101,7 +100,7 @@ public abstract class ScriptHost protected boolean perUser; public String user; - public String getName() {return main ==null?null: main.getName();} + public String getName() {return main ==null?null: main.name();} public final Module main; @@ -112,17 +111,18 @@ public abstract class ScriptHost } public ErrorSnooper errorSnooper = null; - protected ScriptHost(Module code, boolean perUser, ScriptHost parent) + protected ScriptHost(Module code, ScriptServer scriptServer, boolean perUser, ScriptHost parent) { this.parent = parent; this.main = code; this.perUser = perUser; this.user = null; this.strict = false; + this.scriptServer = scriptServer; ModuleData moduleData = new ModuleData(code); initializeModuleGlobals(moduleData); this.moduleData.put(code, moduleData); - this.modules.put(code==null?null:code.getName(), code); + this.modules.put(code==null?null:code.name(), code); mainThread = Thread.currentThread(); } @@ -134,8 +134,8 @@ public abstract class ScriptHost { if (modules.containsKey(moduleName.toLowerCase(Locale.ROOT))) return; // aready imported Module module = getModuleOrLibraryByName(moduleName); - if (modules.containsKey(module.getName())) return; // aready imported, once again, in case some discrepancies in names? - modules.put(module.getName(), module); + if (modules.containsKey(module.name())) return; // aready imported, once again, in case some discrepancies in names? + modules.put(module.name(), module); ModuleData data = new ModuleData(module); initializeModuleGlobals(data); moduleData.put(module, data); @@ -201,7 +201,7 @@ public abstract class ScriptHost if (module == main) throw new InternalExpressionException("Function '"+name+"' is not defined yet"); else - throw new InternalExpressionException("Function '"+name+"' is not defined nor visible by its name in the imported module '"+module.getName()+"'"); + throw new InternalExpressionException("Function '"+name+"' is not defined nor visible by its name in the imported module '"+module.name()+"'"); } return ret; } @@ -448,4 +448,9 @@ public abstract class ScriptHost DEPRECATION_LOG.warn("'"+feature+"' is deprecated and soon will be removed. Please consult the docs for their replacement"); return true; } + + public ScriptServer scriptServer() + { + return scriptServer; + } } diff --git a/src/main/java/carpet/script/ScriptServer.java b/src/main/java/carpet/script/ScriptServer.java new file mode 100644 index 00000000..24e36383 --- /dev/null +++ b/src/main/java/carpet/script/ScriptServer.java @@ -0,0 +1,11 @@ +package carpet.script; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import carpet.script.value.Value; + +// WIP +public class ScriptServer { + public final Map systemGlobals = new ConcurrentHashMap<>(); +} diff --git a/src/main/java/carpet/script/annotation/Locator.java b/src/main/java/carpet/script/annotation/Locator.java index 50eea6d3..3f195607 100644 --- a/src/main/java/carpet/script/annotation/Locator.java +++ b/src/main/java/carpet/script/annotation/Locator.java @@ -15,7 +15,7 @@ import carpet.script.argument.Argument; import carpet.script.argument.BlockArgument; import carpet.script.argument.FunctionArgument; import carpet.script.argument.Vector3Argument; -import carpet.script.bundled.Module; +import carpet.script.Module; import carpet.script.value.BlockValue; import carpet.script.value.FunctionValue; import carpet.script.value.Value; diff --git a/src/main/java/carpet/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java index ac9fe553..aef8e55a 100644 --- a/src/main/java/carpet/script/api/Auxiliary.java +++ b/src/main/java/carpet/script/api/Auxiliary.java @@ -973,9 +973,9 @@ public class Auxiliary { FunctionArgument callback = FunctionArgument.findIn(c, expression.module, lv, 1, true, false); CarpetScriptHost host = ((CarpetScriptHost)c.host); if (callback.function == null) - return BooleanValue.of(host.getScriptServer().events.removeBuiltInEvent(event, host)); + return BooleanValue.of(host.scriptServer().events.removeBuiltInEvent(event, host)); // args don't need to be checked will be checked at the event - return BooleanValue.of( host.getScriptServer().events.handleCustomEvent(event, host, callback.function, callback.args )); + return BooleanValue.of( host.scriptServer().events.handleCustomEvent(event, host, callback.function, callback.args )); }); //signal_event('event', player or null, args.... ) -> number of apps notified expression.addContextFunction("signal_event", -1, (c, t, lv) -> @@ -983,7 +983,7 @@ public class Auxiliary { if (lv.size() == 0) throw new InternalExpressionException("'signal' requires at least one argument"); CarpetContext cc = (CarpetContext)c; - CarpetScriptServer server = ((CarpetScriptHost)c.host).getScriptServer(); + CarpetScriptServer server = ((CarpetScriptHost)c.host).scriptServer(); String eventName = lv.get(0).getString(); // no such event yet if (CarpetEventServer.Event.getEvent(eventName, server) == null) return Value.NULL; @@ -994,7 +994,7 @@ public class Auxiliary { player = EntityValue.getPlayerByValue(server.server, lv.get(1)); if (lv.size() > 2) args = lv.subList(2, lv.size()); } - int counts = ((CarpetScriptHost)c.host).getScriptServer().events.signalEvent(eventName, cc, player, args); + int counts = ((CarpetScriptHost)c.host).scriptServer().events.signalEvent(eventName, cc, player, args); if (counts < 0) return Value.NULL; return new NumericValue(counts); }); diff --git a/src/main/java/carpet/script/api/Entities.java b/src/main/java/carpet/script/api/Entities.java index 7131c99f..b76c5622 100644 --- a/src/main/java/carpet/script/api/Entities.java +++ b/src/main/java/carpet/script/api/Entities.java @@ -257,7 +257,7 @@ public class Entities { Set> types = new HashSet<>(); descriptors.forEach(s -> types.addAll(EntityValue.getEntityDescriptor(s, ((CarpetContext) c).s.getServer()).typeList)); FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 1, true, false); - CarpetEventServer events = ((CarpetScriptHost)c.host).getScriptServer().events; + CarpetEventServer events = ((CarpetScriptHost)c.host).scriptServer().events; if (funArg.function == null) { types.forEach(et -> events.removeBuiltInEvent(CarpetEventServer.Event.getEntityLoadEventName(et), (CarpetScriptHost) c.host)); diff --git a/src/main/java/carpet/script/argument/FileArgument.java b/src/main/java/carpet/script/argument/FileArgument.java index c273dd22..de7c0003 100644 --- a/src/main/java/carpet/script/argument/FileArgument.java +++ b/src/main/java/carpet/script/argument/FileArgument.java @@ -2,7 +2,7 @@ package carpet.script.argument; import carpet.CarpetServer; import carpet.script.CarpetScriptServer; -import carpet.script.bundled.Module; +import carpet.script.Module; import carpet.script.exception.InternalExpressionException; import carpet.script.exception.ThrowStatement; import carpet.script.exception.Throwables; @@ -177,7 +177,7 @@ public class FileArgument private Path toPath(Module module) { - if (!isShared && (module == null || module.getName() == null)) return null; + if (!isShared && module == null) return null; if (zipContainer == null) return resolve(getDescriptor(module, resource)+(isFolder?"":type.extension)); else @@ -204,8 +204,8 @@ public class FileArgument private Path moduleRootPath(Module module) { - if (!isShared && (module == null || module.getName() == null)) return null; - return resolve(isShared?"shared":module.getName()+".data"); + if (!isShared && module == null) return null; + return resolve(isShared?"shared":module.name()+".data"); } public String getDisplayPath() @@ -219,9 +219,9 @@ public class FileArgument { return res.isEmpty()?"shared":"shared/"+res; } - if (module != null && module.getName() != null) // appdata + if (module != null) // appdata { - return module.getName()+".data"+(res==null || res.isEmpty()?"":"/"+res); + return module.name()+".data"+(res==null || res.isEmpty()?"":"/"+res); } throw new InternalExpressionException("Invalid file descriptor: "+res); } diff --git a/src/main/java/carpet/script/argument/FunctionArgument.java b/src/main/java/carpet/script/argument/FunctionArgument.java index bbcb3422..387cc66e 100644 --- a/src/main/java/carpet/script/argument/FunctionArgument.java +++ b/src/main/java/carpet/script/argument/FunctionArgument.java @@ -2,7 +2,7 @@ package carpet.script.argument; import carpet.script.Context; import carpet.script.ScriptHost; -import carpet.script.bundled.Module; +import carpet.script.Module; import carpet.script.command.CommandArgument; import carpet.script.exception.InternalExpressionException; import carpet.script.value.FunctionValue; diff --git a/src/main/java/carpet/script/bundled/BundledModule.java b/src/main/java/carpet/script/bundled/BundledModule.java index 8a0d1744..e53500ec 100644 --- a/src/main/java/carpet/script/bundled/BundledModule.java +++ b/src/main/java/carpet/script/bundled/BundledModule.java @@ -1,32 +1,25 @@ package carpet.script.bundled; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Locale; - +/** + * @deprecated Use the static methods from {@link carpet.script.Module} instead. + * To be removed in first 1.20 snapshots + */ +@Deprecated(forRemoval = true) public class BundledModule extends Module { private String name; private String code; private boolean library; + /** + * @deprecated Use {@link carpet.script.Module} instead + */ + @Deprecated(forRemoval = true) public BundledModule(String name, String code, boolean isLibrary) { library = isLibrary; this.name = name; this.code = code; } - /** - * Creates a new {@link BundledModule} with an app located in Carpet's script storage. - * @param scriptName A {@link String} being the name of the script. The extension will be autocompleted - * @param isLibrary A {@link boolean} indicating whether or not the script is a library - * @return The created {@link BundledModule} - */ - public static BundledModule carpetNative(String scriptName, boolean isLibrary) - { - return fromPath("assets/carpet/scripts/", scriptName, isLibrary); - } /** * Creates a new {@link BundledModule} with an app located at a specified place. @@ -36,9 +29,11 @@ public class BundledModule extends Module * @param scriptName A {@link String} being the name of the script. The extension will be autocompleted * @param isLibrary A {@link boolean} indicating whether or not the script is a library * @return The created {@link BundledModule} + * @deprecated Use {@link carpet.script.Module#fromJarPath(String, String, boolean)} */ + @Deprecated(forRemoval = true) public static BundledModule fromPath(String path, String scriptName, boolean isLibrary) { - return fromPathWithCustomName(path+scriptName+(isLibrary?".scl":".sc"), scriptName, isLibrary); + return fromPathWithCustomName(path+scriptName+(isLibrary?".scl":".sc"), scriptName, isLibrary); } /** @@ -49,23 +44,11 @@ public class BundledModule extends Module * @param customName A {@link String} being the custom name for the script. * @param isLibrary A {@link boolean} indicating whether or not the script is a library * @return The created {@link BundledModule} + * @deprecated Use {@link carpet.script.Module#fromJarPathWithCustomName(String, String, boolean)} */ + @Deprecated(forRemoval = true) public static BundledModule fromPathWithCustomName(String fullPath, String customName, boolean isLibrary) { - BundledModule module = new BundledModule(null, null, isLibrary); - try - { - module.name = customName.toLowerCase(Locale.ROOT); - module.code = IOUtils.toString( - BundledModule.class.getClassLoader().getResourceAsStream(fullPath), - StandardCharsets.UTF_8 - ); - } - catch ( NullPointerException | IOException e) - { - module.name = null; - module.code = null; - } - return module; + return new DelegatingBundledModule(carpet.script.Module.fromJarPathWithCustomName(fullPath, customName, isLibrary)); } @Override @@ -76,4 +59,20 @@ public class BundledModule extends Module @Override public String getCode() { return code; } + + // BundledModule implementation that delegates to a modern Module, returned by the factory methods here + // Saves compute time and memory if extensions were storing their BundledModule and passing it to methods that + // convert it multiple times + private static class DelegatingBundledModule extends BundledModule { + private final carpet.script.Module module; + public DelegatingBundledModule(carpet.script.Module module) { + super(module.name(), module.code(), module.library()); + this.module = module; + } + + @Override + public carpet.script.Module toModule() { + return module; + } + } } \ No newline at end of file diff --git a/src/main/java/carpet/script/bundled/FileModule.java b/src/main/java/carpet/script/bundled/FileModule.java deleted file mode 100644 index 23d558f5..00000000 --- a/src/main/java/carpet/script/bundled/FileModule.java +++ /dev/null @@ -1,46 +0,0 @@ -package carpet.script.bundled; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Locale; - -public class FileModule extends Module -{ - private String name; - private String code; - private boolean library; - public FileModule(Path sourcePath) - { - library = sourcePath.getFileName().toString().endsWith(".scl"); - try - { - name = sourcePath.getFileName().toString().replaceFirst("\\.scl?","").toLowerCase(Locale.ROOT); - code = new String(Files.readAllBytes(sourcePath), StandardCharsets.UTF_8); - } - catch ( IOException e) - { - name = null; - code = null; - } - } - @Override - public String getName() - { - return name; - } - - @Override - public String getCode() - { - return code; - } - - @Override - public boolean isLibrary() - { - return library; - } - -} diff --git a/src/main/java/carpet/script/bundled/Module.java b/src/main/java/carpet/script/bundled/Module.java index cec0fc79..0d818a0c 100644 --- a/src/main/java/carpet/script/bundled/Module.java +++ b/src/main/java/carpet/script/bundled/Module.java @@ -1,38 +1,19 @@ package carpet.script.bundled; -import carpet.CarpetServer; -import carpet.script.argument.FileArgument; -import java.nio.file.Files; -import java.nio.file.Path; -import net.minecraft.nbt.Tag; -import net.minecraft.world.level.storage.LevelResource; - +/** + * @deprecated Use {@link carpet.script.Module} instead. + * To be removed in first 1.20 snapshots + */ +@Deprecated(forRemoval = true) public abstract class Module { public abstract String getName(); public abstract String getCode(); public abstract boolean isLibrary(); - - public static Tag getData(Module module) + + public carpet.script.Module toModule() { - Path dataFile = resolveResource(module); - if (dataFile == null) return null; - if (!Files.exists(dataFile) || !(dataFile.toFile().isFile())) return null; - synchronized (FileArgument.writeIOSync) { return FileArgument.readTag(dataFile); } - } - - public static void saveData(Module module, Tag globalState) - { - Path dataFile = resolveResource(module); - if (dataFile == null) return; - if (!Files.exists(dataFile.getParent()) && !dataFile.toFile().getParentFile().mkdirs()) return; - synchronized (FileArgument.writeIOSync) { FileArgument.writeTagDisk(globalState, dataFile, false); } - } - - private static Path resolveResource(Module module) - { - if (module == null || module.getName() == null) return null; // commandline app - return CarpetServer.minecraft_server.getWorldPath(LevelResource.ROOT).resolve("scripts/"+module.getName()+".data.nbt"); + return new carpet.script.Module(getName(), getCode(), isLibrary()); } @Override diff --git a/src/main/java/carpet/script/language/ControlFlow.java b/src/main/java/carpet/script/language/ControlFlow.java index f7f32a44..d118a514 100644 --- a/src/main/java/carpet/script/language/ControlFlow.java +++ b/src/main/java/carpet/script/language/ControlFlow.java @@ -108,7 +108,7 @@ public class ControlFlow { LazyValue _trace = c.getVariable("_trace"); c.setVariable("_trace", (__c, __t) -> MapValue.wrap(Map.of( StringValue.of("stack"), ListValue.wrap(ret.stack.stream().map(f -> ListValue.of( - StringValue.of(f.getModule().getName()), + StringValue.of(f.getModule().name()), StringValue.of(f.getString()), NumericValue.of(f.getToken().lineno+1), NumericValue.of(f.getToken().linepos+1) diff --git a/src/main/java/carpet/script/language/Sys.java b/src/main/java/carpet/script/language/Sys.java index 29311cb2..b9efebde 100644 --- a/src/main/java/carpet/script/language/Sys.java +++ b/src/main/java/carpet/script/language/Sys.java @@ -431,15 +431,15 @@ public class Sys { { if (lv.size() == 0) throw new InternalExpressionException("'system_variable_get' expects at least a key to be fetched"); Value key = lv.get(0).evalValue(c); - if (lv.size() > 1) ScriptHost.systemGlobals.computeIfAbsent(key, k -> lv.get(1).evalValue(c)); - Value res = ScriptHost.systemGlobals.get(key); + if (lv.size() > 1) c.host.scriptServer().systemGlobals.computeIfAbsent(key, k -> lv.get(1).evalValue(c)); + Value res = c.host.scriptServer().systemGlobals.get(key); if (res!=null) return (cc, tt) -> res; return LazyValue.NULL; }); - expression.addBinaryFunction("system_variable_set", (key, value) -> + expression.addContextFunction("system_variable_set", 2, (c, t, lv) -> { - Value res = ScriptHost.systemGlobals.put(key, value); + Value res = c.host.scriptServer().systemGlobals.put(lv.get(0), lv.get(1)); if (res!=null) return res; return Value.NULL; }); diff --git a/src/main/java/carpet/script/utils/SystemInfo.java b/src/main/java/carpet/script/utils/SystemInfo.java index f39f675d..09095d42 100644 --- a/src/main/java/carpet/script/utils/SystemInfo.java +++ b/src/main/java/carpet/script/utils/SystemInfo.java @@ -42,7 +42,7 @@ public class SystemInfo { String name = c.host.getName(); return name == null?Value.NULL:new StringValue(name); }); - put("app_list", c -> ListValue.wrap(((CarpetScriptHost)c.host).getScriptServer().modules.keySet().stream().filter(Objects::nonNull).map(StringValue::new).collect(Collectors.toList()))); + put("app_list", c -> ListValue.wrap(((CarpetScriptHost)c.host).scriptServer().modules.keySet().stream().filter(Objects::nonNull).map(StringValue::new).collect(Collectors.toList()))); put("app_scope", c -> StringValue.of((c.host).isPerUser()?"player":"global")); put("app_players", c -> ListValue.wrap(c.host.getUserList().stream().map(StringValue::new).collect(Collectors.toList()))); diff --git a/src/main/java/carpet/script/value/FunctionValue.java b/src/main/java/carpet/script/value/FunctionValue.java index 86161478..d7147137 100644 --- a/src/main/java/carpet/script/value/FunctionValue.java +++ b/src/main/java/carpet/script/value/FunctionValue.java @@ -5,8 +5,8 @@ import carpet.script.Context; import carpet.script.Expression; import carpet.script.Fluff; import carpet.script.LazyValue; +import carpet.script.Module; import carpet.script.Tokenizer; -import carpet.script.bundled.Module; import carpet.script.exception.BreakStatement; import carpet.script.exception.ContinueStatement; import carpet.script.exception.ExpressionException; @@ -75,7 +75,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction return (name.equals("_")?"":name) +"("+String.join(", ",stringArgs)+")"; } - public String fullName() {return (name.equals("_")?"":name)+(expression.module == null?"":"["+expression.module.getName()+"]");} + public String fullName() {return (name.equals("_")?"":name)+(expression.module == null?"":"["+expression.module.name()+"]");} @Override public boolean getBoolean()