Changes a lot of things to make everything cleaner. Closes #3
All checks were successful
KnarCraft/Minecraft-Server-Launcher/pipeline/head This commit looks good

Drops the idea of using serializable
Adds a new controller object which takes care of profiles and saving
Moves profile independent settings to its own file
Makes saving and loading from file a lot cleaner
Fixes the bug preventing lastly used profile from loading
Makes the profile object only do profile things
Moves gui initialization to the controller object
Updates vanilla version from 1.16.1 to 1.16.2
Moves backup to common functions
This commit is contained in:
Kristian Knarvik 2020-08-17 21:41:38 +02:00
parent 2ed6b8bedb
commit a3de8a9f6c
24 changed files with 603 additions and 537 deletions

View File

@ -1,10 +1,10 @@
package net.knarcraft.minecraftserverlauncher; package net.knarcraft.minecraftserverlauncher;
import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.profile.Profile; import net.knarcraft.minecraftserverlauncher.profile.Controller;
import net.knarcraft.minecraftserverlauncher.server.Server; import net.knarcraft.minecraftserverlauncher.server.Server;
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles; import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions; import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import net.knarcraft.minecraftserverlauncher.utility.Updater; import net.knarcraft.minecraftserverlauncher.utility.Updater;
@ -33,7 +33,8 @@ public class Main {
private static boolean serversAreRunning = false; private static boolean serversAreRunning = false;
private static final String updateChannel = "alpha"; private static final String updateChannel = "alpha";
private static final String updateURL = "https://api.knarcraft.net/minecraftserverlauncher"; private static final String updateURL = "https://api.knarcraft.net/minecraftserverlauncher";
private static GUI gui; private static ServerLauncherGUI gui;
private static final Controller controller = Controller.getInstance();
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
Updater.checkForUpdate(updateURL, updateChannel, gui); Updater.checkForUpdate(updateURL, updateChannel, gui);
@ -45,8 +46,8 @@ public class Main {
EventQueue.invokeLater(() -> { EventQueue.invokeLater(() -> {
try { try {
new ServerConsoles(); new ServerConsoles();
Profile.load(); controller.loadState();
gui = Profile.getGUI(); gui = controller.getGUI();
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(Main::updateConsoles, 10, 500, TimeUnit.MILLISECONDS); exec.scheduleAtFixedRate(Main::updateConsoles, 10, 500, TimeUnit.MILLISECONDS);
} catch (Exception e) { } catch (Exception e) {
@ -55,6 +56,15 @@ public class Main {
}); });
} }
/**
* Gets the controller used by the software
*
* @return <p>The controller used by the software</p>
*/
public static Controller getController() {
return controller;
}
/** /**
* Retrieves the directory the .jar file is running from * Retrieves the directory the .jar file is running from
* *
@ -77,7 +87,7 @@ public class Main {
*/ */
private static void updateConsoles() { private static void updateConsoles() {
try { try {
for (Collection collection : Profile.getCurrent().getCollections()) { for (Collection collection : controller.getCurrentProfile().getCollections()) {
Server server = collection.getServer(); Server server = collection.getServer();
if (server.isEnabled() && server.getProcess() != null) { if (server.isEnabled() && server.getProcess() != null) {
try { try {
@ -96,10 +106,10 @@ public class Main {
} }
boolean runningNew = serversRunning(); boolean runningNew = serversRunning();
if (!runningNew && serversAreRunning) { if (!runningNew && serversAreRunning) {
Profile.getGUI().updateRunning(false); gui.updateRunning(false);
Profile.getGUI().setStatus("Servers are stopped"); gui.setStatus("Servers are stopped");
} else if (runningNew && !serversAreRunning) { } else if (runningNew && !serversAreRunning) {
Profile.getGUI().updateRunning(true); gui.updateRunning(true);
} }
serversAreRunning = runningNew; serversAreRunning = runningNew;
} catch (Exception e) { } catch (Exception e) {
@ -114,7 +124,7 @@ public class Main {
*/ */
private static boolean serversRunning() { private static boolean serversRunning() {
int num = 0; int num = 0;
for (Collection collection : Profile.getCurrent().getCollections()) { for (Collection collection : controller.getCurrentProfile().getCollections()) {
if (collection.getServer().isStarted() || if (collection.getServer().isStarted() ||
(collection.getServer().getProcess() != null && collection.getServer().getProcess().isAlive())) { (collection.getServer().getProcess() != null && collection.getServer().getProcess().isAlive())) {
num++; num++;

View File

@ -6,7 +6,6 @@ import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerTab; import net.knarcraft.minecraftserverlauncher.userinterface.ServerTab;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import java.io.Serializable;
/** /**
* Acts as a wrapper for objects necessary for each server. * Acts as a wrapper for objects necessary for each server.
@ -15,9 +14,9 @@ import java.io.Serializable;
* @version 1.0.0 * @version 1.0.0
* @since 1.0.0 * @since 1.0.0
*/ */
public class Collection implements Serializable { public class Collection {
private final Server server; private final Server server;
private final transient ServerTab serverTab; private final ServerTab serverTab;
private final Console serverConsole; private final Console serverConsole;
private final String name; private final String name;
@ -45,25 +44,8 @@ public class Collection implements Serializable {
this.server = server; this.server = server;
this.serverConsole = ServerConsoles.addConsoleTab(serverName); this.serverConsole = ServerConsoles.addConsoleTab(serverName);
this.name = serverName; this.name = serverName;
} this.serverTab.setData(server.getPath(), server.isEnabled(), server.getTypeName(), server.getServerVersion(),
server.getMaxRam());
/**
* Creates a new collection with the given parameters
*
* @param name <p>The name identifying the server, server tab, collection and server console</p>
* @param serverPath <p>The path of the server folder</p>
* @param enabled <p>Whether the server should be run when starting servers</p>
* @param typeName <p>The name of the server type the server uses</p>
* @param serverVersion <p>The version of the running server type.</p>
* @param maxRam <p>The maximum amount of RAM the server is allowed to use.</p>
*/
Collection(String name, String serverPath, boolean enabled, String typeName, String serverVersion, String maxRam)
throws ConfigurationException {
this.serverTab = new ServerTab(name);
this.server = new Server(name, serverPath, enabled, typeName, serverVersion, maxRam);
this.serverConsole = ServerConsoles.addConsoleTab(name);
this.name = name;
this.serverTab.setData(serverPath, enabled, typeName, serverVersion, maxRam);
} }
/** /**

View File

@ -0,0 +1,293 @@
package net.knarcraft.minecraftserverlauncher.profile;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.server.Server;
import net.knarcraft.minecraftserverlauncher.server.ServerTypeHandler;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerTab;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import net.knarcraft.minecraftserverlauncher.utility.JarDownloader;
import javax.naming.ConfigurationException;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.Executors;
/**
* This class controls
*/
public class Controller {
private final String workingDirectory = Main.getApplicationWorkDirectory() + File.separator + "files";
private final String profilesFile = workingDirectory + File.separator + "Profiles.txt";
private final String mainFile = workingDirectory + File.separator + "Config.txt";
private final String jarDirectory = workingDirectory + File.separator + "Jars" + File.separator;
private final List<Profile> profileList;
private ServerLauncherGUI serverLauncherGUI;
private Profile currentProfile;
private boolean downloadAllJars;
private static Controller controller;
private Controller() {
this.profileList = new ArrayList<>();
}
/**
* Gets an instance of the controller
*
* @return <p>An instance of the controller</p>
*/
public static Controller getInstance() {
if (controller == null) {
controller = new Controller();
}
return controller;
}
/**
* Returns the GUI used by the software
*
* @return <p>The GUI used by the software</p>
*/
public ServerLauncherGUI getGUI() {
return this.serverLauncherGUI;
}
/**
* Gets whether to download all jar files
*
* @return <p>Whether to download all .jar files</p>
*/
public boolean getDownloadAllJars() {
return downloadAllJars;
}
/**
* Gets whether to run in background after closing
*
* @return <p>Whether to run in background after closing</p>
*/
public boolean getRunInBackground() {
return currentProfile.getRunInBackground();
}
/**
* Gets whether to delay server startup
*
* @return <p>Whether to delay server startup</p>
*/
public int getDelayStartup() {
return currentProfile.getDelayStartup();
}
@Override
public String toString() {
int guiWidth;
int guiHeight;
if (serverLauncherGUI == null) {
guiWidth = 440;
guiHeight = 170;
} else {
guiWidth = serverLauncherGUI.getSize().width;
guiHeight = serverLauncherGUI.getSize().height;
}
return String.format("%s;%d;%d;%b", currentProfile.getName(), guiWidth, guiHeight, downloadAllJars);
}
/**
* Gets a profile by its name
*
* @param name <p>The name of the profile to get</p>
* @return <p>The profile with the given name or null if not found</p>
*/
public Profile getProfileByName(String name) {
for (Profile profile : profileList) {
if (profile.getName().equals(name)) {
return profile;
}
}
return null;
}
/**
* Gets the names of all available profiles
*
* @return <p>A list of all available profiles</p>
*/
public List<String> getProfileNames() {
List<String> profileNames = new ArrayList<>();
profileList.forEach((profile) -> profileNames.add(profile.getName()));
return profileNames;
}
/**
* Adds a profile if the name is valid and unique.
*
* @param name The name of the new profile.
*/
public void addProfile(String name) {
if (!CommonFunctions.nameIsValid(name)) {
serverLauncherGUI.showError("Profile name cannot be blank and cannot contain special characters.");
return;
}
for (Profile profile : profileList) {
if (profile.getName().equals(name)) {
serverLauncherGUI.showError("There is already a profile with this name.");
return;
}
}
Profile newProfile = new Profile(name);
profileList.add(newProfile);
if (currentProfile == null) {
currentProfile = newProfile;
}
}
/**
* Removes a profile with the given name from the list of profiles, if such a profile exists
*
* @param name <p>The name of the profile to rempve</p>
*/
public void removeProfile(String name) {
if (profileList.size() > 1) {
profileList.removeIf(profile -> profile.getName().equals(name));
} else {
serverLauncherGUI.showError("This software requires the existence of at least one profile.");
}
}
/**
* Gets the currently selected profile
*
* @return <p>The currently selected profile</p>
*/
public Profile getCurrentProfile() {
return this.currentProfile;
}
/**
* Loads data about the controller from a save string
*
* @param data <p>The save string to load</p>
* @return <p>The currently selected profile</p>
* @throws IOException <p>If unable to create the GUI</p>
*/
private String fromString(String data) throws IOException {
String[] dataList = data.split(";");
this.downloadAllJars = Boolean.parseBoolean(dataList[3]);
this.serverLauncherGUI = new ServerLauncherGUI(Integer.parseInt(dataList[1]), Integer.parseInt(dataList[2]));
return dataList[0];
}
/**
* Reads profiles and servers from a text file.
*/
public void loadState() throws ConfigurationException, IOException {
//Loads data regarding this controller
String currentProfile = null;
if (new File(mainFile).exists()) {
String controllerData = CommonFunctions.readBufferedReader(new BufferedReader(new InputStreamReader(new FileInputStream(mainFile))));
currentProfile = this.fromString(controllerData);
} else {
this.serverLauncherGUI = new ServerLauncherGUI();
}
try (Scanner in = new Scanner(new File(profilesFile))) {
while (in.hasNextLine()) {
String profileData = in.nextLine();
Profile loadedProfile = Profile.fromString(profileData);
profileList.add(loadedProfile);
}
} catch (FileNotFoundException e) {
addProfile("Default");
}
this.currentProfile = getProfileByName(currentProfile);
if (this.currentProfile == null) {
this.currentProfile = this.profileList.get(0);
}
this.serverLauncherGUI.updateProfiles();
this.serverLauncherGUI.update();
this.currentProfile.updateConsoles();
if (this.downloadAllJars) {
Executors.newSingleThreadExecutor().execute(() -> {
JarDownloader downloader = new JarDownloader(serverLauncherGUI, jarDirectory);
try {
downloader.downloadJars();
} catch (IOException e) {
e.printStackTrace();
}
});
}
if (this.currentProfile.getRunInBackground()) {
Executors.newSingleThreadExecutor().execute(Server::startServers);
this.serverLauncherGUI.hide();
}
}
/**
* Sets the download all jars option
*
* @param downloadAllJars <p>Whether to download all jars</p>
*/
public void setDownloadAllJars(boolean downloadAllJars) {
this.downloadAllJars = downloadAllJars;
}
/**
* Sets the currently selected profile
*
* @param profileName <p>The name of the currently selected profile</p>
*/
public void setCurrentProfile(String profileName) {
this.currentProfile = getProfileByName(profileName);
}
/**
* Saves the state of the entire application to disk
*/
public void saveState() {
saveGUIStateToServer();
try {
CommonFunctions.createAllFolders();
PrintWriter mFile = new PrintWriter(mainFile);
mFile.println(this.toString());
mFile.close();
PrintWriter pFile = new PrintWriter(profilesFile);
for (Profile profile : profileList) {
pFile.println(profile.toString());
}
pFile.close();
} catch (FileNotFoundException e) {
serverLauncherGUI.showError("Unable to save data.");
e.printStackTrace();
}
}
/**
* Updates the server object with the current state of the GUI server tab
*/
private void saveGUIStateToServer() {
for (Collection collection : this.currentProfile.getCollections()) {
Server server = collection.getServer();
ServerTab serverTab = collection.getServerTab();
server.setPath(serverTab.getPath());
server.setMaxRam(serverTab.getMaxRam());
try {
server.setType(ServerTypeHandler.getByName(serverTab.getType()));
} catch (ConfigurationException e) {
e.printStackTrace();
}
try {
server.setServerVersion(serverTab.getVersion());
} catch (IllegalArgumentException e) {
serverLauncherGUI.showError("Invalid server version for " + server.getName());
}
server.setEnabled(serverTab.enabled());
}
}
}

View File

@ -2,23 +2,14 @@ package net.knarcraft.minecraftserverlauncher.profile;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.server.Server; import net.knarcraft.minecraftserverlauncher.server.Server;
import net.knarcraft.minecraftserverlauncher.server.ServerTypeHandler;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles; import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI; import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerTab; import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
import net.knarcraft.minecraftserverlauncher.utility.JarDownloader;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import javax.swing.*; import javax.swing.*;
import java.io.File; import java.io.*;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.concurrent.Executors;
/** /**
* Contains all user settings, and a list of servers. * Contains all user settings, and a list of servers.
@ -27,110 +18,38 @@ import java.util.concurrent.Executors;
* @version 1.0.0 * @version 1.0.0
* @since 1.0.0 * @since 1.0.0
*/ */
public class Profile implements java.io.Serializable { public class Profile {
private static final ArrayList<Profile> profiles = new ArrayList<>();
private static final String workingDirectory = Main.getApplicationWorkDirectory() + File.separator + "files"; private static final ServerLauncherGUI serverLauncherGui = Main.getController().getGUI();
private static final String profilesDir = workingDirectory;
private static final String profilesFile = workingDirectory + File.separator + "Profiles.txt";
private static final String jarDirectory = workingDirectory + File.separator + "Jars" + File.separator;
private static Profile current;
private static transient ServerLauncherGUI serverLauncherGui;
private final ArrayList<Collection> collections; private final ArrayList<Collection> collections;
private final String name; private final String name;
private boolean runInBackground; private boolean runInBackground;
private int delayStartup; private int delayStartup;
private boolean downloadAllAvailableJARFiles;
private Profile(String name) { /**
* Instantiates a new default profile
*
* @param name <p>The name of the profile</p>
*/
public Profile(String name) {
this.collections = new ArrayList<>(); this.collections = new ArrayList<>();
this.name = name; this.name = name;
this.runInBackground = false; this.runInBackground = false;
this.delayStartup = 0; this.delayStartup = 0;
this.downloadAllAvailableJARFiles = false;
profiles.add(this);
if (current == null) {
current = this;
}
} }
private Profile(String name, boolean runInBackground, int delayStartup, boolean downloadAllAvailableJARFiles) { /**
* Instantiates a new profile
*
* @param name <p>The name of the profile</p>
* @param runInBackground <p>Whether to run the software in the background the next time it starts</p>
* @param delayStartup <p>Whether to delay the startup of servers</p>
*/
private Profile(String name, boolean runInBackground, int delayStartup) {
this.collections = new ArrayList<>(); this.collections = new ArrayList<>();
this.name = name; this.name = name;
this.runInBackground = runInBackground; this.runInBackground = runInBackground;
this.delayStartup = delayStartup; this.delayStartup = delayStartup;
this.downloadAllAvailableJARFiles = downloadAllAvailableJARFiles;
profiles.add(this);
if (current == null) {
current = this;
}
}
public static ServerLauncherGUI getGUI() {
return serverLauncherGui;
}
public static Profile getCurrent() {
return current;
}
/**
* Set the current profile to the profile with a certain name.
*
* @param name The name of the profile
*/
public static void setCurrent(String name) {
for (Profile profile : profiles) {
if (profile.name.equals(name)) {
current = profile;
break;
}
}
}
public static Profile getProfile(String name) {
for (Profile profile : profiles) {
if (profile.name.equals(name)) {
return profile;
}
}
return null;
}
public static ArrayList<Profile> getProfiles() {
return profiles;
}
/**
* Adds a profile if the name is valid and unique.
*
* @param name The name of the new profile.
*/
public static void addProfile(String name) {
if (name == null) { //If a user cancels or crosses out window
return;
}
if (name.equals("") && !name.matches("^[!?;]+$")) {
serverLauncherGui.showError("Profile name can't be blank.");
return;
}
for (Profile profile : profiles) {
if (profile.name.equals(name)) {
serverLauncherGui.showError("There is already a profile with this name.");
return;
}
}
new Profile(name);
}
/**
* Removes a profile with the given name from the list of profiles, if such a profile exists
*
* @param name <p>The name of the profile to rempve</p>
*/
public static void removeProfile(String name) {
if (profiles.size() > 1) {
profiles.removeIf(profile -> profile.name.equals(name));
}
} }
/** /**
@ -140,67 +59,47 @@ public class Profile implements java.io.Serializable {
* @return <p>The new profile</p> * @return <p>The new profile</p>
*/ */
private static Profile parseProfile(String[] profileData) { private static Profile parseProfile(String[] profileData) {
return new Profile( return new Profile(profileData[0], Boolean.parseBoolean(profileData[1]), Integer.parseInt(profileData[2]));
profileData[0],
Boolean.parseBoolean(profileData[1]),
Integer.parseInt(profileData[2]),
Boolean.parseBoolean(profileData[3])
);
} }
/** /**
* Parses a server, and creates a new collection. * Gets whether the software should keep running in the background
* *
* @param profile <p>The profile which to add the collection</p> * @return <p>Whether the software should keep running in the backgound</p>
* @param serverData <p>The data to parse</p>
*/ */
private static void parseServer(Profile profile, String[] serverData) throws ConfigurationException {
profile.collections.add(new Collection(
serverData[0],
serverData[1],
Boolean.parseBoolean(serverData[2]),
serverData[3],
serverData[4],
serverData[5])
);
}
public boolean getRunInBackground() { public boolean getRunInBackground() {
return this.runInBackground; return this.runInBackground;
} }
/**
* Sets whether the software should keep running in the background
*
* @param value <p>Whether the software should keep running in the background</p>
*/
public void setRunInBackground(boolean value) { public void setRunInBackground(boolean value) {
this.runInBackground = value; this.runInBackground = value;
} }
/**
* Gets the number of seconds to delay startup
*
* @return <p>The number of seconds to delay starup</p>
*/
public int getDelayStartup() { public int getDelayStartup() {
return this.delayStartup; return this.delayStartup;
} }
/**
* Sets the amount of time to delay startup
*
* @param value <p>The number of seconds to delay startup</p>
*/
public void setDelayStartup(int value) { public void setDelayStartup(int value) {
if (value >= 0) { if (value >= 0) {
this.delayStartup = value; this.delayStartup = value;
} }
} }
/**
* Gets the state of the download all jar files setting
*
* @return <p>Whether to download all jars</p>
*/
public boolean getDownloadAllAvailableJARFiles() {
return this.downloadAllAvailableJARFiles;
}
/**
* Sets the state of the download all jar files setting
*
* @param value <p>The new value of the download all jar files setting</p>
*/
public void setDownloadAllAvailableJARFiles(boolean value) {
this.downloadAllAvailableJARFiles = value;
}
/** /**
* Gets all collections stored as part of this profile * Gets all collections stored as part of this profile
* *
@ -243,13 +142,7 @@ public class Profile implements java.io.Serializable {
if (name == null) { //If a user cancels or crosses out window if (name == null) { //If a user cancels or crosses out window
return; return;
} }
if (getCollection(name) == null && if (getCollection(name) == null && !name.equals("All") && CommonFunctions.nameIsValid(name)) {
!name.equals("") &&
!name.equals("All") &&
!name.contains("!") &&
!name.contains("?") &&
!name.contains(";")
) {
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 my unique and not empty or \"All\"." +
@ -257,6 +150,11 @@ public class Profile implements java.io.Serializable {
} }
} }
/**
* Removes the collection with the given name
*
* @param name <p>The name of the collection to remove</p>
*/
public void removeCollection(String name) { public void removeCollection(String name) {
for (int i = 0; i < collections.size(); i++) { for (int i = 0; i < collections.size(); i++) {
if (collections.get(i).getName().equals(name)) { if (collections.get(i).getName().equals(name)) {
@ -267,6 +165,9 @@ public class Profile implements java.io.Serializable {
} }
} }
/**
* Updates console tabs with the current servers
*/
public void updateConsoles() { public void updateConsoles() {
JTabbedPane consolesTab = ServerConsoles.getTabbedPane(); JTabbedPane consolesTab = ServerConsoles.getTabbedPane();
consolesTab.removeAll(); consolesTab.removeAll();
@ -278,8 +179,8 @@ public class Profile implements java.io.Serializable {
/** /**
* Sends a command to a server, or all servers * Sends a command to a server, or all servers
* *
* @param serverName The target server * @param serverName <p>The target server</p>
* @param command The command to send. * @param command <p>The command to send</p>
*/ */
public void sendCommand(String serverName, String command) { public void sendCommand(String serverName, String command) {
if (serverName.equals("All")) { if (serverName.equals("All")) {
@ -305,194 +206,45 @@ public class Profile implements java.io.Serializable {
} }
} }
/** @Override
* Reads all server tabs, and saves it to the variables of the corresponding servers. public String toString() {
* Saves all profiles and servers to a text file.
*/
public void save() throws FileNotFoundException {
/*try {
FileOutputStream fileOut =
new FileOutputStream(profilesFile);
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(this);
out.close();
fileOut.close();
} catch (IOException i) {
System.out.println("Unable to serialize or write the profile settings file");
i.printStackTrace();
}*/
for (Collection collection : this.collections) {
Server server = collection.getServer();
ServerTab serverTab = collection.getServerTab();
server.setPath(serverTab.getPath());
server.setMaxRam(serverTab.getMaxRam());
try {
server.setType(ServerTypeHandler.getByName(serverTab.getType()));
} catch (ConfigurationException e) {
e.printStackTrace();
}
try {
server.setServerVersion(serverTab.getVersion());
} catch (IllegalArgumentException e) {
serverLauncherGui.showError("Invalid server version for " + server.getName());
}
server.setEnabled(serverTab.enabled());
}
if (!new File(profilesDir).exists() && !new File(profilesDir).mkdirs()) {
serverLauncherGui.showError("Unable to create the folder " + profilesDir);
throw new FileNotFoundException("Unable to create the profiles folder: " + profilesDir);
}
try (PrintWriter file = new PrintWriter(profilesFile)) {
int width;
int height;
if (serverLauncherGui == null) {
width = 440;
height = 170;
} else {
width = serverLauncherGui.getSize().width;
height = serverLauncherGui.getSize().height;
}
file.println(String.format(
"%s;%s;%s",
current.name,
width,
height
));
file.close();
for (Profile profile : profiles) {
StringBuilder saveString = new StringBuilder(String.format( StringBuilder saveString = new StringBuilder(String.format(
"%s;%b;%d;%b?", "%s;%b;%d?",
profile.name, this.name,
profile.runInBackground, this.runInBackground,
profile.delayStartup, this.delayStartup)
profile.downloadAllAvailableJARFiles)
);
for (Collection collection : profile.collections) {
Server server = collection.getServer();
saveString.append(String.format(
"%s;%s;%b;%s;%s;%s!",
server.getName(),
server.getPath(),
server.isEnabled(),
server.getTypeName(),
server.getServerVersion(),
server.getMaxRam()
)
); );
for (Collection collection : this.collections) {
saveString.append(collection.getServer().toString());
} }
saveString = new StringBuilder(saveString.substring(0, saveString.length() - 1)); saveString = new StringBuilder(saveString.substring(0, saveString.length() - 1));
try (PrintWriter fileAppend = new PrintWriter(new FileWriter( return saveString.toString();
profilesFile,
true
))) {
fileAppend.println(saveString);
} catch (IOException e) {
if (serverLauncherGui != null) {
serverLauncherGui.showError("Unable to save to file. Try running the software as an administrator.");
} else {
System.out.println("Unable to save to file. Try running the software as an administrator.");
}
throw new FileNotFoundException("Unable to save to the profiles file.");
}
}
} catch (IOException e) {
if (serverLauncherGui != null) {
serverLauncherGui.showError("Unable to save to file. Try running the software as an administrator.");
}
throw new FileNotFoundException("Unable to create the profiles file");
}
} }
/** /**
* Reads profiles and servers from a text file. * Gets a profile given a saved string
*
* @param profileString <p>The string containing all profile data</p>
* @return <p>A profile with the given data</p>
* @throws ConfigurationException <p>If unable to load one of the profile's servers</p>
*/ */
public static void load() throws ConfigurationException, IOException { public static Profile fromString(String profileString) throws ConfigurationException {
/*Profile p; Profile profile;
if (!new File(profilesFile).exists()) { if (profileString.contains("?")) {
addProfile("Default"); String[] data = profileString.split("\\?");
return;
}
try {
FileInputStream fileIn = new FileInputStream(profilesFile);
ObjectInputStream in = new ObjectInputStream(fileIn);
p = (Profile) in.readObject();
in.close();
fileIn.close();
profiles.add(p);
} catch (IOException i) {
i.printStackTrace();
} catch (ClassNotFoundException c) {
System.out.println("Profile class not found");
c.printStackTrace();
}*/
try (Scanner in = new Scanner(new File(profilesFile))) {
try {
String[] staticData = in.nextLine().split(";", -1);
String profileName = staticData[0];
int guiWidth = Integer.parseInt(staticData[1]);
int guiHeight = Integer.parseInt(staticData[2]);
serverLauncherGui = new ServerLauncherGUI(guiWidth, guiHeight);
while (in.hasNextLine()) {
String line = in.nextLine();
if (line.contains("?")) {
String[] data = line.split("\\?");
String[] profileData = data[0].split(";", -1); String[] profileData = data[0].split(";", -1);
Profile profile = parseProfile(profileData); profile = parseProfile(profileData);
if (data[1].contains("!")) { if (data[1].contains("!")) {
String[] servers = data[1].split("!", -1); String[] servers = data[1].split("!", -1);
for (String server : servers) { for (String server : servers) {
String[] serverData = server.split(";", -1); profile.collections.add(new Collection(Server.fromString(server)));
parseServer(profile, serverData);
} }
} else { } else {
String[] serverData = data[1].split(";", -1); profile.collections.add(new Collection(Server.fromString(data[1])));
parseServer(profile, serverData);
} }
} else { } else {
String[] profileData = line.split(";", -1); profile = parseProfile(profileString.split(";", -1));
parseProfile(profileData);
}
}
current = getProfile(profileName);
} catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
e.printStackTrace();
serverLauncherGui = new ServerLauncherGUI();
serverLauncherGui.showError("Invalid Profile.txt file. Profiles could not be loaded. If this error persists, please " +
"manually delete the file.");
System.exit(1);
} catch (IOException e) {
e.printStackTrace();
}
if (profiles.size() == 0) {
addProfile("Default");
}
} catch (FileNotFoundException | NoSuchElementException e) {
try {
serverLauncherGui = new ServerLauncherGUI();
serverLauncherGui.showMessage("A profiles file was not found. Default profile was created.");
} catch (IOException ex) {
ex.printStackTrace();
}
addProfile("Default");
}
serverLauncherGui.update();
serverLauncherGui.updateProfiles();
current.updateConsoles();
if (current.downloadAllAvailableJARFiles) {
Executors.newSingleThreadExecutor().execute(() -> {
JarDownloader downloader = new JarDownloader(serverLauncherGui, jarDirectory);
try {
downloader.downloadJars();
} catch (IOException e) {
e.printStackTrace();
}
});
}
if (current.runInBackground) {
Executors.newSingleThreadExecutor().execute(Server::startServers);
serverLauncherGui.hide();
} }
return profile;
} }
} }

View File

@ -2,7 +2,7 @@ package net.knarcraft.minecraftserverlauncher.server;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.profile.Profile; import net.knarcraft.minecraftserverlauncher.profile.Controller;
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType; import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit;
* @version 1.0.0 * @version 1.0.0
* @since 1.0.0 * @since 1.0.0
*/ */
public class Server implements java.io.Serializable { public class Server {
/** /**
* Available ram sizes. For ServerLauncherGUI dropdown * Available ram sizes. For ServerLauncherGUI dropdown
*/ */
@ -108,7 +108,7 @@ public class Server implements java.io.Serializable {
* @throws IOException If a writer's process is already closed but not null. * @throws IOException If a writer's process is already closed but not null.
*/ */
public static void stop() throws IOException { public static void stop() throws IOException {
for (Collection collection : Profile.getCurrent().getCollections()) { for (Collection collection : Main.getController().getCurrentProfile().getCollections()) {
Server server = collection.getServer(); Server server = collection.getServer();
if (server.writer != null) { if (server.writer != null) {
if (server.type.isProxy()) { if (server.type.isProxy()) {
@ -127,16 +127,17 @@ public class Server implements java.io.Serializable {
* Runs all enabled servers with their settings * Runs all enabled servers with their settings
*/ */
public static void startServers() { public static void startServers() {
Profile.getGUI().setStatus("Starting servers"); Controller controller = Main.getController();
for (Collection collection : Profile.getCurrent().getCollections()) { controller.getGUI().setStatus("Starting servers");
for (Collection collection : controller.getCurrentProfile().getCollections()) {
if (!collection.getServer().runServer()) { if (!collection.getServer().runServer()) {
Profile.getGUI().setStatus("An error occurred. Start aborted"); controller.getGUI().setStatus("An error occurred. Start aborted");
try { try {
Server.stop(); Server.stop();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
Profile.getGUI().updateRunning(false); controller.getGUI().updateRunning(false);
return; return;
} }
} }
@ -322,7 +323,7 @@ public class Server implements java.io.Serializable {
*/ */
public void addPlayer(String name) { public void addPlayer(String name) {
this.playerList.add(name); this.playerList.add(name);
Profile.getGUI().addPlayer(name); Main.getController().getGUI().addPlayer(name);
} }
/** /**
@ -332,7 +333,7 @@ public class Server implements java.io.Serializable {
*/ */
public void removePlayer(String name) { public void removePlayer(String name) {
playerList.removeIf(player -> player.equals(name)); playerList.removeIf(player -> player.equals(name));
Profile.getGUI().removePlayer(name); Main.getController().getGUI().removePlayer(name);
} }
/** /**
@ -350,22 +351,24 @@ public class Server implements java.io.Serializable {
* @return <p>True if nothing went wrong</p> * @return <p>True if nothing went wrong</p>
*/ */
private boolean runServer() { private boolean runServer() {
//Ignore a disabled server
if (!this.enabled) { if (!this.enabled) {
this.started = false; this.started = false;
return true; return true;
} }
this.started = true; //Tries to do necessary pre-start work
if (!initializeJarDownload() || !delayStartup()) { if (!initializeJarDownload() || !delayStartup()) {
this.started = false;
return false; return false;
} }
//Starts the server if possible
try { try {
startServerProcess(); startServerProcess();
Profile.getGUI().setStatus("Servers are running"); Main.getController().getGUI().setStatus("Servers are running");
this.started = true; this.started = true;
return true; return true;
} catch (IOException e) { } catch (IOException e) {
Profile.getGUI().setStatus("Could not start server"); Main.getController().getGUI().setStatus("Could not start server");
this.started = false; this.started = false;
return false; return false;
} }
@ -379,16 +382,11 @@ public class Server implements java.io.Serializable {
private void startServerProcess() throws IOException { private void startServerProcess() throws IOException {
ProcessBuilder builder; ProcessBuilder builder;
String serverPath; String serverPath;
String serverFile; //Decide the path of the .jar file to be executed
if (type.getName().equals("Custom")) { if (type.getName().equals("Custom")) {
serverFile = serverVersion; serverPath = this.path + File.separator + serverVersion;
} else { } else {
serverFile = this.type.getName() + serverVersion + ".jar"; serverPath = jarDirectory + this.type.getName() + serverVersion + ".jar";
}
if (!type.getName().equals("Custom")) {
serverPath = jarDirectory + serverFile;
} else {
serverPath = this.path + File.separator + serverFile;
} }
builder = new ProcessBuilder("java", "-Xmx" + this.maxRam, "-Xms512M", builder = new ProcessBuilder("java", "-Xmx" + this.maxRam, "-Xms512M",
"-Djline.terminal=jline.UnsupportedTerminal", "-Dcom.mojang.eula.agree=true", "-jar", serverPath, "-Djline.terminal=jline.UnsupportedTerminal", "-Dcom.mojang.eula.agree=true", "-jar", serverPath,
@ -407,8 +405,8 @@ public class Server implements java.io.Serializable {
*/ */
private boolean delayStartup() { private boolean delayStartup() {
try { try {
Profile.getGUI().setStatus("Delaying startup"); Main.getController().getGUI().setStatus("Delaying startup");
TimeUnit.SECONDS.sleep(Profile.getCurrent().getDelayStartup()); TimeUnit.SECONDS.sleep(Main.getController().getCurrentProfile().getDelayStartup());
return true; return true;
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
@ -423,13 +421,14 @@ public class Server implements java.io.Serializable {
* @return <p>True if nothing went wrong</p> * @return <p>True if nothing went wrong</p>
*/ */
private boolean initializeJarDownload() { private boolean initializeJarDownload() {
if (!Profile.getCurrent().getDownloadAllAvailableJARFiles()) { Controller controller = Main.getController();
if (!controller.getDownloadAllJars()) {
try { try {
Profile.getGUI().setStatus("Downloading jar..."); controller.getGUI().setStatus("Downloading jar...");
this.downloadJar(); this.downloadJar();
Profile.getGUI().setStatus("File downloaded"); controller.getGUI().setStatus("File downloaded");
} catch (IOException e) { } catch (IOException e) {
Profile.getGUI().setStatus("Error: Jar file not found"); controller.getGUI().setStatus("Error: Jar file not found");
e.printStackTrace(); e.printStackTrace();
this.started = false; this.started = false;
return false; return false;

View File

@ -10,10 +10,10 @@ import java.util.Map;
/** /**
* This class acts as a container for all "latest" server versions * This class acts as a container for all "latest" server versions
*/ */
public class ServerVersionContainer implements java.io.Serializable { public class ServerVersionContainer {
private static ServerVersionContainer serverVersionContainer; private static ServerVersionContainer serverVersionContainer;
private String versionFile = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator + "versions.csv"; private final String versionFile = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator + "versions.csv";
private String vanillaVersion; private String vanillaVersion;
private String snapshotVersion; private String snapshotVersion;
private String bungeeVersion; private String bungeeVersion;
@ -273,15 +273,6 @@ public class ServerVersionContainer implements java.io.Serializable {
saveState(); saveState();
} }
/**
* Gets the entire sponge vanilla version map
*
* @return <p>The entire sponge vanilla version map</p>
*/
public Map<String, String> getSpongeVanillaVersions() {
return this.spongeVanillaVersions;
}
/** /**
* Gets a specific sponge vanilla version * Gets a specific sponge vanilla version
* *
@ -292,16 +283,6 @@ public class ServerVersionContainer implements java.io.Serializable {
return spongeVanillaVersions.get(versionKey); return spongeVanillaVersions.get(versionKey);
} }
/**
* Replaces the entire sponge vanilla version map
*
* @param newVersions <p>The new version map to use</p>
*/
public void setSpongeVanillaVersion(Map<String, String> newVersions) {
this.spongeVanillaVersions = newVersions;
saveState();
}
/** /**
* Sets the current version for a given sponge vanilla version * Sets the current version for a given sponge vanilla version
* *

View File

@ -12,9 +12,9 @@ import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stri
public class BungeeCord extends AbstractServerType { public class BungeeCord extends AbstractServerType {
private String versionURL; private final String versionURL;
private String srcStart; private final String srcStart;
private String srcEnd; private final String srcEnd;
/** /**
* Instantiates a new BungeeCord server type * Instantiates a new BungeeCord server type

View File

@ -10,7 +10,7 @@ import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.down
*/ */
public class CraftBukkit extends AbstractServerType { public class CraftBukkit extends AbstractServerType {
private String downloadURLPart; private final String downloadURLPart;
/** /**
* Instantiates a new server type * Instantiates a new server type

View File

@ -1,7 +1,6 @@
package net.knarcraft.minecraftserverlauncher.server.servertypes; package net.knarcraft.minecraftserverlauncher.server.servertypes;
import java.io.File; import java.io.File;
import java.io.IOException;
public class Custom extends AbstractServerType { public class Custom extends AbstractServerType {
/** /**
@ -14,7 +13,7 @@ public class Custom extends AbstractServerType {
} }
@Override @Override
public boolean downloadJar(String folder, String version) throws IOException { public boolean downloadJar(String folder, String version) {
File filePath = new File(folder + version); File filePath = new File(folder + version);
return filePath.isFile(); return filePath.isFile();
} }

View File

@ -11,10 +11,10 @@ import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.down
public class SpongeVanilla extends AbstractServerType { public class SpongeVanilla extends AbstractServerType {
private String versionURL; private final String versionURL;
private String srcStart; private final String srcStart;
private String srcEnd; private final String srcEnd;
private String downloadURLPart; private final String downloadURLPart;
/** /**
* Instantiates a new SpongeVanilla server type * Instantiates a new SpongeVanilla server type

View File

@ -19,7 +19,7 @@ public class Travertine extends Waterfall {
String srcEnd, String downloadURL) { String srcEnd, String downloadURL) {
super(typeName, isProxy, versions, versionURL, srcStart, srcEnd, downloadURL); super(typeName, isProxy, versions, versionURL, srcStart, srcEnd, downloadURL);
this.oldVersion = ServerVersionContainer.getInstance().getTravertineVersion(); this.oldVersion = ServerVersionContainer.getInstance().getTravertineVersion();
this.versionUpdateFunction = (newVersion) -> serverVersionContainer.setTravertineVersion(newVersion); this.versionUpdateFunction = serverVersionContainer::setTravertineVersion;
} }
} }

View File

@ -6,7 +6,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readFile; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readFile;
@ -14,12 +13,12 @@ import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stri
public class Waterfall extends AbstractServerType { public class Waterfall extends AbstractServerType {
private String srcStart; private final String srcStart;
private String srcEnd; private final String srcEnd;
private String versionURL; private final String versionURL;
String oldVersion; String oldVersion;
Consumer<String> versionUpdateFunction; Consumer<String> versionUpdateFunction;
ServerVersionContainer serverVersionContainer; final ServerVersionContainer serverVersionContainer;
/** /**
* Instantiates a new Waterfall server type * Instantiates a new Waterfall server type
@ -40,7 +39,7 @@ public class Waterfall extends AbstractServerType {
this.srcEnd = srcEnd; this.srcEnd = srcEnd;
this.versionURL = versionURL; this.versionURL = versionURL;
this.oldVersion = serverVersionContainer.getWaterfallVersion(); this.oldVersion = serverVersionContainer.getWaterfallVersion();
this.versionUpdateFunction = (newVersion) -> serverVersionContainer.setWaterfallVersion(newVersion); this.versionUpdateFunction = serverVersionContainer::setWaterfallVersion;
} }
@Override @Override

View File

@ -1,6 +1,6 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.profile.Profile; import net.knarcraft.minecraftserverlauncher.Main;
import javax.swing.*; import javax.swing.*;
import javax.swing.text.DefaultCaret; import javax.swing.text.DefaultCaret;
@ -66,7 +66,7 @@ public class Console implements ActionListener, KeyListener {
//Sends the command from the input to the server with the same name. //Sends the command from the input to the server with the same name.
if (e.getSource() == textInput) { if (e.getSource() == textInput) {
java.lang.String text = textInput.getText(); java.lang.String text = textInput.getText();
Profile.getCurrent().sendCommand(this.name, text); Main.getController().getCurrentProfile().sendCommand(this.name, text);
commands.add(text); commands.add(text);
if (commands.size() > 25) { if (commands.size() > 25) {
commands.remove(0); commands.remove(0);

View File

@ -1,5 +1,7 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import java.io.File;
/** /**
* Describes a generic GUI * Describes a generic GUI
*/ */
@ -42,4 +44,12 @@ public interface GUI {
*/ */
void showMessage(String message); void showMessage(String message);
/**
* Asks the user for a directory as a file object
*
* @param prompt <p>The prompt to show the user</p>
* @return <p>The directory given by the user</p>
*/
File askForDirectory(String prompt);
} }

View File

@ -2,6 +2,9 @@ package net.knarcraft.minecraftserverlauncher.userinterface;
import javax.swing.*; import javax.swing.*;
/**
* This class handles displaying messages to the user
*/
public abstract class MessageHandler implements GUI { public abstract class MessageHandler implements GUI {
private final boolean silent; private final boolean silent;

View File

@ -2,6 +2,7 @@ package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.profile.Controller;
import net.knarcraft.minecraftserverlauncher.profile.Profile; import net.knarcraft.minecraftserverlauncher.profile.Profile;
import net.knarcraft.minecraftserverlauncher.server.Server; import net.knarcraft.minecraftserverlauncher.server.Server;
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions; import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
@ -62,6 +63,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
private String aboutText; private String aboutText;
private SystemTray tray; private SystemTray tray;
private TrayIcon trayIcon; private TrayIcon trayIcon;
private Controller controller;
/** /**
* Creates the application window * Creates the application window
@ -70,6 +72,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
super(false); super(false);
initialize(440, 170); initialize(440, 170);
loadMessages(); loadMessages();
this.controller = Main.getController();
this.globalPlayers = new ArrayList<>(); this.globalPlayers = new ArrayList<>();
} }
@ -83,6 +86,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
super(false); super(false);
initialize(width, height); initialize(width, height);
loadMessages(); loadMessages();
this.controller = Main.getController();
this.globalPlayers = new ArrayList<>(); this.globalPlayers = new ArrayList<>();
} }
@ -105,6 +109,21 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
} }
} }
@Override
public File askForDirectory(String prompt) {
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new java.io.File("."));
chooser.setDialogTitle(prompt);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(null) != JFileChooser.APPROVE_OPTION) {
setStatus("Choice aborted by user");
return null;
}
return chooser.getSelectedFile();
}
/** /**
* Adds a player to the global playerlist, and updates the players combo. * Adds a player to the global playerlist, and updates the players combo.
* *
@ -129,10 +148,12 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
* Updates the profiles combo. * Updates the profiles combo.
*/ */
public void updateProfiles() { public void updateProfiles() {
String selectedProfile = Main.getController().getCurrentProfile().getName();
this.profiles.removeAllItems(); this.profiles.removeAllItems();
for (Profile profile : Profile.getProfiles()) { for (String profile : Main.getController().getProfileNames()) {
this.profiles.addItem(profile.getName()); this.profiles.addItem(profile);
} }
this.profiles.setSelectedItem(selectedProfile);
} }
/** /**
@ -148,16 +169,15 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
* Updates ServerLauncherGUI according to current profile settings. * Updates ServerLauncherGUI according to current profile settings.
*/ */
public void update() { public void update() {
Controller controller = Main.getController();
serversPane.removeAll(); serversPane.removeAll();
for (Collection collection : Profile.getCurrent().getCollections()) { chckbxmntmRunInBackground.setState(controller.getRunInBackground());
serversPane.addTab(collection.getName(), collection.getServerTab().getPanel()); chckbxmntmDelayStartup.setState(controller.getDelayStartup() > 0);
} chckbxmntmDownloadJars.setState(controller.getDownloadAllJars());
chckbxmntmRunInBackground.setState(Profile.getCurrent().getRunInBackground());
chckbxmntmDelayStartup.setState(Profile.getCurrent().getDelayStartup() > 0);
chckbxmntmDownloadJars.setState(Profile.getCurrent().getDownloadAllAvailableJARFiles());
this.targetServer.removeAllItems(); this.targetServer.removeAllItems();
this.targetServer.addItem("All"); this.targetServer.addItem("All");
for (Collection collection : Profile.getCurrent().getCollections()) { for (Collection collection : controller.getCurrentProfile().getCollections()) {
serversPane.addTab(collection.getName(), collection.getServerTab().getPanel());
this.targetServer.addItem(collection.getName()); this.targetServer.addItem(collection.getName());
} }
} }
@ -453,11 +473,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
trayIcon.setImageAutoSize(true); trayIcon.setImageAutoSize(true);
ActionListener exitListener = e -> { ActionListener exitListener = e -> {
stop(); stop();
try { controller.saveState();
Profile.getCurrent().save();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
System.exit(0); System.exit(0);
}; };
@ -481,7 +497,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
frame.addWindowListener(new WindowAdapter() { frame.addWindowListener(new WindowAdapter() {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
if (Profile.getCurrent().getRunInBackground() && SystemTray.isSupported()) { if (controller.getRunInBackground() && SystemTray.isSupported()) {
try { try {
tray.add(trayIcon); tray.add(trayIcon);
frame.setVisible(false); frame.setVisible(false);
@ -490,11 +506,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
} }
} else { } else {
stop(); stop();
try { controller.saveState();
Profile.getCurrent().save();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
System.exit(0); System.exit(0);
} }
} }
@ -514,11 +526,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
frame.addWindowListener(new WindowAdapter() { frame.addWindowListener(new WindowAdapter() {
@Override @Override
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
try { controller.saveState();
Profile.getCurrent().save();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
stop(); stop();
System.exit(0); System.exit(0);
} }
@ -572,68 +580,60 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
} else if (e.getSource() == mntmStory) { } else if (e.getSource() == mntmStory) {
CommonFunctions.goToURL("https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherStory/"); CommonFunctions.goToURL("https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherStory/");
} else if (e.getSource() == btnStartServer) { } else if (e.getSource() == btnStartServer) {
try { controller.saveState();
Profile.getCurrent().save();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
Executors.newSingleThreadExecutor().execute(Server::startServers); Executors.newSingleThreadExecutor().execute(Server::startServers);
} else if (e.getSource() == btnStopServer) { } else if (e.getSource() == btnStopServer) {
stop(); stop();
} else if (e.getSource() == addServer) { } else if (e.getSource() == addServer) {
String serverName = JOptionPane.showInputDialog("Name of server: "); String serverName = JOptionPane.showInputDialog("Name of server: ");
try { try {
Profile.getCurrent().addCollection(serverName); controller.getCurrentProfile().addCollection(serverName);
} catch (ConfigurationException e1) { } catch (ConfigurationException e1) {
e1.printStackTrace(); e1.printStackTrace();
} }
this.update(); this.update();
Profile.getCurrent().updateConsoles(); controller.getCurrentProfile().updateConsoles();
} else if (e.getSource() == backup) { } else if (e.getSource() == backup) {
backup(); CommonFunctions.backup(this);
} else if (e.getSource() == addProfile) { } else if (e.getSource() == addProfile) {
Profile.addProfile(JOptionPane.showInputDialog("Profile name: ")); controller.addProfile(JOptionPane.showInputDialog("Profile name: "));
updateProfiles(); updateProfiles();
} else if (e.getSource() == delProfile) { } else if (e.getSource() == delProfile) {
Object selected = profiles.getSelectedItem(); Object selected = profiles.getSelectedItem();
if (selected != null) { if (selected != null) {
Profile.removeProfile(selected.toString()); controller.removeProfile(selected.toString());
updateProfiles(); updateProfiles();
} }
} else if (e.getSource() == profiles) { } else if (e.getSource() == profiles) {
try {
changeProfile(); changeProfile();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
} else if (e.getSource() == btnKick) { } else if (e.getSource() == btnKick) {
if (selectedServerValue != null && selectedPlayerValue != null) { if (selectedServerValue != null && selectedPlayerValue != null) {
Profile.getCurrent().sendCommand(selectedServerValue, "kick " + selectedPlayerValue); controller.getCurrentProfile().sendCommand(selectedServerValue, "kick " + selectedPlayerValue);
} }
} else if (e.getSource() == btnBan) { } else if (e.getSource() == btnBan) {
if (selectedServerValue != null && selectedPlayerValue != null) { if (selectedServerValue != null && selectedPlayerValue != null) {
Profile.getCurrent().sendCommand(selectedServerValue, "ban " + selectedPlayerValue); controller.getCurrentProfile().sendCommand(selectedServerValue, "ban " + selectedPlayerValue);
} }
} else if (e.getSource() == btnOp) { } else if (e.getSource() == btnOp) {
if (selectedServerValue != null && selectedPlayerValue != null) { if (selectedServerValue != null && selectedPlayerValue != null) {
Profile.getCurrent().sendCommand(selectedServerValue, "op " + selectedPlayerValue); controller.getCurrentProfile().sendCommand(selectedServerValue, "op " + selectedPlayerValue);
} }
} else if (e.getSource() == btnDeop) { } else if (e.getSource() == btnDeop) {
if (selectedServerValue != null && selectedPlayerValue != null) { if (selectedServerValue != null && selectedPlayerValue != null) {
Profile.getCurrent().sendCommand(selectedServerValue, "deop " + selectedPlayerValue); controller.getCurrentProfile().sendCommand(selectedServerValue, "deop " + selectedPlayerValue);
} }
} else if (e.getSource() == btnCustomCommand) { } else if (e.getSource() == btnCustomCommand) {
if (selectedServerValue != null) { if (selectedServerValue != null) {
Profile.getCurrent().sendCommand(selectedServerValue, customCommand.getText()); controller.getCurrentProfile().sendCommand(selectedServerValue, customCommand.getText());
customCommand.setText(""); customCommand.setText("");
} }
} else if (e.getSource() == btnSaveserver) { } else if (e.getSource() == btnSaveserver) {
if (selectedServerValue != null) { if (selectedServerValue != null) {
Profile.getCurrent().sendCommand(selectedServerValue, "save-all"); controller.getCurrentProfile().sendCommand(selectedServerValue, "save-all");
} }
} else if (e.getSource() == btnReload) { } else if (e.getSource() == btnReload) {
if (selectedServerValue != null) { if (selectedServerValue != null) {
Profile.getCurrent().sendCommand(selectedServerValue, "reload"); controller.getCurrentProfile().sendCommand(selectedServerValue, "reload");
} }
} else if (e.getSource() == btnServerConsoles) { } else if (e.getSource() == btnServerConsoles) {
ServerConsoles.setAsVisible(); ServerConsoles.setAsVisible();
@ -661,14 +661,14 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
/** /**
* Saves the previous profile and loads data from the new profile. * Saves the previous profile and loads data from the new profile.
*/ */
private void changeProfile() throws FileNotFoundException { private void changeProfile() {
Profile.getCurrent().save(); controller.saveState();
Object current = this.profiles.getSelectedItem(); Object current = this.profiles.getSelectedItem();
if (current != null) { if (current != null) {
Profile.setCurrent(current.toString()); controller.setCurrentProfile(current.toString());
} }
this.update(); this.update();
Profile.getCurrent().updateConsoles(); controller.getCurrentProfile().updateConsoles();
} }
/** /**
@ -690,11 +690,15 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
private void delay() { private void delay() {
Object selected = profiles.getSelectedItem(); Object selected = profiles.getSelectedItem();
if (selected != null) { if (selected != null) {
Profile profile = Profile.getProfile(selected.toString()); Profile profile = controller.getProfileByName(selected.toString());
if (chckbxmntmDelayStartup.isSelected()) { if (chckbxmntmDelayStartup.isSelected()) {
Objects.requireNonNull(profile).setDelayStartup( String response = JOptionPane.showInputDialog("Seconds to delay: ");
Integer.parseInt(JOptionPane.showInputDialog("Seconds to delay: ")) if (response == null) {
); chckbxmntmDelayStartup.setState(false);
return;
}
int parsed = Integer.parseInt(response);
Objects.requireNonNull(profile).setDelayStartup(parsed);
} else { } else {
Objects.requireNonNull(profile).setDelayStartup(0); Objects.requireNonNull(profile).setDelayStartup(0);
} }
@ -709,7 +713,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
private void background() { private void background() {
Object selected = profiles.getSelectedItem(); Object selected = profiles.getSelectedItem();
if (selected != null) { if (selected != null) {
Profile profile = Profile.getProfile(selected.toString()); Profile profile = controller.getProfileByName(selected.toString());
Objects.requireNonNull(profile).setRunInBackground(chckbxmntmRunInBackground.isSelected()); Objects.requireNonNull(profile).setRunInBackground(chckbxmntmRunInBackground.isSelected());
} else { } else {
showError("No profile selected"); showError("No profile selected");
@ -722,47 +726,12 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
private void downloadJars() { private void downloadJars() {
Object selected = profiles.getSelectedItem(); Object selected = profiles.getSelectedItem();
if (selected != null) { if (selected != null) {
Profile profile = Profile.getProfile(selected.toString()); controller.setDownloadAllJars(chckbxmntmDownloadJars.isSelected());
Objects.requireNonNull(profile).setDownloadAllAvailableJARFiles(chckbxmntmDownloadJars.isSelected());
} else { } else {
showError("No profile selected"); showError("No profile selected");
} }
} }
/**
* Copies all server directories to a folder specified by the user.
*/
private void backup() {
JFileChooser chooser = new JFileChooser();
chooser.setCurrentDirectory(new java.io.File("."));
chooser.setDialogTitle("Backup folder");
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
File path = chooser.getSelectedFile();
for (Collection collection : Profile.getCurrent().getCollections()) {
if (!collection.getServer().getPath().equals("") && collection.getServer().isEnabled()) {
String name = collection.getServer().getName();
File srcFolder = new File(collection.getServer().getPath());
File destFolder = new File(path, name);
if (!destFolder.exists()) {
if (destFolder.mkdirs()) {
try {
CommonFunctions.copyFolder(this, srcFolder, destFolder);
} catch (IOException e) {
e.printStackTrace();
return;
}
} else {
return;
}
}
}
}
}
this.setStatus("Backup finished");
}
/** /**
* Updates the list of players currently online on the selected server, * Updates the list of players currently online on the selected server,
*/ */
@ -777,7 +746,7 @@ public class ServerLauncherGUI extends MessageHandler implements ActionListener,
targetPlayer.addItem(player); targetPlayer.addItem(player);
} }
} else { } else {
for (String player : Profile.getCurrent().getCollection(selectedServerValue).getServer().getPlayers()) { for (String player : controller.getCurrentProfile().getCollection(selectedServerValue).getServer().getPlayers()) {
targetPlayer.addItem(player); targetPlayer.addItem(player);
} }
} }

View File

@ -1,6 +1,6 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.profile.Profile; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.server.Server; import net.knarcraft.minecraftserverlauncher.server.Server;
import net.knarcraft.minecraftserverlauncher.server.ServerTypeHandler; import net.knarcraft.minecraftserverlauncher.server.ServerTypeHandler;
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType; import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
@ -29,7 +29,7 @@ public class ServerTab implements ActionListener {
public ServerTab(String name) throws ConfigurationException { public ServerTab(String name) throws ConfigurationException {
this.name = name; this.name = name;
panel = new JPanel(); panel = new JPanel();
Profile.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();
panel.setLayout(sl_panel_3); panel.setLayout(sl_panel_3);
@ -197,9 +197,9 @@ public class ServerTab implements ActionListener {
* Removes the collection containing this ServerTab, and updates everything necessary. * Removes the collection containing this ServerTab, and updates everything necessary.
*/ */
private void remove() { private void remove() {
Profile.getCurrent().removeCollection(this.name); Main.getController().getCurrentProfile().removeCollection(this.name);
Profile.getGUI().update(); Main.getController().getGUI().update();
Profile.getCurrent().updateConsoles(); Main.getController().getCurrentProfile().updateConsoles();
} }
/** /**

View File

@ -1,7 +1,9 @@
package net.knarcraft.minecraftserverlauncher.utility; package net.knarcraft.minecraftserverlauncher.utility;
import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI; import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.server.Server;
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
import java.io.*; import java.io.*;
import java.net.URI; import java.net.URI;
@ -21,7 +23,7 @@ import java.util.Scanner;
*/ */
public final class CommonFunctions { public final class CommonFunctions {
private static String filesDirectory = Main.getApplicationWorkDirectory() + File.separator + "files"; private static final String filesDirectory = Main.getApplicationWorkDirectory() + File.separator + "files";
/** /**
* Creates all folders necessary for tests and normal operation * Creates all folders necessary for tests and normal operation
@ -128,7 +130,7 @@ public final class CommonFunctions {
* @param destination <p>Target destination</p> * @param destination <p>Target destination</p>
* @throws IOException <p>If we can't start a file stream</p> * @throws IOException <p>If we can't start a file stream</p>
*/ */
public static void copyFolder(ServerLauncherGUI serverLauncherGui, File source, File destination) throws IOException { public static void copyFolder(GUI serverLauncherGui, File source, File destination) throws IOException {
if (!source.isDirectory()) { if (!source.isDirectory()) {
copyFile(serverLauncherGui, source, destination); copyFile(serverLauncherGui, source, destination);
} else { } else {
@ -156,7 +158,7 @@ public final class CommonFunctions {
* @param destination <p>The location of the copied file</p> * @param destination <p>The location of the copied file</p>
* @throws IOException <p>If reading or writing fails</p> * @throws IOException <p>If reading or writing fails</p>
*/ */
private static void copyFile(ServerLauncherGUI serverLauncherGui, File source, File destination) throws IOException { private static void copyFile(GUI serverLauncherGui, File source, File destination) throws IOException {
serverLauncherGui.setStatus("Copying file " + source + "..."); serverLauncherGui.setStatus("Copying file " + source + "...");
InputStream in = new FileInputStream(source); InputStream in = new FileInputStream(source);
OutputStream out = new FileOutputStream(destination); OutputStream out = new FileOutputStream(destination);
@ -199,4 +201,43 @@ 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
*
* @param name <p>The name to check</p>
* @return <p>True if the name is valid</p>
*/
public static boolean nameIsValid(String name) {
return !name.equals("") && name.matches("[^!?;,]+");
}
} }

View File

@ -15,7 +15,7 @@ import java.io.IOException;
public final class JarDownloader { public final class JarDownloader {
private final String jarDirectory; private final String jarDirectory;
private GUI gui; private final GUI gui;
/** /**
* Initializes a jar downloader * Initializes a jar downloader

View File

@ -6,5 +6,5 @@ Paper;1.16.1,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://stati
Bungee;Latest;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 Bungee;Latest;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
Waterfall;Latest;https://papermc.io/api/v1/waterfall/1.16;"latest":";";https://papermc.io/api/v1/waterfall/1.16/ Waterfall;Latest;https://papermc.io/api/v1/waterfall/1.16;"latest":";";https://papermc.io/api/v1/waterfall/1.16/
Travertine;Latest;https://papermc.io/api/v1/travertine/1.16;"latest":";";https://papermc.io/api/v1/travertine/1.16/ Travertine;Latest;https://papermc.io/api/v1/travertine/1.16;"latest":";";https://papermc.io/api/v1/travertine/1.16/
Vanilla;Latest,Snapshot,1.16.1,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.16.2,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/
Custom;; Custom;;
Can't render this file because it contains an unexpected character in line 1 and column 151.

View File

@ -0,0 +1,23 @@
package net.knarcraft.minecraftserverlauncher.server;
import org.junit.Test;
import javax.naming.ConfigurationException;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
public class ServerTest {
@Test
public void fromStringTest() throws ConfigurationException {
Server server = Server.fromString("asd;/home/;false;Bukkit;1.10.2;4G;");
assertEquals("asd", server.getName());
assertEquals("/home/", server.getPath());
assertFalse(server.isEnabled());
assertEquals("Bukkit", server.getTypeName());
assertEquals("1.10.2", server.getServerVersion());
assertEquals("4G", server.getMaxRam());
}
}

View File

@ -13,7 +13,7 @@ import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.crea
public class ServerVersionContainerTest { public class ServerVersionContainerTest {
private final String filesDirectory = Main.getApplicationWorkDirectory() + File.separator + "files"; private final String filesDirectory = Main.getApplicationWorkDirectory() + File.separator + "files";
private String versionFile = filesDirectory + File.separator + "versions.csv"; private final String versionFile = filesDirectory + File.separator + "versions.csv";
private ServerVersionContainer serverVersionContainer; private ServerVersionContainer serverVersionContainer;
@Before @Before

View File

@ -1,5 +1,7 @@
package net.knarcraft.minecraftserverlauncher.userinterface; package net.knarcraft.minecraftserverlauncher.userinterface;
import java.io.File;
public class FakeGUI extends MessageHandler implements GUI { public class FakeGUI extends MessageHandler implements GUI {
/*** /***
@ -13,4 +15,9 @@ public class FakeGUI extends MessageHandler implements GUI {
public void setStatus(String message) { public void setStatus(String message) {
System.out.println(message); System.out.println(message);
} }
@Override
public File askForDirectory(String prompt) {
return null;
}
} }

View File

@ -1,19 +1,17 @@
package net.knarcraft.minecraftserverlauncher.utility; package net.knarcraft.minecraftserverlauncher.utility;
import net.knarcraft.minecraftserverlauncher.profile.Profile; import net.knarcraft.minecraftserverlauncher.Main;
import org.junit.Test; import org.junit.Test;
import java.io.FileNotFoundException;
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween; import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
public class CommonFunctionsTest { public class CommonFunctionsTest {
@Test @Test
public void saveProfileTest() throws FileNotFoundException { public void saveProfileTest() {
Profile.addProfile("Test"); Main.getController().addProfile("Test");
Profile.getCurrent().save(); Main.getController().saveState();
} }
@Test @Test