diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..5c98b42 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/.idea/ButtonServerRunner.iml b/.idea/ButtonServerRunner.iml new file mode 100644 index 0000000..cc49f58 --- /dev/null +++ b/.idea/ButtonServerRunner.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..15a15b2 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..4f1aeda --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_yaml_snakeyaml_1_21.xml b/.idea/libraries/Maven__org_yaml_snakeyaml_1_21.xml new file mode 100644 index 0000000..c86e780 --- /dev/null +++ b/.idea/libraries/Maven__org_yaml_snakeyaml_1_21.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/markdown-navigator/profiles_settings.xml b/.idea/markdown-navigator/profiles_settings.xml new file mode 100644 index 0000000..57927c5 --- /dev/null +++ b/.idea/markdown-navigator/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..4cc859a --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/MCServerRunner.iml b/MCServerRunner.iml new file mode 100644 index 0000000..cc49f58 --- /dev/null +++ b/MCServerRunner.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 16c2771..ad3271f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,59 +1,60 @@ - - 4.0.0 - ButtonDevTeam - MCServerRunner - 0.0.1-SNAPSHOT - - src - - - maven-compiler-plugin - 3.5.1 - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-jar-plugin - 3.1.0 - - - - true - buttondevteam.serverrunner.ServerRunner - ServerRunner_lib/ - - - - - - maven-shade-plugin - 3.1.1 - - - package - - shade - - - - - - - - - jline - jline - 2.12 - - - - org.yaml - snakeyaml - 1.21 - - + + 4.0.0 + ButtonDevTeam + MCServerRunner + 0.0.1-SNAPSHOT + + src + ServerRunner + + + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + + true + buttondevteam.serverrunner.ServerRunner + ServerRunner_lib/ + + + + + + maven-shade-plugin + 3.1.1 + + + package + + shade + + + + + + + + + jline + jline + 2.12 + + + + org.yaml + snakeyaml + 1.21 + + \ No newline at end of file diff --git a/src/buttondevteam/serverrunner/Config.java b/src/buttondevteam/serverrunner/Config.java index 29ca5e3..263eac2 100644 --- a/src/buttondevteam/serverrunner/Config.java +++ b/src/buttondevteam/serverrunner/Config.java @@ -4,6 +4,7 @@ public class Config { public String serverVersion; public String serverParams; public int restartAt; + public String customJar; public Config(String serverVersion, String serverParams, int restartAt) { this.serverVersion = serverVersion; @@ -14,5 +15,6 @@ public class Config { this.serverVersion = "1.12.2"; this.serverParams = "-Djline.terminal=jline.UnixTerminal -Xms4G -Xmx6G"; this.restartAt = 12; + this.customJar = ""; } } diff --git a/src/buttondevteam/serverrunner/ServerRunner.java b/src/buttondevteam/serverrunner/ServerRunner.java index 6be612e..5365c85 100644 --- a/src/buttondevteam/serverrunner/ServerRunner.java +++ b/src/buttondevteam/serverrunner/ServerRunner.java @@ -1,226 +1,229 @@ -package buttondevteam.serverrunner; - -import jline.console.ConsoleReader; -import jline.console.CursorBuffer; -import org.yaml.snakeyaml.Yaml; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.Calendar; -import java.util.Collections; -import java.util.TimeZone; -import java.util.regex.Pattern; - -public class ServerRunner { - private static final int RESTART_MESSAGE_COUNT = 60; - - private static final int interval = 24; // hours - - private static volatile boolean stop = false; - private static int restartcounter = RESTART_MESSAGE_COUNT; - private static volatile Process serverprocess; - private static volatile PrintWriter serveroutput; - private static volatile Thread rt; - private static volatile ConsoleReader reader; - private static volatile PrintWriter runnerout; - - private static volatile boolean customrestartfailed = false; - - public static void main(String[] args) throws IOException { - Yaml yaml = new Yaml(); - File f=new File("plugins/ServerRunner/config.yml"); - f.getParentFile().mkdirs(); - final Config config; - if(!f.exists()) - Files.write(f.toPath(), Collections.singleton(yaml.dump(config = new Config()))); - else - config=yaml.load(new FileInputStream(f)); - if (!new File("spigot-" + config.serverVersion + ".jar").exists()) { - System.out.println("The server JAR for " + config.serverVersion + " cannot be found!"); - return; - } - reader = new ConsoleReader(); - reader.setPrompt("Runner>"); - runnerout = new PrintWriter(reader.getOutput()); - writeToScreen("Starting server..."); - serverprocess = startServer(config); - serveroutput = new PrintWriter(serverprocess.getOutputStream()); - rt = Thread.currentThread(); - final Thread it = new Thread() { - @Override - public void run() { - try { - String readLine; - while (!stop) { - try { - if ((readLine = reader.readLine()) == null) - break; - if (readLine.equalsIgnoreCase("stop")) - ServerRunner.stop(); - serveroutput.println(readLine); - serveroutput.flush(); - } catch (Exception e) { - e.printStackTrace(); - Thread.sleep(100); //Sleep a bit and keep going - } - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - ServerRunner.stop(); - writeToScreen("Stopped " + Thread.currentThread().getName()); - } - }; - it.setName("InputThread"); - it.start(); - final Thread ot = new Thread() { - @Override - public void run() { - try { - BufferedReader serverinput = new BufferedReader( - new InputStreamReader(serverprocess.getInputStream(), StandardCharsets.UTF_8)); - String line; - while (true) { - if ((line = serverinput.readLine()) != null) { - writeToScreen(line); - if (line.contains("FAILED TO BIND TO PORT")) { - ServerRunner.stop(); - writeToScreen("A server is already running!"); - } - if (Pattern.matches( - "\\[\\d\\d:\\d\\d:\\d\\d INFO]: Unknown command. Type \"/help\" for help.\\s+", line)) - customrestartfailed = true; - - } else if (!stop) { - try { - serverinput.close(); - } catch (Exception e) { - e.printStackTrace(); - } - try { - serveroutput.close(); - } catch (Exception e) { - e.printStackTrace(); - } - writeToScreen("Server stopped! Restarting..."); - serverprocess = startServer(config); - serverinput = new BufferedReader(new InputStreamReader(serverprocess.getInputStream())); - serveroutput = new PrintWriter(serverprocess.getOutputStream()); - restartcounter = RESTART_MESSAGE_COUNT; - } else - break; - } - serverinput.close(); - } catch (IOException e) { - e.printStackTrace(); - } - ServerRunner.stop(); - writeToScreen("Stopped " + Thread.currentThread().getName()); - } - }; - ot.setName("OutputThread"); - ot.start(); - Thread.currentThread().setName("RestarterThread"); - long starttime = syncStart(config.restartAt); - System.out.println("Restart scheduled in " + starttime / 3600000f); - boolean firstrun = true; - while (!stop) { - try { - if (restartcounter >= 0) { - if (restartcounter == RESTART_MESSAGE_COUNT) { - if (firstrun) { - // writeToScreen("Sleeping for " + starttime); - Thread.sleep(starttime); - firstrun = false; - } else - Thread.sleep(interval * 3600000); - customrestartfailed = false; - serveroutput.println("schrestart"); - serveroutput.flush(); - } else if (restartcounter > 0) { - if (customrestartfailed) { - if (restartcounter % 10 == 0) - sendMessage(serveroutput, "red", - "-- Server restarting in " + restartcounter + " seconds!"); - Thread.sleep(1000); - } else { - restartcounter = RESTART_MESSAGE_COUNT; - continue; // Don't decrement the counter so it will sleep the full time - } - } else { - Thread.sleep(500); - if (customrestartfailed) { - writeToScreen("Stopping server for restart..."); - serveroutput.println("restart"); - serveroutput.flush(); - customrestartfailed = false; - } - Thread.sleep(5000); // Don't run needless cycles - } - restartcounter--; - } - } catch (InterruptedException e) { // The while checks if stop is true and then stops - } - } - writeToScreen("Stopped " + Thread.currentThread().getName()); - } - - private static Process startServer(Config config) throws IOException { - return Runtime.getRuntime().exec(("java "+config.serverParams+" -jar spigot-" + config.serverVersion + ".jar").split(" ")); - } - - private static void sendMessage(PrintWriter output, String color, String text) { - output.println("tellraw @a {\"text\":\"" + text + "\",\"color\":\"" + color + "\"}"); - output.flush(); - writeToScreen(text); - } - - private static void stop() { - stop = true; - rt.interrupt(); // The restarter thread sleeps for a long time and keeps the program running - } - - private static void writeToScreen(String line) { - stashLine(); - runnerout.println(line); - unstashLine(); - } - - private static CursorBuffer stashed; - - private static void stashLine() { - stashed = reader.getCursorBuffer().copy(); - try { - reader.getOutput().write("\u001b[1G\u001b[K"); - reader.flush(); - } catch (IOException e) { - // ignore - } - } - - private static void unstashLine() { - try { - reader.resetPromptLine(reader.getPrompt(), stashed.toString(), stashed.cursor); - } catch (IOException e) { - // ignore - } - } - - private static double hoursOf(Calendar parsedTime) { - return parsedTime.get(Calendar.HOUR_OF_DAY) + parsedTime.get(Calendar.MINUTE) / 60. - + parsedTime.get(Calendar.SECOND) / 3600.; - } - - private static long syncStart(double startHour) { // Copied original code from SimpleBackup - double now = hoursOf(Calendar.getInstance(TimeZone.getTimeZone("GMT"))); - double diff = now - startHour; - if (diff < 0) { - diff += 24; - } - double intervalPart = diff - Math.floor(diff / interval) * interval; - double remaining = interval - intervalPart; - return (long) (remaining * 3600000); - } - -} +package buttondevteam.serverrunner; + +import jline.console.ConsoleReader; +import jline.console.CursorBuffer; +import org.yaml.snakeyaml.Yaml; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.Calendar; +import java.util.Collections; +import java.util.TimeZone; +import java.util.regex.Pattern; + +public class ServerRunner { + private static final int RESTART_MESSAGE_COUNT = 60; + + private static final int interval = 24; // hours + + private static volatile boolean stop = false; + private static int restartcounter = RESTART_MESSAGE_COUNT; + private static volatile Process serverprocess; + private static volatile PrintWriter serveroutput; + private static volatile Thread rt; + private static volatile ConsoleReader reader; + private static volatile PrintWriter runnerout; + + private static volatile boolean customrestartfailed = false; + + public static void main(String[] args) throws IOException { + Yaml yaml = new Yaml(); + File f = new File("plugins/ServerRunner/config.yml"); + f.getParentFile().mkdirs(); + final Config config; + if (!f.exists()) + Files.write(f.toPath(), Collections.singleton(yaml.dump(config = new Config()))); + else + config = yaml.load(new FileInputStream(f)); + final File serverJar = new File(config.customJar == null || config.customJar.length() == 0 + ? "spigot-" + config.serverVersion + ".jar" + : config.customJar); + if (!serverJar.exists()) { + System.out.println("The server JAR for " + config.serverVersion + " cannot be found!"); + return; + } + reader = new ConsoleReader(); + reader.setPrompt("Runner>"); + runnerout = new PrintWriter(reader.getOutput()); + writeToScreen("Starting server..."); + serverprocess = startServer(config, serverJar); + serveroutput = new PrintWriter(serverprocess.getOutputStream()); + rt = Thread.currentThread(); + final Thread it = new Thread() { + @Override + public void run() { + try { + String readLine; + while (!stop) { + try { + if ((readLine = reader.readLine()) == null) + break; + if (readLine.equalsIgnoreCase("stop")) + ServerRunner.stop(); + serveroutput.println(readLine); + serveroutput.flush(); + } catch (Exception e) { + e.printStackTrace(); + Thread.sleep(100); //Sleep a bit and keep going + } + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + ServerRunner.stop(); + writeToScreen("Stopped " + Thread.currentThread().getName()); + } + }; + it.setName("InputThread"); + it.start(); + final Thread ot = new Thread() { + @Override + public void run() { + try { + BufferedReader serverinput = new BufferedReader( + new InputStreamReader(serverprocess.getInputStream(), StandardCharsets.UTF_8)); + String line; + while (true) { + if ((line = serverinput.readLine()) != null) { + writeToScreen(line); + if (line.contains("FAILED TO BIND TO PORT")) { + ServerRunner.stop(); + writeToScreen("A server is already running!"); + } + if (Pattern.matches( + "\\[\\d\\d:\\d\\d:\\d\\d INFO]: Unknown command. Type \"/help\" for help.\\s+", line)) + customrestartfailed = true; + + } else if (!stop) { + try { + serverinput.close(); + } catch (Exception e) { + e.printStackTrace(); + } + try { + serveroutput.close(); + } catch (Exception e) { + e.printStackTrace(); + } + writeToScreen("Server stopped! Restarting..."); + serverprocess = startServer(config, serverJar); + serverinput = new BufferedReader(new InputStreamReader(serverprocess.getInputStream())); + serveroutput = new PrintWriter(serverprocess.getOutputStream()); + restartcounter = RESTART_MESSAGE_COUNT; + } else + break; + } + serverinput.close(); + } catch (IOException e) { + e.printStackTrace(); + } + ServerRunner.stop(); + writeToScreen("Stopped " + Thread.currentThread().getName()); + } + }; + ot.setName("OutputThread"); + ot.start(); + Thread.currentThread().setName("RestarterThread"); + long starttime = syncStart(config.restartAt); + System.out.println("Restart scheduled in " + starttime / 3600000f); + boolean firstrun = true; + while (!stop) { + try { + if (restartcounter >= 0) { + if (restartcounter == RESTART_MESSAGE_COUNT) { + if (firstrun) { + // writeToScreen("Sleeping for " + starttime); + Thread.sleep(starttime); + firstrun = false; + } else + Thread.sleep(interval * 3600000); + customrestartfailed = false; + serveroutput.println("schrestart"); + serveroutput.flush(); + } else if (restartcounter > 0) { + if (customrestartfailed) { + if (restartcounter % 10 == 0) + sendMessage(serveroutput, "red", + "-- Server restarting in " + restartcounter + " seconds!"); + Thread.sleep(1000); + } else { + restartcounter = RESTART_MESSAGE_COUNT; + continue; // Don't decrement the counter so it will sleep the full time + } + } else { + Thread.sleep(500); + if (customrestartfailed) { + writeToScreen("Stopping server for restart..."); + serveroutput.println("restart"); + serveroutput.flush(); + customrestartfailed = false; + } + Thread.sleep(5000); // Don't run needless cycles + } + restartcounter--; + } + } catch (InterruptedException e) { // The while checks if stop is true and then stops + } + } + writeToScreen("Stopped " + Thread.currentThread().getName()); + } + + private static Process startServer(Config config, File serverJar) throws IOException { + return Runtime.getRuntime().exec(new String[]{"java", config.serverParams, "-jar", serverJar.getPath()}); + } + + private static void sendMessage(PrintWriter output, String color, String text) { + output.println("tellraw @a {\"text\":\"" + text + "\",\"color\":\"" + color + "\"}"); + output.flush(); + writeToScreen(text); + } + + private static void stop() { + stop = true; + rt.interrupt(); // The restarter thread sleeps for a long time and keeps the program running + } + + private static void writeToScreen(String line) { + stashLine(); + runnerout.println(line); + unstashLine(); + } + + private static CursorBuffer stashed; + + private static void stashLine() { + stashed = reader.getCursorBuffer().copy(); + try { + reader.getOutput().write("\u001b[1G\u001b[K"); + reader.flush(); + } catch (IOException e) { + // ignore + } + } + + private static void unstashLine() { + try { + reader.resetPromptLine(reader.getPrompt(), stashed.toString(), stashed.cursor); + } catch (IOException e) { + // ignore + } + } + + private static double hoursOf(Calendar parsedTime) { + return parsedTime.get(Calendar.HOUR_OF_DAY) + parsedTime.get(Calendar.MINUTE) / 60. + + parsedTime.get(Calendar.SECOND) / 3600.; + } + + private static long syncStart(double startHour) { // Copied original code from SimpleBackup + double now = hoursOf(Calendar.getInstance(TimeZone.getTimeZone("GMT"))); + double diff = now - startHour; + if (diff < 0) { + diff += 24; + } + double intervalPart = diff - Math.floor(diff / interval) * interval; + double remaining = interval - intervalPart; + return (long) (remaining * 3600000); + } + +}