From dbae5813f0c754e950df3ff28bd7f8207e73fcd6 Mon Sep 17 00:00:00 2001 From: gnembon Date: Fri, 21 May 2021 22:31:02 -0300 Subject: [PATCH 1/5] added framework for auto resource fetching for the apps --- .../java/carpet/commands/ScriptCommand.java | 9 +- .../java/carpet/script/CarpetScriptHost.java | 24 +++- .../carpet/script/CarpetScriptServer.java | 14 +-- .../carpet/script/utils/AppStoreManager.java | 117 +++++++++--------- .../java/carpet/settings/SettingsManager.java | 2 +- 5 files changed, 91 insertions(+), 75 deletions(-) diff --git a/src/main/java/carpet/commands/ScriptCommand.java b/src/main/java/carpet/commands/ScriptCommand.java index 288f487c..7b50286f 100644 --- a/src/main/java/carpet/commands/ScriptCommand.java +++ b/src/main/java/carpet/commands/ScriptCommand.java @@ -271,13 +271,13 @@ public class ScriptCommand suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.listAvailableModules(true),bb)). executes((cc) -> { - boolean success = CarpetServer.scriptServer.addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false); + boolean success = CarpetServer.scriptServer.addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, true, false, false, null); return success?1:0; }). then(literal("global"). executes((cc) -> { - boolean success = CarpetServer.scriptServer.addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false); + boolean success = CarpetServer.scriptServer.addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "app"), null, false, false, false, null); return success?1:0; } ) @@ -328,8 +328,9 @@ public class ScriptCommand )?1:0)))); LiteralArgumentBuilder d = literal("download").requires((player) -> SettingsManager.canUseCommand(player, CarpetSettings.commandScriptACE)). - then(literal("global").then(argument("path", StringArgumentType.greedyString()).suggests(ScriptCommand::suggestDownloadableApps).executes(cc-> AppStoreManager.downloadScript(cc, StringArgumentType.getString(cc,"path"), true)))). - then(literal("local").then(argument("path", StringArgumentType.greedyString()).suggests(ScriptCommand::suggestDownloadableApps).executes(cc-> AppStoreManager.downloadScript(cc, StringArgumentType.getString(cc,"path"), false)))); + then(argument("path", StringArgumentType.greedyString()). + suggests(ScriptCommand::suggestDownloadableApps). + executes(cc-> AppStoreManager.downloadScript(cc.getSource(), StringArgumentType.getString(cc,"path")))); dispatcher.register(literal("script"). requires((player) -> SettingsManager.canUseCommand(player, CarpetSettings.commandScript)). diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java index 98ec2ef2..7b653118 100644 --- a/src/main/java/carpet/script/CarpetScriptHost.java +++ b/src/main/java/carpet/script/CarpetScriptHost.java @@ -12,8 +12,10 @@ import carpet.script.exception.CarpetExpressionException; import carpet.script.exception.ExpressionException; import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InvalidCallbackException; +import carpet.script.utils.AppStoreManager; import carpet.script.value.EntityValue; import carpet.script.value.FunctionValue; +import carpet.script.value.ListValue; import carpet.script.value.MapValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; @@ -78,6 +80,7 @@ public class CarpetScriptHost extends ScriptHost Predicate commandValidator; boolean isRuleApp; + public AppStoreManager.StoreNode storeSource; private CarpetScriptHost(CarpetScriptServer server, Module code, boolean perUser, ScriptHost parent, Map config, Map argTypes, Predicate commandValidator, boolean isRuleApp) { @@ -98,9 +101,10 @@ public class CarpetScriptHost extends ScriptHost appArgTypes = argTypes; this.commandValidator = commandValidator; this.isRuleApp = isRuleApp; + storeSource = null; } - public static CarpetScriptHost create(CarpetScriptServer scriptServer, Module module, boolean perPlayer, ServerCommandSource source, Predicate commandValidator, boolean isRuleApp) + public static CarpetScriptHost create(CarpetScriptServer scriptServer, Module module, boolean perPlayer, ServerCommandSource source, Predicate commandValidator, boolean isRuleApp, AppStoreManager.StoreNode storeSource) { CarpetScriptHost host = new CarpetScriptHost(scriptServer, module, perPlayer, null, Collections.emptyMap(), new HashMap<>(), commandValidator, isRuleApp); // parse code and convert to expression @@ -117,6 +121,7 @@ public class CarpetScriptHost extends ScriptHost host.setChatErrorSnooper(source); CarpetExpression ex = new CarpetExpression(host.main, code, source, new BlockPos(0, 0, 0)); ex.getExpr().asATextSource(); + host.storeSource = storeSource; ex.scriptRunCommand(host, new BlockPos(source.getPosition())); } catch (CarpetExpressionException e) @@ -130,6 +135,10 @@ public class CarpetScriptHost extends ScriptHost host.handleErrorWithStack("Math doesn't compute", ae); return null; } + finally + { + host.storeSource = null; + } } return host; } @@ -302,8 +311,19 @@ public class CarpetScriptHost extends ScriptHost else { checkModVersionRequirements(loadRequirements); + }; + if (storeSource != null) + { + Value resources = config.get(new StringValue("resources")); + if (resources != null) + { + if (!(resources instanceof ListValue)) throw new InternalExpressionException("App resources not defined as a list"); + for (Value resource : ((ListValue) resources).getItems()) + { + AppStoreManager.addResource(this, storeSource, resource); + } + } } - appConfig = config; } catch (NullPointerException ignored) diff --git a/src/main/java/carpet/script/CarpetScriptServer.java b/src/main/java/carpet/script/CarpetScriptServer.java index 5f056e98..e22a3419 100644 --- a/src/main/java/carpet/script/CarpetScriptServer.java +++ b/src/main/java/carpet/script/CarpetScriptServer.java @@ -21,6 +21,7 @@ import carpet.script.language.Functions; import carpet.script.language.Loops; import carpet.script.language.Sys; import carpet.script.language.Threading; +import carpet.script.utils.AppStoreManager; import carpet.script.value.FunctionValue; import carpet.script.value.Value; import carpet.utils.CarpetProfiler; @@ -54,9 +55,6 @@ import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; -import static net.minecraft.server.command.CommandManager.argument; -import static net.minecraft.server.command.CommandManager.literal; - public class CarpetScriptServer { //make static for now, but will change that later: @@ -127,7 +125,7 @@ public class CarpetScriptServer tickStart = 0L; stopAll = false; holyMoly = server.getCommandManager().getDispatcher().getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toSet()); - globalHost = CarpetScriptHost.create(this, null, false, null, p -> true, false); + globalHost = CarpetScriptHost.create(this, null, false, null, p -> true, false, null); } public void initializeForWorld() @@ -142,7 +140,7 @@ public class CarpetScriptServer { for (String moduleName: listAvailableModules(false)) { - addScriptHost(server.getCommandSource(), moduleName, null, true, true, false); + addScriptHost(server.getCommandSource(), moduleName, null, true, true, false, null); } } CarpetEventServer.Event.START.onTick(); @@ -241,7 +239,7 @@ public class CarpetScriptServer } public boolean addScriptHost(ServerCommandSource source, String name, Predicate commandValidator, - boolean perPlayer, boolean autoload, boolean isRuleApp) + boolean perPlayer, boolean autoload, boolean isRuleApp, AppStoreManager.StoreNode installer) { CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet load", CarpetProfiler.TYPE.GENERAL); if (commandValidator == null) commandValidator = p -> true; @@ -260,7 +258,7 @@ public class CarpetScriptServer Messenger.m(source, "r Failed to add "+name+" app"); return false; } - CarpetScriptHost newHost = CarpetScriptHost.create(this, module, perPlayer, source, commandValidator, isRuleApp); + CarpetScriptHost newHost = CarpetScriptHost.create(this, module, perPlayer, source, commandValidator, isRuleApp, installer); if (newHost == null) { Messenger.m(source, "r Failed to add "+name+" app"); @@ -488,7 +486,7 @@ public class CarpetScriptServer apps.keySet().forEach(s -> removeScriptHost(server.getCommandSource(), s, false, false)); CarpetEventServer.Event.clearAllBuiltinEvents(); init(); - apps.forEach((s, data) -> addScriptHost(server.getCommandSource(), s,data.commandValidator, data.perUser,false, data.isRuleApp)); + apps.forEach((s, data) -> addScriptHost(server.getCommandSource(), s,data.commandValidator, data.perUser,false, data.isRuleApp, null)); } public void reAddCommands() diff --git a/src/main/java/carpet/script/utils/AppStoreManager.java b/src/main/java/carpet/script/utils/AppStoreManager.java index dc14e996..9e69b22f 100644 --- a/src/main/java/carpet/script/utils/AppStoreManager.java +++ b/src/main/java/carpet/script/utils/AppStoreManager.java @@ -1,5 +1,8 @@ package carpet.script.utils; +import carpet.CarpetServer; +import carpet.script.CarpetScriptHost; +import carpet.script.value.Value; import carpet.settings.ParsedRule; import carpet.settings.Validator; import carpet.utils.Messenger; @@ -7,12 +10,11 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; -import com.mojang.brigadier.context.CommandContext; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.command.CommandException; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.util.WorldSavePath; -import org.apache.commons.lang3.tuple.Pair; +import org.apache.commons.lang3.tuple.Triple; import java.io.BufferedReader; import java.io.FileWriter; @@ -44,12 +46,18 @@ public class AppStoreManager /** A local copy of the scarpet repo's file structure, to avoid multiple queries to github.com while typing out the * {@code /script download} command and getting the suggestions. */ - public static final PathNode appStoreRoot = PathNode.folder(null, ""); + public static final StoreNode appStoreRoot = StoreNode.folder(null, ""); /** This is the base link to the scarpet app repo from the github api. */ private static String scarpetRepoLink = "https://api.github.com/repos/gnembon/scarpet/contents/programs/"; + public static void addResource(CarpetScriptHost carpetScriptHost, StoreNode storeSource, Value resource) + { + // todo + // locate online file, download to specified location + } + public static class ScarpetAppStoreValidator extends Validator { @Override public String validate(ServerCommandSource source, ParsedRule currentRule, String newValue, String string) @@ -69,25 +77,25 @@ public class AppStoreManager public String description() { return "Appstore link should point to a valid github repository";} } - public static class PathNode + public static class StoreNode { public String name; - public PathNode parent; - public Map children; + public StoreNode parent; + public Map children; public boolean sealed; public String value; - public static PathNode folder(PathNode parent, String name) + public static StoreNode folder(StoreNode parent, String name) { - PathNode node = new PathNode(parent, name); + StoreNode node = new StoreNode(parent, name); node.children = new HashMap<>(); node.value = null; node.sealed = false; return node; } - public static PathNode scriptFile(PathNode parent, String name, String value) + public static StoreNode scriptFile(StoreNode parent, String name, String value) { - PathNode node = new PathNode(parent, name); + StoreNode node = new StoreNode(parent, name); node.children = null; node.value = value; node.sealed = true; @@ -110,7 +118,7 @@ public class AppStoreManager { return this == appStoreRoot ? new StringBuilder() : parent.createPrePath().append(pathElement()); } - private PathNode(PathNode parent, String name) + private StoreNode(StoreNode parent, String name) { this.parent = parent; this.name = name; @@ -175,7 +183,7 @@ public class AppStoreManager return children.values().stream().map(s -> prefix+s.pathElement().replaceAll("/$", "")).collect(Collectors.toList()); } - public PathNode drillDown(String pathElement) throws IOException + public StoreNode drillDown(String pathElement) throws IOException { if (isLeaf()) throw new IOException(pathElement+" is not a folder"); fillChildren(); @@ -185,7 +193,7 @@ public class AppStoreManager public String getValue(String file) throws IOException { - PathNode leaf = drillDown(file); + StoreNode leaf = drillDown(file); if (!leaf.isLeaf()) throw new IOException(file+" is not a file"); return leaf.value; } @@ -201,7 +209,7 @@ public class AppStoreManager public static List suggestionsFromPath(String currentPath) throws IOException { String[] path = currentPath.split("/"); - PathNode appKiosk = appStoreRoot; + StoreNode appKiosk = appStoreRoot; for(String pathElement : path) { if (appKiosk.cannotContinueFor(pathElement)) return appKiosk.createPathSuggestions(); @@ -216,14 +224,15 @@ public class AppStoreManager * methods to avoid repeating code and so it makes more sense what it's exactly doing. * * @param path The user-inputted path to the script - * @param global Whether or not we wanna save it to the local scripts folder or in the global config folder * @return {@code 1} if we succesfully saved the script, {@code 0} otherwise */ - public static int downloadScript(CommandContext cc, String path, boolean global) + public static int downloadScript(ServerCommandSource source, String path) { - Pair code = getScriptCode(path); - return saveScriptToFile(path, code.getLeft(), code.getRight(), cc, global); + Triple code = getScriptCode(path); + if (!saveScriptToFile(source, path, code.getLeft(), code.getMiddle(), false)) return 0; + boolean success = CarpetServer.scriptServer.addScriptHost(source, code.getLeft(), null, true, false, false, code.getRight()); + return success?1:0; } /** Gets the code once the user inputs the command. @@ -231,10 +240,10 @@ public class AppStoreManager * @param appPath The user inputted path to the scarpet script * @return Pair of app file name and content */ - public static Pair getScriptCode(String appPath) + public static Triple getScriptCode(String appPath) { String[] path = appPath.split("/"); - PathNode appKiosk = appStoreRoot; + StoreNode appKiosk = appStoreRoot; try { for(String pathElement : Arrays.copyOfRange(path, 0, path.length-1)) @@ -242,7 +251,7 @@ public class AppStoreManager String appName = path[path.length-1]; URL appURL = new URL(appKiosk.getValue(appName)); HttpURLConnection http = (HttpURLConnection) appURL.openConnection(); - return Pair.of(appName, getStringFromStream((InputStream) http.getContent())); + return Triple.of(appName, getStringFromStream((InputStream) http.getContent()), appKiosk); } catch (IOException e) { @@ -250,43 +259,36 @@ public class AppStoreManager } } - public static int saveScriptToFile(String path, String appFileName, String code, CommandContext cc, boolean globalSavePath){ + public static boolean saveScriptToFile(ServerCommandSource source, String path, String appFileName, String code, boolean globalSavePath){ String scriptPath; - String message; - if(globalSavePath && !cc.getSource().getMinecraftServer().isDedicated()) + String location; + if(globalSavePath && !source.getMinecraftServer().isDedicated()) { //cos config folder only is in clients scriptPath = FabricLoader.getInstance().getConfigDir().resolve("carpet/scripts/appstore").toAbsolutePath()+"/"+path; - message = "global script config folder"; + location = "global script config folder"; } else { - scriptPath = cc.getSource().getMinecraftServer().getSavePath(WorldSavePath.ROOT).resolve("scripts").toAbsolutePath()+"/"+appFileName; - message = "world scripts folder"; + scriptPath = source.getMinecraftServer().getSavePath(WorldSavePath.ROOT).resolve("scripts").toAbsolutePath()+"/"+appFileName; + location = "world scripts folder"; } try { Path scriptLocation = Paths.get(scriptPath); - Path scriptFolderLocation = Paths.get(scriptPath.substring(0, scriptPath.lastIndexOf('/')));//folder location without file name - if (!Files.exists(scriptFolderLocation)) - Files.createDirectories(scriptFolderLocation); - + Files.createDirectories(scriptLocation.getParent()); if(Files.exists(scriptLocation)) - Messenger.m(cc.getSource(), String.format("gi Note: overwriting existing file '%s'", appFileName)); - - - Messenger.m(cc.getSource(), "gi Placing script in " + message); - + Messenger.m(source, String.format("gi Note: overwriting existing app '%s'", appFileName)); FileWriter fileWriter = new FileWriter(scriptPath); fileWriter.write(code); fileWriter.close(); } catch (IOException e) { - Messenger.m(cc.getSource(), "r Error in downloading script"); - return 0; + Messenger.m(source, "r Error in downloading script: "+e.getMessage()); + return false; } - Messenger.m(cc.getSource(), "gi Successfully created "+ appFileName + " in " + message); - return 1; + Messenger.m(source, "gi Successfully created "+ appFileName + " in " + location); + return true; } /** Returns the string from the inputstream gotten from the html request. @@ -298,28 +300,23 @@ public class AppStoreManager */ public static String getStringFromStream(InputStream inputStream) throws IOException { - if (inputStream != null) - { - Writer stringWriter = new StringWriter(); + if (inputStream == null) + throw new IOException("No app to be found on the appstore"); - char[] charBuffer = new char[2048]; - try - { - Reader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); - int counter; - while ((counter = reader.read(charBuffer)) != -1) - stringWriter.write(charBuffer, 0, counter); - - } - finally - { - inputStream.close(); - } - return stringWriter.toString(); - } - else + Writer stringWriter = new StringWriter(); + char[] charBuffer = new char[2048]; + try { - return ""; + Reader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + int counter; + while ((counter = reader.read(charBuffer)) != -1) + stringWriter.write(charBuffer, 0, counter); + } + finally + { + inputStream.close(); + } + return stringWriter.toString(); } } diff --git a/src/main/java/carpet/settings/SettingsManager.java b/src/main/java/carpet/settings/SettingsManager.java index 3c0ae01a..c5ee9760 100644 --- a/src/main/java/carpet/settings/SettingsManager.java +++ b/src/main/java/carpet/settings/SettingsManager.java @@ -193,7 +193,7 @@ public class SettingsManager { if (rule.getBoolValue() || (rule.type == String.class && !rule.get().equals("false"))) { - CarpetServer.scriptServer.addScriptHost(source, rule.scarpetApp, s -> canUseCommand(s, rule.get()), false, false, true); + CarpetServer.scriptServer.addScriptHost(source, rule.scarpetApp, s -> canUseCommand(s, rule.get()), false, false, true, null); } else { CarpetServer.scriptServer.removeScriptHost(source, rule.scarpetApp, false, true); } From deb4f7834742142cb7198e28ce1396a4f7b8b5e2 Mon Sep 17 00:00:00 2001 From: gnembon Date: Fri, 21 May 2021 23:08:33 -0300 Subject: [PATCH 2/5] rotfl fixes #874 --- src/main/java/carpet/script/language/Operators.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/carpet/script/language/Operators.java b/src/main/java/carpet/script/language/Operators.java index 6f18f456..f539656c 100644 --- a/src/main/java/carpet/script/language/Operators.java +++ b/src/main/java/carpet/script/language/Operators.java @@ -74,7 +74,7 @@ public class Operators { int size = lv.size(); if (size == 0) return Value.NULL; Value accumulator = lv.get(0); - for (Value v: lv.subList(1, size)) accumulator = accumulator.multiply(v); + for (Value v: lv.subList(1, size)) accumulator = accumulator.divide(v); return accumulator; }); expression.addFunctionalEquivalence("/", "quotient"); From f21897fab1f35c073ac46a5c067bf0c36682ad51 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 22 May 2021 01:21:20 -0300 Subject: [PATCH 3/5] added custom context to be used in optimization evaluations that should expose all programmers issues, while allowing reporting errors to the error snooping entity. Fixes #875 --- src/main/java/carpet/script/Context.java | 60 +++++++++++++++++++ src/main/java/carpet/script/Expression.java | 15 ++--- src/main/java/carpet/script/ScriptHost.java | 7 ++- .../script/exception/ExpressionException.java | 4 +- 4 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/main/java/carpet/script/Context.java b/src/main/java/carpet/script/Context.java index 17bcd2c6..748da050 100644 --- a/src/main/java/carpet/script/Context.java +++ b/src/main/java/carpet/script/Context.java @@ -1,5 +1,6 @@ package carpet.script; +import carpet.script.exception.InternalExpressionException; import carpet.script.value.Value; import java.util.HashMap; @@ -83,4 +84,63 @@ public class Context { return new Context(this.host); } + public ScriptHost.ErrorSnooper getErrorSnooper() + { + return host.errorSnooper; + } + + + /** + * immutable context only for reason on reporting access violations in evaluating expressions in optimizization + * mode detecting any potential violations that may happen on the way + */ + public static class ContextForErrorReporting extends Context + { + public ScriptHost.ErrorSnooper optmizerEerrorSnooper; + public ContextForErrorReporting(Context parent) + { + super(null); + optmizerEerrorSnooper = parent.host.errorSnooper; + } + + @Override + public ScriptHost.ErrorSnooper getErrorSnooper() + { + return optmizerEerrorSnooper; + } + + public void badProgrammer() + { + throw new InternalExpressionException("Attempting to access the execution context while optimizing the code;" + + " This is not the problem with your code, but the error cause by improper use of code compile optimizations" + + "of scarpet authors. Please report this issue directly to the scarpet issue tracker"); + + } + @Override + public LazyValue getVariable(String name) { badProgrammer(); return null;} + + @Override + public void setVariable(String name, LazyValue lv) { badProgrammer(); } + + @Override + public void delVariable(String variable) { badProgrammer(); } + + @Override + public void removeVariablesMatching(String varname) { badProgrammer(); } + + @Override + public Context with(String variable, LazyValue lv) { badProgrammer(); return this; } + + @Override + public Set getAllVariableNames() { badProgrammer(); return null;} + + @Override + public Context recreate() { badProgrammer(); return null;} + + @Override + protected void initialize() { badProgrammer();} + + @Override + public Context duplicate() { badProgrammer(); return null;} + } } diff --git a/src/main/java/carpet/script/Expression.java b/src/main/java/carpet/script/Expression.java index 2f33ecc2..b1a62fcc 100644 --- a/src/main/java/carpet/script/Expression.java +++ b/src/main/java/carpet/script/Expression.java @@ -1072,6 +1072,7 @@ public class Expression if (!CarpetSettings.scriptsOptimization) return root.op; + Context optimizeOnlyContext = new Context.ContextForErrorReporting(context); CarpetScriptServer.LOG.info("Input code size for "+getModuleName()+": " + treeSize(root) + " nodes, " + treeDepth(root) + " deep"); boolean changed = true; @@ -1088,13 +1089,13 @@ public class Expression while (true) { int tree_size = treeSize(root); int tree_depth = treeDepth(root); - boolean optimized = optimizeTree(context, root, Context.Type.NONE, 0); + boolean optimized = optimizeTree(optimizeOnlyContext, root, Context.Type.NONE, 0); if (!optimized) break; changed = true; CarpetScriptServer.LOG.info("Optimized from " + tree_size + " nodes, " + tree_depth + " code depth to " + treeSize(root) + " nodes, " + treeDepth(root) + " code depth"); } } - return extractOp(context, root, Context.Type.NONE); + return extractOp(optimizeOnlyContext, root, Context.Type.NONE); } private int treeSize(ExpressionNode node) @@ -1222,25 +1223,25 @@ public class Expression Value val = ((LazyValue.Constant) arg.op).get(); args.add((c, t) -> val); } - else args.add((c, t) -> arg.op.evalValue(null, requestedType)); + else args.add((c, t) -> arg.op.evalValue(ctx, requestedType)); } catch (NullPointerException npe) { throw new ExpressionException(ctx, this, node.token, "Attempted to evaluate context free expression"); } } // applying argument unpacking - args= AbstractLazyFunction.lazify(AbstractLazyFunction.unpackLazy(args, null, requestedType)); + args= AbstractLazyFunction.lazify(AbstractLazyFunction.unpackLazy(args, ctx, requestedType)); Value result; if (operation instanceof ILazyFunction) { - result = ((ILazyFunction) operation).lazyEval(null, expectedType, this, node.token, args).evalValue(null, expectedType); + result = ((ILazyFunction) operation).lazyEval(ctx, expectedType, this, node.token, args).evalValue(null, expectedType); } else if (args.size() == 1) { - result = ((ILazyOperator)operation).lazyEval(null, expectedType, this, node.token, args.get(0), null).evalValue(null, expectedType); + result = ((ILazyOperator)operation).lazyEval(ctx, expectedType, this, node.token, args.get(0), null).evalValue(null, expectedType); } else // args == 2 { - result = ((ILazyOperator)operation).lazyEval(null, expectedType, this, node.token, args.get(0), args.get(1)).evalValue(null, expectedType); + result = ((ILazyOperator)operation).lazyEval(ctx, expectedType, this, node.token, args.get(0), args.get(1)).evalValue(null, expectedType); } node.op = LazyValue.ofConstant(result); //node.token.morph(Tokenizer.Token.TokenType.CONSTANT, node.token.surface); diff --git a/src/main/java/carpet/script/ScriptHost.java b/src/main/java/carpet/script/ScriptHost.java index 150cc0ea..919e0ced 100644 --- a/src/main/java/carpet/script/ScriptHost.java +++ b/src/main/java/carpet/script/ScriptHost.java @@ -105,7 +105,12 @@ public abstract class ScriptHost public final Module main; - public Fluff.TriFunction> errorSnooper = null; + @FunctionalInterface + public interface ErrorSnooper + { + List apply(Expression expression, Tokenizer.Token token, String message); + } + public ErrorSnooper errorSnooper = null; protected ScriptHost(Module code, boolean perUser, ScriptHost parent) { diff --git a/src/main/java/carpet/script/exception/ExpressionException.java b/src/main/java/carpet/script/exception/ExpressionException.java index b0872d05..7e494b1d 100644 --- a/src/main/java/carpet/script/exception/ExpressionException.java +++ b/src/main/java/carpet/script/exception/ExpressionException.java @@ -72,9 +72,9 @@ public class ExpressionException extends RuntimeException implements ResolvedExc synchronized static String makeMessage(Context c, Expression e, Tokenizer.Token t, String message) throws ExpressionException { - if (c.host.errorSnooper != null) + if (c.getErrorSnooper() != null) { - List alternative = c.host.errorSnooper.apply(e, t, message); + List alternative = c.getErrorSnooper().apply(e, t, message); if (alternative!= null) { return String.join("\n", alternative); From c6db496a1fce8d840b521873361d2de3d5f59209 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 22 May 2021 01:57:04 -0300 Subject: [PATCH 4/5] fixes behaviour of folder and file detections in java 16, fixes #869 --- src/main/java/carpet/script/argument/FileArgument.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/carpet/script/argument/FileArgument.java b/src/main/java/carpet/script/argument/FileArgument.java index beaa0279..d4fb6152 100644 --- a/src/main/java/carpet/script/argument/FileArgument.java +++ b/src/main/java/carpet/script/argument/FileArgument.java @@ -222,7 +222,10 @@ public class FileArgument String ext = type.extension; try { - return Files.list(dir).filter(path -> (type==Type.FOLDER)?path.toString().endsWith("/"):path.toString().endsWith(ext)); + return Files.list(dir).filter(path -> (type==Type.FOLDER) + ?Files.isDirectory(path) + :(Files.isRegularFile(path) && path.toString().endsWith(ext)) + ); } catch (IOException ignored) { @@ -252,6 +255,7 @@ public class FileArgument close(); } if (type == Type.FOLDER) + // java 8 paths are inconsistent. in java 16 they all should not have trailing slashes return strings.map(s -> s.endsWith("/")?s.substring(0, s.length()-1):s); return strings.map(FilenameUtils::removeExtension); } From fb4c40c951b4633770a4980f75037e99c5e7a4a1 Mon Sep 17 00:00:00 2001 From: gnembon Date: Sat, 22 May 2021 22:14:16 -0300 Subject: [PATCH 5/5] separated properly client disconnect from server shutdown allowing for retaining carpet settings till world is gone. Fixes #854 --- src/main/java/carpet/CarpetServer.java | 3 +++ .../java/carpet/mixins/MinecraftServer_coreMixin.java | 6 ++++++ src/main/java/carpet/network/CarpetClient.java | 10 +++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/carpet/CarpetServer.java b/src/main/java/carpet/CarpetServer.java index 126d8d85..a847a9fa 100644 --- a/src/main/java/carpet/CarpetServer.java +++ b/src/main/java/carpet/CarpetServer.java @@ -188,6 +188,9 @@ public class CarpetServer implements ClientModInitializer,DedicatedServerModInit // this for whatever reason gets called multiple times even when joining; TickSpeed.reset(); + } + public static void onServerDoneClosing(MinecraftServer server) + { settingsManager.detachServer(); } diff --git a/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java b/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java index 8b47e629..29511879 100644 --- a/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java +++ b/src/main/java/carpet/mixins/MinecraftServer_coreMixin.java @@ -50,6 +50,12 @@ public abstract class MinecraftServer_coreMixin CarpetServer.onServerClosed((MinecraftServer) (Object) this); } + @Inject(method = "shutdown", at = @At("TAIL")) + private void serverDoneClosed(CallbackInfo ci) + { + CarpetServer.onServerDoneClosing((MinecraftServer) (Object) this); + } + @Inject(method = "prepareStartRegion", at = @At("RETURN")) private void afterSpawnCreated(WorldGenerationProgressListener worldGenerationProgressListener, CallbackInfo ci) { diff --git a/src/main/java/carpet/network/CarpetClient.java b/src/main/java/carpet/network/CarpetClient.java index 4236d2d3..49627f78 100644 --- a/src/main/java/carpet/network/CarpetClient.java +++ b/src/main/java/carpet/network/CarpetClient.java @@ -37,9 +37,13 @@ public class CarpetClient public static void disconnect() { - isServerCarpet = false; - clientPlayer = null; - CarpetServer.onServerClosed(null); + if (isServerCarpet) + { + isServerCarpet = false; + clientPlayer = null; + CarpetServer.onServerClosed(null); + CarpetServer.onServerDoneClosing(null); + } } public static void setCarpet()