Compare commits
20 Commits
v1.3.4-bet
...
v1.4.2-bet
Author | SHA1 | Date | |
---|---|---|---|
545e7bacc6 | |||
b142b6d05e | |||
166d63f1b2 | |||
8f25fa2796 | |||
3467c900f0 | |||
9f092a73fe | |||
50b9188229 | |||
b021de5594 | |||
a1ae162b07 | |||
b2ee22eb7b | |||
65ede11ab5 | |||
c26a3bc3b5 | |||
71e47acbb0 | |||
60fdcf5ddc | |||
bf77c13072 | |||
849655bfc6 | |||
e8ecee1cd0 | |||
5e24d5daa8 | |||
9532683301 | |||
365d08f2e2 |
16
README.md
16
README.md
@ -1,6 +1,14 @@
|
|||||||
# Minecraft-Server-Launcher
|
# Minecraft-Server-Launcher
|
||||||
I originally created this software in 2013 using AutoIt. Since I am now learning Java, I have recreated it in Java.
|
|
||||||
The original version can be found at: https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncher/
|
|
||||||
Its goal is to do everything the original does, just better. The original is 1595 lines of code repetition and dirty code. I had no prior programming experience when I first started working on the original, which is why it became such a mess.
|
|
||||||
|
|
||||||
The code is now in a fully working state. It is still missing an auto update feature, but it can be used, and is fully functional.
|
I originally created this software in 2013 using AutoIt. After learning Java, I recreated it in Java. The original
|
||||||
|
version can be found at: https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncher/
|
||||||
|
This version's goal is to do everything the original does, just better. The original is 1595 lines of code repetition
|
||||||
|
and dirty code. I had no prior programming experience when I first started working on the original, which is why it
|
||||||
|
became such a mess.
|
||||||
|
|
||||||
|
The software is in a fully working stage with a functional updater. The software is still in beta because there are
|
||||||
|
still a lot of things I want to change and small annoyances. The software is fully portable. Make sure to put it in its
|
||||||
|
own folder as it will create lots of files.
|
||||||
|
|
||||||
|
The updater will move the new version to minecraft-server-launcher.jar, so you should rename the downloaded file to this
|
||||||
|
if it's named something else to avoid confusion.
|
@ -1,3 +1,3 @@
|
|||||||
As this is a personal one-man project, I prefer to stay in charge of the code.
|
As this is a personal one-man project, I prefer to stay in charge of the code. I appreciate code fixing mistakes, or
|
||||||
I appreciate code fixing mistakes, or code improvements, but the software's functionality or purpose, should not be changed.
|
code improvements, but the software's functionality or purpose, should not be changed. I might change anything at any
|
||||||
I might change anything at any time, so you might want to keep that in mind before doing big changes yourself.
|
time, so you might want to keep that in mind before doing big changes yourself.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
Fixes # .
|
Fixes # .
|
||||||
|
|
||||||
Proposed changes:
|
Proposed changes:
|
||||||
|
|
||||||
-
|
-
|
||||||
-
|
-
|
||||||
-
|
-
|
||||||
|
@ -11,6 +11,7 @@ import javax.naming.ConfigurationException;
|
|||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps track of a set of servers and some user settings
|
* Keeps track of a set of servers and some user settings
|
||||||
@ -22,7 +23,7 @@ import java.util.ArrayList;
|
|||||||
public class Profile {
|
public class Profile {
|
||||||
|
|
||||||
private static final ServerLauncherGUI serverLauncherGui = Main.getController().getGUI();
|
private static final ServerLauncherGUI serverLauncherGui = Main.getController().getGUI();
|
||||||
private final ArrayList<Collection> collections;
|
private final List<Collection> collections;
|
||||||
private final String name;
|
private final String name;
|
||||||
private boolean runInBackground;
|
private boolean runInBackground;
|
||||||
private int delayStartup;
|
private int delayStartup;
|
||||||
@ -106,7 +107,7 @@ public class Profile {
|
|||||||
*
|
*
|
||||||
* @return <p>All collections stored by this profile</p>
|
* @return <p>All collections stored by this profile</p>
|
||||||
*/
|
*/
|
||||||
public ArrayList<Collection> getCollections() {
|
public List<Collection> getCollections() {
|
||||||
return this.collections;
|
return this.collections;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,14 +141,16 @@ public class Profile {
|
|||||||
* @param name <p>The name of the collection and its elements</p>
|
* @param name <p>The name of the collection and its elements</p>
|
||||||
*/
|
*/
|
||||||
public void addCollection(String name) throws ConfigurationException {
|
public void addCollection(String name) throws ConfigurationException {
|
||||||
if (name == null) { //If a user cancels or crosses out window
|
//Skip if no name was given
|
||||||
|
if (name == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (getCollection(name) == null && !name.equals("All") && CommonFunctions.nameIsValid(name)) {
|
if (getCollection(name) == null && !name.equals("All") && CommonFunctions.nameIsValid(name)) {
|
||||||
collections.add(new Collection(name));
|
collections.add(new Collection(name));
|
||||||
} else {
|
} else {
|
||||||
serverLauncherGui.showError("A server name must my unique and not empty or \"All\"." +
|
serverLauncherGui.showError("A server name must be unique and not empty. " +
|
||||||
"It can't contain any of the characters \"!\", \"?\" or \";\".");
|
"In addition, a server cannot be named: \"All\". " +
|
||||||
|
"It cannot contain any of the characters \"!\", \"?\" or \";\".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +379,7 @@ public class ServerLauncherController {
|
|||||||
* Updates the GUI as necessary to display loaded data
|
* Updates the GUI as necessary to display loaded data
|
||||||
*/
|
*/
|
||||||
private void executeGUILoadingTasks() {
|
private void executeGUILoadingTasks() {
|
||||||
this.serverLauncherGUI.updateProfiles();
|
this.serverLauncherGUI.getControlPanelTab().updateProfiles();
|
||||||
this.serverLauncherGUI.updateWithSavedProfileData();
|
this.serverLauncherGUI.updateWithSavedProfileData();
|
||||||
this.currentProfile.updateConsoles();
|
this.currentProfile.updateConsoles();
|
||||||
if (this.downloadAllJars) {
|
if (this.downloadAllJars) {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.knarcraft.minecraftserverlauncher.utility;
|
package net.knarcraft.minecraftserverlauncher.server;
|
||||||
|
|
||||||
import net.knarcraft.minecraftserverlauncher.Main;
|
import net.knarcraft.minecraftserverlauncher.Main;
|
||||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||||
import net.knarcraft.minecraftserverlauncher.server.ServerVersionContainer;
|
|
||||||
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
|
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
|
||||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
|
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
@ -326,9 +326,10 @@ public class Server {
|
|||||||
/**
|
/**
|
||||||
* Runs a Minecraft server
|
* Runs a Minecraft server
|
||||||
*
|
*
|
||||||
|
* @param skipDelay <p>Whether to skip the startup delay for this server</p>
|
||||||
* @return <p>True if nothing went wrong</p>
|
* @return <p>True if nothing went wrong</p>
|
||||||
*/
|
*/
|
||||||
public boolean runServer(boolean isFirstServer) {
|
public boolean runServer(boolean skipDelay) {
|
||||||
if (ServerHandler.stoppingServers()) {
|
if (ServerHandler.stoppingServers()) {
|
||||||
gui.logMessage("Stopping servers. Cannot start yet.");
|
gui.logMessage("Stopping servers. Cannot start yet.");
|
||||||
return false;
|
return false;
|
||||||
@ -339,12 +340,13 @@ public class Server {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//Tries to do necessary pre-start work
|
//Tries to do necessary pre-start work
|
||||||
if (!initializeJarDownload() || (!isFirstServer && !delayStartup())) {
|
if (!initializeJarDownload() || (!skipDelay && !delayStartup())) {
|
||||||
gui.logError("Failed to perform startup tasks.");
|
gui.logError("Failed to perform startup tasks.");
|
||||||
this.started = false;
|
this.started = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ServerHandler.stoppingServers()) {
|
if (ServerHandler.stoppingServers()) {
|
||||||
|
gui.logMessage("Stopping servers. Cannot start yet.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//Starts the server if possible
|
//Starts the server if possible
|
||||||
@ -367,14 +369,18 @@ public class Server {
|
|||||||
*/
|
*/
|
||||||
private String getJavaCommand() {
|
private String getJavaCommand() {
|
||||||
ServerLauncherController controller = ServerLauncherController.getInstance();
|
ServerLauncherController controller = ServerLauncherController.getInstance();
|
||||||
|
|
||||||
if (serverVersion.toLowerCase().contains("latest")) {
|
if (serverVersion.toLowerCase().contains("latest")) {
|
||||||
return controller.getJavaCommand();
|
return controller.getJavaCommand();
|
||||||
} else if (serverVersion.contains(".") && serverVersion.split("\\.").length >= 2 &&
|
} else if (serverVersion.contains(".") && serverVersion.split("\\.").length >= 2) {
|
||||||
Integer.parseInt(serverVersion.split("\\.")[1]) >= 17) {
|
try {
|
||||||
return controller.getJavaCommand();
|
if (Integer.parseInt(serverVersion.split("\\.")[1]) >= 17) {
|
||||||
} else {
|
return controller.getJavaCommand();
|
||||||
return controller.getOldJavaCommand();
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return controller.getOldJavaCommand();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,9 +117,11 @@ public class ServerHandler {
|
|||||||
public static void startServers() {
|
public static void startServers() {
|
||||||
ServerLauncherController controller = Main.getController();
|
ServerLauncherController controller = Main.getController();
|
||||||
gui.setStatus("Starting servers");
|
gui.setStatus("Starting servers");
|
||||||
int serverNum = 0;
|
Server previouslyStartedServer = null;
|
||||||
|
|
||||||
for (Collection collection : controller.getCurrentProfile().getCollections()) {
|
for (Collection collection : controller.getCurrentProfile().getCollections()) {
|
||||||
if (!collection.getServer().runServer(serverNum++ == 0)) {
|
Server server = collection.getServer();
|
||||||
|
if (!server.runServer(previouslyStartedServer == null || previouslyStartedServer.isProxy())) {
|
||||||
gui.showError("An error occurred. Start aborted. Please check relevant log files.");
|
gui.showError("An error occurred. Start aborted. Please check relevant log files.");
|
||||||
try {
|
try {
|
||||||
stop();
|
stop();
|
||||||
@ -129,6 +131,9 @@ public class ServerHandler {
|
|||||||
gui.updateGUIElementsWhenServersStartOrStop(false);
|
gui.updateGUIElementsWhenServersStartOrStop(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (server.isEnabled()) {
|
||||||
|
previouslyStartedServer = server;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ public class ServerTypeHandler {
|
|||||||
break;
|
break;
|
||||||
case "Paper":
|
case "Paper":
|
||||||
newType = new Paper("Paper", false, serverVersions, serverTypeInfo[2],
|
newType = new Paper("Paper", false, serverVersions, serverTypeInfo[2],
|
||||||
serverTypeInfo[3]);
|
serverTypeInfo[3], serverTypeInfo[4], serverTypeInfo[5]);
|
||||||
break;
|
break;
|
||||||
case "Bungee":
|
case "Bungee":
|
||||||
newType = new BungeeCord("Bungee", true, serverVersions, serverTypeInfo[2],
|
newType = new BungeeCord("Bungee", true, serverVersions, serverTypeInfo[2],
|
||||||
|
@ -22,6 +22,7 @@ public class ServerVersionContainer {
|
|||||||
private String bungeeVersion;
|
private String bungeeVersion;
|
||||||
private Map<String, String> waterfallVersions;
|
private Map<String, String> waterfallVersions;
|
||||||
private Map<String, String> travertineVersions;
|
private Map<String, String> travertineVersions;
|
||||||
|
private Map<String, String> paperVersions;
|
||||||
private Map<String, String> spongeVanillaVersions;
|
private Map<String, String> spongeVanillaVersions;
|
||||||
private Map<String, String> spongeForgeVersions;
|
private Map<String, String> spongeForgeVersions;
|
||||||
private String downloadedBuildToolsVersion;
|
private String downloadedBuildToolsVersion;
|
||||||
@ -32,6 +33,7 @@ public class ServerVersionContainer {
|
|||||||
private ServerVersionContainer() {
|
private ServerVersionContainer() {
|
||||||
this.waterfallVersions = new HashMap<>();
|
this.waterfallVersions = new HashMap<>();
|
||||||
this.travertineVersions = new HashMap<>();
|
this.travertineVersions = new HashMap<>();
|
||||||
|
this.paperVersions = new HashMap<>();
|
||||||
this.spongeVanillaVersions = new HashMap<>();
|
this.spongeVanillaVersions = new HashMap<>();
|
||||||
this.spongeForgeVersions = new HashMap<>();
|
this.spongeForgeVersions = new HashMap<>();
|
||||||
loadState();
|
loadState();
|
||||||
@ -58,6 +60,7 @@ public class ServerVersionContainer {
|
|||||||
this.bungeeVersion = null;
|
this.bungeeVersion = null;
|
||||||
this.waterfallVersions = new HashMap<>();
|
this.waterfallVersions = new HashMap<>();
|
||||||
this.travertineVersions = new HashMap<>();
|
this.travertineVersions = new HashMap<>();
|
||||||
|
this.paperVersions = new HashMap<>();
|
||||||
this.spongeVanillaVersions = new HashMap<>();
|
this.spongeVanillaVersions = new HashMap<>();
|
||||||
this.spongeForgeVersions = new HashMap<>();
|
this.spongeForgeVersions = new HashMap<>();
|
||||||
this.downloadedBuildToolsVersion = null;
|
this.downloadedBuildToolsVersion = null;
|
||||||
@ -70,6 +73,7 @@ public class ServerVersionContainer {
|
|||||||
"bungeeVersion;" + bungeeVersion + "\n" +
|
"bungeeVersion;" + bungeeVersion + "\n" +
|
||||||
"waterfallVersions;" + mapToString(waterfallVersions) + "\n" +
|
"waterfallVersions;" + mapToString(waterfallVersions) + "\n" +
|
||||||
"travertineVersions;" + mapToString(travertineVersions) + "\n" +
|
"travertineVersions;" + mapToString(travertineVersions) + "\n" +
|
||||||
|
"paperVersions;" + mapToString(paperVersions) + "\n" +
|
||||||
"spongeVanillaVersions;" + mapToString(spongeVanillaVersions) + "\n" +
|
"spongeVanillaVersions;" + mapToString(spongeVanillaVersions) + "\n" +
|
||||||
"spongeForgeVersions;" + mapToString(spongeForgeVersions) + "\n" +
|
"spongeForgeVersions;" + mapToString(spongeForgeVersions) + "\n" +
|
||||||
"downloadedBuildToolsVersion;" + downloadedBuildToolsVersion;
|
"downloadedBuildToolsVersion;" + downloadedBuildToolsVersion;
|
||||||
@ -163,6 +167,9 @@ public class ServerVersionContainer {
|
|||||||
case "travertineVersions":
|
case "travertineVersions":
|
||||||
parseVersionsToMap(travertineVersions, variableValue);
|
parseVersionsToMap(travertineVersions, variableValue);
|
||||||
break;
|
break;
|
||||||
|
case "paperVersions":
|
||||||
|
parseVersionsToMap(paperVersions, variableValue);
|
||||||
|
break;
|
||||||
case "spongeVanillaVersions":
|
case "spongeVanillaVersions":
|
||||||
parseVersionsToMap(spongeVanillaVersions, variableValue);
|
parseVersionsToMap(spongeVanillaVersions, variableValue);
|
||||||
break;
|
break;
|
||||||
@ -291,6 +298,27 @@ public class ServerVersionContainer {
|
|||||||
saveState();
|
saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a specific paper version
|
||||||
|
*
|
||||||
|
* @param versionKey <p>The version to check the current version of</p>
|
||||||
|
* @return <p>The current paper version</p>
|
||||||
|
*/
|
||||||
|
public String getPaperVersion(String versionKey) {
|
||||||
|
return this.paperVersions.get(versionKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the current version for a given paper version
|
||||||
|
*
|
||||||
|
* @param mapKey <p>The version key to set version for</p>
|
||||||
|
* @param newValue <p>The new current version</p>
|
||||||
|
*/
|
||||||
|
public void setPaperVersion(String mapKey, String newValue) {
|
||||||
|
this.paperVersions.put(mapKey, newValue);
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a specific sponge vanilla version
|
* Gets a specific sponge vanilla version
|
||||||
*
|
*
|
||||||
|
@ -2,8 +2,8 @@ package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
|||||||
|
|
||||||
import net.knarcraft.minecraftserverlauncher.Main;
|
import net.knarcraft.minecraftserverlauncher.Main;
|
||||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.server.JarBuilder;
|
||||||
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
|
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;
|
||||||
|
@ -3,19 +3,25 @@ package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
|||||||
/**
|
/**
|
||||||
* This class represents the Paper Minecraft server type
|
* This class represents the Paper Minecraft server type
|
||||||
*/
|
*/
|
||||||
public class Paper extends Spigot {
|
public class Paper extends Waterfall {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instantiates a new Paper server type
|
* Instantiates a new Paper server type
|
||||||
*
|
*
|
||||||
* @param typeName <p>The name of the server type</p>
|
* @param typeName <p>The name of the server type</p>
|
||||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||||
* @param versions <p>A list of one or more server versions for the type</p>
|
* @param versions <p>The available versions for the server type</p>
|
||||||
* @param downloadURL <p>The URL used for downloading .jar files</p>
|
* @param versionURL <p>The URL used to finding the newest version</p>
|
||||||
* @param downloadURLPart <p>A string used after the download url as an additional part of the URL</p>
|
* @param srcStart <p>The string after which the version id starts</p>
|
||||||
|
* @param srcEnd <p>The string marking the end of the version id</p>
|
||||||
|
* @param downloadURL <p>The URL used for downloading the latest version</p>
|
||||||
*/
|
*/
|
||||||
public Paper(String typeName, boolean isProxy, String[] versions, String downloadURL, String downloadURLPart) {
|
public Paper(String typeName, boolean isProxy, String[] versions, String versionURL, String srcStart,
|
||||||
super(typeName, isProxy, versions, downloadURL, downloadURLPart);
|
String srcEnd, String downloadURL) {
|
||||||
|
super(typeName, isProxy, versions, versionURL, srcStart, srcEnd, downloadURL);
|
||||||
|
|
||||||
|
this.oldVersionFunction = serverVersionContainer::getPaperVersion;
|
||||||
|
this.versionUpdateFunction = serverVersionContainer::setPaperVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,13 +50,21 @@ 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(readRemoteFile(versionURL + version), srcStart, srcEnd);
|
String versionFileContents = readRemoteFile(versionURL + version);
|
||||||
String fullURL = downloadURL + version + "/" + newestVersion + "/download";
|
String[] versions = stringBetween(versionFileContents, srcStart, srcEnd).split(",");
|
||||||
|
String newestVersion = versions[versions.length - 1];
|
||||||
String oldVersion = oldVersionFunction.apply(version);
|
String oldVersion = oldVersionFunction.apply(version);
|
||||||
|
|
||||||
//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)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Get necessary information for downloading the latest version
|
||||||
|
String newestVersionInfoURL = versionURL + version + "/builds/" + newestVersion;
|
||||||
|
String fileName = stringBetween(readRemoteFile(newestVersionInfoURL), "\"name\":\"", "\"");
|
||||||
|
String fullURL = downloadURL + version + "/builds/" + newestVersion + "/downloads/" + fileName;
|
||||||
|
|
||||||
//The new jar file could not be downloaded
|
//The new jar file could not be downloaded
|
||||||
if (!downloadFile(fullURL, Paths.get(filePath.toURI()))) {
|
if (!downloadFile(fullURL, Paths.get(filePath.toURI()))) {
|
||||||
return false;
|
return false;
|
||||||
@ -64,4 +72,5 @@ public class Waterfall extends AbstractServerType {
|
|||||||
versionUpdateFunction.accept(version, newestVersion);
|
versionUpdateFunction.accept(version, newestVersion);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,106 @@
|
|||||||
|
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||||
|
|
||||||
|
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Backup GUI is used to display backup progress
|
||||||
|
*/
|
||||||
|
public class BackupGUI implements ActionListener {
|
||||||
|
private static JFrame frame;
|
||||||
|
private static JTextArea progressTextArea;
|
||||||
|
private static JProgressBar progressBar;
|
||||||
|
private static JButton cancelButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new GUI
|
||||||
|
*/
|
||||||
|
public BackupGUI() {
|
||||||
|
instantiate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the server consoles frame
|
||||||
|
*/
|
||||||
|
public void instantiate() {
|
||||||
|
if (frame != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frame = new JFrame("Running backup...");
|
||||||
|
frame.setBounds(100, 100, 500, 140);
|
||||||
|
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||||
|
ImageIcon img;
|
||||||
|
try {
|
||||||
|
img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png")));
|
||||||
|
frame.setIconImage(img.getImage());
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
|
|
||||||
|
progressTextArea = new JTextArea();
|
||||||
|
progressTextArea.setEditable(false);
|
||||||
|
progressBar = new JProgressBar();
|
||||||
|
cancelButton = new JButton("Cancel");
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
|
||||||
|
panel.add(progressTextArea);
|
||||||
|
panel.add(Box.createRigidArea(new Dimension(0, 5)));
|
||||||
|
panel.add(progressBar);
|
||||||
|
|
||||||
|
JPanel buttonPane = new JPanel();
|
||||||
|
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
|
||||||
|
buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
|
||||||
|
buttonPane.add(Box.createHorizontalGlue());
|
||||||
|
buttonPane.add(cancelButton);
|
||||||
|
cancelButton.addActionListener(BackupGUI.this);
|
||||||
|
|
||||||
|
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||||
|
Container contentPane = frame.getContentPane();
|
||||||
|
contentPane.add(panel, BorderLayout.CENTER);
|
||||||
|
contentPane.add(buttonPane, BorderLayout.PAGE_END);
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates information about the backup progress
|
||||||
|
*
|
||||||
|
* @param infoText <p>The text to display</p>
|
||||||
|
* @param progressPercent <p>The new percent of the progress bar</p>
|
||||||
|
*/
|
||||||
|
public static void updateProgress(String infoText, int progressPercent) {
|
||||||
|
if (progressTextArea != null) {
|
||||||
|
progressTextArea.setText(infoText);
|
||||||
|
}
|
||||||
|
if (progressBar != null) {
|
||||||
|
progressBar.setValue(progressPercent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the backup GUI
|
||||||
|
*/
|
||||||
|
public static void destroy() {
|
||||||
|
if (frame != null) {
|
||||||
|
frame.dispose();
|
||||||
|
frame = null;
|
||||||
|
progressBar = null;
|
||||||
|
progressTextArea = null;
|
||||||
|
cancelButton = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent actionEvent) {
|
||||||
|
if (actionEvent.getSource() == cancelButton) {
|
||||||
|
BackupUtil.abortBackup();
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||||
|
|
||||||
|
import net.knarcraft.minecraftserverlauncher.Main;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for clicking the close button of a server tab
|
||||||
|
*/
|
||||||
|
public class CloseTabActionListener implements ActionListener {
|
||||||
|
|
||||||
|
private final String tabName;
|
||||||
|
private final JTabbedPane tabPane;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new close tab action listener
|
||||||
|
*
|
||||||
|
* @param tabPane <p>The tab pane containing all tabs</p>
|
||||||
|
* @param tabName <p>The name of the tab connected to this action listener</p>
|
||||||
|
*/
|
||||||
|
public CloseTabActionListener(JTabbedPane tabPane, String tabName) {
|
||||||
|
this.tabName = tabName;
|
||||||
|
this.tabPane = tabPane;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent evt) {
|
||||||
|
int index = tabPane.indexOfTab(tabName);
|
||||||
|
if (index >= 0) {
|
||||||
|
//Abort if the user just mis-clicked
|
||||||
|
int answer = JOptionPane.showConfirmDialog(null,
|
||||||
|
String.format("Do you really want to remove the server %s?", tabName), "Remove server",
|
||||||
|
JOptionPane.YES_NO_OPTION
|
||||||
|
);
|
||||||
|
if (answer == JOptionPane.YES_NO_OPTION) {
|
||||||
|
//Remove the server
|
||||||
|
ServerLauncherController controller = Main.getController();
|
||||||
|
controller.getCurrentProfile().removeCollection(tabName);
|
||||||
|
controller.getGUI().updateWithSavedProfileData();
|
||||||
|
controller.getCurrentProfile().updateConsoles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -93,7 +93,7 @@ public class Console extends KeyAdapter implements ActionListener, KeyListener {
|
|||||||
StringBuilder newTextBuilder = new StringBuilder();
|
StringBuilder newTextBuilder = new StringBuilder();
|
||||||
for (String line : oldTextList) {
|
for (String line : oldTextList) {
|
||||||
if (!line.equals("")) {
|
if (!line.equals("")) {
|
||||||
newTextBuilder.append(line);
|
newTextBuilder.append(line).append("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.textOutput.setText(newTextBuilder.toString());
|
this.textOutput.setText(newTextBuilder.toString());
|
||||||
|
@ -0,0 +1,218 @@
|
|||||||
|
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||||
|
|
||||||
|
import net.knarcraft.minecraftserverlauncher.Main;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
public class ControlPanelTab implements ActionListener {
|
||||||
|
|
||||||
|
private JButton startServerButton;
|
||||||
|
private JButton stopServerButton;
|
||||||
|
private JButton backupButton;
|
||||||
|
private JButton addProfileButton;
|
||||||
|
private JButton showConsolesButton;
|
||||||
|
private JButton deleteProfileButton;
|
||||||
|
private JComboBox<String> profiles;
|
||||||
|
private final JPanel controlPanelPanel;
|
||||||
|
private final ServerLauncherController controller;
|
||||||
|
private final JLabel statusLabel = new JLabel("Servers are stopped");
|
||||||
|
|
||||||
|
public ControlPanelTab(JPanel controlPanelPanel) {
|
||||||
|
this.controlPanelPanel = controlPanelPanel;
|
||||||
|
this.controller = Main.getController();
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the text of the status label
|
||||||
|
*
|
||||||
|
* @param text <p>The new text of the status label</p>
|
||||||
|
*/
|
||||||
|
public void setStatusText(String text) {
|
||||||
|
this.statusLabel.setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the ServerLauncherGUI components to block a user from doing illegal actions
|
||||||
|
*
|
||||||
|
* @param running <p>Whether the servers are currently running</p>
|
||||||
|
*/
|
||||||
|
public void updateGUIElementsWhenServersStartOrStop(boolean running) {
|
||||||
|
boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running.
|
||||||
|
profiles.setEnabled(stopped);
|
||||||
|
addProfileButton.setEnabled(stopped);
|
||||||
|
deleteProfileButton.setEnabled(stopped);
|
||||||
|
startServerButton.setEnabled(stopped);
|
||||||
|
stopServerButton.setEnabled(running);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops all servers
|
||||||
|
*/
|
||||||
|
public void stopServers() {
|
||||||
|
GUI gui = Main.getController().getGUI();
|
||||||
|
try {
|
||||||
|
gui.setStatus("Servers are stopping...");
|
||||||
|
ServerHandler.stop();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
gui.showError("Could not stop server.");
|
||||||
|
e1.printStackTrace();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
gui.showError("Could not kill server.");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the currently selected profile
|
||||||
|
*
|
||||||
|
* @return <p>The currently selected profile or null</p>
|
||||||
|
*/
|
||||||
|
public String getSelectedProfile() {
|
||||||
|
Object selectedProfile = profiles.getSelectedItem();
|
||||||
|
if (selectedProfile != null) {
|
||||||
|
return selectedProfile.toString();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the profiles combo
|
||||||
|
*/
|
||||||
|
public void updateProfiles() {
|
||||||
|
String selectedProfile = Main.getController().getCurrentProfile().getName();
|
||||||
|
this.profiles.removeAllItems();
|
||||||
|
for (String profile : Main.getController().getProfileNames()) {
|
||||||
|
this.profiles.addItem(profile);
|
||||||
|
}
|
||||||
|
this.profiles.setSelectedItem(selectedProfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the selected profile
|
||||||
|
*/
|
||||||
|
private void deleteProfile() {
|
||||||
|
Object selected = profiles.getSelectedItem();
|
||||||
|
int answer = JOptionPane.showConfirmDialog(null,
|
||||||
|
String.format("Do you really want to remove the profile %s?", selected), "Remove profile",
|
||||||
|
JOptionPane.YES_NO_OPTION
|
||||||
|
);
|
||||||
|
if (answer == JOptionPane.YES_NO_OPTION) {
|
||||||
|
if (selected != null) {
|
||||||
|
controller.removeProfile(selected.toString());
|
||||||
|
updateProfiles();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the previous profile and loads data from the new profile
|
||||||
|
*/
|
||||||
|
private void changeProfile() {
|
||||||
|
controller.saveState();
|
||||||
|
Object current = this.profiles.getSelectedItem();
|
||||||
|
if (current != null) {
|
||||||
|
controller.setCurrentProfile(current.toString());
|
||||||
|
}
|
||||||
|
controller.getGUI().updateWithSavedProfileData();
|
||||||
|
controller.getCurrentProfile().updateConsoles();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialize() {
|
||||||
|
SpringLayout springLayout = new SpringLayout();
|
||||||
|
controlPanelPanel.setLayout(springLayout);
|
||||||
|
|
||||||
|
JLabel lblBasicControls = new JLabel("Basic controls");
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, lblBasicControls, 10, SpringLayout.NORTH, controlPanelPanel);
|
||||||
|
controlPanelPanel.add(lblBasicControls);
|
||||||
|
|
||||||
|
startServerButton = new JButton("Start servers");
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, lblBasicControls, 0, SpringLayout.WEST, startServerButton);
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, startServerButton, 6, SpringLayout.SOUTH, lblBasicControls);
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, startServerButton, 10, SpringLayout.WEST, controlPanelPanel);
|
||||||
|
controlPanelPanel.add(startServerButton);
|
||||||
|
startServerButton.addActionListener(this);
|
||||||
|
|
||||||
|
stopServerButton = new JButton("Stop servers");
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, stopServerButton, 0, SpringLayout.NORTH, startServerButton);
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, stopServerButton, 6, SpringLayout.EAST, startServerButton);
|
||||||
|
controlPanelPanel.add(stopServerButton);
|
||||||
|
stopServerButton.addActionListener(this);
|
||||||
|
|
||||||
|
showConsolesButton = new JButton("View server consoles");
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, showConsolesButton, 0, SpringLayout.NORTH, stopServerButton);
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, showConsolesButton, 6, SpringLayout.EAST, stopServerButton);
|
||||||
|
controlPanelPanel.add(showConsolesButton);
|
||||||
|
showConsolesButton.addActionListener(this);
|
||||||
|
|
||||||
|
backupButton = new JButton("Backup");
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, backupButton, 0, SpringLayout.NORTH, showConsolesButton);
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, backupButton, 6, SpringLayout.EAST, showConsolesButton);
|
||||||
|
controlPanelPanel.add(backupButton);
|
||||||
|
backupButton.addActionListener(this);
|
||||||
|
|
||||||
|
JLabel profileLabel = new JLabel("Profile");
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, profileLabel, 6, SpringLayout.SOUTH, startServerButton);
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, profileLabel, 10, SpringLayout.WEST, controlPanelPanel);
|
||||||
|
controlPanelPanel.add(profileLabel);
|
||||||
|
|
||||||
|
addProfileButton = new JButton("+");
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, addProfileButton, 6, SpringLayout.SOUTH, profileLabel);
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, addProfileButton, 10, SpringLayout.WEST, controlPanelPanel);
|
||||||
|
controlPanelPanel.add(addProfileButton);
|
||||||
|
addProfileButton.addActionListener(this);
|
||||||
|
|
||||||
|
deleteProfileButton = new JButton("-");
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, deleteProfileButton, 0, SpringLayout.NORTH, addProfileButton);
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, deleteProfileButton, 6, SpringLayout.EAST, addProfileButton);
|
||||||
|
controlPanelPanel.add(deleteProfileButton);
|
||||||
|
deleteProfileButton.addActionListener(this);
|
||||||
|
|
||||||
|
profiles = new JComboBox<>();
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, profiles, 0, SpringLayout.NORTH, addProfileButton);
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, profiles, 6, SpringLayout.EAST, deleteProfileButton);
|
||||||
|
springLayout.putConstraint(SpringLayout.EAST, profiles, 124, SpringLayout.EAST, deleteProfileButton);
|
||||||
|
controlPanelPanel.add(profiles);
|
||||||
|
profiles.addActionListener(this);
|
||||||
|
|
||||||
|
springLayout.putConstraint(SpringLayout.NORTH, statusLabel, 6, SpringLayout.SOUTH, addProfileButton);
|
||||||
|
springLayout.putConstraint(SpringLayout.SOUTH, statusLabel, -10, SpringLayout.SOUTH, controlPanelPanel);
|
||||||
|
springLayout.putConstraint(SpringLayout.WEST, statusLabel, 10, SpringLayout.WEST, controlPanelPanel);
|
||||||
|
springLayout.putConstraint(SpringLayout.EAST, statusLabel, -10, SpringLayout.EAST, controlPanelPanel);
|
||||||
|
statusLabel.setFont(new Font("", Font.BOLD, 12));
|
||||||
|
controlPanelPanel.add(statusLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent actionEvent) {
|
||||||
|
Object actionSource = actionEvent.getSource();
|
||||||
|
if (actionSource == startServerButton) {
|
||||||
|
controller.saveState();
|
||||||
|
Executors.newSingleThreadExecutor().execute(ServerHandler::startServers);
|
||||||
|
} else if (actionSource == stopServerButton) {
|
||||||
|
stopServers();
|
||||||
|
} else if (actionSource == backupButton) {
|
||||||
|
//Run backup in its own thread to prevent locking up
|
||||||
|
Executors.newSingleThreadExecutor().execute(() -> BackupUtil.backup(controller.getGUI()));
|
||||||
|
} else if (actionSource == addProfileButton) {
|
||||||
|
controller.addProfile(JOptionPane.showInputDialog("Profile name: "));
|
||||||
|
updateProfiles();
|
||||||
|
} else if (actionSource == deleteProfileButton) {
|
||||||
|
deleteProfile();
|
||||||
|
} else if (actionSource == profiles) {
|
||||||
|
changeProfile();
|
||||||
|
} else if (actionSource == showConsolesButton) {
|
||||||
|
ServerConsoles.setAsVisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,11 @@
|
|||||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class keeps track of all consoles
|
* This class keeps track of all consoles
|
||||||
@ -31,6 +35,12 @@ public class ServerConsoles {
|
|||||||
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||||
consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP);
|
consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP);
|
||||||
frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER);
|
frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER);
|
||||||
|
ImageIcon img;
|
||||||
|
try {
|
||||||
|
img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png")));
|
||||||
|
frame.setIconImage(img.getImage());
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,6 @@ public class ServerControlTab implements ActionListener {
|
|||||||
private JButton customCommandButton;
|
private JButton customCommandButton;
|
||||||
private JButton saveServerButton;
|
private JButton saveServerButton;
|
||||||
private JButton reloadButton;
|
private JButton reloadButton;
|
||||||
private JButton showConsolesButton;
|
|
||||||
private JTextField customCommandTextField;
|
private JTextField customCommandTextField;
|
||||||
|
|
||||||
private final ServerLauncherController controller = ServerLauncherController.getInstance();
|
private final ServerLauncherController controller = ServerLauncherController.getInstance();
|
||||||
@ -134,13 +133,6 @@ public class ServerControlTab implements ActionListener {
|
|||||||
springLayout.putConstraint(SpringLayout.EAST, reloadButton, 0, SpringLayout.EAST, opButton);
|
springLayout.putConstraint(SpringLayout.EAST, reloadButton, 0, SpringLayout.EAST, opButton);
|
||||||
controlServers.add(reloadButton);
|
controlServers.add(reloadButton);
|
||||||
reloadButton.addActionListener(this);
|
reloadButton.addActionListener(this);
|
||||||
|
|
||||||
showConsolesButton = new JButton("View server consoles");
|
|
||||||
springLayout.putConstraint(SpringLayout.NORTH, showConsolesButton, 0, SpringLayout.NORTH, saveServerButton);
|
|
||||||
springLayout.putConstraint(SpringLayout.WEST, showConsolesButton, 0, SpringLayout.WEST, lblTargetServer);
|
|
||||||
springLayout.putConstraint(SpringLayout.EAST, showConsolesButton, 0, SpringLayout.EAST, targetServerCombo);
|
|
||||||
controlServers.add(showConsolesButton);
|
|
||||||
showConsolesButton.addActionListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -181,9 +173,7 @@ public class ServerControlTab implements ActionListener {
|
|||||||
//Registers actions on all commands executed on a specific server
|
//Registers actions on all commands executed on a specific server
|
||||||
handleServerCommands(actionSource, selectedServerValue);
|
handleServerCommands(actionSource, selectedServerValue);
|
||||||
|
|
||||||
if (actionSource == showConsolesButton) {
|
if (actionSource == targetServerCombo) {
|
||||||
ServerConsoles.setAsVisible();
|
|
||||||
} else if (actionSource == targetServerCombo) {
|
|
||||||
updatePlayers();
|
updatePlayers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,11 @@ 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.ServerLauncherController;
|
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||||
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
|
|
||||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.naming.ConfigurationException;
|
import javax.naming.ConfigurationException;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import javax.swing.plaf.basic.BasicButtonUI;
|
||||||
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;
|
||||||
@ -18,7 +17,6 @@ import java.io.IOException;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
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;
|
||||||
@ -33,25 +31,19 @@ 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 ServerLauncherController controller;
|
private final ServerLauncherController controller;
|
||||||
private Map<String, String> textStrings;
|
private Map<String, String> textStrings;
|
||||||
private Tray applicationTray;
|
private Tray applicationTray;
|
||||||
|
|
||||||
private JFrame frame;
|
private JFrame frame;
|
||||||
private JTabbedPane tabbedPane;
|
private JTabbedPane mainTabbedPane;
|
||||||
private JTabbedPane serversPane;
|
private JTabbedPane serversPane;
|
||||||
private ServerControlTab serverControlTab;
|
private ServerControlTab serverControlTab;
|
||||||
|
private ControlPanelTab controlPanelTab;
|
||||||
private ServerLauncherMenu serverLauncherMenu;
|
private ServerLauncherMenu serverLauncherMenu;
|
||||||
|
|
||||||
//Basic controls
|
private JButton addServerTabButton;
|
||||||
private JButton startServerButton;
|
private JButton addServerPaneButton;
|
||||||
private JButton stopServerButton;
|
|
||||||
private JButton addServerButton;
|
|
||||||
private JButton backupButton;
|
|
||||||
private JButton addProfileButton;
|
|
||||||
private JButton deleteProfileButton;
|
|
||||||
private JComboBox<String> profiles;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the application window
|
* Creates the application window
|
||||||
@ -99,9 +91,18 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
|
|||||||
return this.serversPane;
|
return this.serversPane;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets this GUI's control panel tab
|
||||||
|
*
|
||||||
|
* @return <p>The control panel tab for this GUI</p>
|
||||||
|
*/
|
||||||
|
public ControlPanelTab getControlPanelTab() {
|
||||||
|
return this.controlPanelTab;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStatus(String text) {
|
public void setStatus(String text) {
|
||||||
this.lblStatuslabel.setText(text);
|
controlPanelTab.setStatusText(text);
|
||||||
this.logMessage(text);
|
this.logMessage(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,18 +121,6 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
|
|||||||
return chooser.getSelectedFile();
|
return chooser.getSelectedFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the profiles combo
|
|
||||||
*/
|
|
||||||
public void updateProfiles() {
|
|
||||||
String selectedProfile = Main.getController().getCurrentProfile().getName();
|
|
||||||
this.profiles.removeAllItems();
|
|
||||||
for (String profile : Main.getController().getProfileNames()) {
|
|
||||||
this.profiles.addItem(profile);
|
|
||||||
}
|
|
||||||
this.profiles.setSelectedItem(selectedProfile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the server control tab used by this GUI
|
* Gets the server control tab used by this GUI
|
||||||
*
|
*
|
||||||
@ -160,7 +149,82 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
|
|||||||
serverControlTab.update();
|
serverControlTab.update();
|
||||||
for (Collection collection : controller.getCurrentProfile().getCollections()) {
|
for (Collection collection : controller.getCurrentProfile().getCollections()) {
|
||||||
serversPane.addTab(collection.getName(), collection.getServerTab().getPanel());
|
serversPane.addTab(collection.getName(), collection.getServerTab().getPanel());
|
||||||
|
addCloseButtonToServerTab(collection.getName());
|
||||||
}
|
}
|
||||||
|
addAddButtonToServerTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an add button to the servers tab's tabs
|
||||||
|
*/
|
||||||
|
private void addAddButtonToServerTab() {
|
||||||
|
JPanel tabPanel = new JPanel();
|
||||||
|
tabPanel.setLayout(new GridLayout());
|
||||||
|
tabPanel.setOpaque(false);
|
||||||
|
|
||||||
|
JPanel tabContentsPanel = new JPanel(new SpringLayout());
|
||||||
|
serversPane.addTab("Add tab", tabContentsPanel);
|
||||||
|
|
||||||
|
addServerTabButton = getAddServerButton(true);
|
||||||
|
addServerTabButton.addActionListener(this);
|
||||||
|
addServerPaneButton = getAddServerButton(false);
|
||||||
|
addServerPaneButton.addActionListener(this);
|
||||||
|
|
||||||
|
tabContentsPanel.add(addServerTabButton);
|
||||||
|
tabPanel.add(addServerPaneButton);
|
||||||
|
serversPane.setTabComponentAt(serversPane.getTabCount() - 1, tabPanel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a button for adding a new server
|
||||||
|
*
|
||||||
|
* @param displayButtonStyle <p>Whether to show or hide the button's style</p>
|
||||||
|
* @return <p>A new add server button</p>
|
||||||
|
*/
|
||||||
|
private JButton getAddServerButton(boolean displayButtonStyle) {
|
||||||
|
JButton addButton = new JButton("+ Add server");
|
||||||
|
if (!displayButtonStyle) {
|
||||||
|
addButton.setBorder(BorderFactory.createEtchedBorder());
|
||||||
|
addButton.setFocusable(false);
|
||||||
|
addButton.setBorderPainted(false);
|
||||||
|
addButton.setContentAreaFilled(false);
|
||||||
|
addButton.setRolloverEnabled(true);
|
||||||
|
addButton.setUI(new BasicButtonUI());
|
||||||
|
}
|
||||||
|
return addButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param serverName <p>The name of the server/tab to add a close button to</p>
|
||||||
|
*/
|
||||||
|
private void addCloseButtonToServerTab(String serverName) {
|
||||||
|
int index = serversPane.indexOfTab(serverName);
|
||||||
|
JPanel tabPanel = new JPanel(new GridBagLayout());
|
||||||
|
tabPanel.setOpaque(false);
|
||||||
|
JLabel serverTitleLabel = new JLabel(serverName);
|
||||||
|
JButton removeServerButton = new JButton("(X)");
|
||||||
|
removeServerButton.setBorder(BorderFactory.createEtchedBorder());
|
||||||
|
removeServerButton.setFocusable(false);
|
||||||
|
removeServerButton.setBorderPainted(false);
|
||||||
|
removeServerButton.setContentAreaFilled(false);
|
||||||
|
removeServerButton.setRolloverEnabled(true);
|
||||||
|
removeServerButton.setPreferredSize(new Dimension(18, 17));
|
||||||
|
removeServerButton.setUI(new BasicButtonUI());
|
||||||
|
|
||||||
|
GridBagConstraints gridBagConstraints = new GridBagConstraints();
|
||||||
|
gridBagConstraints.gridx = 0;
|
||||||
|
gridBagConstraints.gridy = 0;
|
||||||
|
gridBagConstraints.weightx = 1;
|
||||||
|
|
||||||
|
tabPanel.add(serverTitleLabel, gridBagConstraints);
|
||||||
|
|
||||||
|
gridBagConstraints.gridx++;
|
||||||
|
gridBagConstraints.weightx = 0;
|
||||||
|
tabPanel.add(removeServerButton, gridBagConstraints);
|
||||||
|
|
||||||
|
serversPane.setTabComponentAt(index, tabPanel);
|
||||||
|
|
||||||
|
removeServerButton.addActionListener(new CloseTabActionListener(serversPane, serverName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -194,93 +258,30 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
|
|||||||
|
|
||||||
this.serverLauncherMenu = new ServerLauncherMenu(menuBar, this);
|
this.serverLauncherMenu = new ServerLauncherMenu(menuBar, this);
|
||||||
|
|
||||||
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
|
mainTabbedPane = new JTabbedPane(JTabbedPane.TOP);
|
||||||
frame.getContentPane().add(tabbedPane);
|
frame.getContentPane().add(mainTabbedPane);
|
||||||
|
|
||||||
JPanel panelBasic = new JPanel();
|
JPanel controlPanelPanel = new JPanel();
|
||||||
tabbedPane.addTab("Control panel", null, panelBasic, null);
|
mainTabbedPane.addTab("Control panel", null, controlPanelPanel, null);
|
||||||
SpringLayout sl_panel = new SpringLayout();
|
controlPanelTab = new ControlPanelTab(controlPanelPanel);
|
||||||
panelBasic.setLayout(sl_panel);
|
|
||||||
|
|
||||||
JLabel lblBasicControls = new JLabel("Basic controls");
|
JPanel controlServersPanel = new JPanel();
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, lblBasicControls, 10, SpringLayout.NORTH, panelBasic);
|
mainTabbedPane.addTab("Control servers", null, controlServersPanel, null);
|
||||||
panelBasic.add(lblBasicControls);
|
serverControlTab = new ServerControlTab(frame, controlServersPanel);
|
||||||
|
|
||||||
startServerButton = new JButton("Start servers");
|
JPanel serversPanel = new JPanel();
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, lblBasicControls, 0, SpringLayout.WEST, startServerButton);
|
mainTabbedPane.addTab("Servers", null, serversPanel, null);
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, startServerButton, 6, SpringLayout.SOUTH, lblBasicControls);
|
SpringLayout serversPanelSpringLayout = new SpringLayout();
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, startServerButton, 10, SpringLayout.WEST, panelBasic);
|
serversPanel.setLayout(serversPanelSpringLayout);
|
||||||
panelBasic.add(startServerButton);
|
|
||||||
startServerButton.addActionListener(this);
|
|
||||||
|
|
||||||
stopServerButton = new JButton("Stop servers");
|
serversPane = new JTabbedPane(JTabbedPane.TOP);
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, stopServerButton, 0, SpringLayout.NORTH, startServerButton);
|
serversPanelSpringLayout.putConstraint(SpringLayout.NORTH, serversPane, 0, SpringLayout.NORTH, serversPanel);
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, stopServerButton, 6, SpringLayout.EAST, startServerButton);
|
serversPanelSpringLayout.putConstraint(SpringLayout.WEST, serversPane, 0, SpringLayout.WEST, serversPanel);
|
||||||
panelBasic.add(stopServerButton);
|
serversPanelSpringLayout.putConstraint(SpringLayout.SOUTH, serversPane, 0, SpringLayout.SOUTH, serversPanel);
|
||||||
stopServerButton.addActionListener(this);
|
serversPanelSpringLayout.putConstraint(SpringLayout.EAST, serversPane, 0, SpringLayout.EAST, serversPanel);
|
||||||
|
serversPanel.add(serversPane);
|
||||||
|
|
||||||
JLabel lblProfile = new JLabel("Profile");
|
serversPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, lblProfile, 6, SpringLayout.SOUTH, startServerButton);
|
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, lblProfile, 10, SpringLayout.WEST, panelBasic);
|
|
||||||
panelBasic.add(lblProfile);
|
|
||||||
|
|
||||||
addProfileButton = new JButton("+");
|
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, addProfileButton, 6, SpringLayout.SOUTH, lblProfile);
|
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, addProfileButton, 10, SpringLayout.WEST, panelBasic);
|
|
||||||
panelBasic.add(addProfileButton);
|
|
||||||
addProfileButton.addActionListener(this);
|
|
||||||
|
|
||||||
deleteProfileButton = new JButton("-");
|
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, deleteProfileButton, 0, SpringLayout.NORTH, addProfileButton);
|
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, deleteProfileButton, 6, SpringLayout.EAST, addProfileButton);
|
|
||||||
panelBasic.add(deleteProfileButton);
|
|
||||||
deleteProfileButton.addActionListener(this);
|
|
||||||
|
|
||||||
profiles = new JComboBox<>();
|
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, profiles, 0, SpringLayout.NORTH, addProfileButton);
|
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, profiles, 6, SpringLayout.EAST, deleteProfileButton);
|
|
||||||
sl_panel.putConstraint(SpringLayout.EAST, profiles, 124, SpringLayout.EAST, deleteProfileButton);
|
|
||||||
panelBasic.add(profiles);
|
|
||||||
profiles.addActionListener(this);
|
|
||||||
|
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, lblStatuslabel, 6, SpringLayout.SOUTH, addProfileButton);
|
|
||||||
sl_panel.putConstraint(SpringLayout.SOUTH, lblStatuslabel, -10, SpringLayout.SOUTH, panelBasic);
|
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, lblStatuslabel, 10, SpringLayout.WEST, panelBasic);
|
|
||||||
sl_panel.putConstraint(SpringLayout.EAST, lblStatuslabel, -10, SpringLayout.EAST, panelBasic);
|
|
||||||
panelBasic.add(lblStatuslabel);
|
|
||||||
|
|
||||||
addServerButton = new JButton("Add server");
|
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, addServerButton, 0, SpringLayout.NORTH, startServerButton);
|
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, addServerButton, 6, SpringLayout.EAST, stopServerButton);
|
|
||||||
panelBasic.add(addServerButton);
|
|
||||||
addServerButton.addActionListener(this);
|
|
||||||
|
|
||||||
backupButton = new JButton("Backup");
|
|
||||||
sl_panel.putConstraint(SpringLayout.NORTH, backupButton, 0, SpringLayout.NORTH, startServerButton);
|
|
||||||
sl_panel.putConstraint(SpringLayout.WEST, backupButton, 6, SpringLayout.EAST, addServerButton);
|
|
||||||
panelBasic.add(backupButton);
|
|
||||||
backupButton.addActionListener(this);
|
|
||||||
|
|
||||||
JPanel controlServers = new JPanel();
|
|
||||||
tabbedPane.addTab("Control servers", null, controlServers, null);
|
|
||||||
|
|
||||||
serverControlTab = new ServerControlTab(frame, controlServers);
|
|
||||||
|
|
||||||
|
|
||||||
JPanel panel_2 = new JPanel();
|
|
||||||
tabbedPane.addTab("Servers", null, panel_2, null);
|
|
||||||
SpringLayout sl_panel_2 = new SpringLayout();
|
|
||||||
panel_2.setLayout(sl_panel_2);
|
|
||||||
|
|
||||||
JTabbedPane tabbedPane_1 = new JTabbedPane(JTabbedPane.TOP);
|
|
||||||
sl_panel_2.putConstraint(SpringLayout.NORTH, tabbedPane_1, 0, SpringLayout.NORTH, panel_2);
|
|
||||||
sl_panel_2.putConstraint(SpringLayout.WEST, tabbedPane_1, 0, SpringLayout.WEST, panel_2);
|
|
||||||
sl_panel_2.putConstraint(SpringLayout.SOUTH, tabbedPane_1, 0, SpringLayout.SOUTH, panel_2);
|
|
||||||
sl_panel_2.putConstraint(SpringLayout.EAST, tabbedPane_1, 0, SpringLayout.EAST, panel_2);
|
|
||||||
panel_2.add(tabbedPane_1);
|
|
||||||
|
|
||||||
this.serversPane = tabbedPane_1;
|
|
||||||
tabbedPane_1.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
|
|
||||||
|
|
||||||
frame.validate();
|
frame.validate();
|
||||||
frame.pack();
|
frame.pack();
|
||||||
@ -296,25 +297,10 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
|
|||||||
applicationTray.hideToTray();
|
applicationTray.hideToTray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the currently selected profile
|
|
||||||
*
|
|
||||||
* @return <p>The currently selected profile or null</p>
|
|
||||||
*/
|
|
||||||
public String getSelectedProfile() {
|
|
||||||
Object selectedProfile = profiles.getSelectedItem();
|
|
||||||
if (selectedProfile != null) {
|
|
||||||
return selectedProfile.toString();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
Object actionSource = e.getSource();
|
Object actionSource = e.getSource();
|
||||||
//Registers actions on the main tab
|
//Register actions on the main tab
|
||||||
handleMainTabButtons(actionSource);
|
handleMainTabButtons(actionSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,33 +311,8 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
|
|||||||
* @param actionSource <p>The object being interacted with</p>
|
* @param actionSource <p>The object being interacted with</p>
|
||||||
*/
|
*/
|
||||||
private void handleMainTabButtons(Object actionSource) {
|
private void handleMainTabButtons(Object actionSource) {
|
||||||
if (actionSource == startServerButton) {
|
if (actionSource == addServerTabButton || actionSource == addServerPaneButton) {
|
||||||
controller.saveState();
|
|
||||||
Executors.newSingleThreadExecutor().execute(ServerHandler::startServers);
|
|
||||||
} else if (actionSource == stopServerButton) {
|
|
||||||
stopServers();
|
|
||||||
} else if (actionSource == addServerButton) {
|
|
||||||
addServer();
|
addServer();
|
||||||
} else if (actionSource == backupButton) {
|
|
||||||
CommonFunctions.backup(this);
|
|
||||||
} else if (actionSource == addProfileButton) {
|
|
||||||
controller.addProfile(JOptionPane.showInputDialog("Profile name: "));
|
|
||||||
updateProfiles();
|
|
||||||
} else if (actionSource == deleteProfileButton) {
|
|
||||||
deleteProfile();
|
|
||||||
} else if (actionSource == profiles) {
|
|
||||||
changeProfile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the selected profile
|
|
||||||
*/
|
|
||||||
private void deleteProfile() {
|
|
||||||
Object selected = profiles.getSelectedItem();
|
|
||||||
if (selected != null) {
|
|
||||||
controller.removeProfile(selected.toString());
|
|
||||||
updateProfiles();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,42 +337,9 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
|
|||||||
*/
|
*/
|
||||||
public void updateGUIElementsWhenServersStartOrStop(boolean running) {
|
public void updateGUIElementsWhenServersStartOrStop(boolean running) {
|
||||||
boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running.
|
boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running.
|
||||||
profiles.setEnabled(stopped);
|
mainTabbedPane.setEnabledAt(1, !stopped);
|
||||||
addProfileButton.setEnabled(stopped);
|
mainTabbedPane.setEnabledAt(2, stopped);
|
||||||
deleteProfileButton.setEnabled(stopped);
|
controlPanelTab.updateGUIElementsWhenServersStartOrStop(running);
|
||||||
startServerButton.setEnabled(stopped);
|
|
||||||
addServerButton.setEnabled(stopped);
|
|
||||||
tabbedPane.setEnabledAt(2, stopped);
|
|
||||||
stopServerButton.setEnabled(running);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the previous profile and loads data from the new profile
|
|
||||||
*/
|
|
||||||
private void changeProfile() {
|
|
||||||
controller.saveState();
|
|
||||||
Object current = this.profiles.getSelectedItem();
|
|
||||||
if (current != null) {
|
|
||||||
controller.setCurrentProfile(current.toString());
|
|
||||||
}
|
|
||||||
this.updateWithSavedProfileData();
|
|
||||||
controller.getCurrentProfile().updateConsoles();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops all servers
|
|
||||||
*/
|
|
||||||
public void stopServers() {
|
|
||||||
try {
|
|
||||||
setStatus("Servers are stopping...");
|
|
||||||
ServerHandler.stop();
|
|
||||||
} catch (IOException e1) {
|
|
||||||
showError("Could not stop server.");
|
|
||||||
e1.printStackTrace();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
showError("Could not kill server.");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,7 +164,7 @@ public class ServerLauncherMenu implements ActionListener {
|
|||||||
* Creates a checkbox menu item
|
* Creates a checkbox menu item
|
||||||
*
|
*
|
||||||
* @param itemName <p>The name of the new checkbox item</p>
|
* @param itemName <p>The name of the new checkbox item</p>
|
||||||
* @param parent <p>The parent menu the item belongs to</p>
|
* @param parent <p>The parent menu the item belongs to</p>
|
||||||
* @return <p>The created checkbox menu item</p>
|
* @return <p>The created checkbox menu item</p>
|
||||||
*/
|
*/
|
||||||
private JCheckBoxMenuItem createCheckBoxMenuItem(String itemName, JMenu parent) {
|
private JCheckBoxMenuItem createCheckBoxMenuItem(String itemName, JMenu parent) {
|
||||||
@ -178,7 +178,7 @@ public class ServerLauncherMenu implements ActionListener {
|
|||||||
* Creates a menu item
|
* Creates a menu item
|
||||||
*
|
*
|
||||||
* @param itemName <p>The name of the new item</p>
|
* @param itemName <p>The name of the new item</p>
|
||||||
* @param parent <p>The parent menu the item belongs to</p>
|
* @param parent <p>The parent menu the item belongs to</p>
|
||||||
* @return <p>The created menu item</p>
|
* @return <p>The created menu item</p>
|
||||||
*/
|
*/
|
||||||
private JMenuItem createMenuItem(String itemName, JMenu parent) {
|
private JMenuItem createMenuItem(String itemName, JMenu parent) {
|
||||||
@ -190,6 +190,7 @@ public class ServerLauncherMenu implements ActionListener {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Asks the user for the new Java path
|
* Asks the user for the new Java path
|
||||||
|
*
|
||||||
* @param old <p>Whether asking for the path to the old java version</p>
|
* @param old <p>Whether asking for the path to the old java version</p>
|
||||||
*/
|
*/
|
||||||
private void configureJava(boolean old) {
|
private void configureJava(boolean old) {
|
||||||
@ -237,7 +238,7 @@ public class ServerLauncherMenu implements ActionListener {
|
|||||||
* 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
|
||||||
*/
|
*/
|
||||||
private void delay() {
|
private void delay() {
|
||||||
String selectedProfile = serverLauncherGUI.getSelectedProfile();
|
String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
|
||||||
if (selectedProfile != null) {
|
if (selectedProfile != null) {
|
||||||
Profile profile = controller.getProfileByName(selectedProfile);
|
Profile profile = controller.getProfileByName(selectedProfile);
|
||||||
if (delayStartupCheckBoxMenuItem.isSelected()) {
|
if (delayStartupCheckBoxMenuItem.isSelected()) {
|
||||||
@ -260,7 +261,7 @@ public class ServerLauncherMenu implements ActionListener {
|
|||||||
* Saves the runInBackground setting to the current profile
|
* Saves the runInBackground setting to the current profile
|
||||||
*/
|
*/
|
||||||
private void background() {
|
private void background() {
|
||||||
String selectedProfile = serverLauncherGUI.getSelectedProfile();
|
String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
|
||||||
if (selectedProfile != null) {
|
if (selectedProfile != null) {
|
||||||
Profile profile = controller.getProfileByName(selectedProfile);
|
Profile profile = controller.getProfileByName(selectedProfile);
|
||||||
Objects.requireNonNull(profile).setRunInBackground(runInBackgroundCheckBoxMenuItem.isSelected());
|
Objects.requireNonNull(profile).setRunInBackground(runInBackgroundCheckBoxMenuItem.isSelected());
|
||||||
@ -273,7 +274,7 @@ public class ServerLauncherMenu implements ActionListener {
|
|||||||
* Saves the downloadJars setting to the current profile
|
* Saves the downloadJars setting to the current profile
|
||||||
*/
|
*/
|
||||||
private void downloadJars() {
|
private void downloadJars() {
|
||||||
String selectedProfile = serverLauncherGUI.getSelectedProfile();
|
String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
|
||||||
if (selectedProfile != null) {
|
if (selectedProfile != null) {
|
||||||
controller.setDownloadAllJars(downloadJarsCheckBoxMenuItem.isSelected());
|
controller.setDownloadAllJars(downloadJarsCheckBoxMenuItem.isSelected());
|
||||||
} else {
|
} else {
|
||||||
|
@ -23,11 +23,9 @@ public class ServerTab implements ActionListener {
|
|||||||
private final JComboBox<String> serverVersions;
|
private final JComboBox<String> serverVersions;
|
||||||
private final JComboBox<String> maxRam;
|
private final JComboBox<String> maxRam;
|
||||||
private final JCheckBox enabledCheckbox;
|
private final JCheckBox enabledCheckbox;
|
||||||
private final JButton removeServerButton;
|
|
||||||
private final JButton browseButton;
|
private final JButton browseButton;
|
||||||
private final JTextField directory;
|
private final JTextField directory;
|
||||||
private final JPanel panel;
|
private final JPanel panel;
|
||||||
private final String name;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes a new server tab with the given name
|
* Initializes a new server tab with the given name
|
||||||
@ -36,7 +34,6 @@ public class ServerTab implements ActionListener {
|
|||||||
* @throws ConfigurationException <p>If unable to create the new tab</p>
|
* @throws ConfigurationException <p>If unable to create the new tab</p>
|
||||||
*/
|
*/
|
||||||
public ServerTab(String name) throws ConfigurationException {
|
public ServerTab(String name) throws ConfigurationException {
|
||||||
this.name = name;
|
|
||||||
panel = new JPanel();
|
panel = new JPanel();
|
||||||
Main.getController().getGUI().getPane().addTab(name, null, panel, null);
|
Main.getController().getGUI().getPane().addTab(name, null, panel, null);
|
||||||
SpringLayout sl_panel_3 = new SpringLayout();
|
SpringLayout sl_panel_3 = new SpringLayout();
|
||||||
@ -88,14 +85,6 @@ public class ServerTab implements ActionListener {
|
|||||||
panel.add(enabledCheckbox);
|
panel.add(enabledCheckbox);
|
||||||
enabledCheckbox.addActionListener(this);
|
enabledCheckbox.addActionListener(this);
|
||||||
|
|
||||||
removeServerButton = new JButton("Remove server");
|
|
||||||
sl_panel_3.putConstraint(SpringLayout.NORTH, removeServerButton, 0, SpringLayout.NORTH, serverVersions);
|
|
||||||
sl_panel_3.putConstraint(SpringLayout.SOUTH, removeServerButton, 0, SpringLayout.SOUTH, serverVersions);
|
|
||||||
sl_panel_3.putConstraint(SpringLayout.WEST, removeServerButton, 6, SpringLayout.EAST, serverVersions);
|
|
||||||
sl_panel_3.putConstraint(SpringLayout.EAST, removeServerButton, -10, SpringLayout.EAST, panel);
|
|
||||||
panel.add(removeServerButton);
|
|
||||||
removeServerButton.addActionListener(this);
|
|
||||||
|
|
||||||
JLabel lblDirectory = new JLabel("Directory");
|
JLabel lblDirectory = new JLabel("Directory");
|
||||||
sl_panel_3.putConstraint(SpringLayout.WEST, lblDirectory, 6, SpringLayout.EAST, enabledCheckbox);
|
sl_panel_3.putConstraint(SpringLayout.WEST, lblDirectory, 6, SpringLayout.EAST, enabledCheckbox);
|
||||||
panel.add(lblDirectory);
|
panel.add(lblDirectory);
|
||||||
@ -112,7 +101,7 @@ public class ServerTab implements ActionListener {
|
|||||||
|
|
||||||
browseButton = new JButton("Browse");
|
browseButton = new JButton("Browse");
|
||||||
sl_panel_3.putConstraint(SpringLayout.EAST, directory, -6, SpringLayout.WEST, browseButton);
|
sl_panel_3.putConstraint(SpringLayout.EAST, directory, -6, SpringLayout.WEST, browseButton);
|
||||||
sl_panel_3.putConstraint(SpringLayout.NORTH, browseButton, 3, SpringLayout.SOUTH, removeServerButton);
|
sl_panel_3.putConstraint(SpringLayout.NORTH, browseButton, 3, SpringLayout.SOUTH, serverVersions);
|
||||||
sl_panel_3.putConstraint(SpringLayout.EAST, browseButton, -10, SpringLayout.EAST, panel);
|
sl_panel_3.putConstraint(SpringLayout.EAST, browseButton, -10, SpringLayout.EAST, panel);
|
||||||
sl_panel_3.putConstraint(SpringLayout.SOUTH, directory, 0, SpringLayout.SOUTH, browseButton);
|
sl_panel_3.putConstraint(SpringLayout.SOUTH, directory, 0, SpringLayout.SOUTH, browseButton);
|
||||||
sl_panel_3.putConstraint(SpringLayout.NORTH, directory, 0, SpringLayout.NORTH, browseButton);
|
sl_panel_3.putConstraint(SpringLayout.NORTH, directory, 0, SpringLayout.NORTH, browseButton);
|
||||||
@ -209,9 +198,7 @@ public class ServerTab implements ActionListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
if (e.getSource() == removeServerButton) {
|
if (e.getSource() == browseButton) {
|
||||||
remove();
|
|
||||||
} else if (e.getSource() == browseButton) {
|
|
||||||
browse();
|
browse();
|
||||||
} else if (e.getSource() == serverTypes) {
|
} else if (e.getSource() == serverTypes) {
|
||||||
try {
|
try {
|
||||||
@ -222,15 +209,6 @@ public class ServerTab implements ActionListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the collection containing this ServerTab, and updates everything necessary
|
|
||||||
*/
|
|
||||||
private void remove() {
|
|
||||||
Main.getController().getCurrentProfile().removeCollection(this.name);
|
|
||||||
Main.getController().getGUI().updateWithSavedProfileData();
|
|
||||||
Main.getController().getCurrentProfile().updateConsoles();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asks the user for server location and updates the GUI if given a valid value
|
* Asks the user for server location and updates the GUI if given a valid value
|
||||||
*/
|
*/
|
||||||
|
@ -59,7 +59,7 @@ public class Tray {
|
|||||||
trayIcon = new TrayIcon(trayImage, "Minecraft Server Launcher", popup);
|
trayIcon = new TrayIcon(trayImage, "Minecraft Server Launcher", popup);
|
||||||
trayIcon.setImageAutoSize(true);
|
trayIcon.setImageAutoSize(true);
|
||||||
ActionListener exitListener = e -> {
|
ActionListener exitListener = e -> {
|
||||||
serverLauncherGUI.stopServers();
|
serverLauncherGUI.getControlPanelTab().stopServers();
|
||||||
controller.saveState();
|
controller.saveState();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
};
|
};
|
||||||
@ -92,7 +92,7 @@ public class Tray {
|
|||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
serverLauncherGUI.stopServers();
|
serverLauncherGUI.getControlPanelTab().stopServers();
|
||||||
controller.saveState();
|
controller.saveState();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ public class Tray {
|
|||||||
@Override
|
@Override
|
||||||
public void windowClosing(WindowEvent e) {
|
public void windowClosing(WindowEvent e) {
|
||||||
controller.saveState();
|
controller.saveState();
|
||||||
serverLauncherGUI.stopServers();
|
serverLauncherGUI.getControlPanelTab().stopServers();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,269 @@
|
|||||||
|
package net.knarcraft.minecraftserverlauncher.utility;
|
||||||
|
|
||||||
|
import net.knarcraft.minecraftserverlauncher.Main;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.profile.Collection;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.server.Server;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.userinterface.BackupGUI;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper class for performing server backup
|
||||||
|
*/
|
||||||
|
public final class BackupUtil {
|
||||||
|
|
||||||
|
private static boolean backupAborted;
|
||||||
|
private static boolean backupRunning = false;
|
||||||
|
|
||||||
|
private BackupUtil() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aborts the currently running backup
|
||||||
|
*/
|
||||||
|
public static void abortBackup() {
|
||||||
|
backupAborted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively copies a folder to another location
|
||||||
|
*
|
||||||
|
* @param source <p>The folder to copy</p>
|
||||||
|
* @param destination <p>Target destination</p>
|
||||||
|
* @param backupFileSize <p>The total file size of the backup in progress</p>
|
||||||
|
* @param alreadyCopied <p>The amount of bytes already copied</p>
|
||||||
|
* @throws IOException <p>If we can't start a file stream</p>
|
||||||
|
*/
|
||||||
|
private static long backupFolder(File source, File destination, long backupFileSize,
|
||||||
|
long alreadyCopied) throws IOException {
|
||||||
|
if (backupAborted) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
if (!source.isDirectory()) {
|
||||||
|
long copiedFileSize = copyFile(source, destination);
|
||||||
|
BackupGUI.updateProgress("Copying " + source + "\n to " + destination,
|
||||||
|
(int) ((alreadyCopied + copiedFileSize) * 100 / backupFileSize));
|
||||||
|
return copiedFileSize;
|
||||||
|
} else {
|
||||||
|
if (!destination.exists() && !destination.mkdir()) {
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
String[] files = source.list();
|
||||||
|
long copiedFilesSize = 0;
|
||||||
|
if (files != null) {
|
||||||
|
for (String file : files) {
|
||||||
|
File srcFile = new File(source, file);
|
||||||
|
File destinationFile = new File(destination, file);
|
||||||
|
copiedFilesSize += backupFolder(srcFile, destinationFile, backupFileSize,
|
||||||
|
alreadyCopied + copiedFilesSize);
|
||||||
|
BackupGUI.updateProgress("Copying " + source + "\n to " + destination,
|
||||||
|
(int) ((alreadyCopied + copiedFilesSize) * 100 / backupFileSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return copiedFilesSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies a file from one location to another
|
||||||
|
*
|
||||||
|
* @param source <p>The file to copy</p>
|
||||||
|
* @param destination <p>The location of the copied file</p>
|
||||||
|
* @throws IOException <p>If reading or writing fails</p>
|
||||||
|
*/
|
||||||
|
private static long copyFile(File source, File destination) throws IOException {
|
||||||
|
InputStream in = new FileInputStream(source);
|
||||||
|
OutputStream out = new FileOutputStream(destination);
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int length;
|
||||||
|
while ((length = in.read(buffer)) > 0) {
|
||||||
|
out.write(buffer, 0, length);
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
out.close();
|
||||||
|
return Files.size(source.toPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all server directories to a folder specified by the user
|
||||||
|
*
|
||||||
|
* @param gui <p>The GUI to use for informing the user</p>
|
||||||
|
*/
|
||||||
|
public static void backup(GUI gui) {
|
||||||
|
backupAborted = false;
|
||||||
|
if (backupRunning) {
|
||||||
|
gui.setStatus("A backup is already running");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
backupRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the folder to save the backed up files in
|
||||||
|
File path = gui.askForDirectory("Backup folder");
|
||||||
|
if (path == null || !path.isDirectory()) {
|
||||||
|
backupRunning = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui.setStatus("Backup running...");
|
||||||
|
List<List<File>> serverFolders = getFoldersOfEnabledServers(path);
|
||||||
|
|
||||||
|
gui.setStatus("Calculating backup size...");
|
||||||
|
long backupFileSize = getFolderSize(gui, serverFolders);
|
||||||
|
|
||||||
|
long locationFreeSpace = path.getFreeSpace();
|
||||||
|
if (locationFreeSpace < (backupFileSize + 2048000000)) {
|
||||||
|
gui.setStatus("Not enough available space. " + (backupFileSize / 1000000) + "MB necessary, but only " +
|
||||||
|
(locationFreeSpace / 1000000) + "MB available");
|
||||||
|
backupRunning = false;
|
||||||
|
backupAborted = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gui.setStatus("Backing up " + (backupFileSize / 1000000) + "MB");
|
||||||
|
|
||||||
|
performBackup(gui, serverFolders, backupFileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the actual backup after checks have passed and necessary info is available
|
||||||
|
*
|
||||||
|
* @param gui <p>The GUI to use for informing the user</p>
|
||||||
|
* @param serverFolders <p>The folders of the servers to backup</p>
|
||||||
|
* @param backupFileSize <p>The total size of the folders to backup</p>
|
||||||
|
*/
|
||||||
|
private static void performBackup(GUI gui, List<List<File>> serverFolders, long backupFileSize) {
|
||||||
|
new BackupGUI();
|
||||||
|
BackupGUI.updateProgress("Backup starting...", 0);
|
||||||
|
long alreadyCopied = 0;
|
||||||
|
for (List<File> serverFolder : serverFolders) {
|
||||||
|
if (backupAborted || !backupRunning) {
|
||||||
|
gui.setStatus("Backup aborted");
|
||||||
|
backupRunning = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
alreadyCopied = backupServerFiles(gui, serverFolder, backupFileSize, alreadyCopied);
|
||||||
|
}
|
||||||
|
backupRunning = false;
|
||||||
|
if (backupAborted) {
|
||||||
|
gui.setStatus("Backup aborted");
|
||||||
|
} else {
|
||||||
|
BackupGUI.destroy();
|
||||||
|
gui.setStatus("Backup finished");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backs up the files for a single server
|
||||||
|
*
|
||||||
|
* @param gui <p>The GUI to use for informing the user</p>
|
||||||
|
* @param serverFolder <p>The server's input and output folders</p>
|
||||||
|
* @param backupFileSize <p>The total size of the files to backup</p>
|
||||||
|
* @param alreadyCopied <p>The amount of bytes already copied</p>
|
||||||
|
* @return <p>The new amount of bytes copied</p>
|
||||||
|
*/
|
||||||
|
private static long backupServerFiles(GUI gui, List<File> serverFolder, long backupFileSize, long alreadyCopied) {
|
||||||
|
File srcFolder = serverFolder.get(0);
|
||||||
|
File destinationFolder = serverFolder.get(1);
|
||||||
|
|
||||||
|
//Create child folders
|
||||||
|
if (!destinationFolder.exists() && !destinationFolder.mkdirs()) {
|
||||||
|
backupRunning = false;
|
||||||
|
gui.logError("Unable to create necessary sub-folder in the backup folder");
|
||||||
|
throw new IllegalArgumentException("Unable to create necessary sub-folder in the backup folder");
|
||||||
|
}
|
||||||
|
//Backup
|
||||||
|
try {
|
||||||
|
alreadyCopied += backupFolder(srcFolder, destinationFolder, backupFileSize, alreadyCopied);
|
||||||
|
} catch (IOException e) {
|
||||||
|
gui.showError("Backup caused an error: " + e.getMessage());
|
||||||
|
gui.logError(Arrays.toString(e.getStackTrace()));
|
||||||
|
BackupGUI.destroy();
|
||||||
|
backupRunning = false;
|
||||||
|
}
|
||||||
|
return alreadyCopied;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the size of a list of folders
|
||||||
|
*
|
||||||
|
* @param gui <p>The GUI to write any errors to</p>
|
||||||
|
* @param serverFolders <p>The folder to find the size of</p>
|
||||||
|
* @return <p>The size of the given folders</p>
|
||||||
|
*/
|
||||||
|
private static long getFolderSize(GUI gui, List<List<File>> serverFolders) {
|
||||||
|
long folderSize = 0;
|
||||||
|
for (List<File> serverFolder : serverFolders) {
|
||||||
|
File srcFolder = serverFolder.get(0);
|
||||||
|
try (Stream<Path> walk = Files.walk(srcFolder.toPath())) {
|
||||||
|
folderSize += walk.filter(Files::isRegularFile).mapToLong(BackupUtil::getFileSize).sum();
|
||||||
|
} catch (IOException e) {
|
||||||
|
gui.setStatus(String.format("IO errors %s", e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return folderSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the input and output folders for enabled servers
|
||||||
|
*
|
||||||
|
* <p>The input folders are the folders to copy, while the output folders are the folders to write the backup to.
|
||||||
|
* Each list element contains a list of exactly two File items. The first one is the input folder, and the second
|
||||||
|
* one is the output folder</p>
|
||||||
|
*
|
||||||
|
* @param path <p>The path of the backup folder, as given by the user</p>
|
||||||
|
* @return <p>The folders to copy from/to</p>
|
||||||
|
*/
|
||||||
|
private static List<List<File>> getFoldersOfEnabledServers(File path) {
|
||||||
|
List<List<File>> serverFolders = new ArrayList<>();
|
||||||
|
|
||||||
|
//Get folders of servers to back up
|
||||||
|
List<Collection> collections = Main.getController().getCurrentProfile().getCollections();
|
||||||
|
for (Collection collection : collections) {
|
||||||
|
//Ignore disabled and invalid servers
|
||||||
|
if (collection.getServer().getPath().equals("") || !collection.getServer().isEnabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//Decide sub-folders
|
||||||
|
Server targetServer = collection.getServer();
|
||||||
|
String name = targetServer.getName();
|
||||||
|
File srcFolder = new File(targetServer.getPath());
|
||||||
|
File destinationFolder = new File(path, name);
|
||||||
|
|
||||||
|
List<File> serverFolder = new ArrayList<>();
|
||||||
|
serverFolder.add(srcFolder);
|
||||||
|
serverFolder.add(destinationFolder);
|
||||||
|
serverFolders.add(serverFolder);
|
||||||
|
}
|
||||||
|
return serverFolders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the size of a file given its path
|
||||||
|
*
|
||||||
|
* @param path <p>The path to a file</p>
|
||||||
|
* @return <p>The size of the file in bytes, or 0 if an exception is thrown</p>
|
||||||
|
*/
|
||||||
|
private static long getFileSize(Path path) {
|
||||||
|
try {
|
||||||
|
return Files.size(path);
|
||||||
|
} catch (IOException exception) {
|
||||||
|
System.out.printf("Failed to get size of %s%n%s", path, exception);
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,9 +1,6 @@
|
|||||||
package net.knarcraft.minecraftserverlauncher.utility;
|
package net.knarcraft.minecraftserverlauncher.utility;
|
||||||
|
|
||||||
import net.knarcraft.minecraftserverlauncher.Main;
|
import net.knarcraft.minecraftserverlauncher.Main;
|
||||||
import net.knarcraft.minecraftserverlauncher.profile.Collection;
|
|
||||||
import net.knarcraft.minecraftserverlauncher.server.Server;
|
|
||||||
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
|
|
||||||
import net.knarcraft.minecraftserverlauncher.userinterface.WebBrowser;
|
import net.knarcraft.minecraftserverlauncher.userinterface.WebBrowser;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@ -16,7 +13,6 @@ import java.io.FileWriter;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
@ -53,7 +49,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>
|
||||||
*/
|
*/
|
||||||
protected static void createFolder(File folder) throws FileNotFoundException {
|
public 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.");
|
||||||
@ -130,6 +126,7 @@ public final class CommonFunctions {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a buffered writer for writing to a given file
|
* Gets a buffered writer for writing to a given file
|
||||||
|
*
|
||||||
* @param path <p>The path to the file to write to</p>
|
* @param path <p>The path to the file to write to</p>
|
||||||
* @return <p>A buffered writer for writing to the file</p>
|
* @return <p>A buffered writer for writing to the file</p>
|
||||||
* @throws FileNotFoundException <p>If the file does not exist</p>
|
* @throws FileNotFoundException <p>If the file does not exist</p>
|
||||||
@ -153,8 +150,8 @@ public final class CommonFunctions {
|
|||||||
/**
|
/**
|
||||||
* Writes text to a file and adds a trailing newline
|
* Writes text to a file and adds a trailing newline
|
||||||
*
|
*
|
||||||
* @param path <p>The path of the file to write to</p>
|
* @param path <p>The path of the file to write to</p>
|
||||||
* @param text <p>The text to write</p>
|
* @param text <p>The text to write</p>
|
||||||
* @throws IOException <p>If unable to write to the file</p>
|
* @throws IOException <p>If unable to write to the file</p>
|
||||||
*/
|
*/
|
||||||
public static void writeFile(String path, String text) throws IOException {
|
public static void writeFile(String path, String text) throws IOException {
|
||||||
@ -210,55 +207,6 @@ public final class CommonFunctions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursively copies a folder to another location
|
|
||||||
*
|
|
||||||
* @param source <p>The folder to copy</p>
|
|
||||||
* @param destination <p>Target destination</p>
|
|
||||||
* @throws IOException <p>If we can't start a file stream</p>
|
|
||||||
*/
|
|
||||||
private static void copyFolder(GUI serverLauncherGui, File source, File destination) throws IOException {
|
|
||||||
if (!source.isDirectory()) {
|
|
||||||
copyFile(serverLauncherGui, source, destination);
|
|
||||||
} else {
|
|
||||||
serverLauncherGui.setStatus("Copying directory " + source);
|
|
||||||
if (!destination.exists() && !destination.mkdir()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
String[] files = source.list();
|
|
||||||
if (files != null) {
|
|
||||||
for (String file : files) {
|
|
||||||
File srcFile = new File(source, file);
|
|
||||||
File destinationFile = new File(destination, file);
|
|
||||||
copyFolder(serverLauncherGui, srcFile, destinationFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
serverLauncherGui.setStatus("Copied directory " + source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies a file from one location to another
|
|
||||||
*
|
|
||||||
* @param serverLauncherGui <p>The serverLauncherGui to use for alerting the user</p>
|
|
||||||
* @param source <p>The file to copy</p>
|
|
||||||
* @param destination <p>The location of the copied file</p>
|
|
||||||
* @throws IOException <p>If reading or writing fails</p>
|
|
||||||
*/
|
|
||||||
private static void copyFile(GUI serverLauncherGui, File source, File destination) throws IOException {
|
|
||||||
serverLauncherGui.setStatus("Copying file " + source + "...");
|
|
||||||
InputStream in = new FileInputStream(source);
|
|
||||||
OutputStream out = new FileOutputStream(destination);
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int length;
|
|
||||||
while ((length = in.read(buffer)) > 0) {
|
|
||||||
out.write(buffer, 0, length);
|
|
||||||
}
|
|
||||||
in.close();
|
|
||||||
out.close();
|
|
||||||
serverLauncherGui.setStatus("Copied file " + source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens an url in the user's default application.
|
* Opens an url in the user's default application.
|
||||||
*
|
*
|
||||||
@ -295,34 +243,6 @@ public final class CommonFunctions {
|
|||||||
return text.toString().trim();
|
return text.toString().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies all server directories to a folder specified by the user.
|
|
||||||
*/
|
|
||||||
public static void backup(GUI gui) {
|
|
||||||
File path = gui.askForDirectory("Backup folder");
|
|
||||||
for (Collection collection : Main.getController().getCurrentProfile().getCollections()) {
|
|
||||||
//Ignore disabled and invalid servers
|
|
||||||
if (collection.getServer().getPath().equals("") || !collection.getServer().isEnabled()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//Decide sub-folders
|
|
||||||
Server targetServer = collection.getServer();
|
|
||||||
String name = targetServer.getName();
|
|
||||||
File srcFolder = new File(targetServer.getPath());
|
|
||||||
File destinationFolder = new File(path, name);
|
|
||||||
//Create child folders
|
|
||||||
if (!destinationFolder.exists() && !destinationFolder.mkdirs()) {
|
|
||||||
throw new IllegalArgumentException("Unable to create necessary sub-folder in the backup folder");
|
|
||||||
}
|
|
||||||
//Backup
|
|
||||||
try {
|
|
||||||
CommonFunctions.copyFolder(gui, srcFolder, destinationFolder);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gui.setStatus("Backup finished");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates that a name is not empty and does not contain invalid characters
|
* Validates that a name is not empty and does not contain invalid characters
|
||||||
@ -339,7 +259,7 @@ public final class CommonFunctions {
|
|||||||
*
|
*
|
||||||
* @param target <p>The folder to delete from</p>
|
* @param target <p>The folder to delete from</p>
|
||||||
*/
|
*/
|
||||||
static void removeFilesRecursively(File target) {
|
public static void removeFilesRecursively(File target) {
|
||||||
File[] oldFiles = target.listFiles();
|
File[] oldFiles = target.listFiles();
|
||||||
if (oldFiles == null) {
|
if (oldFiles == null) {
|
||||||
throw new IllegalArgumentException("Unable to list files in directory");
|
throw new IllegalArgumentException("Unable to list files in directory");
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
beta
|
beta
|
||||||
1.3.4
|
1.4.2
|
|
@ -1,11 +1,11 @@
|
|||||||
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/
|
Vanilla;Latest,Snapshot,1.18,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;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-
|
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.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-
|
Paper;1.18,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://papermc.io/api/v2/projects/paper/versions/;"builds":[;];https://papermc.io/api/v2/projects/paper/versions/
|
||||||
#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;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-
|
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.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/
|
Waterfall;1.18,1.17,1.16,1.15,1.14,1.13,1.12,1.11;https://papermc.io/api/v2/projects/waterfall/versions/;"builds":[;];https://papermc.io/api/v2/projects/waterfall/versions/
|
||||||
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/v2/projects/travertine/versions/;"builds":[;];https://papermc.io/api/v2/projects/travertine/versions/
|
||||||
Custom;
|
Custom;
|
Can't render this file because it contains an unexpected character in line 1 and column 200.
|
@ -1,8 +1,9 @@
|
|||||||
package net.knarcraft.minecraftserverlauncher.utility;
|
package net.knarcraft.minecraftserverlauncher.server;
|
||||||
|
|
||||||
import net.knarcraft.minecraftserverlauncher.Main;
|
import net.knarcraft.minecraftserverlauncher.Main;
|
||||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||||
import net.knarcraft.minecraftserverlauncher.userinterface.FakeGUI;
|
import net.knarcraft.minecraftserverlauncher.userinterface.FakeGUI;
|
||||||
|
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||||
import org.junit.jupiter.api.AfterAll;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
@ -38,7 +38,7 @@ 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;\ndownloadedBuildToolsVersion;null",
|
"travertineVersions;\npaperVersions;\nspongeVanillaVersions;\nspongeForgeVersions;\ndownloadedBuildToolsVersion;null",
|
||||||
serverVersionContainer.toString());
|
serverVersionContainer.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user