package net.ME1312.SubServers.Velocity; import net.ME1312.Galaxi.Library.AsyncConsolidator; import net.ME1312.Galaxi.Library.Container.ContainedPair; import net.ME1312.Galaxi.Library.Container.Container; import net.ME1312.Galaxi.Library.Container.Pair; import net.ME1312.Galaxi.Library.Container.Value; import net.ME1312.Galaxi.Library.Map.ObjectMap; import net.ME1312.Galaxi.Library.Platform; import net.ME1312.Galaxi.Library.Try; import net.ME1312.Galaxi.Library.Util; import net.ME1312.Galaxi.Library.Version.Version; import net.ME1312.SubData.Client.SubDataClient; import net.ME1312.SubData.Client.SubDataSender; import net.ME1312.SubServers.Client.Common.Network.API.*; import net.ME1312.SubServers.Client.Common.Network.Packet.PacketCreateServer; import net.ME1312.SubServers.Client.Common.Network.Packet.PacketUpdateServer; import net.ME1312.SubServers.Velocity.Library.Compatibility.ChatColor; import net.ME1312.SubServers.Velocity.Network.Packet.PacketCheckPermission; import net.ME1312.SubServers.Velocity.Network.Packet.PacketInExRunEvent; import net.ME1312.SubServers.Velocity.Server.CachedPlayer; import net.ME1312.SubServers.Velocity.Server.ServerData; import net.ME1312.SubServers.Velocity.Server.SubServerData; import com.google.gson.Gson; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.RawCommand; import com.velocitypowered.api.command.SimpleCommand; import com.velocitypowered.api.proxy.ConsoleCommandSource; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.ServerInfo; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import java.net.URL; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Supplier; @SuppressWarnings("deprecation") public final class SubCommand implements SimpleCommand { static final MinecraftChannelIdentifier pmc = MinecraftChannelIdentifier.create("subservers", "input"); static HashMap>> permitted = new HashMap>>(); private Map proxyCache = Collections.emptyMap(); private Map hostCache = Collections.emptyMap(); private Map> groupCache = Collections.emptyMap(); private Proxy proxyMasterCache = null; private long cacheDate = 0; private ExProxy plugin; SubCommand(ExProxy plugin) { this.plugin = plugin; } @SuppressWarnings("unchecked") @Override public void execute(Invocation invocation) { CommandSource sender = invocation.source(); String label = '/' + invocation.alias(); String[] args = invocation.arguments(); if (!(sender instanceof Player)) { if (plugin.api.getSubDataNetwork()[0] == null || plugin.api.getSubDataNetwork()[0].isClosed()) { new IllegalStateException("SubData is not connected").printStackTrace(); if (!(sender instanceof ConsoleCommandSource)) sender.sendMessage(Component.text("An exception has occurred while running this command", NamedTextColor.RED)); } else { if (args.length > 0) { if (args[0].equalsIgnoreCase("help") || args[0].equalsIgnoreCase("?")) { for (String s : printHelp()) sender.sendMessage(Component.text(s)); } else if (args[0].equalsIgnoreCase("version") || args[0].equalsIgnoreCase("ver")) { sender.sendMessage(Component.text("SubServers > These are the platforms and versions that are running SubServers.Sync:")); sender.sendMessage(Component.text(" " + Platform.getSystemName() + ' ' + Platform.getSystemVersion() + ((Platform.getSystemBuild() != null)?" (" + Platform.getSystemBuild() + ')':"") + ((!Platform.getSystemArchitecture().equals("unknown"))?" [" + Platform.getSystemArchitecture() + ']':"") + ',')); sender.sendMessage(Component.text(" Java " + Platform.getJavaVersion() + ((!Platform.getJavaArchitecture().equals("unknown"))?" [" + Platform.getJavaArchitecture() + ']':"") + ',')); sender.sendMessage(Component.text(" " + ExProxy.getInstance().getVersion().getName() + ' ' + ExProxy.getInstance().getVersion().getVersion() + ',')); sender.sendMessage(Component.text(" SubServers.Sync v" + plugin.version.toExtendedString() + ((plugin.api.getPluginBuild() != null)?" (" + plugin.api.getPluginBuild() + ')':""))); sender.sendMessage(Component.text("")); new Thread(() -> { try { ObjectMap tags = new ObjectMap(new Gson().fromJson("{\"tags\":" + Util.readAll(new BufferedReader(new InputStreamReader(new URL("https://api.github.com/repos/ME1312/SubServers-2/git/refs/tags").openStream(), Charset.forName("UTF-8")))) + '}', Map.class)); List versions = new LinkedList(); Version updversion = plugin.version; int updcount = 0; for (ObjectMap tag : tags.getMapList("tags")) versions.add(Version.fromString(tag.getString("ref").substring(10))); Collections.sort(versions); for (Version version : versions) { if (version.compareTo(updversion) > 0) { updversion = version; updcount++; } } if (updcount == 0) { sender.sendMessage(Component.text("You are on the latest version.")); } else { sender.sendMessage(Component.text("SubServers.Sync v" + updversion + " is available. You are " + updcount + " version" + ((updcount == 1)?"":"s") + " behind.")); } } catch (Exception e) { } }, "SubServers.Sync::Update_Check").start(); } else if (args[0].equalsIgnoreCase("list")) { plugin.api.getGroups(groups -> plugin.api.getHosts(hosts -> plugin.api.getServers(servers -> plugin.api.getMasterProxy(proxymaster -> plugin.api.getProxies(proxies -> { int i = 0; boolean sent = false; String div = ChatColor.RESET + ", "; if (groups.keySet().size() > 0) { sender.sendMessage(Component.text("Group/Server List:")); for (String group : groups.keySet()) { String message = " "; message += ChatColor.GOLD + group + ChatColor.RESET + ": "; for (Server server : groups.get(group)) { if (i != 0) message += div; if (!(server instanceof SubServer)) { message += ChatColor.WHITE; } else if (((SubServer) server).isRunning()) { if (((SubServer) server).getStopAction() == SubServer.StopAction.REMOVE_SERVER || ((SubServer) server).getStopAction() == SubServer.StopAction.RECYCLE_SERVER || ((SubServer) server).getStopAction() == SubServer.StopAction.DELETE_SERVER) { message += ChatColor.AQUA; } else { message += ChatColor.GREEN; } } else if (((SubServer) server).isAvailable() && ((SubServer) server).isEnabled() && ((SubServer) server).getCurrentIncompatibilities().size() == 0) { message += ChatColor.YELLOW; } else { message += ChatColor.RED; } message += server.getDisplayName() + ((server.getName().equals(server.getDisplayName()))?"":" ["+server.getName()+']'); i++; } if (i == 0) message += ChatColor.RESET + "(none)"; sender.sendMessage(ChatColor.convertColor(message)); i = 0; sent = true; } if (!sent) sender.sendMessage(Component.text("(none)")); sent = false; } sender.sendMessage(Component.text("Host/SubServer List:")); for (Host host : hosts.values()) { String message = " "; if (host.isAvailable() && host.isEnabled()) { message += ChatColor.AQUA; } else { message += ChatColor.RED; } message += host.getDisplayName() + " [" + ((host.getName().equals(host.getDisplayName()))?"":host.getName()+ChatColor.stripColor(div)) + host.getAddress().getHostAddress() + "]" + ChatColor.RESET + ": "; for (SubServer subserver : host.getSubServers().values()) { if (i != 0) message += div; if (subserver.isRunning()) { if (subserver.getStopAction() == SubServer.StopAction.REMOVE_SERVER || subserver.getStopAction() == SubServer.StopAction.RECYCLE_SERVER || subserver.getStopAction() == SubServer.StopAction.DELETE_SERVER) { message += ChatColor.AQUA; } else { message += ChatColor.GREEN; } } else if (subserver.isAvailable() && subserver.isEnabled() && subserver.getCurrentIncompatibilities().size() == 0) { message += ChatColor.YELLOW; } else { message += ChatColor.RED; } message += subserver.getDisplayName() + " [" + ((subserver.getName().equals(subserver.getDisplayName()))?"":subserver.getName()+ChatColor.stripColor(div)) + subserver.getAddress().getPort() + "]"; i++; } if (i == 0) message += ChatColor.RESET + "(none)"; sender.sendMessage(ChatColor.convertColor(message)); i = 0; sent = true; } if (!sent) sender.sendMessage(Component.text("(none)")); sender.sendMessage(Component.text("Server List:")); String message = " "; for (Server server : servers.values()) if (!(server instanceof SubServer)) { if (i != 0) message += div; message += ChatColor.WHITE + server.getDisplayName() + " [" + ((server.getName().equals(server.getDisplayName()))?"":server.getName()+ChatColor.stripColor(div)) + server.getAddress().getAddress().getHostAddress()+':'+server.getAddress().getPort() + "]"; i++; } if (i == 0) message += ChatColor.RESET + "(none)"; sender.sendMessage(ChatColor.convertColor(message)); if (proxies.keySet().size() > 0) { sender.sendMessage(Component.text("Proxy List:")); message = " (master)"; for (Proxy proxy : proxies.values()) { message += div; if (proxy.getSubData()[0] != null) { message += ChatColor.AQUA; } else { message += ChatColor.RED; } message += proxy.getDisplayName() + ((proxy.getName().equals(proxy.getDisplayName()))?"":" ["+proxy.getName()+']'); } sender.sendMessage(ChatColor.convertColor(message)); } }))))); } else if (args[0].equalsIgnoreCase("info") || args[0].equalsIgnoreCase("status")) { if (args.length > 1) { String type = (args.length > 2)?args[1]:null; String name = args[(type != null)?2:1]; Runnable getPlayer = () -> plugin.api.getRemotePlayer(name, player -> { if (player != null) { sender.sendMessage(ChatColor.convertColor("SubServers > Info on player: " + ChatColor.WHITE + player.getName())); if (player.getProxyName() != null) sender.sendMessage(ChatColor.convertColor(" -> Proxy: " + ChatColor.WHITE + player.getProxyName())); if (player.getServerName() != null) sender.sendMessage(ChatColor.convertColor(" -> Server: " + ChatColor.WHITE + player.getServerName())); if (player.getAddress() != null) sender.sendMessage(ChatColor.convertColor(" -> Address: " + ChatColor.WHITE + player.getAddress().getAddress().getHostAddress() + ':' + player.getAddress().getPort())); sender.sendMessage(ChatColor.convertColor(" -> UUID: " + ChatColor.AQUA + player.getUniqueId())); } else { if (type == null) { sender.sendMessage(Component.text("SubServers > There is no object with that name")); } else { sender.sendMessage(Component.text("SubServers > There is no player with that name")); } } }); Runnable getServer = () -> plugin.api.getServer(name, server -> { if (server != null) { sender.sendMessage(ChatColor.convertColor("SubServers > Info on " + ((server instanceof SubServer)?"sub":"") + "server: " + ChatColor.WHITE + server.getDisplayName())); if (!server.getName().equals(server.getDisplayName())) sender.sendMessage(ChatColor.convertColor(" -> System Name: " + ChatColor.WHITE + server.getName())); if (server instanceof SubServer) { sender.sendMessage(ChatColor.convertColor(" -> Available: " + ((((SubServer) server).isAvailable())?ChatColor.GREEN+"yes":ChatColor.RED+"no"))); sender.sendMessage(ChatColor.convertColor(" -> Enabled: " + ((((SubServer) server).isEnabled())?ChatColor.GREEN+"yes":ChatColor.RED+"no"))); if (!((SubServer) server).isEditable()) sender.sendMessage(ChatColor.convertColor(" -> Editable: " + ChatColor.RED + "no")); sender.sendMessage(ChatColor.convertColor(" -> Host: " + ChatColor.WHITE + ((SubServer) server).getHost())); if (((SubServer) server).getTemplate() != null) sender.sendMessage(ChatColor.convertColor(" -> Template: " + ChatColor.WHITE + ((SubServer) server).getHost())); } if (server.getGroups().size() > 0) sender.sendMessage(ChatColor.convertColor(" -> Group" + ((server.getGroups().size() > 1)?"s:":": " + ChatColor.WHITE + server.getGroups().get(0)))); if (server.getGroups().size() > 1) for (String group : server.getGroups()) sender.sendMessage(ChatColor.convertColor(" - " + ChatColor.WHITE + group)); sender.sendMessage(ChatColor.convertColor(" -> Address: " + ChatColor.WHITE + server.getAddress().getAddress().getHostAddress()+':'+server.getAddress().getPort())); if (server instanceof SubServer) sender.sendMessage(ChatColor.convertColor(" -> " + ((((SubServer) server).isOnline())?"Online":"Running") + ": " + ((((SubServer) server).isRunning())?ChatColor.GREEN+"yes":ChatColor.RED+"no"))); if (!(server instanceof SubServer) || ((SubServer) server).isRunning()) { sender.sendMessage(ChatColor.convertColor(" -> Connected: " + ((server.getSubData()[0] != null)?ChatColor.GREEN+"yes"+((server.getSubData().length > 1)?ChatColor.AQUA+" +"+(server.getSubData().length-1)+" subchannel"+((server.getSubData().length == 2)?"":"s"):""):ChatColor.RED+"no"))); sender.sendMessage(ChatColor.convertColor(" -> Players: " + ChatColor.AQUA + server.getRemotePlayers().size() + " online")); } sender.sendMessage(ChatColor.convertColor(" -> MOTD: " + ChatColor.WHITE + ChatColor.stripColor(server.getMotd()))); if (server instanceof SubServer) { if (((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(ChatColor.convertColor(" -> Stop Action: " + ChatColor.WHITE + ((SubServer) server).getStopAction().toString())); if (((SubServer) server).isStopping()) sender.sendMessage(ChatColor.convertColor(" -> Stopping: " + ChatColor.GREEN+"yes")); } sender.sendMessage(ChatColor.convertColor(" -> Signature: " + ChatColor.AQUA + server.getSignature())); if (server instanceof SubServer) sender.sendMessage(ChatColor.convertColor(" -> Logging: " + ((((SubServer) server).isLogging())?ChatColor.GREEN+"yes":ChatColor.RED+"no"))); sender.sendMessage(ChatColor.convertColor(" -> Restricted: " + ((server.isRestricted())?ChatColor.GREEN+"yes":ChatColor.RED+"no"))); if (server instanceof SubServer && ((SubServer) server).getIncompatibilities().size() > 0) { List current = new ArrayList(); for (String other : ((SubServer) server).getCurrentIncompatibilities()) current.add(other.toLowerCase()); sender.sendMessage(Component.text(" -> Incompatibilities:")); for (String other : ((SubServer) server).getIncompatibilities()) sender.sendMessage(ChatColor.convertColor(" - " + ((current.contains(other.toLowerCase()))?ChatColor.WHITE:ChatColor.GRAY) + other)); } sender.sendMessage(ChatColor.convertColor(" -> Hidden: " + ((server.isHidden())?ChatColor.GREEN+"yes":ChatColor.RED+"no"))); } else { if (type == null) { getPlayer.run(); } else { sender.sendMessage(Component.text("SubServers > There is no server with that name")); } } }); Runnable getGroup = () -> plugin.api.getGroup(name, group -> { if (group != null) { sender.sendMessage(ChatColor.convertColor("SubServers > Info on group: " + ChatColor.WHITE + group.key())); sender.sendMessage(ChatColor.convertColor(" -> Servers: " + ((group.value().size() <= 0)?ChatColor.GRAY + "(none)":ChatColor.AQUA.toString() + group.value().size()))); for (Server server : group.value()) sender.sendMessage(ChatColor.convertColor(" - " + ChatColor.WHITE + server.getDisplayName() + ((server.getName().equals(server.getDisplayName()))?"":" ["+server.getName()+']'))); } else { if (type == null) { getServer.run(); } else { sender.sendMessage(Component.text("SubServers > There is no group with that name")); } } }); Runnable getHost = () -> plugin.api.getHost(name, host -> { if (host != null) { sender.sendMessage(ChatColor.convertColor("SubServers > Info on host: " + ChatColor.WHITE + host.getDisplayName())); if (!host.getName().equals(host.getDisplayName())) sender.sendMessage(ChatColor.convertColor(" -> System Name: " + ChatColor.WHITE + host.getName())); sender.sendMessage(ChatColor.convertColor(" -> Available: " + ((host.isAvailable())?ChatColor.GREEN+"yes":ChatColor.RED+"no"))); sender.sendMessage(ChatColor.convertColor(" -> Enabled: " + ((host.isEnabled())?ChatColor.GREEN+"yes":ChatColor.RED+"no"))); sender.sendMessage(ChatColor.convertColor(" -> Address: " + ChatColor.WHITE + host.getAddress().getHostAddress())); if (host.getSubData().length > 0) sender.sendMessage(ChatColor.convertColor(" -> Connected: " + ((host.getSubData()[0] != null)?ChatColor.GREEN+"yes"+((host.getSubData().length > 1)?ChatColor.AQUA+" +"+(host.getSubData().length-1)+" subchannel"+((host.getSubData().length == 2)?"":"s"):""):ChatColor.RED+"no"))); sender.sendMessage(ChatColor.convertColor(" -> SubServers: " + ((host.getSubServers().keySet().size() <= 0)?ChatColor.GRAY + "(none)":ChatColor.AQUA.toString() + host.getSubServers().keySet().size()))); for (SubServer subserver : host.getSubServers().values()) sender.sendMessage(ChatColor.convertColor(" - " + ((subserver.isEnabled())?ChatColor.WHITE:ChatColor.GRAY) + subserver.getDisplayName() + ((subserver.getName().equals(subserver.getDisplayName()))?"":" ["+subserver.getName()+']'))); sender.sendMessage(ChatColor.convertColor(" -> Templates: " + ((host.getCreator().getTemplates().keySet().size() <= 0)?ChatColor.GRAY + "(none)":ChatColor.AQUA.toString() + host.getCreator().getTemplates().keySet().size()))); for (SubCreator.ServerTemplate template : host.getCreator().getTemplates().values()) sender.sendMessage(ChatColor.convertColor(" - " + ((template.isEnabled())?ChatColor.WHITE:ChatColor.GRAY) + template.getDisplayName() + ((template.getName().equals(template.getDisplayName()))?"":" ["+template.getName()+']'))); sender.sendMessage(ChatColor.convertColor(" -> Signature: " + ChatColor.AQUA + host.getSignature())); } else { if (type == null) { getGroup.run(); } else { sender.sendMessage(Component.text("SubServers > There is no host with that name")); } } }); Runnable getProxy = () -> plugin.api.getProxy(name, proxy -> { if (proxy != null) { sender.sendMessage(ChatColor.convertColor("SubServers > Info on proxy: " + ChatColor.WHITE + proxy.getDisplayName())); if (!proxy.getName().equals(proxy.getDisplayName())) sender.sendMessage(ChatColor.convertColor(" -> System Name: " + ChatColor.WHITE + proxy.getName())); if (!proxy.isMaster()) sender.sendMessage(ChatColor.convertColor(" -> Connected: " + ((proxy.getSubData()[0] != null)?ChatColor.GREEN+"yes"+((proxy.getSubData().length > 1)?ChatColor.AQUA+" +"+(proxy.getSubData().length-1)+" subchannel"+((proxy.getSubData().length == 2)?"":"s"):""):ChatColor.RED+"no"))); else if (!proxy.getDisplayName().toLowerCase().contains("master")) sender.sendMessage(ChatColor.convertColor(" -> Type: " + ChatColor.WHITE + "Master")); sender.sendMessage(ChatColor.convertColor(" -> Players: " + ChatColor.AQUA + proxy.getPlayers().size() + " online")); sender.sendMessage(ChatColor.convertColor(" -> Signature: " + ChatColor.AQUA + proxy.getSignature())); } else { if (type == null) { getHost.run(); } else { sender.sendMessage(Component.text("SubServers > There is no proxy with that name")); } } }); if (type == null) { getProxy.run(); } else { switch (type.toLowerCase()) { case "p": case "proxy": getProxy.run(); break; case "h": case "host": getHost.run(); break; case "g": case "group": getGroup.run(); break; case "s": case "server": case "subserver": getServer.run(); break; case "u": case "user": case "player": getPlayer.run(); break; default: sender.sendMessage(Component.text("SubServers > There is no object type with that name")); } } } else { sender.sendMessage(Component.text("SubServers > Usage: " + label + " " + args[0].toLowerCase() + " [proxy|host|group|server|player] ")); } } else if (args[0].equalsIgnoreCase("start")) { if (args.length > 1) { selectServers(sender, args, 1, true, select -> { if (select.subservers.length > 0) { Container success = new Container(0); Container running = new Container(0); AsyncConsolidator merge = new AsyncConsolidator(() -> { if (running.value > 0) sender.sendMessage(Component.text("SubServers > " + running.value + " subserver"+((running.value == 1)?" was":"s were") + " already running")); if (success.value > 0) sender.sendMessage(Component.text("SubServers > Started " + success.value + " subserver"+((success.value == 1)?"":"s"))); }); for (SubServer server : select.subservers) { merge.reserve(); server.start(null, response -> { switch (response) { case 3: case 4: sender.sendMessage(Component.text("SubServers > Subserver " + server.getName() + " has disappeared")); break; case 5: sender.sendMessage(Component.text("SubServers > The host for " + server.getName() + " is not available")); break; case 6: sender.sendMessage(Component.text("SubServers > The host for " + server.getName() + " is not enabled")); break; case 7: sender.sendMessage(Component.text("SubServers > Subserver " + server.getName() + " is not available")); break; case 8: sender.sendMessage(Component.text("SubServers > SubServer " + server.getName() + " is not enabled")); break; case 9: running.value++; break; case 10: sender.sendMessage(Component.text("SubServers > Subserver " + server.getName() + " cannot start while incompatible server(s) are running")); break; case 0: success.value++; break; } merge.release(); }); } } }); } else { sender.sendMessage(Component.text("Usage: " + label + " " + args[0].toLowerCase() + " ")); } } else if (args[0].equalsIgnoreCase("restart")) { if (args.length > 1) { selectServers(sender, args, 1, true, select -> { if (select.subservers.length > 0) { // Step 5: Start the stopped Servers once more Consumer starter = server -> server.start(response -> { switch (response) { case 3: case 4: sender.sendMessage(Component.text("SubServers > Could not restart server: Subserver " + server.getName() + " has disappeared")); break; case 5: sender.sendMessage(Component.text("SubServers > Could not restart server: The host for " + server.getName() + " is no longer available")); break; case 6: sender.sendMessage(Component.text("SubServers > Could not restart server: The host for " + server.getName() + " is no longer enabled")); break; case 7: sender.sendMessage(Component.text("SubServers > Could not restart server: Subserver " + server.getName() + " is no longer available")); break; case 8: sender.sendMessage(Component.text("SubServers > Could not restart server: Subserver " + server.getName() + " is no longer enabled")); break; case 10: sender.sendMessage(Component.text("SubServers > Could not restart server: Subserver " + server.getName() + " cannot start while incompatible server(s) are running")); break; case 9: case 0: // success! break; } }); // Step 4: Listen for stopped Servers final HashMap listening = new HashMap(); PacketInExRunEvent.callback("SubStoppedEvent", new Consumer>() { @Override public void accept(ObjectMap json) { try { if (listening.size() > 0) { PacketInExRunEvent.callback("SubStoppedEvent", this); String name = json.getString("server").toLowerCase(); if (listening.containsKey(name)) { Timer timer = new Timer("SubServers.Sync::Server_Restart_Command_Handler(" + name + ")"); timer.schedule(new TimerTask() { @Override public void run() { starter.accept(listening.get(name)); listening.remove(name); timer.cancel(); } }, 100); } } } catch (Exception e) {} } }); // Step 1-3: Restart Servers / Receive command Responses Container success = new Container(0); AsyncConsolidator merge = new AsyncConsolidator(() -> { if (success.value > 0) sender.sendMessage(Component.text("SubServers > Restarting " + success.value + " subserver"+((success.value == 1)?"":"s"))); }); for (SubServer server : select.subservers) { merge.reserve(); listening.put(server.getName().toLowerCase(), server); server.stop(response -> { if (response != 0) listening.remove(server.getName().toLowerCase()); switch (response) { case 3: case 4: sender.sendMessage(Component.text("Could not restart server: Subserver " + server.getName() + " has disappeared")); break; case 5: starter.accept(server); case 0: success.value++; break; } merge.release(); }); } } }); } else { sender.sendMessage(Component.text("Usage: " + label + " " + args[0].toLowerCase() + " ")); } } else if (args[0].equalsIgnoreCase("stop")) { if (args.length > 1) { selectServers(sender, args, 1, true, select -> { if (select.subservers.length > 0) { Container success = new Container(0); Container running = new Container(0); AsyncConsolidator merge = new AsyncConsolidator(() -> { if (running.value > 0) sender.sendMessage(Component.text("SubServers > " + running.value + " subserver"+((running.value == 1)?" was":"s were") + " already offline")); if (success.value > 0) sender.sendMessage(Component.text("SubServers > Stopping " + success.value + " subserver"+((success.value == 1)?"":"s"))); }); for (SubServer server : select.subservers) { merge.reserve(); server.stop(response -> { switch (response) { case 3: case 4: sender.sendMessage(Component.text("SubServers > Subserver " + server.getName() + " has disappeared")); break; case 5: running.value++; break; case 0: success.value++; break; } merge.release(); }); } } }); } else { sender.sendMessage(Component.text("Usage: " + label + " " + args[0].toLowerCase() + " ")); } } else if (args[0].equalsIgnoreCase("kill") || args[0].equalsIgnoreCase("terminate")) { if (args.length > 1) { selectServers(sender, args, 1, true, select -> { if (select.subservers.length > 0) { Container success = new Container(0); Container running = new Container(0); AsyncConsolidator merge = new AsyncConsolidator(() -> { if (running.value > 0) sender.sendMessage(Component.text("SubServers > " + running.value + " subserver"+((running.value == 1)?" was":"s were") + " already offline")); if (success.value > 0) sender.sendMessage(Component.text("SubServers > Terminated " + success.value + " subserver"+((success.value == 1)?"":"s"))); }); for (SubServer server : select.subservers) { merge.reserve(); server.terminate(response -> { switch (response) { case 3: case 4: sender.sendMessage(Component.text("SubServers > Subserver " + server.getName() + " has disappeared")); break; case 5: running.value++; break; case 0: success.value++; break; } merge.release(); }); } } }); } else { sender.sendMessage(Component.text("Usage: " + label + " " + args[0].toLowerCase() + " ")); } } else if (args[0].equalsIgnoreCase("cmd") || args[0].equalsIgnoreCase("command")) { if (args.length > 1) { selectServers(sender, args, 1, false, select -> { if (select.servers.length > 0) { if (select.args.length > 2) { StringBuilder builder = new StringBuilder(select.args[2]); for (int i = 3; i < select.args.length; i++) { builder.append(' '); builder.append(select.args[i]); } Container success = new Container(0); Container running = new Container(0); AsyncConsolidator merge = new AsyncConsolidator(() -> { if (running.value > 0) sender.sendMessage(Component.text("SubServers > " + running.value + " server"+((running.value == 1)?" was":"s were") + " offline")); if (success.value > 0) sender.sendMessage(Component.text("SubServers > Sent command to " + success.value + " server"+((success.value == 1)?"":"s"))); }); for (Server server : select.servers) { merge.reserve(); server.command(builder.toString(), response -> { switch (response) { case 3: case 4: sender.sendMessage(Component.text("SubServers > Server " + server.getName() + " has disappeared")); break; case 5: running.value++; break; case 0: success.value++; break; } merge.release(); }); } } else { sender.sendMessage(Component.text("SubServers > No command was entered")); } } }); } else { sender.sendMessage(Component.text("Usage: " + label + " " + args[0].toLowerCase() + " [Args...]")); } } else if (args[0].equalsIgnoreCase("create")) { if (args.length > 3) { if (args.length > 5 && !Try.all.run(() -> Integer.parseInt(args[5]))) { sender.sendMessage(Component.text("SubServers > Invalid port number")); } else { ((SubDataClient) SubAPI.getInstance().getSubDataNetwork()[0]).sendPacket(new PacketCreateServer(null, args[1], args[2],args[3], (args.length > 4)?new Version(args[4]):null, (args.length > 5)?Integer.parseInt(args[5]):null, data -> { switch (data.getInt(0x0001)) { case 3: case 4: sender.sendMessage(Component.text("SubServers > There is already a subserver with that name")); break; case 5: sender.sendMessage(Component.text("SubServers > There is no host with that name")); break; case 6: sender.sendMessage(Component.text("SubServers > That host is not available")); break; case 7: sender.sendMessage(Component.text("SubServers > That host is not enabled")); break; case 8: sender.sendMessage(Component.text("SubServers > There is no template with that name")); break; case 9: sender.sendMessage(Component.text("SubServers > That template is not enabled")); break; case 10: sender.sendMessage(Component.text("SubServers > That template requires a Minecraft version to be specified")); break; case 11: sender.sendMessage(Component.text("SubServers > Invalid port number")); break; case 0: sender.sendMessage(Component.text("SubServers > Creating subserver " + args[1])); break; } })); } } else { sender.sendMessage(Component.text("SubServers > Usage: " + label + " " + args[0].toLowerCase() + "