diff --git a/core/src/main/java/co/aikar/commands/CommandCompletionContext.java b/core/src/main/java/co/aikar/commands/CommandCompletionContext.java index b647a5de..dbcbc595 100644 --- a/core/src/main/java/co/aikar/commands/CommandCompletionContext.java +++ b/core/src/main/java/co/aikar/commands/CommandCompletionContext.java @@ -32,7 +32,7 @@ import java.util.Map; public class CommandCompletionContext { private final RegisteredCommand command; - private final CommandIssuer issuer; + protected final CommandIssuer issuer; private final String input; private final String config; private final Map configs = Maps.newHashMap(); diff --git a/pom.xml b/pom.xml index 3bf05c5a..e84ee9af 100644 --- a/pom.xml +++ b/pom.xml @@ -100,6 +100,6 @@ bukkit paper - + sponge diff --git a/sponge/pom.xml b/sponge/pom.xml new file mode 100644 index 00000000..bf96924d --- /dev/null +++ b/sponge/pom.xml @@ -0,0 +1,63 @@ + + + + + 4.0.0 + + + co.aikar + acf-parent + 0.5.0-SNAPSHOT + ../pom.xml + + + acf-sponge + 0.5.0-SNAPSHOT + + ACF (Sponge) + + + + spongepowered + https://repo.spongepowered.org/maven/ + + + + + + co.aikar + acf-core + 0.5.0-SNAPSHOT + compile + + + org.spongepowered + spongeapi + 5.1.0 + provided + + + diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java new file mode 100644 index 00000000..5b75b474 --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletionContext.java @@ -0,0 +1,38 @@ +/* + * 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; + +import org.spongepowered.api.command.CommandSource; + +@SuppressWarnings("WeakerAccess") +public class SpongeCommandCompletionContext extends CommandCompletionContext { + + SpongeCommandCompletionContext(final RegisteredCommand command, final CommandIssuer issuer, final String input, final String config, final String[] args) { + super(command, issuer, input, config, args); + } + + public CommandSource getSource() { + return this.issuer.getIssuer(); + } +} diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletions.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletions.java new file mode 100644 index 00000000..2a073c24 --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandCompletions.java @@ -0,0 +1,34 @@ +/* + * 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; + +import org.spongepowered.api.command.CommandSource; + +@SuppressWarnings("WeakerAccess") +public class SpongeCommandCompletions extends CommandCompletions { + + public SpongeCommandCompletions(final SpongeCommandManager manager) { + super(manager); + } +} diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandContexts.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandContexts.java new file mode 100644 index 00000000..73b9334d --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandContexts.java @@ -0,0 +1,32 @@ +/* + * 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; + +@SuppressWarnings("WeakerAccess") +public class SpongeCommandContexts extends CommandContexts { + + public SpongeCommandContexts(final SpongeCommandManager manager) { + super(manager); + } +} diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java new file mode 100644 index 00000000..a9570ce1 --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandExecutionContext.java @@ -0,0 +1,42 @@ +/* + * 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; + +import org.spongepowered.api.command.CommandSource; + +import java.lang.reflect.Parameter; +import java.util.List; +import java.util.Map; + +public class SpongeCommandExecutionContext extends CommandExecutionContext { + + SpongeCommandExecutionContext(RegisteredCommand cmd, Parameter param, CommandIssuer sender, List args, + int index, Map passedArgs) { + super(cmd, param, sender, args, index, passedArgs); + } + + public CommandSource getSource() { + return this.issuer.getIssuer(); + } +} diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandIssuer.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandIssuer.java new file mode 100644 index 00000000..e1eb467c --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandIssuer.java @@ -0,0 +1,58 @@ +/* + * 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; + +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.text.serializer.TextSerializers; + +public class SpongeCommandIssuer implements CommandIssuer { + + private final CommandSource source; + + SpongeCommandIssuer(final CommandSource source) { + this.source = source; + } + + @Override + public boolean isPlayer() { + return this.source instanceof Player; + } + + @Override + public T getIssuer() { + //noinspection unchecked + return (T) this.source; + } + + @Override + public void sendMessage(final String message) { + this.source.sendMessage(TextSerializers.FORMATTING_CODE.deserialize(message)); + } + + @Override + public boolean hasPermission(final String permission) { + return this.source.hasPermission(permission); + } +} diff --git a/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java new file mode 100644 index 00000000..82be09ce --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeCommandManager.java @@ -0,0 +1,122 @@ +/* + * 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; + +import co.aikar.timings.Timing; +import co.aikar.timings.Timings; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.plugin.PluginContainer; + +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("WeakerAccess") +public class SpongeCommandManager extends CommandManager { + + protected final PluginContainer plugin; + protected Map registeredCommands = new HashMap<>(); + protected SpongeCommandContexts contexts; + protected SpongeCommandCompletions completions; + + public SpongeCommandManager(PluginContainer plugin) { + this.plugin = plugin; + } + + @Override + public boolean isCommandIssuer(Class type) { + return CommandSource.class.isAssignableFrom(type); + } + + @Override + public synchronized CommandContexts getCommandContexts() { + if (this.contexts == null) { + this.contexts = new SpongeCommandContexts(this); + } + return contexts; + } + + @Override + public synchronized CommandCompletions getCommandCompletions() { + if (this.completions == null) { + this.completions = new SpongeCommandCompletions(this); + } + return completions; + } + + @Override + public boolean hasRegisteredCommands() { + return !registeredCommands.isEmpty(); + } + + @Override + public void registerCommand(BaseCommand command) { + command.onRegister(this); + + for (Map.Entry entry : command.registeredCommands.entrySet()) { + String key = entry.getKey().toLowerCase(); + SpongeRootCommand value = (SpongeRootCommand) entry.getValue(); + if (!value.isRegistered) { + Sponge.getCommandManager().register(this.plugin, value, value.name); + } + value.isRegistered = true; + registeredCommands.put(key, value); + } + } + + public Timing createTiming(final SpongeRegisteredCommand command) { + return Timings.of(this.plugin, "Command: " + command.command); + } + + @Override + public RootCommand createRootCommand(String cmd) { + return new SpongeRootCommand(this, cmd); + } + + @Override + public CommandIssuer getCommandIssuer(Object issuer) { + if (!(issuer instanceof CommandSource)) { + throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Command Issuer."); + } + return new SpongeCommandIssuer((CommandSource) issuer); + } + + @Override + public R createCommandContext(RegisteredCommand command, Parameter parameter, CommandIssuer sender, List args, int i, Map passedArgs) { + return (R) new SpongeCommandExecutionContext(command, parameter, sender, args, i, passedArgs); + } + + @Override + public CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) { + return new SpongeCommandCompletionContext(command, sender, input, config, args); + } + + @Override + public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) { + return new RegisteredCommand(command, cmdName, method, prefSubCommand); + } +} diff --git a/sponge/src/main/java/co/aikar/commands/SpongeRegisteredCommand.java b/sponge/src/main/java/co/aikar/commands/SpongeRegisteredCommand.java new file mode 100644 index 00000000..19a273fa --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeRegisteredCommand.java @@ -0,0 +1,50 @@ +/* + * 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; + +import co.aikar.timings.Timing; + +import java.lang.reflect.Method; + +public class SpongeRegisteredCommand extends RegisteredCommand { + + private final Timing timing; + + SpongeRegisteredCommand(BaseCommand scope, String command, Method method, String prefSubCommand) { + super(scope, command, method, prefSubCommand); + this.timing = ((SpongeCommandManager) scope.manager).createTiming(this); + } + + @Override + public void preCommand() { + this.timing.startTiming(); + super.preCommand(); + } + + @Override + public void postCommand() { + super.postCommand(); + this.timing.stopTiming(); + } +} diff --git a/sponge/src/main/java/co/aikar/commands/SpongeRootCommand.java b/sponge/src/main/java/co/aikar/commands/SpongeRootCommand.java new file mode 100644 index 00000000..9784d0c7 --- /dev/null +++ b/sponge/src/main/java/co/aikar/commands/SpongeRootCommand.java @@ -0,0 +1,145 @@ +/* + * 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; + +import co.aikar.commands.apachecommonslang.ApacheCommonsLangUtil; +import org.spongepowered.api.command.CommandCallable; +import org.spongepowered.api.command.CommandException; +import org.spongepowered.api.command.CommandMapping; +import org.spongepowered.api.command.CommandResult; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.text.Text; +import org.spongepowered.api.world.Location; +import org.spongepowered.api.world.World; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import javax.annotation.Nullable; + +public class SpongeRootCommand implements CommandCallable, RootCommand { + + private final SpongeCommandManager manager; + final String name; + private BaseCommand defCommand; + private Map subCommands = new HashMap<>(); + private List children = new ArrayList<>(); + boolean isRegistered = false; + + SpongeRootCommand(SpongeCommandManager manager, String name) { + this.manager = manager; + this.name = name; + } + + @Override + public CommandResult process(CommandSource source, String arguments) throws CommandException { + if(this.execute(new SpongeCommandIssuer(source), this.name, arguments.split(" "))) { + return CommandResult.success(); + } + return CommandResult.empty(); + } + + @Override + public List getSuggestions(CommandSource source, String arguments, @Nullable Location location) throws CommandException { + return tabComplete(new SpongeCommandIssuer(source), this.name, arguments.split(" ")); + } + + @Override + public boolean testPermission(CommandSource source) { + return true; + } + + @Override + public Optional getShortDescription(CommandSource source) { + return Optional.empty(); + } + + @Override + public Optional getHelp(CommandSource source) { + return Optional.empty(); + } + + @Override + public Text getUsage(CommandSource source) { + return Text.of(); + } + + private List tabComplete(CommandIssuer sender, String alias, String[] args) throws IllegalArgumentException { + Set completions = new HashSet<>(); + this.children.forEach(child -> completions.addAll(child.tabComplete(sender, alias, args))); + return new ArrayList<>(completions); + } + + private boolean execute(CommandIssuer sender, String commandLabel, String[] args) { + 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) { + if (!subHandler.testPermission(sender)) { + return true; + } + subHandler.execute(sender, commandLabel, args); + return false; + } + } + if (!this.defCommand.testPermission(sender)) { + return true; + } + + this.defCommand.execute(sender, commandLabel, args); + return false; + } + + public void addChild(BaseCommand command) { + if (this.defCommand == null || !command.subCommands.get("__default").isEmpty()) { + this.defCommand = command; + //this.setDescription(command.getDescription()); + //this.setUsage(command.getUsage()); + //this.setAliases(command.getAliases()); + } + command.subCommands.keySet().forEach(key -> { + if (key.equals(BaseCommand.DEFAULT) || key.equals(BaseCommand.UNKNOWN)) { + return; + } + BaseCommand regged = this.subCommands.get(key); + if (regged != null) { + ACFLog.severe("ACF Error: " + command.getName() + " registered subcommand " + key + " for root command " + this.name + " - but it is already defined in " + regged.getName()); + ACFLog.severe("2 subcommands of the same prefix may not be spread over 2 different classes. Ignoring this."); + return; + } + this.subCommands.put(key, command); + }); + this.children.add(command); + } + + @Override + public CommandManager getManager() { + return manager; + } +}