use of com.mojang.brigadier.tree.CommandNode in project SpongeCommon by SpongePowered.
the class SpongeParameterTranslator method createCommandTree.
@SuppressWarnings({ "unchecked", "rawtypes" })
public Collection<LiteralCommandNode<CommandSourceStack>> createCommandTree(final Command.Parameterized command, final Collection<String> aliases) {
if (aliases.isEmpty()) {
throw new IllegalArgumentException("Aliases must not be empty.");
}
// create the first literal.
final Collection<String> sortedAliases = aliases.stream().sorted().collect(Collectors.toList());
final Iterator<String> aliasIterator = sortedAliases.iterator();
final String baseAlias = aliasIterator.next();
final SpongeCommandExecutorWrapper executor = command.executor().map(SpongeCommandExecutorWrapper::new).orElse(null);
// Create the defining characteristics of the node.
final LiteralArgumentBuilder<CommandSourceStack> basicNode = LiteralArgumentBuilder.literal(baseAlias);
basicNode.requires((Predicate) command.executionRequirements());
if (command.isTerminal() && executor != null) {
basicNode.executes(executor);
}
final SpongeLiteralCommandNode commandNode = new SpongeLiteralCommandNode(basicNode);
if (executor != null) {
this.createAndAttachNode(Collections.singleton(commandNode), command.parameters(), executor, true, true);
}
for (final Parameter.Subcommand subcommand : command.subcommands()) {
final Collection<LiteralCommandNode<CommandSourceStack>> builtSubcommand = this.createCommandTree(subcommand.command(), subcommand.aliases());
builtSubcommand.forEach(commandNode::addChild);
}
this.createFlags(commandNode, command.flags(), executor);
final List<LiteralCommandNode<CommandSourceStack>> allCommandNodes = new ArrayList<>();
allCommandNodes.add(commandNode);
final Collection<CommandNode<CommandSourceStack>> children = commandNode.getChildren();
while (aliasIterator.hasNext()) {
final LiteralArgumentBuilder<CommandSourceStack> redirectedNode = LiteralArgumentBuilder.literal(aliasIterator.next());
redirectedNode.executes(commandNode.getCommand());
redirectedNode.requires(commandNode.getRequirement());
// merged, the above can be substituted in here.
for (final CommandNode<CommandSourceStack> child : children) {
redirectedNode.then(child);
}
allCommandNodes.add(new SpongeLiteralCommandNode(redirectedNode));
}
return Collections.unmodifiableCollection(allCommandNodes);
}
use of com.mojang.brigadier.tree.CommandNode in project SpongeCommon by SpongePowered.
the class CommandsMixin method impl$testPermissionAndPreventRecalculationWhenSendingNodes.
@Redirect(method = "fillUsableCommands", at = @At(value = "INVOKE", target = "Lcom/mojang/brigadier/tree/CommandNode;canUse(Ljava/lang/Object;)Z", remap = false))
private boolean impl$testPermissionAndPreventRecalculationWhenSendingNodes(final CommandNode<CommandSourceStack> commandNode, final Object source, final CommandNode<CommandSourceStack> rootCommandNode, final CommandNode<SharedSuggestionProvider> rootSuggestion, final CommandSourceStack sourceButTyped, final Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> commandNodeToSuggestionNode) {
final ServerPlayer e = (ServerPlayer) sourceButTyped.getEntity();
final Map<CommandNode<CommandSourceStack>, List<CommandNode<SharedSuggestionProvider>>> playerNodes = this.impl$playerNodeCache.get(e);
final List<CommandNode<SharedSuggestionProvider>> existingNodes = playerNodes.get(commandNode);
if (existingNodes != null) {
if (!existingNodes.isEmpty()) {
boolean hasCustomSuggestionsAlready = CommandUtil.checkForCustomSuggestions(rootSuggestion);
for (final CommandNode<SharedSuggestionProvider> node : existingNodes) {
// Because we don't control the client, we have to work around it here.
if (hasCustomSuggestionsAlready && node instanceof ArgumentCommandNode) {
final ArgumentCommandNode<SharedSuggestionProvider, ?> argNode = (ArgumentCommandNode<SharedSuggestionProvider, ?>) node;
if (argNode.getCustomSuggestions() != null) {
// Rebuild the node without the custom suggestions.
rootSuggestion.addChild(this.impl$cloneArgumentCommandNodeWithoutSuggestions(argNode));
continue;
}
} else if (node instanceof ArgumentCommandNode && ((ArgumentCommandNode<?, ?>) node).getCustomSuggestions() != null) {
// no more custom suggestions
hasCustomSuggestionsAlready = true;
}
rootSuggestion.addChild(node);
}
}
// If empty, we have a node won't resolve (even if not complex), so we ignore it.
return false;
// If we have already processed this node and it appears in the suggestion node list, prevent a potentially costly
// canUse check as we know we can already use it.
} else if (!commandNodeToSuggestionNode.containsKey(commandNode) && !SpongeNodePermissionCache.canUse(rootCommandNode instanceof RootCommandNode, this.impl$commandManager.getDispatcher(), commandNode, sourceButTyped)) {
playerNodes.put(commandNode, Collections.emptyList());
return false;
}
if (commandNode instanceof SpongeArgumentCommandNode && ((SpongeArgumentCommandNode<?>) commandNode).isComplex()) {
final boolean hasCustomSuggestionsAlready = CommandUtil.checkForCustomSuggestions(rootSuggestion);
final CommandNode<SharedSuggestionProvider> finalCommandNode = ((SpongeArgumentCommandNode<?>) commandNode).getComplexSuggestions(rootSuggestion, commandNodeToSuggestionNode, playerNodes, !hasCustomSuggestionsAlready);
if (!this.impl$getChildrenFromNode(commandNode).isEmpty()) {
this.shadow$fillUsableCommands(commandNode, finalCommandNode, sourceButTyped, commandNodeToSuggestionNode);
}
return false;
}
// Normal node, handle it normally. We don't add to the playerNodeCache - the commandNodeToSuggestionNode map handles this.
return true;
}
use of com.mojang.brigadier.tree.CommandNode in project SpongeCommon by SpongePowered.
the class CommandsMixin method impl$addNonBrigSuggestions.
@Redirect(method = "sendCommands", at = @At(value = "INVOKE", target = "Lnet/minecraft/commands/Commands;fillUsableCommands(Lcom/mojang/brigadier/tree/CommandNode;Lcom/mojang/brigadier/tree/CommandNode;Lnet/minecraft/commands/CommandSourceStack;Ljava/util/Map;)V"))
private void impl$addNonBrigSuggestions(final Commands commands, final CommandNode<CommandSourceStack> p_197052_1_, final CommandNode<SharedSuggestionProvider> p_197052_2_, final CommandSourceStack p_197052_3_, final Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> p_197052_4_, final ServerPlayer playerEntity) {
try (final CauseStackManager.StackFrame frame = PhaseTracker.getCauseStackManager().pushCauseFrame()) {
frame.addContext(EventContextKeys.SUBJECT, (Subject) playerEntity);
final CommandCause sourceToUse = ((CommandSourceStackBridge) p_197052_3_).bridge$withCurrentCause();
try {
this.impl$playerNodeCache.put(playerEntity, new IdentityHashMap<>());
// We use this because the redirects should be a 1:1 mapping (which is what this map is for).
final IdentityHashMap<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> idMap = new IdentityHashMap<>(p_197052_4_);
this.shadow$fillUsableCommands(p_197052_1_, p_197052_2_, (CommandSourceStack) sourceToUse, idMap);
} finally {
this.impl$playerNodeCache.remove(playerEntity);
}
for (final CommandNode<SharedSuggestionProvider> node : this.impl$commandManager.getNonBrigadierSuggestions(sourceToUse)) {
p_197052_2_.addChild(node);
}
}
}
Aggregations