diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..fb1b0391 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# SubServers 2 Ignored Files + +*.iml + +## Directory-based project format: +.idea/ + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties + +# Hide Unfinished Project Files +# (none) + +# Hide Others +.DS_STORE \ No newline at end of file diff --git a/Artifacts/SubServers.Bungee.jar b/Artifacts/SubServers.Bungee.jar new file mode 100644 index 00000000..9f16b654 Binary files /dev/null and b/Artifacts/SubServers.Bungee.jar differ diff --git a/SubServers.Bungee/META-INF/MANIFEST.MF b/SubServers.Bungee/META-INF/MANIFEST.MF new file mode 100644 index 00000000..46365f90 --- /dev/null +++ b/SubServers.Bungee/META-INF/MANIFEST.MF @@ -0,0 +1,4 @@ +Manifest-Version: 1.0 +Class-Path: BungeeCord.jar +Main-Class: net.ME1312.SubServers.Proxy.Launch + diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubCreateEvent.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubCreateEvent.java new file mode 100644 index 00000000..13c6bc05 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubCreateEvent.java @@ -0,0 +1,7 @@ +package net.ME1312.SubServers.Proxy.Event; + +/** + * Created by christian on 12/4/16. + */ +public class SubCreateEvent { +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubSendCommandEvent.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubSendCommandEvent.java new file mode 100644 index 00000000..89ed41d6 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubSendCommandEvent.java @@ -0,0 +1,70 @@ +package net.ME1312.SubServers.Proxy.Event; + +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.md_5.bungee.api.plugin.Event; + +import java.util.UUID; + +public class SubSendCommandEvent extends Event { + private boolean cancelled = false; + private UUID player; + private SubServer server; + private String command; + + /** + * Server Start Event + * + * @param server Server Starting + * @param player Player Starting Server + */ + public SubSendCommandEvent(SubServer server, UUID player, String command) { + this.player = player; + this.server = server; + this.command = command; + } + + /** + * Gets the Server Effected + * @return The Server Effected + */ + public SubServer getServer() { return server; } + + /** + * Gets the player that Triggered the Event + * @return The Player that triggered this Event or Null if Console + */ + public UUID getPlayer() { return player; } + + /** + * Gets the Command to Send + * + * @return Command to Send + */ + public String getCommand() { + return command; + } + + /** + * Sets the Command to be Sent + * + * @param value Value + */ + public void setCommand(String value) { + + } + + /** + * Gets the Cancelled Status + * @return Cancelled Status + */ + public boolean isCancelled() { + return cancelled; + } + + /** + * Sets the Cancelled Status + */ + public void setCancelled(boolean value) { + cancelled = value; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubStartEvent.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubStartEvent.java new file mode 100644 index 00000000..04102a9b --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubStartEvent.java @@ -0,0 +1,50 @@ +package net.ME1312.SubServers.Proxy.Event; + +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.md_5.bungee.api.plugin.Event; + +import java.util.UUID; + +public class SubStartEvent extends Event { + private boolean cancelled = false; + private UUID player; + private SubServer server; + + /** + * Server Start Event + * + * @param server Server Starting + * @param player Player Starting Server + */ + public SubStartEvent(SubServer server, UUID player) { + this.player = player; + this.server = server; + } + + /** + * Gets the Server Effected + * @return The Server Effected + */ + public SubServer getServer() { return server; } + + /** + * Gets the player that Triggered the Event + * @return The Player that triggered this Event or Null if Console + */ + public UUID getPlayer() { return player; } + + /** + * Gets the Cancelled Status + * @return Cancelled Status + */ + public boolean isCancelled() { + return cancelled; + } + + /** + * Sets the Cancelled Status + */ + public void setCancelled(boolean value) { + cancelled = value; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubStopEvent.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubStopEvent.java new file mode 100644 index 00000000..23422f47 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubStopEvent.java @@ -0,0 +1,62 @@ +package net.ME1312.SubServers.Proxy.Event; + +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.md_5.bungee.api.plugin.Event; + +import java.util.UUID; + +public class SubStopEvent extends Event { + private boolean cancelled = false; + private UUID player; + private SubServer server; + private boolean force; + + /** + * Server Stop Event + * + * @param server Server Stopping + * @param player Player Stopping Server + * @param force If it was a Forced Shutdown + */ + public SubStopEvent(SubServer server, UUID player, boolean force) { + this.player = player; + this.server = server; + this.force = force; + } + + /** + * Gets the Server Effected + * @return The Server Effected + */ + public SubServer getServer() { return server; } + + /** + * Gets the player that Triggered the Event + * @return The Player that triggered this Event or Null if Console + */ + public UUID getPlayer() { return player; } + + /** + * Gets if it was a forced shutdown + * + * @return Forced Shutdown Status + */ + public boolean isForced() { + return force; + } + + /** + * Gets the Cancelled Status + * @return Cancelled Status + */ + public boolean isCancelled() { + return cancelled; + } + + /** + * Sets the Cancelled Status + */ + public void setCancelled(boolean value) { + cancelled = value; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubStoppedEvent.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubStoppedEvent.java new file mode 100644 index 00000000..d84c295c --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Event/SubStoppedEvent.java @@ -0,0 +1,23 @@ +package net.ME1312.SubServers.Proxy.Event; + +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.md_5.bungee.api.plugin.Event; + +public class SubStoppedEvent extends Event { + private SubServer server; + + /** + * Server Shell Exit Event + * + * @param server Server that Stopped + */ + public SubStoppedEvent(SubServer server) { + this.server = server; + } + + /** + * Gets the Server Effected + * @return The Server Effected + */ + public SubServer getServer() { return server; } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Executable.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Executable.java new file mode 100644 index 00000000..ff0003b1 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Executable.java @@ -0,0 +1,64 @@ +package net.ME1312.SubServers.Proxy.Host; + +import java.io.File; +import java.io.Serializable; + +/** + * Executable Variable Class + * + * @author ME1312 + */ +@SuppressWarnings("serial") +public class Executable implements Serializable { + public boolean isFile; + private File File; + private String Str; + /** + * New Executable + * + * @param exe Executable String or File Path + */ + public Executable(String exe) { + if (new File(exe).exists()) { + isFile = true; + File = new File(exe); + Str = exe; + } else { + isFile = false; + File = null; + Str = exe; + } + } + + /** + * New Executable + * + * @param Path File Path + */ + public Executable(File Path) { + isFile = true; + File = Path; + Str = Path.toString(); + } + + @Override + public String toString() { + String String; + if (isFile) { + String = File.toString(); + } else { + String = Str; + } + return String; + } + + /** + * Get Executable File + * + * @return File or Null if Executable isn't a file + */ + public File toFile() { + return File; + } + +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Host.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Host.java new file mode 100644 index 00000000..16c31100 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Host.java @@ -0,0 +1,203 @@ +package net.ME1312.SubServers.Proxy.Host; + +import net.ME1312.SubServers.Proxy.Libraries.Exception.InvalidServerException; +import net.ME1312.SubServers.Proxy.Libraries.UniversalFile; +import net.ME1312.SubServers.Proxy.SubPlugin; + +import java.io.File; +import java.net.InetAddress; +import java.util.Map; +import java.util.UUID; + +/** + * Host Layout Class + * + * @author ME1312 + */ +public abstract class Host { + + /** + * This constructor is required to launch your host from the drivers list. Do not add or remove any arguments. + * + * @param plugin SubServers Internals + * @param enabled If your host is enabled + * @param address The address of your host + * @param directory The runtime directory of your host + */ + public Host(SubPlugin plugin, String name, Boolean enabled, InetAddress address, UniversalFile directory) {} + + /** + * Is this Host Enabled? + * + * @return Enabled Status + */ + public abstract boolean isEnabled(); + + /** + * Set if this Host is Enabled + * + * @param value Value + */ + public abstract void setEnabled(boolean value); + + /** + * Get the Address of this Host + * + * @return Host Address + */ + public abstract InetAddress getAddress(); + + /** + * Get the Name of this Host + * + * @return Host Name + */ + public abstract String getName(); + + /** + * Starts the Servers Specified + * + * @param servers Servers + */ + public void start(String... servers) { + start(null, servers); + } + + /** + * Starts the Servers Specified + * + * @param player Player who started + * @param servers Servers + */ + public abstract void start(UUID player, String... servers); + + /** + * Stops the Servers Specified + * + * @param servers Servers + */ + public void stop(String... servers) { + stop(null, servers); + } + + /** + * Stops the Servers Specified + * + * @param player Player who started + * @param servers Servers + */ + public abstract void stop(UUID player, String... servers); + + /** + * Terminates the Servers Specified + * + * @param servers Servers + */ + public void terminate(String... servers) { + terminate(null, servers); + } + + /** + * Terminates the Servers Specified + * + * @param player Player who started + * @param servers Servers + */ + public abstract void terminate(UUID player, String... servers); + + /** + * Commands the Servers Specified + * + * @param command Command to send + * @param servers Servers + */ + public void command(String command, String... servers) { + command(null, command, servers); + } + + /** + * Commands the Servers Specified + * + * @param player Player who started + * @param command Command to send + * @param servers Servers + */ + public abstract void command(UUID player, String command, String... servers); + + /** + * Gets the SubCreator Instance for this Host + * + * @return SubCreator + */ + public abstract SubCreator getCreator(); + + /** + * Gets the SubServers on this Host + * + * @return SubServer Map + */ + public abstract Map getSubServers(); + + /** + * Gets a SubServer + * + * @param name SubServer Name + * @return a SubServer + */ + public abstract SubServer getSubServer(String name); + + /** + * Adds a SubServer + * + * @param player Player who Added + * @param name Name of Server + * @param enabled Enabled Status + * @param port Port Number + * @param motd Motd of the Server + * @param log Logging Status + * @param directory Directory + * @param executable Executable + * @param stopcmd Command to Stop the Server + * @param restart Auto Restart Status + * @param temporary Temporary Status + * @return The SubServer + * @throws InvalidServerException + */ + public abstract SubServer addSubServer(UUID player, String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean start, boolean restart, boolean temporary) throws InvalidServerException; + + /** + * Adds a SubServer + * + * @param name Name of Server + * @param enabled Enabled Status + * @param port Port Number + * @param motd Motd of the Server + * @param log Logging Status + * @param directory Directory + * @param executable Executable + * @param stopcmd Command to Stop the Server + * @param restart Auto Restart Status + * @param temporary Temporary Status + * @return The SubServer + * @throws InvalidServerException + */ + public SubServer addSubServer(String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean start, boolean restart, boolean temporary) throws InvalidServerException { + return addSubServer(null, name, enabled, port, motd, log, directory, executable, stopcmd, start, restart, temporary); + } + + /** + * Removes a SubServer + * + * @param name SubServer Name + * @throws InterruptedException + */ + public abstract void removeSubServer(String name) throws InterruptedException; + + /** + * Forces the Removal of a SubServer + * + * @param name SubServer Name + */ + public abstract void forceRemoveSubServer(String name); + +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalHost.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalHost.java new file mode 100644 index 00000000..d8d0d73f --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalHost.java @@ -0,0 +1,125 @@ +package net.ME1312.SubServers.Proxy.Host.Internal; + +import net.ME1312.SubServers.Proxy.Host.Executable; +import net.ME1312.SubServers.Proxy.Libraries.Exception.InvalidServerException; +import net.ME1312.SubServers.Proxy.Host.Host; +import net.ME1312.SubServers.Proxy.Host.SubCreator; +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.ME1312.SubServers.Proxy.Libraries.UniversalFile; +import net.ME1312.SubServers.Proxy.SubPlugin; + +import java.io.File; +import java.net.InetAddress; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; +import java.util.UUID; + +public class InternalHost extends Host { + private HashMap servers = new HashMap(); + + private String name; + private boolean enabled; + private InetAddress address; + private InternalSubCreator creator; + UniversalFile directory; + SubPlugin plugin; + + public InternalHost(SubPlugin plugin, String name, Boolean enabled, InetAddress address, UniversalFile directory) { + super(plugin, name, enabled, address, directory); + this.plugin = plugin; + this.name = name; + this.enabled = enabled; + this.address = address; + this.creator = new InternalSubCreator(this); + this.directory = directory; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean value) { + this.enabled = value; + } + + @Override + public InetAddress getAddress() { + return address; + } + + @Override + public String getName() { + return name; + } + + @Override + public void start(UUID player, String... servers) { + for (String server : servers) { + this.servers.get(server.toLowerCase()).start(player); + } + } + + @Override + public void stop(UUID player, String... servers) { + for (String server : servers) { + this.servers.get(server.toLowerCase()).stop(player); + } + } + + @Override + public void terminate(UUID player, String... servers) { + for (String server : servers) { + this.servers.get(server.toLowerCase()).terminate(player); + } + } + + @Override + public void command(UUID player, String command, String... servers) { + for (String server : servers) { + this.servers.get(server.toLowerCase()).command(player, command); + } + } + + @Override + public SubCreator getCreator() { + return creator; + } + + @Override + public Map getSubServers() { + return new TreeMap(servers); + } + + @Override + public SubServer getSubServer(String name) { + return servers.get(name.toLowerCase()); + } + + @Override + public SubServer addSubServer(UUID player, String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean start, boolean restart, boolean temporary) throws InvalidServerException { + if (plugin.getServers().keySet().contains(name.toLowerCase())) throw new InvalidServerException("A Server already exists with this name!"); + SubServer server = new InternalSubServer(this, name, enabled, port, motd, log, directory, executable, stopcmd, start, restart, temporary); + servers.put(name.toLowerCase(), server); + return server; + } + + @Override + public void removeSubServer(String name) throws InterruptedException { + if (getSubServer(name).isRunning()) { + getSubServer(name).stop(); + getSubServer(name).waitFor(); + } + servers.remove(name.toLowerCase()); + } + + @Override + public void forceRemoveSubServer(String name) { + if (getSubServer(name).isRunning()) { + getSubServer(name).terminate(); + } + servers.remove(name.toLowerCase()); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalSubCreator.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalSubCreator.java new file mode 100644 index 00000000..5b28ccb7 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalSubCreator.java @@ -0,0 +1,36 @@ +package net.ME1312.SubServers.Proxy.Host.Internal; + +import net.ME1312.SubServers.Proxy.Host.Host; +import net.ME1312.SubServers.Proxy.Host.SubCreator; +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; + +import java.io.File; +import java.util.UUID; + +public class InternalSubCreator extends SubCreator { + private Host host; + + public InternalSubCreator(Host host) { + this.host = host; + } + + @Override + public void create(UUID player, String name, int port, File directory, ServerType type, Version version, int memory) { + + } + + @Override + public void waitFor() throws InterruptedException { + + } + + @Override + public Host getHost() { + return host; + } + + @Override + public boolean isBusy() { + return false; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalSubLogger.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalSubLogger.java new file mode 100644 index 00000000..1d75eb3e --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalSubLogger.java @@ -0,0 +1,66 @@ +package net.ME1312.SubServers.Proxy.Host.Internal; + +import net.ME1312.SubServers.Proxy.Libraries.Container; + +import java.io.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class InternalSubLogger extends Thread { + InputStream is; + String name; + Container log; + PrintWriter writer = null; + + InternalSubLogger(InputStream is, String name, Container log, File file) { + this.is = is; + this.name = name; + this.log = log; + if (file != null) + try { + this.writer = new PrintWriter(file, "UTF-8"); + this.writer.println("---------- LOG START: " + name + " ----------"); + this.writer.flush(); + } catch (UnsupportedEncodingException | FileNotFoundException e) { + e.printStackTrace(); + } + } + + @Override + public void run() { + try { + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + String line = null; + while ((line = br.readLine()) != null) { + if (log.get() && !line.startsWith(">")) { + String msg = line; + /* REGEX Formatting + String type = "INFO"; + Matcher matcher = Pattern.compile("^((?:\\s*\\[?[0-9]{2}:[0-9]{2}:[0-9]{2}]?)?\\s*(?:\\[|\\[.*\\/)?(INFO|WARN|WARNING|ERROR|ERR|SEVERE)\\]:?\\s*)").matcher(msg); + while (matcher.find()) { + type = matcher.group(2); + } + */ + msg = msg.replaceAll("^((?:\\s*\\[?[0-9]{2}:[0-9]{2}:[0-9]{2}]?)?\\s*(?:\\[|\\[.*\\/)?(INFO|WARN|WARNING|ERROR|ERR|SEVERE)\\]:?\\s*)", ""); + + System.out.println(name + " > " + msg); + + if (writer != null) { + writer.println(line); + writer.flush(); + } + } + if (writer != null) { + writer.println(line); + writer.flush(); + } + } + } catch (IOException ioe) {} finally { + if (writer != null) { + writer.println("---------- END LOG ----------"); + writer.close(); + } + } + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalSubServer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalSubServer.java new file mode 100644 index 00000000..0c848dea --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Internal/InternalSubServer.java @@ -0,0 +1,229 @@ +package net.ME1312.SubServers.Proxy.Host.Internal; + +import net.ME1312.SubServers.Proxy.Event.SubSendCommandEvent; +import net.ME1312.SubServers.Proxy.Event.SubStartEvent; +import net.ME1312.SubServers.Proxy.Event.SubStopEvent; +import net.ME1312.SubServers.Proxy.Event.SubStoppedEvent; +import net.ME1312.SubServers.Proxy.Host.Executable; +import net.ME1312.SubServers.Proxy.Libraries.Container; +import net.ME1312.SubServers.Proxy.Libraries.Exception.InvalidServerException; +import net.ME1312.SubServers.Proxy.Host.Host; +import net.ME1312.SubServers.Proxy.Host.SubServer; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class InternalSubServer extends SubServer { + private InternalHost host; + private boolean enabled; + private Container log; + private File directory; + private Executable executable; + private String stopcmd; + private Process process; + private List queue; + private boolean restart; + private boolean temporary; + private InternalSubServer instance; + + public InternalSubServer(Host host, String name, boolean enabled, int port, String motd, boolean log, String directory, Executable executable, String stopcmd, boolean start, boolean restart, boolean temporary) throws InvalidServerException { + super(host, name, port, motd); + this.host = (InternalHost) host; + this.enabled = enabled; + this.log = new Container(log); + this.directory = new File(((InternalHost) host).directory, directory); + this.executable = executable; + this.stopcmd = stopcmd; + this.process = null; + this.queue = new ArrayList(); + this.restart = restart; + this.temporary = temporary; + this.instance = this; + + if (start || temporary) start(); + } + + private void run() { + new Thread() { + public void run() { + final Container allowRestart = new Container(true); + try { + process = Runtime.getRuntime().exec(executable.toString(), null, directory); + System.out.println("SubServers > Now starting " + instance.getName()); + final InternalSubLogger read = new InternalSubLogger(process.getInputStream(), instance.getName(), log, null); + read.start(); + final BufferedWriter cmd = new BufferedWriter(new OutputStreamWriter(process.getOutputStream())); + new Thread() { + @Override + public void run() { + try { + do { + if (!queue.isEmpty()) { + while (queue.size() > 0) { + try { + if (queue.get(0).equalsIgnoreCase(stopcmd)) allowRestart.set(false); + cmd.write(queue.get(0)); + cmd.newLine(); + cmd.flush(); + queue.remove(0); + Thread.sleep(100); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } + } + Thread.sleep(500); + + } while (read.isAlive()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }.start(); + try { + process.waitFor(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + allowRestart.set(false); + } + + SubStoppedEvent event = new SubStoppedEvent(instance); + host.plugin.getPluginManager().callEvent(event); + System.out.println("SubServers > " + instance.getName() + " has stopped"); + process = null; + queue.clear(); + + if (temporary) { + try { + host.removeSubServer(instance.getName()); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } else { + if (restart && allowRestart.get()) { + try { + Thread.sleep(2500); + start(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + }.start(); + } + + @Override + public void start(UUID player) { + if (enabled && !isRunning()) { + SubStartEvent event = new SubStartEvent(this, player); + host.plugin.getPluginManager().callEvent(event); + if (!event.isCancelled()) { + run(); + } + } + } + + @Override + public void stop(UUID player) { + if (isRunning()) { + SubStopEvent event = new SubStopEvent(this, player, false); + host.plugin.getPluginManager().callEvent(event); + if (!event.isCancelled()) { + queue.add(stopcmd); + } + } + } + + @Override + public void terminate(UUID player) { + if (isRunning()) { + SubStopEvent event = new SubStopEvent(this, player, true); + host.plugin.getPluginManager().callEvent(event); + if (!event.isCancelled()) { + process.destroyForcibly(); + } + } + } + + @Override + public void command(UUID player, String command) { + if (isRunning()) { + SubSendCommandEvent event = new SubSendCommandEvent(this, player, command); + host.plugin.getPluginManager().callEvent(event); + if (!event.isCancelled()) { + queue.add(command); + } + } + } + + @Override + public void waitFor() throws InterruptedException { + if (isRunning()) { + process.waitFor(); + } + } + + @Override + public boolean isRunning() { + return process != null && process.isAlive(); + } + + @Override + public Host getHost() { + return host; + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean value) { + enabled = value; + } + + @Override + public boolean isLogging() { + return log.get(); + } + + @Override + public void setLogging(boolean value) { + log.set(value); + } + + @Override + public String getStopCommand() { + return stopcmd; + } + + @Override + public void setStopCommand(String value) { + stopcmd = value; + } + + @Override + public boolean willAutoRestart() { + return restart; + } + + @Override + public void setAutoRestart(boolean value) { + restart = value; + } + + @Override + public boolean isTemporary() { + return temporary; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Server.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Server.java new file mode 100644 index 00000000..fe36c478 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/Server.java @@ -0,0 +1,38 @@ +package net.ME1312.SubServers.Proxy.Host; + +import net.ME1312.SubServers.Proxy.Libraries.Exception.InvalidServerException; +import net.ME1312.SubServers.Proxy.Network.Client; +import net.ME1312.SubServers.Proxy.Network.ClientHandler; +import net.md_5.bungee.BungeeServerInfo; +import net.md_5.bungee.api.ChatColor; + +import java.net.InetSocketAddress; + +/** + * Server Class + * + * @author ME1312 + */ +public class Server extends BungeeServerInfo implements ClientHandler { + private Client client = null; + + public Server(String name, InetSocketAddress address, String motd, boolean restricted) throws InvalidServerException { + super(name, address, ChatColor.translateAlternateColorCodes('&', motd), restricted); + if (name.contains(" ")) throw new InvalidServerException("Server names cannot have spaces: " + name); + } + + @Override + public Client getSubDataClient() { + return client; + } + + @Override + public void linkSubDataClient(Client client) { + if (this.client == null) { + client.setHandler(this); + this.client = client; + } else if (client == null) { + this.client = null; + } else throw new IllegalStateException("A SubData Client is already linked to Server: " + getName()); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/SubCreator.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/SubCreator.java new file mode 100644 index 00000000..c2607910 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/SubCreator.java @@ -0,0 +1,31 @@ +package net.ME1312.SubServers.Proxy.Host; + +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; + +import java.io.File; +import java.util.UUID; + +/** + * SubCreator Layout Class + * + * @author ME1312 + */ +public abstract class SubCreator { + public enum ServerType { + SPIGOT, + BUKKIT, + VANILLA, + SPONGE, + } + + public abstract void create(UUID player, String name, int port, File directory, ServerType type, Version version, int memory); + public void create(String name, int port, File directory, ServerType type, Version version, int memory) { + create(null, name, port, directory, type, version, memory); + } + + public abstract void waitFor() throws InterruptedException; + + public abstract Host getHost(); + + public abstract boolean isBusy(); +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/SubServer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/SubServer.java new file mode 100644 index 00000000..006a3972 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Host/SubServer.java @@ -0,0 +1,172 @@ +package net.ME1312.SubServers.Proxy.Host; + +import net.ME1312.SubServers.Proxy.Libraries.Exception.InvalidServerException; + +import java.net.InetSocketAddress; +import java.util.UUID; + +/** + * SubServer Layout Class + * + * @author ME1312 + */ +public abstract class SubServer extends Server { + + /** + * Creates a SubServer + * + * @param host Host + * @param name Server Name + * @param port Port Number + * @param motd Server MOTD + * @throws InvalidServerException + */ + public SubServer(Host host, String name, int port, String motd) throws InvalidServerException { + super(name, InetSocketAddress.createUnresolved(host.getAddress().getHostAddress(), port), motd, false); + } + + /** + * Starts the Server + * + * @param player Player who Started + */ + public abstract void start(UUID player); + + /** + * Starts the Server + */ + public void start() { + start(null); + } + + /** + * Stops the Server + * + * @param player Player who Stopped + */ + public abstract void stop(UUID player); + + /** + * Stops the Server + */ + public void stop() { + stop(null); + } + + /** + * Terminates the Server + * + * @param player Player who Terminated + */ + public abstract void terminate(UUID player); + + /** + * Terminates the Server + */ + public void terminate() { + terminate(null); + } + + /** + * Commands the Server + * + * @param player Player who Commanded + * @param command Command to Send + */ + public abstract void command(UUID player, String command); + + /** + * Commands the Server + * + * @param command Command to Send + */ + public void command(String command) { + command(null, command); + } + + /** + * Waits for the Server to Stop + * + * @throws InterruptedException + */ + public abstract void waitFor() throws InterruptedException; + + /** + * If the Server is Running + * + * @return Running Status + */ + public abstract boolean isRunning(); + + /** + * Grabs the Host of the Server + * + * @return The Host + */ + public abstract Host getHost(); + + /** + * If the Server is Enabled + * + * @return Enabled Status + */ + public abstract boolean isEnabled(); + + /** + * Set if the Server is Enabled + * + * @param value Value + */ + public abstract void setEnabled(boolean value); + + /** + * If the Server is Logging + * + * @return Logging Status + */ + public abstract boolean isLogging(); + + /** + * Set if the Server is Logging + * + * @param value Value + */ + public abstract void setLogging(boolean value); + + /** + * Grab the Command to Stop the Server + * + * @return Stop Command + */ + public abstract String getStopCommand(); + + /** + * Set the Command that Stops the Server + * + * @param value Value + */ + public abstract void setStopCommand(String value); + + /** + * If the Server will Auto Restart on unexpected shutdowns + * + * @return Auto Restart Status + */ + public abstract boolean willAutoRestart(); + + /** + * Set if the Server will Auto Restart on unexpected shutdowns + * + * @param value Value + */ + public abstract void setAutoRestart(boolean value); + + /** + * If the Server is Temporary + * + * @return Temporary Status + */ + public abstract boolean isTemporary(); + + +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Launch.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Launch.java new file mode 100644 index 00000000..57175e25 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Launch.java @@ -0,0 +1,90 @@ +package net.ME1312.SubServers.Proxy; + +import java.security.Security; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import joptsimple.OptionParser; +import joptsimple.OptionSet; +import net.md_5.bungee.Bootstrap; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.command.ConsoleCommandSender; + +/** + * SubServers/BungeeCord Class + * + * @author ME1312 + */ +public final class Launch { + + /** + * Launch SubServers/BungeeCord + * + * @param args + * @throws Exception + */ + public static void main(String[] args) throws Exception { + System.out.println(""); + System.out.println("*******************************************"); + System.out.println("*** Warning, this build is Unofficial ***"); + System.out.println("*** ***"); + System.out.println("*** Please report all issues to ME1312, ***"); + System.out.println("*** NOT the Spigot Staff! Thank You! ***"); + System.out.println("*******************************************"); + System.out.println(""); + + Security.setProperty("networkaddress.cache.ttl", "30"); + Security.setProperty("networkaddress.cache.negative.ttl", "10"); + OptionParser parser = new OptionParser(); + parser.allowsUnrecognizedOptions(); + parser.accepts("v"); + parser.accepts("version"); + parser.accepts("noconsole"); + OptionSet options = parser.parse(args); + if(options.has("version") || options.has("v")) { + System.out.println(Bootstrap.class.getPackage().getImplementationVersion()); + } else { + try { + if (BungeeCord.class.getPackage().getSpecificationVersion() != null) { + Date bungee = (new SimpleDateFormat("yyyyMMdd")).parse(BungeeCord.class.getPackage().getSpecificationVersion()); + Calendar line = Calendar.getInstance(); + line.add(3, -4); + if (bungee.before(line.getTime())) { + System.out.println("*******************************************"); + System.out.println("*** Warning, this build is outdated ***"); + System.out.println("*** Please download a new build from: ***"); + System.out.println("*** http://ci.md-5.net/job/BungeeCord ***"); + System.out.println("*** Errors may arise on older versions! ***"); + System.out.println("*******************************************"); + System.out.println(""); + } + } else throw new NullPointerException(); + } catch (Exception e) { + System.out.println("*******************************************"); + System.out.println("*** Problem checking BungeeCord Version ***"); + System.out.println("*** This build could be outdated. ***"); + System.out.println("*** ***"); + System.out.println("*** Errors may arise on older versions! ***"); + System.out.println("*******************************************"); + System.out.println(""); + } + + SubPlugin bungee = new SubPlugin(); + ProxyServer.setInstance(bungee); + bungee.getLogger().info("Enabled BungeeCord version " + bungee.getVersion()); + bungee.start(); + + String line; + if(!options.has("noconsole")) { + while(bungee.isRunning && (line = bungee.getConsoleReader().readLine(">")) != null) { + if(!bungee.getPluginManager().dispatchCommand(ConsoleCommandSender.getInstance(), line)) { + bungee.getConsole().sendMessage(ChatColor.RED + "Command not found"); + } + } + } + + } + } +} \ No newline at end of file diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Config/YAMLConfig.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Config/YAMLConfig.java new file mode 100644 index 00000000..40ff7ad1 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Config/YAMLConfig.java @@ -0,0 +1,65 @@ +package net.ME1312.SubServers.Proxy.Libraries.Config; + +import org.json.JSONObject; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.error.YAMLException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Map; + +@SuppressWarnings("unused") +public class YAMLConfig { + private File file; + private Yaml yaml; + private YAMLSection config; + + @SuppressWarnings("unchecked") + public YAMLConfig(File file) throws IOException, YAMLException { + if (file.exists()) { + this.config = new YAMLSection((Map) (this.yaml = new Yaml(getDumperOptions())).load(new FileInputStream(this.file = file)), null, null, yaml); + } else { + this.config = new YAMLSection(null, null, null, yaml); + } + } + + public YAMLSection get() { + return config; + } + + public void set(YAMLSection yaml) { + config = yaml; + } + + @SuppressWarnings("unchecked") + public void reload() throws IOException { + config = new YAMLSection((Map) yaml.load(new FileInputStream(file)), null, null, yaml); + } + + public void save() throws IOException { + FileWriter writer = new FileWriter(file); + yaml.dump(config.map, writer); + writer.close(); + } + + @Override + public String toString() { + return yaml.dump(config.map); + } + + public JSONObject toJSON() { + return new JSONObject(config.map); + } + + protected static DumperOptions getDumperOptions() { + DumperOptions options = new DumperOptions(); + options.setAllowUnicode(true); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + options.setIndent(4); + + return options; + } +} \ No newline at end of file diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Config/YAMLSection.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Config/YAMLSection.java new file mode 100644 index 00000000..f22edd25 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Config/YAMLSection.java @@ -0,0 +1,509 @@ +package net.ME1312.SubServers.Proxy.Libraries.Config; + +import net.md_5.bungee.api.ChatColor; +import org.json.JSONObject; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.error.YAMLException; + +import java.io.InputStream; +import java.io.Reader; +import java.util.*; + +@SuppressWarnings({"unchecked", "unused"}) +public class YAMLSection { + protected Map map; + protected String label = null; + protected YAMLSection up = null; + private Yaml yaml; + + public YAMLSection() { + this.map = new HashMap<>(); + this.yaml = new Yaml(YAMLConfig.getDumperOptions()); + } + + public YAMLSection(InputStream io) throws YAMLException { + this.map = (Map) (this.yaml = new Yaml(YAMLConfig.getDumperOptions())).load(io); + } + + public YAMLSection(Reader reader) throws YAMLException { + this.map = (Map) (this.yaml = new Yaml(YAMLConfig.getDumperOptions())).load(reader); + } + + public YAMLSection(String yaml) throws YAMLException { + this.map = (Map) (this.yaml = new Yaml(YAMLConfig.getDumperOptions())).load(yaml); + } + + protected YAMLSection(Map map, YAMLSection up, String label, Yaml yaml) { + this.map = new HashMap(); + this.yaml = yaml; + this.label = label; + this.up = up; + + if (map != null) { + for (String key : map.keySet()) { + this.map.put(key, map.get(key)); + } + } + } + + public Set getKeys() { + return map.keySet(); + } + + + public Collection getValues() { + List values = new ArrayList(); + for (String value : map.keySet()) { + values.add(new YAMLValue(map.get(value), this, value, yaml)); + } + return values; + } + + public boolean contains(String label) { + return map.keySet().contains(label); + } + + public void remove(String label) { + map.remove(label); + } + + public void clear() { + map.clear(); + } + + public void set(String label, Object value) { + if (value instanceof YAMLConfig) { // YAML Handler Values + ((YAMLConfig) value).get().up = this; + ((YAMLConfig) value).get().label = label; + map.put(label, ((YAMLConfig) value).get().map); + } else if (value instanceof YAMLSection) { + ((YAMLSection) value).up = this; + ((YAMLSection) value).label = label; + map.put(label, ((YAMLSection) value).map); + } else if (value instanceof YAMLValue) { + map.put(label, ((YAMLValue) value).asObject()); + } else { + map.put(label, value); + } + + if (this.label != null && this.up != null) { + this.up.set(this.label, this); + } + } + + public void setAll(Map values) { + for (String value : values.keySet()) { + set(value, values.get(value)); + } + } + + public void setAll(YAMLSection values) { + for (String value : values.map.keySet()) { + set(value, values.map.get(value)); + } + } + + public YAMLSection superSection() { + return up; + } + + @Override + public String toString() { + return yaml.dump(map); + } + + public JSONObject toJSON() { + return new JSONObject(map); + } + + public YAMLValue get(String label) { + return (map.get(label) != null)?(new YAMLValue(map.get(label), this, label, yaml)):null; + } + + public YAMLValue get(String label, Object def) { + return new YAMLValue((map.get(label) != null)?map.get(label):def, this, label, yaml); + } + + public YAMLValue get(String label, YAMLValue def) { + return (map.get(label) != null) ? (new YAMLValue(map.get(label), this, label, yaml)) : def; + } + + public List getList(String label) { + if (map.get(label) != null) { + List values = new ArrayList(); + for (Object value : (List) map.get(label)) { + values.add(new YAMLValue(value, null, null, yaml)); + } + return values; + } else { + return null; + } + } + + public List getList(String label, Collection def) { + if (map.get(label) != null) { + return getList(label); + } else { + List values = new ArrayList(); + for (Object value : def) { + values.add(new YAMLValue(value, null, null, yaml)); + } + return values; + } + } + + public List getList(String label, List def) { + if (map.get(label) != null) { + return getList(label); + } else { + List values = new ArrayList(); + for (YAMLValue value : def) { + values.add(value); + } + return values; + } + } + + public Object getObject(String label) { + return map.get(label); + } + + public Object getObject(String label, Object def) { + return (map.get(label) != null)?map.get(label):def; + } + + public List getObjectList(String label) { + return (List) map.get(label); + } + + public List getObjectList(String label, List def) { + return (List) ((map.get(label) != null)?map.get(label):def); + } + + public boolean getBoolean(String label) { + return (boolean) map.get(label); + } + + public boolean getBoolean(String label, boolean def) { + return (boolean) ((map.get(label) != null)?map.get(label):def); + } + + public List getBooleanList(String label) { + return (List) map.get(label); + } + + public List getBooleanList(String label, List def) { + return (List) ((map.get(label) != null)?map.get(label):def); + } + + public YAMLSection getSection(String label) { + return (map.get(label) != null)?(new YAMLSection((Map) map.get(label), this, label, yaml)):null; + } + + public YAMLSection getSection(String label, Map def) { + return new YAMLSection((Map) ((map.get(label) != null)?map.get(label):def), this, label, yaml); + } + + public YAMLSection getSection(String label, YAMLSection def) { + return (map.get(label) != null)?(new YAMLSection((Map) map.get(label), this, label, yaml)):def; + } + + public List getSectionList(String label) { + if (map.get(label) != null) { + List values = new ArrayList(); + for (Map value : (List>) map.get(label)) { + values.add(new YAMLSection(value, null, null, yaml)); + } + return values; + } else { + return null; + } + } + + public List getSectionList(String label, Collection> def) { + if (map.get(label) != null) { + return getSectionList(label); + } else { + List values = new ArrayList(); + for (Map value : def) { + values.add(new YAMLSection(value, null, null, yaml)); + } + return values; + } + } + + public List getSectionList(String label, List def) { + if (map.get(label) != null) { + return getSectionList(label); + } else { + List values = new ArrayList(); + for (YAMLSection value : def) { + values.add(value); + } + return values; + } + } + + public double getDouble(String label) { + return (double) map.get(label); + } + + public double getDouble(String label, double def) { + return (double) ((map.get(label) != null)?map.get(label):def); + } + + public List getDoubleList(String label) { + return (List) map.get(label); + } + + public List getDoubleList(String label, List def) { + return (List) ((map.get(label) != null)?map.get(label):def); + } + + public float getFloat(String label) { + return (float) map.get(label); + } + + public float getFloat(String label, float def) { + return (float) ((map.get(label) != null)?map.get(label):def); + } + + public List getFloatList(String label) { + return (List) map.get(label); + } + + public List getFloatList(String label, float def) { + return (List) ((map.get(label) != null)?map.get(label):def); + } + + public int getInt(String label) { + return (int) map.get(label); + } + + public int getInt(String label, int def) { + return (int) ((map.get(label) != null)?map.get(label):def); + } + + public List getIntList(String label) { + return (List) map.get(label); + } + + public List getIntList(String label, List def) { + return (List) ((map.get(label) != null)?map.get(label):def); + } + + public long getLong(String label) { + return (long) map.get(label); + } + + public long getLong(String label, long def) { + return (long) ((map.get(label) != null)?map.get(label):def); + } + + public List getLongList(String label) { + return (List) map.get(label); + } + + public List getLongList(String label, List def) { + return (List) ((map.get(label) != null)?map.get(label):def); + } + + public short getShort(String label) { + return (short) map.get(label); + } + + public short getShort(String label, short def) { + return (short) ((map.get(label) != null)?map.get(label):def); + } + + public List getShortList(String label) { + return (List) map.get(label); + } + + public List getShortList(String label, List def) { + return (List) ((map.get(label) != null)?map.get(label):def); + } + + public String getRawString(String label) { + return (String) map.get(label); + } + + public String getRawString(String label, String def) { + return (String) ((map.get(label) != null)?map.get(label):def); + } + + public List getRawStringList(String label) { + return (List) map.get(label); + } + + public List getRawStringList(String label, List def) { + return (List) ((map.get(label) != null)?map.get(label):def); + } + + public String getString(String label) { + return (map.get(label) != null)?unescapeJavaString((String) map.get(label)):null; + } + + public String getString(String label, String def) { + return unescapeJavaString((String) ((map.get(label) != null) ? map.get(label) : def)); + } + + public List getStringList(String label) { + if (map.get(label) != null) { + List values = new ArrayList(); + for (String value : (List) map.get(label)) { + values.add(unescapeJavaString(value)); + } + return values; + } else { + return null; + } + } + + public List getStringList(String label, List def) { + if (map.get(label) != null) { + return getStringList(label); + } else { + List values = new ArrayList(); + for (String value : def) { + values.add(unescapeJavaString(value)); + } + return values; + } + } + + public String getColoredString(String label, char color) { + return (map.get(label) != null)? ChatColor.translateAlternateColorCodes(color, unescapeJavaString((String) map.get(label))):null; + } + + public String getColoredString(String label, String def, char color) { + return ChatColor.translateAlternateColorCodes(color, unescapeJavaString((String) ((map.get(label) != null) ? map.get(label) : def))); + } + + public List getColoredStringList(String label, char color) { + if (map.get(label) != null) { + List values = new ArrayList(); + for (String value : (List) map.get(label)) { + values.add(ChatColor.translateAlternateColorCodes(color, unescapeJavaString(value))); + } + return values; + } else { + return null; + } + } + + public List getColoredStringList(String label, List def, char color) { + if (map.get(label) != null) { + return getColoredStringList(label, color); + } else { + List values = new ArrayList(); + for (String value : def) { + values.add(ChatColor.translateAlternateColorCodes(color, unescapeJavaString(value))); + } + return values; + } + } + + public boolean isBoolean(String label) { + return (map.get(label) instanceof Boolean); + } + + public boolean isSection(String label) { + return (map.get(label) instanceof Map); + } + + public boolean isDouble(String label) { + return (map.get(label) instanceof Double); + } + + public boolean isFloat(String label) { + return (map.get(label) instanceof Float); + } + + public boolean isInt(String label) { + return (map.get(label) instanceof Integer); + } + + public boolean isList(String label) { + return (map.get(label) instanceof List); + } + + public boolean isLong(String label) { + return (map.get(label) instanceof Long); + } + + public boolean isString(String label) { + return (map.get(label) instanceof String); + } + + static String unescapeJavaString(String str) { + + StringBuilder sb = new StringBuilder(str.length()); + + for (int i = 0; i < str.length(); i++) { + char ch = str.charAt(i); + if (ch == '\\') { + char nextChar = (i == str.length() - 1) ? '\\' : str + .charAt(i + 1); + // Octal escape? + if (nextChar >= '0' && nextChar <= '7') { + String code = "" + nextChar; + i++; + if ((i < str.length() - 1) && str.charAt(i + 1) >= '0' + && str.charAt(i + 1) <= '7') { + code += str.charAt(i + 1); + i++; + if ((i < str.length() - 1) && str.charAt(i + 1) >= '0' + && str.charAt(i + 1) <= '7') { + code += str.charAt(i + 1); + i++; + } + } + sb.append((char) Integer.parseInt(code, 8)); + continue; + } + switch (nextChar) { + case '\\': + ch = '\\'; + break; + case 'b': + ch = '\b'; + break; + case 'f': + ch = '\f'; + break; + case 'n': + ch = '\n'; + break; + case 'r': + ch = '\r'; + break; + case 't': + ch = '\t'; + break; + case '\"': + ch = '\"'; + break; + case '\'': + ch = '\''; + break; + // Hex Unicode: u???? + case 'u': + if (i >= str.length() - 5) { + ch = 'u'; + break; + } + int code = Integer.parseInt( + "" + str.charAt(i + 2) + str.charAt(i + 3) + + str.charAt(i + 4) + str.charAt(i + 5), 16); + sb.append(Character.toChars(code)); + i += 5; + continue; + } + i++; + } + sb.append(ch); + } + return sb.toString(); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Config/YAMLValue.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Config/YAMLValue.java new file mode 100644 index 00000000..c5567135 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Config/YAMLValue.java @@ -0,0 +1,156 @@ +package net.ME1312.SubServers.Proxy.Libraries.Config; + +import net.md_5.bungee.api.ChatColor; +import org.yaml.snakeyaml.Yaml; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@SuppressWarnings({"unchecked", "unused"}) +public class YAMLValue { + protected Object obj; + protected String label; + protected YAMLSection up; + private Yaml yaml; + + public YAMLValue(Object obj, YAMLSection up, String label, Yaml yaml) { + this.obj = obj; + this.label = label; + this.yaml = yaml; + this.up = up; + } + + public YAMLSection getDefiningSection() { + return up; + } + + public Object asObject() { + return obj; + } + + public List asObjectList() { + return (List) obj; + } + + public boolean asBoolean() { + return (boolean) obj; + } + + public List asBooleanList() { + return (List) obj; + } + + public YAMLSection asSection() { + return new YAMLSection((Map) obj, up, label, yaml); + } + + public List asSectionList() { + List values = new ArrayList(); + for (Map value : (List>) obj) { + values.add(new YAMLSection(value, null, null, yaml)); + } + return values; + } + + public double asDouble() { + return (double) obj; + } + + public List asDoubleList() { + return (List) obj; + } + + public float asFloat() { + return (float) obj; + } + + public List asFloatList() { + return (List) obj; + } + + public int asInt() { + return (int) obj; + } + + public List asIntList() { + return (List) obj; + } + + public long asLong() { + return (long) obj; + } + + public List asLongList() { + return (List) obj; + } + + public String asRawString() { + return (String) obj; + } + + public List asRawStringList() { + return (List) obj; + } + + public String asString() { + return YAMLSection.unescapeJavaString((String) obj); + } + + public List asStringList() { + List values = new ArrayList(); + for (String value : (List) obj) { + values.add(YAMLSection.unescapeJavaString(value)); + } + return values; + } + + public String asColoredString(char color) { + return ChatColor.translateAlternateColorCodes(color, YAMLSection.unescapeJavaString((String) obj)); + } + + public List asColoredStringList(char color) { + List values = new ArrayList(); + for (String value : (List) obj) { + values.add(ChatColor.translateAlternateColorCodes(color, YAMLSection.unescapeJavaString(value))); + } + return values; + } + + public boolean isBoolean() { + return (obj instanceof Boolean); + } + + public boolean isSection() { + return (obj instanceof Map); + } + + public boolean isDouble() { + return (obj instanceof Double); + } + + public boolean isFloat(String path) { + return (obj instanceof Float); + } + + public boolean isInt() { + return (obj instanceof Integer); + } + + public boolean isList() { + return (obj instanceof List); + } + + public boolean isLong() { + return (obj instanceof Long); + } + + public boolean isString() { + return (obj instanceof String); + } + + @Override + public String toString() { + return obj.toString(); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Container.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Container.java new file mode 100644 index 00000000..4b6b08a0 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Container.java @@ -0,0 +1,37 @@ +package net.ME1312.SubServers.Proxy.Libraries; + +/** + * Container Class + * + * @author ME1312 + */ +public class Container { + private T obj; + + /** + * Creates a Container + * + * @param item Object to Store + */ + public Container(T item) { + obj = item; + } + + /** + * Grabs the Object + * + * @return The Object + */ + public T get() { + return obj; + } + + /** + * Overwrite the Object + * + * @param value Object to Store + */ + public void set(T value) { + obj = value; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/IllegalPacketException.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/IllegalPacketException.java new file mode 100644 index 00000000..71591d40 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/IllegalPacketException.java @@ -0,0 +1,8 @@ +package net.ME1312.SubServers.Proxy.Libraries.Exception; + +public class IllegalPacketException extends IllegalStateException { + public IllegalPacketException() {} + public IllegalPacketException(String s) { + super(s); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/InvalidDriverException.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/InvalidDriverException.java new file mode 100644 index 00000000..190b46ee --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/InvalidDriverException.java @@ -0,0 +1,8 @@ +package net.ME1312.SubServers.Proxy.Libraries.Exception; + +public class InvalidDriverException extends IllegalStateException { + public InvalidDriverException() {} + public InvalidDriverException(String s) { + super(s); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/InvalidHostException.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/InvalidHostException.java new file mode 100644 index 00000000..68bf6320 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/InvalidHostException.java @@ -0,0 +1,8 @@ +package net.ME1312.SubServers.Proxy.Libraries.Exception; + +public class InvalidHostException extends IllegalStateException { + public InvalidHostException() {} + public InvalidHostException(String s) { + super(s); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/InvalidServerException.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/InvalidServerException.java new file mode 100644 index 00000000..fb6021b8 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Exception/InvalidServerException.java @@ -0,0 +1,8 @@ +package net.ME1312.SubServers.Proxy.Libraries.Exception; + +public class InvalidServerException extends IllegalStateException { + public InvalidServerException() {} + public InvalidServerException(String s) { + super(s); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Files/build.sh b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Files/build.sh new file mode 100644 index 00000000..4fc78dda --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Files/build.sh @@ -0,0 +1,156 @@ +# Version: 2.11.0a+ +# +# SubCreator Build Script +# Usage: "bash build.sh [jre]" +# +#!/usr/bin/env bash +if [ -z "$1" ] + then + echo ERROR: No Build Version Supplied + rm -Rf build-subserver.sh + exit 1 +fi +if [ -z "$2" ] + then + echo ERROR: No Server Software Supplied + rm -Rf build-subserver.sh + exit 1 +fi +echo ---------- SERVER BUILD START ---------- +if [ $2 == bukkit ] || [ $2 == spigot ] + then + echo Downloading Buildtools... + curl -o BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar; retvalb=$? + if [ $retvalb -eq 0 ]; then + echo Downloaded Buildtools! + else + echo ERROR: Failed Downloading Buildtools. Is SpigotMC.org down? + rm -Rf build-subserver.sh + exit 1 + fi + if [ -d "Buildtools" ] + then + rm -Rf Buildtools + fi + mkdir Buildtools + cd "Buildtools" + echo Building CraftBukkit/Spigot Jarfiles... + export MAVEN_OPTS="-Xmx2G" + if [ -z "$3" ] + then + java -Xmx2G -jar ../BuildTools.jar --rev $1; retvalc=$? + else + HOME=$3 java -Xmx2G -jar ../BuildTools.jar --rev $1; retvalc=$? + fi + cd ../ + if [ $retvalc -eq 0 ]; then + echo CraftBukkit/Spigot Jarfiles Built! + if [ $2 == "spigot" ]; then + cp Buildtools/spigot-*.jar Spigot.jar + else + cp Buildtools/craftbukkit-*.jar Craftbukkit.jar + fi + echo Added Jarfiles! + echo Cleaning Up... + rm -Rf BuildTools.jar + rm -Rf Buildtools + echo ---------- END SERVER BUILD ---------- + rm -Rf build-subserver.sh + exit 0 + else + echo ERROR: Buildtools exited with an error. Please try again + rm -Rf BuildTools.jar + rm -Rf Buildtools + rm -Rf build-subserver.sh + exit 1 + fi +else + if [ $2 == "vanilla" ]; then + if [ -d "Buildtools" ] + then + rm -Rf Buildtools + fi + mkdir Buildtools + mkdir Buildtools/Vanilla + echo Downloading Vanilla Server Jarfile + curl -o Buildtools/Vanilla/minecraft_server.$1.jar https://s3.amazonaws.com/Minecraft.Download/versions/$1/minecraft_server.$1.jar; retvald=$? + if [ $retvald -eq 0 ]; then + echo Downloading Vanilla Patches... + curl -o Buildtools/Vanilla/bungee-patch.jar http://minecraft.me1312.net/lib/subservers/vanilla-bungee-patch.1.2.jar; retvale=$? + if [ $retvale -eq 0 ]; then + echo Patching Vanilla for BungeeCord Support + cd Buildtools/Vanilla + java -jar bungee-patch.jar $1; retvalf=$?; + if [ $retvalf -eq 0 ]; then + echo Patched Vanilla Jar! + cd ../../ + cp Buildtools/Vanilla/out/$1-bungee.jar Buildtools/vanilla-$1.jar + cp Buildtools/Vanilla/out/$1-bungee.jar Vanilla.jar + echo Added Jarfiles! + echo Cleaning Up... + rm -Rf Buildtools + echo ---------- END SERVER BUILD ---------- + rm -Rf build-subserver.sh + exit 0 + else + echo ERROR: Failed Applying Patch. + rm -Rf Buildtools + rm -Rf build-subserver.sh + exit 1 + fi + else + echo ERROR: Failed Downloading Patch. Is Dropbox.com down? + rm -Rf Buildtools + rm -Rf build-subserver.sh + exit 1 + fi + else + echo ERROR: Failed Downloading Jarfile. Is Minecraft.net down? + rm -Rf Buildtools + rm -Rf build-subserver.sh + exit 1 + fi + else + if [ $2 == "sponge" ]; then + IFS='::' read -r -a version <<< "$1" + sversion=$(echo ${version[@]:1} | tr -d ' ') + echo Downloading Minecraft Forge + curl -o forge-${version[0]}-installer.jar http://files.minecraftforge.net/maven/net/minecraftforge/forge/${version[0]}/forge-${version[0]}-installer.jar; retvalg=$? + if [ $retvalg -eq 0 ]; then + echo Installing Minecraft Forge Server + java -jar ./forge-${version[0]}-installer.jar --installServer; retvalh=$? + if [ $retvalh -eq 0 ]; then + mkdir ./mods + echo Downloading SpongeForge + curl -o mods/Sponge.jar http://files.minecraftforge.net/maven/org/spongepowered/spongeforge/$sversion/spongeforge-$sversion.jar; retvali=$? + if [ $retvali -eq 0 ]; then + echo Cleaning Up... + rm -Rf forge-${version[0]}-installer.jar + rm -Rf forge-${version[0]}-installer.jar.log + mv -f forge-${version[0]}-universal.jar Forge.jar + echo ---------- END SERVER BUILD ---------- + rm -Rf build-subserver.sh + exit 0 + else + echo ERROR: Failed Downloading Jarfile. Is MinecraftForge.net down? + rm -Rf forge-${version[0]}-installer.jar + rm -Rf forge-${version[0]}-installer.jar.log + rm -Rf forge-${version[0]}-universal.jar + rm -Rf build-subserver.sh + exit 1 + fi + else + echo ERROR: Failed Installing Forge. + rm -Rf forge-${version[0]}-installer.jar + rm -Rf forge-${version[0]}-installer.jar.log + rm -Rf build-subserver.sh + exit 1 + fi + else + echo ERROR: Failed Downloading Jarfile. Is MinecraftForge.net down? + rm -Rf build-subserver.sh + exit 1 + fi + fi + fi +fi \ No newline at end of file diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Files/config.yml b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Files/config.yml new file mode 100644 index 00000000..6b058469 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Files/config.yml @@ -0,0 +1,30 @@ +Settings: + Version: '2.11.0a+' + Git-Bash: 'C:\Program Files\Git' + Log-Creator: true + Enable-Graphic-Interface: true + Update-External-Files: true + SubData: + Address: '127.0.0.1:4391' + Password: 'password123' + Allowed-Connections: [] + +Hosts: + '~': + Enabled: true + Driver: 'BUILT-IN' + Address: '127.0.0.1' + Directory: './' + +Servers: + 'Server_1': + Enabled: false + Host: '~' + Port: 25566 + Motd: '&aThis is a SubServer' + Log: true + Directory: '~/Server_1' + Executable: 'java -Djline.terminal=jline.UnsupportedTerminal -jar Spigot.jar' + Stop-Command: 'stop' + Run-On-Launch: false + Auto-Restart: false \ No newline at end of file diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Files/lang.yml b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Files/lang.yml new file mode 100644 index 00000000..d9022879 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Files/lang.yml @@ -0,0 +1,3 @@ +Version: '2.11.0a+' +Lang: + 'Console-Only-Command': '&4Console Access Only.' \ No newline at end of file diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/UniversalFile.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/UniversalFile.java new file mode 100644 index 00000000..29e36c80 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/UniversalFile.java @@ -0,0 +1,72 @@ +package net.ME1312.SubServers.Proxy.Libraries; + +import java.io.File; + +/** + * Universal File Class + * + * @author ME1312 + */ +public class UniversalFile extends File { + + /** + * Creates a File Link. Path names are separated by ':' + * + * @param pathname Path name + */ + public UniversalFile(String pathname) { + super(pathname.replace(".:", System.getProperty("user.dir") + ":").replace(':', File.separatorChar)); + } + + /** + * Creates a File Link. Path names are separated by the divider + * + * @param pathname Path name + * @param divider Divider to use + */ + public UniversalFile(String pathname, char divider) { + super(pathname.replace("." + divider, System.getProperty("user.dir") + divider).replace(divider, File.separatorChar)); + } + + /** + * Creates a File Link. + * + * @see File + * @param file File + */ + public UniversalFile(File file) { + super(file.getPath()); + } + + /** + * Creates a File. Path names are separated by the ':' + * + * @see File + * @param parent Parent File + * @param child Path name + */ + public UniversalFile(File parent, String child) { + super(parent, child.replace(':', File.separatorChar)); + } + + /** + * Creates a File. Path names are separated by the divider + * + * @see File + * @param parent Parent File + * @param child Path name + * @param divider Divider to use + */ + public UniversalFile(File parent, String child, char divider) { + super(parent, child.replace(divider, File.separatorChar)); + } + + /** + * Gets the Universal File Path (separated by ':') + * + * @return + */ + public String getUniversalPath() { + return getPath().replace(File.separatorChar, ':'); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Version/Version.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Version/Version.java new file mode 100644 index 00000000..03cae495 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Version/Version.java @@ -0,0 +1,224 @@ +package net.ME1312.SubServers.Proxy.Libraries.Version; + +import java.io.Serializable; + +/** + * Version Class + * + * @author ME1312 + */ +@SuppressWarnings("serial") +public class Version implements Serializable, Comparable { + private String string; + + /** + * Creates a Version + * + * @param string Version String + */ + public Version(String string) { + this.string = string; + } + + + /** + * Creates a Version + * + * @param ints Version Numbers (Will be separated with dots) + */ + public Version(Integer... ints) { + String string = Integer.toString(ints[0]); + int i = 0; + if (ints.length != 1) { + do { + i++; + string = string + "." + ints[i]; + } while ((i + 1) != ints.length); + } + this.string = string; + } + + @Override + public String toString() { + return string; + } + + /** + * See if Versions are Equal + * + * @param version Version to Compare + * @return + */ + public boolean equals(Version version) { + return compareTo(version) == 0; + } + + /* + * Returns 1 if Greater than + * Returns 0 if Equal + * Returns -1 if Less than + *//** + * + * Compare Versions + * + * @param version The version to compare to + */ + public int compareTo(Version version) { + String version1 = this.string; + String version2 = version.toString(); + + VersionTokenizer tokenizer1 = new VersionTokenizer(version1); + VersionTokenizer tokenizer2 = new VersionTokenizer(version2); + + int number1 = 0, number2 = 0; + String suffix1 = "", suffix2 = ""; + + while (tokenizer1.MoveNext()) { + if (!tokenizer2.MoveNext()) { + do { + number1 = tokenizer1.getNumber(); + suffix1 = tokenizer1.getSuffix(); + if (number1 != 0 || suffix1.length() != 0) { + // Version one is longer than number two, and non-zero + return 1; + } + } + while (tokenizer1.MoveNext()); + + // Version one is longer than version two, but zero + return 0; + } + + number1 = tokenizer1.getNumber(); + suffix1 = tokenizer1.getSuffix(); + number2 = tokenizer2.getNumber(); + suffix2 = tokenizer2.getSuffix(); + + if (number1 < number2) { + // Number one is less than number two + return -1; + } + if (number1 > number2) { + // Number one is greater than number two + return 1; + } + + boolean empty1 = suffix1.length() == 0; + boolean empty2 = suffix2.length() == 0; + + if (empty1 && empty2) continue; // No suffixes + if (empty1) return 1; // First suffix is empty (1.2 > 1.2b) + if (empty2) return -1; // Second suffix is empty (1.2a < 1.2) + + // Lexical comparison of suffixes + int result = suffix1.compareTo(suffix2); + if (result != 0) return result; + + } + if (tokenizer2.MoveNext()) { + do { + number2 = tokenizer2.getNumber(); + suffix2 = tokenizer2.getSuffix(); + if (number2 != 0 || suffix2.length() != 0) { + // Version one is longer than version two, and non-zero + return -1; + } + } + while (tokenizer2.MoveNext()); + + // Version two is longer than version one, but zero + return 0; + } + return 0; + } + + /** + * See if Versions are Equal + * + * @param ver1 Version to Compare + * @param ver2 Version to Compare + * @return + */ + public static boolean isEqual(Version ver1, Version ver2) { + return compare(ver1, ver2) == 0; + } + + /* + * Returns 1 if Greater than + * Returns 0 if Equal + * Returns -1 if Less than + *//** + * Compare Versions + * + * @param ver1 Version to Compare + * @param ver2 Version to Compare + */ + public static int compare(Version ver1, Version ver2) { + String version1 = ver1.toString(); + String version2 = ver2.toString(); + + VersionTokenizer tokenizer1 = new VersionTokenizer(version1); + VersionTokenizer tokenizer2 = new VersionTokenizer(version2); + + int number1 = 0, number2 = 0; + String suffix1 = "", suffix2 = ""; + + while (tokenizer1.MoveNext()) { + if (!tokenizer2.MoveNext()) { + do { + number1 = tokenizer1.getNumber(); + suffix1 = tokenizer1.getSuffix(); + if (number1 != 0 || suffix1.length() != 0) { + // Version one is longer than number two, and non-zero + return 1; + } + } + while (tokenizer1.MoveNext()); + + // Version one is longer than version two, but zero + return 0; + } + + number1 = tokenizer1.getNumber(); + suffix1 = tokenizer1.getSuffix(); + number2 = tokenizer2.getNumber(); + suffix2 = tokenizer2.getSuffix(); + + if (number1 < number2) { + // Number one is less than number two + return -1; + } + if (number1 > number2) { + // Number one is greater than number two + return 1; + } + + boolean empty1 = suffix1.length() == 0; + boolean empty2 = suffix2.length() == 0; + + if (empty1 && empty2) continue; // No suffixes + if (empty1) return 1; // First suffix is empty (1.2 > 1.2b) + if (empty2) return -1; // Second suffix is empty (1.2a < 1.2) + + // Lexical comparison of suffixes + int result = suffix1.compareTo(suffix2); + if (result != 0) return result; + + } + if (tokenizer2.MoveNext()) { + do { + number2 = tokenizer2.getNumber(); + suffix2 = tokenizer2.getSuffix(); + if (number2 != 0 || suffix2.length() != 0) { + // Version one is longer than version two, and non-zero + return -1; + } + } + while (tokenizer2.MoveNext()); + + // Version two is longer than version one, but zero + return 0; + } + return 0; + } +} \ No newline at end of file diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Version/VersionTokenizer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Version/VersionTokenizer.java new file mode 100644 index 00000000..34ecf2e6 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Libraries/Version/VersionTokenizer.java @@ -0,0 +1,64 @@ +package net.ME1312.SubServers.Proxy.Libraries.Version; + +public final class VersionTokenizer { + private final String _versionString; + private final int _length; + + private int _position; + private int _number; + private String _suffix; + private boolean _hasValue; + + protected int getNumber() { + return _number; + } + + protected String getSuffix() { + return _suffix; + } + + protected boolean hasValue() { + return _hasValue; + } + + protected VersionTokenizer(String versionString) { + if (versionString == null) + throw new IllegalArgumentException("versionString is null"); + + _versionString = versionString; + _length = versionString.length(); + } + + protected boolean MoveNext() { + _number = 0; + _suffix = ""; + _hasValue = false; + + // No more characters + if (_position >= _length) + return false; + + _hasValue = true; + + while (_position < _length) { + char c = _versionString.charAt(_position); + if (c < '0' || c > '9') break; + _number = _number * 10 + (c - '0'); + _position++; + } + + int suffixStart = _position; + + while (_position < _length) { + char c = _versionString.charAt(_position); + if (c == '.') break; + _position++; + } + + _suffix = _versionString.substring(suffixStart, _position); + + if (_position < _length) _position++; + + return true; + } +} \ No newline at end of file diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Client.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Client.java new file mode 100644 index 00000000..66547214 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Client.java @@ -0,0 +1,211 @@ +package net.ME1312.SubServers.Proxy.Network; + +import net.ME1312.SubServers.Proxy.Libraries.Exception.IllegalPacketException; +import net.ME1312.SubServers.Proxy.Network.Packet.PacketAuthorization; +import net.ME1312.SubServers.Proxy.SubPlugin; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; +import java.net.Socket; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +/** + * Network Client Class + * + * @author ME1312 + */ +public class Client { + private Socket socket; + private SocketAddress address; + private ClientHandler handler; + private List queue = new ArrayList(); + private Timer authorized; + private SubPlugin plugin; + private Client instance; + + /** + * Network Client + * + * @param plugin SubPlugin + * @param client Socket to Bind + */ + public Client(SubPlugin plugin, Socket client) { + this.plugin = plugin; + socket = client; + address = client.getRemoteSocketAddress(); + instance = this; + authorized = new Timer("auth" + client.getRemoteSocketAddress().toString()); + authorized.schedule(new TimerTask() { + @Override + public void run() { + if (!socket.isClosed()) try { + plugin.subdata.removeClient(instance); + } catch (IOException e) { + e.printStackTrace(); + } + } + }, 15000); + loop(); + } + + /** + * Network Loop + */ + protected void loop() { + new Thread() { + public void run() { + try { + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + String input; + while ((input = in.readLine()) != null) { + try { + JSONObject json = new JSONObject(input); + PacketIn packet = plugin.subdata.decodePacket(json); + if (authorized == null || packet instanceof PacketAuthorization) { + try { + packet.execute(instance, (json.keySet().contains("c")) ? json.getJSONObject("c") : null); + } catch (Exception e) { + new InvocationTargetException(e, "Exception while executing PacketIn").printStackTrace(); + } + } + } catch (IllegalPacketException e) { + e.printStackTrace(); + } catch (JSONException e) { + new IllegalPacketException("Unknown Packet Format: " + input).printStackTrace(); + } + } + try { + plugin.subdata.removeClient(instance); + } catch (IOException e1) { + e1.printStackTrace(); + } + } catch (Exception e) { + if (e.getMessage() == null || !e.getMessage().equals("Socket closed")) e.printStackTrace(); + try { + plugin.subdata.removeClient(instance); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + }.start(); + new Thread() { + public void run() { + try { + PrintWriter out = new PrintWriter(socket.getOutputStream(), true); + while (!socket.isClosed()) { + while (queue.size() > 0) { + try { + out.println(plugin.subdata.encodePacket(queue.get(0))); + queue.remove(0); + } catch (IllegalPacketException e) { + e.printStackTrace(); + } + } + sleep(100); + } + try { + plugin.subdata.removeClient(instance); + } catch (IOException e1) { + e1.printStackTrace(); + } + } catch (Exception e) { + if (e.getMessage() == null || !e.getMessage().equals("Socket closed")) e.printStackTrace(); + try { + plugin.subdata.removeClient(instance); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + }.start(); + } + + /** + * Authorize Connection + */ + public void authorize() { + if (authorized != null) { + authorized.cancel(); + System.out.println("SubData > " + socket.getRemoteSocketAddress().toString() + " logged in"); + } + authorized = null; + } + + /** + * Send Packet to Client + * + * @param packet Packet to send + */ + public void sendPacket(PacketOut packet) { + queue.add(packet); + } + + /** + * Get Raw Connection + * + * @return Socket + */ + public Socket getConnection() { + return socket; + } + + /** + * Get Remote Address + * + * @return Address + */ + public SocketAddress getAddress() { + return address; + } + + /** + * If the connection is authorized + * + * @return Authorization Status + */ + public boolean isAuthorized() { + return authorized == null; + } + + /** + * Gets the Linked Handler + * + * @return Handler + */ + public ClientHandler getHandler() { + return handler; + } + + /** + * Sets the Handler + * Warning: This method should only be called by ClientHandler methods + * + * @see ClientHandler + * @param obj Handler + */ + public void setHandler(ClientHandler obj) { + handler = obj; + } + + /** + * Disconnects the Client + * + * @throws IOException + */ + protected void disconnect() throws IOException { + if (!socket.isClosed()) getConnection().close(); + if (handler != null) handler.linkSubDataClient(null); + handler = null; + + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/ClientHandler.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/ClientHandler.java new file mode 100644 index 00000000..51879f82 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/ClientHandler.java @@ -0,0 +1,22 @@ +package net.ME1312.SubServers.Proxy.Network; + +/** + * Client Handler Layout Class + * + * @author ME1312 + */ +public interface ClientHandler { + /** + * Gets the SubData Client + * + * @return SubData Client (or null if not linked) + */ + Client getSubDataClient(); + + /** + * Link a SubData Client to this Object + * + * @param client Client to Link + */ + void linkSubDataClient(Client client); +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/NetworkManager.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/NetworkManager.java new file mode 100644 index 00000000..c1bf665a --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/NetworkManager.java @@ -0,0 +1,250 @@ +package net.ME1312.SubServers.Proxy.Network; + +import net.ME1312.SubServers.Proxy.Libraries.Exception.IllegalPacketException; +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; +import net.ME1312.SubServers.Proxy.Network.Packet.PacketAuthorization; +import net.ME1312.SubServers.Proxy.Network.Packet.PacketLinkServer; +import net.ME1312.SubServers.Proxy.Network.Packet.PacketRequestServerInfo; +import net.ME1312.SubServers.Proxy.Network.Packet.PacketRequestServers; +import net.ME1312.SubServers.Proxy.SubPlugin; +import org.json.JSONObject; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * NetworkManager Class + * + * @author ME1312 + */ +public final class NetworkManager { + private HashMap, String> pOut = new HashMap, String>(); + private HashMap pIn = new HashMap(); + private HashMap clients = new HashMap(); + private List allowedAddresses = new ArrayList(); + private ServerSocket server; + private SubPlugin plugin; + + /** + * SubServers Network Manager + * + * @param plugin SubPlugin + * @param port Port + * @param backlog Connection Queue + * @param address Bind Address + * @throws IOException + */ + public NetworkManager(SubPlugin plugin, int port, int backlog, InetAddress address) throws IOException { + server = new ServerSocket(port, backlog, address); + this.plugin = plugin; + + allowConnection(address); + loadDefaults(); + } + + private void loadDefaults() { + for (String s : plugin.config.get().getSection("Settings").getSection("SubData").getStringList("Allowed-Connections")) { + try { + allowedAddresses.add(InetAddress.getByName(s)); + } catch (Exception e) { + e.printStackTrace(); + } + } + + registerPacket(new PacketAuthorization(plugin), "Authorization"); + registerPacket(new PacketLinkServer(plugin), "LinkServer"); + registerPacket(new PacketRequestServerInfo(plugin), "RequestServerInfo"); + registerPacket(new PacketRequestServers(plugin), "RequestServers"); + + registerPacket(PacketAuthorization.class, "Authorization"); + registerPacket(PacketLinkServer.class, "LinkServer"); + registerPacket(PacketRequestServerInfo.class, "RequestServerInfo"); + registerPacket(PacketRequestServers.class, "RequestServers"); + } + + /** + * Gets the Server Socket + * + * @return Server Socket + */ + public ServerSocket getServer() { + return server; + } + + /** + * Add a Client to the Network + * + * @param socket Client to add + * @throws IOException + */ + public Client addClient(Socket socket) throws IOException { + if (allowedAddresses.contains(socket.getInetAddress())) { + Client client = new Client(plugin, socket); + System.out.println("SubData > " + client.getAddress().toString() + " has connected"); + clients.put(client.getAddress(), client); + return client; + } else { + System.out.println("SubData > " + socket.getRemoteSocketAddress().toString() + " attempted to connect, but isn't whitelisted"); + socket.close(); + return null; + } + } + + /** + * Grabs a Client from the Network + * + * @param socket Socket to search + * @return Client + */ + public Client getClient(Socket socket) { + return clients.get(socket.getRemoteSocketAddress()); + } + + /** + * Grabs a Client from the Network + * + * @param address Address to search + * @return Client + */ + public Client getClient(SocketAddress address) { + return clients.get(address); + } + + /** + * Remove a Client from the Network + * + * @param client Client to Kick + * @throws IOException + */ + public void removeClient(Client client) throws IOException { + SocketAddress address = client.getAddress(); + if (clients.keySet().contains(address)) { + clients.remove(address); + client.disconnect(); + System.out.println("SubData > " + client.getAddress().toString() + " has disconnected"); + } + } + + /** + * Remove a Client from the Network + * + * @param address Address to Kick + * @throws IOException + */ + public void removeClient(SocketAddress address) throws IOException { + Client client = clients.get(address); + if (clients.keySet().contains(address)) { + clients.remove(address); + client.disconnect(); + System.out.println("SubData > " + client.getAddress().toString() + " has disconnected"); + } + } + + /** + * Register Packet to the Network + * + * @param packet PacketIn to register + * @param handle Handle to Bind + */ + public void registerPacket(PacketIn packet, String handle) { + pIn.put(handle, packet); + } + + /** + * Register Packet to the Network + * + * @param packet PacketOut to register + * @param handle Handle to bind + */ + public void registerPacket(Class packet, String handle) { + pOut.put(packet, handle); + } + + /** + * Broadcast a Packet to everything on the Network + * Warning: There are usually different types of applications on the network at once, they may not recognise the same packet handles + * + * @param packet Packet to send + */ + public void broadcastPacket(PacketOut packet) { + for (Client client : clients.values()) { + client.sendPacket(packet); + } + } + + /** + * Allow Connections from an Address + * + * @param address Address to allow + */ + public void allowConnection(InetAddress address) { + if (!allowedAddresses.contains(address)) allowedAddresses.add(address); + } + + /** + * Deny Connections from an Address + * + * @param address Address to deny + */ + public void denyConnection(InetAddress address) { + allowedAddresses.remove(address); + } + + /** + * JSON Encode PacketOut + * + * @param packet PacketOut + * @return JSON Formatted Packet + * @throws IllegalPacketException + */ + protected JSONObject encodePacket(PacketOut packet) throws IllegalPacketException { + JSONObject json = new JSONObject(); + + if (!pOut.keySet().contains(packet.getClass())) throw new IllegalPacketException("Unknown PacketOut Channel: " + packet.getClass().getCanonicalName()); + if (packet.getVersion().toString() == null) throw new NullPointerException("PacketOut Version cannot be null: " + packet.getClass().getCanonicalName()); + + JSONObject contents = packet.generate(); + json.put("h", pOut.get(packet.getClass())); + json.put("v", packet.getVersion().toString()); + if (contents != null) json.put("c", contents); + return json; + } + + /** + * JSON Decode PacketIn + * + * @param json JSON to Decode + * @return PacketIn + * @throws IllegalPacketException + * @throws InvocationTargetException + */ + protected PacketIn decodePacket(JSONObject json) throws IllegalPacketException, InvocationTargetException { + if (!json.keySet().contains("h") || !json.keySet().contains("v")) throw new IllegalPacketException("Unknown Packet Format: " + json.toString()); + if (!pIn.keySet().contains(json.getString("h"))) throw new IllegalPacketException("Unknown PacketIn Channel: " + json.getString("h")); + + PacketIn packet = pIn.get(json.getString("h")); + if (!new Version(json.getString("v")).equals(packet.getVersion())) throw new IllegalPacketException("Packet Version Mismatch in " + json.getString("h") + ": " + json.getString("v") + "->" + packet.getVersion().toString()); + return packet; + } + + /** + * Drops All Connections and Stops the SubData Listener + * + * @throws IOException + */ + public void destroy() throws IOException { + while(clients.size() > 0) { + removeClient((Client) clients.values().toArray()[0]); + } + server.close(); + System.out.println("SubServers > The SubData Listener has been closed"); + plugin.subdata = null; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketAuthorization.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketAuthorization.java new file mode 100644 index 00000000..4f1af814 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketAuthorization.java @@ -0,0 +1,47 @@ +package net.ME1312.SubServers.Proxy.Network.Packet; + +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; +import net.ME1312.SubServers.Proxy.Network.Client; +import net.ME1312.SubServers.Proxy.Network.PacketIn; +import net.ME1312.SubServers.Proxy.Network.PacketOut; +import net.ME1312.SubServers.Proxy.SubPlugin; +import org.json.JSONObject; + +public class PacketAuthorization implements PacketIn, PacketOut { + private SubPlugin plugin; + private boolean response; + private String message; + + public PacketAuthorization(SubPlugin plugin) { + this.plugin = plugin; + } + + public PacketAuthorization(boolean response, String message) { + this.response = response; + this.message = message; + } + + @Override + public JSONObject generate() { + return new JSONObject("{\"r\": " + response + ", \"" + message.replace("\"", "\\\"") + "\"}"); + } + + @Override + public void execute(Client client, JSONObject data) { + try { + if (data.getString("password").equals(plugin.config.get().getSection("Settings").getSection("SubData").getString("Password"))) { + client.authorize(); + client.sendPacket(new PacketAuthorization(true, "Successfully Logged in")); + } else { + client.sendPacket(new PacketAuthorization(false, "Invalid Password")); + } + } catch (Exception e) { + client.sendPacket(new PacketAuthorization(false, e.getClass().getCanonicalName() + ": " + e.getMessage())); + } + } + + @Override + public Version getVersion() { + return new Version("2.11.0a"); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketLinkServer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketLinkServer.java new file mode 100644 index 00000000..9b05b3ee --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketLinkServer.java @@ -0,0 +1,55 @@ +package net.ME1312.SubServers.Proxy.Network.Packet; + +import net.ME1312.SubServers.Proxy.Host.Server; +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; +import net.ME1312.SubServers.Proxy.Network.Client; +import net.ME1312.SubServers.Proxy.Network.PacketIn; +import net.ME1312.SubServers.Proxy.Network.PacketOut; +import net.ME1312.SubServers.Proxy.SubPlugin; +import org.json.JSONObject; + +import java.util.Map; + +public class PacketLinkServer implements PacketIn, PacketOut { + private SubPlugin plugin; + private boolean response; + private String message; + + public PacketLinkServer(SubPlugin plugin) { + this.plugin = plugin; + } + + public PacketLinkServer(boolean response, String message) { + this.response = response; + this.message = message; + } + + + @Override + public JSONObject generate() { + return new JSONObject("{\"r\": " + response + ", \"" + message.replace("\"", "\\\"") + "\"}"); + } + + @Override + public void execute(Client client, JSONObject data) { + try { + Map servers = plugin.api.getServers(); + if (servers.keySet().contains(data.getString("name").toLowerCase())) { + Server server = servers.get(data.getString("name").toLowerCase()); + server.linkSubDataClient(client); + System.out.println("SubData > " + client.getAddress().toString() + " has been defined as " + ((server instanceof SubServer)?"SubServer":"Server") + ": " + server.getName()); + client.sendPacket(new PacketLinkServer(true, "Definition Successful")); + } else { + client.sendPacket(new PacketLinkServer(false, "There is no server with that name")); + } + } catch (Exception e) { + client.sendPacket(new PacketLinkServer(false, e.getClass().getCanonicalName() + ": " + e.getMessage())); + } + } + + @Override + public Version getVersion() { + return new Version("2.11.0a"); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketRequestServerInfo.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketRequestServerInfo.java new file mode 100644 index 00000000..6e9f3654 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketRequestServerInfo.java @@ -0,0 +1,62 @@ +package net.ME1312.SubServers.Proxy.Network.Packet; + +import net.ME1312.SubServers.Proxy.Host.Server; +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; +import net.ME1312.SubServers.Proxy.Network.Client; +import net.ME1312.SubServers.Proxy.Network.PacketIn; +import net.ME1312.SubServers.Proxy.Network.PacketOut; +import net.ME1312.SubServers.Proxy.SubPlugin; +import org.json.JSONObject; + +public class PacketRequestServerInfo implements PacketIn, PacketOut { + private SubPlugin plugin; + private Server server; + + public PacketRequestServerInfo(SubPlugin plugin, Server server) { + this.server = server; + } + + public PacketRequestServerInfo(SubPlugin plugin) { + this.plugin = plugin; + } + + @Override + public JSONObject generate() { + JSONObject json = new JSONObject(); + JSONObject info = new JSONObject(); + json.put("type", (server == null)?"invalid":((server instanceof SubServer)?"subserver":"server")); + + if (server != null && server instanceof SubServer) { + info.put("host", ((SubServer) server).getHost().getName()); + info.put("enabled", ((SubServer) server).isEnabled()); + info.put("log", ((SubServer) server).isLogging()); + info.put("dir", plugin.config.get().getSection("Servers").getSection(server.getName()).getString("Directory")); + info.put("exec", plugin.config.get().getSection("Servers").getSection(server.getName()).getString("Executable")); + info.put("running", ((SubServer) server).isRunning()); + info.put("stop-cmd", ((SubServer) server).getStopCommand()); + info.put("auto-run", plugin.config.get().getSection("Servers").getSection(server.getName()).getBoolean("Run-On-Launch")); + info.put("auto-restart", ((SubServer) server).willAutoRestart()); + info.put("temp", ((SubServer) server).isTemporary()); + } if (server != null) { + info.put("name", server.getName()); + info.put("address", server.getAddress().toString()); + info.put("restricted", server.isRestricted()); + info.put("motd", server.getMotd()); + info.put("subdata", server.getSubDataClient() == null); + } + + json.put("server", info); + return json; + } + + @Override + public void execute(Client client, JSONObject data) { + client.sendPacket(new PacketRequestServerInfo(plugin, plugin.api.getServer(data.getString("server")))); + } + + @Override + public Version getVersion() { + return new Version("2.11.0a"); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketRequestServers.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketRequestServers.java new file mode 100644 index 00000000..c47b0b80 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/Packet/PacketRequestServers.java @@ -0,0 +1,53 @@ +package net.ME1312.SubServers.Proxy.Network.Packet; + +import net.ME1312.SubServers.Proxy.Host.Server; +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; +import net.ME1312.SubServers.Proxy.Network.Client; +import net.ME1312.SubServers.Proxy.Network.PacketIn; +import net.ME1312.SubServers.Proxy.Network.PacketOut; +import net.ME1312.SubServers.Proxy.SubPlugin; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; +import java.util.TreeMap; + +public class PacketRequestServers implements PacketIn, PacketOut { + private SubPlugin plugin; + + public PacketRequestServers(SubPlugin plugin) { + this.plugin = plugin; + } + + @Override + public JSONObject generate() { + JSONObject json = new JSONObject(); + + List exServers = new ArrayList(); + for (Server server : plugin.exServers.values()) { + exServers.add(server.getName()); + } + json.put("servers", exServers); + + TreeMap> hosts = new TreeMap>(); + for (SubServer server : plugin.api.getSubServers().values()) { + List servers = (hosts.keySet().contains(server.getHost().getName()))?hosts.get(server.getHost().getName()):new ArrayList(); + servers.add(server.getName()); + hosts.put(server.getHost().getName(), servers); + } + json.put("hosts", hosts); + + return json; + } + + @Override + public void execute(Client client, JSONObject data) { + client.sendPacket(this); + } + + @Override + public Version getVersion() { + return new Version("2.11.0a"); + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/PacketIn.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/PacketIn.java new file mode 100644 index 00000000..21f5a8d7 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/PacketIn.java @@ -0,0 +1,27 @@ +package net.ME1312.SubServers.Proxy.Network; + +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; +import net.ME1312.SubServers.Proxy.Network.Client; +import org.json.JSONObject; + +/** + * PacketIn Layout Class + * + * @author ME1312 + */ +public interface PacketIn { + /** + * Execute Incoming Packet + * + * @param client Client Accepting + * @param data Incoming Data + */ + void execute(Client client, JSONObject data); + + /** + * Get Packet Version + * + * @return Packet Version + */ + Version getVersion(); +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/PacketOut.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/PacketOut.java new file mode 100644 index 00000000..ef9cdd10 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/Network/PacketOut.java @@ -0,0 +1,25 @@ +package net.ME1312.SubServers.Proxy.Network; + +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; +import org.json.JSONObject; + +/** + * PacketOut Layout Class + * + * @author ME1312 + */ +public interface PacketOut { + /** + * Generate JSON Packet Contents + * + * @return Packet Contents + */ + JSONObject generate(); + + /** + * Get Packet Version + * + * @return Packet Version + */ + Version getVersion(); +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/SubAPI.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/SubAPI.java new file mode 100644 index 00000000..7ffca944 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/SubAPI.java @@ -0,0 +1,150 @@ +package net.ME1312.SubServers.Proxy; + +import net.ME1312.SubServers.Proxy.Host.Server; +import net.ME1312.SubServers.Proxy.Host.Host; +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.ME1312.SubServers.Proxy.Libraries.UniversalFile; +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; +import net.ME1312.SubServers.Proxy.Network.NetworkManager; + +import java.util.Map; +import java.util.TreeMap; + +/** + * SubAPI Class + * + * @author ME1312 + */ +public final class SubAPI { + private SubPlugin plugin; + private static SubAPI api; + + protected SubAPI(SubPlugin plugin) { + this.plugin = plugin; + api = this; + } + + /** + * Gets the SubAPI Methods + * + * @return SubAPI + */ + public static SubAPI getInstance() { + return api; + } + + /** + * Gets the SubServers Internals + * + * @deprecated Use SubAPI Methods when available + * @return SubPlugin Internals + */ + @Deprecated + public SubPlugin getInternals() { + return plugin; + } + + /** + * Gets the SubData Network Manager + * + * @return SubData Network Manager + */ + public NetworkManager getSubDataNetwork() { + return plugin.subdata; + } + + /** + * Adds a Driver for Hosts + * + * @param driver Driver to add + * @param handle Handle to Bind + */ + public void addHostDriver(Class driver, String handle) { + if (plugin.hostDrivers.keySet().contains(handle.toLowerCase())) throw new IllegalStateException("Driver already exists: " + handle); + plugin.hostDrivers.put(handle, driver); + } + + /** + * Gets the Hosts + * + * @return Host Map + */ + public Map getHosts() { + return new TreeMap<>(plugin.hosts); + } + + /** + * Gets a Host + * + * @param name Host name + * @return a Host + */ + public Host getHost(String name) { + return getHosts().get(name.toLowerCase()); + } + + /** + * Gets the Servers (including SubServers) + * + * @return Server Map + */ + public Map getServers() { + TreeMap servers = new TreeMap(); + servers.putAll(plugin.exServers); + for (Host host : plugin.hosts.values()) { + servers.putAll(host.getSubServers()); + } + return servers; + } + + /** + * Gets a Server + * + * @param name Server name + * @return a Server + */ + public Server getServer(String name) { + return getServers().get(name.toLowerCase()); + } + + /** + * Gets the SubServers + * + * @return SubServer Map + */ + public Map getSubServers() { + TreeMap servers = new TreeMap(); + for (Host host : plugin.hosts.values()) { + servers.putAll(host.getSubServers()); + } + return servers; + } + + /** + * Gets a SubServer + * + * @param name SubServer name + * @return a SubServer + */ + public SubServer getSubServer(String name) { + return getSubServers().get(name.toLowerCase()); + } + + /** + * Gets the Runtime Directory + * + * @return Directory + */ + public UniversalFile getRuntimeDirectory() { + return plugin.dir; + } + + /** + * Gets the SubServers Version + * + * @return SubServers Version + */ + public Version getWrapperVersion() { + return plugin.version; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/SubCommand.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/SubCommand.java new file mode 100644 index 00000000..9ad2c386 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/SubCommand.java @@ -0,0 +1,141 @@ +package net.ME1312.SubServers.Proxy; + +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.config.ServerInfo; +import net.md_5.bungee.api.plugin.Command; +import net.md_5.bungee.command.ConsoleCommandSender; + +import java.util.Map; + +/** + * Plugin Command Class + * + * @author ME1312 + */ +public final class SubCommand extends Command { + private SubPlugin plugin; + + public SubCommand(SubPlugin plugin) { + super("subserver", "subservers.console_only", "sub", "subservers"); + this.plugin = plugin; + } + + /** + * Load /Sub in console + * + * @param sender + * @param args + */ + @SuppressWarnings("deprecation") + @Override + public void execute(CommandSender sender, String[] args) { + if (sender instanceof ConsoleCommandSender) { + if (args.length > 0) { + if (args[0].equalsIgnoreCase("help") || args[0].equalsIgnoreCase("?")) { + sender.sendMessages(printHelp()); + } else if (args[0].equalsIgnoreCase("version") || args[0].equalsIgnoreCase("ver")) { + sender.sendMessage("SubServers > SubServers.Proxy is running version " + plugin.version.toString()); + } else if (args[0].equalsIgnoreCase("list")) { + sender.sendMessages( + "SubServers > Host List:", plugin.hosts.keySet().toString(), + "SubServers > Server List:", plugin.getServers().keySet().toString()); + } else if (args[0].equalsIgnoreCase("start")) { + if (args.length > 1) { + Map servers = plugin.getServers(); + if (!servers.keySet().contains(args[1].toLowerCase())) { + sender.sendMessage("SubServers > There is no server with that name"); + } else if (!(servers.get(args[1].toLowerCase()) instanceof SubServer)) { + sender.sendMessage("SubServers > That Server is not a SubServer"); + } else if (!((SubServer) servers.get(args[1].toLowerCase())).isEnabled()) { + sender.sendMessage("SubServers > That SubServer is not enabled"); + } else if (((SubServer) servers.get(args[1].toLowerCase())).isRunning()) { + sender.sendMessage("SubServers > That SubServer is already running"); + } else { + ((SubServer) servers.get(args[1].toLowerCase())).start(); + } + } else { + sender.sendMessage("SubServers > Usage: /sub start "); + } + } else if (args[0].equalsIgnoreCase("stop")) { + if (args.length > 1) { + Map servers = plugin.getServers(); + if (!servers.keySet().contains(args[1].toLowerCase())) { + sender.sendMessage("SubServers > There is no server with that name"); + } else if (!(servers.get(args[1].toLowerCase()) instanceof SubServer)) { + sender.sendMessage("SubServers > That Server is not a SubServer"); + } else if (!((SubServer) servers.get(args[1].toLowerCase())).isRunning()) { + sender.sendMessage("SubServers > That SubServer is not running"); + } else { + ((SubServer) servers.get(args[1].toLowerCase())).stop(); + } + } else { + sender.sendMessage("SubServers > Usage: /sub stop "); + } + } else if (args[0].equalsIgnoreCase("kill") || args[0].equalsIgnoreCase("terminate")) { + if (args.length > 1) { + Map servers = plugin.getServers(); + if (!servers.keySet().contains(args[1].toLowerCase())) { + sender.sendMessage("SubServers > There is no server with that name"); + } else if (!(servers.get(args[1].toLowerCase()) instanceof SubServer)) { + sender.sendMessage("SubServers > That Server is not a SubServer"); + } else if (!((SubServer) servers.get(args[1].toLowerCase())).isRunning()) { + sender.sendMessage("SubServers > That SubServer is not running"); + } else { + ((SubServer) servers.get(args[1].toLowerCase())).terminate(); + } + } else { + sender.sendMessage("SubServers > Usage: /sub kill "); + } + } else if (args[0].equalsIgnoreCase("cmd") || args[0].equalsIgnoreCase("command")) { + if (args.length > 2) { + Map servers = plugin.getServers(); + if (!servers.keySet().contains(args[1].toLowerCase())) { + sender.sendMessage("SubServers > There is no server with that name"); + } else if (!(servers.get(args[1].toLowerCase()) instanceof SubServer)) { + sender.sendMessage("SubServers > That Server is not a SubServer"); + } else if (!((SubServer) servers.get(args[1].toLowerCase())).isRunning()) { + sender.sendMessage("SubServers > That SubServer is not running"); + } else { + int i = 2; + String str = args[2]; + if (args.length > 3) { + do { + i++; + str = str + " " + args[i]; + } while ((i + 1) != args.length); + } + ((SubServer) servers.get(args[1].toLowerCase())).command(str); + } + } else { + sender.sendMessage("SubServers > Usage: /sub cmd [Args...]"); + } + } else if (args[0].equalsIgnoreCase("create")) { + + } + } else { + sender.sendMessages(printHelp()); + } + } else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', plugin.lang.get().getSection("Lang").getString("Console-Only-Command"))); + } + } + + public String[] printHelp() { + return new String[]{ + "SubServers > Console Command Help:", + " Help: /sub help", + " List: /sub list", + " Version: /sub version", + " Start Server: /sub start ", + " Stop Server: /sub stop ", + " Terminate Server: /sub kill ", + " Command Server: /sub cmd [Args...]", + " Create Server: /sub create [RAM]", + "", + " To see BungeeCord Supplied Commands, please visit:", + " https://www.spigotmc.org/wiki/bungeecord-commands/" + }; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/SubPlugin.java b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/SubPlugin.java new file mode 100644 index 00000000..7e62be86 --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Proxy/SubPlugin.java @@ -0,0 +1,282 @@ +package net.ME1312.SubServers.Proxy; + +import net.ME1312.SubServers.Proxy.Host.Executable; +import net.ME1312.SubServers.Proxy.Host.Server; +import net.ME1312.SubServers.Proxy.Libraries.Config.YAMLConfig; +import net.ME1312.SubServers.Proxy.Libraries.Exception.InvalidHostException; +import net.ME1312.SubServers.Proxy.Libraries.Exception.InvalidServerException; +import net.ME1312.SubServers.Proxy.Host.Host; +import net.ME1312.SubServers.Proxy.Host.SubServer; +import net.ME1312.SubServers.Proxy.Libraries.UniversalFile; +import net.ME1312.SubServers.Proxy.Libraries.Version.Version; +import net.ME1312.SubServers.Proxy.Network.NetworkManager; +import net.md_5.bungee.BungeeCord; +import net.md_5.bungee.api.config.ServerInfo; + +import java.io.*; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.file.Files; +import java.util.*; + +/** + * Main Plugin Class + * + * @author ME1312 + */ +public final class SubPlugin extends BungeeCord { + protected final HashMap> hostDrivers = new HashMap>(); + public final HashMap exServers = new HashMap(); + public final HashMap hosts = new HashMap(); + + public final UniversalFile dir = new UniversalFile(new File("./")); + public YAMLConfig config; + public YAMLConfig lang; + public NetworkManager subdata; + public final Version version = new Version("2.11.0a"); + + protected boolean running = false; + public final SubAPI api = new SubAPI(this); + + protected SubPlugin() throws IOException { + enable(); + } + + /** + * Enable Plugin + * + * @throws IOException + */ + protected void enable() throws IOException { + if (running) throw new IllegalStateException("SubServers has already been loaded"); + System.out.println("SubServers > Loading SubServers v" + version.toString() + " Libraries... "); + running = true; + UniversalFile dir = new UniversalFile(this.dir, "SubServers"); + dir.mkdir(); + if (!(new UniversalFile(dir, "config.yml").exists())) { + copyFromJar("net/ME1312/SubServers/Proxy/Libraries/Files/config.yml", new UniversalFile(dir, "config.yml").getPath()); + System.out.println("SubServers > Created ~/SubServers/config.yml"); + } else if ((new Version((new YAMLConfig(new UniversalFile(dir, "config.yml"))).get().getSection("Settings").getString("Version", "0")).compareTo(new Version("2.11.0a+"))) != 0) { + Files.move(new UniversalFile(dir, "config.yml").toPath(), new UniversalFile(dir, "config.old" + Math.round(Math.random() * 100000) + ".yml").toPath()); + + copyFromJar("net/ME1312/SubServers/Proxy/Libraries/Files/config.yml", new UniversalFile(dir, "config.yml").getPath()); + System.out.println("SubServers > Updated ~/SubServers/config.yml"); + } + + if (!(new UniversalFile(dir, "lang.yml").exists())) { + copyFromJar("net/ME1312/SubServers/Proxy/Libraries/Files/lang.yml", new UniversalFile(dir, "lang.yml").getPath()); + System.out.println("SubServers > Created ~/SubServers/lang.yml"); + } else if ((new Version((new YAMLConfig(new UniversalFile(dir, "lang.yml"))).get().getString("Version", "0")).compareTo(new Version("2.11.0a+"))) != 0) { + Files.move(new UniversalFile(dir, "lang.yml").toPath(), new UniversalFile(dir, "lang.old" + Math.round(Math.random() * 100000) + ".yml").toPath()); + copyFromJar("net/ME1312/SubServers/Proxy/Libraries/Files/lang.yml", new UniversalFile(dir, "lang.yml").getPath()); + System.out.println("SubServers > Updated ~/SubServers/lang.yml"); + } + + if (!(new UniversalFile(dir, "build.sh").exists())) { + copyFromJar("net/ME1312/SubServers/Proxy/Libraries/Files/build.sh", new UniversalFile(dir, "build.sh").getPath()); + System.out.println("SubServers > Created ~/SubServers/build.sh"); + } else { + String Version = "null"; + BufferedReader brText = new BufferedReader(new FileReader(new UniversalFile(dir, "build.sh"))); + try { + Version = brText.readLine().split("Version: ")[1]; + } catch (NullPointerException e) {} + brText.close(); + + if (!Version.equalsIgnoreCase("2.11.0a+")) { + Files.move(new UniversalFile(dir, "build.sh").toPath(), new UniversalFile(dir, "build.old" + Math.round(Math.random() * 100000) + ".sh").toPath()); + copyFromJar("net/ME1312/SubServers/Proxy/Libraries/Files/build.sh", new UniversalFile(dir, "build.sh").getPath()); + System.out.println("SubServers > Updated ~/SubServers/build.sh"); + } + } + + hostDrivers.put("built-in", net.ME1312.SubServers.Proxy.Host.Internal.InternalHost.class); + + System.out.println("SubServers > Loading BungeeCord Libraries..."); + } + + /** + * Load Hosts, Servers, SubServers, and SubData. + */ + @Override + public void startListeners() { + try { + config = new YAMLConfig(new UniversalFile(dir, "SubServers:config.yml")); + lang = new YAMLConfig(new UniversalFile(dir, "SubServers:lang.yml")); + subdata = new NetworkManager(this, Integer.parseInt(config.get().getSection("Settings").getSection("SubData").getString("Address", "127.0.0.1:4391").split(":")[1]), 10, + InetAddress.getByName(config.get().getSection("Settings").getSection("SubData").getString("Address", "127.0.0.1:4391").split(":")[0])); + System.out.println("SubServers > SubData Listening on " + subdata.getServer().getLocalSocketAddress().toString()); + loop(); + + long begin = Calendar.getInstance().getTime().getTime(); + int hosts = 0; + System.out.println("SubServers > Loading Hosts..."); + for (String name : config.get().getSection("Hosts").getKeys()) { + try { + if (name.contains(" ")) throw new InvalidHostException("Host names cannot have spaces: " + name); + if (!hostDrivers.keySet().contains(config.get().getSection("Hosts").getSection(name).getString("Driver").toLowerCase())) throw new InvalidHostException("Invalid Driver for host: " + name); + Host host = hostDrivers.get(config.get().getSection("Hosts").getSection(name).getString("Driver").toLowerCase()).getConstructor(SubPlugin.class, String.class, Boolean.class, InetAddress.class, UniversalFile.class).newInstance( + this, name, (Boolean) config.get().getSection("Hosts").getSection(name).getBoolean("Enabled"), InetAddress.getByName(config.get().getSection("Hosts").getSection(name).getString("Address")), new UniversalFile(new File(config.get().getSection("Hosts").getSection(name).getString("Directory")))); + this.hosts.put(name.toLowerCase(), host); + subdata.allowConnection(host.getAddress()); + hosts++; + } catch (Exception e) { + e.printStackTrace(); + } + } + + int servers = 0; + System.out.println("SubServers > Loading Servers..."); + YAMLConfig bungee = new YAMLConfig(new UniversalFile(dir, "config.yml")); + for (String name : bungee.get().getSection("servers").getKeys()) { + try { + Server server = new Server(name, new InetSocketAddress(bungee.get().getSection("servers").getSection(name).getString("address").split(":")[0], + Integer.parseInt(bungee.get().getSection("servers").getSection(name).getString("address").split(":")[1])), bungee.get().getSection("servers").getSection(name).getString("motd"), + bungee.get().getSection("servers").getSection(name).getBoolean("restricted")); + exServers.put(name.toLowerCase(), server); + subdata.allowConnection(server.getAddress().getAddress()); + servers++; + } catch (Exception e) { + e.printStackTrace(); + } + } + + int subservers = 0; + System.out.println("SubServers > Loading SubServers..."); + for (String name : config.get().getSection("Servers").getKeys()) { + try { + if (!this.hosts.keySet().contains(config.get().getSection("Servers").getSection(name).getString("Host").toLowerCase())) throw new InvalidServerException("There is no host with this name:" + name); + SubServer server = this.hosts.get(config.get().getSection("Servers").getSection(name).getString("Host").toLowerCase()).addSubServer(name, config.get().getSection("Servers").getSection(name).getBoolean("Enabled"), + config.get().getSection("Servers").getSection(name).getInt("Port"), config.get().getSection("Servers").getSection(name).getString("Motd"), config.get().getSection("Servers").getSection(name).getBoolean("Log"), + config.get().getSection("Servers").getSection(name).getString("Directory"), new Executable(config.get().getSection("Servers").getSection(name).getString("Executable")), config.get().getSection("Servers").getSection(name).getString("Stop-Command"), + config.get().getSection("Servers").getSection(name).getBoolean("Run-On-Launch"), config.get().getSection("Servers").getSection(name).getBoolean("Auto-Restart"), false); + + subservers++; + } catch (Exception e) { + e.printStackTrace(); + } + } + + System.out.println("SubServers > " + hosts + " Host(s), " + servers + " Server(s), and " + subservers + " SubServer(s) loaded in " + (Calendar.getInstance().getTime().getTime() - begin) + "ms"); + + getPluginManager().registerCommand(null, new SubCommand(this)); + + super.startListeners(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * SubData Listener Loop + */ + public void loop() { + new Thread() { + public void run() { + while(running && subdata != null) { + try { + subdata.addClient(subdata.getServer().accept()); + } catch (IOException e) { + if (e.getMessage() == null || !e.getMessage().equals("Socket closed")) e.printStackTrace(); + } + } + } + }.start(); + } + + /** + * Override BungeeCord Servers + * + * @see SubAPI#getServers() + * @return Server Map + */ + @Override + public Map getServers() { + TreeMap servers = new TreeMap(); + servers.putAll(this.exServers); + for (Host host : this.hosts.values()) { + servers.putAll(host.getSubServers()); + } + return servers; + } + + /** + * Reset all changes made by startListeners + * + * @see SubPlugin#startListeners() + */ + @Override + public void stopListeners() { + try { + System.out.println("SubServers > Resetting Hosts and Server Data"); + List hosts = new ArrayList(); + hosts.addAll(this.hosts.keySet()); + + for (String host : hosts) { + List subservers = new ArrayList(); + subservers.addAll(this.hosts.get(host).getSubServers().keySet()); + + for (String server : subservers) { + this.hosts.get(host).removeSubServer(server); + } + subservers.clear(); + this.hosts.remove(host); + } + hosts.clear(); + exServers.clear(); + + subdata.destroy(); + } catch (Exception e) { + e.printStackTrace(); + } + + super.stopListeners(); + } + + /** + * Disable Plugin + */ + protected void disable() { + if (running) { + running = false; + } + } + + /** + * Override BungeeCord Stop Functions + */ + @Override + public void stop() { + disable(); + super.stop(); + } + + /** + * Override BungeeCord Stop Functions + * + * @param reason Reason + */ + @Override + public void stop(String reason) { + disable(); + super.stop(reason); + } + + private void copyFromJar(String resource, String destination) { + InputStream resStreamIn = SubPlugin.class.getClassLoader().getResourceAsStream(resource); + File resDestFile = new File(destination); + try { + OutputStream resStreamOut = new FileOutputStream(resDestFile); + int readBytes; + byte[] buffer = new byte[4096]; + while ((readBytes = resStreamIn.read(buffer)) > 0) { + resStreamOut.write(buffer, 0, readBytes); + } + resStreamOut.close(); + resStreamIn.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + +} diff --git a/SubServers.Client/src/plugin.yml b/SubServers.Client/src/plugin.yml new file mode 100644 index 00000000..2176d8c9 --- /dev/null +++ b/SubServers.Client/src/plugin.yml @@ -0,0 +1,54 @@ +name: 'SubServers' +main: 'net.ME1312.SubServers.Client.SubPlugin' +version: '2.11.0a' +authors: [ME1312] +website: 'http://www.example.com/' +commands: + subservers: + description: All SubServer Commands + usage: /SubServers [Server] + subserver: + description: All SubServer Commands + usage: /SubServer [Server] + sub: + description: All SubServer Commands + usage: /Sub [Server] +permissions: + subserver.*: + description: All Subserver Commands + default: op + children: + subserver.command: + description: Subservers GUI + default: op + subserver.command.*: + description: 'Subserver Commands/Actions' + default: op + children: + subserver.command.create: + description: Creates a SubServer + default: op + subserver.command.start.*: + description: Starts a Subserver + default: op + subserver.command.kill.*: + description: Terminates a Subserver + default: op + subserver.command.stop.*: + description: Stops a Subserver + default: op + subserver.command.send.*: + description: Sends Commands to a Subserver + default: op + subserver.command.edit.*: + description: Edits a SubServer + default: op + subserver.command.teleport.*: + description: Teleport to SubServers + default: op + subserver.command.teleport.others.*: + description: Teleport Others to SubServers + default: op + subserver.command.reload: + description: Reload Subservers Configs + default: op \ No newline at end of file