Merge branch 'master' into 1.17

This commit is contained in:
gnembon committed 2021-05-22 22:14:43 -03:00
commit 95d8c5fd90
14 files changed
+189 -90

No files matched your search

+3
View File
@@ -188,6 +188,9 @@ public class CarpetServer implements ClientModInitializer,DedicatedServerModInit
// this for whatever reason gets called multiple times even when joining; // this for whatever reason gets called multiple times even when joining;
TickSpeed.reset(); TickSpeed.reset();
}
public static void onServerDoneClosing(MinecraftServer server)
{
settingsManager.detachServer(); settingsManager.detachServer();
} }
@@ -271,13 +271,13 @@ public class ScriptCommand
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.listAvailableModules(true),bb)). suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.listAvailableModules(true),bb)).
executes((cc) -> 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; return success?1:0;
}). }).
then(literal("global"). then(literal("global").
executes((cc) -> 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; return success?1:0;
} }
) )
@@ -328,8 +328,9 @@ public class ScriptCommand
)?1:0)))); )?1:0))));
LiteralArgumentBuilder<ServerCommandSource> d = literal("download").requires((player) -> SettingsManager.canUseCommand(player, CarpetSettings.commandScriptACE)). LiteralArgumentBuilder<ServerCommandSource> 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(argument("path", StringArgumentType.greedyString()).
then(literal("local").then(argument("path", StringArgumentType.greedyString()).suggests(ScriptCommand::suggestDownloadableApps).executes(cc-> AppStoreManager.downloadScript(cc, StringArgumentType.getString(cc,"path"), false)))); suggests(ScriptCommand::suggestDownloadableApps).
executes(cc-> AppStoreManager.downloadScript(cc.getSource(), StringArgumentType.getString(cc,"path"))));
dispatcher.register(literal("script"). dispatcher.register(literal("script").
requires((player) -> SettingsManager.canUseCommand(player, CarpetSettings.commandScript)). requires((player) -> SettingsManager.canUseCommand(player, CarpetSettings.commandScript)).
@@ -50,6 +50,12 @@ public abstract class MinecraftServer_coreMixin
CarpetServer.onServerClosed((MinecraftServer) (Object) this); 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")) @Inject(method = "prepareStartRegion", at = @At("RETURN"))
private void afterSpawnCreated(WorldGenerationProgressListener worldGenerationProgressListener, CallbackInfo ci) private void afterSpawnCreated(WorldGenerationProgressListener worldGenerationProgressListener, CallbackInfo ci)
{ {
@@ -37,9 +37,13 @@ public class CarpetClient
public static void disconnect() public static void disconnect()
{ {
isServerCarpet = false; if (isServerCarpet)
clientPlayer = null; {
CarpetServer.onServerClosed(null); isServerCarpet = false;
clientPlayer = null;
CarpetServer.onServerClosed(null);
CarpetServer.onServerDoneClosing(null);
}
} }
public static void setCarpet() public static void setCarpet()
@@ -12,8 +12,10 @@ import carpet.script.exception.CarpetExpressionException;
import carpet.script.exception.ExpressionException; import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.InvalidCallbackException; import carpet.script.exception.InvalidCallbackException;
import carpet.script.utils.AppStoreManager;
import carpet.script.value.EntityValue; import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue; import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue;
import carpet.script.value.MapValue; import carpet.script.value.MapValue;
import carpet.script.value.NumericValue; import carpet.script.value.NumericValue;
import carpet.script.value.StringValue; import carpet.script.value.StringValue;
@@ -78,6 +80,7 @@ public class CarpetScriptHost extends ScriptHost
Predicate<ServerCommandSource> commandValidator; Predicate<ServerCommandSource> commandValidator;
boolean isRuleApp; boolean isRuleApp;
public AppStoreManager.StoreNode storeSource;
private CarpetScriptHost(CarpetScriptServer server, Module code, boolean perUser, ScriptHost parent, Map<Value, Value> config, Map<String, CommandArgument> argTypes, Predicate<ServerCommandSource> commandValidator, boolean isRuleApp) private CarpetScriptHost(CarpetScriptServer server, Module code, boolean perUser, ScriptHost parent, Map<Value, Value> config, Map<String, CommandArgument> argTypes, Predicate<ServerCommandSource> commandValidator, boolean isRuleApp)
{ {
@@ -98,9 +101,10 @@ public class CarpetScriptHost extends ScriptHost
appArgTypes = argTypes; appArgTypes = argTypes;
this.commandValidator = commandValidator; this.commandValidator = commandValidator;
this.isRuleApp = isRuleApp; this.isRuleApp = isRuleApp;
storeSource = null;
} }
public static CarpetScriptHost create(CarpetScriptServer scriptServer, Module module, boolean perPlayer, ServerCommandSource source, Predicate<ServerCommandSource> commandValidator, boolean isRuleApp) public static CarpetScriptHost create(CarpetScriptServer scriptServer, Module module, boolean perPlayer, ServerCommandSource source, Predicate<ServerCommandSource> commandValidator, boolean isRuleApp, AppStoreManager.StoreNode storeSource)
{ {
CarpetScriptHost host = new CarpetScriptHost(scriptServer, module, perPlayer, null, Collections.emptyMap(), new HashMap<>(), commandValidator, isRuleApp); CarpetScriptHost host = new CarpetScriptHost(scriptServer, module, perPlayer, null, Collections.emptyMap(), new HashMap<>(), commandValidator, isRuleApp);
// parse code and convert to expression // parse code and convert to expression
@@ -117,6 +121,7 @@ public class CarpetScriptHost extends ScriptHost
host.setChatErrorSnooper(source); host.setChatErrorSnooper(source);
CarpetExpression ex = new CarpetExpression(host.main, code, source, new BlockPos(0, 0, 0)); CarpetExpression ex = new CarpetExpression(host.main, code, source, new BlockPos(0, 0, 0));
ex.getExpr().asATextSource(); ex.getExpr().asATextSource();
host.storeSource = storeSource;
ex.scriptRunCommand(host, new BlockPos(source.getPosition())); ex.scriptRunCommand(host, new BlockPos(source.getPosition()));
} }
catch (CarpetExpressionException e) catch (CarpetExpressionException e)
@@ -130,6 +135,10 @@ public class CarpetScriptHost extends ScriptHost
host.handleErrorWithStack("Math doesn't compute", ae); host.handleErrorWithStack("Math doesn't compute", ae);
return null; return null;
} }
finally
{
host.storeSource = null;
}
} }
return host; return host;
} }
@@ -302,8 +311,19 @@ public class CarpetScriptHost extends ScriptHost
else else
{ {
checkModVersionRequirements(loadRequirements); 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; appConfig = config;
} }
catch (NullPointerException ignored) catch (NullPointerException ignored)
@@ -21,6 +21,7 @@ import carpet.script.language.Functions;
import carpet.script.language.Loops; import carpet.script.language.Loops;
import carpet.script.language.Sys; import carpet.script.language.Sys;
import carpet.script.language.Threading; import carpet.script.language.Threading;
import carpet.script.utils.AppStoreManager;
import carpet.script.value.FunctionValue; import carpet.script.value.FunctionValue;
import carpet.script.value.Value; import carpet.script.value.Value;
import carpet.utils.CarpetProfiler; import carpet.utils.CarpetProfiler;
@@ -54,9 +55,6 @@ import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
public class CarpetScriptServer public class CarpetScriptServer
{ {
//make static for now, but will change that later: //make static for now, but will change that later:
@@ -127,7 +125,7 @@ public class CarpetScriptServer
tickStart = 0L; tickStart = 0L;
stopAll = false; stopAll = false;
holyMoly = server.getCommandManager().getDispatcher().getRoot().getChildren().stream().map(CommandNode::getName).collect(Collectors.toSet()); 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() public void initializeForWorld()
@@ -142,7 +140,7 @@ public class CarpetScriptServer
{ {
for (String moduleName: listAvailableModules(false)) 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(); CarpetEventServer.Event.START.onTick();
@@ -241,7 +239,7 @@ public class CarpetScriptServer
} }
public boolean addScriptHost(ServerCommandSource source, String name, Predicate<ServerCommandSource> commandValidator, public boolean addScriptHost(ServerCommandSource source, String name, Predicate<ServerCommandSource> 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); CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet load", CarpetProfiler.TYPE.GENERAL);
if (commandValidator == null) commandValidator = p -> true; if (commandValidator == null) commandValidator = p -> true;
@@ -260,7 +258,7 @@ public class CarpetScriptServer
Messenger.m(source, "r Failed to add "+name+" app"); Messenger.m(source, "r Failed to add "+name+" app");
return false; 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) if (newHost == null)
{ {
Messenger.m(source, "r Failed to add "+name+" app"); 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)); apps.keySet().forEach(s -> removeScriptHost(server.getCommandSource(), s, false, false));
CarpetEventServer.Event.clearAllBuiltinEvents(); CarpetEventServer.Event.clearAllBuiltinEvents();
init(); 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() public void reAddCommands()
+60
View File
@@ -1,5 +1,6 @@
package carpet.script; package carpet.script;
import carpet.script.exception.InternalExpressionException;
import carpet.script.value.Value; import carpet.script.value.Value;
import java.util.HashMap; import java.util.HashMap;
@@ -83,4 +84,63 @@ public class Context
{ {
return new Context(this.host); 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<String> getAllVariableNames() { badProgrammer(); return null;}
@Override
public Context recreate() { badProgrammer(); return null;}
@Override
protected void initialize() { badProgrammer();}
@Override
public Context duplicate() { badProgrammer(); return null;}
}
} }
+8 -7
View File
@@ -1072,6 +1072,7 @@ public class Expression
if (!CarpetSettings.scriptsOptimization) if (!CarpetSettings.scriptsOptimization)
return root.op; return root.op;
Context optimizeOnlyContext = new Context.ContextForErrorReporting(context);
CarpetScriptServer.LOG.info("Input code size for "+getModuleName()+": " + treeSize(root) + " nodes, " + treeDepth(root) + " deep"); CarpetScriptServer.LOG.info("Input code size for "+getModuleName()+": " + treeSize(root) + " nodes, " + treeDepth(root) + " deep");
boolean changed = true; boolean changed = true;
@@ -1088,13 +1089,13 @@ public class Expression
while (true) { while (true) {
int tree_size = treeSize(root); int tree_size = treeSize(root);
int tree_depth = treeDepth(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; if (!optimized) break;
changed = true; changed = true;
CarpetScriptServer.LOG.info("Optimized from " + tree_size + " nodes, " + tree_depth + " code depth to " + treeSize(root) + " nodes, " + treeDepth(root) + " code depth"); 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) private int treeSize(ExpressionNode node)
@@ -1222,25 +1223,25 @@ public class Expression
Value val = ((LazyValue.Constant) arg.op).get(); Value val = ((LazyValue.Constant) arg.op).get();
args.add((c, t) -> val); 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) { } catch (NullPointerException npe) {
throw new ExpressionException(ctx, this, node.token, "Attempted to evaluate context free expression"); throw new ExpressionException(ctx, this, node.token, "Attempted to evaluate context free expression");
} }
} }
// applying argument unpacking // applying argument unpacking
args= AbstractLazyFunction.lazify(AbstractLazyFunction.unpackLazy(args, null, requestedType)); args= AbstractLazyFunction.lazify(AbstractLazyFunction.unpackLazy(args, ctx, requestedType));
Value result; Value result;
if (operation instanceof ILazyFunction) 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) 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 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.op = LazyValue.ofConstant(result);
//node.token.morph(Tokenizer.Token.TokenType.CONSTANT, node.token.surface); //node.token.morph(Tokenizer.Token.TokenType.CONSTANT, node.token.surface);
+6 -1
View File
@@ -105,7 +105,12 @@ public abstract class ScriptHost
public final Module main; public final Module main;
public Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorSnooper = null; @FunctionalInterface
public interface ErrorSnooper
{
List<String> apply(Expression expression, Tokenizer.Token token, String message);
}
public ErrorSnooper errorSnooper = null;
protected ScriptHost(Module code, boolean perUser, ScriptHost parent) protected ScriptHost(Module code, boolean perUser, ScriptHost parent)
{ {
@@ -222,7 +222,10 @@ public class FileArgument
String ext = type.extension; String ext = type.extension;
try 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) catch (IOException ignored)
{ {
@@ -252,6 +255,7 @@ public class FileArgument
close(); close();
} }
if (type == Type.FOLDER) 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(s -> s.endsWith("/")?s.substring(0, s.length()-1):s);
return strings.map(FilenameUtils::removeExtension); return strings.map(FilenameUtils::removeExtension);
} }
@@ -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 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<String> alternative = c.host.errorSnooper.apply(e, t, message); List<String> alternative = c.getErrorSnooper().apply(e, t, message);
if (alternative!= null) if (alternative!= null)
{ {
return String.join("\n", alternative); return String.join("\n", alternative);
@@ -74,7 +74,7 @@ public class Operators {
int size = lv.size(); int size = lv.size();
if (size == 0) return Value.NULL; if (size == 0) return Value.NULL;
Value accumulator = lv.get(0); 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; return accumulator;
}); });
expression.addFunctionalEquivalence("/", "quotient"); expression.addFunctionalEquivalence("/", "quotient");
@@ -1,5 +1,8 @@
package carpet.script.utils; package carpet.script.utils;
import carpet.CarpetServer;
import carpet.script.CarpetScriptHost;
import carpet.script.value.Value;
import carpet.settings.ParsedRule; import carpet.settings.ParsedRule;
import carpet.settings.Validator; import carpet.settings.Validator;
import carpet.utils.Messenger; import carpet.utils.Messenger;
@@ -7,12 +10,11 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import com.mojang.brigadier.context.CommandContext;
import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.command.CommandException; import net.minecraft.command.CommandException;
import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.util.WorldSavePath; 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.BufferedReader;
import java.io.FileWriter; 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 /** 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. * {@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. /** 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/"; 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<String> public static class ScarpetAppStoreValidator extends Validator<String>
{ {
@Override public String validate(ServerCommandSource source, ParsedRule<String> currentRule, String newValue, String string) @Override public String validate(ServerCommandSource source, ParsedRule<String> 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 String description() { return "Appstore link should point to a valid github repository";}
} }
public static class PathNode public static class StoreNode
{ {
public String name; public String name;
public PathNode parent; public StoreNode parent;
public Map<String, PathNode> children; public Map<String, StoreNode> children;
public boolean sealed; public boolean sealed;
public String value; 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.children = new HashMap<>();
node.value = null; node.value = null;
node.sealed = false; node.sealed = false;
return node; 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.children = null;
node.value = value; node.value = value;
node.sealed = true; node.sealed = true;
@@ -110,7 +118,7 @@ public class AppStoreManager
{ {
return this == appStoreRoot ? new StringBuilder() : parent.createPrePath().append(pathElement()); 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.parent = parent;
this.name = name; this.name = name;
@@ -175,7 +183,7 @@ public class AppStoreManager
return children.values().stream().map(s -> prefix+s.pathElement().replaceAll("/$", "")).collect(Collectors.toList()); 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"); if (isLeaf()) throw new IOException(pathElement+" is not a folder");
fillChildren(); fillChildren();
@@ -185,7 +193,7 @@ public class AppStoreManager
public String getValue(String file) throws IOException 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"); if (!leaf.isLeaf()) throw new IOException(file+" is not a file");
return leaf.value; return leaf.value;
} }
@@ -201,7 +209,7 @@ public class AppStoreManager
public static List<String> suggestionsFromPath(String currentPath) throws IOException public static List<String> suggestionsFromPath(String currentPath) throws IOException
{ {
String[] path = currentPath.split("/"); String[] path = currentPath.split("/");
PathNode appKiosk = appStoreRoot; StoreNode appKiosk = appStoreRoot;
for(String pathElement : path) for(String pathElement : path)
{ {
if (appKiosk.cannotContinueFor(pathElement)) return appKiosk.createPathSuggestions(); 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. * 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 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 * @return {@code 1} if we succesfully saved the script, {@code 0} otherwise
*/ */
public static int downloadScript(CommandContext<ServerCommandSource> cc, String path, boolean global) public static int downloadScript(ServerCommandSource source, String path)
{ {
Pair<String,String> code = getScriptCode(path); Triple<String,String, StoreNode> code = getScriptCode(path);
return saveScriptToFile(path, code.getLeft(), code.getRight(), cc, global); 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. /** 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 * @param appPath The user inputted path to the scarpet script
* @return Pair of app file name and content * @return Pair of app file name and content
*/ */
public static Pair<String,String> getScriptCode(String appPath) public static Triple<String,String, StoreNode> getScriptCode(String appPath)
{ {
String[] path = appPath.split("/"); String[] path = appPath.split("/");
PathNode appKiosk = appStoreRoot; StoreNode appKiosk = appStoreRoot;
try try
{ {
for(String pathElement : Arrays.copyOfRange(path, 0, path.length-1)) for(String pathElement : Arrays.copyOfRange(path, 0, path.length-1))
@@ -242,7 +251,7 @@ public class AppStoreManager
String appName = path[path.length-1]; String appName = path[path.length-1];
URL appURL = new URL(appKiosk.getValue(appName)); URL appURL = new URL(appKiosk.getValue(appName));
HttpURLConnection http = (HttpURLConnection) appURL.openConnection(); 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) catch (IOException e)
{ {
@@ -250,43 +259,36 @@ public class AppStoreManager
} }
} }
public static int saveScriptToFile(String path, String appFileName, String code, CommandContext<ServerCommandSource> cc, boolean globalSavePath){ public static boolean saveScriptToFile(ServerCommandSource source, String path, String appFileName, String code, boolean globalSavePath){
String scriptPath; String scriptPath;
String message; String location;
if(globalSavePath && !cc.getSource().getMinecraftServer().isDedicated()) if(globalSavePath && !source.getMinecraftServer().isDedicated())
{ //cos config folder only is in clients { //cos config folder only is in clients
scriptPath = FabricLoader.getInstance().getConfigDir().resolve("carpet/scripts/appstore").toAbsolutePath()+"/"+path; scriptPath = FabricLoader.getInstance().getConfigDir().resolve("carpet/scripts/appstore").toAbsolutePath()+"/"+path;
message = "global script config folder"; location = "global script config folder";
} }
else else
{ {
scriptPath = cc.getSource().getMinecraftServer().getSavePath(WorldSavePath.ROOT).resolve("scripts").toAbsolutePath()+"/"+appFileName; scriptPath = source.getMinecraftServer().getSavePath(WorldSavePath.ROOT).resolve("scripts").toAbsolutePath()+"/"+appFileName;
message = "world scripts folder"; location = "world scripts folder";
} }
try try
{ {
Path scriptLocation = Paths.get(scriptPath); Path scriptLocation = Paths.get(scriptPath);
Path scriptFolderLocation = Paths.get(scriptPath.substring(0, scriptPath.lastIndexOf('/')));//folder location without file name Files.createDirectories(scriptLocation.getParent());
if (!Files.exists(scriptFolderLocation))
Files.createDirectories(scriptFolderLocation);
if(Files.exists(scriptLocation)) if(Files.exists(scriptLocation))
Messenger.m(cc.getSource(), String.format("gi Note: overwriting existing file '%s'", appFileName)); Messenger.m(source, String.format("gi Note: overwriting existing app '%s'", appFileName));
Messenger.m(cc.getSource(), "gi Placing script in " + message);
FileWriter fileWriter = new FileWriter(scriptPath); FileWriter fileWriter = new FileWriter(scriptPath);
fileWriter.write(code); fileWriter.write(code);
fileWriter.close(); fileWriter.close();
} }
catch (IOException e) catch (IOException e)
{ {
Messenger.m(cc.getSource(), "r Error in downloading script"); Messenger.m(source, "r Error in downloading script: "+e.getMessage());
return 0; return false;
} }
Messenger.m(cc.getSource(), "gi Successfully created "+ appFileName + " in " + message); Messenger.m(source, "gi Successfully created "+ appFileName + " in " + location);
return 1; return true;
} }
/** Returns the string from the inputstream gotten from the html request. /** 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 public static String getStringFromStream(InputStream inputStream) throws IOException
{ {
if (inputStream != null) if (inputStream == null)
{ throw new IOException("No app to be found on the appstore");
Writer stringWriter = new StringWriter();
char[] charBuffer = new char[2048]; Writer stringWriter = new StringWriter();
try 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
{ {
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();
} }
} }
@@ -193,7 +193,7 @@ public class SettingsManager
{ {
if (rule.getBoolValue() || (rule.type == String.class && !rule.get().equals("false"))) 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 { } else {
CarpetServer.scriptServer.removeScriptHost(source, rule.scarpetApp, false, true); CarpetServer.scriptServer.removeScriptHost(source, rule.scarpetApp, false, true);
} }