diff --git a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java index 934d1dd71..9d1569ec9 100644 --- a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java +++ b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java @@ -5,6 +5,7 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; +import lombok.Getter; import lombok.NonNull; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -15,10 +16,11 @@ import us.myles.ViaVersion.api.ViaVersionConfig; import us.myles.ViaVersion.api.boss.BossBar; import us.myles.ViaVersion.api.boss.BossColor; import us.myles.ViaVersion.api.boss.BossStyle; +import us.myles.ViaVersion.api.command.ViaVersionCommand; import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.protocol.ProtocolRegistry; import us.myles.ViaVersion.boss.ViaBossBar; -import us.myles.ViaVersion.commands.ViaVersionCommand; +import us.myles.ViaVersion.commands.ViaCommandHandler; import us.myles.ViaVersion.handlers.ViaVersionInitializer; import us.myles.ViaVersion.protocols.base.ProtocolInfo; import us.myles.ViaVersion.update.UpdateListener; @@ -41,6 +43,7 @@ import java.util.concurrent.TimeUnit; public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVersionConfig { private final Map portedPlayers = new ConcurrentHashMap<>(); + private ViaCommandHandler commandHandler; private boolean debug = false; @Override @@ -77,7 +80,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe Bukkit.getPluginManager().registerEvents(new UpdateListener(this), this); - getCommand("viaversion").setExecutor(new ViaVersionCommand(this)); + getCommand("viaversion").setExecutor(commandHandler = new ViaCommandHandler()); } public void gatherProtocolVersion() { @@ -283,6 +286,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe return this.debug; } + @Override + public ViaVersionCommand getCommandHandler() { + return commandHandler; + } + public void setDebug(boolean value) { this.debug = value; } diff --git a/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java b/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java index 89d84144e..5f69cf8ee 100644 --- a/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java +++ b/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java @@ -5,6 +5,7 @@ import org.bukkit.entity.Player; import us.myles.ViaVersion.api.boss.BossBar; import us.myles.ViaVersion.api.boss.BossColor; import us.myles.ViaVersion.api.boss.BossStyle; +import us.myles.ViaVersion.api.command.ViaVersionCommand; import java.util.UUID; @@ -93,4 +94,11 @@ public interface ViaVersionAPI { * @return true if debug is enabled */ boolean isDebug(); + + /** + * Get ViaVersions command handler + * + * @return command handler + */ + ViaVersionCommand getCommandHandler(); } diff --git a/src/main/java/us/myles/ViaVersion/api/command/ViaSubCommand.java b/src/main/java/us/myles/ViaVersion/api/command/ViaSubCommand.java new file mode 100644 index 000000000..3d95deb03 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/api/command/ViaSubCommand.java @@ -0,0 +1,52 @@ +package us.myles.ViaVersion.api.command; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import us.myles.ViaVersion.commands.ViaCommandHandler; + +public abstract class ViaSubCommand { + /** + * Subcommand name + * + * @return your input + */ + public abstract String name(); + + /** + * subcommand description, this'll show in /viaversion list + * + * @return your input + */ + public abstract String description(); + + /** + * Usage example: + * "playerversion [name]" + * + * @return your input + */ + public String usage(){ + return name(); + } + + /** + * Permission, null for everyone + * @return + */ + public String permission(){ + return "viaversion.admin"; + } + + /** + * Gets triggered on execution + * + * @param sender Command sender + * @param args Arguments + * @return command executed succesfully if false, show usage + */ + public abstract boolean execute(CommandSender sender, String[] args); + + public String color(String s){ + return ViaCommandHandler.color(s); + } +} diff --git a/src/main/java/us/myles/ViaVersion/api/command/ViaVersionCommand.java b/src/main/java/us/myles/ViaVersion/api/command/ViaVersionCommand.java new file mode 100644 index 000000000..707cac6b7 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/api/command/ViaVersionCommand.java @@ -0,0 +1,27 @@ +package us.myles.ViaVersion.api.command; + +public interface ViaVersionCommand { + /** + * Register your own subcommand inside ViaVersion + * + * @param command Your own SubCommand instance to handle it. + * @throws Exception throws an exception when the subcommand already exists or if it's not valid, example: spacee + */ + void registerSubCommand(ViaSubCommand command) throws Exception; + + /** + * Check if a subcommand is registered. + * + * @param name Subcommand name + * @return true if it exists + */ + boolean hasSubCommand(String name); + + /** + * Get subcommand instance by name + * + * @param name subcommand name + * @return ViaSubCommand instance + */ + ViaSubCommand getSubCommand(String name); +} diff --git a/src/main/java/us/myles/ViaVersion/commands/ViaCommandHandler.java b/src/main/java/us/myles/ViaVersion/commands/ViaCommandHandler.java new file mode 100644 index 000000000..f7f15995d --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/commands/ViaCommandHandler.java @@ -0,0 +1,113 @@ +package us.myles.ViaVersion.commands; + +import lombok.NonNull; +import org.apache.commons.lang.Validate; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import us.myles.ViaVersion.api.ViaVersion; +import us.myles.ViaVersion.api.command.ViaSubCommand; +import us.myles.ViaVersion.api.command.ViaVersionCommand; +import us.myles.ViaVersion.commands.defaultsubs.*; + +import java.util.*; + +public class ViaCommandHandler implements ViaVersionCommand, CommandExecutor { + private Map commandMap; + + public ViaCommandHandler() { + commandMap = new HashMap<>(); + try { + registerDefaults(); + } catch (Exception e) { + //ignore never throws exception because it doesn't exists + } + } + + @Override + public void registerSubCommand(@NonNull ViaSubCommand command) throws Exception { + Validate.isTrue(command.name().matches("^[a-z0-9_-]{3,15}$"), command.name() + " is not a valid subcommand name"); + if (hasSubCommand(command.name())) + throw new Exception("ViaSubCommand " + command.name() + " does already exists!"); //Maybe another exception later. + commandMap.put(command.name().toLowerCase(), command); + } + + @Override + public boolean hasSubCommand(String name) { + return commandMap.containsKey(name.toLowerCase()); + } + + @Override + public ViaSubCommand getSubCommand(String name) { + return commandMap.get(name.toLowerCase()); + } + + @Override + public boolean onCommand(CommandSender sender, Command cmd, String arg, String[] args) { + if (args.length == 0) { + showHelp(sender); + return false; + } + + if (!hasSubCommand(args[0])){ + sender.sendMessage(color("&cThis command is not found")); + showHelp(sender); + return false; + } + ViaSubCommand handler = getSubCommand(args[0]); + + if (!hasPermission(sender, handler.permission())){ + sender.sendMessage(color("&cYou are not allowed to use this command!")); + return false; + } + + String[] subArgs = Arrays.copyOfRange(args, 1, args.length); + boolean result = handler.execute(sender, subArgs); + if (!result) + sender.sendMessage("Usage: /viaversion " + handler.usage()); + return result; + } + + public void showHelp(CommandSender sender) { + Set allowed = calculateAllowedCommands(sender); + if (allowed.size() == 0){ + sender.sendMessage(color("&cYou are not allowed to use this command!")); + return; + } + sender.sendMessage(color("&aViaVersion &c" + ViaVersion.getInstance().getVersion())); + sender.sendMessage(color("&6Commands:")); + for (ViaSubCommand cmd : allowed) + sender.sendMessage(color(String.format("&2/viaversion %s &7- &6%s", cmd.usage(), cmd.description()))); + allowed.clear(); + } + + private Set calculateAllowedCommands(CommandSender sender) { + Set cmds = new HashSet<>(); + for (ViaSubCommand sub : commandMap.values()) + if (hasPermission(sender, sub.permission())) + cmds.add(sub); + return cmds; + } + + private boolean hasPermission(CommandSender sender, String permission){ + return permission == null || sender.hasPermission(permission); + } + + + public static String color(String string) { + try { + string = ChatColor.translateAlternateColorCodes('&', string); //Dont replace all & with $ like we did before. + } catch (Exception ignored) { + } + return string; + } + + private void registerDefaults() throws Exception { + registerSubCommand(new ListSubCmd()); + registerSubCommand(new DebugSubCmd()); + registerSubCommand(new DisplayLeaksSubCmd()); + registerSubCommand(new DontBugMeSubCmd()); + registerSubCommand(new AutoTeamSubCmd()); + } +} diff --git a/src/main/java/us/myles/ViaVersion/commands/ViaVersionCommand.java b/src/main/java/us/myles/ViaVersion/commands/ViaVersionCommand.java deleted file mode 100644 index 791f5fb53..000000000 --- a/src/main/java/us/myles/ViaVersion/commands/ViaVersionCommand.java +++ /dev/null @@ -1,82 +0,0 @@ -package us.myles.ViaVersion.commands; - -import io.netty.util.ResourceLeakDetector; -import lombok.RequiredArgsConstructor; -import org.bukkit.Bukkit; -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import us.myles.ViaVersion.ViaVersionPlugin; -import us.myles.ViaVersion.api.ViaVersion; - -import java.util.ArrayList; -import java.util.List; - -@RequiredArgsConstructor -public class ViaVersionCommand implements CommandExecutor { - - private final ViaVersionPlugin plugin; - - @Override - public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) { - if (sender.hasPermission("viaversion.admin")) { - if (args.length == 0) { - sendHelp(sender); - } else if (args.length == 1) { - if (args[0].equalsIgnoreCase("list")) { - List portedPlayers = new ArrayList<>(); - List normalPlayers = new ArrayList<>(); - for (Player p : Bukkit.getOnlinePlayers()) { - if (ViaVersion.getInstance().isPorted(p)) { - portedPlayers.add(p.getName()); - } else { - normalPlayers.add(p.getName()); - } - } - - sender.sendMessage(color("&8[&61.9&8]: &b" + portedPlayers.toString())); - sender.sendMessage(color("&8[&61.8&8]: &b" + normalPlayers.toString())); - } else if (args[0].equalsIgnoreCase("debug")) { - plugin.setDebug(!plugin.isDebug()); - sender.sendMessage(color("&6Debug mode is now " + (plugin.isDebug() ? "&aenabled" : "&cdisabled"))); - } else if (args[0].equalsIgnoreCase("displayleaks")) { - if (ResourceLeakDetector.getLevel() != ResourceLeakDetector.Level.ADVANCED) { - ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); - } else { - ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED); - } - sender.sendMessage(color("&6Leak detector is now " + (ResourceLeakDetector.getLevel() == ResourceLeakDetector.Level.ADVANCED ? "&aenabled" : "&cdisabled"))); - } else if (args[0].equalsIgnoreCase("dontbugme")) { - boolean newValue = !plugin.isCheckForUpdates(); - plugin.getConfig().set("checkforupdates", newValue); - plugin.saveConfig(); - sender.sendMessage(color("&6We will " + (newValue ? "&anotify you about updates." : "&cnot tell you about updates."))); - } else if (args[0].equalsIgnoreCase("autoteam")) { - boolean newValue = !plugin.isAutoTeam(); - plugin.getConfig().set("auto-team", newValue); - plugin.saveConfig(); - sender.sendMessage(color("&6We will " + (newValue ? "&aautomatically team players" : "&cno longer auto team players"))); - sender.sendMessage(color("&6All players will need to re-login for the change to take place.")); - } else { - sendHelp(sender); - } - } - - } - return false; - } - - public void sendHelp(CommandSender sender) { - sender.sendMessage(color("&aViaVersion &c" + ViaVersion.getInstance().getVersion())); - sender.sendMessage(color("&6Commands:")); - sender.sendMessage(color("&2/viaversion list &7- &6Shows lists of all 1.9 clients and 1.8 clients.")); - sender.sendMessage(color("&2/viaversion debug &7- &6Toggle debug mode")); - sender.sendMessage(color("&2/viaversion autoteam &7- &6Toggle automatically teaming to prevent colliding.")); - sender.sendMessage(color("&2/viaversion dontbugme &7- &6Toggle checking for updates.")); - } - - public String color(String string) { - return string.replace("&", "ยง"); - } -} diff --git a/src/main/java/us/myles/ViaVersion/commands/defaultsubs/AutoTeamSubCmd.java b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/AutoTeamSubCmd.java new file mode 100644 index 000000000..86e673e9b --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/AutoTeamSubCmd.java @@ -0,0 +1,31 @@ +package us.myles.ViaVersion.commands.defaultsubs; + +import org.bukkit.command.CommandSender; +import us.myles.ViaVersion.ViaVersionPlugin; +import us.myles.ViaVersion.api.ViaVersion; +import us.myles.ViaVersion.api.command.ViaSubCommand; + +public class AutoTeamSubCmd extends ViaSubCommand { + @Override + public String name() { + return "autoteam"; + } + + @Override + public String description() { + return "Toggle automatically teaming to prevent colliding."; + } + + @Override + public boolean execute(CommandSender sender, String[] args) { + ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance(); + + boolean newValue = !plugin.isAutoTeam(); + plugin.getConfig().set("auto-team", newValue); + plugin.saveConfig(); + sender.sendMessage(color("&6We will " + (newValue ? "&aautomatically team players" : "&cno longer auto team players"))); + sender.sendMessage(color("&6All players will need to re-login for the change to take place.")); + + return true; + } +} diff --git a/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DebugSubCmd.java b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DebugSubCmd.java new file mode 100644 index 000000000..ba1b2b272 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DebugSubCmd.java @@ -0,0 +1,27 @@ +package us.myles.ViaVersion.commands.defaultsubs; + +import org.bukkit.command.CommandSender; +import us.myles.ViaVersion.ViaVersionPlugin; +import us.myles.ViaVersion.api.ViaVersion; +import us.myles.ViaVersion.api.command.ViaSubCommand; + +public class DebugSubCmd extends ViaSubCommand { + @Override + public String name() { + return "debug"; + } + + @Override + public String description() { + return "Toggle debug mode"; + } + + @Override + public boolean execute(CommandSender sender, String[] args) { + ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance(); + + plugin.setDebug(!plugin.isDebug()); + sender.sendMessage(color("&6Debug mode is now " + (plugin.isDebug() ? "&aenabled" : "&cdisabled"))); + return true; + } +} diff --git a/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DisplayLeaksSubCmd.java b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DisplayLeaksSubCmd.java new file mode 100644 index 000000000..f230cb2c2 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DisplayLeaksSubCmd.java @@ -0,0 +1,28 @@ +package us.myles.ViaVersion.commands.defaultsubs; + +import io.netty.util.ResourceLeakDetector; +import org.bukkit.command.CommandSender; +import us.myles.ViaVersion.api.command.ViaSubCommand; + +public class DisplayLeaksSubCmd extends ViaSubCommand { + @Override + public String name() { + return "displayleaks"; + } + + @Override + public String description() { + return "Try to hunt memory leaks!"; + } + + @Override + public boolean execute(CommandSender sender, String[] args) { + if (ResourceLeakDetector.getLevel() != ResourceLeakDetector.Level.ADVANCED) { + ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED); + } else { + ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED); + } + sender.sendMessage(color("&6Leak detector is now " + (ResourceLeakDetector.getLevel() == ResourceLeakDetector.Level.ADVANCED ? "&aenabled" : "&cdisabled"))); + return true; + } +} diff --git a/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DontBugMeSubCmd.java b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DontBugMeSubCmd.java new file mode 100644 index 000000000..0ca7033a4 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/DontBugMeSubCmd.java @@ -0,0 +1,30 @@ +package us.myles.ViaVersion.commands.defaultsubs; + +import org.bukkit.command.CommandSender; +import us.myles.ViaVersion.ViaVersionPlugin; +import us.myles.ViaVersion.api.ViaVersion; +import us.myles.ViaVersion.api.command.ViaSubCommand; + +public class DontBugMeSubCmd extends ViaSubCommand { + @Override + public String name() { + return "dontbugme"; + } + + @Override + public String description() { + return "Toggle checking for updates"; + } + + @Override + public boolean execute(CommandSender sender, String[] args) { + ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance(); + + boolean newValue = !plugin.isCheckForUpdates(); + plugin.getConfig().set("checkforupdates", newValue); + plugin.saveConfig(); + sender.sendMessage(color("&6We will " + (newValue ? "&anotify you about updates." : "&cnot tell you about updates."))); + + return true; + } +} diff --git a/src/main/java/us/myles/ViaVersion/commands/defaultsubs/ListSubCmd.java b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/ListSubCmd.java new file mode 100644 index 000000000..af5605b57 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/commands/defaultsubs/ListSubCmd.java @@ -0,0 +1,46 @@ +package us.myles.ViaVersion.commands.defaultsubs; + +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import us.myles.ViaVersion.api.ViaVersion; +import us.myles.ViaVersion.api.command.ViaSubCommand; + +import java.util.*; + +public class ListSubCmd extends ViaSubCommand { + @Override + public String name() { + return "list"; + } + + @Override + public String description() { + return "Shows lists of the versions from logged in players"; + } + + @Override + public String usage() { + return "list"; + } + + @Override + public boolean execute(CommandSender sender, String[] args) { + Map> playerVersions = new HashMap<>(); + for (Player p : Bukkit.getOnlinePlayers()) { + int playerVersion = ViaVersion.getInstance().getPlayerVersion(p); + if (playerVersions.containsKey(playerVersion)) { + playerVersions.get(playerVersion).add(p.getName()); + continue; + } + playerVersions.put(playerVersion, Collections.singleton(p.getName())); + } + Map> sorted = new TreeMap<>(playerVersions); + + for (Map.Entry> entry : sorted.entrySet()) + sender.sendMessage(String.format(color("&8[&6%s&8]: &b%s"), entry.getKey(), entry.getValue())); //TODO: Make versions like [1.8,1.9,1.9.1,1.9.2,etc] instead of protocol id + + sorted.clear(); + return true; + } +} diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 8d5cb9082..314f3d36e 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -7,5 +7,4 @@ loadbefore: [ProtocolLib, ProxyPipe] commands: viaversion: description: Shows ViaVersion Version and more. - permission: viaversion.admin aliases: [viaver] \ No newline at end of file