diff --git a/bungee/acf-bungee.iml b/bungee/acf-bungee.iml
new file mode 100644
index 00000000..892a370e
--- /dev/null
+++ b/bungee/acf-bungee.iml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bungee/pom.xml b/bungee/pom.xml
new file mode 100644
index 00000000..c6ef3c6f
--- /dev/null
+++ b/bungee/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+ acf-parent
+ co.aikar
+ 0.5.0-SNAPSHOT
+
+ 4.0.0
+
+ acf-bungee
+ 0.5.0-SNAPSHOT
+
+ ACF (Bungee)
+
+
+
+ BungeeCord-repo
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+
+
+
+
+ co.aikar
+ acf-core
+ 0.5.0-SNAPSHOT
+ compile
+
+
+ net.md-5
+ BungeeCord-api
+ 1.11-SNAPSHOT
+
+
+
+
\ No newline at end of file
diff --git a/bungee/src/main/java/co/aikar/commands/ACFBungeeUtil.java b/bungee/src/main/java/co/aikar/commands/ACFBungeeUtil.java
new file mode 100644
index 00000000..55e8948b
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/ACFBungeeUtil.java
@@ -0,0 +1,144 @@
+/*
+ * 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 net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.CommandSender;
+import net.md_5.bungee.api.ProxyServer;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class ACFBungeeUtil {
+
+ public static String color(String message) {
+ return ChatColor.translateAlternateColorCodes('&', message);
+ }
+
+ public static void sendMsg(CommandSender player, String message) {
+ message = color(message);
+ for (String msg : ACFPatterns.NEWLINE.split(message)) {
+ player.sendMessage(msg);
+ }
+ }
+
+ public static String removeColors(String msg) {
+ return ChatColor.stripColor(color(msg));
+ }
+
+ public static String replaceChatString(String message, String replace, String with) {
+ return replaceChatString(message, Pattern.compile(Pattern.quote(replace), Pattern.CASE_INSENSITIVE), with);
+ }
+
+ public static String replaceChatString(String message, Pattern replace, String with) {
+ final String[] split = replace.split(message + "1");
+
+ if (split.length < 2) {
+ return replace.matcher(message).replaceAll(with);
+ }
+ message = split[0];
+
+ for (int i = 1; i < split.length; i++) {
+ final String prev = getLastColors(message);
+ message += with + prev + split[i];
+ }
+ return message.substring(0, message.length() - 1);
+ }
+
+ //Imported from org.bukkit.ChatColor
+
+ public static final char COLOR_CHAR = '\u00A7';
+
+ public static String getLastColors(String input) {
+ String result = "";
+ int length = input.length();
+
+ // Search backwards from the end as it is faster
+ for (int index = length - 1; index > -1; index--) {
+ char section = input.charAt(index);
+ if (section == COLOR_CHAR && index < length - 1) {
+ char c = input.charAt(index + 1);
+ ChatColor color = ChatColor.getByChar(c);
+
+ if (color != null) {
+ result = color.toString() + result;
+
+ // Once we find a color or reset we can stop searching
+ if (isChatColorAColor(color) || color.equals(ChatColor.RESET)) {
+ break;
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public static boolean isChatColorAColor(ChatColor chatColor) {
+ return chatColor != ChatColor.MAGIC && chatColor != ChatColor.BOLD
+ && chatColor != ChatColor.STRIKETHROUGH && chatColor != ChatColor.UNDERLINE
+ && chatColor != ChatColor.ITALIC;
+ }
+
+
+ public static ProxiedPlayer findPlayerSmart(CommandSender requester, String origName) {
+ String name = ACFUtil.replace(origName, ":confirm", "");
+ if (name.length() < 3) {
+ requester.sendMessage("§cUsername too short, must be at least three characters");
+ return null;
+ }
+ if (!isValidName(name)) {
+ requester.sendMessage("§c'" + name + "' is not a valid username");
+ return null;
+ }
+
+ List matches = new ArrayList<>(ProxyServer.getInstance().matchPlayer(name));
+
+ if (matches.size() > 1) {
+ requester.sendMessage("§cMultiple players matched '" + name + "', please be more specific");
+ return null;
+ }
+
+ if (matches.isEmpty()) {
+ requester.sendMessage("§cNo player matching '" + name + "' is connected to this server");
+ return null;
+ }
+
+ return matches.get(0);
+ }
+
+ public static boolean isValidName(String name) {
+ return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches();
+ }
+
+ public static T validate(T object, String message, Object... values) {
+ if (object == null) {
+ throw new NullPointerException(String.format(message, values));
+ }
+ return object;
+ }
+
+
+}
diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletionContext.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletionContext.java
new file mode 100644
index 00000000..02f8661c
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletionContext.java
@@ -0,0 +1,37 @@
+/*
+ * 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 net.md_5.bungee.api.CommandSender;
+
+public class BungeeCommandCompletionContext extends CommandCompletionContext {
+
+ BungeeCommandCompletionContext(RegisteredCommand command, CommandIssuer issuer, String input, String config, String[] args) {
+ super(command, issuer, input, config, args);
+ }
+
+ public CommandSender getSender() {
+ return this.getIssuer().getIssuer();
+ }
+}
diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletions.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletions.java
new file mode 100644
index 00000000..7a53196c
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandCompletions.java
@@ -0,0 +1,72 @@
+/*
+ * 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 net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.CommandSender;
+import net.md_5.bungee.api.ProxyServer;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class BungeeCommandCompletions extends CommandCompletions {
+
+ public BungeeCommandCompletions(CommandManager manager) {
+ super(manager);
+ registerCompletion("chatcolors", (sender, config, input, c) -> {
+ Stream colors = Stream.of(ChatColor.values());
+ if (c.hasConfig("colorsonly")) {
+ colors = colors.filter(color -> color.ordinal() <= 0xF);
+ }
+ String filter = c.getConfig("filter");
+ if (filter != null) {
+ Set filters = Arrays.stream(ACFPatterns.COLON.split(filter))
+ .map(ACFUtil::simplifyString).collect(Collectors.toSet());
+
+ colors = colors.filter(color -> filters.contains(ACFUtil.simplifyString(color.name())));
+ }
+
+ return colors.map(color -> ACFUtil.simplifyString(color.name())).collect(Collectors.toList());
+ });
+ registerCompletion("players", (sender, config, input, c) -> {
+ ACFBungeeUtil.validate(sender, "Sender cannot be null");
+
+ ArrayList matchedPlayers = new ArrayList<>();
+ for (ProxiedPlayer player : ProxyServer.getInstance().getPlayers()) {
+ String name = player.getName();
+ if (ApacheCommonsLangUtil.startsWithIgnoreCase(name, input)) {
+ matchedPlayers.add(name);
+ }
+ }
+
+ matchedPlayers.sort(String.CASE_INSENSITIVE_ORDER);
+ return matchedPlayers;
+ });
+ }
+}
diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandContexts.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandContexts.java
new file mode 100644
index 00000000..cb9a0924
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandContexts.java
@@ -0,0 +1,84 @@
+/*
+ * 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.annotation.Optional;
+import co.aikar.commands.contexts.OnlineProxiedPlayer;
+import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.CommandSender;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class BungeeCommandContexts extends CommandContexts {
+
+ BungeeCommandContexts(CommandManager manager) {
+ super(manager);
+ registerContext(OnlineProxiedPlayer.class, (c) -> {
+ final String playercheck = c.popFirstArg();
+ ProxiedPlayer proxiedPlayer = ACFBungeeUtil.findPlayerSmart(c.getSender(), playercheck);
+ if (proxiedPlayer == null) {
+ if (c.hasAnnotation(Optional.class)) {
+ return null;
+ }
+ ACFBungeeUtil.sendMsg(c.getSender(), "§cCould not find a player by the name " + playercheck);
+ throw new InvalidCommandArgument(false);
+ }
+ return new OnlineProxiedPlayer(proxiedPlayer);
+ });
+ registerSenderAwareContext(CommandSender.class, BungeeCommandExecutionContext::getSender);
+ registerSenderAwareContext(ProxiedPlayer.class, (c) -> {
+ ProxiedPlayer proxiedPlayer = c.getSender() instanceof ProxiedPlayer ? (ProxiedPlayer) c.getSender() : null;
+ if (proxiedPlayer == null && !c.hasAnnotation(Optional.class)) {
+ throw new InvalidCommandArgument("Requires a player to run this command", false);
+ }
+ return proxiedPlayer;
+ });
+ registerContext(ChatColor.class, c -> {
+ String first = c.popFirstArg();
+ Stream colors = Stream.of(ChatColor.values());
+ if (c.hasFlag("colorsonly")) {
+ colors = colors.filter(color -> color.ordinal() <= 0xF);
+ }
+ String filter = c.getFlagValue("filter", (String) null);
+ if (filter != null) {
+ filter = ACFUtil.simplifyString(filter);
+ String finalFilter = filter;
+ colors = colors.filter(color -> finalFilter.equals(ACFUtil.simplifyString(color.name())));
+ }
+
+ ChatColor match = ACFUtil.simpleMatch(ChatColor.class, first);
+ if (match == null) {
+ String valid = colors
+ .map(color -> ChatColor.YELLOW + ACFUtil.simplifyString(color.name()))
+ .collect(Collectors.joining("&c, "));
+
+ throw new InvalidCommandArgument("Please specify one of: " + valid);
+ }
+ return match;
+ });
+ }
+}
diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java
new file mode 100644
index 00000000..e8439177
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandExecutionContext.java
@@ -0,0 +1,41 @@
+/*
+ * 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 net.md_5.bungee.api.CommandSender;
+
+import java.lang.reflect.Parameter;
+import java.util.List;
+import java.util.Map;
+
+public class BungeeCommandExecutionContext extends CommandExecutionContext {
+
+ BungeeCommandExecutionContext(RegisteredCommand cmd, Parameter param, CommandIssuer sender, List args, int index, Map passedArgs) {
+ super(cmd, param, sender, args, index, passedArgs);
+ }
+
+ public CommandSender getSender() {
+ return this.issuer.getIssuer();
+ }
+}
diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandIssuer.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandIssuer.java
new file mode 100644
index 00000000..4d9dcb8d
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandIssuer.java
@@ -0,0 +1,57 @@
+/*
+ * 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 net.md_5.bungee.api.CommandSender;
+import net.md_5.bungee.api.chat.TextComponent;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+
+public class BungeeCommandIssuer implements CommandIssuer{
+ private final CommandSender sender;
+
+ BungeeCommandIssuer(CommandSender sender) {
+ this.sender = sender;
+ }
+
+
+ @Override
+ public T getIssuer() {
+ return (T) sender;
+ }
+
+ @Override
+ public boolean isPlayer() {
+ return sender instanceof ProxiedPlayer;
+ }
+
+ @Override
+ public void sendMessage(String message) {
+ sender.sendMessage(new TextComponent(ACFBungeeUtil.color(message)));
+ }
+
+ @Override
+ public boolean hasPermission(String name) {
+ return sender.hasPermission(name);
+ }
+}
diff --git a/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java b/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java
new file mode 100644
index 00000000..4c28e683
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/BungeeCommandManager.java
@@ -0,0 +1,147 @@
+/*
+ * 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.ApacheCommonsExceptionUtil;
+import net.md_5.bungee.api.CommandSender;
+import net.md_5.bungee.api.plugin.Command;
+import net.md_5.bungee.api.plugin.Plugin;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
+public class BungeeCommandManager extends CommandManager {
+
+ protected final Plugin plugin;
+ protected Map knownCommands = new HashMap<>();
+ protected Map registeredCommands = new HashMap<>();
+ protected BungeeCommandContexts contexts;
+ protected BungeeCommandCompletions completions;
+
+ public BungeeCommandManager(Plugin plugin) {
+ this.plugin = plugin;
+ }
+
+ public Plugin getPlugin() {
+ return this.plugin;
+ }
+
+ @Override
+ public synchronized CommandContexts getCommandContexts() {
+ if (this.contexts == null) {
+ this.contexts = new BungeeCommandContexts(this);
+ }
+ return contexts;
+ }
+
+ @Override
+ public synchronized CommandCompletions getCommandCompletions() {
+ if (this.completions == null) {
+ this.completions = new BungeeCommandCompletions(this);
+ }
+ return completions;
+ }
+
+ @Override
+ public void registerCommand(BaseCommand command) {
+ final String plugin = this.plugin.getDescription().getName().toLowerCase();
+ command.onRegister(this);
+ for (Map.Entry entry : command.registeredCommands.entrySet()) {
+ String key = entry.getKey().toLowerCase();
+ BungeeRootCommand value = (BungeeRootCommand) entry.getValue();
+ if (!value.isRegistered) {
+ this.plugin.getProxy().getPluginManager().registerCommand(this.plugin, value);
+ }
+ value.isRegistered = true;
+ registeredCommands.put(key, value);
+ }
+ }
+
+ @Override
+ public boolean hasRegisteredCommands() {
+ return !registeredCommands.isEmpty();
+ }
+
+ @Override
+ public boolean isCommandIssuer(Class> aClass) {
+ return CommandSender.class.isAssignableFrom(aClass);
+ }
+
+ @Override
+ public CommandIssuer getCommandIssuer(Object issuer) {
+ if (!(issuer instanceof CommandSender)) {
+ throw new IllegalArgumentException(issuer.getClass().getName() + " is not a Command Issuer.");
+ }
+ return new BungeeCommandIssuer((CommandSender) issuer);
+ }
+
+ @Override
+ public RootCommand createRootCommand(String cmd) {
+ return new BungeeRootCommand(this, cmd);
+ }
+
+ @Override
+ public R createCommandContext(RegisteredCommand command, Parameter parameter, CommandIssuer sender, List args, int i, Map passedArgs) {
+ return (R) new BungeeCommandExecutionContext(command, parameter, sender, args, i, passedArgs);
+ }
+
+ @Override
+ public CommandCompletionContext createCompletionContext(RegisteredCommand command, CommandIssuer sender, String input, String config, String[] args) {
+ return new BungeeCommandCompletionContext(command, sender, input, config, args);
+ }
+
+ @Override
+ public RegisteredCommand createRegisteredCommand(BaseCommand command, String cmdName, Method method, String prefSubCommand) {
+ return new RegisteredCommand(command, cmdName, method, prefSubCommand);
+ }
+
+ @Override
+ public void log(LogLevel level, String message) {
+ switch(level) {
+ case INFO:
+ this.plugin.getLogger().info(LogLevel.LOG_PREFIX + message);
+ return;
+ case ERROR:
+ this.plugin.getLogger().severe(LogLevel.LOG_PREFIX + message);
+ }
+ }
+
+ @Override
+ public void log(LogLevel level, String message, Throwable throwable) {
+ switch(level) {
+ case INFO:
+ this.plugin.getLogger().log(Level.INFO, LogLevel.LOG_PREFIX + message, throwable);
+ return;
+ case ERROR:
+ this.plugin.getLogger().log(Level.SEVERE, LogLevel.LOG_PREFIX + message);
+ for(String line : ACFPatterns.NEWLINE.split(ApacheCommonsExceptionUtil.getFullStackTrace(throwable))) {
+ this.plugin.getLogger().severe(LogLevel.LOG_PREFIX + line);
+ }
+ }
+ }
+}
diff --git a/bungee/src/main/java/co/aikar/commands/BungeeRegisteredCommand.java b/bungee/src/main/java/co/aikar/commands/BungeeRegisteredCommand.java
new file mode 100644
index 00000000..4693ab17
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/BungeeRegisteredCommand.java
@@ -0,0 +1,43 @@
+/*
+ * 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 java.lang.reflect.Method;
+
+public class BungeeRegisteredCommand extends RegisteredCommand {
+
+ BungeeRegisteredCommand(BaseCommand scope, String command, Method method, String prefSubCommand) {
+ super(scope, command, method, prefSubCommand);
+ }
+
+ @Override
+ public void preCommand() {
+ super.preCommand();
+ }
+
+ @Override
+ public void postCommand() {
+ super.postCommand();
+ }
+}
diff --git a/bungee/src/main/java/co/aikar/commands/BungeeRootCommand.java b/bungee/src/main/java/co/aikar/commands/BungeeRootCommand.java
new file mode 100644
index 00000000..c5760894
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/BungeeRootCommand.java
@@ -0,0 +1,106 @@
+/*
+ * 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 net.md_5.bungee.api.CommandSender;
+import net.md_5.bungee.api.plugin.Command;
+import net.md_5.bungee.api.plugin.TabExecutor;
+
+import java.util.*;
+
+public class BungeeRootCommand extends Command implements RootCommand, TabExecutor {
+
+ private final BungeeCommandManager manager;
+ private final String name;
+ private BaseCommand defCommand;
+ private Map subCommands = new HashMap<>();
+ private List children = new ArrayList<>();
+ private String permission;
+ boolean isRegistered = false;
+
+ BungeeRootCommand(BungeeCommandManager manager, String name) {
+ super(name);
+ this.manager = manager;
+ this.name = name;
+ }
+
+ @Override
+ public void addChild(BaseCommand command) {
+ if (this.defCommand == null || !command.subCommands.get("__default").isEmpty()) {
+ this.defCommand = command;
+ this.permission = command.permission;
+ //this.setPermissionMessage(command.permissionMessage);
+ //this.setDescription(command.getDescription());
+ //this.setUsage(command.getUsage());
+ }
+ command.subCommands.keySet().forEach(key -> {
+ if (key.equals(BaseCommand.DEFAULT) || key.equals(BaseCommand.UNKNOWN)) {
+ return;
+ }
+ BaseCommand regged = this.subCommands.get(key);
+ if (regged != null) {
+ this.manager.log(LogLevel.ERROR, "ACF Error: " + command.getName() + " registered subcommand " + key + " for root command " + getName() + " - but it is already defined in " + regged.getName());
+ this.manager.log(LogLevel.ERROR, "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;
+ }
+
+ @Override
+ public void execute(CommandSender sender, String[] args) {
+ execute(new BungeeCommandIssuer(sender), getName(), args);
+ }
+
+ private void 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) {
+ subHandler.execute(sender, commandLabel, args);
+ return;
+ }
+ }
+
+ this.defCommand.execute(sender, commandLabel, args);
+ }
+
+ @Override
+ public Iterable onTabComplete(CommandSender commandSender, String[] strings) {
+ return onTabComplete(new BungeeCommandIssuer(commandSender), getName(), strings);
+ }
+
+ private List onTabComplete(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);
+ }
+}
diff --git a/bungee/src/main/java/co/aikar/commands/contexts/OnlineProxiedPlayer.java b/bungee/src/main/java/co/aikar/commands/contexts/OnlineProxiedPlayer.java
new file mode 100644
index 00000000..258b8ea9
--- /dev/null
+++ b/bungee/src/main/java/co/aikar/commands/contexts/OnlineProxiedPlayer.java
@@ -0,0 +1,61 @@
+/*
+ * 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.contexts;
+
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+
+import java.util.Objects;
+
+public class OnlineProxiedPlayer {
+
+ public final ProxiedPlayer player;
+
+ public OnlineProxiedPlayer(ProxiedPlayer player) {
+ this.player = player;
+ }
+
+ public ProxiedPlayer getPlayer(){
+ return player;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ OnlineProxiedPlayer that = (OnlineProxiedPlayer) o;
+ return Objects.equals(player, that.player);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(player);
+ }
+
+ @Override
+ public String toString() {
+ return "OnlineProxiedPlayer{" +
+ "proxiedPlayer=" + player +
+ '}';
+ }
+}
diff --git a/pom.xml b/pom.xml
index e84ee9af..2127295d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -99,7 +99,7 @@
core
bukkit
paper
-
+ bungee
sponge