Fixes some bugs preventing servers from starting
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good

This commit is contained in:
Kristian Knarvik 2020-08-07 04:08:05 +02:00
parent b144bbb903
commit a2d4d491ba
4 changed files with 158 additions and 81 deletions

View File

@ -83,7 +83,7 @@ public class Main {
Server server = collection.getServer(); Server server = collection.getServer();
if (server.isEnabled() && server.getProcess() != null) { if (server.isEnabled() && server.getProcess() != null) {
try { try {
String readText = server.read(); String readText = server.readFromServer();
if (!readText.equals("")) { if (!readText.equals("")) {
collection.getServerConsole().output(readText); collection.getServerConsole().output(readText);
updatePlayerList(readText, server); updatePlayerList(readText, server);
@ -117,7 +117,8 @@ public class Main {
private static boolean serversRunning() { private static boolean serversRunning() {
int num = 0; int num = 0;
for (Collection collection : Profile.getCurrent().getCollections()) { for (Collection collection : Profile.getCurrent().getCollections()) {
if (collection.getServer().isStarted() || (collection.getServer().getProcess() != null && collection.getServer().getProcess().isAlive())) { if (collection.getServer().isStarted() ||
(collection.getServer().getProcess() != null && collection.getServer().getProcess().isAlive())) {
num++; num++;
} }
} }

View File

@ -48,6 +48,11 @@ public class Server {
private final String bungeeVersion; private final String bungeeVersion;
private boolean started; private boolean started;
/**
* Initializes a new server with default values
*
* @param name <p>The name of the server</p>
*/
public Server(String name) { public Server(String name) {
this.name = name; this.name = name;
this.path = ""; this.path = "";
@ -65,6 +70,20 @@ public class Server {
this.bungeeVersion = ""; this.bungeeVersion = "";
} }
/**
* Initializes a server with the given values
*
* @param name <p>The name of the server</p>
* @param path <p>The file path of the folder containing the server files</p>
* @param enabled <p>Whether the server is enabled to start the next time servers are started</p>
* @param typeName <p>The name of the server type currently in use on the server</p>
* @param serverVersion <p>The currently selected server version for the given server type</p>
* @param maxRam <p>The maximum amount of ram the server is allowed to use</p>
* @param vanillaVersion <p>The version of the "latest" downloaded vanilla version</p>
* @param snapshotVersion <p>The version of the "latest" downloaded snapshot version</p>
* @param spongeVanillaVersion <p>The version of the "latest" SpongeVanilla jar downloaded</p>
* @param bungeeVersion <p>The version of the "latest" bungee jar downloaded</p>
*/
public Server(String name, String path, boolean enabled, String typeName, String serverVersion, String maxRam, public Server(String name, String path, boolean enabled, String typeName, String serverVersion, String maxRam,
String vanillaVersion, String snapshotVersion, String spongeVanillaVersion, String bungeeVersion) { String vanillaVersion, String snapshotVersion, String spongeVanillaVersion, String bungeeVersion) {
this.name = name; this.name = name;
@ -80,18 +99,38 @@ public class Server {
this.playerList = new ArrayList<>(); this.playerList = new ArrayList<>();
} }
/**
* Gets the name of the server
*
* @return <p>The name of the server</p>
*/
public String getName() { public String getName() {
return this.name; return this.name;
} }
/**
* Whether the server has been started
*
* @return <p>True if the server has been started. False otherwise</p>
*/
public boolean isStarted() { public boolean isStarted() {
return started; return started;
} }
/**
* Gets the name of the server type used by this server
*
* @return <p>The name of the server type used by this server</p>
*/
public String getTypeName() { public String getTypeName() {
return this.type.getName(); return this.type.getName();
} }
/**
* Gets the version used given server type used
*
* @return <p>The server version given server type</p>
*/
public String getServerVersion() { public String getServerVersion() {
return this.serverVersion; return this.serverVersion;
} }
@ -255,76 +294,39 @@ public class Server {
} }
/** /**
* Runs the Minecraft server. * Runs a Minecraft server
*
* @return <p>True if nothing went wrong</p>
*/ */
private boolean run() { private boolean run() {
if (this.enabled) { if (!this.enabled) {
this.started = true;
if (!Profile.getCurrent().getDownloadAllAvailableJARFiles()) {
try {
Profile.getGUI().setStatus("Downloading jar...");
this.downloadJar();
Profile.getGUI().setStatus("File downloaded");
} catch (IOException e) {
System.out.println(e.getMessage());
Profile.getGUI().setStatus("Error: Jar file not found");
e.printStackTrace();
this.started = false;
return false;
}
}
try {
Profile.getGUI().setStatus("Delaying startup");
TimeUnit.SECONDS.sleep(Profile.getCurrent().getDelayStartup());
} catch (InterruptedException e) {
e.printStackTrace();
this.started = false;
return false;
}
try {
ProcessBuilder builder;
String serverPath;
if (Profile.getCurrent().getDownloadAllAvailableJARFiles() && !type.getName().equals("Custom")) {
serverPath = jarDirectory + this.getType();
} else {
serverPath = this.path + File.separator + this.getType();
}
builder = new ProcessBuilder(
"java",
"-Xmx" + this.maxRam,
"-Xms512M",
"-Djline.terminal=jline.UnsupportedTerminal",
"-Dcom.mojang.eula.agree=true",
"-jar",
serverPath,
"nogui"
);
builder.directory(new File(this.path));
builder.redirectErrorStream(true);
this.process = builder.start();
this.writer = new BufferedWriter(new OutputStreamWriter(this.process.getOutputStream()));
this.reader = new BufferedReader(new InputStreamReader(this.process.getInputStream()));
Profile.getGUI().setStatus("Servers are running");
this.started = true;
return true;
} catch (IOException e) {
Profile.getGUI().setStatus("Could not start server");
this.started = false;
return false;
}
} else {
this.started = false; this.started = false;
return true; return true;
} }
this.started = true;
if (!initializeJarDownload() || !delayStartup()) {
return false;
}
try {
startServerProcess();
Profile.getGUI().setStatus("Servers are running");
this.started = true;
return true;
} catch (IOException e) {
Profile.getGUI().setStatus("Could not start server");
this.started = false;
return false;
}
} }
/** /**
* Reads all available output from the server process. * Reads all available output from the server process
* *
* @return The server output * @return <p>The server output</p>
* @throws IOException If reading from the reader fails * @throws IOException <p>If reading from the reader fails</p>
*/ */
public String read() throws IOException { public String readFromServer() throws IOException {
String line; String line;
StringBuilder text = new StringBuilder(); StringBuilder text = new StringBuilder();
while (reader.ready() && (line = reader.readLine()) != null) { while (reader.ready() && (line = reader.readLine()) != null) {
@ -334,10 +336,77 @@ public class Server {
} }
/** /**
* Downloads necessary .jar file for the server. * Starts the process running this server
* This is unfortunately hardcoded since there is no golden standard, and we only host some jars ourselves.
* *
* @throws FileNotFoundException if the file was not found and could not be acquired. * @throws IOException <p>If the process cannot be started</p>
*/
private void startServerProcess() throws IOException {
ProcessBuilder builder;
String serverPath;
String serverFile;
if (type.getName().equals("Custom")) {
serverFile = serverVersion;
} else {
serverFile = this.type.getName() + serverVersion + ".jar";
}
if (Profile.getCurrent().getDownloadAllAvailableJARFiles() && !type.getName().equals("Custom")) {
serverPath = jarDirectory + serverFile;
} else {
serverPath = this.path + File.separator + serverFile;
}
builder = new ProcessBuilder("java", "-Xmx" + this.maxRam, "-Xms512M",
"-Djline.terminal=jline.UnsupportedTerminal", "-Dcom.mojang.eula.agree=true", "-jar", serverPath,
"nogui");
builder.directory(new File(this.path));
builder.redirectErrorStream(true);
this.process = builder.start();
this.writer = new BufferedWriter(new OutputStreamWriter(this.process.getOutputStream()));
this.reader = new BufferedReader(new InputStreamReader(this.process.getInputStream()));
}
/**
* Delays the server's startup for the given amount of time
*
* @return <p>True if the delay was successful</p>
*/
private boolean delayStartup() {
try {
Profile.getGUI().setStatus("Delaying startup");
TimeUnit.SECONDS.sleep(Profile.getCurrent().getDelayStartup());
return true;
} catch (InterruptedException e) {
e.printStackTrace();
this.started = false;
return false;
}
}
/**
* Starts downloading the necessary .jar file
*
* @return <p>True if nothing went wrong</p>
*/
private boolean initializeJarDownload() {
if (!Profile.getCurrent().getDownloadAllAvailableJARFiles()) {
try {
Profile.getGUI().setStatus("Downloading jar...");
this.downloadJar();
Profile.getGUI().setStatus("File downloaded");
} catch (IOException e) {
System.out.println(e.getMessage());
Profile.getGUI().setStatus("Error: Jar file not found");
e.printStackTrace();
this.started = false;
return false;
}
}
return true;
}
/**
* Downloads necessary .jar file for the server.
*
* @throws FileNotFoundException <p>If the file was not found and could not be acquired</p>
*/ */
private void downloadJar() throws IOException { private void downloadJar() throws IOException {
String path = this.path + File.separator; String path = this.path + File.separator;

View File

@ -54,7 +54,7 @@ public class Vanilla extends AbstractServerType {
* Gets the URL to the .jar file for the newest version * Gets the URL to the .jar file for the newest version
* *
* @return <p>An array containing the latest version and a link to its file</p> * @return <p>An array containing the latest version and a link to its file</p>
* @throws IOException <p>If the remote resource cannot be read</p> * @throws IOException <p>If the remote resource cannot be readFromServer</p>
*/ */
private String[] getLatestFile() throws IOException { private String[] getLatestFile() throws IOException {
String versionText = readFile(versionURL); String versionText = readFile(versionURL);
@ -70,7 +70,7 @@ public class Vanilla extends AbstractServerType {
* *
* @param versionURL <p>The URL to the version document describing the .jar file</p> * @param versionURL <p>The URL to the version document describing the .jar file</p>
* @return <p>The URL necessary do download the .jar file</p> * @return <p>The URL necessary do download the .jar file</p>
* @throws IOException <p>If the remote resource cannot be read</p> * @throws IOException <p>If the remote resource cannot be readFromServer</p>
*/ */
private String getVanillaDownloadURL(String versionURL) throws IOException { private String getVanillaDownloadURL(String versionURL) throws IOException {
String versionText = readFile(versionURL); String versionText = readFile(versionURL);

View File

@ -2,7 +2,13 @@ package net.knarcraft.minecraftserverlauncher.utility;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI; import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
import java.io.*; import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
@ -14,16 +20,16 @@ import java.util.Scanner;
/** /**
* A holding class for methods shared between classes. * A holding class for methods shared between classes.
* *
* @author Kristian Knarvik <kristian.knarvik@knett.no> * @author Kristian Knarvik <kristian.knarvik@knett.no>
* @version 1.0.0 * @version 1.0.0
* @since 1.0.0 * @since 1.0.0
*/ */
public class CommonFunctions { public class CommonFunctions {
/** /**
* Gets a resource as an InputStream * Gets a resource as an InputStream
* *
* @param resourceName <p>The name of the resource you want to read</p> * @param resourceName <p>The name of the resource you want to readFromServer</p>
* @return <p>An input stream which can be used to access the resource</p> * @return <p>An input stream which can be used to access the resource</p>
*/ */
public static InputStream getResourceAsStream(String resourceName) { public static InputStream getResourceAsStream(String resourceName) {
@ -34,8 +40,8 @@ public class CommonFunctions {
/** /**
* Gets a resource as a Scanner * Gets a resource as a Scanner
* *
* @param resourceName <p>The name of the resource you want to read</p> * @param resourceName <p>The name of the resource you want to readFromServer</p>
* @return <p>A scanner which can be used to read contents of the resource</p> * @return <p>A scanner which can be used to readFromServer contents of the resource</p>
* @throws FileNotFoundException <p>If the resource is not found</p> * @throws FileNotFoundException <p>If the resource is not found</p>
*/ */
public static Scanner getResourceAsScanner(String resourceName) throws FileNotFoundException { public static Scanner getResourceAsScanner(String resourceName) throws FileNotFoundException {
@ -50,8 +56,8 @@ public class CommonFunctions {
* Finds a substring between two substrings in a string * Finds a substring between two substrings in a string
* *
* @param string <p>The string containing the substrings</p> * @param string <p>The string containing the substrings</p>
* @param start <p>The substring before the wanted substring</p> * @param start <p>The substring before the wanted substring</p>
* @param end <p>The substring after the wanted substring</p> * @param end <p>The substring after the wanted substring</p>
* @return <p>The wanted substring</p> * @return <p>The wanted substring</p>
*/ */
public static String stringBetween(String string, String start, String end) { public static String stringBetween(String string, String start, String end) {
@ -67,7 +73,7 @@ public class CommonFunctions {
* *
* <p>This is used to find the newest version of jars and the software.</p> * <p>This is used to find the newest version of jars and the software.</p>
* *
* @param path <p>The full url of the file to read</p> * @param path <p>The full url of the file to readFromServer</p>
* @return <p>True if successful. False otherwise</p> * @return <p>True if successful. False otherwise</p>
*/ */
public static String readFile(String path) throws IOException { public static String readFile(String path) throws IOException {
@ -78,7 +84,7 @@ public class CommonFunctions {
/** /**
* Downloads a file from a website and replaces the target file * Downloads a file from a website and replaces the target file
* *
* @param path <p>The full url of the file to download</p> * @param path <p>The full url of the file to download</p>
* @param outfile <p>The file to save to</p> * @param outfile <p>The file to save to</p>
* @return <p>True if successful. False otherwise</p> * @return <p>True if successful. False otherwise</p>
*/ */
@ -96,7 +102,7 @@ public class CommonFunctions {
/** /**
* Recursively copies a folder to another location * Recursively copies a folder to another location
* *
* @param source <p>The folder to copy</p> * @param source <p>The folder to copy</p>
* @param destination <p>Target destination</p> * @param destination <p>Target destination</p>
* @throws IOException <p>If we can't start a file stream</p> * @throws IOException <p>If we can't start a file stream</p>
*/ */
@ -124,8 +130,8 @@ public class CommonFunctions {
* Copies a file from one location to another * Copies a file from one location to another
* *
* @param serverLauncherGui <p>The serverLauncherGui to use for alerting the user</p> * @param serverLauncherGui <p>The serverLauncherGui to use for alerting the user</p>
* @param source <p>The file to copy</p> * @param source <p>The file to copy</p>
* @param destination <p>The location of the copied file</p> * @param destination <p>The location of the copied file</p>
* @throws IOException <p>If reading or writing fails</p> * @throws IOException <p>If reading or writing fails</p>
*/ */
private static void copyFile(ServerLauncherGUI serverLauncherGui, File source, File destination) throws IOException { private static void copyFile(ServerLauncherGUI serverLauncherGui, File source, File destination) throws IOException {
@ -144,6 +150,7 @@ public class CommonFunctions {
/** /**
* Opens an url in the user's default application. * Opens an url in the user's default application.
*
* @param url <p>The URL to open</p> * @param url <p>The URL to open</p>
*/ */
public static void goToURL(String url) { public static void goToURL(String url) {