Skip to content

Commit

Permalink
Organized Brigadier
Browse files Browse the repository at this point in the history
  • Loading branch information
Mqzn committed Sep 17, 2024
1 parent 2fe73ba commit 202ede4
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 183 deletions.
181 changes: 181 additions & 0 deletions brigadier/src/main/java/dev/velix/imperat/BaseBrigadierManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package dev.velix.imperat;

import com.mojang.brigadier.LiteralMessage;
import com.mojang.brigadier.Message;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import dev.velix.imperat.command.Command;
import dev.velix.imperat.command.Description;
import dev.velix.imperat.command.parameters.CommandParameter;
import dev.velix.imperat.command.parameters.FlagParameter;
import dev.velix.imperat.command.suggestions.CompletionArg;
import dev.velix.imperat.command.tree.CommandNode;
import dev.velix.imperat.command.tree.ParameterNode;
import dev.velix.imperat.context.ArgumentQueue;
import dev.velix.imperat.context.Source;
import dev.velix.imperat.context.SuggestionContext;
import dev.velix.imperat.resolvers.SuggestionResolver;
import dev.velix.imperat.util.ImperatDebugger;
import dev.velix.imperat.util.TypeUtility;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
import static com.mojang.brigadier.builder.RequiredArgumentBuilder.argument;

public abstract non-sealed class BaseBrigadierManager<S extends Source> implements BrigadierManager<S> {

protected final Imperat<S> dispatcher;
protected final List<ArgumentTypeResolver> resolvers = new ArrayList<>();

protected BaseBrigadierManager(Imperat<S> dispatcher) {
this.dispatcher = dispatcher;
}

@Override
public BrigadierNode parseCommandIntoNode(Command<S> command) {
var tree = command.tree();
var root = tree.getRoot();
//ImperatDebugger.visualize("Parsing %s '%s'", (command.isSubCommand() ? "sub-command" : "command"), command.getName());
return convertRoot(root);
}

private BrigadierNode convertRoot(CommandNode<S> root) {
BrigadierNode bRoot = BrigadierNode.create(literal(root.getData().name()));
bRoot.withExecution(dispatcher, this)
.withRequirement((obj) -> {
var source = wrapCommandSource(obj);
return root.getData().isIgnoringACPerms()
|| dispatcher.getPermissionResolver().hasPermission(source, root.getData().permission());
}
);

for (var child : root.getChildren()) {
bRoot.addChild(convertNode(root, root, child));
}
return bRoot;
}

private BrigadierNode convertNode(CommandNode<S> root, ParameterNode<?> parent, ParameterNode<?> node) {
BrigadierNode child = BrigadierNode.create(node instanceof CommandNode<?> ? literal(node.getData().name()) : argument(node.getData().name(), getArgumentType(node.getData())));
child.withExecution(dispatcher, this)
.withRequirement((obj) -> {
var permissionResolver = dispatcher.getPermissionResolver();
var source = wrapCommandSource(obj);

boolean isIgnoringAC = root.getData().isIgnoringACPerms();
if (parent != root && parent instanceof CommandNode<?> parentCmdNode) {
isIgnoringAC = isIgnoringAC && parentCmdNode.getData().isIgnoringACPerms();
}
if (node instanceof CommandNode<?> commandNode) {
isIgnoringAC = isIgnoringAC && commandNode.getData().isIgnoringACPerms();
}
if (isIgnoringAC) {
return true;
}
boolean hasParentPerm = permissionResolver.hasPermission(source, parent.getData().permission());
boolean hasNodePerm = permissionResolver.hasPermission(source, node.getData().permission());

return (hasParentPerm && hasNodePerm);
});

if (!(node instanceof CommandNode<?>)) {
child.suggest(createSuggestionProvider(root.getData(), node.getData()));
}

for (var innerChild : node.getChildren()) {
child.addChild(convertNode(root, node, innerChild));
}
return child;
}


private @NotNull SuggestionProvider<Object> createSuggestionProvider(
Command<S> command,
CommandParameter parameter
) {
SuggestionResolver<S, ?> suggestionResolver = dispatcher.getParameterSuggestionResolver(parameter);
ImperatDebugger.debug("suggestion resolver is null=%s for param '%s'", suggestionResolver == null, parameter.format());
if (suggestionResolver == null) {
return ((context, builder) -> builder.buildFuture());
}

return (context, builder) -> {

try {

S source = this.wrapCommandSource(context.getSource());
String tooltipMessage = parameter.description() == Description.EMPTY ? parameter.format() : parameter.description().toString();
Message tooltip = new LiteralMessage(tooltipMessage);
String input = context.getInput();

ArgumentQueue args = ArgumentQueue.parseAutoCompletion(
input.startsWith("/") ? input.substring(1) : input
);

CompletionArg arg = new CompletionArg(args.getLast(), args.size() - 1);
SuggestionContext<S> ctx = dispatcher.getContextFactory().createSuggestionContext(dispatcher, source, command, args, arg);
suggestionResolver
.autoComplete(ctx, parameter)
.stream()
.filter(c -> arg.value().isEmpty() || arg.value().isBlank() || c.toLowerCase().startsWith(arg.value().toLowerCase()))
.distinct()
.sorted(String.CASE_INSENSITIVE_ORDER)
.forEach(suggestionResult -> builder.suggest(suggestionResult, tooltip));

} catch (Throwable e) {
e.printStackTrace();
}
return builder.buildFuture();
};
}


//resolvers methods

@Override
public <T> void registerArgumentResolver(
Class<T> type,
ArgumentTypeResolver argumentTypeResolver
) {
resolvers.add((param) -> {
if (param.isFlag()) {

FlagParameter flagParameter = param.asFlagParameter();
if (flagParameter.isSwitch()) {
return argumentTypeResolver.resolveArgType(flagParameter);
}

return param.type() == flagParameter.getFlagData().inputType()
? argumentTypeResolver.resolveArgType(param) : null;
}
return TypeUtility.matches(param.type(), type) ? argumentTypeResolver.resolveArgType(param) : null;
});
}

@Override
public void registerArgumentResolver(ArgumentTypeResolver argumentTypeResolver) {
resolvers.add(argumentTypeResolver);
}

@Override
public @NotNull ArgumentType<?> getArgumentType(CommandParameter parameter) {
for (var resolver : resolvers) {
var resolved = resolver.resolveArgType(parameter);
if (resolved != null)
return resolved;
}
return getStringArgType(parameter);
}


private StringArgumentType getStringArgType(CommandParameter parameter) {
if (parameter.isGreedy()) return StringArgumentType.greedyString();
else return StringArgumentType.string();
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,7 @@
*
* @param <S> the command-source type
*/
public interface BrigadierManager<S extends Source> {

/**
* Get the dispatcher
*
* @return {@link Imperat}
*/
Imperat<S> getDispatcher();
public sealed interface BrigadierManager<S extends Source> permits BaseBrigadierManager {

/**
* Converts the original command source from brigadier
Expand Down
Loading

0 comments on commit 202ede4

Please sign in to comment.