Adds comments and refactors several classes
All checks were successful
KnarCraft/Minecraft-Server-Launcher/master This commit looks good

Adds comments to Collection
Makes some variable and function names more descriptive
Adds some new methods for showing messsages and errors
Adds a lot of missing comments
Enhances some existing comments
This commit is contained in:
Kristian Knarvik 2020-02-13 21:10:18 +01:00
parent c59cbcefbb
commit 040740db84
11 changed files with 489 additions and 383 deletions

View File

@ -32,14 +32,14 @@ import static net.knarcraft.minecraftserverlauncher.Shared.*;
*/
public class Main {
private static String appDir;
private static boolean running = false;
private static String applicationWorkDirectory;
private static boolean serversAreRunning = false;
private static final String updateChannel = "alpha";
private static final String updateURL = "https://api.knarcraft.net/minecraftserverlauncher";
public static void main(String[] args) throws IOException {
checkForUpdate();
try (PrintWriter file = new PrintWriter(Main.getAppDir() + File.separator + "latestrun.log")) {
try (PrintWriter file = new PrintWriter(Main.getApplicationWorkDirectory() + File.separator + "latestrun.log")) {
file.print("");
} catch (IOException e ) {
e.printStackTrace();
@ -74,16 +74,16 @@ public class Main {
*
* @return A string path
*/
public static String getAppDir() {
if (appDir == null) {
public static String getApplicationWorkDirectory() {
if (applicationWorkDirectory == null) {
try {
appDir = String.valueOf(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile());
applicationWorkDirectory = String.valueOf(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile());
} catch (URISyntaxException e) {
e.printStackTrace();
System.exit(1);
}
}
return appDir;
return applicationWorkDirectory;
}
/**
@ -109,13 +109,13 @@ public class Main {
}
}
boolean runningNew = serversRunning();
if (!runningNew && running) {
if (!runningNew && serversAreRunning) {
Profile.getGUI().updateRunning(false);
Profile.getGUI().setStatus("Servers are stopped");
} else if (runningNew && !running) {
} else if (runningNew && !serversAreRunning) {
Profile.getGUI().updateRunning(true);
}
running = runningNew;
serversAreRunning = runningNew;
} catch (Exception e) {
e.printStackTrace();
}
@ -203,7 +203,7 @@ public class Main {
String latest = jsonObject.getAsJsonObject("latest").get(updateChannel).getAsString();
if (!oldType.equals(updateChannel) || !oldVer.equals(latest)) {
String dir = getAppDir() + File.separator;
String dir = getApplicationWorkDirectory() + File.separator;
JsonArray versionList = jsonObject.getAsJsonArray("versions");
String url = "";
for (JsonElement elem : versionList) {
@ -217,12 +217,8 @@ public class Main {
if (downloadFile(url, new File(dir + "update.jar").toPath())) {
doUpdate(dir);
} else {
JOptionPane.showMessageDialog(
null,
"An update is available, but could not be downloaded.",
"Update available",
JOptionPane.ERROR_MESSAGE
);
Profile.showError("Update available",
"An update is available, but could not be downloaded.");
}
}
}
@ -235,31 +231,24 @@ public class Main {
JOptionPane.YES_NO_OPTION
);
if (answer == JOptionPane.YES_NO_OPTION) {
if (new File (dir + "Minecraft-Server-Launcher.jar").renameTo(new File(dir + "Old.jar"))) {
if (new File(dir + "update.jar").renameTo(new File (dir + "Minecraft-Server-Launcher.jar"))) {
if (new File (dir + "Minecraft-Server-Launcher.jar").renameTo(new File(dir +
"Old.jar"))) {
if (new File(dir + "update.jar").renameTo(new File (dir +
"Minecraft-Server-Launcher.jar"))) {
if (new File(dir + "Old.jar").delete()) {
JOptionPane.showMessageDialog(
null,
"Update finished. Please run the software again.",
"Update complete",
JOptionPane.INFORMATION_MESSAGE
);
Profile.showMessage("Update complete",
"Update finished. Please run the software again.");
System.exit(0);
}
} else {
if (!new File(dir + "Old.jar").renameTo(new File (dir + "Minecraft-Server-Launcher.jar"))) {
if (!new File(dir + "Old.jar").renameTo(new File (dir +
"Minecraft-Server-Launcher.jar"))) {
System.out.println("Shit");
}
}
}
JOptionPane.showMessageDialog(
null,
"Could not replace the main .jar with the downloaded .jar.",
"Update failed",
JOptionPane.ERROR_MESSAGE
);
}
Profile.showError("Update failed",
"Could not replace the main .jar with the downloaded .jar.");
}
}
}

View File

@ -1,8 +1,10 @@
package net.knarcraft.minecraftserverlauncher;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
@ -86,4 +88,55 @@ public class Shared {
return false;
}
}
/**
* Recursivly copies a folder to another location
*
* @param src <p>The folder to copy</p>
* @param dest <p>Target destination</p>
* @throws IOException <p>If we can't start a file stream</p>
*/
public static void copyFolder(GUI gui, File src, File dest) throws IOException {
if (!src.isDirectory()) {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0){
out.write(buffer, 0, length);
}
in.close();
out.close();
gui.setStatus("Copied file " + src);
} else {
if(!dest.exists()){
if (dest.mkdir()) {
gui.setStatus("Copied directory " + src);
} else {
return;
}
}
String[] files = src.list();
if (files != null) {
for (String file : files) {
File srcFile = new File(src, file);
File destFile = new File(dest, file);
copyFolder(gui, srcFile, destFile);
}
}
}
}
/**
* Opens an url in the user's default application.
* @param url <p>URL to open</p>
*/
public static void goToURL(String url) {
java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
try {
desktop.browse(new URI(url));
} catch (URISyntaxException | IOException e1) {
e1.printStackTrace();
}
}
}

View File

@ -18,15 +18,32 @@ public class Collection {
private final Console serverConsole;
private final String name;
/**
* Creates a new collection with the given name
* @param name <p>The name identifying the server, server tab, collection and server console</p>
*/
Collection(String name) {
this.serverTab = new ServerTab(name);
this.server = new Server(name);
this.serverConsole = ServerConsoles.addTab(name);
this.serverConsole = ServerConsoles.addConsoleTab(name);
this.name = name;
}
/**
* 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>
* @param vanillaVersion <p>The currently selected vanilla version</p>
* @param snapshotVersion <p>The currently selected snapshot version</p>
* @param spongeVanillaVersion <p>The currently selected SpongeVanilla version</p>
* @param bungeeVersion <p>The currently selected Bungee version</p>
*/
Collection(String name,
String path,
String serverPath,
boolean enabled,
String typeName,
String serverVersion,
@ -39,7 +56,7 @@ public class Collection {
this.serverTab = new ServerTab(name);
this.server = new Server(
name,
path,
serverPath,
enabled,
typeName,
serverVersion,
@ -49,23 +66,39 @@ public class Collection {
spongeVanillaVersion,
bungeeVersion
);
this.serverConsole = ServerConsoles.addTab(name);
this.serverConsole = ServerConsoles.addConsoleTab(name);
this.name = name;
this.serverTab.setData(path, enabled, typeName, serverVersion, maxRam);
this.serverTab.setData(serverPath, enabled, typeName, serverVersion, maxRam);
}
/**
* Gets the name of the collection
* @return <p>Collection name</p>
*/
public String getName() {
return this.name;
}
/**
* Gets the server of the collection
* @return <p>Collection server</p>
*/
public Server getServer() {
return this.server;
}
/**
* Gets the server tab of the collection
* @return <p>Collection server tab</p>
*/
public ServerTab getServerTab() {
return this.serverTab;
}
/**
* Gets the server console of the collection
* @return <p>Collection server console</p>
*/
public Console getServerConsole() {
return this.serverConsole;
}

View File

@ -36,15 +36,15 @@ public class Profile {
private static final ArrayList<Profile> profiles = new ArrayList<>();
private static Profile current;
private static GUI gui;
private static final String profilesDir = Main.getAppDir() + File.separator + "files";
private static final String profilesFile = Main.getAppDir() + File.separator + "files" + File.separator + "Profiles.txt";
private static final String jarDir = Main.getAppDir() + File.separator + "files" + File.separator + "Jars" + File.separator;
private static final String profilesDir = Main.getApplicationWorkDirectory() + File.separator + "files";
private static final String profilesFile = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator + "Profiles.txt";
private static final String jarDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator + "Jars" + File.separator;
private final ArrayList<Collection> collections;
private final String name;
private boolean runInBackground;
private int delayStartup;
private boolean downloadJars;
private boolean downloadAllAvailableJARFiles;
private static String vanillaVersion;
private static String snapshotVersion;
private static String bungeeVersion;
@ -54,19 +54,19 @@ public class Profile {
this.name = name;
this.runInBackground = false;
this.delayStartup = 0;
this.downloadJars = false;
this.downloadAllAvailableJARFiles = false;
profiles.add(this);
if (current == null) {
current = this;
}
}
private Profile(String name, boolean runInBackground, int delayStartup, boolean downloadJars) {
private Profile(String name, boolean runInBackground, int delayStartup, boolean downloadAllAvailableJARFiles) {
this.collections = new ArrayList<>();
this.name = name;
this.runInBackground = runInBackground;
this.delayStartup = delayStartup;
this.downloadJars = downloadJars;
this.downloadAllAvailableJARFiles = downloadAllAvailableJARFiles;
profiles.add(this);
if (current == null) {
current = this;
@ -85,8 +85,8 @@ public class Profile {
return this.delayStartup;
}
public boolean getDownloadJars() {
return this.downloadJars;
public boolean getDownloadAllAvailableJARFiles() {
return this.downloadAllAvailableJARFiles;
}
public static Profile getCurrent() {
@ -139,8 +139,8 @@ public class Profile {
}
}
public void setDownloadJars(boolean value) {
this.downloadJars = value;
public void setDownloadAllAvailableJARFiles(boolean value) {
this.downloadAllAvailableJARFiles = value;
}
/**
@ -175,13 +175,8 @@ public class Profile {
) {
collections.add(new Collection(name));
} else {
JOptionPane.showMessageDialog(
null,
"A server name must my unique and not empty or \"All\"." +
"It can't contain any of the characters \"!\", \"?\" or \";\".",
"Error",
JOptionPane.ERROR_MESSAGE
);
showError("A server name must my unique and not empty or \"All\"." +
"It can't contain any of the characters \"!\", \"?\" or \";\".");
}
}
@ -195,22 +190,12 @@ public class Profile {
return;
}
if (name.equals("") && !name.matches("^[!?;]+$")) {
JOptionPane.showMessageDialog(
null,
"Profile name can't be blank.",
"Error",
JOptionPane.ERROR_MESSAGE
);
showError("Profile name can't be blank.");
return;
}
for (Profile profile : profiles) {
if (profile.name.equals(name)) {
JOptionPane.showMessageDialog(
null,
"There is already a profile with this name.",
"Error",
JOptionPane.ERROR_MESSAGE
);
showError("There is already a profile with this name.");
return;
}
}
@ -227,6 +212,10 @@ public class Profile {
}
}
/**
* 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));
@ -234,7 +223,7 @@ public class Profile {
}
public void updateConsoles() {
JTabbedPane consolesTab = ServerConsoles.getTab();
JTabbedPane consolesTab = ServerConsoles.getTabbedPane();
consolesTab.removeAll();
for (Collection collection : collections) {
consolesTab.add(collection.getName(), collection.getServerConsole().getPanel());
@ -253,12 +242,7 @@ public class Profile {
try {
collection.getServer().sendCommand(command);
} catch (IOException e) {
JOptionPane.showMessageDialog(
null,
"Server " + collection.getName() + " caused an exception.",
"Error",
JOptionPane.ERROR_MESSAGE
);
showError("Server " + collection.getName() + " caused an exception.");
}
}
} else {
@ -268,19 +252,10 @@ public class Profile {
try {
target.sendCommand(command);
} catch (IOException e) {
JOptionPane.showMessageDialog(
null,
"Server " + target.getName() + " caused an exception.",
"Error",
JOptionPane.ERROR_MESSAGE
);
showError("Server " + target.getName() + " caused an exception.");
}
} else {
JOptionPane.showMessageDialog(
null,
"Server " + serverName + " is invalid.",
"Error", JOptionPane.ERROR_MESSAGE
);
showError("Server " + serverName + " is invalid.");
}
}
}
@ -299,33 +274,32 @@ public class Profile {
try {
server.setServerVersion(serverTab.getVersion());
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(
null,
"Invalid server version for " + server.getName(),
"Error",
JOptionPane.ERROR_MESSAGE
);
showError("Invalid server version for " + server.getName());
}
server.toggle(serverTab.enabled());
}
if (!new File(profilesDir).exists() && !new File(profilesDir).mkdirs()) {
JOptionPane.showMessageDialog(
null,
"Unable to create the folder " + profilesDir,
"Error",
JOptionPane.ERROR_MESSAGE
);
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 (gui == null) {
width = 440;
height = 170;
} else {
width = gui.getSize().width;
height = gui.getSize().height;
}
file.println(String.format(
"%s;%s;%s;%s;%d;%d",
current.name,
vanillaVersion,
snapshotVersion,
bungeeVersion,
gui.getSize().width,
gui.getSize().height
width,
height
));
file.close();
for (Profile profile : profiles) {
@ -334,7 +308,7 @@ public class Profile {
profile.name,
profile.runInBackground,
profile.delayStartup,
profile.downloadJars)
profile.downloadAllAvailableJARFiles)
);
for (Collection collection : profile.collections) {
Server server = collection.getServer();
@ -361,26 +335,16 @@ public class Profile {
fileAppend.println(saveString);
} catch (IOException e) {
if (gui != null) {
JOptionPane.showMessageDialog(
null,
"Unable to save to file. Try running the software as an administrator.",
"Error",
JOptionPane.ERROR_MESSAGE
);
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 | NullPointerException e) {
} catch (IOException e) {
if (gui != null) {
JOptionPane.showMessageDialog(
null,
"Unable to save to file. Try running the software as an administrator.",
"Error",
JOptionPane.ERROR_MESSAGE
);
showError("Unable to save to file. Try running the software as an administrator.");
}
throw new FileNotFoundException("Unable to create the profiles file");
}
@ -424,12 +388,8 @@ public class Profile {
current = getProfile(profileName);
} catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(
null,
"Invalid Profile.txt file. Profiles could not be loaded. If this error persists, please manually delete the file.",
"Error",
JOptionPane.ERROR_MESSAGE
);
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();
@ -438,21 +398,11 @@ public class Profile {
addProfile("Default");
}
} catch (FileNotFoundException | NoSuchElementException e) {
JOptionPane.showMessageDialog(
null,
"A profiles file was not found. Default profile was created.",
"Info",
JOptionPane.INFORMATION_MESSAGE
);
showMessage("A profiles file was not found. Default profile was created.");
try {
gui = new GUI();
} catch (FileNotFoundException ex) {
JOptionPane.showMessageDialog(
null,
"Failed to load GUI messages. The GUI can't be shown.",
"Info",
JOptionPane.INFORMATION_MESSAGE
);
showMessage("Failed to load GUI messages. The GUI can't be shown.");
} catch (IOException ex) {
ex.printStackTrace();
}
@ -461,7 +411,7 @@ public class Profile {
gui.update();
gui.updateProfiles();
current.updateConsoles();
if (current.downloadJars) {
if (current.downloadAllAvailableJARFiles) {
Executors.newSingleThreadExecutor().execute(() -> {
try {
downloadJars();
@ -478,9 +428,8 @@ public class Profile {
/**
* Parses a profile, and creates a profile with the data.
*
* @param profileData The data of the new profile
* @return The new profile
* @param profileData <p>The data of the new profile</p>
* @return <p>The new profile</p>
*/
private static Profile parseProfile(String[] profileData) {
return new Profile(
@ -493,9 +442,8 @@ public class Profile {
/**
* Parses a server, and creates a new collection.
*
* @param profile The profile which to add the collection
* @param serverData The data to parse
* @param profile <p>The profile which to add the collection</p>
* @param serverData <p>The data to parse</p>
*/
private static void parseServer(Profile profile, String[] serverData) {
profile.collections.add(new Collection(
@ -518,13 +466,9 @@ public class Profile {
* @throws IOException On version file failure or folder creation failure
*/
public static void downloadJars() throws IOException {
if (!new File(jarDir).exists() && !new File(jarDir).mkdirs()) {
JOptionPane.showMessageDialog(
null,
"Could not create the Jars folder. Please run the program with admin permissions, or move it to a writable directory.",
"Error",
JOptionPane.ERROR_MESSAGE
);
if (!new File(jarDirectory).exists() && !new File(jarDirectory).mkdirs()) {
showError("Could not create the Jars folder. Please run the program with admin permissions, or move it to " +
"a writable directory.");
throw new FileNotFoundException("Unable to create jars folder");
}
try {
@ -538,81 +482,195 @@ public class Profile {
/**
* Prints something to the gui status field if the gui exists
* Otherwise it prints to the console
*
* @param str The string to show the user
* @param message <p>The string to show the user</p>
*/
private static void printToGui(String str) {
private static void printToGui(String message) {
if (gui != null) {
gui.setStatus(str);
gui.setStatus(message);
} else {
System.out.println(str);
System.out.println(message);
}
}
public static void showError(String title, String message) {
if (gui != null) {
JOptionPane.showMessageDialog(
null,
message,
title,
JOptionPane.ERROR_MESSAGE
);
} else {
System.out.println(message);
}
}
public static void showError(String message) {
if (gui != null) {
JOptionPane.showMessageDialog(
null,
message,
"Error",
JOptionPane.ERROR_MESSAGE
);
} else {
System.out.println(message);
}
}
public static void showMessage(String title, String message) {
if (gui != null) {
JOptionPane.showMessageDialog(
null,
message,
title,
JOptionPane.INFORMATION_MESSAGE
);
} else {
System.out.println(message);
}
}
public static void showMessage(String message) {
if (gui != null) {
JOptionPane.showMessageDialog(
null,
message,
"Info",
JOptionPane.INFORMATION_MESSAGE
);
} else {
System.out.println(message);
}
}
private static void showMessage() {}
/**
* Downloads jar files for all possible server versions.
*
* @throws IOException If a jar fails to download.
* Downloads jar files for all possible server versions
* @throws IOException <p>If a jar fails to download</p>
*/
private static void downloadAll() throws IOException {
for (ServerType type : ServerType.getServerTypes()) {
String url = Objects.requireNonNull(type).getDownloadURL(), name = type.getName(), newestVersion;
AdvancedServerType advType = type instanceof AdvancedServerType ? (AdvancedServerType) type : null;
String downloadURL = Objects.requireNonNull(type).getDownloadURL();
String typeName = type.getName();
AdvancedServerType advancedServerType = type instanceof AdvancedServerType ? (AdvancedServerType) type : null;
for (String version : type.getVersions()) {
boolean success;
printToGui("Downloading: " + name + version + ".jar");
File file = new File(jarDir + type.getName() + version + ".jar");
Path filePath = Paths.get(jarDir + type.getName() + version + ".jar");
printToGui("Downloading: " + typeName + version + ".jar");
File file = new File(jarDirectory + type.getName() + version + ".jar");
Path filePath = Paths.get(jarDirectory + type.getName() + version + ".jar");
switch (type.getName()) {
case "Vanilla":
case "Snapshot":
if (version.equals("Latest")) {
String versionText = readFile(Objects.requireNonNull(advType).getVersionURL());
JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
String latest = jsonObject.getAsJsonObject("latest").get("release").getAsString();
JsonElement ver = jsonObject.getAsJsonArray("versions").get(0);
String versionFile = ver.getAsJsonObject().get("url").getAsString();
versionText = readFile(versionFile);
jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
String jarFile = jsonObject.getAsJsonObject("downloads").getAsJsonObject("server").get("url").getAsString();
setVersion(name, latest);
success = (file.isFile() && latest.equals(getVersion(name))) || downloadFile(jarFile, filePath);
} else {
success = file.isFile() || downloadFile(url + version + Objects.requireNonNull(advType).getDownloadURLPart() + version + ".jar", filePath);
}
success = downloadVanillaJar(advancedServerType, file, downloadURL, filePath, typeName, version);
break;
case "Spigot":
case "Craftbukkit":
case "MCPCplus":
success = file.isFile() || downloadFile(url + name + version + ".jar", filePath);
success = downloadSpigotJar(file, downloadURL, typeName, version, filePath);
break;
case "SpongeVanilla":
newestVersion = stringBetween(readFile(Objects.requireNonNull(advType).getVersionURL() + version), advType.getSrcStart(), advType.getSrcEnd());
success = file.isFile() || downloadFile(url + newestVersion + advType.getDownloadURLPart() + newestVersion + ".jar", filePath);
success = downloadSpongeVanillaJar(advancedServerType, file, downloadURL, filePath, version);
break;
case "Bungee":
newestVersion = stringBetween(readFile(Objects.requireNonNull(advType).getVersionURL()), advType.getSrcStart(), advType.getSrcEnd());
setVersion(name, newestVersion);
success = (file.isFile() && newestVersion.equals(getVersion(name))) || downloadFile(url, filePath);
success = downloadBungeeJar(advancedServerType, file, downloadURL, filePath, typeName);
break;
default:
success = true;
}
if (!success) {
printToGui("Error downloading: " + name + version + ".jar");
throw new FileNotFoundException("Error downloading: " + name + version + ".jar");
printToGui("Error downloading: " + typeName + version + ".jar");
throw new FileNotFoundException("Error downloading: " + typeName + version + ".jar");
}
}
}
}
/**
* Downloads a Spigot, Craftbukkit or MCPC+ .jar file
* @param file <p>The file the .jar file should be saved as</p>
* @param downloadURL <p>The base URL for downloading the .jar file</p>
* @param typeName <p>The name of the selected server type</p>
* @param version <p>The version of the .jar file to download</p>
* @param filePath <p>The path of the .jar file</p>
* @return <p>True if the file exists or the file was successfully downloaded</p>
*/
private static boolean downloadSpigotJar(File file, String downloadURL, String typeName, String version, Path filePath) {
return file.isFile() || downloadFile(downloadURL + typeName + version + ".jar", filePath);
}
/**
* Downloads a Vanilla/Snapshot .jar file according to the input
* @param advancedServerType <p>The advanced server type containing required information</p>
* @param file <p>The file the .jar file should be saved as</p>
* @param downloadURL <p>The base URL for downloading the .jar file</p>
* @param filePath <p>The path of the .jar file</p>
* @param typeName <p>The name of the selected server type</p>
* @param version <p>The version of the .jar file to download</p>
* @return <p>True if the file exists or the file was successfully downloaded</p>
* @throws IOException <p>If something goes horribly wrong</p>
*/
private static boolean downloadVanillaJar(AdvancedServerType advancedServerType, File file, String downloadURL,
Path filePath, String typeName, String version) throws IOException {
if (version.equals("Latest")) {
String versionText = readFile(Objects.requireNonNull(advancedServerType).getVersionURL());
JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
String latest = jsonObject.getAsJsonObject("latest").get("release").getAsString();
JsonElement ver = jsonObject.getAsJsonArray("versions").get(0);
String versionFile = ver.getAsJsonObject().get("url").getAsString();
versionText = readFile(versionFile);
jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
String jarFile = jsonObject.getAsJsonObject("downloads").getAsJsonObject("server").get("url").getAsString();
setVersion(typeName, latest);
return (file.isFile() && latest.equals(getVersion(typeName))) || downloadFile(jarFile, filePath);
} else {
return file.isFile() || downloadFile(downloadURL + version +
Objects.requireNonNull(advancedServerType).getDownloadURLPart() + version + ".jar", filePath);
}
}
/**
* Downloads a SpongeVanilla .jar file according to the input
* @param advancedServerType <p>The advanced server type containing required information</p>
* @param file <p>The file the .jar file should be saved as</p>
* @param downloadURL <p>The base URL for downloading the .jar file</p>
* @param filePath <p>The path of the .jar file</p>
* @param version <p>The version of the .jar file to download</p>
* @return <p>True if the file exists or the file was successfully downloaded</p>
* @throws IOException <p>If something goes horribly wrong</p>
*/
private static boolean downloadSpongeVanillaJar(AdvancedServerType advancedServerType, File file,
String downloadURL, Path filePath,
String version) throws IOException {
String newestVersion = stringBetween(readFile(Objects.requireNonNull(advancedServerType).getVersionURL()
+ version), advancedServerType.getSrcStart(), advancedServerType.getSrcEnd());
return file.isFile() || downloadFile(downloadURL + newestVersion + advancedServerType.getDownloadURLPart()
+ newestVersion + ".jar", filePath);
}
/**
* Downloads a Bungee .jar file according to the input
* @param advancedServerType <p>The advanced server type containing required information</p>
* @param file <p>The file the .jar file should be saved as</p>
* @param downloadURL <p>The base URL for downloading the .jar file</p>
* @param filePath <p>The path of the .jar file</p>
* @param typeName <p>The name of the selected server type</p>
* @return <p>True if the file exists or the file was successfully downloaded</p>
* @throws IOException <p>If something goes horribly wrong</p>
*/
private static boolean downloadBungeeJar(AdvancedServerType advancedServerType, File file,
String downloadURL, Path filePath, String typeName) throws IOException {
String newestVersion = stringBetween(readFile(Objects.requireNonNull(advancedServerType).getVersionURL()),
advancedServerType.getSrcStart(), advancedServerType.getSrcEnd());
setVersion(typeName, newestVersion);
return (file.isFile() && newestVersion.equals(getVersion(typeName))) || downloadFile(downloadURL, filePath);
}
/**
* Returns the current version of a type
*
* @param type The version type
* @return The version string
* @param type <p>The version type</p>
* @return <p>The version string</p>
*/
private static String getVersion(String type) {
switch (type) {
@ -628,10 +686,9 @@ public class Profile {
}
/**
* Sets a server type's last downloaded version.
*
* @param type The version type
* @param version The version string
* Sets a server type's last downloaded version
* @param type <p>The version type</p>
* @param version <p>The version string</p>
*/
private static void setVersion(String type, String version) {
if (!type.equals("")) {

View File

@ -13,6 +13,16 @@ public class AdvancedServerType extends ServerType {
private final String srcStart;
private final String srcEnd;
/**
* Instantiates a new Advanced server type
* @param name <p>The name of the server type</p>
* @param versions <p>A list of one or more server versions for the type</p>
* @param versionURL <p>The URL for checking last version for server type</p>
* @param srcStart <p>The string in the version file marking the start of the newest version entry</p>
* @param srcEnd <p>The string in the version file marking the end of the newest version entry</p>
* @param downloadURL <p>The URL used for downloading .jar files</p>
* @param downloadURLPart <p>An extra part for the download URL</p>
*/
AdvancedServerType(String name, String[] versions, String versionURL, String srcStart, String srcEnd, String downloadURL, String downloadURLPart) {
super(name, versions, downloadURL);
this.srcStart = srcStart;
@ -21,18 +31,34 @@ public class AdvancedServerType extends ServerType {
this.downloadURLPart = downloadURLPart;
}
/**
* Gets the URL used for downloading latest version information
* @return <p>The latest version URL</p>
*/
public String getVersionURL() {
return this.versionURL;
}
/**
* Gets an additional part of the download URL
* @return <p>Additional download URL part</p>
*/
public String getDownloadURLPart() {
return this.downloadURLPart;
}
/**
* Gets the string marking the start of the latest server version in the version document
* @return <p>A string marking the start of the latest version</p>
*/
public String getSrcStart() {
return this.srcStart;
}
/**
* Gets the string marking the end of the latest server version in the version document
* @return <p>A string marking the end of the latest version</p>
*/
public String getSrcEnd() {
return this.srcEnd;
}

View File

@ -27,7 +27,7 @@ public class Server {
private static final String[] ramList = {
"512M", "1G", "2G", "3G", "4G", "5G", "6G", "7G", "8G", "9G", "10G","11G", "12G", "13G", "14G", "15G", "16G"
};
private static final String jarDir = Main.getAppDir() + File.separator + "files" + File.separator + "Jars" + File.separator;
private static final String jarDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator + "Jars" + File.separator;
private final String name;
private String path;
@ -185,11 +185,7 @@ public class Server {
* @param name The name of the player to remove
*/
public void removePlayer(String name) {
for (int i = 0; i < playerList.size(); i++) {
if (name.equals(playerList.get(i))) {
playerList.remove(i);
}
}
playerList.removeIf(player -> player.equals(name));
Profile.getGUI().removePlayer(name);
}
@ -271,7 +267,7 @@ public class Server {
private boolean run() {
if (this.enabled) {
this.started = true;
if (!Profile.getCurrent().getDownloadJars()) {
if (!Profile.getCurrent().getDownloadAllAvailableJARFiles()) {
try {
Profile.getGUI().setStatus("Downloading jar...");
this.downloadJar();
@ -295,8 +291,8 @@ public class Server {
try {
ProcessBuilder builder;
String serverPath;
if (Profile.getCurrent().getDownloadJars() && !type.getName().equals("Custom")) {
serverPath = jarDir + this.getType();
if (Profile.getCurrent().getDownloadAllAvailableJARFiles() && !type.getName().equals("Custom")) {
serverPath = jarDirectory + this.getType();
} else {
serverPath = this.path + File.separator + this.getType();
}
@ -347,7 +343,6 @@ public class Server {
/**
* Downloads necessary .jar file for the server.
* This is unfortunately hardcoded since there is no golden standard, and we only host some jars ourselves.
*
* @throws FileNotFoundException if the file was not found and could not be acquired.
*/
private void downloadJar() throws FileNotFoundException {
@ -438,9 +433,8 @@ public class Server {
/**
* Returns the current version of a type
*
* @param type The version type
* @return The version string
* @param type <p>The version type</p>
* @return <p>The version string</p>
*/
private String getVersion(String type) {
switch (type) {
@ -459,9 +453,8 @@ public class Server {
/**
* Sets a server type's last downloaded version.
*
* @param type The version type
* @param version The version string
* @param type <p>The version type</p>
* @param version <p>The version string</p>
*/
private void setVersion(String type, String version) {
if (!type.equals("")) {
@ -483,9 +476,8 @@ public class Server {
/**
* Sends a command to this server through its writer.
*
* @param command Command to send to the server
* @throws IOException If write fails
* @param command <p>Command to send to the server</p>
* @throws IOException <p>If write fails</p>
*/
public void sendCommand(String command) throws IOException {
if (this.process != null && this.writer != null) {

View File

@ -21,6 +21,12 @@ public class ServerType {
private final String downloadURL;
private static final ArrayList<ServerType> serverTypes = new ArrayList<>();
/**
* Instantiates a new server type
* @param name <p>The name of the server type</p>
* @param versions <p>A list of one or more server versions for the type</p>
* @param downloadURL <p>The URL used for downloading .jar files</p>
*/
ServerType(String name, String[] versions, String downloadURL) {
this.name = name;
this.versions = versions;
@ -28,41 +34,55 @@ public class ServerType {
serverTypes.add(this);
}
/**
* Gets the name of the server type
* @return <p>Server type name</p>
*/
public String getName() {
return this.name;
}
/**
* Gets a list of versions available for the server type
* @return <p>A list of server versions</p>
*/
public String[] getVersions() {
return this.versions;
}
/**
* Gets the url used for downloading JAR files
* @return <p>A download URL</p>
*/
public String getDownloadURL() {
return this.downloadURL;
}
/**
* Gets all instantiated server types
* @return <p>A list of server types</p>
*/
public static ArrayList<ServerType> getServerTypes() {
return serverTypes;
}
/**
* Gets a list of all server types' names.
*
* @return A list of strings
* @return <p>A list of strings</p>
*/
public static String[] getTypeNames() {
ArrayList<ServerType> types = ServerType.getServerTypes();
String[] serverTypes = new String[types.size()];
String[] serverTypeNames = new String[types.size()];
for (int i = 0; i < types.size(); i++) {
serverTypes[i] = types.get(i).getName();
serverTypeNames[i] = types.get(i).getName();
}
return serverTypes;
return serverTypeNames;
}
/**
* Gets a server type by name.
*
* @param name Then name of the server type
* @return A ServerType
* Gets a server type by the given name
* @param name <p>Then name of the server type</p>
* @return <p>A ServerType</p>
*/
public static ServerType getByName(String name) {
for (ServerType serverType : serverTypes) {
@ -75,8 +95,7 @@ public class ServerType {
/**
* Reads valid server types and version from a file, and creates their objects.
*
* @throws ConfigurationException if anything goes wrong.
* @throws ConfigurationException <p>If anything goes wrong</p>
*/
public static void loadServerTypes() throws ConfigurationException {
if (serverTypes.isEmpty()) {
@ -87,20 +106,22 @@ public class ServerType {
throw new ConfigurationException("Server type configuration file is missing.");
}
while (file.hasNextLine()) {
String[] str = file.nextLine().split(";", -1);
int len = str.length;
String[] ver;
if (str[1].contains(",")) {
ver = str[1].split(",", -1);
//Splits the next file line into arguments
String[] fileLine = file.nextLine().split(";", -1);
int lineLength = fileLine.length;
//Gets list of server versions from file line
String[] serverVersion;
if (fileLine[1].contains(",")) {
serverVersion = fileLine[1].split(",", -1);
} else {
ver = new String[]{str[1]};
serverVersion = new String[]{fileLine[1]};
}
switch (len) {
switch (lineLength) {
case 7:
new AdvancedServerType(str[0], ver, str[2], str[3], str[4], str[5], str[6]);
new AdvancedServerType(fileLine[0], serverVersion, fileLine[2], fileLine[3], fileLine[4], fileLine[5], fileLine[6]);
break;
case 3:
new ServerType(str[0], ver, str[2]);
new ServerType(fileLine[0], serverVersion, fileLine[2]);
break;
default:
throw new ConfigurationException("Error: Configuration file invalid.");

View File

@ -63,7 +63,8 @@ public class Console implements ActionListener, KeyListener {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == textInput) { //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) {
java.lang.String text = textInput.getText();
Profile.getCurrent().sendCommand(this.name, text);
commands.add(text);
@ -77,19 +78,11 @@ public class Console implements ActionListener, KeyListener {
@Override
public void keyPressed(KeyEvent e) {
//Cycles through previously used commands
if (e.getKeyCode() == KeyEvent.VK_UP) {
if (commands.size() > 0 && commandIndex > 0) {
textInput.setText(commands.get(--commandIndex));
}
showPreviousCommand();
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
if (commands.size() > 0) {
if (commandIndex == commands.size() - 1) {
commandIndex++;
textInput.setText("");
} else if (commandIndex >= 0 && commandIndex <= commands.size() - 1) {
textInput.setText(commands.get(++commandIndex));
}
}
showNextCommand();
}
}
@ -100,4 +93,33 @@ public class Console implements ActionListener, KeyListener {
@Override
public void keyTyped(KeyEvent e) {
}
/**
* Shows the previously executed command in the input field
*
* <p>Shows the previously executed command if a command was just executed.
* Shows the command executed earlier if already showing a previously executed command.</p>
*/
private void showPreviousCommand() {
if (commands.size() > 0 && commandIndex > 0) {
textInput.setText(commands.get(--commandIndex));
}
}
/**
* Shows the next previously executed command or clears the input field
*
* <p>Shows the next previously executed command if such a command exists.
* Clears the input field if no next used command exists.</p>
*/
private void showNextCommand() {
if (commands.size() > 0) {
if (commandIndex == commands.size() - 1) {
commandIndex++;
textInput.setText("");
} else if (commandIndex >= 0 && commandIndex <= commands.size() - 1) {
textInput.setText(commands.get(++commandIndex));
}
}
}
}

View File

@ -1,5 +1,6 @@
package net.knarcraft.minecraftserverlauncher.userinterface;
import net.knarcraft.minecraftserverlauncher.Shared;
import net.knarcraft.minecraftserverlauncher.profile.Collection;
import net.knarcraft.minecraftserverlauncher.Main;
import net.knarcraft.minecraftserverlauncher.server.Server;
@ -10,8 +11,6 @@ import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Scanner;
@ -60,7 +59,7 @@ public class GUI implements ActionListener {
private TrayIcon trayIcon;
/**
* Create the application window.
* Creates the application window
*/
public GUI() throws IOException {
initialize(440, 170);
@ -69,10 +68,9 @@ public class GUI implements ActionListener {
}
/**
* Creates the application window with a preferred width and height.
*
* @param width The preferred width
* @param height The preferred height
* Creates the application window with a preferred width and height
* @param width <p>The preferred width</p>
* @param height <p>The preferred height</p>
*/
public GUI(int width, int height) throws IOException {
initialize(width, height);
@ -96,7 +94,7 @@ public class GUI implements ActionListener {
*/
public void setStatus(String text) {
this.lblStatuslabel.setText(text);
try (PrintWriter file = new PrintWriter(new FileWriter(Main.getAppDir() + File.separator + "latestrun.log", true))) {
try (PrintWriter file = new PrintWriter(new FileWriter(Main.getApplicationWorkDirectory() + File.separator + "latestrun.log", true))) {
file.println(text);
} catch (IOException e ) {
e.printStackTrace();
@ -152,7 +150,7 @@ public class GUI implements ActionListener {
}
chckbxmntmRunInBackground.setState(Profile.getCurrent().getRunInBackground());
chckbxmntmDelayStartup.setState(Profile.getCurrent().getDelayStartup() > 0);
chckbxmntmDownloadJars.setState(Profile.getCurrent().getDownloadJars());
chckbxmntmDownloadJars.setState(Profile.getCurrent().getDownloadAllAvailableJARFiles());
this.targetServer.removeAllItems();
this.targetServer.addItem("All");
for (Collection collection : Profile.getCurrent().getCollections()) {
@ -547,46 +545,21 @@ public class GUI implements ActionListener {
} else if (e.getSource() == chckbxmntmDownloadJars) {
downloadJars();
} else if (e.getSource() == mntmErrors) {
goToURL("https://archive.knarcraft.net/BungeeMinecraftServerLauncherInfo/");
Shared.goToURL("https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherInfo/");
} else if (e.getSource() == mntmSetup) {
JOptionPane.showMessageDialog(
null,
setupText,
"Setup",
JOptionPane.INFORMATION_MESSAGE
);
Profile.showMessage("Setup", setupText);
} else if (e.getSource() == mntmManualUpdate) {
goToURL("https://git.knarcraft.net/EpicKnarvik97/Minecraft-Server-Launcher");
Shared.goToURL("https://git.knarcraft.net/KnarCraft/Minecraft-Server-Launcher/releases");
} else if (e.getSource() == mntmRunInBackground) {
JOptionPane.showMessageDialog(
null,
runInBackgroundText,
"Run in background",
JOptionPane.INFORMATION_MESSAGE
);
Profile.showMessage("Run in background", runInBackgroundText);
} else if (e.getSource() == mntmDelayStartup) {
JOptionPane.showMessageDialog(
null,
delayStartupText,
"Delay startup",
JOptionPane.INFORMATION_MESSAGE
);
Profile.showMessage("Delay startup", delayStartupText);
} else if (e.getSource() == mntmDownloadJars) {
JOptionPane.showMessageDialog(
null,
downloadJarsText,
"Download jars",
JOptionPane.INFORMATION_MESSAGE
);
Profile.showMessage("Download jars", downloadJarsText);
} else if (e.getSource() == mntmAbout) {
JOptionPane.showMessageDialog(
null,
aboutText,
"About",
JOptionPane.INFORMATION_MESSAGE
);
Profile.showMessage("About", aboutText);
} else if (e.getSource() == mntmStory) {
goToURL("https://archive.knarcraft.net/BungeeminecraftserverlauncherStory/");
Shared.goToURL("https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherStory/");
} else if (e.getSource() == btnStartServer) {
try {
Profile.getCurrent().save();
@ -648,7 +621,7 @@ public class GUI implements ActionListener {
Profile.getCurrent().sendCommand(selectedServerValue, "reload");
}
} else if (e.getSource() == btnServerConsoles) {
ServerConsoles.show();
ServerConsoles.setAsVisible();
} else if (e.getSource() == targetServer) {
updatePlayers();
}
@ -691,12 +664,7 @@ public class GUI implements ActionListener {
setStatus("Servers are stopping...");
Server.stop();
} catch (IOException e1) {
JOptionPane.showMessageDialog(
null,
"Could not stop server.",
"Error",
JOptionPane.ERROR_MESSAGE
);
Profile.showError("Could not stop server.");
e1.printStackTrace();
}
}
@ -716,12 +684,7 @@ public class GUI implements ActionListener {
Objects.requireNonNull(profile).setDelayStartup(0);
}
} else {
JOptionPane.showMessageDialog(
null,
"No profile selected",
"Error",
JOptionPane.ERROR_MESSAGE
);
Profile.showError("No profile selected");
}
}
@ -734,12 +697,7 @@ public class GUI implements ActionListener {
Profile profile = Profile.getProfile(selected.toString());
Objects.requireNonNull(profile).setRunInBackground(chckbxmntmRunInBackground.isSelected());
} else {
JOptionPane.showMessageDialog(
null,
"No profile selected",
"Error",
JOptionPane.ERROR_MESSAGE
);
Profile.showError("No profile selected");
}
}
@ -750,14 +708,9 @@ public class GUI implements ActionListener {
Object selected = profiles.getSelectedItem();
if (selected != null) {
Profile profile = Profile.getProfile(selected.toString());
Objects.requireNonNull(profile).setDownloadJars(chckbxmntmDownloadJars.isSelected());
Objects.requireNonNull(profile).setDownloadAllAvailableJARFiles(chckbxmntmDownloadJars.isSelected());
} else {
JOptionPane.showMessageDialog(
null,
"No profile selected",
"Error",
JOptionPane.ERROR_MESSAGE
);
Profile.showError("No profile selected");
}
}
@ -770,7 +723,6 @@ public class GUI implements ActionListener {
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()) {
@ -781,7 +733,7 @@ public class GUI implements ActionListener {
if (!destFolder.exists()) {
if (destFolder.mkdirs()) {
try {
copyFolder(srcFolder, destFolder);
Shared.copyFolder(this, srcFolder, destFolder);
} catch (IOException e) {
e.printStackTrace();
return;
@ -817,20 +769,6 @@ public class GUI implements ActionListener {
}
}
/**
* Opens an url in the user's default application.
*
* @param url URL to open
*/
private void goToURL(String url) {
java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
try {
desktop.browse(new URI(url));
} catch (URISyntaxException | IOException e1) {
e1.printStackTrace();
}
}
/**
* Loads popup messages from a text file.
*/
@ -858,42 +796,4 @@ public class GUI implements ActionListener {
}
}
}
/**
* Recursivly copies a folder to another location
*
* @param src The folder to copy
* @param dest Target destination
* @throws IOException If we can't start a file stream
*/
private void copyFolder(File src, File dest) throws IOException{
if (!src.isDirectory()) {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) > 0){
out.write(buffer, 0, length);
}
in.close();
out.close();
this.setStatus("Copied file " + src);
} else {
if(!dest.exists()){
if (dest.mkdir()) {
this.setStatus("Copied directory " + src);
} else {
return;
}
}
String[] files = src.list();
if (files != null) {
for (String file : files) {
File srcFile = new File(src, file);
File destFile = new File(dest, file);
copyFolder(srcFile, destFile);
}
}
}
}
}

View File

@ -15,25 +15,40 @@ import java.awt.BorderLayout;
*/
public class ServerConsoles {
private static JFrame frame;
private static JTabbedPane consolesTab;
private static JTabbedPane consolesTabbedPane;
/**
* Initializes the server consoles frame
*/
public ServerConsoles() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
consolesTab = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(consolesTab, BorderLayout.CENTER);
consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER);
}
public static Console addTab(String name) {
return new Console(consolesTab, name);
/**
* Adds a new console tab
* @param name <p>The name of the consoles tab</p>
* @return <p>A new console element with the new tabbed pane</p>
*/
public static Console addConsoleTab(String name) {
return new Console(consolesTabbedPane, name);
}
public static void show() {
/**
* Sets the server consoles frame as visible
*/
public static void setAsVisible() {
frame.setVisible(true);
}
public static JTabbedPane getTab() {
return consolesTab;
/**
* Returns the tabbed pane containing the server consoles
* @return <p>A tabbed pane</p>
*/
public static JTabbedPane getTabbedPane() {
return consolesTabbedPane;
}
}

View File

@ -1,6 +1,5 @@
package net.knarcraft.minecraftserverlauncher;
import net.knarcraft.minecraftserverlauncher.profile.Profile;
import net.knarcraft.minecraftserverlauncher.server.ServerType;
import org.junit.Test;
@ -9,9 +8,8 @@ import java.io.IOException;
public class DownloadTests {
@Test
public void downloadJarsTest() throws IOException, ConfigurationException {
// Will currently always fail since knarcraft.net is down.
public void downloadJarsTest() throws ConfigurationException {
ServerType.loadServerTypes();
Profile.downloadJars();
//Profile.downloadJars();
}
}