diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java index edd5281e..15901d95 100644 --- a/src/main/java/carpet/script/CarpetScriptHost.java +++ b/src/main/java/carpet/script/CarpetScriptHost.java @@ -3,6 +3,7 @@ package carpet.script; import carpet.CarpetServer; import carpet.script.api.Auxiliary; import carpet.script.bundled.Module; +import carpet.script.command.CommandArgument; import carpet.script.exception.CarpetExpressionException; import carpet.script.exception.ExpressionException; import carpet.script.exception.InternalExpressionException; @@ -26,8 +27,10 @@ import net.minecraft.util.math.BlockPos; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static java.lang.Math.max; @@ -41,8 +44,9 @@ public class CarpetScriptHost extends ScriptHost public boolean persistenceRequired; public Map appConfig; + public Map appArgTypes; - private CarpetScriptHost(CarpetScriptServer server, Module code, boolean perUser, ScriptHost parent, Map config) + private CarpetScriptHost(CarpetScriptServer server, Module code, boolean perUser, ScriptHost parent, Map config, Map argTypes) { super(code, perUser, parent); this.saveTimeout = 0; @@ -58,11 +62,12 @@ public class CarpetScriptHost extends ScriptHost persistenceRequired = ((CarpetScriptHost)parent).persistenceRequired; } appConfig = config; + appArgTypes = argTypes; } public static CarpetScriptHost create(CarpetScriptServer scriptServer, Module module, boolean perPlayer, ServerCommandSource source) { - CarpetScriptHost host = new CarpetScriptHost(scriptServer, module, perPlayer, null, Collections.emptyMap() ); + CarpetScriptHost host = new CarpetScriptHost(scriptServer, module, perPlayer, null, Collections.emptyMap(), new HashMap<>()); // parse code and convert to expression if (module != null) { @@ -97,7 +102,7 @@ public class CarpetScriptHost extends ScriptHost @Override protected ScriptHost duplicate() { - return new CarpetScriptHost(scriptServer, main, false, this, appConfig); + return new CarpetScriptHost(scriptServer, main, false, this, appConfig, appArgTypes); } @Override @@ -132,7 +137,22 @@ public class CarpetScriptHost extends ScriptHost Map config = ((MapValue) ret).getMap(); setPerPlayer(config.getOrDefault(new StringValue("scope"), new StringValue("player")).getString().equalsIgnoreCase("player")); persistenceRequired = config.getOrDefault(new StringValue("stay_loaded"), Value.FALSE).getBoolean(); - this.appConfig = config; + // read custom arguments + Value arguments = config.get(StringValue.of("arguments")); + if (arguments != null) + { + if (!(arguments instanceof MapValue)) + throw new InternalExpressionException("'arguments' element in config should be a map"); + for (Map.Entry typeData : ((MapValue)arguments).getMap().entrySet()) + { + String argument = typeData.getKey().getString(); + Value spec = typeData.getValue(); + if (!(spec instanceof MapValue)) throw new InternalExpressionException("Spec for '"+argument+"' should be a map"); + Map specData = ((MapValue) spec).getMap().entrySet().stream().collect(Collectors.toMap(e -> e.getKey().getString(), Map.Entry::getValue)); + appArgTypes.put(argument, CommandArgument.buildFromConfig(argument, specData)); + } + } + appConfig = config; } catch (NullPointerException | InvalidCallbackException ignored) { diff --git a/src/main/java/carpet/script/CarpetScriptServer.java b/src/main/java/carpet/script/CarpetScriptServer.java index fe22646e..923e4752 100644 --- a/src/main/java/carpet/script/CarpetScriptServer.java +++ b/src/main/java/carpet/script/CarpetScriptServer.java @@ -315,14 +315,14 @@ public class CarpetScriptServer List args = new ArrayList<>(argNames.size()); for (String s : paramNames) { - args.add(CommandArgument.getValue(ctx, s)); + args.add(CommandArgument.getValue(ctx, s, cHost)); } Value response = cHost.handleCommand(ctx.getSource(), function, args); if (!response.isNull()) Messenger.m(ctx.getSource(), "gi " + response.getString()); return (int) response.readInteger(); } - private LiteralArgumentBuilder getFancyCommand(LiteralArgumentBuilder command, ScriptHost host, FunctionValue function ) + private LiteralArgumentBuilder getFancyCommand(LiteralArgumentBuilder command, CarpetScriptHost host, FunctionValue function ) { List argNames = function.getArguments(); String hostName = host.getName(); @@ -336,10 +336,10 @@ public class CarpetScriptServer { List reversedArgs = new ArrayList<>(argNames); Collections.reverse(reversedArgs); - RequiredArgumentBuilder argChain = CommandArgument.argumentNode(reversedArgs.get(0)).executes(c -> execute(c, hostName, function, argNames)); + RequiredArgumentBuilder argChain = CommandArgument.argumentNode(reversedArgs.get(0), host).executes(c -> execute(c, hostName, function, argNames)); for (int i = 1; i < reversedArgs.size(); i++) { - argChain = CommandArgument.argumentNode(reversedArgs.get(i)).then(argChain); + argChain = CommandArgument.argumentNode(reversedArgs.get(i), host).then(argChain); } return command.then(literal(function.getString()). requires((player) -> modules.containsKey(hostName)). diff --git a/src/main/java/carpet/script/command/CommandArgument.java b/src/main/java/carpet/script/command/CommandArgument.java index 1a014834..ff4235a5 100644 --- a/src/main/java/carpet/script/command/CommandArgument.java +++ b/src/main/java/carpet/script/command/CommandArgument.java @@ -1,5 +1,6 @@ package carpet.script.command; +import carpet.script.CarpetScriptHost; import carpet.script.exception.InternalExpressionException; import carpet.script.value.ListValue; import carpet.script.value.NumericValue; @@ -42,21 +43,25 @@ public abstract class CommandArgument public static final Map builtIns = baseTypes.stream().collect(Collectors.toMap(CommandArgument::getTypeSuffix, a -> a)); - private static CommandArgument getTypeForArgument(String argument) + public static final CommandArgument DEFAULT = baseTypes.get(0); + + private static CommandArgument getTypeForArgument(String argument, CarpetScriptHost host) { String[] components = argument.split("_"); String suffix = components[components.length-1].toLowerCase(Locale.ROOT); - return builtIns.getOrDefault(suffix, builtIns.get("string")); + CommandArgument arg = host.appArgTypes.get(suffix); + if (arg != null) return arg; + return builtIns.getOrDefault(suffix, DEFAULT); } - public static RequiredArgumentBuilder argumentNode(String param) + public static RequiredArgumentBuilder argumentNode(String param, CarpetScriptHost host) { - CommandArgument arg = getTypeForArgument(param); + CommandArgument arg = getTypeForArgument(param, host); return arg.needsMatching? argument(param, arg.getArgumentType()).suggests(arg::suggest) : argument(param, arg.getArgumentType()); } private String suffix; - private final Collection examples; + private Collection examples; protected boolean needsMatching = false; protected CommandArgument( @@ -69,17 +74,17 @@ public abstract class CommandArgument this.needsMatching = needsMatching; } - public static ArgumentType getArgument(String param) + public static ArgumentType getArgument(String param, CarpetScriptHost host) { - return getTypeForArgument(param).getArgumentType(); + return getTypeForArgument(param, host).getArgumentType(); } protected abstract ArgumentType getArgumentType(); - public static Value getValue(CommandContext context, String param) throws CommandSyntaxException + public static Value getValue(CommandContext context, String param, CarpetScriptHost host) throws CommandSyntaxException { - return getTypeForArgument(param).getValueFromContext(context, param); + return getTypeForArgument(param, host).getValueFromContext(context, param); } protected abstract Value getValueFromContext(CommandContext context, String param) throws CommandSyntaxException; @@ -108,9 +113,20 @@ public abstract class CommandArgument variant.configure(config); variant.suffix = suffix; return variant; - }; + } - protected abstract void configure(Map config); + protected void configure(Map config) + { + if (config.containsKey("suggest")) + { + Value suggestionValue = config.get("suggest"); + if (!(suggestionValue instanceof ListValue)) throw new InternalExpressionException("Argument suggestions needs to be a list"); + examples = ((ListValue) suggestionValue).getItems().stream() + .map(Value::getString) + .collect(Collectors.toSet()); + if (!examples.isEmpty()) needsMatching = true; + } + }; public CompletableFuture suggest( CommandContext context, @@ -177,6 +193,7 @@ public abstract class CommandArgument @Override protected void configure(Map config) { + super.configure(config); caseSensitive = config.getOrDefault("case_sensitive", Value.FALSE).getBoolean(); if (config.containsKey("options")) { @@ -222,6 +239,7 @@ public abstract class CommandArgument @Override protected void configure(Map config) { + super.configure(config); mustBeLoaded = config.getOrDefault("loaded", Value.FALSE).getBoolean(); } @@ -264,6 +282,7 @@ public abstract class CommandArgument @Override protected void configure(Map config) { + super.configure(config); if (config.containsKey("min")) { min = NumericValue.asNumber(config.get("min"), "min").getDouble();