37 Commits

Author SHA1 Message Date
b6baa9ad6f Updates software version to 1.3.3
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-17 01:08:14 +02:00
c2f12a1a49 Adds the underscore character to regexes for player detection
This fixes a bug where players with underscores in their names won't be added to the player list
2021-08-17 01:07:20 +02:00
5030b4932b Updates software version
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 15:22:34 +02:00
e47b34a472 Improves output logging and fixes some bugs
Fixes an error caused by the BuildTools directory not being created
Creates functions for writing to files in CommonFunctions
Adds some more error info to the log when BuildTools fails to download
Fixes some typos
Makes sure all visible text is logged
2021-08-03 15:22:04 +02:00
28291cf4c3 Updates software version
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 14:00:32 +02:00
f8ba6e7ad1 Fixes the software crashing if an old configuration is used
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 14:00:02 +02:00
c9c2a1b43b Fixes a maven warning
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 13:44:39 +02:00
0425617f4c Updates software version to 1.3
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 13:18:57 +02:00
12189c12d7 Comments out SpongeVanilla and SpongeForge for now
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 12:48:23 +02:00
00cfe78491 Increases readability a bit 2021-08-03 12:28:21 +02:00
dc362eb2c8 Simplifies the version comparator a bit
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 12:23:59 +02:00
73faa4408e Makes the version comparator more generic 2021-08-03 12:14:59 +02:00
85febdf41b Improves version checking to prevent and update notice when running an unreleased version
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 11:50:32 +02:00
6ca49d2ccd Adds a menu item for easily delete built .jar files
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 11:06:02 +02:00
429b1fcec0 Improves readability of the server launcher menu code 2021-08-03 10:40:12 +02:00
33795a90a9 Prevents jars from being built as part of jar downloading
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-03 10:16:43 +02:00
e4be75b770 Finishes custom java path
Adds missing menu items
Adds menu item functionality
2021-08-02 22:24:10 +02:00
0018816d90 Makes the software build Spigot and CraftBukkit jars if the latest version is chosen 2021-08-02 21:50:12 +02:00
f1eead3807 Adds various fixes to make the two java versions work as expected
Makes it possible to load a controller without generating a GUI, for better testing
Makes sure not to try and parse empty profile lines
Saves controller settings in a more readable and appendable format
Adds code for using the correct java version for the occasion
Adds a new function for writing to files
2021-08-02 21:06:22 +02:00
6ec44f1f92 Improves console and GUI messages
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
Adds newlines when writing to console
Add Error: on lines containing an error
Makes it clearer when a jar build is successful
Makes failures show errors rather than throwing exceptions
2021-08-02 17:57:09 +02:00
d61239c417 Removes BuildTools files after tests have finished 2021-08-02 17:54:35 +02:00
32c17c6005 Improves writing speed when not using a GUI
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
Uses buffered writers instead of System.out
Uses a GUI for writing JarBuilder messages
Adds some missing comments to the jar builder
2021-08-02 16:49:35 +02:00
52eacb9980 Adds 1.17 to server versions 2021-08-02 16:22:04 +02:00
043f2045e6 Makes some improvements
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
Saves the downloaded BuildTools version to the server version container
Adds a check to see whether the BuildTools file exists
Adds a helper function for reading local files
2021-08-02 16:09:22 +02:00
51ceac69da Makes the jar building finally work
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-08-02 11:38:43 +02:00
123a8eddda Adds some still not working code for building spigot and bukkit .jar files
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-06-11 20:41:30 +02:00
8cdb1f143c Adds a new function for deleting files recursively 2021-02-12 16:12:58 +01:00
3254481326 Improves server waiting and killing
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
Makes the client force stop servers if the stop button is clicked more than once
Prevents new servers from starting after server stop is initialized
2021-02-05 18:41:54 +01:00
fb705f4e13 Adds server console truncation after 1000 lines of output
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-02-05 15:53:29 +01:00
15dd8db31b Updates software version
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-01-29 20:42:56 +01:00
fa6a0df4c7 Removes the annoying delay before starting the first server when enabling server delay 2021-01-29 20:30:07 +01:00
8b0423e231 Updates software version
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-01-28 03:09:28 +01:00
b1454b1156 Improves username login/logout checking by using a proper regex match
Additionally, this commit fixes a bug where instead of Username, users are shown as Username[IP:PORT]
2021-01-28 03:08:10 +01:00
a4d7b1041c Updates software version
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2021-01-27 16:12:03 +01:00
a705fc8b3e Updates Minecraft server jar versions to 1.16.5 2021-01-27 16:11:50 +01:00
5fe4384b59 Updates software version
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good
2020-12-28 16:55:02 +01:00
2f31a6c248 Updates server version to 1.16.4 and fixes downloading of waterfall and travertine 2020-12-28 16:54:36 +01:00
37 changed files with 1222 additions and 287 deletions

1
.gitignore vendored
View File

@ -28,4 +28,5 @@ hs_err_pid*
bin/ bin/
out/ out/
.idea
*.txt *.txt

View File

