diff --git a/bukkit/src/main/java/co/aikar/commands/BukkitRootCommand.java b/bukkit/src/main/java/co/aikar/commands/BukkitRootCommand.java index d0eaf04b..94a22eb9 100644 --- a/bukkit/src/main/java/co/aikar/commands/BukkitRootCommand.java +++ b/bukkit/src/main/java/co/aikar/commands/BukkitRootCommand.java @@ -76,12 +76,12 @@ public class BukkitRootCommand extends Command implements RootCommand { BaseCommand subHandler = this.subCommands.get(checkSub); if (subHandler != null) { subHandler.execute(sender, commandLabel, args); - return false; + return true; } } this.defCommand.execute(sender, commandLabel, args); - return false; + return true; } public void addChild(BaseCommand command) { diff --git a/core/src/main/java/co/aikar/commands/BaseCommand.java b/core/src/main/java/co/aikar/commands/BaseCommand.java index 1244f5ed..9baf90bb 100644 --- a/core/src/main/java/co/aikar/commands/BaseCommand.java +++ b/core/src/main/java/co/aikar/commands/BaseCommand.java @@ -67,6 +67,7 @@ public abstract class BaseCommand { String permission; private ExceptionHandler exceptionHandler = null; + CommandOperationContext lastCommandOperationContext; public BaseCommand() {} public BaseCommand(String cmd) { @@ -340,30 +341,26 @@ public abstract class BaseCommand { } private void postCommandOperation() { - Stack commandManagers = CommandManager.currentCommandManager.get(); - Stack commandIssuers = CommandManager.currentCommandIssuer.get(); - commandManagers.pop(); - commandIssuers.pop(); + CommandManager.commandOperationContext.get().pop(); execSubcommand = null; execLabel = null; origArgs = new String[]{}; } private void preCommandOperation(CommandIssuer issuer, String commandLabel, String[] args) { - Stack commandManagers = CommandManager.currentCommandManager.get(); - Stack commandIssuers = CommandManager.currentCommandIssuer.get(); - commandManagers.push(this.manager); - commandIssuers.push(issuer); - + Stack contexts = CommandManager.commandOperationContext.get(); + CommandOperationContext context = this.manager.createCommandOperationContext(this, issuer, commandLabel, args); + contexts.push(context); + lastCommandOperationContext = context; execSubcommand = null; execLabel = commandLabel; origArgs = args; } - private CommandIssuer getCurrentCommandIssuer() { + public CommandIssuer getCurrentCommandIssuer() { return CommandManager.getCurrentCommandIssuer(); } - private CommandManager getCurrentCommandManager() { + public CommandManager getCurrentCommandManager() { return CommandManager.getCurrentCommandManager(); } diff --git a/core/src/main/java/co/aikar/commands/CommandManager.java b/core/src/main/java/co/aikar/commands/CommandManager.java index 4dc856f8..ca3d01d2 100644 --- a/core/src/main/java/co/aikar/commands/CommandManager.java +++ b/core/src/main/java/co/aikar/commands/CommandManager.java @@ -32,8 +32,10 @@ import java.util.*; @SuppressWarnings("WeakerAccess") public abstract class CommandManager { - static ThreadLocal> currentCommandManager = ThreadLocal.withInitial(Stack::new); - static ThreadLocal> currentCommandIssuer = ThreadLocal.withInitial(Stack::new); + /** + * This is a stack incase a command calls a command + */ + static ThreadLocal> commandOperationContext = ThreadLocal.withInitial(Stack::new); protected Map rootCommands = new HashMap<>(); protected CommandReplacements replacements = new CommandReplacements(this); protected Locales locales = new Locales(this); @@ -51,20 +53,18 @@ public abstract class CommandManager { formatters.put(MessageType.ERROR, plain); } + public static CommandOperationContext getCurrentCommandOperationContext() { + return commandOperationContext.get().peek(); + } + public static CommandIssuer getCurrentCommandIssuer() { - Stack commandIssuers = currentCommandIssuer.get(); - if (commandIssuers == null) { - return null; - } - return commandIssuers.peek(); + CommandOperationContext context = commandOperationContext.get().peek(); + return context != null ? context.getCommandIssuer() : null; } public static CommandManager getCurrentCommandManager() { - Stack commandManagers = currentCommandManager.get(); - if (commandManagers == null) { - return null; - } - return commandManagers.peek(); + CommandOperationContext context = commandOperationContext.get().peek(); + return context != null ? context.getCommandManager() : null; } /** @@ -186,4 +186,14 @@ public abstract class CommandManager { public Locale getIssuerLocale(CommandIssuer issuer) { return getLocales().getDefaultLocale(); } + + public CommandOperationContext createCommandOperationContext(BaseCommand command, CommandIssuer issuer, String commandLabel, String[] args) { + return new CommandOperationContext( + this, + issuer, + command, + commandLabel, + args + ); + } } diff --git a/core/src/main/java/co/aikar/commands/CommandOperationContext.java b/core/src/main/java/co/aikar/commands/CommandOperationContext.java new file mode 100644 index 00000000..ea1c41e2 --- /dev/null +++ b/core/src/main/java/co/aikar/commands/CommandOperationContext.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package co.aikar.commands; + +/** + * Holds information about the currently executing command on this thread + */ +public class CommandOperationContext { + + private final CommandManager manager; + private final CommandIssuer issuer; + private final BaseCommand command; + private final String commandLabel; + private final String[] args; + + CommandOperationContext(CommandManager manager, CommandIssuer issuer, BaseCommand command, String commandLabel, String[] args) { + this.manager = manager; + this.issuer = issuer; + this.command = command; + this.commandLabel = commandLabel; + this.args = args; + } + + public CommandManager getCommandManager() { + return manager; + } + + public CommandIssuer getCommandIssuer() { + return issuer; + } + + public BaseCommand getCommand() { + return command; + } + + public String getCommandLabel() { + return commandLabel; + } + + public String[] getArgs() { + return args; + } +} diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandContexts.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandContexts.java index 73b9334d..9dd6b5bf 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeCommandContexts.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandContexts.java @@ -23,10 +23,14 @@ package co.aikar.commands; +import co.aikar.commands.contexts.CommandResultSupplier; + @SuppressWarnings("WeakerAccess") public class SpongeCommandContexts extends CommandContexts { public SpongeCommandContexts(final SpongeCommandManager manager) { super(manager); + + registerIssuerOnlyContext(CommandResultSupplier.class, c -> new CommandResultSupplier()); } } diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java index 58e1b129..7006f1b6 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java @@ -153,4 +153,15 @@ public class SpongeCommandManager extends CommandManager { } } } + + @Override + public CommandOperationContext createCommandOperationContext(BaseCommand command, CommandIssuer issuer, String commandLabel, String[] args) { + return new SpongeCommandOperationContext( + this, + issuer, + command, + commandLabel, + args + ); + } } diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandOperationContext.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandOperationContext.java new file mode 100644 index 00000000..e1c363d7 --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandOperationContext.java @@ -0,0 +1,18 @@ +package co.aikar.commands; + +import org.spongepowered.api.command.CommandResult; + +public class SpongeCommandOperationContext extends CommandOperationContext { + private CommandResult result = CommandResult.success(); + SpongeCommandOperationContext(CommandManager manager, CommandIssuer issuer, BaseCommand command, String commandLabel, String[] args) { + super(manager, issuer, command, commandLabel, args); + } + + public CommandResult getResult() { + return result; + } + + public void setResult(CommandResult result) { + this.result = result; + } +} diff --git a/sponge/src/main/java/co/aikar/commands/SpongeRootCommand.java b/sponge/src/main/java/co/aikar/commands/SpongeRootCommand.java index d75994f4..4a671981 100644 --- a/sponge/src/main/java/co/aikar/commands/SpongeRootCommand.java +++ b/sponge/src/main/java/co/aikar/commands/SpongeRootCommand.java @@ -24,6 +24,7 @@ package co.aikar.commands; import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil; +import org.jetbrains.annotations.NotNull; import org.spongepowered.api.command.CommandCallable; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; @@ -62,37 +63,34 @@ public class SpongeRootCommand implements CommandCallable, RootCommand { } @Override - public CommandResult process(CommandSource source, String arguments) throws CommandException { + public CommandResult process(@NotNull CommandSource source, @NotNull String arguments) throws CommandException { String[] args = arguments.isEmpty() ? new String[0] : arguments.split(" "); - if(this.execute(new SpongeCommandIssuer(manager, source), this.name, args)) { - return CommandResult.success(); - } - return CommandResult.empty(); + return this.execute(new SpongeCommandIssuer(manager, source), this.name, args); } @Override - public List getSuggestions(CommandSource source, String arguments, @Nullable Location location) throws CommandException { + public List getSuggestions(@NotNull CommandSource source, @NotNull String arguments, @Nullable Location location) throws CommandException { String[] args = arguments.isEmpty() ? new String[0] : arguments.split(" "); return tabComplete(new SpongeCommandIssuer(manager, source), this.name, args); } @Override - public boolean testPermission(CommandSource source) { + public boolean testPermission(@NotNull CommandSource source) { return this.defCommand.hasPermission(source); } @Override - public Optional getShortDescription(CommandSource source) { + public Optional getShortDescription(@NotNull CommandSource source) { return Optional.empty(); } @Override - public Optional getHelp(CommandSource source) { + public Optional getHelp(@NotNull CommandSource source) { return Optional.empty(); } @Override - public Text getUsage(CommandSource source) { + public Text getUsage(@NotNull CommandSource source) { return Text.of(); } @@ -102,18 +100,19 @@ public class SpongeRootCommand implements CommandCallable, RootCommand { return new ArrayList<>(completions); } - private boolean execute(CommandIssuer sender, String commandLabel, String[] args) { + private CommandResult execute(CommandIssuer sender, String commandLabel, String[] args) { + BaseCommand cmd = this.defCommand; for (int i = args.length; i >= 0; i--) { String checkSub = ApacheCommonsLangUtil.join(args, " ", 0, i).toLowerCase(); BaseCommand subHandler = this.subCommands.get(checkSub); if (subHandler != null) { - subHandler.execute(sender, commandLabel, args); - return false; + cmd = subHandler; + break; } } - this.defCommand.execute(sender, commandLabel, args); - return false; + cmd.execute(sender, commandLabel, args); + return ((SpongeCommandOperationContext) cmd.lastCommandOperationContext).getResult(); } public void addChild(BaseCommand command) { diff --git a/sponge/src/main/java/co/aikar/commands/contexts/CommandResultSupplier.java b/sponge/src/main/java/co/aikar/commands/contexts/CommandResultSupplier.java new file mode 100644 index 00000000..30b155e7 --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/contexts/CommandResultSupplier.java @@ -0,0 +1,19 @@ +package co.aikar.commands.contexts; + +import co.aikar.commands.CommandManager; +import co.aikar.commands.SpongeCommandOperationContext; +import org.spongepowered.api.command.CommandResult; + +import java.util.function.Consumer; + +public class CommandResultSupplier implements Consumer { + + public CommandResultSupplier() { + } + + @Override + public void accept(CommandResult commandResult) { + SpongeCommandOperationContext context = (SpongeCommandOperationContext) CommandManager.getCurrentCommandOperationContext(); + context.setResult(commandResult); + } +}