online suggestions via suggester

This commit is contained in:
gnembon committed 2020-11-13 06:30:55 -04:00
1 parent 5f9df1239a
commit bc99b081ca
2 files changed
+72 -34

No files matched your search

@@ -215,7 +215,7 @@ public class CarpetScriptHost extends ScriptHost
Value spec = typeData.getValue(); Value spec = typeData.getValue();
if (!(spec instanceof MapValue)) throw new InternalExpressionException("Spec for '"+argument+"' should be a map"); if (!(spec instanceof MapValue)) throw new InternalExpressionException("Spec for '"+argument+"' should be a map");
Map<String, Value> specData = ((MapValue) spec).getMap().entrySet().stream().collect(Collectors.toMap(e -> e.getKey().getString(), Map.Entry::getValue)); Map<String, Value> specData = ((MapValue) spec).getMap().entrySet().stream().collect(Collectors.toMap(e -> e.getKey().getString(), Map.Entry::getValue));
appArgTypes.put(argument, CommandArgument.buildFromConfig(argument, specData)); appArgTypes.put(argument, CommandArgument.buildFromConfig(argument, specData, this));
} }
} }
appConfig = config; appConfig = config;
@@ -2,11 +2,13 @@ package carpet.script.command;
import carpet.fakes.BlockStateArgumentInterface; import carpet.fakes.BlockStateArgumentInterface;
import carpet.script.CarpetScriptHost; import carpet.script.CarpetScriptHost;
import carpet.script.argument.FunctionArgument;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.value.BlockValue; import carpet.script.value.BlockValue;
import carpet.script.value.EntityValue; import carpet.script.value.EntityValue;
import carpet.script.value.FormattedTextValue; import carpet.script.value.FormattedTextValue;
import carpet.script.value.ListValue; import carpet.script.value.ListValue;
import carpet.script.value.MapValue;
import carpet.script.value.NBTSerializableValue; import carpet.script.value.NBTSerializableValue;
import carpet.script.value.NumericValue; import carpet.script.value.NumericValue;
import carpet.script.value.StringValue; import carpet.script.value.StringValue;
@@ -22,11 +24,14 @@ import com.mojang.brigadier.arguments.LongArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.context.ParsedCommandNode;
import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder; import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.mojang.brigadier.tree.ArgumentCommandNode;
import com.mojang.brigadier.tree.CommandNode;
import net.minecraft.advancement.Advancement; import net.minecraft.advancement.Advancement;
import net.minecraft.command.CommandSource; import net.minecraft.command.CommandSource;
import net.minecraft.command.argument.AngleArgumentType; import net.minecraft.command.argument.AngleArgumentType;
@@ -74,8 +79,10 @@ import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec2f;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@@ -259,13 +266,15 @@ public abstract class CommandArgument
{ {
CommandArgument arg = getTypeForArgument(param, host); CommandArgument arg = getTypeForArgument(param, host);
if (arg.suggestionProvider != null) return argument(param, arg.getArgumentType()).suggests(arg.suggestionProvider); if (arg.suggestionProvider != null) return argument(param, arg.getArgumentType()).suggests(arg.suggestionProvider);
return arg.needsMatching? argument(param, arg.getArgumentType()).suggests(arg::suggest) : argument(param, arg.getArgumentType()); return arg.needsMatching? argument(param, arg.getArgumentType()).suggests((c, b) -> arg.suggest(c, b, host)) : argument(param, arg.getArgumentType());
} }
protected String suffix; protected String suffix;
protected Collection<String> examples; protected Collection<String> examples;
protected boolean needsMatching = false; protected boolean needsMatching = false;
protected SuggestionProvider<ServerCommandSource> suggestionProvider; protected SuggestionProvider<ServerCommandSource> suggestionProvider;
protected FunctionArgument<Value> customSuggester;
protected CommandArgument( protected CommandArgument(
String suffix, String suffix,
@@ -292,7 +301,7 @@ public abstract class CommandArgument
return suffix; return suffix;
} }
public static CommandArgument buildFromConfig(String suffix, Map<String, Value> config) public static CommandArgument buildFromConfig(String suffix, Map<String, Value> config, CarpetScriptHost host)
{ {
if (!config.containsKey("type")) if (!config.containsKey("type"))
throw new InternalExpressionException("Custom types should at least specify the type"); throw new InternalExpressionException("Custom types should at least specify the type");
@@ -300,15 +309,20 @@ public abstract class CommandArgument
if (!builtIns.containsKey(baseType)) if (!builtIns.containsKey(baseType))
throw new InternalExpressionException("Unknown base type: "+baseType); throw new InternalExpressionException("Unknown base type: "+baseType);
CommandArgument variant = builtIns.get(baseType).builder().get(); CommandArgument variant = builtIns.get(baseType).builder().get();
variant.configure(config); variant.configure(config, host);
variant.suffix = suffix; variant.suffix = suffix;
return variant; return variant;
} }
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
if (config.containsKey("suggester"))
{
customSuggester = FunctionArgument.fromCommandSpec(host, config.get("suggester"));
}
if (config.containsKey("suggest")) if (config.containsKey("suggest"))
{ {
if (config.containsKey("suggester")) throw new InternalExpressionException("Attempted to provide 'suggest' list while 'suggester' is present");
Value suggestionValue = config.get("suggest"); Value suggestionValue = config.get("suggest");
if (!(suggestionValue instanceof ListValue)) throw new InternalExpressionException("Argument suggestions needs to be a list"); if (!(suggestionValue instanceof ListValue)) throw new InternalExpressionException("Argument suggestions needs to be a list");
examples = ((ListValue) suggestionValue).getItems().stream() examples = ((ListValue) suggestionValue).getItems().stream()
@@ -316,34 +330,55 @@ public abstract class CommandArgument
.collect(Collectors.toSet()); .collect(Collectors.toSet());
if (!examples.isEmpty()) needsMatching = true; if (!examples.isEmpty()) needsMatching = true;
} }
}; }
public CompletableFuture<Suggestions> suggest( public CompletableFuture<Suggestions> suggest(
CommandContext<ServerCommandSource> context, CommandContext<ServerCommandSource> context,
SuggestionsBuilder suggestionsBuilder SuggestionsBuilder suggestionsBuilder,
) CarpetScriptHost host
) throws CommandSyntaxException
{ {
String prefix = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT); String prefix = suggestionsBuilder.getRemaining().toLowerCase(Locale.ROOT);
suggestFor(prefix).forEach(suggestionsBuilder::suggest); suggestFor(context, prefix, host).forEach(suggestionsBuilder::suggest);
return suggestionsBuilder.buildFuture(); return suggestionsBuilder.buildFuture();
} }
protected List<String> suggestFor(String prefix) protected List<String> suggestFor(CommandContext<ServerCommandSource> context, String prefix, CarpetScriptHost host) throws CommandSyntaxException
{ {
return getOptions().stream().filter(s -> optionMatchesPrefix(prefix, s)).collect(Collectors.toList()); return getOptions(context, host).stream().filter(s -> optionMatchesPrefix(prefix, s)).collect(Collectors.toList());
} }
protected Collection<String> getOptions() protected Collection<String> getOptions(CommandContext<ServerCommandSource> context, CarpetScriptHost host) throws CommandSyntaxException
{ {
if (customSuggester != null)
{
Map<Value, Value> params = new HashMap<>();
for(ParsedCommandNode<ServerCommandSource> pnode : context.getNodes())
{
CommandNode<ServerCommandSource> node = pnode.getNode();
if (node instanceof ArgumentCommandNode)
{
params.put(StringValue.of(node.getName()), CommandArgument.getValue(context, node.getName(), host));
}
}
List<Value> args = new ArrayList<>(customSuggester.args.size()+1);
args.add(MapValue.wrap(params));
args.addAll(customSuggester.args);
Value response = host.handleCommand(context.getSource(), customSuggester.function, args);
if (!(response instanceof ListValue)) throw error("Custom suggester should return a list of options");
return ((ListValue) response).getItems().stream().map(Value::getString).collect(Collectors.toList());
}
if (needsMatching) return examples;
//return Lists.newArrayList(""); //return Lists.newArrayList("");
// better than nothing I guess // better than nothing I guess
// nothing is such a bad default. // nothing is such a bad default.
if (needsMatching) return examples;
return Collections.singletonList("... "+getTypeSuffix()); return Collections.singletonList("... "+getTypeSuffix());
} }
protected boolean optionMatchesPrefix(String prefix, String option) protected boolean optionMatchesPrefix(String prefix, String option)
{ {
//prefix = prefix.toLowerCase(Locale.ROOT);
//option = option.toLowerCase(Locale.ROOT);
for(int i = 0; !option.startsWith(prefix, i); ++i) for(int i = 0; !option.startsWith(prefix, i); ++i)
{ {
i = option.indexOf('_', i); i = option.indexOf('_', i);
@@ -382,9 +417,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
caseSensitive = config.getOrDefault("case_sensitive", Value.FALSE).getBoolean(); caseSensitive = config.getOrDefault("case_sensitive", Value.FALSE).getBoolean();
if (config.containsKey("options")) if (config.containsKey("options"))
{ {
@@ -397,7 +432,10 @@ public abstract class CommandArgument
} }
@Override @Override
protected Collection<String> getOptions() { return validOptions.isEmpty()?super.getOptions():validOptions; } protected Collection<String> getOptions(CommandContext<ServerCommandSource> context, CarpetScriptHost host) throws CommandSyntaxException
{
return validOptions.isEmpty()?super.getOptions(context, host):validOptions;
}
@Override @Override
protected Supplier<CommandArgument> builder() { return WordArgument::new; } protected Supplier<CommandArgument> builder() { return WordArgument::new; }
@@ -446,9 +484,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
mustBeLoaded = config.getOrDefault("loaded", Value.FALSE).getBoolean(); mustBeLoaded = config.getOrDefault("loaded", Value.FALSE).getBoolean();
} }
@@ -481,9 +519,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
blockCentered = config.getOrDefault("block_centered", Value.TRUE).getBoolean(); blockCentered = config.getOrDefault("block_centered", Value.TRUE).getBoolean();
} }
@@ -529,9 +567,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
onlyFans = config.getOrDefault("players", Value.FALSE).getBoolean(); onlyFans = config.getOrDefault("players", Value.FALSE).getBoolean();
single = config.getOrDefault("single", Value.FALSE).getBoolean(); single = config.getOrDefault("single", Value.FALSE).getBoolean();
} }
@@ -570,9 +608,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
single = config.getOrDefault("single", Value.FALSE).getBoolean(); single = config.getOrDefault("single", Value.FALSE).getBoolean();
} }
@@ -611,9 +649,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
single = config.getOrDefault("single", Value.FALSE).getBoolean(); single = config.getOrDefault("single", Value.FALSE).getBoolean();
} }
@@ -648,9 +686,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
mapRequired = !config.getOrDefault("allow_element", Value.FALSE).getBoolean(); mapRequired = !config.getOrDefault("allow_element", Value.FALSE).getBoolean();
} }
@@ -694,9 +732,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
if (config.containsKey("options")) if (config.containsKey("options"))
{ {
Value optionsValue = config.get("options"); Value optionsValue = config.get("options");
@@ -736,9 +774,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
if (config.containsKey("min")) if (config.containsKey("min"))
{ {
min = NumericValue.asNumber(config.get("min"), "min").getDouble(); min = NumericValue.asNumber(config.get("min"), "min").getDouble();
@@ -787,9 +825,9 @@ public abstract class CommandArgument
} }
@Override @Override
protected void configure(Map<String, Value> config) protected void configure(Map<String, Value> config, CarpetScriptHost host)
{ {
super.configure(config); super.configure(config, host);
if (config.containsKey("min")) if (config.containsKey("min"))
{ {
min = NumericValue.asNumber(config.get("min"), "min").getLong(); min = NumericValue.asNumber(config.get("min"), "min").getLong();