@ -126,9 +126,9 @@
<version>2.8.5</version> <version>2.8.5</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit</artifactId> <artifactId>junit-jupiter-api</artifactId>
<version>4.11</version> <version>5.7.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@ -1,15 +1,16 @@
package net.knarcraft.minecraftserverlauncher; package net.knarcraft.minecraftserverlauncher;
import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.profile.Controller; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.Server;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles; import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI; import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import net.knarcraft.minecraftserverlauncher.utility.Updater; import net.knarcraft.minecraftserverlauncher.utility.Updater;
import java.awt.*; import java.awt.*;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
@ -27,21 +28,17 @@ import java.util.concurrent.TimeUnit;
public class Main { public class Main {
private static final String updateChannel = "beta"; private static final String updateChannel = "beta";
private static final String updateURL = "https://api.knarcraft.net/minecraftserverlauncher"; private static final String updateURL = "https://api.knarcraft.net/minecraftserverlauncher";
private static final Controller controller = Controller.getInstance(); private static final ServerLauncherController controller = ServerLauncherController.getInstance();
private static String applicationWorkDirectory; private static String applicationWorkDirectory;
private static boolean serversAreRunning = false; private static boolean serversAreRunning = false;
private static ServerLauncherGUI gui; private static ServerLauncherGUI gui;
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
Updater.checkForUpdate(updateURL, updateChannel); Updater.checkForUpdate(updateURL, updateChannel);
try (PrintWriter file = new PrintWriter(Main.getApplicationWorkDirectory() + File.separator + "latestrun.log")) { CommonFunctions.writeFile(Main.getApplicationWorkDirectory() + File.separator + "latestrun.log", "");
file.print("");
} catch (IOException e) {
e.printStackTrace();
}
EventQueue.invokeLater(() -> { EventQueue.invokeLater(() -> {
try { try {
new ServerConsoles(); ServerConsoles.instantiate();
controller.loadState(); controller.loadState();
gui = controller.getGUI(); gui = controller.getGUI();
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
@ -57,7 +54,7 @@ public class Main {
* *
* @return <p>The controller used by the software</p> * @return <p>The controller used by the software</p>
*/ */
public static Controller getController() { public static ServerLauncherController getController() {
return controller; return controller;
} }
@ -85,6 +82,7 @@ public class Main {
boolean runningNew = serversRunning(); boolean runningNew = serversRunning();
if (serversAreRunning && !runningNew) { if (serversAreRunning && !runningNew) {
//Servers stopped running //Servers stopped running
Server.serversStopped();
gui.updateGUIElementsWhenServersStartOrStop(false); gui.updateGUIElementsWhenServersStartOrStop(false);
gui.setStatus("Servers are stopped"); gui.setStatus("Servers are stopped");
} else if (!serversAreRunning && runningNew) { } else if (!serversAreRunning && runningNew) {

View File

@ -8,7 +8,7 @@ import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import javax.swing.*; import javax.swing.*;
import java.io.*; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
/** /**
@ -230,7 +230,9 @@ public class Profile {
*/ */
public static Profile fromString(String profileString) throws ConfigurationException { public static Profile fromString(String profileString) throws ConfigurationException {
Profile profile; Profile profile;
if (profileString.contains("?")) { if (profileString.equals("")) {
return null;
} else if (profileString.contains("?")) {
String[] data = profileString.split("\\?"); String[] data = profileString.split("\\?");
String[] profileData = data[0].split(";", -1); String[] profileData = data[0].split(";", -1);
profile = parseProfile(profileData); profile = parseProfile(profileData);

View File

@ -9,16 +9,20 @@ import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import net.knarcraft.minecraftserverlauncher.utility.JarDownloader; import net.knarcraft.minecraftserverlauncher.utility.JarDownloader;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import java.io.*; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
/** /**
* This class handles profiles, GUI creation and session restoration * This class handles profiles, GUI creation and session restoration
*/ */
public class Controller { public class ServerLauncherController {
private final String workingDirectory = Main.getApplicationWorkDirectory() + File.separator + "files"; private final String workingDirectory = Main.getApplicationWorkDirectory() + File.separator + "files";
private final String profilesFile = workingDirectory + File.separator + "Profiles.txt"; private final String profilesFile = workingDirectory + File.separator + "Profiles.txt";
@ -28,12 +32,14 @@ public class Controller {
private ServerLauncherGUI serverLauncherGUI; private ServerLauncherGUI serverLauncherGUI;
private Profile currentProfile; private Profile currentProfile;
private boolean downloadAllJars; private boolean downloadAllJars;
private static Controller controller; private static ServerLauncherController controller;
private String javaCommand = "java";
private String oldJavaCommand = "java";
/** /**
* Instantiates a new controller * Instantiates a new controller
*/ */
private Controller() { private ServerLauncherController() {
this.profileList = new ArrayList<>(); this.profileList = new ArrayList<>();
} }
@ -42,9 +48,9 @@ public class Controller {
* *
* @return <p>An instance of the controller</p> * @return <p>An instance of the controller</p>
*/ */
public static Controller getInstance() { public static ServerLauncherController getInstance() {
if (controller == null) { if (controller == null) {
controller = new Controller(); controller = new ServerLauncherController();
} }
return controller; return controller;
} }
@ -85,6 +91,47 @@ public class Controller {
return currentProfile.getDelayStartup(); return currentProfile.getDelayStartup();
} }
/**
* Gets the command for running java
*
* @return <p>The command for running Java</p>
*/
public String getJavaCommand() {
return javaCommand;
}
/**
* Gets the command for running older versions of Java
*
* <p>The command used to run older minecraft server versions. JRE 8 should probably work.
* Can be just "java" or a file path.</p>
*
* @return <p>The command for running older versions of Java</p>
*/
public String getOldJavaCommand() {
return oldJavaCommand;
}
/**
* Sets the command for running Java
*
* <p>To play on the newest version of Minecraft, this needs to be JDK 16. Can be just "java" or a file path.</p>
*
* @param javaCommand <p>The command used for running Java</p>
*/
public void setJavaCommand(String javaCommand) {
this.javaCommand = javaCommand;
}
/**
* Sets the command for running older versions of java
*
* @param oldJavaCommand <p>The command used for running older versions of Java</p>
*/
public void setOldJavaCommand(String oldJavaCommand) {
this.oldJavaCommand = oldJavaCommand;
}
@Override @Override
public String toString() { public String toString() {
int guiWidth; int guiWidth;
@ -96,7 +143,8 @@ public class Controller {
guiWidth = serverLauncherGUI.getSize().width; guiWidth = serverLauncherGUI.getSize().width;
guiHeight = serverLauncherGUI.getSize().height; guiHeight = serverLauncherGUI.getSize().height;
} }
return String.format("%s;%d;%d;%b", currentProfile.getName(), guiWidth, guiHeight, downloadAllJars); return String.format("selectedProfile;%s\nguiWidth;%d\nguiHeight;%d\ndownloadAllJars;%b\njavaCommand;%s\noldJavaCommand;%s",
currentProfile.getName(), guiWidth, guiHeight, downloadAllJars, javaCommand, oldJavaCommand);
} }
/** /**
@ -171,37 +219,135 @@ public class Controller {
} }
/** /**
* Loads data about the controller from a save string * Sets the download all jars option
* *
* @param data <p>The save string to load</p> * @param downloadAllJars <p>Whether to download all jars</p>
* @return <p>The currently selected profile</p>
* @throws IOException <p>If unable to create the GUI</p>
*/ */
private String fromString(String data) throws IOException { public void setDownloadAllJars(boolean downloadAllJars) {
String[] dataList = data.split(";"); this.downloadAllJars = downloadAllJars;
this.downloadAllJars = Boolean.parseBoolean(dataList[3]); }
this.serverLauncherGUI = new ServerLauncherGUI(Integer.parseInt(dataList[1]), Integer.parseInt(dataList[2]));
return dataList[0]; /**
* Sets the currently selected profile
*
* @param profileName <p>The name of the currently selected profile</p>
*/
public void setCurrentProfile(String profileName) {
this.currentProfile = getProfileByName(profileName);
}
/**
* Gets the directory containing .jar files
*
* @return <p>The directory containing .jar files</p>
*/
public String getJarDirectory() {
return this.jarDirectory;
}
/**
* Saves the state of the entire application to disk
*/
public void saveState() {
saveGUIStateToServer();
try {
CommonFunctions.createAllFolders();
CommonFunctions.writeFile(mainFile, this.toString());
StringBuilder builder = new StringBuilder();
for (Profile profile : profileList) {
builder.append(profile.toString()).append("\n");
}
CommonFunctions.writeFile(profilesFile, builder.toString());
} catch (IOException e) {
serverLauncherGUI.showError("Unable to save data.");
e.printStackTrace();
}
} }
/** /**
* Reads profiles and servers from a text file * Reads profiles and servers from a text file
*/ */
public void loadState() throws ConfigurationException, IOException { public void loadState() throws ConfigurationException, IOException {
loadState(false);
}
/**
* Reads profiles and servers from a text file
*
* @param silent <p>If silent, no GUI will be created</p>
*/
public void loadState(boolean silent) throws ConfigurationException, IOException {
//Loads data regarding this controller //Loads data regarding this controller
String currentProfile = null; String currentProfile = null;
if (new File(mainFile).exists()) { if (new File(mainFile).exists()) {
String controllerData = CommonFunctions.readBufferedReader(new BufferedReader(new InputStreamReader(new FileInputStream(mainFile)))); currentProfile = this.fromString(silent);
currentProfile = this.fromString(controllerData); } else if (!silent) {
} else {
this.serverLauncherGUI = new ServerLauncherGUI(); this.serverLauncherGUI = new ServerLauncherGUI();
} }
if (silent) {
return;
}
//Loads all saved profiles //Loads all saved profiles
loadProfiles(currentProfile); loadProfiles(currentProfile);
//Makes the GUI show the loaded data //Makes the GUI show the loaded data
executeGUILoadingTasks(); executeGUILoadingTasks();
} }
/**
* Loads data about the controller from a save string
*
* @param silent <p>If silent, no GUI will be created</p>
* @return <p>The currently selected profile</p>
*/
private String fromString(boolean silent) {
Map<String, String> loadedData = new HashMap<>();
try {
String currentData = CommonFunctions.readFile(mainFile);
for (String line : currentData.split("\n")) {
parseSaveLine(loadedData, line);
}
this.downloadAllJars = Boolean.parseBoolean(loadedData.get("downloadAllJars"));
if (!silent) {
if (loadedData.get("guiWidth") != null && loadedData.get("guiHeight") != null) {
this.serverLauncherGUI = new ServerLauncherGUI(Integer.parseInt(loadedData.get("guiWidth")),
Integer.parseInt(loadedData.get("guiHeight")));
} else {
this.serverLauncherGUI = new ServerLauncherGUI();
}
} else {
this.serverLauncherGUI = new ServerLauncherGUI(true);
}
if (loadedData.get("javaCommand") != null) {
this.javaCommand = loadedData.get("javaCommand");
}
if (loadedData.get("oldJavaCommand") != null) {
this.oldJavaCommand = loadedData.get("oldJavaCommand");
}
return loadedData.get("selectedProfile");
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* Saves one config line to the provided map
*
* @param loadedData <p>The map to save the loaded configuration to</p>
* @param line <p>The line to read</p>
*/
private void parseSaveLine(Map<String, String> loadedData, String line) {
String[] lineData = line.split(";");
if (lineData.length != 2) {
return;
}
loadedData.put(lineData[0], lineData[1]);
}
/** /**
* Loads all saved profiles * Loads all saved profiles
* *
@ -213,6 +359,9 @@ public class Controller {
while (in.hasNextLine()) { while (in.hasNextLine()) {
String profileData = in.nextLine(); String profileData = in.nextLine();
Profile loadedProfile = Profile.fromString(profileData); Profile loadedProfile = Profile.fromString(profileData);
if (loadedProfile == null) {
continue;
}
profileList.add(loadedProfile); profileList.add(loadedProfile);
} }
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
@ -248,45 +397,6 @@ public class Controller {
} }
} }
/**
* Sets the download all jars option
*
* @param downloadAllJars <p>Whether to download all jars</p>
*/
public void setDownloadAllJars(boolean downloadAllJars) {
this.downloadAllJars = downloadAllJars;
}
/**
* Sets the currently selected profile
*
* @param profileName <p>The name of the currently selected profile</p>
*/
public void setCurrentProfile(String profileName) {
this.currentProfile = getProfileByName(profileName);
}
/**
* Saves the state of the entire application to disk
*/
public void saveState() {
saveGUIStateToServer();
try {
CommonFunctions.createAllFolders();
PrintWriter mFile = new PrintWriter(mainFile);
mFile.println(this.toString());
mFile.close();
PrintWriter pFile = new PrintWriter(profilesFile);
for (Profile profile : profileList) {
pFile.println(profile.toString());
}
pFile.close();
} catch (FileNotFoundException e) {
serverLauncherGUI.showError("Unable to save data.");
e.printStackTrace();
}
}
/** /**
* Updates the server object with the current state of the GUI server tab * Updates the server object with the current state of the GUI server tab
*/ */

View File

@ -2,7 +2,7 @@ package net.knarcraft.minecraftserverlauncher.server;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.profile.Controller; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType; import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions; import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
@ -19,8 +19,8 @@ import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween; import java.util.regex.Pattern;
/** /**
@ -51,6 +51,7 @@ public class Server {
private BufferedReader reader; private BufferedReader reader;
private boolean started; private boolean started;
private ScheduledExecutorService consoleOutputExecutor; private ScheduledExecutorService consoleOutputExecutor;
private static boolean stoppingServers = false;
/** /**
* Initializes a new server with default values * Initializes a new server with default values
@ -108,12 +109,27 @@ public class Server {
return this.reader; return this.reader;
} }
/**
* Marks the servers as finished stopping when a stop is confirmed
*/
public static void serversStopped() {
if (stoppingServers) {
stoppingServers = false;
}
}
/** /**
* Tries to stop all enabled servers * Tries to stop all enabled servers
* *
* @throws IOException <p>If a writer's process is already closed but not null</p> * @throws IOException <p>If a writer's process is already closed but not null</p>
*/ */
public static void stop() throws IOException { public static void stop() throws IOException, InterruptedException {
if (stoppingServers) {
killServers();
return;
}
stoppingServers = true;
for (Collection collection : Main.getController().getCurrentProfile().getCollections()) { for (Collection collection : Main.getController().getCurrentProfile().getCollections()) {
Server server = collection.getServer(); Server server = collection.getServer();
if (server.writer != null) { if (server.writer != null) {
@ -129,18 +145,46 @@ public class Server {
} }
} }
/**
* Kills all server processes
*
* @throws InterruptedException <p>If interrupted waiting for any of the servers to stop</p>
*/
private static void killServers() throws InterruptedException {
for (Collection collection : Main.getController().getCurrentProfile().getCollections()) {
Server server = collection.getServer();
killServer(server);
}
}
/**
* Kills the given server after waiting 30 seconds for it to terminate normally
*
* @param server <p>The server to kill</p>
* @throws InterruptedException <p>If interrupted waiting for the server to stop</p>
*/
private static void killServer(Server server) throws InterruptedException {
if (server.process != null) {
if (!server.process.waitFor(30, TimeUnit.SECONDS)) {
server.process.destroyForcibly();
server.process.waitFor();
}
}
}
/** /**
* Runs all enabled servers with their settings * Runs all enabled servers with their settings
*/ */
public static void startServers() { public static void startServers() {
Controller controller = Main.getController(); ServerLauncherController controller = Main.getController();
controller.getGUI().setStatus("Starting servers"); controller.getGUI().setStatus("Starting servers");
int serverNum = 0;
for (Collection collection : controller.getCurrentProfile().getCollections()) { for (Collection collection : controller.getCurrentProfile().getCollections()) {
if (!collection.getServer().runServer()) { if (!collection.getServer().runServer(serverNum++ == 0)) {
controller.getGUI().setStatus("An error occurred. Start aborted"); controller.getGUI().showError("An error occurred. Start aborted. Please check the BuildTools log.");
try { try {
Server.stop(); Server.stop();
} catch (IOException e) { } catch (IOException | InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
controller.getGUI().updateGUIElementsWhenServersStartOrStop(false); controller.getGUI().updateGUIElementsWhenServersStartOrStop(false);
@ -280,9 +324,9 @@ public class Server {
} }
/** /**
* Checks whether this server is fully stopped * Removes all information about the server's process, writer and reader
*/ */
private void stopped() { private void cleanStoppedServerValues() {
consoleOutputExecutor.shutdown(); consoleOutputExecutor.shutdown();
process = null; process = null;
writer = null; writer = null;
@ -357,17 +401,23 @@ public class Server {
* *
* @return <p>True if nothing went wrong</p> * @return <p>True if nothing went wrong</p>
*/ */
private boolean runServer() { private boolean runServer(boolean isFirstServer) {
if (stoppingServers) {
return false;
}
//Ignore a disabled server //Ignore a disabled server
if (!this.enabled) { if (!this.enabled) {
this.started = false; this.started = false;
return true; return true;
} }
//Tries to do necessary pre-start work //Tries to do necessary pre-start work
if (!initializeJarDownload() || !delayStartup()) { if (!initializeJarDownload() || (!isFirstServer && !delayStartup())) {
this.started = false; this.started = false;
return false; return false;
} }
if (stoppingServers) {
return false;
}
//Starts the server if possible //Starts the server if possible
try { try {
startServerProcess(); startServerProcess();
@ -381,6 +431,23 @@ public class Server {
} }
} }
/**
* Gets the correct java command to use for the selected server version
*
* @return <p>The java version to run</p>
*/
private String getJavaCommand() {
ServerLauncherController controller = ServerLauncherController.getInstance();
if (serverVersion.toLowerCase().contains("latest")) {
return controller.getJavaCommand();
} else if (serverVersion.contains(".") && serverVersion.split("\\.").length >= 2 &&
Integer.parseInt(serverVersion.split("\\.")[1]) >= 17) {
return controller.getJavaCommand();
} else {
return controller.getOldJavaCommand();
}
}
/** /**
* Starts the process running this server * Starts the process running this server
* *
@ -395,7 +462,7 @@ public class Server {
} else { } else {
serverPath = jarDirectory + this.type.getName() + serverVersion + ".jar"; serverPath = jarDirectory + this.type.getName() + serverVersion + ".jar";
} }
builder = new ProcessBuilder("java", "-Xmx" + this.maxRam, "-Xms512M", builder = new ProcessBuilder(getJavaCommand(), "-Xmx" + this.maxRam, "-Xms512M",
"-Djline.terminal=jline.UnsupportedTerminal", "-Dcom.mojang.eula.agree=true", "-jar", serverPath, "-Djline.terminal=jline.UnsupportedTerminal", "-Dcom.mojang.eula.agree=true", "-jar", serverPath,
"nogui"); "nogui");
builder.directory(new File(this.path)); builder.directory(new File(this.path));
@ -427,14 +494,14 @@ public class Server {
updatePlayerList(readText); updatePlayerList(readText);
} }
if (!getProcess().isAlive()) { if (!getProcess().isAlive()) {
stopped(); cleanStoppedServerValues();
} }
} }
/** /**
* Looks for strings implying a player has joined or left, and updates the appropriate lists * Looks for strings implying a player has joined or left, and updates the appropriate lists
* *
* @param text <p>The text to search</p> * @param text <p>The text to search</p>
*/ */
private void updatePlayerList(String text) { private void updatePlayerList(String text) {
if (!getType().isProxy()) { if (!getType().isProxy()) {
@ -461,23 +528,44 @@ public class Server {
*/ */
private String getPlayer(String text, boolean joined) { private String getPlayer(String text, boolean joined) {
String playerName; String playerName;
String loginPattern1 = " ([A-Z0-9a-z_]+)\\[/[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+:[0-9]+] logged in";
String loginPattern2 = "UUID of player ([A-Z0-9a-z_]+) is";
String logoutPattern1 = "INFO]: ([A-Z0-9a-z_]+) lost connection";
String logoutPattern2 = " ([A-Z0-9a-z_]+) left the game";
if (joined) { if (joined) {
playerName = stringBetween(text, "[Server thread/INFO]: ", " joined the game"); playerName = getFirstRegexCaptureGroup(loginPattern1, text);
if (playerName.equals("")) { if (playerName.equals("")) {
playerName = stringBetween(text, "UUID of player ", " is "); playerName = getFirstRegexCaptureGroup(loginPattern2, text);
} }
} else { } else {
playerName = stringBetween(text, "INFO]: ", " lost connection"); playerName = getFirstRegexCaptureGroup(logoutPattern1, text);
if (playerName.equals("")) { if (playerName.equals("")) {
playerName = stringBetween(text, "[Server thread/INFO]: ", " left the game"); playerName = getFirstRegexCaptureGroup(logoutPattern2, text);
}
if (playerName.equals("")) {
playerName = stringBetween(text, "INFO]: ", " left the game");
} }
} }
return playerName; return playerName;
} }
/**
* Returns the first regex capture group found in a pattern
*
* @param pattern <p>The regex pattern to use</p>
* @param text <p>The string to execute the pattern on</p>
* @return <p>The first capture group if a match is found. An empty string otherwise</p>
*/
private String getFirstRegexCaptureGroup(String pattern, String text) {
Pattern compiledPattern = Pattern.compile(pattern);
Matcher patternMatcher = compiledPattern.matcher(text);
if (patternMatcher.find()) {
return patternMatcher.group(1);
} else {
return "";
}
}
/** /**
* Delays the server's startup for the given amount of time * Delays the server's startup for the given amount of time
* *
@ -501,7 +589,7 @@ public class Server {
* @return <p>True if nothing went wrong</p> * @return <p>True if nothing went wrong</p>
*/ */
private boolean initializeJarDownload() { private boolean initializeJarDownload() {
Controller controller = Main.getController(); ServerLauncherController controller = Main.getController();
if (!controller.getDownloadAllJars()) { if (!controller.getDownloadAllJars()) {
try { try {
controller.getGUI().setStatus("Downloading jar..."); controller.getGUI().setStatus("Downloading jar...");

View File

@ -1,6 +1,17 @@
package net.knarcraft.minecraftserverlauncher.server; package net.knarcraft.minecraftserverlauncher.server;
import net.knarcraft.minecraftserverlauncher.server.servertypes.*; import net.knarcraft.minecraftserverlauncher.server.servertypes.BungeeCord;
import net.knarcraft.minecraftserverlauncher.server.servertypes.CraftBukkit;
import net.knarcraft.minecraftserverlauncher.server.servertypes.Custom;
import net.knarcraft.minecraftserverlauncher.server.servertypes.MCPCPlus;
import net.knarcraft.minecraftserverlauncher.server.servertypes.Paper;
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
import net.knarcraft.minecraftserverlauncher.server.servertypes.Spigot;
import net.knarcraft.minecraftserverlauncher.server.servertypes.SpongeForge;
import net.knarcraft.minecraftserverlauncher.server.servertypes.SpongeVanilla;
import net.knarcraft.minecraftserverlauncher.server.servertypes.Travertine;
import net.knarcraft.minecraftserverlauncher.server.servertypes.Vanilla;
import net.knarcraft.minecraftserverlauncher.server.servertypes.Waterfall;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -76,8 +87,13 @@ public class ServerTypeHandler {
throw new ConfigurationException("Server type configuration file is missing."); throw new ConfigurationException("Server type configuration file is missing.");
} }
while (file.hasNextLine()) { while (file.hasNextLine()) {
String nextLine = file.nextLine();
if (nextLine.startsWith("#")) {
continue;
}
//Splits the next file line into arguments //Splits the next file line into arguments
String[] serverTypeInfo = file.nextLine().split(";", -1); String[] serverTypeInfo = nextLine.split(";", -1);
//Gets list of server versions from file line //Gets list of server versions from file line
String[] serverVersions; String[] serverVersions;

View File

@ -3,7 +3,10 @@ package net.knarcraft.minecraftserverlauncher.server;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions; import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import java.io.*; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -21,6 +24,7 @@ public class ServerVersionContainer {
private Map<String, String> travertineVersions; private Map<String, String> travertineVersions;
private Map<String, String> spongeVanillaVersions; private Map<String, String> spongeVanillaVersions;
private Map<String, String> spongeForgeVersions; private Map<String, String> spongeForgeVersions;
private String downloadedBuildToolsVersion;
/** /**
* Initializes a new server version container * Initializes a new server version container
@ -56,6 +60,7 @@ public class ServerVersionContainer {
this.travertineVersions = new HashMap<>(); this.travertineVersions = new HashMap<>();
this.spongeVanillaVersions = new HashMap<>(); this.spongeVanillaVersions = new HashMap<>();
this.spongeForgeVersions = new HashMap<>(); this.spongeForgeVersions = new HashMap<>();
this.downloadedBuildToolsVersion = null;
} }
@Override @Override
@ -66,7 +71,8 @@ public class ServerVersionContainer {
"waterfallVersions;" + mapToString(waterfallVersions) + "\n" + "waterfallVersions;" + mapToString(waterfallVersions) + "\n" +
"travertineVersions;" + mapToString(travertineVersions) + "\n" + "travertineVersions;" + mapToString(travertineVersions) + "\n" +
"spongeVanillaVersions;" + mapToString(spongeVanillaVersions) + "\n" + "spongeVanillaVersions;" + mapToString(spongeVanillaVersions) + "\n" +
"spongeForgeVersions;" + mapToString(spongeForgeVersions); "spongeForgeVersions;" + mapToString(spongeForgeVersions) + "\n" +
"downloadedBuildToolsVersion;" + downloadedBuildToolsVersion;
} }
/** /**
@ -105,7 +111,7 @@ public class ServerVersionContainer {
} }
} }
file = new PrintWriter(versionFile); file = new PrintWriter(versionFile);
file.println(this.toString()); file.println(this);
file.close(); file.close();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -119,8 +125,8 @@ public class ServerVersionContainer {
if (!new File(versionFile).exists()) { if (!new File(versionFile).exists()) {
return; return;
} }
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(versionFile)))) { try {
String currentData = CommonFunctions.readBufferedReader(reader); String currentData = CommonFunctions.readFile(versionFile);
for (String line : currentData.split("\n")) { for (String line : currentData.split("\n")) {
parseSaveLine(line); parseSaveLine(line);
} }
@ -163,6 +169,9 @@ public class ServerVersionContainer {
case "spongeForgeVersions": case "spongeForgeVersions":
parseVersionsToMap(spongeForgeVersions, variableValue); parseVersionsToMap(spongeForgeVersions, variableValue);
break; break;
case "downloadedBuildToolsVersion":
downloadedBuildToolsVersion = variableValue;
break;
default: default:
throw new IllegalArgumentException("Invalid key encountered in the server version file."); throw new IllegalArgumentException("Invalid key encountered in the server version file.");
} }
@ -172,9 +181,9 @@ public class ServerVersionContainer {
* Reads versions from a text string and updates the version map * Reads versions from a text string and updates the version map
* *
* @param targetMap <p>The map to update</p> * @param targetMap <p>The map to update</p>
* @param data <p>The data string to parse</p> * @param data <p>The data string to parse</p>
*/ */
private void parseVersionsToMap(Map<String,String> targetMap, String data) { private void parseVersionsToMap(Map<String, String> targetMap, String data) {
String[] versions = data.split(","); String[] versions = data.split(",");
for (String version : versions) { for (String version : versions) {
String[] versionData = version.split("!"); String[] versionData = version.split("!");
@ -323,5 +332,25 @@ public class ServerVersionContainer {
spongeForgeVersions.put(mapKey, newValue); spongeForgeVersions.put(mapKey, newValue);
saveState(); saveState();
} }
/**
* Gets the version of the downloaded BuildTools file
*
* @return <p>The version of the downloaded BuildTools file</p>
*/
public String getDownloadedBuildToolsVersion() {
return this.downloadedBuildToolsVersion;
}
/**
* Sets the version of the downloaded BuildTools file
*
* @param newValue <p>The new version</p></p>
*/
public void setDownloadedBuildToolsVersion(String newValue) {
this.downloadedBuildToolsVersion = newValue;
saveState();
}
} }

View File

@ -7,7 +7,7 @@ import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readRemoteFile;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween;
/** /**
@ -65,7 +65,7 @@ public class BungeeCord extends AbstractServerType {
private boolean downloadLatestJar(File filePath) throws IOException { private boolean downloadLatestJar(File filePath) throws IOException {
ServerVersionContainer versionContainer = ServerVersionContainer.getInstance(); ServerVersionContainer versionContainer = ServerVersionContainer.getInstance();
String newestVersion = stringBetween(readFile(versionURL), srcStart, srcEnd); String newestVersion = stringBetween(readRemoteFile(versionURL), srcStart, srcEnd);
String oldVersion = versionContainer.getBungeeVersion(); String oldVersion = versionContainer.getBungeeVersion();
//The file is already the newest version //The file is already the newest version
if (filePath.isFile() && newestVersion.equals(oldVersion)) { if (filePath.isFile() && newestVersion.equals(oldVersion)) {

View File

@ -1,5 +1,10 @@
package net.knarcraft.minecraftserverlauncher.server.servertypes; package net.knarcraft.minecraftserverlauncher.server.servertypes;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
import net.knarcraft.minecraftserverlauncher.utility.JarBuilder;
import java.io.File; import java.io.File;
import java.nio.file.Paths; import java.nio.file.Paths;
@ -31,7 +36,31 @@ public class CraftBukkit extends AbstractServerType {
String targetFile = this.getName() + version + ".jar"; String targetFile = this.getName() + version + ".jar";
String file = downloadURLPart + version + ".jar"; String file = downloadURLPart + version + ".jar";
File filePath = new File(folder + targetFile); File filePath = new File(folder + targetFile);
return filePath.isFile() || downloadFile(downloadURL + file, Paths.get(filePath.toURI()));
if (version.equals("Latest")) {
return filePath.isFile() || buildJar(folder);
} else {
return filePath.isFile() || downloadFile(downloadURL + file, Paths.get(filePath.toURI()));
}
}
/**
* Builds the necessary .jar file
*
* @param folder <p>The folder the build file should be moved to</p>
* @return <p>True if the build was successful</p>
*/
private boolean buildJar(String folder) {
String buildToolsDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator +
"BuildTools" + File.separator;
GUI gui = ServerLauncherController.getInstance().getGUI();
JarBuilder jarBuilder = new JarBuilder(buildToolsDirectory, folder, gui);
if (this instanceof Spigot) {
return jarBuilder.buildSpigotJar();
} else {
return jarBuilder.buildBukkitJar();
}
} }
} }

View File

@ -20,8 +20,8 @@ public class SpongeVanilla extends AbstractServerType {
private final String srcStart; private final String srcStart;
private final String srcEnd; private final String srcEnd;
private final String downloadURLPart; private final String downloadURLPart;
Function<String,String> oldVersionFunction; Function<String, String> oldVersionFunction;
BiConsumer<String,String> versionUpdateFunction; BiConsumer<String, String> versionUpdateFunction;
final ServerVersionContainer serverVersionContainer; final ServerVersionContainer serverVersionContainer;
/** /**
@ -53,7 +53,7 @@ public class SpongeVanilla extends AbstractServerType {
String file = this.getName() + version + ".jar"; String file = this.getName() + version + ".jar";
File filePath = new File(folder + file); File filePath = new File(folder + file);
String versionText = CommonFunctions.readFile(versionURL + version); String versionText = CommonFunctions.readRemoteFile(versionURL + version);
String newestVersion = CommonFunctions.stringBetween(versionText, srcStart, srcEnd); String newestVersion = CommonFunctions.stringBetween(versionText, srcStart, srcEnd);
String jarURL = downloadURL + newestVersion + downloadURLPart + newestVersion + ".jar"; String jarURL = downloadURL + newestVersion + downloadURLPart + newestVersion + ".jar";

View File

@ -12,7 +12,7 @@ import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readRemoteFile;
/** /**
* This class represents the regular vanilla Minecraft server type * This class represents the regular vanilla Minecraft server type
@ -54,9 +54,9 @@ public class Vanilla extends AbstractServerType {
/** /**
* Downloads the latest .jar file found if necessary * Downloads the latest .jar file found if necessary
* *
* @param filePath <p>The path of the jar file to download</p> * @param filePath <p>The path of the jar file to download</p>
* @param releaseType <p>The release type used for downloading</p> * @param releaseType <p>The release type used for downloading</p>
* @param lastVersion <p>The last server version found</p> * @param lastVersion <p>The last server version found</p>
* @param versionContainer <p>The version container to use</p> * @param versionContainer <p>The version container to use</p>
* @return <p>True if the jar exists and is the latest version or was downloaded</p> * @return <p>True if the jar exists and is the latest version or was downloaded</p>
* @throws IOException <p>If the .jar cannot be downloaded</p> * @throws IOException <p>If the .jar cannot be downloaded</p>
@ -90,7 +90,7 @@ public class Vanilla extends AbstractServerType {
* @throws IOException <p>If the remote resource cannot be readFromServer</p> * @throws IOException <p>If the remote resource cannot be readFromServer</p>
*/ */
private String[] getLatestFile(String releaseType) throws IOException { private String[] getLatestFile(String releaseType) throws IOException {
String versionText = readFile(versionURL); String versionText = readRemoteFile(versionURL);
JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject(); JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
String latest = jsonObject.getAsJsonObject("latest").get(releaseType).getAsString(); String latest = jsonObject.getAsJsonObject("latest").get(releaseType).getAsString();
String versionURL = getServerFileVersionURL(latest); String versionURL = getServerFileVersionURL(latest);
@ -106,7 +106,7 @@ public class Vanilla extends AbstractServerType {
* @throws IOException <p>If the remote resource cannot be readFromServer</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 = readRemoteFile(versionURL);
JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject(); JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
return jsonObject.getAsJsonObject("downloads").getAsJsonObject("server").get("url").getAsString(); return jsonObject.getAsJsonObject("downloads").getAsJsonObject("server").get("url").getAsString();
} }
@ -119,7 +119,7 @@ public class Vanilla extends AbstractServerType {
* @throws IOException <p>If the file cannot be downloaded</p> * @throws IOException <p>If the file cannot be downloaded</p>
*/ */
private String getServerFileVersionURL(String targetVersion) throws IOException { private String getServerFileVersionURL(String targetVersion) throws IOException {
String versionText = readFile(versionURL); String versionText = readRemoteFile(versionURL);
JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject(); JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
JsonArray availableVersions = jsonObject.getAsJsonArray("versions"); JsonArray availableVersions = jsonObject.getAsJsonArray("versions");
for (JsonElement availableVersion : availableVersions) { for (JsonElement availableVersion : availableVersions) {

View File

@ -9,7 +9,7 @@ import java.util.function.BiConsumer;
import java.util.function.Function; import java.util.function.Function;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readRemoteFile;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween;
/** /**
@ -50,7 +50,7 @@ public class Waterfall extends AbstractServerType {
public boolean downloadJar(String folder, String version) throws IOException { public boolean downloadJar(String folder, String version) throws IOException {
String file = this.getName() + version + ".jar"; String file = this.getName() + version + ".jar";
File filePath = new File(folder + file); File filePath = new File(folder + file);
String newestVersion = stringBetween(readFile(versionURL + version), srcStart, srcEnd); String newestVersion = stringBetween(readRemoteFile(versionURL + version), srcStart, srcEnd);
String fullURL = downloadURL + version + "/" + newestVersion + "/download"; String fullURL = downloadURL + version + "/" + newestVersion + "/download";
String oldVersion = oldVersionFunction.apply(version); String oldVersion = oldVersionFunction.apply(version);
//The file is already the newest version //The file is already the newest version

View File

@ -5,7 +5,11 @@ import net.knarcraft.minecraftserverlauncher.Main;
import javax.swing.*; import javax.swing.*;
import javax.swing.text.DefaultCaret; import javax.swing.text.DefaultCaret;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList; import java.util.ArrayList;
import static javax.swing.text.DefaultCaret.ALWAYS_UPDATE; import static javax.swing.text.DefaultCaret.ALWAYS_UPDATE;
@ -26,11 +30,12 @@ public class Console extends KeyAdapter implements ActionListener, KeyListener {
private final JPanel panel; private final JPanel panel;
private final ArrayList<String> commands = new ArrayList<>(); private final ArrayList<String> commands = new ArrayList<>();
private int commandIndex; private int commandIndex;
private final int maxConsoleLines = 1000;
/** /**
* Instantiates a new console * Instantiates a new console
* *
* @param tab <p>The tabbed pane used for displaying the console</p> * @param tab <p>The tabbed pane used for displaying the console</p>
* @param name <p>The name of the console tab</p> * @param name <p>The name of the console tab</p>
*/ */
Console(JTabbedPane tab, String name) { Console(JTabbedPane tab, String name) {
@ -67,9 +72,33 @@ public class Console extends KeyAdapter implements ActionListener, KeyListener {
* @param text <p>The string to print</p> * @param text <p>The string to print</p>
*/ */
public void output(String text) { public void output(String text) {
int outputLines = this.textOutput.getLineCount();
if (outputLines > maxConsoleLines) {
truncateConsole(outputLines);
}
this.textOutput.setText(this.textOutput.getText() + "\n" + text); this.textOutput.setText(this.textOutput.getText() + "\n" + text);
} }
/**
* Truncates the first 50 lines if the console output has reached the max limit
*
* @param outputLines <p>The currently readable lines in the console output field</p>
*/
private void truncateConsole(int outputLines) {
String oldText = this.textOutput.getText();
String[] oldTextList = oldText.split("\n");
for (int i = 0; i < outputLines - maxConsoleLines + 50; i++) {
oldTextList[i] = "";
}
StringBuilder newTextBuilder = new StringBuilder();
for (String line : oldTextList) {
if (!line.equals("")) {
newTextBuilder.append(line);
}
}
this.textOutput.setText(newTextBuilder.toString());
}
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
//Sends the command from the input to the server with the same name. //Sends the command from the input to the server with the same name.
@ -99,7 +128,7 @@ public class Console extends KeyAdapter implements ActionListener, KeyListener {
* Shows the previously executed command in the input field * Shows the previously executed command in the input field
* *
* <p>Shows the previously executed command if a command was just executed. * <p>Shows the previously executed command if a command was just executed.
* Shows the command executed earlier if already showing a previously executed command.</p> * Shows the command executed earlier if already showing a previously executed command</p>
*/ */
private void showPreviousCommand() { private void showPreviousCommand() {
if (commands.size() > 0 && commandIndex > 0) { if (commands.size() > 0 && commandIndex > 0) {
@ -111,7 +140,7 @@ public class Console extends KeyAdapter implements ActionListener, KeyListener {
* Shows the next previously executed command or clears the input field * Shows the next previously executed command or clears the input field
* *
* <p>Shows the next previously executed command if such a command exists. * <p>Shows the next previously executed command if such a command exists.
* Clears the input field if no next used command exists.</p> * Clears the input field if no next used command exists</p>
*/ */
private void showNextCommand() { private void showNextCommand() {
if (commands.size() > 0) { if (commands.size() > 0) {

View File

@ -44,6 +44,20 @@ public interface GUI {
*/ */
void showMessage(String message); void showMessage(String message);
/**
* Logs a message to the logfile
*
* @param message <p>The message to log</p>
*/
void logMessage(String message);
/**
* Logs an error to the logfile
*
* @param error <p>The error to log</p>
*/
void logError(String error);
/** /**
* Asks the user for a directory as a file object * Asks the user for a directory as a file object
* *

View File

@ -1,6 +1,13 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import javax.swing.*; import javax.swing.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
/** /**
* This class handles displaying messages to the user * This class handles displaying messages to the user
@ -8,6 +15,8 @@ import javax.swing.*;
public abstract class MessageHandler implements GUI { public abstract class MessageHandler implements GUI {
private final boolean silent; private final boolean silent;
private final BufferedWriter writer;
private final String logFile = Main.getApplicationWorkDirectory() + File.separator + "latestrun.log";
/*** /***
* Initializes a new message handler * Initializes a new message handler
@ -16,15 +25,42 @@ public abstract class MessageHandler implements GUI {
*/ */
public MessageHandler(boolean silent) { public MessageHandler(boolean silent) {
this.silent = silent; this.silent = silent;
this.writer = new BufferedWriter(new OutputStreamWriter(System.out));
}
@Override
public void logMessage(String message) {
try {
CommonFunctions.appendFile(logFile, "[Info]: " + message);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void logError(String message) {
try {
CommonFunctions.appendFile(logFile, "[Error]: " + message);
} catch (IOException e) {
e.printStackTrace();
}
} }
@Override @Override
public void showError(String title, String message) { public void showError(String title, String message) {
if (silent) { if (silent) {
System.out.println(message); try {
writer.write("[Error]: ");
writer.write(message);
writer.newLine();
writer.flush();
} catch (IOException e) {
System.out.println(message);
}
} else { } else {
showJOptionPane(title, message, JOptionPane.ERROR_MESSAGE); showJOptionPane(title, message, JOptionPane.ERROR_MESSAGE);
} }
logError(message);
} }
@Override @Override
@ -35,10 +71,17 @@ public abstract class MessageHandler implements GUI {
@Override @Override
public void showMessage(String title, String message) { public void showMessage(String title, String message) {
if (silent) { if (silent) {
System.out.println(message); try {
writer.write("[Info]: " + message);
writer.newLine();
writer.flush();
} catch (IOException e) {
System.out.println(message);
}
} else { } else {
showJOptionPane(title, message, JOptionPane.INFORMATION_MESSAGE); showJOptionPane(title, message, JOptionPane.INFORMATION_MESSAGE);
} }
logMessage(message);
} }
@Override @Override

View File

@ -17,15 +17,21 @@ public class ServerConsoles {
private static JFrame frame; private static JFrame frame;
private static JTabbedPane consolesTabbedPane; private static JTabbedPane consolesTabbedPane;
private ServerConsoles() {
}
/** /**
* Initializes the server consoles frame * Initializes the server consoles frame
*/ */
public ServerConsoles() { public static void instantiate() {
frame = new JFrame(); if (frame == null || consolesTabbedPane == null) {
frame.setBounds(100, 100, 450, 300); frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); frame.setBounds(100, 100, 450, 300);
consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP); frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER); consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER);
}
} }
/** /**

View File

@ -1,7 +1,7 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.profile.Controller; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import javax.swing.*; import javax.swing.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@ -25,13 +25,13 @@ public class ServerControlTab implements ActionListener {
private JButton showConsolesButton; private JButton showConsolesButton;
private JTextField customCommandTextField; private JTextField customCommandTextField;
private Controller controller = Controller.getInstance(); private final ServerLauncherController controller = ServerLauncherController.getInstance();
private final ArrayList<String> globalPlayers; private final ArrayList<String> globalPlayers;
/** /**
* Instantiates a new server control tab * Instantiates a new server control tab
* *
* @param mainFrame <p>The main frame of the GUI</p> * @param mainFrame <p>The main frame of the GUI</p>
* @param controlServers <p>The JPanel to attach the server controls to</p> * @param controlServers <p>The JPanel to attach the server controls to</p>
*/ */
public ServerControlTab(JFrame mainFrame, JPanel controlServers) { public ServerControlTab(JFrame mainFrame, JPanel controlServers) {
@ -42,7 +42,7 @@ public class ServerControlTab implements ActionListener {
/** /**
* Initializes GUI elements for the server control tab * Initializes GUI elements for the server control tab
* *
* @param mainFrame <p>The main frame of the GUI</p> * @param mainFrame <p>The main frame of the GUI</p>
* @param controlServers <p>The JPanel to attach the server controls to</p> * @param controlServers <p>The JPanel to attach the server controls to</p>
*/ */
private void initialize(JFrame mainFrame, JPanel controlServers) { private void initialize(JFrame mainFrame, JPanel controlServers) {
@ -149,7 +149,7 @@ public class ServerControlTab implements ActionListener {
public void update() { public void update() {
this.targetServerCombo.removeAllItems(); this.targetServerCombo.removeAllItems();
this.targetServerCombo.addItem("All"); this.targetServerCombo.addItem("All");
for (Collection collection : Controller.getInstance().getCurrentProfile().getCollections()) { for (Collection collection : ServerLauncherController.getInstance().getCurrentProfile().getCollections()) {
this.targetServerCombo.addItem(collection.getName()); this.targetServerCombo.addItem(collection.getName());
} }
} }
@ -232,7 +232,7 @@ public class ServerControlTab implements ActionListener {
/** /**
* Handles command buttons acting on a specific server * Handles command buttons acting on a specific server
* *
* @param actionSource <p>The object being interacted with</p> * @param actionSource <p>The object being interacted with</p>
* @param selectedServerValue <p>The server currently selected</p> * @param selectedServerValue <p>The server currently selected</p>
*/ */
private void handleServerCommands(Object actionSource, String selectedServerValue) { private void handleServerCommands(Object actionSource, String selectedServerValue) {
@ -252,7 +252,7 @@ public class ServerControlTab implements ActionListener {
/** /**
* Handles command buttons which act on a player * Handles command buttons which act on a player
* *
* @param actionSource <p>The clicked object</p> * @param actionSource <p>The clicked object</p>
* @param selectedServerValue <p>The server currently selected</p> * @param selectedServerValue <p>The server currently selected</p>
* @param selectedPlayerValue <p>The player currently selected</p> * @param selectedPlayerValue <p>The player currently selected</p>
*/ */

View File

@ -2,7 +2,7 @@ package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.profile.Controller; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.Server; import net.knarcraft.minecraftserverlauncher.server.Server;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions; import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
@ -12,15 +12,14 @@ import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter; import java.io.File;
import java.awt.event.MouseEvent; import java.io.FileNotFoundException;
import java.awt.event.WindowAdapter; import java.io.IOException;
import java.awt.event.WindowEvent; import java.util.HashMap;
import java.io.*; import java.util.Map;
import java.util.*; import java.util.Scanner;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import static java.awt.Frame.NORMAL;
import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE; import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
@ -35,7 +34,7 @@ import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getR
public class ServerLauncherGUI extends MessageHandler implements ActionListener, GUI { public class ServerLauncherGUI extends MessageHandler implements ActionListener, GUI {
private final JLabel lblStatuslabel = new JLabel("Servers are stopped"); private final JLabel lblStatuslabel = new JLabel("Servers are stopped");
private Controller controller; private final ServerLauncherController controller;
private Map<String, String> textStrings; private Map<String, String> textStrings;
private Tray applicationTray; private Tray applicationTray;
@ -64,6 +63,20 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
this.controller = Main.getController(); this.controller = Main.getController();
} }
/**
* Creates the application window
*
* @param silent <p>Whether to make the GUI silent (hidden, for testing)</p>
*/
public ServerLauncherGUI(boolean silent) throws IOException {
super(silent);
if (!silent) {
initialize(440, 170);
}
loadMessages();
this.controller = Main.getController();
}
/** /**
* Creates the application window with a preferred width and height * Creates the application window with a preferred width and height
* *
@ -89,12 +102,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
@Override @Override
public void setStatus(String text) { public void setStatus(String text) {
this.lblStatuslabel.setText(text); this.lblStatuslabel.setText(text);
try (PrintWriter file = new PrintWriter(new FileWriter(Main.getApplicationWorkDirectory() + this.logMessage(text);
File.separator + "latestrun.log", true))) {
file.println(text);
} catch (IOException e) {
e.printStackTrace();
}
} }
@Override @Override
@ -146,7 +154,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
* Updates ServerLauncherGUI according to current profile settings * Updates ServerLauncherGUI according to current profile settings
*/ */
public void updateWithSavedProfileData() { public void updateWithSavedProfileData() {
Controller controller = Main.getController(); ServerLauncherController controller = Main.getController();
serversPane.removeAll(); serversPane.removeAll();
serverLauncherMenu.update(); serverLauncherMenu.update();
serverControlTab.update(); serverControlTab.update();
@ -158,7 +166,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
/** /**
* Initializes the server launcher GUI * Initializes the server launcher GUI
* *
* @param width <p>The width of the GUI</p> * @param width <p>The width of the GUI</p>
* @param height <p>The height of the GUI</p> * @param height <p>The height of the GUI</p>
* @throws IOException <p>If unable to load the GUI icon</p> * @throws IOException <p>If unable to load the GUI icon</p>
*/ */
@ -169,7 +177,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
UnsupportedLookAndFeelException | UnsupportedLookAndFeelException |
InstantiationException | InstantiationException |
IllegalAccessException e IllegalAccessException e
) { ) {
e.printStackTrace(); e.printStackTrace();
} }
@ -311,7 +319,6 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
} }
/** /**
* Handles buttons and the combo on the main tab * Handles buttons and the combo on the main tab
* *
@ -401,6 +408,9 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
} catch (IOException e1) { } catch (IOException e1) {
showError("Could not stop server."); showError("Could not stop server.");
e1.printStackTrace(); e1.printStackTrace();
} catch (InterruptedException e) {
showError("Could not kill server.");
e.printStackTrace();
} }
} }

View File

@ -1,12 +1,13 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.profile.Controller;
import net.knarcraft.minecraftserverlauncher.profile.Profile; import net.knarcraft.minecraftserverlauncher.profile.Profile;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions; import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import javax.swing.*; import javax.swing.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.io.File;
import java.util.Objects; import java.util.Objects;
/** /**
@ -14,11 +15,14 @@ import java.util.Objects;
*/ */
public class ServerLauncherMenu implements ActionListener { public class ServerLauncherMenu implements ActionListener {
private JMenuBar menuBar; private final JMenuBar menuBar;
//Options //Options
private JCheckBoxMenuItem runInBackgroundCheckBoxMenuItem; private JCheckBoxMenuItem runInBackgroundCheckBoxMenuItem;
private JCheckBoxMenuItem delayStartupCheckBoxMenuItem; private JCheckBoxMenuItem delayStartupCheckBoxMenuItem;
private JCheckBoxMenuItem downloadJarsCheckBoxMenuItem; private JCheckBoxMenuItem downloadJarsCheckBoxMenuItem;
private JMenuItem javaCommandMenuItem;
private JMenuItem oldJavaCommandMenuItem;
private JMenuItem deleteBuiltJarsMenuItem;
//Help //Help
private JMenuItem errorsMenuItem; private JMenuItem errorsMenuItem;
private JMenuItem setupMenuItem; private JMenuItem setupMenuItem;
@ -27,21 +31,24 @@ public class ServerLauncherMenu implements ActionListener {
private JMenuItem runInBackgroundMenuItem; private JMenuItem runInBackgroundMenuItem;
private JMenuItem delayStartupMenuItem; private JMenuItem delayStartupMenuItem;
private JMenuItem downloadJarsMenuItem; private JMenuItem downloadJarsMenuItem;
private JMenuItem javaCommandInfoMenuItem;
private JMenuItem oldJavaCommandInfoMenuItem;
private JMenuItem deleteBuiltJarsInfoMenuItem;
//Info/about //Info/about
private JMenuItem aboutMenuItem; private JMenuItem aboutMenuItem;
private JMenuItem storyMenuItem; private JMenuItem storyMenuItem;
private Controller controller; private final ServerLauncherController controller;
private ServerLauncherGUI serverLauncherGUI; private final ServerLauncherGUI serverLauncherGUI;
/** /**
* Initializes a new server launcher menu * Initializes a new server launcher menu
* *
* @param menuBar <p>The menu bar to attach items to</p> * @param menuBar <p>The menu bar to attach items to</p>
* @param serverLauncherGUI <p>The server launcher GUI to use</p> * @param serverLauncherGUI <p>The server launcher GUI to use</p>
*/ */
public ServerLauncherMenu(JMenuBar menuBar, ServerLauncherGUI serverLauncherGUI) { public ServerLauncherMenu(JMenuBar menuBar, ServerLauncherGUI serverLauncherGUI) {
this.controller = Controller.getInstance(); this.controller = ServerLauncherController.getInstance();
this.menuBar = menuBar; this.menuBar = menuBar;
this.serverLauncherGUI = serverLauncherGUI; this.serverLauncherGUI = serverLauncherGUI;
initialize(); initialize();
@ -53,64 +60,23 @@ public class ServerLauncherMenu implements ActionListener {
public void initialize() { public void initialize() {
JMenu mnOptions = new JMenu("Options"); JMenu mnOptions = new JMenu("Options");
menuBar.add(mnOptions); menuBar.add(mnOptions);
generateOptionsMenuItems(mnOptions);
runInBackgroundCheckBoxMenuItem = new JCheckBoxMenuItem("Run in background on exit");
mnOptions.add(runInBackgroundCheckBoxMenuItem);
runInBackgroundCheckBoxMenuItem.addActionListener(this);
delayStartupCheckBoxMenuItem = new JCheckBoxMenuItem("Delay Startup");
mnOptions.add(delayStartupCheckBoxMenuItem);
delayStartupCheckBoxMenuItem.addActionListener(this);
downloadJarsCheckBoxMenuItem = new JCheckBoxMenuItem("Download jars");
mnOptions.add(downloadJarsCheckBoxMenuItem);
downloadJarsCheckBoxMenuItem.addActionListener(this);
JMenu mnHelp = new JMenu("Help"); JMenu mnHelp = new JMenu("Help");
menuBar.add(mnHelp); menuBar.add(mnHelp);
errorsMenuItem = new JMenuItem("Errors"); errorsMenuItem = createMenuItem("Errors", mnHelp);
mnHelp.add(errorsMenuItem); setupMenuItem = createMenuItem("Setup", mnHelp);
errorsMenuItem.addActionListener(this); manualUpdateMenuItem = createMenuItem("Manual update", mnHelp);
setupMenuItem = new JMenuItem("Setup");
mnHelp.add(setupMenuItem);
setupMenuItem.addActionListener(this);
manualUpdateMenuItem = new JMenuItem("Manual update");
mnHelp.add(manualUpdateMenuItem);
manualUpdateMenuItem.addActionListener(this);
JMenu mnInfo = new JMenu("Info"); JMenu mnInfo = new JMenu("Info");
menuBar.add(mnInfo); menuBar.add(mnInfo);
generateInfoMenuItems(mnInfo);
JMenu mnOptionsInfo = new JMenu("Options");
mnInfo.add(mnOptionsInfo);
runInBackgroundMenuItem = new JMenuItem("Run in background on exit");
mnOptionsInfo.add(runInBackgroundMenuItem);
runInBackgroundMenuItem.addActionListener(this);
delayStartupMenuItem = new JMenuItem("Delay Startup");
mnOptionsInfo.add(delayStartupMenuItem);
delayStartupMenuItem.addActionListener(this);
downloadJarsMenuItem = new JMenuItem("Download jars");
mnOptionsInfo.add(downloadJarsMenuItem);
downloadJarsMenuItem.addActionListener(this);
JMenu mnAbout = new JMenu("About");
mnInfo.add(mnAbout);
aboutMenuItem = new JMenuItem("About");
mnAbout.add(aboutMenuItem);
aboutMenuItem.addActionListener(this);
storyMenuItem = new JMenuItem("Story");
mnAbout.add(storyMenuItem);
storyMenuItem.addActionListener(this);
} }
/**
* Updates the state of checkboxes based on whether options are enabled
*/
public void update() { public void update() {
runInBackgroundCheckBoxMenuItem.setState(controller.getRunInBackground()); runInBackgroundCheckBoxMenuItem.setState(controller.getRunInBackground());
delayStartupCheckBoxMenuItem.setState(controller.getDelayStartup() > 0); delayStartupCheckBoxMenuItem.setState(controller.getDelayStartup() > 0);
@ -126,6 +92,12 @@ public class ServerLauncherMenu implements ActionListener {
delay(); delay();
} else if (actionSource == downloadJarsCheckBoxMenuItem) { } else if (actionSource == downloadJarsCheckBoxMenuItem) {
downloadJars(); downloadJars();
} else if (actionSource == javaCommandMenuItem) {
configureJava(false);
} else if (actionSource == oldJavaCommandMenuItem) {
configureJava(true);
} else if (actionSource == deleteBuiltJarsMenuItem) {
deleteBuiltJars();
} else if (actionSource == errorsMenuItem) { } else if (actionSource == errorsMenuItem) {
CommonFunctions.goToURL(serverLauncherGUI.getMessage("infoURL")); CommonFunctions.goToURL(serverLauncherGUI.getMessage("infoURL"));
} else if (actionSource == setupMenuItem) { } else if (actionSource == setupMenuItem) {
@ -138,6 +110,12 @@ public class ServerLauncherMenu implements ActionListener {
serverLauncherGUI.showMessage("Delay startup", serverLauncherGUI.getMessage("delayStartupText")); serverLauncherGUI.showMessage("Delay startup", serverLauncherGUI.getMessage("delayStartupText"));
} else if (actionSource == downloadJarsMenuItem) { } else if (actionSource == downloadJarsMenuItem) {
serverLauncherGUI.showMessage("Download jars", serverLauncherGUI.getMessage("downloadJarsText")); serverLauncherGUI.showMessage("Download jars", serverLauncherGUI.getMessage("downloadJarsText"));
} else if (actionSource == javaCommandInfoMenuItem) {
serverLauncherGUI.showMessage("Java command", serverLauncherGUI.getMessage("javaCommandText"));
} else if (actionSource == oldJavaCommandInfoMenuItem) {
serverLauncherGUI.showMessage("Old Java command", serverLauncherGUI.getMessage("oldJavaCommandText"));
} else if (actionSource == deleteBuiltJarsInfoMenuItem) {
serverLauncherGUI.showMessage("Delete built jar files", serverLauncherGUI.getMessage("deleteBuiltJarFilesText"));
} else if (actionSource == aboutMenuItem) { } else if (actionSource == aboutMenuItem) {
serverLauncherGUI.showMessage("About", serverLauncherGUI.getMessage("aboutText")); serverLauncherGUI.showMessage("About", serverLauncherGUI.getMessage("aboutText"));
} else if (actionSource == storyMenuItem) { } else if (actionSource == storyMenuItem) {
@ -145,6 +123,116 @@ public class ServerLauncherMenu implements ActionListener {
} }
} }
/**
* Generates the children of the options menu
*
* @param mnOptions <p>A reference to the options menu</p>
*/
private void generateOptionsMenuItems(JMenu mnOptions) {
runInBackgroundCheckBoxMenuItem = createCheckBoxMenuItem("Run in background on exit", mnOptions);
delayStartupCheckBoxMenuItem = createCheckBoxMenuItem("Delay Startup", mnOptions);
downloadJarsCheckBoxMenuItem = createCheckBoxMenuItem("Download jars", mnOptions);
javaCommandMenuItem = createMenuItem("Java command", mnOptions);
oldJavaCommandMenuItem = createMenuItem("Old Java command", mnOptions);
deleteBuiltJarsMenuItem = createMenuItem("Delete built jar files", mnOptions);
}
/**
* Generates the children of the info menu
*
* @param mnInfo <p>A reference to the info menu</p>
*/
private void generateInfoMenuItems(JMenu mnInfo) {
JMenu mnOptionsInfo = new JMenu("Options");
mnInfo.add(mnOptionsInfo);
runInBackgroundMenuItem = createMenuItem("Run in background on exit", mnOptionsInfo);
delayStartupMenuItem = createMenuItem("Delay Startup", mnOptionsInfo);
downloadJarsMenuItem = createMenuItem("Download jars", mnOptionsInfo);
javaCommandInfoMenuItem = createMenuItem("Java command", mnOptionsInfo);
oldJavaCommandInfoMenuItem = createMenuItem("Old Java command", mnOptionsInfo);
deleteBuiltJarsInfoMenuItem = createMenuItem("Delete built jar files", mnOptionsInfo);
JMenu mnAbout = new JMenu("About");
mnInfo.add(mnAbout);
aboutMenuItem = createMenuItem("About", mnAbout);
storyMenuItem = createMenuItem("Story", mnAbout);
}
/**
* Creates a checkbox menu item
*
* @param itemName <p>The name of the new checkbox item</p>
* @param parent <p>The parent menu the item belongs to</p>
* @return <p>The created checkbox menu item</p>
*/
private JCheckBoxMenuItem createCheckBoxMenuItem(String itemName, JMenu parent) {
JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(itemName);
parent.add(menuItem);
menuItem.addActionListener(this);
return menuItem;
}
/**
* Creates a menu item
*
* @param itemName <p>The name of the new item</p>
* @param parent <p>The parent menu the item belongs to</p>
* @return <p>The created menu item</p>
*/
private JMenuItem createMenuItem(String itemName, JMenu parent) {
JMenuItem menuItem = new JMenuItem(itemName);
parent.add(menuItem);
menuItem.addActionListener(this);
return menuItem;
}
/**
* Asks the user for the new Java path
* @param old <p>Whether asking for the path to the old java version</p>
*/
private void configureJava(boolean old) {
if (old) {
String response = JOptionPane.showInputDialog("Command or path to Java: ", controller.getOldJavaCommand());
if (response != null) {
controller.setOldJavaCommand(response);
}
} else {
String response = JOptionPane.showInputDialog("Command or path to Java: ", controller.getJavaCommand());
if (response != null) {
controller.setJavaCommand(response);
}
}
}
/**
* Deletes build Spigot and Bukkit .jar files if the user accepts
*/
private void deleteBuiltJars() {
int answer = JOptionPane.showConfirmDialog(null, "This will delete built .jar files, causing them " +
"to be rebuilt on the next run. Do you want to continue?", "Delete built .jar files",
JOptionPane.YES_NO_OPTION
);
if (answer == JOptionPane.YES_NO_OPTION) {
String jarDirectory = controller.getJarDirectory();
File spigotFile = new File(jarDirectory + "SpigotLatest.jar");
File bukkitFile = new File(jarDirectory + "BukkitLatest.jar");
boolean success = true;
if (spigotFile.exists() && !spigotFile.delete()) {
serverLauncherGUI.showError("Unable to delete latest spigot .jar");
success = false;
}
if (bukkitFile.exists() && !bukkitFile.delete()) {
serverLauncherGUI.showError("Unable to delete latest bukkit .jar");
success = false;
}
if (success) {
serverLauncherGUI.showMessage("Deletion successful", "Deleted built .jar files");
}
}
}
/** /**
* Asks the user for a delay if checked, and sets the value to the current profile * Asks the user for a delay if checked, and sets the value to the current profile
*/ */

View File

@ -1,13 +1,17 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.Controller; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions; import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -20,14 +24,14 @@ public class Tray {
private SystemTray tray; private SystemTray tray;
private TrayIcon trayIcon; private TrayIcon trayIcon;
private Controller controller; private final ServerLauncherController controller;
private ServerLauncherGUI serverLauncherGUI; private final ServerLauncherGUI serverLauncherGUI;
private JFrame mainFrame; private final JFrame mainFrame;
/** /**
* Instantiates a new tray * Instantiates a new tray
* *
* @param mainFrame <p>The main frame of the GUI</p> * @param mainFrame <p>The main frame of the GUI</p>
* @param serverLauncherGUI <p>The server launcher GUI to use</p> * @param serverLauncherGUI <p>The server launcher GUI to use</p>
*/ */
public Tray(JFrame mainFrame, ServerLauncherGUI serverLauncherGUI) { public Tray(JFrame mainFrame, ServerLauncherGUI serverLauncherGUI) {

View File

@ -12,7 +12,8 @@ public class WebBrowser {
private static JFrame browserFrame; private static JFrame browserFrame;
private static JTextPane editorPane; private static JTextPane editorPane;
private WebBrowser() {} private WebBrowser() {
}
/** /**
* Instantiates a new web browser * Instantiates a new web browser
@ -44,7 +45,8 @@ public class WebBrowser {
editorPane.setContentType("text/html"); editorPane.setContentType("text/html");
editorPane.addHyperlinkListener(hyperlinkEvent -> { editorPane.addHyperlinkListener(hyperlinkEvent -> {
if (hyperlinkEvent.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) { if (hyperlinkEvent.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
displayPage(hyperlinkEvent.getURL().toString()); } displayPage(hyperlinkEvent.getURL().toString());
}
}); });
} catch (IOException e) { } catch (IOException e) {
editorPane.setContentType("text/html"); editorPane.setContentType("text/html");

View File

@ -6,7 +6,18 @@ import net.knarcraft.minecraftserverlauncher.server.Server;
import net.knarcraft.minecraftserverlauncher.userinterface.GUI; import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
import net.knarcraft.minecraftserverlauncher.userinterface.WebBrowser; import net.knarcraft.minecraftserverlauncher.userinterface.WebBrowser;
import java.io.*; import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
@ -16,7 +27,7 @@ import java.nio.file.StandardCopyOption;
import java.util.Scanner; 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
@ -34,7 +45,6 @@ public final class CommonFunctions {
public static void createAllFolders() throws FileNotFoundException { public static void createAllFolders() throws FileNotFoundException {
createFolder(new File(filesDirectory)); createFolder(new File(filesDirectory));
createFolder(new File(filesDirectory + File.separator + "Jars")); createFolder(new File(filesDirectory + File.separator + "Jars"));
createFolder(new File(filesDirectory + File.separator + "testjars"));
} }
/** /**
@ -43,7 +53,7 @@ public final class CommonFunctions {
* @param folder <p>The folder to create</p> * @param folder <p>The folder to create</p>
* @throws FileNotFoundException <p>If unable to create the folder</p> * @throws FileNotFoundException <p>If unable to create the folder</p>
*/ */
private static void createFolder(File folder) throws FileNotFoundException { protected static void createFolder(File folder) throws FileNotFoundException {
if (!folder.exists()) { if (!folder.exists()) {
if (!folder.mkdirs()) { if (!folder.mkdirs()) {
throw new FileNotFoundException("Cannot create necessary directory."); throw new FileNotFoundException("Cannot create necessary directory.");
@ -100,12 +110,88 @@ public final class CommonFunctions {
* *
* @param path <p>The full url of the file to readFromServer</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>
* @throws IOException <p>If unable to find or read the file</p>
*/ */
public static String readFile(String path) throws IOException { public static String readRemoteFile(String path) throws IOException {
URL url = new URL(path); URL url = new URL(path);
return new Scanner(url.openStream()).useDelimiter("\\Z").next(); return new Scanner(url.openStream()).useDelimiter("\\Z").next();
} }
/**
* Gets a buffered reader for reading a given file
*
* @param path <p>The path of the file to read</p>
* @return <p>A buffered reader for reading the file</p>
* @throws FileNotFoundException <p>If the file does not exist</p>
*/
public static BufferedReader getFileReader(String path) throws FileNotFoundException {
return new BufferedReader(new InputStreamReader(new FileInputStream(path)));
}
/**
* Gets a buffered writer for writing to a given file
* @param path <p>The path to the file to write to</p>
* @return <p>A buffered writer for writing to the file</p>
* @throws FileNotFoundException <p>If the file does not exist</p>
*/
public static BufferedWriter getFileWriter(String path) throws FileNotFoundException {
return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path)));
}
/**
* Reads a file from disk
*
* @param path <p>The path of the file to read</p>
* @return <p>The contents of the file</p>
* @throws IOException <p>If unable to find or read the file</p>
*/
public static String readFile(String path) throws IOException {
return CommonFunctions.readBufferedReader(getFileReader(path));
}
/**
* Writes text to a file and adds a trailing newline
*
* @param path <p>The path of the file to write to</p>
* @param text <p>The text to write</p>
* @throws IOException <p>If unable to write to the file</p>
*/
public static void writeFile(String path, String text) throws IOException {
writeFile(path, text, true);
}
/**
* Writes text to a file
*
* @param path <p>The path of the file to write to</p>
* @param text <p>The text to write</p>
* @param addTrailingNewline <p>Whether to add a new line at the end of the file</p>
* @throws IOException <p>If unable to write to the file</p>
*/
public static void writeFile(String path, String text, Boolean addTrailingNewline) throws IOException {
BufferedWriter writer = getFileWriter(path);
writer.write(text);
if (addTrailingNewline) {
writer.newLine();
}
writer.close();
}
/**
* Appends text to a file
*
* @param path <p>The path to the file to append to</p>
* @param text <p>The text to append</p>
* @throws IOException <p>If unable to append to the file</p>
*/
public static void appendFile(String path, String text) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(path, true));
writer.write(text);
writer.newLine();
writer.close();
}
/** /**
* Downloads a file from a website and replaces the target file * Downloads a file from a website and replaces the target file
* *
@ -199,9 +285,12 @@ public final class CommonFunctions {
StringBuilder text = new StringBuilder(); StringBuilder text = new StringBuilder();
char[] readCharacters = new char[1000]; char[] readCharacters = new char[1000];
while (reader.ready()) { while (reader.ready()) {
reader.read(readCharacters); if (reader.read(readCharacters) > 0) {
text.append(readCharacters); text.append(readCharacters);
readCharacters = new char[1000]; readCharacters = new char[1000];
} else {
return text.toString().trim();
}
} }
return text.toString().trim(); return text.toString().trim();
} }
@ -244,4 +333,32 @@ public final class CommonFunctions {
public static boolean nameIsValid(String name) { public static boolean nameIsValid(String name) {
return !name.equals("") && name.matches("[^!?;,]+"); return !name.equals("") && name.matches("[^!?;,]+");
} }
/**
* Removes all files within a folder
*
* @param target <p>The folder to delete from</p>
*/
static void removeFilesRecursively(File target) {
File[] oldFiles = target.listFiles();
if (oldFiles == null) {
throw new IllegalArgumentException("Unable to list files in directory");
}
for (File file : oldFiles) {
if (file.isFile()) {
if (!file.delete()) {
throw new IllegalArgumentException("Unable to delete a file from the directory");
}
}
}
for (File file : oldFiles) {
if (file.isDirectory()) {
removeFilesRecursively(file);
if (!file.delete()) {
throw new IllegalArgumentException("Unable to delete a file from the directory");
}
}
}
}
} }

View File

@ -0,0 +1,179 @@
package net.knarcraft.minecraftserverlauncher.utility;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.server.ServerVersionContainer;
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.file.Paths;
/**
* The jar builder is responsible for building the newest Spigot and CraftBukkit .jar files using BuildTools
*/
public class JarBuilder {
private final String buildDirectory;
private final String jarDirectory;
private final ServerVersionContainer versionContainer;
private final GUI gui;
private final String javaCommand;
/**
* Instantiates a new jar builder
*
* @param buildDirectory <p>The directory containing BuildTool files</p>
* @param jarDirectory <p>The directory containing downloaded .jar files</p>
* @param gui <p>The GUI to write messages to</p>
*/
public JarBuilder(String buildDirectory, String jarDirectory, GUI gui) {
this.buildDirectory = buildDirectory;
this.jarDirectory = jarDirectory;
this.gui = gui;
this.versionContainer = ServerVersionContainer.getInstance();
this.javaCommand = ServerLauncherController.getInstance().getJavaCommand();
try {
CommonFunctions.createFolder(new File(buildDirectory));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/**
* Builds the latest version of the spigot .jar file
*/
public boolean buildSpigotJar() {
gui.setStatus("Building Spigot jar ...");
downloadBuildTools();
ProcessBuilder processBuilder = new ProcessBuilder(javaCommand, "-jar", "BuildTools.jar", "--rev",
"latest", "--output-dir", jarDirectory);
if (executeBuildProcess(processBuilder) && moveBuiltJar("spigot-", "SpigotLatest.jar")) {
gui.setStatus("Finished moving spigot.jar");
return true;
} else {
return false;
}
}
/**
* Builds the latest version of the craftbukkit .jar file
*/
public boolean buildBukkitJar() {
gui.setStatus("Building Bukkit jar ...");
downloadBuildTools();
ProcessBuilder processBuilder = new ProcessBuilder(javaCommand, "-jar", "BuildTools.jar", "--compile",
"craftbukkit", "--rev", "latest", "--output-dir", jarDirectory);
if (executeBuildProcess(processBuilder) && moveBuiltJar("craftbukkit-", "BukkitLatest.jar")) {
gui.setStatus("Finished moving craftbukkit.jar");
return true;
} else {
return false;
}
}
/**
* Downloads the latest BuildTools version
*/
public void downloadBuildTools() {
ServerLauncherGUI gui = Main.getController().getGUI();
try {
String latestVersion = getLatestBuildToolsVersion();
boolean exists = new File(buildDirectory + "BuildTools.jar").exists();
boolean isUpdated = latestVersion.equals(versionContainer.getDownloadedBuildToolsVersion());
if (!exists || !isUpdated) {
String buildToolsURL = "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar";
boolean success = CommonFunctions.downloadFile(buildToolsURL, Paths.get(buildDirectory + "BuildTools.jar"));
if (!success) {
gui.setStatus("Unable to download the latest BuildTools");
gui.logError("Target: " + buildDirectory + "BuildTools.jar");
gui.logError("URL: " + buildToolsURL);
} else {
versionContainer.setDownloadedBuildToolsVersion(latestVersion);
}
}
} catch (IOException e) {
gui.setStatus("Unable to download the latest BuildTools");
gui.logMessage(e.getMessage());
}
}
/**
* Moves a built .jar file to its target file
*
* @param searchString <p>The start of the name of the built file used to find it</p>
* @param newName <p>The new name of the built file</p>
* @return <p>True if the .jar file was moved successfully</p>
*/
private boolean moveBuiltJar(String searchString, String newName) {
File[] foundFiles = new File(jarDirectory).listFiles((file) -> file.isFile() && file.getName().startsWith(searchString));
if (foundFiles != null && foundFiles.length == 1) {
File newFileLocation = new File(jarDirectory + File.separator + newName);
if (newFileLocation.exists()) {
if (!newFileLocation.delete()) {
gui.showError("Unable to delete previously built .jar");
}
}
if (!foundFiles[0].renameTo(newFileLocation)) {
gui.showError("Unable to move built .jar");
} else {
return true;
}
}
return false;
}
/**
* Starts the build process and initializes
*
* @param processBuilder <p>The process builder to execute</p>
* @return <p>True if the process exited successfully</p>
*/
private boolean executeBuildProcess(ProcessBuilder processBuilder) {
processBuilder.directory(new File(buildDirectory));
processBuilder.redirectErrorStream(true);
try {
Process process = processBuilder.start();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
do {
writer.write(CommonFunctions.readBufferedReader(reader));
} while (process.isAlive());
writer.newLine();
writer.flush();
if (process.exitValue() == 0) {
gui.setStatus("Jar building process finished successfully.");
return true;
} else {
gui.showError("Jar building process failed with exit code " + process.exitValue() +
". Please check the BuildTools log for errors.");
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* Gets the latest build tools version available
*
* @return <p>The latest build tools version available</p>
* @throws IOException <p>If unable to read the version file</p>
*/
String getLatestBuildToolsVersion() throws IOException {
String versionDocument;
versionDocument = CommonFunctions.readRemoteFile("https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/");
return CommonFunctions.stringBetween(versionDocument, "BuildTools #", " [");
}
}

View File

@ -60,6 +60,9 @@ public final class JarDownloader {
continue; continue;
} }
for (String version : type.getVersions()) { for (String version : type.getVersions()) {
if ((type.getName().equals("Spigot") || type.getName().equals("Bukkit")) && version.equals("Latest")) {
continue;
}
gui.setStatus("Downloading " + type.getName() + version + "..."); gui.setStatus("Downloading " + type.getName() + version + "...");
boolean success = type.downloadJar(jarDirectory, version); boolean success = type.downloadJar(jarDirectory, version);
if (!success) { if (!success) {

View File

@ -5,16 +5,18 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.userinterface.GUI; import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import javax.swing.*; import javax.swing.*;
import java.io.*; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Scanner; import java.util.Scanner;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readRemoteFile;
/** /**
* A utility used for updating the software * A utility used for updating the software
@ -45,11 +47,11 @@ public final class Updater {
String oldVer = file.nextLine(); String oldVer = file.nextLine();
file.close(); file.close();
String data = readFile(updateURL); String data = readRemoteFile(updateURL);
JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject(); JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
String latest = jsonObject.getAsJsonObject("latest").get(updateChannel).getAsString(); String latest = jsonObject.getAsJsonObject("latest").get(updateChannel).getAsString();
if (!oldType.equals(updateChannel) || !oldVer.equals(latest)) { if (!oldType.equals(updateChannel) || isVersionHigher(oldVer, latest)) {
JsonArray versionList = jsonObject.getAsJsonArray("versions"); JsonArray versionList = jsonObject.getAsJsonArray("versions");
String url = ""; String url = "";
for (JsonElement elem : versionList) { for (JsonElement elem : versionList) {
@ -75,6 +77,27 @@ public final class Updater {
} }
} }
/**
* Decides whether one version number is higher than another
*
* @param oldVersion <p>The old version to check</p>
* @param newVersion <p>The new version to check</p>
* @return <p>True if the new version is higher than the old one</p>
*/
public static boolean isVersionHigher(String oldVersion, String newVersion) {
String[] oldVersionParts = oldVersion.split("\\.");
String[] newVersionParts = newVersion.split("\\.");
int versionLength = Math.max(oldVersionParts.length, newVersionParts.length);
for (int i = 0; i < versionLength; i++) {
int oldVersionNumber = oldVersionParts.length > i ? Integer.parseInt(oldVersionParts[i]) : 0;
int newVersionNumber = newVersionParts.length > i ? Integer.parseInt(newVersionParts[i]) : 0;
if (newVersionNumber != oldVersionNumber) {
return newVersionNumber > oldVersionNumber;
}
}
return false;
}
/** /**
* Updates the software * Updates the software
* *
@ -82,8 +105,9 @@ public final class Updater {
* @throws IOException <p>If unable to run the updater</p> * @throws IOException <p>If unable to run the updater</p>
*/ */
private static void runUpdater(String url) throws IOException { private static void runUpdater(String url) throws IOException {
String javaCommand = ServerLauncherController.getInstance().getJavaCommand();
ProcessBuilder builder; ProcessBuilder builder;
builder = new ProcessBuilder("java", "-jar", "Updater.jar", url, "yes", targetFile, "5", "nogui"); builder = new ProcessBuilder(javaCommand, "-jar", "Updater.jar", url, "yes", targetFile, "5", "nogui");
builder.directory(new File(Main.getApplicationWorkDirectory())); builder.directory(new File(Main.getApplicationWorkDirectory()));
builder.redirectErrorStream(true); builder.redirectErrorStream(true);
builder.start(); builder.start();

View File

@ -1,2 +1,2 @@
beta beta
1.2.3 1.3.3
1 beta
2 1.2.3 1.3.3

View File

@ -5,4 +5,7 @@ downloadJarsText=This option will download all the .jar files available in the p
aboutText=This software was created to start and manage several servers simultaneously._BREAK_You no longer have to do the tedious work of manually downloading different .jar files every time you want to try something new. aboutText=This software was created to start and manage several servers simultaneously._BREAK_You no longer have to do the tedious work of manually downloading different .jar files every time you want to try something new.
infoURL=https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherInfo/ infoURL=https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherInfo/
manualUpdateURL=https://git.knarcraft.net/KnarCraft/Minecraft-Server-Launcher/releases manualUpdateURL=https://git.knarcraft.net/KnarCraft/Minecraft-Server-Launcher/releases
storyURL=https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherStory/ storyURL=https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherStory/
javaCommandText=This option allows you to set a custom command/path to the Java executable used for Minecraft 1.17 and above._BREAK_If "java" is currently pointing to Java 8, you can use this to set a custom one for running new Minecraft servers and BuildTools.
oldJavaCommandText=This option allows you to set a custom command/path to the Java executable used for Minecraft 1.16 and below._BREAK_If "java" is currently pointing to Java 16, you can use this to set a custom one for running old Minecraft servers.
deleteBuiltJarFilesText=This option allows you to easily delete built Spigot and Bukkit .jar files._BREAK_You should occasionally run this option to update the built .jar files to ensure you're running the latest update.
Can't render this file because it contains an unexpected character in line 9 and column 136.

View File

@ -1,11 +1,11 @@
Vanilla;Latest,Snapshot,1.16.3,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.9,1.7.10,1.6.4,1.5.2,1.4.7,1.3.2,1.2.5;https://launchermeta.mojang.com/mc/game/version_manifest.json;"release":";";https://s3.amazonaws.com/Minecraft.Download/versions/ Vanilla;Latest,Snapshot,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.9,1.7.10,1.6.4,1.5.2,1.4.7,1.3.2,1.2.5;https://launchermeta.mojang.com/mc/game/version_manifest.json;"release":";";https://s3.amazonaws.com/Minecraft.Download/versions/
Spigot;1.16.3,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.9.4,1.8.8,1.7.10,1.6.4-R2.1,1.5.2-R1.1,1.4.7-R1.1;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Spigot/;spigot- Spigot;Latest,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.9.4,1.8.8,1.7.10,1.6.4-R2.1,1.5.2-R1.1,1.4.7-R1.1;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Spigot/;spigot-
Paper;1.16.3,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Paper/;Paper- Paper;1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Paper/;Paper-
SpongeVanilla;1.12.2,1.11.2,1.10.2,1.8.9;https://dl-api.spongepowered.org/v1/org.spongepowered/spongevanilla/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongevanilla/;/spongevanilla- #SpongeVanilla;1.12.2,1.11.2,1.10.2,1.8.9;https://dl-api.spongepowered.org/v1/org.spongepowered/spongevanilla/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongevanilla/;/spongevanilla-
Craftbukkit;1.16.3,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8,1.7.10-R0.1,1.6.4-R2.0,1.5.2-R1.0,1.4.6-R0.3,1.3.2-R3.0,1.2.5-R2.0,1.1-R6,1.0.1-R1,b1.8.1,b1.7.3;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Bukkit/;craftbukkit- Craftbukkit;Latest,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8,1.7.10-R0.1,1.6.4-R2.0,1.5.2-R1.0,1.4.6-R0.3,1.3.2-R3.0,1.2.5-R2.0,1.1-R6,1.0.1-R1,b1.8.1,b1.7.3;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Bukkit/;craftbukkit-
SpongeForge;1.12.2,1.11.2,1.10.2;https://dl-api.spongepowered.org/v1/org.spongepowered/spongeforge/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongeforge/;/spongeforge- #SpongeForge;1.12.2,1.11.2,1.10.2;https://dl-api.spongepowered.org/v1/org.spongepowered/spongeforge/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongeforge/;/spongeforge-
MCPCplus;1.6.4,1.6.2,1.5.2,1.4.7;https://static.knarcraft.net/archive/downloads/minecraftserverjars/MCPC+/;mcpcplus MCPCplus;1.6.4,1.6.2,1.5.2,1.4.7;https://static.knarcraft.net/archive/downloads/minecraftserverjars/MCPC+/;mcpcplus
Bungee;Latest,1.7.10,1.6.4,1.5.2,1.4.7;https://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/;Artifacts of BungeeCord #; ;http://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/BungeeCord.jar;https://static.knarcraft.net/archive/downloads/minecraftserverjars/BungeeCord/;BungeeCord- Bungee;Latest,1.7.10,1.6.4,1.5.2,1.4.7;https://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/;Artifacts of BungeeCord #; ;http://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/BungeeCord.jar;https://static.knarcraft.net/archive/downloads/minecraftserverjars/BungeeCord/;BungeeCord-
Waterfall;1.16,1.15,1.14,1.13,1.12,1.11;https://papermc.io/api/v1/waterfall/;"latest":";";https://papermc.io/api/v1/waterfall/ Waterfall;1.17,1.16,1.15,1.14,1.13,1.12,1.11;https://papermc.io/api/v1/waterfall/;"latest":;,;https://papermc.io/api/v1/waterfall/
Travertine;1.16,1.15,1.14,1.13,1.12;https://papermc.io/api/v1/travertine/;"latest":";";https://papermc.io/api/v1/travertine/ Travertine;1.16,1.15,1.14,1.13,1.12;https://papermc.io/api/v1/travertine/;"latest":;,;https://papermc.io/api/v1/travertine/
Custom; Custom;
Can't render this file because it contains an unexpected character in line 1 and column 193.

View File

@ -1,11 +1,11 @@
package net.knarcraft.minecraftserverlauncher.server; package net.knarcraft.minecraftserverlauncher.server;
import org.junit.Test; import org.junit.jupiter.api.Test;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import static junit.framework.TestCase.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static junit.framework.TestCase.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
public class ServerTest { public class ServerTest {

View File

@ -1,13 +1,12 @@
package net.knarcraft.minecraftserverlauncher.server; package net.knarcraft.minecraftserverlauncher.server;
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType; import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
import org.junit.Test; import org.junit.jupiter.api.Test;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import java.util.Arrays; import java.util.Arrays;
import static junit.framework.TestCase.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class ServerTypeHandlerTest { public class ServerTypeHandlerTest {

View File

@ -2,13 +2,16 @@ package net.knarcraft.minecraftserverlauncher.server;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions; import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import org.junit.Before; import org.junit.jupiter.api.BeforeEach;
import org.junit.Test; import org.junit.jupiter.api.Test;
import java.io.*; import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import static junit.framework.TestCase.assertEquals;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.createAllFolders; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.createAllFolders;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ServerVersionContainerTest { public class ServerVersionContainerTest {
@ -16,7 +19,7 @@ public class ServerVersionContainerTest {
private final String versionFile = filesDirectory + File.separator + "versions.csv"; private final String versionFile = filesDirectory + File.separator + "versions.csv";
private ServerVersionContainer serverVersionContainer; private ServerVersionContainer serverVersionContainer;
@Before @BeforeEach
public void setUp() { public void setUp() {
try { try {
createAllFolders(); createAllFolders();
@ -35,14 +38,14 @@ public class ServerVersionContainerTest {
serverVersionContainer.reset(); serverVersionContainer.reset();
System.out.println(serverVersionContainer.toString()); System.out.println(serverVersionContainer.toString());
assertEquals("vanillaVersion;null\nsnapshotVersion;null\nbungeeVersion;null\nwaterfallVersions;\n" + assertEquals("vanillaVersion;null\nsnapshotVersion;null\nbungeeVersion;null\nwaterfallVersions;\n" +
"travertineVersions;\nspongeVanillaVersions;\nspongeForgeVersions;", "travertineVersions;\nspongeVanillaVersions;\nspongeForgeVersions;\ndownloadedBuildToolsVersion;null",
serverVersionContainer.toString()); serverVersionContainer.toString());
} }
@Test @Test
public void saveStateTest() throws IOException { public void saveStateTest() throws IOException {
serverVersionContainer.saveState(); serverVersionContainer.saveState();
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(versionFile))); BufferedReader reader = CommonFunctions.getFileReader(versionFile);
String savedData = CommonFunctions.readBufferedReader(reader); String savedData = CommonFunctions.readBufferedReader(reader);
reader.close(); reader.close();
assertEquals(serverVersionContainer.toString(), savedData); assertEquals(serverVersionContainer.toString(), savedData);

View File

@ -1,19 +1,31 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class FakeGUI extends MessageHandler implements GUI { public class FakeGUI extends MessageHandler implements GUI {
private final BufferedWriter writer;
/*** /***
* Initializes a new fake gui * Initializes a new fake gui
*/ */
public FakeGUI() { public FakeGUI() {
super(true); super(true);
this.writer = new BufferedWriter(new OutputStreamWriter(System.out));
} }
@Override @Override
public void setStatus(String message) { public void setStatus(String message) {
System.out.println(message); try {
writer.write(message);
writer.newLine();
writer.flush();
} catch (IOException e) {
System.out.println(message);
}
} }
@Override @Override

View File

@ -1,19 +1,12 @@
package net.knarcraft.minecraftserverlauncher.utility; package net.knarcraft.minecraftserverlauncher.utility;
import net.knarcraft.minecraftserverlauncher.Main; import org.junit.jupiter.api.Test;
import org.junit.Test;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween;
import static org.junit.Assert.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
public class CommonFunctionsTest { public class CommonFunctionsTest {
@Test
public void saveProfileTest() {
Main.getController().addProfile("Test");
Main.getController().saveState();
}
@Test @Test
public void stringBetweenTest() { public void stringBetweenTest() {
String substring = stringBetween("fish'nchips", "f", "'"); String substring = stringBetween("fish'nchips", "f", "'");

View File

@ -0,0 +1,105 @@
package net.knarcraft.minecraftserverlauncher.utility;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
import net.knarcraft.minecraftserverlauncher.userinterface.FakeGUI;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import javax.naming.ConfigurationException;
import java.io.File;
import java.io.IOException;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JarBuilderTest {
private static JarBuilder jarBuilder;
private static String targetDirectory;
private static String jarDirectory;
@BeforeAll
public static void preSetUp() {
try {
ServerLauncherController.getInstance().loadState(true);
} catch (ConfigurationException | IOException e) {
e.printStackTrace();
}
}
@BeforeEach
public void setUp() {
targetDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator +
"BuildTools" + File.separator;
jarDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator +
"testjars" + File.separator;
jarBuilder = new JarBuilder(targetDirectory, jarDirectory, new FakeGUI());
removeBuildToolsFiles();
}
@AfterAll
public static void tearDown() {
removeBuildToolsFiles();
}
@Test
@Order(3)
public void buildLatestSpigotJarTest() {
File spigotFile = new File(jarDirectory + "SpigotLatest.jar");
if (spigotFile.exists() && !spigotFile.delete()) {
throw new IllegalArgumentException("Unable to remove existing spigot .jar");
}
jarBuilder.buildSpigotJar();
assertTrue(spigotFile.exists());
}
@Test
@Order(4)
public void buildLatestBukkitJarTest() {
File bukkitFile = new File(jarDirectory + "BukkitLatest.jar");
if (bukkitFile.exists() && !bukkitFile.delete()) {
throw new IllegalArgumentException("Unable to remove existing bukkit .jar");
}
jarBuilder.buildBukkitJar();
assertTrue(new File(jarDirectory + "BukkitLatest.jar").exists());
}
@Test
@Order(2)
public void downloadLatestBuildToolsJarTest() {
jarBuilder.downloadBuildTools();
assertTrue(new File(targetDirectory + "BuildTools.jar").exists());
}
@Test
@Order(1)
public void getLatestBuildToolsVersionTest() {
try {
String latestVersion = jarBuilder.getLatestBuildToolsVersion();
assertNotEquals("", latestVersion);
int newVersion = Integer.parseInt(latestVersion);
assertNotEquals(newVersion, 0);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Removes build tools files
*/
private static void removeBuildToolsFiles() {
File target = new File(targetDirectory);
if (!target.exists() && !target.mkdirs()) {
throw new IllegalArgumentException("Unable to create the test files directory");
}
CommonFunctions.removeFilesRecursively(target);
}
}

View File

@ -4,28 +4,35 @@ import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.server.ServerTypeHandler; import net.knarcraft.minecraftserverlauncher.server.ServerTypeHandler;
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType; import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
import net.knarcraft.minecraftserverlauncher.userinterface.FakeGUI; import net.knarcraft.minecraftserverlauncher.userinterface.FakeGUI;
import org.junit.AfterClass; import org.junit.jupiter.api.AfterAll;
import org.junit.BeforeClass; import org.junit.jupiter.api.BeforeAll;
import org.junit.Test; import org.junit.jupiter.api.Test;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import static junit.framework.TestCase.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static junit.framework.TestCase.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
public class JarDownloaderTest { public class JarDownloaderTest {
private static String targetDirectory; private static String targetDirectory;
@BeforeClass @BeforeAll
public static void setUp() { public static void setUp() {
targetDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator + String filesDirectory = Main.getApplicationWorkDirectory() + File.separator + "files";
"testjars" + File.separator; try {
CommonFunctions.createFolder(new File(filesDirectory + File.separator + "testjars"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
targetDirectory = filesDirectory + File.separator + "testjars" + File.separator;
removeDownloadedFiles(); removeDownloadedFiles();
} }
@AfterClass @AfterAll
public static void cleanUp() { public static void cleanUp() {
removeDownloadedFiles(); removeDownloadedFiles();
} }
@ -36,7 +43,7 @@ public class JarDownloaderTest {
downloader.downloadJars(); downloader.downloadJars();
} }
@Test /*@Test
public void spongeVanillaDownloadTest() throws IOException, ConfigurationException { public void spongeVanillaDownloadTest() throws IOException, ConfigurationException {
singleDownloadTest(ServerTypeHandler.getByName("SpongeVanilla")); singleDownloadTest(ServerTypeHandler.getByName("SpongeVanilla"));
} }
@ -44,7 +51,7 @@ public class JarDownloaderTest {
@Test @Test
public void spongeForgeDownloadTest() throws IOException, ConfigurationException { public void spongeForgeDownloadTest() throws IOException, ConfigurationException {
singleDownloadTest(ServerTypeHandler.getByName("SpongeForge")); singleDownloadTest(ServerTypeHandler.getByName("SpongeForge"));
} }*/
@Test @Test
public void spigotDownloadTest() throws ConfigurationException, IOException { public void spigotDownloadTest() throws ConfigurationException, IOException {
@ -57,7 +64,7 @@ public class JarDownloaderTest {
} }
@Test @Test
public void craftbukkitDownloadTest() throws ConfigurationException, IOException { public void craftBukkitDownloadTest() throws ConfigurationException, IOException {
singleDownloadTest(ServerTypeHandler.getByName("Bukkit")); singleDownloadTest(ServerTypeHandler.getByName("Bukkit"));
} }
@ -95,6 +102,10 @@ public class JarDownloaderTest {
private void singleDownloadTest(ServerType serverType) throws IOException { private void singleDownloadTest(ServerType serverType) throws IOException {
assertNotNull(serverType); assertNotNull(serverType);
for (String serverVersion : serverType.getVersions()) { for (String serverVersion : serverType.getVersions()) {
if ((serverType.getName().equals("Spigot") || serverType.getName().equals("Bukkit"))
&& serverVersion.equals("Latest")) {
continue;
}
System.out.println("Downloading " + serverType.getName() + serverVersion + ".jar"); System.out.println("Downloading " + serverType.getName() + serverVersion + ".jar");
serverType.downloadJar(targetDirectory, serverVersion); serverType.downloadJar(targetDirectory, serverVersion);
assertTrue(new File(targetDirectory + serverType.getName() + serverVersion + ".jar").exists()); assertTrue(new File(targetDirectory + serverType.getName() + serverVersion + ".jar").exists());
@ -109,12 +120,6 @@ public class JarDownloaderTest {
if (!target.exists() && !target.mkdirs()) { if (!target.exists() && !target.mkdirs()) {
throw new IllegalArgumentException("Unable to create the test files directory"); throw new IllegalArgumentException("Unable to create the test files directory");
} }
File[] oldFiles = target.listFiles(); CommonFunctions.removeFilesRecursively(target);
if (oldFiles == null) {
throw new IllegalArgumentException("Unable to list files in jar test directory");
}
for (File file : oldFiles) {
assertTrue(file.delete());
}
} }
} }

View File

@ -0,0 +1,23 @@
package net.knarcraft.minecraftserverlauncher.utility;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class UpdaterTest {
@Test
public void isVersionHigherTest() {
assertTrue(Updater.isVersionHigher("1.1.1", "1.1.2"));
assertFalse(Updater.isVersionHigher("1.1.1", "1.1.1"));
assertFalse(Updater.isVersionHigher("1.1.1", "1.1.0"));
assertTrue(Updater.isVersionHigher("1.1.1", "1.2.1"));
assertFalse(Updater.isVersionHigher("1.2.1", "1.1.6"));
assertTrue(Updater.isVersionHigher("1.2.1", "2.1.6"));
assertTrue(Updater.isVersionHigher("1.2.1", "2.0.0"));
assertTrue(Updater.isVersionHigher("1.2", "1.2.1"));
assertTrue(Updater.isVersionHigher("1.1.2", "1.2"));
}
}