From 7433fc04a8cc6847c2add57a8612d1e80a733749 Mon Sep 17 00:00:00 2001 From: ME1312 Date: Thu, 17 Mar 2022 00:18:34 -0400 Subject: [PATCH] #75 Added Server Signs --- SubServers.Bungee/common/pom.xml | 2 +- SubServers.Bungee/pom.xml | 2 +- .../Host/External/ExternalSubServer.java | 6 + .../Host/Internal/InternalSubServer.java | 10 +- .../SubServers/Bungee/Host/SubServer.java | 8 + .../SubServers/Bungee/Host/SubServerImpl.java | 8 +- .../Bungee/Library/ConfigUpdater.java | 15 +- .../ME1312/SubServers/Bungee/SubCommand.java | 5 +- .../ME1312/SubServers/Bungee/SubProxy.java | 2 +- .../Library/Compatibility/BungeeChat.java | 6 + .../Library/Compatibility/OfflineBlock.java | 73 ++ .../Compatibility/PlaceholderImpl.java | 726 +--------------- .../Client/Bukkit/Library/Placeholders.java | 785 ++++++++++++++++++ .../SubServers/Client/Bukkit/SubCommand.java | 11 +- .../SubServers/Client/Bukkit/SubPlugin.java | 36 +- .../SubServers/Client/Bukkit/SubSigns.java | 271 ++++++ SubServers.Client/Bukkit/src/plugin.yml | 17 +- SubServers.Client/Common/pom.xml | 4 +- .../Client/Common/Network/API/SubServer.java | 10 + .../SubServers/Client/Sponge/SubCommand.java | 7 +- .../SubServers/Client/Sponge/SubPlugin.java | 2 +- SubServers.Host/pom.xml | 4 +- .../net/ME1312/SubServers/Host/ExHost.java | 2 +- .../ME1312/SubServers/Host/SubCommand.java | 5 +- .../net/ME1312/SubServers/Sync/ExProxy.java | 2 +- .../ME1312/SubServers/Sync/SubCommand.java | 5 +- .../ME1312/SubServers/Velocity/ExProxy.java | 2 +- .../SubServers/Velocity/SubCommand.java | 5 +- 28 files changed, 1260 insertions(+), 771 deletions(-) create mode 100644 SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/OfflineBlock.java create mode 100644 SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Placeholders.java create mode 100644 SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubSigns.java diff --git a/SubServers.Bungee/common/pom.xml b/SubServers.Bungee/common/pom.xml index 962bd4a9..a2e458db 100644 --- a/SubServers.Bungee/common/pom.xml +++ b/SubServers.Bungee/common/pom.xml @@ -28,7 +28,7 @@ net.ME1312.Galaxi GalaxiUtil - 21w50a + 22w11a compile diff --git a/SubServers.Bungee/pom.xml b/SubServers.Bungee/pom.xml index c4504489..2b9caf17 100644 --- a/SubServers.Bungee/pom.xml +++ b/SubServers.Bungee/pom.xml @@ -34,7 +34,7 @@ net.ME1312.SubData Server - 21w50a + 22w11a compile diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/External/ExternalSubServer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/External/ExternalSubServer.java index 9b993d32..6966ed4c 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/External/ExternalSubServer.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/External/ExternalSubServer.java @@ -128,6 +128,7 @@ public class ExternalSubServer extends SubServerImpl { } void started(UUID address) { if (!running) { + stopping = false; started = false; running = true; lock = false; @@ -152,6 +153,7 @@ public class ExternalSubServer extends SubServerImpl { if (!event.isCancelled()) { history.add(new LoggedCommand(player, stopcmd)); host.queue(new PacketExControlServer(this, Action.STOP)); + stopping = true; return true; } else return false; } else return false; @@ -159,7 +161,9 @@ public class ExternalSubServer extends SubServerImpl { private void stopped(Boolean allowrestart) { logger.stop(); history.clear(); + started = false; running = false; + stopping = false; SubStoppedEvent event = new SubStoppedEvent(this); host.plugin.getPluginManager().callEvent(event); Logger.get("SubServers").info(getName() + " has stopped"); @@ -205,6 +209,7 @@ public class ExternalSubServer extends SubServerImpl { host.plugin.getPluginManager().callEvent(event); if (!event.isCancelled()) { host.queue(new PacketExControlServer(this, Action.TERMINATE)); + stopping = true; return true; } else return false; } else return false; @@ -220,6 +225,7 @@ public class ExternalSubServer extends SubServerImpl { history.add(new LoggedCommand(player, event.getCommand())); if (event.getCommand().equalsIgnoreCase(stopcmd)) { host.queue(new PacketExControlServer(this, Action.STOP)); + stopping = true; } else { host.queue(new PacketExControlServer(this, Action.COMMAND, event.getCommand())); } diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java index e6bcaab0..6823135b 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java @@ -149,6 +149,7 @@ public class InternalSubServer extends SubServerImpl { private void run() { boolean locked = lock; allowrestart = true; + stopping = false; started = false; try { ProcessBuilder pb = new ProcessBuilder().command(Executable.parse(host.getCreator().getBashDirectory(), executable)).directory(directory); @@ -181,6 +182,8 @@ public class InternalSubServer extends SubServerImpl { Logger.get("SubServers").info(getName() + " has stopped"); process = null; command = null; + started = false; + stopping = false; history.clear(); SubStoppedEvent event = new SubStoppedEvent(this); @@ -245,6 +248,7 @@ public class InternalSubServer extends SubServerImpl { host.plugin.getPluginManager().callEvent(event); if (!event.isCancelled()) { try { + stopping = true; allowrestart = false; history.add(new LoggedCommand(player, stopcmd)); if (process != null && process.isAlive()) { @@ -267,6 +271,7 @@ public class InternalSubServer extends SubServerImpl { SubStopEvent event = new SubStopEvent(player, this, true); host.plugin.getPluginManager().callEvent(event); if (!event.isCancelled()) { + stopping = true; allowrestart = false; if (process != null && process.isAlive()) Executable.terminate(process); return true; @@ -282,7 +287,10 @@ public class InternalSubServer extends SubServerImpl { host.plugin.getPluginManager().callEvent(event); if (!event.isCancelled() && (player == null || !DISALLOWED_COMMANDS.matcher(command).find())) { try { - if (event.getCommand().equalsIgnoreCase(stopcmd)) allowrestart = false; + if (event.getCommand().equalsIgnoreCase(stopcmd)) { + stopping = true; + allowrestart = false; + } history.add(new LoggedCommand(player, event.getCommand())); if (process != null && process.isAlive()) { this.command.write(event.getCommand()); diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/SubServer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/SubServer.java index 88de2ca6..beb2d532 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/SubServer.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/SubServer.java @@ -217,6 +217,14 @@ public interface SubServer extends Server { */ boolean isOnline(); + /** + * If the Server is Stopping
+ * This method can only be true when the server is stopped through the server manager! + * + * @return Stopping Status + */ + boolean isStopping(); + /** * Grabs the Host of the Server * diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/SubServerImpl.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/SubServerImpl.java index 2e381d1c..7dfd3439 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/SubServerImpl.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/SubServerImpl.java @@ -22,7 +22,7 @@ public abstract class SubServerImpl extends ServerImpl implements SubServer { private List> incompatibilities = new ArrayList>(); private SubCreator.ServerTemplate templateV = null; private String templateS = null; - protected boolean registered, started, updating; + protected boolean registered, started, stopping, updating; /** * Creates a SubServer @@ -93,6 +93,11 @@ public abstract class SubServerImpl extends ServerImpl implements SubServer { return isRunning() && started; } + @Override + public boolean isStopping() { + return isRunning() && stopping; + } + @Override public void setTemplate(String template) { this.templateV = null; @@ -183,6 +188,7 @@ public abstract class SubServerImpl extends ServerImpl implements SubServer { sinfo.set("exec", getExecutable()); sinfo.set("running", isRunning()); sinfo.set("online", isOnline()); + sinfo.set("stopping", isStopping()); sinfo.set("stop-cmd", getStopCommand()); sinfo.set("stop-action", getStopAction().toString()); sinfo.set("auto-run", SubAPI.getInstance().getInternals().servers.get().getMap("Servers").getMap(getName(), new ObjectMap()).getBoolean("Run-On-Launch", false)); diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/ConfigUpdater.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/ConfigUpdater.java index b723c30a..cf05d50e 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/ConfigUpdater.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/ConfigUpdater.java @@ -325,8 +325,11 @@ public class ConfigUpdater { existing = updated.clone(); i++; } if (was.compareTo(new Version("21w49b")) <= 0) { + if (existing.contains("Lang")) { + updated.getMap("Lang").remove("Command.Teleport"); + } - //existing = updated.clone(); + existing = updated.clone(); i++; }// if (was.compareTo(new Version("99w99a")) <= 0) { // // do something @@ -358,6 +361,13 @@ public class ConfigUpdater { def.put("Bungee.List.List", "&f$str$"); def.put("Bungee.List.Divider", "&f, "); def.put("Bungee.List.Total", "Total players online: $int$"); + def.put("Signs.Create", "&aSubServers &2&l\\u00BB&a Server sign activated"); + def.put("Signs.Delete", "&aSubServers &2&l\\u00BB&a Server sign removed"); + def.put("Signs.Text.Error", "&f&oSubServers\\n&3$str$\\n&7Unknown Status\\n&8\\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022"); + def.put("Signs.Text.Offline", "&c&oSubServers\\n&3#subserver.displayname($str$)\\n&4Offline\\n&7Click to Start"); + def.put("Signs.Text.Starting", "&e&oSubServers\\n&3#subserver.displayname($str$)\\n&6Starting\\n&8\\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022"); + def.put("Signs.Text.Online", "&a&oSubServers\\n&3#subserver.displayname($str$)\\n&2#subserver.players($str$) Online\\n&7Click to Join"); + def.put("Signs.Text.Stopping", "&e&oSubServers\\n&3#subserver.displayname($str$)\\n&6Stopping\\n&8\\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022 \\u2022"); def.put("Command.Generic.Player-Only", "&cSubServers &4&l\\u00BB&c The console cannot perform this command"); def.put("Command.Generic.Console-Only", "&cSubServers &4&l\\u00BB&c This command is for console use only"); def.put("Command.Generic.Usage", "&7SubServers &8&l\\u00BB&7 Usage: &f$str$"); @@ -457,7 +467,8 @@ public class ConfigUpdater { def.put("Command.Delete.Disappeared", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c has disappeared"); def.put("Command.Delete.Running", "&cSubServers &4&l\\u00BB&c Cannot delete &4$str$&c while it is still running"); def.put("Command.Delete", "&aSubServers &2&l\\u00BB&a Deleting &2$int$&a subserver(s)"); - def.put("Command.Teleport", "&aSubServers &2&l\\u00BB&a Teleporting &2$str$&a to server"); + def.put("Command.Teleport", "&aSubServers &2&l\\u00BB&a Teleporting to &2$str$"); + def.put("Command.Teleport.Others", "&aSubServers &2&l\\u00BB&a Teleporting &2$name$&a to &2$str$"); def.put("Command.Teleport.Not-Running", "&cSubServers &4&l\\u00BB&c Subserver &4$str$&c is not running"); def.put("Interface.Generic.Back", "&cBack"); def.put("Interface.Generic.Back-Arrow", "&e&l<--"); diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubCommand.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubCommand.java index 13b85c77..d98d4fa3 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubCommand.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubCommand.java @@ -289,7 +289,10 @@ public final class SubCommand extends Command implements TabExecutor { sender.sendMessage(" -> Players: " + ChatColor.AQUA + server.getRemotePlayers().size() + " online"); } sender.sendMessage(" -> MOTD: " + ChatColor.WHITE + ChatColor.stripColor(server.getMotd())); - if (server instanceof SubServer && ((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(" -> Stop Action: " + ChatColor.WHITE + ((SubServer) server).getStopAction().toString()); + if (server instanceof SubServer) { + if (((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(" -> Stop Action: " + ChatColor.WHITE + ((SubServer) server).getStopAction().toString()); + if (((SubServer) server).isStopping()) sender.sendMessage(" -> Stopping: " + ChatColor.GREEN+"yes"); + } sender.sendMessage(" -> Signature: " + ChatColor.AQUA + server.getSignature()); if (server instanceof SubServer) sender.sendMessage(" -> Logging: " + ((((SubServer) server).isLogging())?ChatColor.GREEN+"yes":ChatColor.RED+"no")); sender.sendMessage(" -> Restricted: " + ((server.isRestricted())?ChatColor.GREEN+"yes":ChatColor.RED+"no")); diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java index 65ab54fb..f695127b 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java @@ -92,7 +92,7 @@ public final class SubProxy extends BungeeCommon implements Listener { public SubProtocol subprotocol; public SubDataServer subdata = null; public SubServer sudo = null; - public static final Version version = Version.fromString("2.18a"); + public static final Version version = Version.fromString("2.18.2a"); public final Proxy mProxy; public boolean canSudo = false; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/BungeeChat.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/BungeeChat.java index 7147746b..54ac3fc4 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/BungeeChat.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/BungeeChat.java @@ -17,6 +17,9 @@ import java.text.DecimalFormat; import java.util.LinkedList; import java.util.List; +/** + * BungeeCord Chat Library Compatibility Class + */ public class BungeeChat { private SubPlugin plugin; @@ -24,6 +27,9 @@ public class BungeeChat { this.plugin = plugin; } + /** + * Output for /sub list + */ public void listCommand(CommandSender sender, String label) { plugin.api.getGroups(groups -> plugin.api.getHosts(hosts -> plugin.api.getServers(servers -> plugin.api.getMasterProxy(proxymaster -> plugin.api.getProxies(proxies -> { int i = 0; diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/OfflineBlock.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/OfflineBlock.java new file mode 100644 index 00000000..7ab89081 --- /dev/null +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/OfflineBlock.java @@ -0,0 +1,73 @@ +package net.ME1312.SubServers.Client.Bukkit.Library.Compatibility; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +/** + * Offline Block Location Class + */ +public class OfflineBlock { + public final UUID world; + public final int x, y, z; + + /** + * Convert an existing location object + * + * @param location Location + */ + public OfflineBlock(Location location) { + this(location.getWorld().getUID(), location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + /** + * Store location data + * + * @param world World ID + * @param x X position + * @param y Y position + * @param z Z position + */ + public OfflineBlock(UUID world, int x, int y, int z) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + } + + /** + * Find the World if loaded + * + * @return World (or null if unavailable) + */ + public World world() { + return Bukkit.getWorld(this.world); + } + + /** + * Find the Location if loaded + * + * @return Location (or null if unavailable) + */ + public Location load() { + World world = Bukkit.getWorld(this.world); + return (world == null)? null : new Location(world, x, y, z); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + OfflineBlock that = (OfflineBlock) o; + return x == that.x && y == that.y && z == that.z && Objects.equals(world, that.world); + } + + @Override + public int hashCode() { + return Objects.hash(world, x, y, z); + } +} diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/PlaceholderImpl.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/PlaceholderImpl.java index 1deaa456..fe42b364 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/PlaceholderImpl.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Compatibility/PlaceholderImpl.java @@ -1,39 +1,18 @@ package net.ME1312.SubServers.Client.Bukkit.Library.Compatibility; -import net.ME1312.Galaxi.Library.Container.ContainedPair; -import net.ME1312.Galaxi.Library.Container.Pair; -import net.ME1312.Galaxi.Library.Map.ObjectMap; -import net.ME1312.Galaxi.Library.Try; -import net.ME1312.Galaxi.Library.Util; -import net.ME1312.SubServers.Client.Bukkit.Event.*; -import net.ME1312.SubServers.Client.Bukkit.SubAPI; import net.ME1312.SubServers.Client.Bukkit.SubPlugin; -import net.ME1312.SubServers.Client.Common.Network.API.*; -import me.clip.placeholderapi.PlaceholderAPI; import me.clip.placeholderapi.expansion.Cacheable; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.clip.placeholderapi.expansion.Taskable; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.scheduler.BukkitTask; - -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * PlaceholderAPI Implementation Class */ public class PlaceholderImpl extends PlaceholderExpansion implements Taskable, Cacheable { private SubPlugin plugin; - private BukkitTask task; - private Cache cache; - private boolean init; /** * Create a PlaceholderAPI Implementation Instance @@ -42,14 +21,8 @@ public class PlaceholderImpl extends PlaceholderExpansion implements Taskable, C */ public PlaceholderImpl(SubPlugin plugin) { this.plugin = plugin; - this.cache = new Cache(); - this.init = false; - - if (plugin.config.get().getMap("Settings").getBoolean("PlaceholderAPI-Ready", false)) init(); } - - @Override public String getIdentifier() { return "subservers"; @@ -70,21 +43,6 @@ public class PlaceholderImpl extends PlaceholderExpansion implements Taskable, C return true; } - private void init() { - if (!init) { - init = true; - Bukkit.getPluginManager().registerEvents(cache.events, plugin); - Bukkit.getScheduler().runTaskLater(plugin, () -> { - if (task == null) { - int interval = plugin.config.get().getMap("Settings").getInt("PlaceholderAPI-Cache-Interval", 300); - int start = interval - new Random().nextInt((interval / 3) + 1); // Don't have all servers request at the same time - task = Bukkit.getScheduler().runTaskTimer(plugin, cache::refresh, 20L * start, 20L * interval); - cache.refresh(); - } - }, 120L); - } - } - @Override public void start() { // do nothing @@ -92,17 +50,12 @@ public class PlaceholderImpl extends PlaceholderExpansion implements Taskable, C @Override public void stop() { - if (task != null) { - try { - task.cancel(); - } catch (Throwable exception) {} - task = null; - } + plugin.phi.stop(); } @Override public void clear() { - cache.reset(); + plugin.phi.clear(); } @Override @@ -112,679 +65,6 @@ public class PlaceholderImpl extends PlaceholderExpansion implements Taskable, C @Override public String onRequest(OfflinePlayer player, String request) { - boolean colored = !request.startsWith("plain_"); - if (!colored || request.startsWith("color_")) request = request.substring(6); - - String response = runMethod(player, request); - if (!init) init(); - - if (response != null && !colored) { - return ChatColor.stripColor(response); - } else { - return response; - } - } - - private static final Pattern replacements = Pattern.compile("#?([^\\s#]+?\\(.*?\\))|\\$([^$]+)\\$", Pattern.CASE_INSENSITIVE); - private String[] arguments(OfflinePlayer player, String text, boolean replace) { - LinkedList arguments = new LinkedList<>(); - - if (text != null && !text.isEmpty()) { - Pattern p = replacements; - Matcher m = p.matcher(text); - - StringBuilder argument = new StringBuilder(); - while (m.find()) { - String[] replacement = findMethod(player, text, m.start(), replace); - - if (replacement[0].contains(",")) { - String[] s = replacement[0].split(","); - argument.append(s[0]); - arguments.add(argument.toString().trim()); - - for (int i = 1; i < s.length - 1; ++i) { - arguments.add(s[i].trim()); - } - - argument = new StringBuilder(); - argument.append(s[s.length - 1]); - } else { - argument.append(replacement[0]); - } - - argument.append(replacement[1]); - - text = replacement[2]; - m = p.matcher(text); - } - - if (text.contains(",")) { - String[] s = text.split(","); - argument.append(s[0]); - arguments.add(argument.toString().trim()); - argument = null; - - for (int i = 1; i < s.length; ++i) { - arguments.add(s[i].trim()); - } - } else if (text.length() > 0) { - argument.append(text); - } - - if (argument != null && argument.length() > 0) { - arguments.add(argument.toString().trim()); - } - } - - return arguments.toArray(new String[0]); - } - - private String replace(OfflinePlayer player, String text) { - if (text != null) { - Pattern p = replacements; - Matcher m = p.matcher(text); - - StringBuilder str = new StringBuilder(); - while (m.find()) { - String[] replacement = findMethod(player, text, m.start(), true); - - str.append(replacement[0]); - str.append(replacement[1]); - - text = replacement[2]; - m = p.matcher(text); - } - - str.append(text); - return str.toString(); - } else { - return null; - } - } - - private String[] findMethod(OfflinePlayer player, String text, int start, boolean run) { - String[] values = new String[3]; - values[0] = text.substring(0, start); - text = text.substring(start); - - int[] open = {'(', '<'}; - int[] close = {')', '>'}; - Arrays.sort(open); - Arrays.sort(close); - - int i = -1; - if (text.codePointAt(0) == '$') { - Matcher m = Pattern.compile("^\\$([^$]+)\\$", Pattern.CASE_INSENSITIVE).matcher(text); - if (m.find()) { - String str = '%' + m.group(1) + '%'; - text = text.substring(m.end()); - if (run) { - String response = PlaceholderAPI.setPlaceholders(player, str); - values[1] = (response == null)?m.group():response; - } else { - values[1] = m.group(); - } - } - } else { - ++i; - boolean responses = false; - StringBuilder str = new StringBuilder(); - for (int level = 0; i < text.codePoints().count(); ++i) { - int c = text.codePointAt(i); - str.appendCodePoint(c); - - if (Arrays.binarySearch(open, c) >= 0) { - ++level; - } else if (Arrays.binarySearch(close, c) >= 0) { - --level; - if (level <= 0) { - if (responses) break; - boolean more = false; - for (int ix = i + 1; ix < text.codePoints().count(); ++ix) { - int cx = text.codePointAt(ix); - if (!Character.isWhitespace(cx) && cx != '_') { - more = cx == '<'; - break; - } - } - if (!more) break; - else responses = true; - } - } - } - if (run) { - String response = runMethod(player, str.toString()); - values[1] = (response == null)?str.toString():response; - } else { - values[1] = str.toString(); - } - } - - StringBuilder str = new StringBuilder(); - for (i += 1; i < text.codePoints().count(); ++i) { - str.appendCodePoint(text.codePointAt(i)); - } - values[2] = str.toString(); - - return values; - } - - private String[] parseMethod(OfflinePlayer player, String text) { - Matcher m = Pattern.compile("^#?(.+?)(?:[\\s_]*\\((.*?)\\))?(?:[\\s_]*<(.*)>)?$", Pattern.CASE_INSENSITIVE).matcher(text); - - if (m.find()) { - String[] values = new String[3]; - - values[0] = m.group(1); - if (m.group(2) == null || m.group(2).trim().isEmpty() || - m.group(3) == null || m.group(3).trim().isEmpty()) { - // Simple parsing: () or <> - values[1] = m.group(2); - values[2] = m.group(3); - } else { - // Complex parsing: () and <> - text = text.substring(m.end(1)); - int stage = 1, level = 0, i = 0; - char open = '(', close = ')'; - boolean responses = false; - StringBuilder str = new StringBuilder(); - for (; i < text.codePoints().count(); ++i) { - int c = text.codePointAt(i); - if (c == open) { - if (level > 0) str.appendCodePoint(c); - ++level; - } else if (c == close) { - --level; - if (level > 0) str.appendCodePoint(c); - else { - if (responses) break; - boolean more = false; - for (int ix = i + 1; ix < text.codePoints().count(); ++ix) { - int cx = text.codePointAt(ix); - if (!Character.isWhitespace(cx) && cx != '_') { - more = cx == '<'; - break; - } - } - if (!more) break; - else { - responses = true; - open = '<'; close = '>'; - values[stage++] = str.toString(); - str = new StringBuilder(); - } - } - } else { - if (level > 0) str.appendCodePoint(c); - } - } - values[stage] = str.toString(); - if (level > 0 || ++i < text.codePoints().count()) { - return null; - } - } - - return values; - } else { - return null; - } - } - - private String runMethod(OfflinePlayer player, String text) { - String[] parsed = parseMethod(player, text); - - if (parsed != null) { - String method = parsed[0]; - String[] args = arguments(player, parsed[1], true); - String[] responses = arguments(player, parsed[2], false); - - for (int i = 0; i < responses.length; ++i) - responses[i] = ChatColor.translateAlternateColorCodes('&', responses[i].trim()); - - return replace(player, runMethod(player, method, args, responses)); - } else { - return null; - } - } - - @SuppressWarnings("ConstantConditions") - private String runMethod(OfflinePlayer player, String method, String[] args, String[] responses) { - Server server = (plugin.api.getName() != null)? cache.getServer(plugin.api.getName()) : null; - SubServer subserver = (server instanceof SubServer)? (SubServer) server : null; - Pair> group = null; - Host host = (subserver != null)? cache.getHost(subserver.getHost()) : null; - Proxy proxy = cache.getMasterProxy(); - - method = method.toLowerCase(); - if (method.startsWith("proxy.")) { - if (args.length > 0 && !args[0].isEmpty()) proxy = cache.getProxy(args[0]); - if (proxy == null) return null; - } else if (method.startsWith("host.")) { - if (args.length > 0 && !args[0].isEmpty()) host = cache.getHost(args[0]); - if (host == null) return null; - } else if (method.startsWith("group.")) { - if (args.length > 0 && !args[0].isEmpty()) group = cache.getGroup(args[0]); -// if (group == null) return null; // Empty groups are null - } else if (method.startsWith("server.")) { - if (args.length > 0 && !args[0].isEmpty()) server = cache.getServer(args[0]); - if (server == null) return null; - } else if (method.startsWith("subserver.")) { - if (args.length > 0 && !args[0].isEmpty()) server = subserver = cache.getSubServer(args[0]); - if (subserver == null) return null; - } - - - // --- Methods where Objects link to other Objects -- - if (method.startsWith("subserver.host")) { - if (method.equals("subserver.host")) { - return subserver.getHost(); - } else { - LinkedList arguments = new LinkedList(); - arguments.addAll(Arrays.asList(args)); - if (args.length > 0) arguments.removeFirst(); - arguments.addFirst(subserver.getHost()); - return runMethod(player, method.substring(10), arguments.toArray(new String[0]), responses); - } - } else if (method.startsWith("subserver.template")) { - if (method.equals("subserver.template")) { - return (subserver.getTemplate() != null)?subserver.getTemplate():defaults(responses, "(custom)")[0]; - } else if (subserver.getTemplate() != null) { - LinkedList arguments = new LinkedList(); - arguments.addAll(Arrays.asList(args)); - if (args.length > 0) arguments.removeFirst(); - arguments.addFirst(subserver.getTemplate()); - arguments.addFirst(subserver.getHost()); - return runMethod(player, "host.creator." + method.substring(10), arguments.toArray(new String[0]), responses); - } else { - return null; - } - } else switch (method) { // --- Straight up Methods --- - case "example": { - return defaults(responses, ChatColor.LIGHT_PURPLE+"Example!")[0]; - } - case "players": { - int i = cache.getMasterProxy().getPlayers().size(); - for (Proxy p : cache.getProxies().values()) i += p.getPlayers().size(); - return Integer.toString(i); - } - case "proxy": - case "proxies": { - return Integer.toString(cache.getProxies().size() + 1); - } - case "proxy.displayname": { - return proxy.getDisplayName(); - } - case "proxy.type": { - return defaults(responses, "Master Proxy", "Proxy") [((proxy.isMaster())?0:1)]; - } - case "proxy.players": { - return Integer.toString(proxy.getPlayers().size()); - } - case "proxy.subdata": { - return defaults(responses, ChatColor.GREEN+"Connected", ChatColor.RED+"Disconnected") [(proxy.getSubData()[0] == null)?1:0]; - } - case "proxy.subdata.channels": - case "proxy.subdata.subchannels": { - return Integer.toString(proxy.getSubData().length - ((method.endsWith(".subchannels"))?1:0)); - } - case "proxy.signature": { - return proxy.getSignature(); - } - case "host": - case "hosts": { - return Integer.toString(cache.getHosts().size()); - } - case "host.displayname": { - return host.getDisplayName(); - } - case "host.available": { - return defaults(responses, ChatColor.GREEN+"Available", ChatColor.RED+"Unavailable") [(host.isAvailable())?0:1]; - } - case "host.enabled": { - return defaults(responses, ChatColor.GREEN+"Enabled", ChatColor.RED+"Disabled") [(host.isEnabled())?0:1]; - } - case "host.address": { - return host.getAddress().getHostAddress(); - } - case "host.creator.template": - case "host.subcreator.template": - case "host.creator.templates": - case "host.subcreator.templates": { - return Integer.toString(host.getCreator().getTemplates().size()); - } - case "host.creator.template.displayname": - case "host.subcreator.template.displayname": { - SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; - if (template != null) return template.getDisplayName(); - else return null; - } - case "host.creator.template.enabled": - case "host.subcreator.template.enabled": { - SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; - if (template != null) return defaults(responses, ChatColor.GREEN+"Enabled", ChatColor.RED+"Disabled") [((template.isEnabled())?0:1)]; - else return null; - } - case "host.creator.template.type": - case "host.subcreator.template.type": { - SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; - if (template != null) return template.getType().toString(); - else return null; - } - case "host.creator.template.requiresversion": - case "host.subcreator.template.requiresversion": { - SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; - if (template != null) return defaults(responses, ChatColor.GREEN+"Optional", ChatColor.YELLOW+"Required") [((template.requiresVersion())?1:0)]; - else return null; - } - case "host.creator.template.updatable": - case "host.subcreator.template.updatable": { - SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; - if (template != null) return defaults(responses, ChatColor.GREEN+"Updatable", ChatColor.RED+"Not Updatable") [((template.canUpdate())?0:1)]; - else return null; - } - case "host.servers": - case "host.subservers": { - return Integer.toString(host.getSubServers().size()); - } - case "host.players": { - return Integer.toString(host.getRemotePlayers().size()); - } - case "host.subdata": { - return defaults(responses, ChatColor.GREEN+"Connected", ChatColor.YELLOW+"Unsupported", ChatColor.RED+"Disconnected") [(host.getSubData().length <= 0)?1:((host.getSubData()[0] == null)?2:0)]; - } - case "host.subdata.channels": - case "host.subdata.subchannels": { - return Integer.toString(Math.max(host.getSubData().length - ((method.endsWith(".subchannels"))?1:0), 0)); - } - case "host.signature": { - return host.getSignature(); - } - case "group": - case "groups": { - return Integer.toString(cache.getGroups().size()); - } - case "group.servers": { - return Integer.toString((group == null)?0:group.value().size()); - } - case "group.players": { - int i = 0; - if (group != null) for (Server s : group.value()) i += s.getRemotePlayers().size(); - return Integer.toString(i); - } - case "server": - case "servers": { - return Integer.toString(cache.getServers().size()); - } - case "server.displayname": - case "subserver.displayname": { - return server.getDisplayName(); - } - case "server.type": - case "subserver.type": { - return defaults(responses, "Subserver", "Server") [((server instanceof SubServer)?0:1)]; - } - case "server.groups": - case "subserver.groups": { - return Integer.toString(server.getGroups().size()); - } - case "server.address": - case "subserver.address": { - return server.getAddress().getAddress().getHostAddress() + ':' + server.getAddress().getPort(); - } - case "server.motd": - case "subserver.motd": { - return server.getMotd(); - } - case "server.restricted": - case "subserver.restricted": { - return defaults(responses, ChatColor.GREEN+"Public", ChatColor.RED+"Private") [(server.isRestricted())?1:0]; - } - case "server.hidden": - case "subserver.hidden": { - return defaults(responses, ChatColor.GREEN+"Visible", ChatColor.RED+"Hidden") [(server.isHidden())?1:0]; - } - case "server.players": - case "subserver.players": { - return Integer.toString(server.getRemotePlayers().size()); - } - case "server.subdata": - case "subserver.subdata": { - return defaults(responses, ChatColor.GREEN+"Connected", ChatColor.RED+"Disconnected") [(server.getSubData()[0] == null)?1:0]; - } - case "server.subdata.channels": - case "subserver.subdata.channels": - case "server.subdata.subchannels": - case "subserver.subdata.subchannels": { - return Integer.toString(server.getSubData().length - ((method.endsWith(".subchannels"))?1:0)); - } - case "server.signature": - case "subserver.signature": { - return server.getSignature(); - } - case "subserver": - case "subservers": { - return Integer.toString(cache.getSubServers().size()); - } - case "subserver.available": { - return defaults(responses, ChatColor.GREEN+"Available", ChatColor.RED+"Unavailable") [(subserver.isAvailable())?0:1]; - } - case "subserver.enabled": { - return defaults(responses, ChatColor.GREEN+"Enabled", ChatColor.RED+"Disabled") [(subserver.isEnabled())?0:1]; - } - case "subserver.editable": { - return defaults(responses, ChatColor.GREEN+"Editable", ChatColor.RED+"Locked") [(subserver.isEditable())?0:1]; - } - case "subserver.running": { - return defaults(responses, ChatColor.GREEN+"Running", ChatColor.RED+"Offline") [(subserver.isRunning())?0:1]; - } - case "subserver.online": { - return defaults(responses, ChatColor.GREEN+"Online", ChatColor.YELLOW+"Starting", ChatColor.RED+"Offline") [(subserver.isOnline())?0:((subserver.isRunning())?1:2)]; - } - case "subserver.logging": { - return defaults(responses, ChatColor.GREEN+"Logging", ChatColor.RED+"Muted") [(subserver.isLogging())?0:1]; - } - case "subserver.temporary": { - return defaults(responses, ChatColor.GREEN+"Permanent", ChatColor.AQUA+"Temporary") [ - (subserver.getStopAction() == SubServer.StopAction.REMOVE_SERVER || subserver.getStopAction() == SubServer.StopAction.RECYCLE_SERVER || subserver.getStopAction() == SubServer.StopAction.DELETE_SERVER)?1:0 - ]; - } - case "subserver.stopaction": { - return subserver.getStopAction().toString(); - } - case "subserver.incompatibilities": - case "subserver.incompatibilities.current": { - List list = (method.endsWith(".current"))?subserver.getCurrentIncompatibilities():subserver.getIncompatibilities(); - return Integer.toString(list.size()); - } - default: { - return null; - } - } - } - - private static String[] defaults(String[] overrides, String... defaults) { - for (int i = 0; i < defaults.length; ++i) { - defaults[i] = (((i < overrides.length && overrides[i].length() > 0)?overrides:defaults)[i]); - } - return defaults; - } - - private final class Cache { - private HashMap proxies = new HashMap(); - private HashMap hosts = new HashMap(); - private HashMap servers = new HashMap(); - private Proxy master = null; - private Listener events = new Events(); - - private void reset() { - proxies.clear(); - hosts.clear(); - servers.clear(); - master = null; - } - - private void refresh() { - if (SubAPI.getInstance().getSubDataNetwork()[0] != null) { - SubAPI.getInstance().getProxies(proxies -> { - this.proxies = new HashMap<>(proxies); - }); - SubAPI.getInstance().getMasterProxy(master -> { - this.master = master; - }); - SubAPI.getInstance().getHosts(hosts -> { - this.hosts = new HashMap<>(hosts); - }); - SubAPI.getInstance().getServers(servers -> { - this.servers = new HashMap<>(servers); - }); - } - } - - private final class Events implements Listener { - private HashMap edits = new HashMap(); - - @EventHandler - public void add(SubAddProxyEvent e) { - SubAPI.getInstance().getProxy(e.getProxy(), proxy -> { - if (proxy != null) proxies.put(proxy.getName().toLowerCase(), proxy); - }); - } - - @EventHandler - public void add(SubAddHostEvent e) { - SubAPI.getInstance().getHost(e.getHost(), host -> { - if (host != null) hosts.put(host.getName().toLowerCase(), host); - }); - } - - @EventHandler - public void add(SubAddServerEvent e) { - add(e.getServer()); - } - - public void add(String s) { - SubAPI.getInstance().getServer(s, server -> { - if (server != null) servers.put(server.getName().toLowerCase(), server); - }); - } - - @EventHandler - public void edit(SubEditServerEvent e) { - String s = e.getServer().toLowerCase(); - if (edits.keySet().contains(s)) edits.get(s).cancel(); - edits.put(s, Bukkit.getScheduler().runTaskLater(plugin, () -> add(s), 120L)); - } - - @EventHandler - public void start(SubStartEvent e) { - Server server = getServer(e.getServer()); - if (server != null) { - Try.all.run(() -> Util.>reflect(Server.class.getDeclaredField("raw"), server).set("running", true)); - add(e.getServer()); - } - } - - @EventHandler - public void started(SubStartedEvent e) { - Server server = getServer(e.getServer()); - if (server != null) { - Try.all.run(() -> Util.>reflect(Server.class.getDeclaredField("raw"), server).set("online", true)); - add(e.getServer()); - } - } - - @EventHandler - public void stopped(SubStoppedEvent e) { - Server server = getServer(e.getServer()); - if (server != null) Try.all.run(() -> { - ObjectMap raw = Util.reflect(Server.class.getDeclaredField("raw"), server); - raw.set("online", false); - raw.set("running", false); - add(e.getServer()); - }); - } - } - - public Map getProxies() { - return proxies; - } - - public Proxy getProxy(String name) { - Util.nullpo(name); - Proxy proxy = getProxies().getOrDefault(name.toLowerCase(), null); - if (proxy == null && master != null && master.getName().equalsIgnoreCase(name)) proxy = master; - return proxy; - } - - public Proxy getMasterProxy() { - return master; - } - - private Map getHosts() { - return hosts; - } - - private Host getHost(String name) { - Util.nullpo(name); - return getHosts().get(name.toLowerCase()); - } - - public Map> getGroups() { - TreeMap> groups = new TreeMap>(); - HashMap conflitresolver = new HashMap(); - for (Server server : getServers().values()) { - for (String name : server.getGroups()) { - String group = name; - if (conflitresolver.keySet().contains(name.toLowerCase())) { - group = conflitresolver.get(name.toLowerCase()); - } else { - conflitresolver.put(name.toLowerCase(), name); - } - List list = (groups.keySet().contains(group))?groups.get(group):new ArrayList(); - list.add(server); - groups.put(group, list); - } - } - return groups; - } - - public Map> getLowercaseGroups() { - Map> groups = getGroups(); - TreeMap> lowercaseGroups = new TreeMap>(); - for (String key : groups.keySet()) { - lowercaseGroups.put(key.toLowerCase(), groups.get(key)); - } - return lowercaseGroups; - } - - public Pair> getGroup(String name) { - Util.nullpo(name); - for (Map.Entry> group : getLowercaseGroups().entrySet()) { - if (group.getKey().equalsIgnoreCase(name)) return new ContainedPair<>(group.getKey(), group.getValue()); - } - return null; - } - - public Map getServers() { - return servers; - } - - public Server getServer(String name) { - Util.nullpo(name); - return getServers().get(name.toLowerCase()); - } - - public Map getSubServers() { - TreeMap servers = new TreeMap(); - for (Map.Entry server : this.servers.entrySet()) { - if (server.getValue() instanceof SubServer) servers.put(server.getKey(), (SubServer) server.getValue()); - } - return servers; - } - - public SubServer getSubServer(String name) { - Util.nullpo(name); - return getSubServers().get(name.toLowerCase()); - } + return plugin.phi.request(player, request); } } diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Placeholders.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Placeholders.java new file mode 100644 index 00000000..c124d6ef --- /dev/null +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Library/Placeholders.java @@ -0,0 +1,785 @@ +package net.ME1312.SubServers.Client.Bukkit.Library; + +import net.ME1312.Galaxi.Library.Access; +import net.ME1312.Galaxi.Library.AsyncConsolidator; +import net.ME1312.Galaxi.Library.Container.ContainedPair; +import net.ME1312.Galaxi.Library.Container.Pair; +import net.ME1312.Galaxi.Library.Map.ObjectMap; +import net.ME1312.Galaxi.Library.Try; +import net.ME1312.Galaxi.Library.Util; +import net.ME1312.SubServers.Client.Bukkit.Event.*; +import net.ME1312.SubServers.Client.Bukkit.SubAPI; +import net.ME1312.SubServers.Client.Bukkit.SubPlugin; +import net.ME1312.SubServers.Client.Common.Network.API.*; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.OfflinePlayer; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.scheduler.BukkitTask; + +import java.lang.invoke.MethodHandle; +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Placeholder Executor Class + */ +public final class Placeholders { + private final CopyOnWriteArrayList listeners; + private final SubPlugin plugin; + public final Cache cache; + private MethodHandle papi; + private BukkitTask task; + private boolean init; + + /** + * Create a Placeholder Executor Instance + * + * @param plugin SubPlugin + */ + public Placeholders(SubPlugin plugin) { + this.plugin = plugin; + this.listeners = new CopyOnWriteArrayList<>(); + this.cache = new Cache(); + this.init = false; + } + + public void start() { + if (!init) { + init = true; + papi = Try.all.get(() -> Access.shared.type(Class.forName("me.clip.placeholderapi.PlaceholderAPI")).method(String.class, "setPlaceholders").parameters(OfflinePlayer.class, String.class).handle()); + Bukkit.getPluginManager().registerEvents(cache.events, plugin); + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> { + if (task == null) { + int interval = plugin.config.get().getMap("Settings").getInt("PlaceholderAPI-Cache-Interval", 30); + int start = interval - new Random().nextInt(interval + 1); // Don't have all servers request at the same time + Runnable task = () -> cache.refresh(() -> { + for (Runnable listener : listeners) { + try { + listener.run(); + } catch (Throwable e) { + e.printStackTrace(); + } + } + }); + this.task = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, task, 20L * start, 20L * interval); + task.run(); + } + }, 120L); + } + } + + public void stop() { + if (task != null) { + try { + task.cancel(); + } catch (Throwable exception) {} + task = null; + } + } + + public void clear() { + cache.reset(); + } + + public void listen(Runnable task) { + listeners.add(task); + } + + public String request(OfflinePlayer player, String request) { + boolean colored = !request.startsWith("plain_"); + if (!colored || request.startsWith("color_")) request = request.substring(6); + if (!init) start(); + + String response = runMethod(player, request); + + if (response != null && !colored) { + return ChatColor.stripColor(response); + } else { + return response; + } + } + + private static final Pattern replacements = Pattern.compile("#?([^\\s#]+?\\(.*?\\))|\\$([^$]+)\\$", Pattern.CASE_INSENSITIVE); + private String[] arguments(OfflinePlayer player, String text, boolean replace) { + LinkedList arguments = new LinkedList<>(); + + if (text != null && !text.isEmpty()) { + Pattern p = replacements; + Matcher m = p.matcher(text); + + StringBuilder argument = new StringBuilder(); + while (m.find()) { + String[] replacement = findMethod(player, text, m.start(), replace); + + if (replacement[0].contains(",")) { + String[] s = replacement[0].split(","); + argument.append(s[0]); + arguments.add(argument.toString().trim()); + + for (int i = 1; i < s.length - 1; ++i) { + arguments.add(s[i].trim()); + } + + argument = new StringBuilder(); + argument.append(s[s.length - 1]); + } else { + argument.append(replacement[0]); + } + + argument.append(replacement[1]); + + text = replacement[2]; + m = p.matcher(text); + } + + if (text.contains(",")) { + String[] s = text.split(","); + argument.append(s[0]); + arguments.add(argument.toString().trim()); + argument = null; + + for (int i = 1; i < s.length; ++i) { + arguments.add(s[i].trim()); + } + } else if (text.length() > 0) { + argument.append(text); + } + + if (argument != null && argument.length() > 0) { + arguments.add(argument.toString().trim()); + } + } + + return arguments.toArray(new String[0]); + } + + public String replace(OfflinePlayer player, String text) { + if (text != null) { + Pattern p = replacements; + Matcher m = p.matcher(text); + + StringBuilder str = new StringBuilder(); + while (m.find()) { + String[] replacement = findMethod(player, text, m.start(), true); + + str.append(replacement[0]); + str.append(replacement[1]); + + text = replacement[2]; + m = p.matcher(text); + } + + str.append(text); + return str.toString(); + } else { + return null; + } + } + + private String[] findMethod(OfflinePlayer player, String text, int start, boolean run) { + String[] values = new String[3]; + values[0] = text.substring(0, start); + text = text.substring(start); + + int[] open = {'(', '<'}; + int[] close = {')', '>'}; + Arrays.sort(open); + Arrays.sort(close); + + int i = -1; + if (text.codePointAt(0) == '$') { + Matcher m = Pattern.compile("^\\$([^$]+)\\$", Pattern.CASE_INSENSITIVE).matcher(text); + if (m.find()) { + String str = '%' + m.group(1) + '%'; + text = text.substring(m.end()); + if (run) { + String response = (papi == null)?null:Try.all.get(() -> (String) papi.invokeExact(player, str)); + values[1] = (response == null)?m.group():response; + } else { + values[1] = m.group(); + } + } + } else { + ++i; + boolean responses = false; + StringBuilder str = new StringBuilder(); + for (int level = 0; i < text.codePoints().count(); ++i) { + int c = text.codePointAt(i); + str.appendCodePoint(c); + + if (Arrays.binarySearch(open, c) >= 0) { + ++level; + } else if (Arrays.binarySearch(close, c) >= 0) { + --level; + if (level <= 0) { + if (responses) break; + boolean more = false; + for (int ix = i + 1; ix < text.codePoints().count(); ++ix) { + int cx = text.codePointAt(ix); + if (!Character.isWhitespace(cx) && cx != '_') { + more = cx == '<'; + break; + } + } + if (!more) break; + else responses = true; + } + } + } + if (run) { + String response = runMethod(player, str.toString()); + values[1] = (response == null)?str.toString():response; + } else { + values[1] = str.toString(); + } + } + + StringBuilder str = new StringBuilder(); + for (i += 1; i < text.codePoints().count(); ++i) { + str.appendCodePoint(text.codePointAt(i)); + } + values[2] = str.toString(); + + return values; + } + + private String[] parseMethod(OfflinePlayer player, String text) { + Matcher m = Pattern.compile("^#?(.+?)(?:[\\s_]*\\((.*?)\\))?(?:[\\s_]*<(.*)>)?$", Pattern.CASE_INSENSITIVE).matcher(text); + + if (m.find()) { + String[] values = new String[3]; + + values[0] = m.group(1); + if (m.group(2) == null || m.group(2).trim().isEmpty() || + m.group(3) == null || m.group(3).trim().isEmpty()) { + // Simple parsing: () or <> + values[1] = m.group(2); + values[2] = m.group(3); + } else { + // Complex parsing: () and <> + text = text.substring(m.end(1)); + int stage = 1, level = 0, i = 0; + char open = '(', close = ')'; + boolean responses = false; + StringBuilder str = new StringBuilder(); + for (; i < text.codePoints().count(); ++i) { + int c = text.codePointAt(i); + if (c == open) { + if (level > 0) str.appendCodePoint(c); + ++level; + } else if (c == close) { + --level; + if (level > 0) str.appendCodePoint(c); + else { + if (responses) break; + boolean more = false; + for (int ix = i + 1; ix < text.codePoints().count(); ++ix) { + int cx = text.codePointAt(ix); + if (!Character.isWhitespace(cx) && cx != '_') { + more = cx == '<'; + break; + } + } + if (!more) break; + else { + responses = true; + open = '<'; close = '>'; + values[stage++] = str.toString(); + str = new StringBuilder(); + } + } + } else { + if (level > 0) str.appendCodePoint(c); + } + } + values[stage] = str.toString(); + if (level > 0 || ++i < text.codePoints().count()) { + return null; + } + } + + return values; + } else { + return null; + } + } + + private String runMethod(OfflinePlayer player, String text) { + String[] parsed = parseMethod(player, text); + + if (parsed != null) { + String method = parsed[0]; + String[] args = arguments(player, parsed[1], true); + String[] responses = arguments(player, parsed[2], false); + + for (int i = 0; i < responses.length; ++i) + responses[i] = ChatColor.translateAlternateColorCodes('&', responses[i].trim()); + + return replace(player, runMethod(player, method, args, responses)); + } else { + return null; + } + } + + @SuppressWarnings("ConstantConditions") + private String runMethod(OfflinePlayer player, String method, String[] args, String[] responses) { + Server server = (plugin.api.getName() != null)? cache.getServer(plugin.api.getName()) : null; + SubServer subserver = (server instanceof SubServer)? (SubServer) server : null; + Pair> group = null; + Host host = (subserver != null)? cache.getHost(subserver.getHost()) : null; + Proxy proxy = cache.getMasterProxy(); + + method = method.toLowerCase(); + if (method.startsWith("proxy.")) { + if (args.length > 0 && !args[0].isEmpty()) proxy = cache.getProxy(args[0]); + if (proxy == null) return null; + } else if (method.startsWith("host.")) { + if (args.length > 0 && !args[0].isEmpty()) host = cache.getHost(args[0]); + if (host == null) return null; + } else if (method.startsWith("group.")) { + if (args.length > 0 && !args[0].isEmpty()) group = cache.getGroup(args[0]); +// if (group == null) return null; // Empty groups are null + } else if (method.startsWith("server.")) { + if (args.length > 0 && !args[0].isEmpty()) server = cache.getServer(args[0]); + if (server == null) return null; + } else if (method.startsWith("subserver.")) { + if (args.length > 0 && !args[0].isEmpty()) server = subserver = cache.getSubServer(args[0]); + if (subserver == null) return null; + } + + + // --- Methods where Objects link to other Objects -- + if (method.startsWith("subserver.host")) { + if (method.equals("subserver.host")) { + return subserver.getHost(); + } else { + LinkedList arguments = new LinkedList(); + arguments.addAll(Arrays.asList(args)); + if (args.length > 0) arguments.removeFirst(); + arguments.addFirst(subserver.getHost()); + return runMethod(player, method.substring(10), arguments.toArray(new String[0]), responses); + } + } else if (method.startsWith("subserver.template")) { + if (method.equals("subserver.template")) { + return (subserver.getTemplate() != null)?subserver.getTemplate():defaults(responses, "(custom)")[0]; + } else if (subserver.getTemplate() != null) { + LinkedList arguments = new LinkedList(); + arguments.addAll(Arrays.asList(args)); + if (args.length > 0) arguments.removeFirst(); + arguments.addFirst(subserver.getTemplate()); + arguments.addFirst(subserver.getHost()); + return runMethod(player, "host.creator." + method.substring(10), arguments.toArray(new String[0]), responses); + } else { + return null; + } + } else switch (method) { // --- Straight up Methods --- + case "example": { + return defaults(responses, ChatColor.LIGHT_PURPLE+"Example!")[0]; + } + case "players": { + int i = cache.getMasterProxy().getPlayers().size(); + for (Proxy p : cache.getProxies().values()) i += p.getPlayers().size(); + return Integer.toString(i); + } + case "proxy": + case "proxies": { + return Integer.toString(cache.getProxies().size() + 1); + } + case "proxy.displayname": { + return proxy.getDisplayName(); + } + case "proxy.type": { + return defaults(responses, "Master Proxy", "Proxy") [((proxy.isMaster())?0:1)]; + } + case "proxy.players": { + return Integer.toString(proxy.getPlayers().size()); + } + case "proxy.subdata": { + return defaults(responses, ChatColor.GREEN+"Connected", ChatColor.RED+"Disconnected") [(proxy.getSubData()[0] == null)?1:0]; + } + case "proxy.subdata.channels": + case "proxy.subdata.subchannels": { + return Integer.toString(proxy.getSubData().length - ((method.endsWith(".subchannels"))?1:0)); + } + case "proxy.signature": { + return proxy.getSignature(); + } + case "host": + case "hosts": { + return Integer.toString(cache.getHosts().size()); + } + case "host.displayname": { + return host.getDisplayName(); + } + case "host.available": { + return defaults(responses, ChatColor.GREEN+"Available", ChatColor.RED+"Unavailable") [(host.isAvailable())?0:1]; + } + case "host.enabled": { + return defaults(responses, ChatColor.GREEN+"Enabled", ChatColor.RED+"Disabled") [(host.isEnabled())?0:1]; + } + case "host.address": { + return host.getAddress().getHostAddress(); + } + case "host.creator.template": + case "host.subcreator.template": + case "host.creator.templates": + case "host.subcreator.templates": { + return Integer.toString(host.getCreator().getTemplates().size()); + } + case "host.creator.template.displayname": + case "host.subcreator.template.displayname": { + SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; + if (template != null) return template.getDisplayName(); + else return null; + } + case "host.creator.template.enabled": + case "host.subcreator.template.enabled": { + SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; + if (template != null) return defaults(responses, ChatColor.GREEN+"Enabled", ChatColor.RED+"Disabled") [((template.isEnabled())?0:1)]; + else return null; + } + case "host.creator.template.type": + case "host.subcreator.template.type": { + SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; + if (template != null) return template.getType().toString(); + else return null; + } + case "host.creator.template.requiresversion": + case "host.subcreator.template.requiresversion": { + SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; + if (template != null) return defaults(responses, ChatColor.GREEN+"Optional", ChatColor.YELLOW+"Required") [((template.requiresVersion())?1:0)]; + else return null; + } + case "host.creator.template.updatable": + case "host.subcreator.template.updatable": { + SubCreator.ServerTemplate template = (args.length > 1 && !args[1].isEmpty())? host.getCreator().getTemplate(args[1]) : null; + if (template != null) return defaults(responses, ChatColor.GREEN+"Updatable", ChatColor.RED+"Not Updatable") [((template.canUpdate())?0:1)]; + else return null; + } + case "host.servers": + case "host.subservers": { + return Integer.toString(host.getSubServers().size()); + } + case "host.players": { + return Integer.toString(host.getRemotePlayers().size()); + } + case "host.subdata": { + return defaults(responses, ChatColor.GREEN+"Connected", ChatColor.YELLOW+"Unsupported", ChatColor.RED+"Disconnected") [(host.getSubData().length <= 0)?1:((host.getSubData()[0] == null)?2:0)]; + } + case "host.subdata.channels": + case "host.subdata.subchannels": { + return Integer.toString(Math.max(host.getSubData().length - ((method.endsWith(".subchannels"))?1:0), 0)); + } + case "host.signature": { + return host.getSignature(); + } + case "group": + case "groups": { + return Integer.toString(cache.getGroups().size()); + } + case "group.servers": { + return Integer.toString((group == null)?0:group.value().size()); + } + case "group.players": { + int i = 0; + if (group != null) for (Server s : group.value()) i += s.getRemotePlayers().size(); + return Integer.toString(i); + } + case "server": + case "servers": { + return Integer.toString(cache.getServers().size()); + } + case "server.displayname": + case "subserver.displayname": { + return server.getDisplayName(); + } + case "server.type": + case "subserver.type": { + return defaults(responses, "Subserver", "Server") [((server instanceof SubServer)?0:1)]; + } + case "server.groups": + case "subserver.groups": { + return Integer.toString(server.getGroups().size()); + } + case "server.address": + case "subserver.address": { + return server.getAddress().getAddress().getHostAddress() + ':' + server.getAddress().getPort(); + } + case "server.motd": + case "subserver.motd": { + return server.getMotd(); + } + case "server.restricted": + case "subserver.restricted": { + return defaults(responses, ChatColor.GREEN+"Public", ChatColor.RED+"Private") [(server.isRestricted())?1:0]; + } + case "server.hidden": + case "subserver.hidden": { + return defaults(responses, ChatColor.GREEN+"Visible", ChatColor.RED+"Hidden") [(server.isHidden())?1:0]; + } + case "server.players": + case "subserver.players": { + return Integer.toString(server.getRemotePlayers().size()); + } + case "server.subdata": + case "subserver.subdata": { + return defaults(responses, ChatColor.GREEN+"Connected", ChatColor.RED+"Disconnected") [(server.getSubData()[0] == null)?1:0]; + } + case "server.subdata.channels": + case "subserver.subdata.channels": + case "server.subdata.subchannels": + case "subserver.subdata.subchannels": { + return Integer.toString(server.getSubData().length - ((method.endsWith(".subchannels"))?1:0)); + } + case "server.signature": + case "subserver.signature": { + return server.getSignature(); + } + case "subserver": + case "subservers": { + return Integer.toString(cache.getSubServers().size()); + } + case "subserver.available": { + return defaults(responses, ChatColor.GREEN+"Available", ChatColor.RED+"Unavailable") [(subserver.isAvailable())?0:1]; + } + case "subserver.enabled": { + return defaults(responses, ChatColor.GREEN+"Enabled", ChatColor.RED+"Disabled") [(subserver.isEnabled())?0:1]; + } + case "subserver.editable": { + return defaults(responses, ChatColor.GREEN+"Editable", ChatColor.RED+"Locked") [(subserver.isEditable())?0:1]; + } + case "subserver.running": { + return defaults(responses, ChatColor.GREEN+"Running", ChatColor.RED+"Offline") [(subserver.isRunning())?0:1]; + } + case "subserver.online": { + return defaults(responses, ChatColor.GREEN+"Online", ChatColor.YELLOW+"Starting", ChatColor.RED+"Offline") [(subserver.isOnline())?0:((subserver.isRunning())?1:2)]; + } + case "subserver.logging": { + return defaults(responses, ChatColor.GREEN+"Logging", ChatColor.RED+"Muted") [(subserver.isLogging())?0:1]; + } + case "subserver.temporary": { + return defaults(responses, ChatColor.GREEN+"Permanent", ChatColor.AQUA+"Temporary") [ + (subserver.getStopAction() == SubServer.StopAction.REMOVE_SERVER || subserver.getStopAction() == SubServer.StopAction.RECYCLE_SERVER || subserver.getStopAction() == SubServer.StopAction.DELETE_SERVER)?1:0 + ]; + } + case "subserver.stopaction": { + return subserver.getStopAction().toString(); + } + case "subserver.incompatibilities": + case "subserver.incompatibilities.current": { + List list = (method.endsWith(".current"))?subserver.getCurrentIncompatibilities():subserver.getIncompatibilities(); + return Integer.toString(list.size()); + } + default: { + return null; + } + } + } + + private static String[] defaults(String[] overrides, String... defaults) { + for (int i = 0; i < defaults.length; ++i) { + defaults[i] = (((i < overrides.length && overrides[i].length() > 0)?overrides:defaults)[i]); + } + return defaults; + } + + public final class Cache { + private HashMap proxies = new HashMap(); + private HashMap hosts = new HashMap(); + private HashMap servers = new HashMap(); + private Proxy master = null; + private Listener events = new Events(); + + private void reset() { + proxies.clear(); + hosts.clear(); + servers.clear(); + master = null; + } + + private void refresh(Runnable callback) { + if (SubAPI.getInstance().getSubDataNetwork()[0] != null) { + AsyncConsolidator async = new AsyncConsolidator(callback); + async.reserve(4); + SubAPI.getInstance().getProxies(proxies -> { + this.proxies = new HashMap<>(proxies); + async.release(); + }); + SubAPI.getInstance().getMasterProxy(master -> { + this.master = master; + async.release(); + }); + SubAPI.getInstance().getHosts(hosts -> { + this.hosts = new HashMap<>(hosts); + async.release(); + }); + SubAPI.getInstance().getServers(servers -> { + this.servers = new HashMap<>(servers); + async.release(); + }); + } + } + + private final class Events implements Listener { + private HashMap edits = new HashMap(); + + @EventHandler + public void add(SubAddProxyEvent e) { + SubAPI.getInstance().getProxy(e.getProxy(), proxy -> { + if (proxy != null) proxies.put(proxy.getName().toLowerCase(), proxy); + }); + } + + @EventHandler + public void add(SubAddHostEvent e) { + SubAPI.getInstance().getHost(e.getHost(), host -> { + if (host != null) hosts.put(host.getName().toLowerCase(), host); + }); + } + + @EventHandler + public void add(SubAddServerEvent e) { + add(e.getServer()); + } + + public void add(String s) { + SubAPI.getInstance().getServer(s, server -> { + if (server != null) servers.put(server.getName().toLowerCase(), server); + }); + } + + @EventHandler + public void edit(SubEditServerEvent e) { + String s = e.getServer().toLowerCase(); + if (edits.keySet().contains(s)) edits.get(s).cancel(); + edits.put(s, Bukkit.getScheduler().runTaskLater(plugin, () -> add(s), 120L)); + } + + @EventHandler + public void start(SubStartEvent e) { + Server server = getServer(e.getServer()); + if (server != null) { + Try.all.run(() -> Util.>reflect(Server.class.getDeclaredField("raw"), server).set("running", true)); + add(e.getServer()); + } + } + + @EventHandler + public void started(SubStartedEvent e) { + Server server = getServer(e.getServer()); + if (server != null) { + Try.all.run(() -> Util.>reflect(Server.class.getDeclaredField("raw"), server).set("online", true)); + add(e.getServer()); + } + } + + @EventHandler + public void stopping(SubStopEvent e) { + Server server = getServer(e.getServer()); + if (server != null) { + Try.all.run(() -> Util.>reflect(Server.class.getDeclaredField("raw"), server).set("stopping", true)); + add(e.getServer()); + } + } + + @EventHandler + public void stopped(SubStoppedEvent e) { + Server server = getServer(e.getServer()); + if (server != null) Try.all.run(() -> { + ObjectMap raw = Util.reflect(Server.class.getDeclaredField("raw"), server); + raw.set("online", false); + raw.set("running", false); + raw.set("stopping", false); + add(e.getServer()); + }); + } + } + + public Map getProxies() { + return proxies; + } + + public Proxy getProxy(String name) { + Util.nullpo(name); + Proxy proxy = getProxies().getOrDefault(name.toLowerCase(), null); + if (proxy == null && master != null && master.getName().equalsIgnoreCase(name)) proxy = master; + return proxy; + } + + public Proxy getMasterProxy() { + return master; + } + + private Map getHosts() { + return hosts; + } + + private Host getHost(String name) { + Util.nullpo(name); + return getHosts().get(name.toLowerCase()); + } + + public Map> getGroups() { + TreeMap> groups = new TreeMap>(); + HashMap conflitresolver = new HashMap(); + for (Server server : getServers().values()) { + for (String name : server.getGroups()) { + String group = name; + if (conflitresolver.keySet().contains(name.toLowerCase())) { + group = conflitresolver.get(name.toLowerCase()); + } else { + conflitresolver.put(name.toLowerCase(), name); + } + List list = (groups.keySet().contains(group))?groups.get(group):new ArrayList(); + list.add(server); + groups.put(group, list); + } + } + return groups; + } + + public Map> getLowercaseGroups() { + Map> groups = getGroups(); + TreeMap> lowercaseGroups = new TreeMap>(); + for (String key : groups.keySet()) { + lowercaseGroups.put(key.toLowerCase(), groups.get(key)); + } + return lowercaseGroups; + } + + public Pair> getGroup(String name) { + Util.nullpo(name); + for (Map.Entry> group : getLowercaseGroups().entrySet()) { + if (group.getKey().equalsIgnoreCase(name)) return new ContainedPair<>(group.getKey(), group.getValue()); + } + return null; + } + + public Map getServers() { + return servers; + } + + public Server getServer(String name) { + Util.nullpo(name); + return getServers().get(name.toLowerCase()); + } + + public Map getSubServers() { + TreeMap servers = new TreeMap(); + for (Map.Entry server : this.servers.entrySet()) { + if (server.getValue() instanceof SubServer) servers.put(server.getKey(), (SubServer) server.getValue()); + } + return servers; + } + + public SubServer getSubServer(String name) { + Util.nullpo(name); + return getSubServers().get(name.toLowerCase()); + } + } +} diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubCommand.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubCommand.java index add04403..75eaac29 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubCommand.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubCommand.java @@ -91,7 +91,7 @@ public final class SubCommand extends Command { } else { sender.sendMessage(plugin.api.getLang("SubServers", "Command.Version.Outdated").replace("$name$", "SubServers.Client.Bukkit").replace("$str$", updversion.toString()).replace("$int$", Integer.toString(updcount))); } - } catch (Exception e) {} + } catch (Throwable e) {} }); } else if (args[0].equalsIgnoreCase("list")) { if (Try.all.get(() -> Class.forName("net.md_5.bungee.api.chat.BaseComponent") != null, false) && sender instanceof Player) { @@ -236,9 +236,12 @@ public final class SubCommand extends Command { if (!(server instanceof SubServer) || ((SubServer) server).isRunning()) { sender.sendMessage(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "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(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Players") + ChatColor.AQUA + server.getRemotePlayers().size() + " online"); - } + } sender.sendMessage(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "MOTD") + ChatColor.WHITE + ChatColor.stripColor(server.getMotd())); - if (server instanceof SubServer && ((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Stop Action") + ChatColor.WHITE + ((SubServer) server).getStopAction().toString()); + if (server instanceof SubServer) { + if (((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Stop Action") + ChatColor.WHITE + ((SubServer) server).getStopAction().toString()); + if (((SubServer) server).isStopping()) sender.sendMessage(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Stopping") + ChatColor.GREEN+"yes"); + } sender.sendMessage(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Signature") + ChatColor.AQUA + server.getSignature()); if (server instanceof SubServer) sender.sendMessage(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Logging") + ((((SubServer) server).isLogging())?ChatColor.GREEN+"yes":ChatColor.RED+"no")); sender.sendMessage(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Restricted") + ((server.isRestricted())?ChatColor.GREEN+"yes":ChatColor.RED+"no")); @@ -860,7 +863,7 @@ public final class SubCommand extends Command { if (target == null || target == sender || sender.hasPermission("subservers.teleport-others")) { if (target == null) target = (Player) sender; - sender.sendMessage(plugin.api.getLang("SubServers", "Command.Teleport").replace("$str$", target.getName())); + sender.sendMessage(plugin.api.getLang("SubServers", (target == sender)?"Command.Teleport":"Command.Teleport.Others").replace("$name$", target.getName()).replace("$str$", server.getDisplayName())); plugin.pmc(target, "Connect", server.getName()); } else { sender.sendMessage(plugin.api.getLang("SubServers", "Command.Generic.Invalid-Permission").replace("$str$", "subservers.teleport-others")); diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubPlugin.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubPlugin.java index a5d4a036..a1ea4c04 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubPlugin.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubPlugin.java @@ -1,5 +1,6 @@ package net.ME1312.SubServers.Client.Bukkit; +import net.ME1312.Galaxi.Library.Access; import net.ME1312.Galaxi.Library.Config.YAMLConfig; import net.ME1312.Galaxi.Library.Config.YAMLSection; import net.ME1312.Galaxi.Library.Container.Pair; @@ -15,6 +16,8 @@ import net.ME1312.SubData.Client.Library.DisconnectReason; import net.ME1312.SubData.Client.SubDataClient; import net.ME1312.SubServers.Client.Bukkit.Graphic.DefaultUIHandler; import net.ME1312.SubServers.Client.Bukkit.Graphic.UIHandler; +import net.ME1312.SubServers.Client.Bukkit.Library.Compatibility.PlaceholderImpl; +import net.ME1312.SubServers.Client.Bukkit.Library.Placeholders; import net.ME1312.SubServers.Client.Bukkit.Library.ConfigUpdater; import net.ME1312.SubServers.Client.Bukkit.Library.Metrics; import net.ME1312.SubServers.Client.Bukkit.Network.SubProtocol; @@ -25,6 +28,7 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import java.io.*; +import java.lang.invoke.MethodHandle; import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.net.URL; @@ -50,13 +54,18 @@ public final class SubPlugin extends JavaPlugin { public UIHandler gui = null; public final Version version; public final SubAPI api = new SubAPI(this); + public final Placeholders phi = new Placeholders(this); public String server_address; + private MethodHandle gson; private long resetDate = 0; private boolean reconnect = false; - public SubPlugin() { + @SuppressWarnings("ConstantConditions") + public SubPlugin() throws Throwable { super(); + Class gson = Class.forName(((Try.all.get(() -> Class.forName("com.google.gson.Gson") != null, false)?"":"org.bukkit.craftbukkit.libs.")) + "com.google.gson.Gson"); + this.gson = Access.shared.type(gson).method("fromJson").instance(gson.newInstance()).parameters(String.class, Class.class).returns(Object.class).handle(); version = Version.fromString(getDescription().getVersion()); subdata.put(0, null); } @@ -65,7 +74,6 @@ public final class SubPlugin extends JavaPlugin { * Enable Plugin */ @Override - @SuppressWarnings("unchecked") public void onEnable() { try { Bukkit.getLogger().info("SubServers > Loading SubServers.Client.Bukkit v" + version.toString() + " Libraries (for Minecraft " + api.getGameVersion() + ")"); @@ -122,6 +130,7 @@ public final class SubPlugin extends JavaPlugin { gui = new DefaultUIHandler(this); if (api.access.value > NO_COMMANDS.value && !config.get().getMap("Settings").getBoolean("API-Only-Mode", false)) { + Bukkit.getPluginManager().registerEvents(new SubSigns(this, new File(dir, "signs.dat")), this); CommandMap cmd = Util.reflect(Bukkit.getServer().getClass().getDeclaredField("commandMap"), Bukkit.getServer()); cmd.register("subservers", new SubCommand(this, "subservers")); @@ -129,8 +138,9 @@ public final class SubPlugin extends JavaPlugin { cmd.register("subservers", new SubCommand(this, "sub")); } - if (api.access.value > NO_INTEGRATIONS.value && Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { - new net.ME1312.SubServers.Client.Bukkit.Library.Compatibility.PlaceholderImpl(this).register(); + if (api.access.value > NO_INTEGRATIONS.value) { + if (config.get().getMap("Settings").getBoolean("PlaceholderAPI-Ready", false)) phi.start(); + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) new PlaceholderImpl(this).register(); } new Metrics(this, 2334); @@ -150,9 +160,9 @@ public final class SubPlugin extends JavaPlugin { } } if (updcount > 0) Bukkit.getLogger().info("SubServers > SubServers.Client.Bukkit v" + updversion + " is available. You are " + updcount + " version" + ((updcount == 1)?"":"s") + " behind."); - } catch (Exception e) {} + } catch (Throwable e) {} }, 0, TimeUnit.DAYS.toSeconds(2) * 20); - } catch (Exception e) { + } catch (Throwable e) { e.printStackTrace(); } } @@ -220,7 +230,8 @@ public final class SubPlugin extends JavaPlugin { } subdata.clear(); subdata.put(0, null); - } catch (InterruptedException e) { + SubSigns.save(); + } catch (IOException | InterruptedException e) { e.printStackTrace(); } } @@ -230,17 +241,10 @@ public final class SubPlugin extends JavaPlugin { * * @param json JSON to parse * @return JSON as a map - * @throws NoSuchMethodException - * @throws IllegalAccessException - * @throws InvocationTargetException - * @throws InstantiationException - * @throws ClassNotFoundException */ @SuppressWarnings("unchecked") - public Map parseJSON(String json) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException { - Class gson = Class.forName(((Try.all.get(() -> Class.forName("com.google.gson.Gson") != null, false)?"":"org.bukkit.craftbukkit.libs.")) + "com.google.gson.Gson"); - //Class gson = com.google.gson.Gson.class; - return (Map) gson.getMethod("fromJson", String.class, Class.class).invoke(gson.newInstance(), json, Map.class); + public Map parseJSON(String json) throws Throwable { + return (Map) (Object) gson.invokeExact(json, Map.class); } /** diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubSigns.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubSigns.java new file mode 100644 index 00000000..0595cdcc --- /dev/null +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/SubSigns.java @@ -0,0 +1,271 @@ +package net.ME1312.SubServers.Client.Bukkit; + +import net.ME1312.SubData.Client.Library.EscapedOutputStream; +import net.ME1312.SubServers.Client.Bukkit.Event.SubStartEvent; +import net.ME1312.SubServers.Client.Bukkit.Event.SubStartedEvent; +import net.ME1312.SubServers.Client.Bukkit.Event.SubStopEvent; +import net.ME1312.SubServers.Client.Bukkit.Event.SubStoppedEvent; +import net.ME1312.SubServers.Client.Bukkit.Library.Compatibility.OfflineBlock; +import net.ME1312.SubServers.Client.Common.Network.API.SubServer; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.world.WorldLoadEvent; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map.Entry; +import java.util.UUID; + +/** + * SubServers Signs Class + */ +public class SubSigns implements Listener { + private static final HashMap data = new HashMap(); + private static HashMap signs = new HashMap(); + private static File file; + private final SubPlugin plugin; + private boolean active = false; + + SubSigns(SubPlugin plugin, File file) throws IOException { + this.plugin = plugin; + SubSigns.file = file; + load(); + } + + public static void save() throws IOException { + if (!data.isEmpty() || (file.exists() && !file.delete())) { + FileOutputStream raw = new FileOutputStream(file, false); + EscapedOutputStream escaped = new EscapedOutputStream(raw, '\u001B', '\u0003'); + for (Entry sign : data.entrySet()) { + raw.write(ByteBuffer.allocate(28).order(ByteOrder.BIG_ENDIAN) + .putLong(sign.getKey().world.getMostSignificantBits()) + .putLong(sign.getKey().world.getLeastSignificantBits()) + .putInt(sign.getKey().x) + .putInt(sign.getKey().y) + .putInt(sign.getKey().z) + .array() + ); + escaped.write(sign.getValue().getBytes(StandardCharsets.UTF_8)); + escaped.control('\u0003'); + } + } + } + + private void load() throws IOException { + if (file.exists()) { + FileInputStream in = new FileInputStream(file); + ByteArrayOutputStream string = new ByteArrayOutputStream(); + ByteBuffer magic = ByteBuffer.allocate(28).order(ByteOrder.BIG_ENDIAN); + + boolean escaped = false; + int b, i = 0; + while ((b = in.read()) != -1) { + if (i < 28) { + magic.put((byte) b); + ++i; + } else if (escaped) { + switch (b) { + case '\u001B': // [ESC] (Escape character) + string.write('\u001B'); + break; + case '\u0003': // [ETX] (End of String character) + magic.position(0); + String server = string.toString(StandardCharsets.UTF_8.name()); + OfflineBlock location = new OfflineBlock(new UUID(magic.getLong(), magic.getLong()), magic.getInt(), magic.getInt(), magic.getInt()); + Location loaded = location.load(); + if (loaded == null) { + data.put(location, server); + } else if (loaded.getBlock().getState() instanceof Sign) { + data.put(location, server); + signs.put(loaded, server); + } else { + Bukkit.getLogger().warning("SubServers > Removed invalid sign data: [\"" + loaded.getWorld().getName() + "\", " + location.x + ", " + location.y + ", " + location.z + "] -> \"" + server + '\"'); + } + magic.clear(); + string.reset(); + i = 0; + break; + default: + string.write('\u001B'); + string.write(b); + break; + } + escaped = false; + } else if (b == '\u001B') { + escaped = true; + } else { + string.write(b); + } + } + listen(); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void load(WorldLoadEvent e) { + UUID wid = e.getWorld().getUID(); + ArrayList removals = new ArrayList(); + HashMap signs = new HashMap(SubSigns.signs); + for (Entry sign : data.entrySet()) { + if (wid == sign.getKey().world) { + OfflineBlock location = sign.getKey(); + Location loaded = location.load(); + if (loaded.getBlock().getState() instanceof Sign) { + signs.put(loaded, sign.getValue()); + } else { + removals.add(sign.getKey()); + Bukkit.getLogger().warning("SubServers > Removed invalid sign data: [\"" + loaded.getWorld().getName() + "\", " + location.x + ", " + location.y + ", " + location.z + "] -> \"" + sign.getValue() + '\"'); + } + } + } + SubSigns.signs = signs; + for (OfflineBlock location : removals) { + data.remove(location); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void create(SignChangeEvent e) { + if (!e.isCancelled() && plugin.lang != null && e.getLine(0).trim().equalsIgnoreCase("[SubServers]")) { + Player player = e.getPlayer(); + String server = e.getLine(1).trim(); + if (server.length() > 0 && player.hasPermission("subservers.signs")) { + Location pos = e.getBlock().getLocation(); + if (pos.getBlock().getState() instanceof Sign) { + HashMap signs = new HashMap(SubSigns.signs); + signs.put(pos, server); + SubSigns.signs = signs; + data.put(new OfflineBlock(pos), server); + + listen(); + refresh(e.getBlock(), server, null); + Bukkit.getLogger().info("SubServers > Server sign created: [\"" + pos.getWorld().getName() + "\", " + pos.getBlockX() + ", " + pos.getBlockY() + ", " + pos.getBlockZ() + "] -> \"" + server + '\"'); + player.sendMessage(plugin.api.getLang("SubServers", "Signs.Create")); + } + } + } + } + + private void listen() { + if (!active && !signs.isEmpty()) { + active = true; + plugin.phi.listen(this::refresh); + plugin.phi.start(); + } + } + + private void refresh() { + if (plugin.lang != null) { + for (Entry pos : signs.entrySet()) { + refresh(pos.getKey().getBlock(), pos.getValue(), null); + } + } + } + + private void refresh(String name, String lang) { + if (plugin.lang != null) { + for (Entry pos : signs.entrySet()) { + if (pos.getValue().equalsIgnoreCase(name)) refresh(pos.getKey().getBlock(), pos.getValue(), lang); + } + } + } + + private void refresh(Block block, String name, String lang) { + if (block.getState() instanceof Sign) { + Sign sign = (Sign) block.getState(); + SubServer server = plugin.phi.cache.getSubServer(name); + if (lang == null) { + if (server == null) { + lang = "Signs.Text.Error"; + } else if (server.isStopping()) { + lang = "Signs.Text.Stopping"; + } else if (server.isOnline()) { + lang = "Signs.Text.Online"; + } else if (server.isRunning()) { + lang = "Signs.Text.Starting"; + } else { + lang = "Signs.Text.Offline"; + } + } + String[] text = plugin.phi.replace(null, plugin.api.getLang("SubServers", lang).replace("$str$", name)).split("\n", 4); + for (int i = 0; i < 4; ++i) if (i < text.length) { + sign.setLine(i, text[i]); + } else { + sign.setLine(i, ""); + } + Bukkit.getScheduler().runTask(plugin, sign::update); + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void interact(PlayerInteractEvent e) { + if (!e.isCancelled() && e.getClickedBlock() != null && plugin.lang != null && plugin.api.getSubDataNetwork()[0] != null && !plugin.api.getSubDataNetwork()[0].isClosed() && signs.containsKey(e.getClickedBlock().getLocation())) { + Player player = e.getPlayer(); + if ((e.getAction() == Action.RIGHT_CLICK_BLOCK || !player.hasPermission("subservers.signs")) && player.hasPermission("subservers.teleport")) { + SubServer server = plugin.phi.cache.getSubServer(signs.get(e.getClickedBlock().getLocation())); + if (server != null) { + if (!server.isRunning()) { + if (server.isEnabled() && server.isAvailable() && server.getCurrentIncompatibilities().size() == 0) server.start(); + } else if (!server.isStopping()) { + player.sendMessage(plugin.api.getLang("SubServers", "Command.Teleport").replace("$name$", player.getName()).replace("$str$", server.getDisplayName())); + plugin.pmc(player, "Connect", server.getName()); + } + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR) + public void delete(BlockBreakEvent e) { + if (!e.isCancelled() && e.getBlock().getState() instanceof Sign && signs.containsKey(e.getBlock().getLocation())) { + Player player = e.getPlayer(); + if (plugin.lang != null && player.hasPermission("subservers.signs")) { + Location pos = e.getBlock().getLocation(); + + HashMap signs = new HashMap(SubSigns.signs); + signs.remove(pos); + SubSigns.signs = signs; + data.remove(new OfflineBlock(pos)); + + player.sendMessage(plugin.api.getLang("SubServers", "Signs.Delete")); + } else { + e.setCancelled(true); + } + } + } + + @EventHandler + public void start(SubStartEvent e) { + refresh(e.getServer(), "Signs.Text.Starting"); + } + + @EventHandler + public void started(SubStartedEvent e) { + refresh(e.getServer(), "Signs.Text.Online"); + } + + @EventHandler + public void stopping(SubStopEvent e) { + refresh(e.getServer(), "Signs.Text.Stopping"); + } + + @EventHandler + public void stopped(SubStoppedEvent e) { + refresh(e.getServer(), "Signs.Text.Offline"); + } +} diff --git a/SubServers.Client/Bukkit/src/plugin.yml b/SubServers.Client/Bukkit/src/plugin.yml index be5f7a0c..032aa982 100644 --- a/SubServers.Client/Bukkit/src/plugin.yml +++ b/SubServers.Client/Bukkit/src/plugin.yml @@ -1,6 +1,6 @@ name: SubServers-Client-Bukkit main: net.ME1312.SubServers.Client.Bukkit.SubPlugin -version: "2.18a" +version: "2.18.2a" authors: ["ME1312"] softdepend: [TitleAPI, PlaceholderAPI] website: "https://github.com/ME1312/SubServers-2" @@ -19,18 +19,21 @@ permissions: description: "Access everything in SubServers.Client" default: op children: - subservers.interface: - description: "Access to the SubServers Interface" - default: op - subservers.command: - description: "Access to the SubServers Command" - default: op subservers.teleport: description: "Access to SubServers' Teleport Command" default: op subservers.teleport-others: description: "Access to Teleport other players using the Teleport Command" default: op + subservers.signs: + description: "Access to manage SubServers Signs" + default: op + subservers.command: + description: "Access to the SubServers Command" + default: op + subservers.interface: + description: "Access to the SubServers Interface" + default: op subservers.host.*: description: "Access to all Host Actions on all Hosts" default: op diff --git a/SubServers.Client/Common/pom.xml b/SubServers.Client/Common/pom.xml index 786f0ed6..6ab8c5db 100644 --- a/SubServers.Client/Common/pom.xml +++ b/SubServers.Client/Common/pom.xml @@ -18,13 +18,13 @@ net.ME1312.Galaxi GalaxiUtil - 21w50a + 22w11a compile net.ME1312.SubData Client - 21w50a + 22w11a compile diff --git a/SubServers.Client/Common/src/net/ME1312/SubServers/Client/Common/Network/API/SubServer.java b/SubServers.Client/Common/src/net/ME1312/SubServers/Client/Common/Network/API/SubServer.java index 66c7fcf3..8e64b301 100644 --- a/SubServers.Client/Common/src/net/ME1312/SubServers/Client/Common/Network/API/SubServer.java +++ b/SubServers.Client/Common/src/net/ME1312/SubServers/Client/Common/Network/API/SubServer.java @@ -335,6 +335,16 @@ public class SubServer extends Server { return raw.getBoolean("online"); } + /** + * If the Server is Stopping
+ * This method can only be true when the server is stopped through the server manager! + * + * @return Stopping Status + */ + public boolean isStopping() { + return raw.getBoolean("stopping"); + } + /** * Grabs the Host of the Server * diff --git a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubCommand.java b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubCommand.java index e1ae38b8..62784ae0 100644 --- a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubCommand.java +++ b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubCommand.java @@ -545,7 +545,10 @@ public final class SubCommand implements CommandExecutor { sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Players")).toBuilder().append(Text.builder(server.getRemotePlayers().size() + " online").color(TextColors.AQUA).build()).build()); } sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "MOTD")).toBuilder().append(Text.builder(server.getMotd().replaceAll("\\u00A7[0-9a-fA-Fk-oK-ORr]", "")).color(TextColors.WHITE).build()).build()); - if (server instanceof SubServer && ((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Stop Action")).toBuilder().append(Text.builder(((SubServer) server).getStopAction().toString()).color(TextColors.WHITE).build()).build()); + if (server instanceof SubServer) { + if (((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Stop Action")).toBuilder().append(Text.builder(((SubServer) server).getStopAction().toString()).color(TextColors.WHITE).build()).build()); + if (((SubServer) server).isStopping()) sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Stopping")).toBuilder().append(Text.builder("yes").color(TextColors.GREEN).build()).build()); + } sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Signature")).toBuilder().append(Text.builder(server.getSignature()).color(TextColors.AQUA).build()).build()); if (server instanceof SubServer) sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Logging")).toBuilder().append(Text.builder((((SubServer) server).isLogging())?"yes":"no").color((((SubServer) server).isLogging())?TextColors.GREEN:TextColors.RED).build()).build()); sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", "Command.Info.Format").replace("$str$", "Restricted")).toBuilder().append(Text.builder((server.isRestricted())?"yes":"no").color((server.isRestricted())?TextColors.GREEN:TextColors.RED).build()).build()); @@ -1224,7 +1227,7 @@ public final class SubCommand implements CommandExecutor { Value msg = new Container<>(false); Consumer action = target -> { if (target == sender || sender.hasPermission("subservers.teleport-others")) { - sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", "Command.Teleport").replace("$str$", target.getName()))); + sender.sendMessage(ChatColor.convertColor(plugin.api.getLang("SubServers", (target == sender)?"Command.Teleport":"Command.Teleport.Others").replace("$name$", target.getName()).replace("$str$", server.getDisplayName()))); plugin.pmc(target, "Connect", server.getName()); } else if (!msg.value()) { msg.value(true); diff --git a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubPlugin.java b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubPlugin.java index 25664b1e..7beb1f25 100644 --- a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubPlugin.java +++ b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/SubPlugin.java @@ -47,7 +47,7 @@ import static net.ME1312.SubServers.Client.Sponge.Library.AccessMode.NO_COMMANDS /** * SubServers Client Plugin Class */ -@Plugin(id = "subservers-client-sponge", name = "SubServers-Client-Sponge", authors = "ME1312", version = "2.18a", url = "https://github.com/ME1312/SubServers-2", description = "Take control of the server manager — from your servers") +@Plugin(id = "subservers-client-sponge", name = "SubServers-Client-Sponge", authors = "ME1312", version = "2.18.2a", url = "https://github.com/ME1312/SubServers-2", description = "Take control of the server manager — from your servers") public final class SubPlugin { HashMap subdata = new HashMap(); Pair>> lang = null; diff --git a/SubServers.Host/pom.xml b/SubServers.Host/pom.xml index 71cf606f..24743aa9 100644 --- a/SubServers.Host/pom.xml +++ b/SubServers.Host/pom.xml @@ -30,13 +30,13 @@ net.ME1312.Galaxi GalaxiEngine - 21w50a + 22w11a compile net.ME1312.Galaxi GalaxiUI - 21w50a + 22w11a runtime diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/ExHost.java b/SubServers.Host/src/net/ME1312/SubServers/Host/ExHost.java index 89dafeaf..89aaf61a 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/ExHost.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/ExHost.java @@ -42,7 +42,7 @@ import java.util.jar.Manifest; /** * SubServers.Host Main Class */ -@App(name = "SubServers.Host", version = "2.18a", authors = "ME1312", website = "https://github.com/ME1312/SubServers-2", description = "Host subservers on separate machines") +@App(name = "SubServers.Host", version = "2.18.2a", authors = "ME1312", website = "https://github.com/ME1312/SubServers-2", description = "Host subservers on separate machines") public final class ExHost { HashMap subdata = new HashMap(); Pair>> lang = null; diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/SubCommand.java b/SubServers.Host/src/net/ME1312/SubServers/Host/SubCommand.java index a2536ac7..be3e53ca 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/SubCommand.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/SubCommand.java @@ -226,7 +226,10 @@ public class SubCommand { sender.sendMessage(" -> Players: " + TextColor.AQUA + server.getRemotePlayers().size() + " online"); } sender.sendMessage(" -> MOTD: " + TextColor.WHITE + TextColor.stripColor(server.getMotd())); - if (server instanceof SubServer && ((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(" -> Stop Action: " + TextColor.WHITE + ((SubServer) server).getStopAction().toString()); + if (server instanceof SubServer) { + if (((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(" -> Stop Action: " + TextColor.WHITE + ((SubServer) server).getStopAction().toString()); + if (((SubServer) server).isStopping()) sender.sendMessage(" -> Stopping: " + TextColor.GREEN+"yes"); + } sender.sendMessage(" -> Signature: " + TextColor.AQUA + server.getSignature()); if (server instanceof SubServer) sender.sendMessage(" -> Logging: " + ((((SubServer) server).isLogging())?TextColor.GREEN+"yes":TextColor.RED+"no")); sender.sendMessage(" -> Restricted: " + ((server.isRestricted())?TextColor.GREEN+"yes":TextColor.RED+"no")); diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java index 724c3df4..e66f6f68 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/ExProxy.java @@ -74,7 +74,7 @@ public final class ExProxy extends BungeeCommon implements Listener { public final Plugin plugin; public final SubAPI api = new SubAPI(this); public SubProtocol subprotocol; - public static final Version version = Version.fromString("2.18a"); + public static final Version version = Version.fromString("2.18.2a"); public final boolean isPatched; public long lastReload = -1; diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/SubCommand.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/SubCommand.java index 98c7b32f..0ead02a7 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/SubCommand.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/SubCommand.java @@ -232,7 +232,10 @@ public final class SubCommand extends Command implements TabExecutor { sender.sendMessage(" -> Players: " + ChatColor.AQUA + server.getRemotePlayers().size() + " online"); } sender.sendMessage(" -> MOTD: " + ChatColor.WHITE + ChatColor.stripColor(server.getMotd())); - if (server instanceof SubServer && ((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(" -> Stop Action: " + ChatColor.WHITE + ((SubServer) server).getStopAction().toString()); + if (server instanceof SubServer) { + if (((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(" -> Stop Action: " + ChatColor.WHITE + ((SubServer) server).getStopAction().toString()); + if (((SubServer) server).isStopping()) sender.sendMessage(" -> Stopping: " + ChatColor.GREEN+"yes"); + } sender.sendMessage(" -> Signature: " + ChatColor.AQUA + server.getSignature()); if (server instanceof SubServer) sender.sendMessage(" -> Logging: " + ((((SubServer) server).isLogging())?ChatColor.GREEN+"yes":ChatColor.RED+"no")); sender.sendMessage(" -> Restricted: " + ((server.isRestricted())?ChatColor.GREEN+"yes":ChatColor.RED+"no")); diff --git a/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/ExProxy.java b/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/ExProxy.java index d9ad79a1..f943b8a4 100644 --- a/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/ExProxy.java +++ b/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/ExProxy.java @@ -64,7 +64,7 @@ import java.nio.charset.Charset; import java.util.*; import java.util.concurrent.TimeUnit; -@Plugin(id = "subservers-sync", name = "SubServers-Sync", authors = "ME1312", version = "2.18a", url = "https://github.com/ME1312/SubServers-2", description = "Dynamically sync player and server connection info over multiple proxy instances") +@Plugin(id = "subservers-sync", name = "SubServers-Sync", authors = "ME1312", version = "2.18.2a", url = "https://github.com/ME1312/SubServers-2", description = "Dynamically sync player and server connection info over multiple proxy instances") public class ExProxy { HashMap subdata = new HashMap(); diff --git a/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/SubCommand.java b/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/SubCommand.java index e509c92e..c5b5c871 100644 --- a/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/SubCommand.java +++ b/SubServers.Sync/velocity/src/net/ME1312/SubServers/Velocity/SubCommand.java @@ -237,7 +237,10 @@ public final class SubCommand implements SimpleCommand { 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 && ((SubServer) server).getStopAction() != SubServer.StopAction.NONE) sender.sendMessage(ChatColor.convertColor(" -> Stop Action: " + ChatColor.WHITE + ((SubServer) server).getStopAction().toString())); + 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")));