Compare commits
120 Commits
v1.0.2-alp
...
master
Author | SHA1 | Date | |
---|---|---|---|
ee99312a12 | |||
545e7bacc6 | |||
b142b6d05e | |||
166d63f1b2 | |||
8f25fa2796 | |||
3467c900f0 | |||
9f092a73fe | |||
50b9188229 | |||
b021de5594 | |||
a1ae162b07 | |||
b2ee22eb7b | |||
65ede11ab5 | |||
c26a3bc3b5 | |||
71e47acbb0 | |||
60fdcf5ddc | |||
bf77c13072 | |||
849655bfc6 | |||
e8ecee1cd0 | |||
5e24d5daa8 | |||
9532683301 | |||
365d08f2e2 | |||
9d8531535d | |||
30de4b2139 | |||
133e335905 | |||
44d8d6ee6b | |||
cd396eee6b | |||
c67f3bdd2c | |||
8476c78589 | |||
a79300732d | |||
b6baa9ad6f | |||
c2f12a1a49 | |||
5030b4932b | |||
e47b34a472 | |||
28291cf4c3 | |||
f8ba6e7ad1 | |||
c9c2a1b43b | |||
0425617f4c | |||
12189c12d7 | |||
00cfe78491 | |||
dc362eb2c8 | |||
73faa4408e | |||
85febdf41b | |||
6ca49d2ccd | |||
429b1fcec0 | |||
33795a90a9 | |||
e4be75b770 | |||
0018816d90 | |||
f1eead3807 | |||
6ec44f1f92 | |||
d61239c417 | |||
32c17c6005 | |||
52eacb9980 | |||
043f2045e6 | |||
51ceac69da | |||
123a8eddda | |||
8cdb1f143c | |||
3254481326 | |||
fb705f4e13 | |||
15dd8db31b | |||
fa6a0df4c7 | |||
8b0423e231 | |||
b1454b1156 | |||
a4d7b1041c | |||
a705fc8b3e | |||
5fe4384b59 | |||
2f31a6c248 | |||
70f8b87eef | |||
a9332c0a6c | |||
2b6315a914 | |||
262418ff7f | |||
31d167a8a4 | |||
44b9bcc960 | |||
9f2dda7c6b | |||
6c0e352649 | |||
5058383f93 | |||
39a8c14ece | |||
5b15fea7b3 | |||
52946c9aec | |||
83f8834530 | |||
d06cc66f31 | |||
3d6476b1ef | |||
070f87222b | |||
1300f6808b | |||
23161c1a8d | |||
4f60ed5d10 | |||
2acc6f4d13 | |||
2f8117ebfa | |||
2008ec8fd1 | |||
d06cf4114a | |||
e71e95df7f | |||
d60e16b4a5 | |||
cc0a5a1659 | |||
a3de8a9f6c | |||
2ed6b8bedb | |||
ba9b192790 | |||
a5db6b3a70 | |||
1d49229b87 | |||
c721aef2a6 | |||
8e626d8097 | |||
0bf355c4de | |||
70d064e590 | |||
ab6453cdc3 | |||
094a1facb2 | |||
a2d4d491ba | |||
b144bbb903 | |||
26cc5370e2 | |||
9ef314b178 | |||
f0ad156e16 | |||
1e34571ca6 | |||
040740db84 | |||
c59cbcefbb | |||
f841d73e2d | |||
194686b9d8 | |||
4901ea0627 | |||
cade97adbe | |||
![]() |
6869743844 | ||
998b901687 | |||
21737b7549 | |||
c88e90b5b5 | |||
a3a8e4f377 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -14,7 +14,6 @@
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
*.zip
|
||||
@ -29,4 +28,5 @@ hs_err_pid*
|
||||
|
||||
bin/
|
||||
out/
|
||||
.idea
|
||||
*.txt
|
24
Jenkinsfile
vendored
Normal file
24
Jenkinsfile
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
echo 'Building...'
|
||||
sh 'mvn clean & mvn validate & mvn compile'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
steps {
|
||||
echo 'Testing...'
|
||||
sh 'mvn test'
|
||||
}
|
||||
}
|
||||
stage('Deploy') {
|
||||
steps {
|
||||
echo 'Deploying...'
|
||||
sh 'mvn verify -Dmaven.test.skip=true'
|
||||
archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
META-INF/MANIFEST.MF
Normal file
4
META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,4 @@
|
||||
Manifest-Version: 1.0
|
||||
Class-Path: gson-2.8.5.jar
|
||||
Main-Class: net.knarcraft.minecraftserverlauncher.Main
|
||||
|
16
README.md
16
README.md
@ -1,6 +1,14 @@
|
||||
# Minecraft-Server-Launcher
|
||||
I originally created this software in 2013 using AutoIt. Since I am now learning Java, I have recreated it in Java.
|
||||
The original version can be found at: https://knarcraft.net/Downloads/Bungeeminecraftserverlauncher/
|
||||
Its goal is to do everything the original does, just better. The original is 1595 lines of code repetition and dirty code. I had no prior programming experience when I first started working on the original, which is why it became such a mess.
|
||||
|
||||
The code is now in a fully working state. It is still missing an auto update feature, but it can be used, and is fully functional.
|
||||
I originally created this software in 2013 using AutoIt. After learning Java, I recreated it in Java. The original
|
||||
version can be found at: https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncher/
|
||||
This version's goal is to do everything the original does, just better. The original is 1595 lines of code repetition
|
||||
and dirty code. I had no prior programming experience when I first started working on the original, which is why it
|
||||
became such a mess.
|
||||
|
||||
The software is in a fully working stage with a functional updater. The software is still in beta because there are
|
||||
still a lot of things I want to change and small annoyances. The software is fully portable. Make sure to put it in its
|
||||
own folder as it will create lots of files.
|
||||
|
||||
The updater will move the new version to minecraft-server-launcher.jar, so you should rename the downloaded file to this
|
||||
if it's named something else to avoid confusion.
|
@ -1,5 +0,0 @@
|
||||
setup=1. Create a new profile, or use the default._BREAK_2. Click on the add server button and insert the name of your server._BREAK_3. Navigate to the servers tab, and find your server._BREAK_4. Fill in all the settings with what you want, and remember to check Enabled._BREAK_5. Navigate back to the Control panel and click Start servers
|
||||
runinbk=The program will run in the background. You don't need to have the gui open all the time._BREAK_When in background mode, you can left click on the tray icon to open the gui again. To exit the program, right click the tray icon and press exit.
|
||||
delaystartup=This adds a delay (in seconds) between the start of each server._BREAK_This option should be used for heavy servers with many plugins, but may not be needed on a single server or servers using a few plugins.
|
||||
downloadjars=This option will download all the .jar files available in the program._BREAK_Instead of downloading .jar files when you start servers, it will download all files you don't already have, on startup._BREAK_This will be faster and more reliable than usual._BREAK_You need to restart the software for this setting to take action.
|
||||
about=This software was created to start and manage several servers simultaneously._BREAK_You no longer have to do the tedious work of manually downloading different .jar files every time you want to try something new.
|
|
@ -1,8 +0,0 @@
|
||||
Vanilla;Latest,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/;/minecraft_server.
|
||||
Snapshot;Latest;https://launchermeta.mojang.com/mc/game/version_manifest.json;"snapshot":";";https://s3.amazonaws.com/Minecraft.Download/versions/;/minecraft_server.
|
||||
SpongeVanilla;1.12.2,1.11.2,1.10.2,1.8.9;https://dl-api.spongepowered.org/v1/org.spongepowered/spongevanilla/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongevanilla/;/spongevanilla-
|
||||
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;
|
||||
Spigot;1.12.2,1.11.2,1.10.2,1.9.4,1.9.4,1.8.8,1.7.10,1.6.4,1.5.2,1.4.7;https://knarcraft.net/Api/Download/bungeeminecraftserverlauncher/jars/Spigot/
|
||||
MCPCplus;1.6.4,1.6.2,1.5.2,1.4.7;https://knarcraft.net/Api/Download/bungeeminecraftserverlauncher/jars/MCPC+/
|
||||
Craftbukkit;1.12.2,1.11.2,1.10.2,1.9.4,1.8.8,1.7.10,1.6.4,1.5.2,1.4.6,1.3.2,1.2.5,1.1,1.0;https://knarcraft.net/Api/Download/bungeeminecraftserverlauncher/jars/Bukkit/
|
||||
Custom;;
|
Can't render this file because it contains an unexpected character in line 1 and column 156.
|
@ -1,3 +1,3 @@
|
||||
As this is a personal one-man project, I prefer to stay in charge of the code.
|
||||
I appreciate code fixing mistakes, or code improvements, but the software's functionality or purpose, should not be changed.
|
||||
I might change anything at any time, so you might want to keep that in mind before doing big changes yourself.
|
||||
As this is a personal one-man project, I prefer to stay in charge of the code. I appreciate code fixing mistakes, or
|
||||
code improvements, but the software's functionality or purpose, should not be changed. I might change anything at any
|
||||
time, so you might want to keep that in mind before doing big changes yourself.
|
||||
|
@ -1,6 +1,7 @@
|
||||
Fixes # .
|
||||
|
||||
Proposed changes:
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
|
135
pom.xml
Normal file
135
pom.xml
Normal file
@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>net.knarcraft.minecraftserverlauncher</groupId>
|
||||
<artifactId>minecraft-server-launcher</artifactId>
|
||||
<version>1.1-SNAPSHOT</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Minecraft Server Launcher</name>
|
||||
<url>https://git.knarcraft.net/KnarCraft/Minecraft-Server-Launcher</url>
|
||||
<inceptionYear>2013</inceptionYear>
|
||||
|
||||
<licenses>
|
||||
<license>
|
||||
<name>ALL RIGHTS RESERVED</name>
|
||||
<url>https://git.knarcraft.net/KnarCraft/Minecraft-Server-Launcher/LICENCE</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>EpicKnarvik97</id>
|
||||
<name>Kristian Knarvik</name>
|
||||
<url>https://kristianknarvik.knarcraft.net</url>
|
||||
<roles>
|
||||
<role>leader</role>
|
||||
<role>developer</role>
|
||||
</roles>
|
||||
<timezone>Europe/Oslo</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<!-- Build an executable JAR -->
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
<mainClass>net.knarcraft.minecraftserverlauncher.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<appendAssemblyId>true</appendAssemblyId>
|
||||
<archive>
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<mainClass>net.knarcraft.minecraftserverlauncher.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-jar-with-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-dependencies</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>copy-dependencies</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/lib</outputDirectory>
|
||||
<overWriteReleases>true</overWriteReleases>
|
||||
<overWriteSnapshots>true</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<directory>${project.basedir}/target</directory>
|
||||
<outputDirectory>${project.build.directory}/classes</outputDirectory>
|
||||
<finalName>${project.artifactId}-${project.version}</finalName>
|
||||
<testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
|
||||
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
|
||||
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/src/main/resources</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>${project.basedir}/src/test/resources</directory>
|
||||
</testResource>
|
||||
</testResources>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.7.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -1,3 +0,0 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: net.knarcraft.serverlauncher.Main
|
||||
|
116
src/main/java/net/knarcraft/minecraftserverlauncher/Main.java
Normal file
116
src/main/java/net/knarcraft/minecraftserverlauncher/Main.java
Normal file
@ -0,0 +1,116 @@
|
||||
package net.knarcraft.minecraftserverlauncher;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.profile.Collection;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.Updater;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
//Java 8 required.
|
||||
|
||||
/**
|
||||
* A software for managing Minecraft servers.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version b1.3.4
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
public class Main {
|
||||
private static final String updateChannel = "beta";
|
||||
private static final String updateURL = "https://api.knarcraft.net/minecraftserverlauncher";
|
||||
private static final ServerLauncherController controller = ServerLauncherController.getInstance();
|
||||
private static String applicationWorkDirectory;
|
||||
private static boolean serversAreRunning = false;
|
||||
private static ServerLauncherGUI gui;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
String logFile = Main.getApplicationWorkDirectory() + File.separator + "latestrun.log";
|
||||
CommonFunctions.writeFile(logFile, "[Info]: Starting Minecraft Server Launcher v." +
|
||||
Updater.getCurrentVersion()[1]);
|
||||
try {
|
||||
Updater.checkForUpdate(updateURL, updateChannel);
|
||||
} catch (IOException e) {
|
||||
CommonFunctions.appendFile(logFile, "[Warning]: Unable to complete update procedure: " + e.getMessage());
|
||||
}
|
||||
EventQueue.invokeLater(() -> {
|
||||
try {
|
||||
ServerConsoles.instantiate();
|
||||
controller.loadState();
|
||||
gui = controller.getGUI();
|
||||
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
|
||||
exec.scheduleAtFixedRate(Main::updateServersRunningState, 10, 500, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller used by the software
|
||||
*
|
||||
* @return <p>The controller used by the software</p>
|
||||
*/
|
||||
public static ServerLauncherController getController() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the directory the .jar file is running from
|
||||
*
|
||||
* @return A string path
|
||||
*/
|
||||
public static String getApplicationWorkDirectory() {
|
||||
if (applicationWorkDirectory == null) {
|
||||
try {
|
||||
applicationWorkDirectory = String.valueOf(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile());
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
return applicationWorkDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the software state if the servers' running state has changed
|
||||
*/
|
||||
private static void updateServersRunningState() {
|
||||
boolean runningNew = serversRunning();
|
||||
if (serversAreRunning && !runningNew) {
|
||||
//Servers stopped running
|
||||
ServerHandler.serversStopped();
|
||||
gui.updateGUIElementsWhenServersStartOrStop(false);
|
||||
gui.setStatus("Servers are stopped");
|
||||
} else if (!serversAreRunning && runningNew) {
|
||||
//Servers started running
|
||||
gui.updateGUIElementsWhenServersStartOrStop(true);
|
||||
}
|
||||
serversAreRunning = runningNew;
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through all servers and looks for any running servers
|
||||
*
|
||||
* @return <p>Whether at least one server is running</p>
|
||||
*/
|
||||
private static boolean serversRunning() {
|
||||
int serversRunning = 0;
|
||||
for (Collection collection : controller.getCurrentProfile().getCollections()) {
|
||||
if (collection.getServer().isStarted() ||
|
||||
(collection.getServer().getProcess() != null && collection.getServer().getProcess().isAlive())) {
|
||||
serversRunning++;
|
||||
}
|
||||
}
|
||||
return serversRunning > 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package net.knarcraft.minecraftserverlauncher.profile;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.server.Server;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.Console;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerTab;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
/**
|
||||
* Acts as a wrapper for objects necessary for each server.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Collection {
|
||||
private final Server server;
|
||||
private final ServerTab serverTab;
|
||||
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) throws ConfigurationException {
|
||||
this.serverTab = new ServerTab(name);
|
||||
this.server = new Server(name);
|
||||
this.serverConsole = ServerConsoles.addConsoleTab(name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new collection with the given server
|
||||
*
|
||||
* @param server <p>The server used for as part of the collection</p>
|
||||
* @throws ConfigurationException <p>If unable to configure the collection</p>
|
||||
*/
|
||||
Collection(Server server) throws ConfigurationException {
|
||||
String serverName = server.getName();
|
||||
this.serverTab = new ServerTab(serverName);
|
||||
this.server = server;
|
||||
this.serverConsole = ServerConsoles.addConsoleTab(serverName);
|
||||
this.name = serverName;
|
||||
this.serverTab.setData(server.getPath(), server.isEnabled(), server.getTypeName(), server.getServerVersion(),
|
||||
server.getMaxRam());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,257 @@
|
||||
package net.knarcraft.minecraftserverlauncher.profile;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.server.Server;
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerConsoles;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import javax.swing.*;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Keeps track of a set of servers and some user settings
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Profile {
|
||||
|
||||
private static final ServerLauncherGUI serverLauncherGui = Main.getController().getGUI();
|
||||
private final List<Collection> collections;
|
||||
private final String name;
|
||||
private boolean runInBackground;
|
||||
private int delayStartup;
|
||||
|
||||
/**
|
||||
* Instantiates a new default profile
|
||||
*
|
||||
* @param name <p>The name of the profile</p>
|
||||
*/
|
||||
public Profile(String name) {
|
||||
this.collections = new ArrayList<>();
|
||||
this.name = name;
|
||||
this.runInBackground = false;
|
||||
this.delayStartup = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.name = name;
|
||||
this.runInBackground = runInBackground;
|
||||
this.delayStartup = delayStartup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a profile, and creates a profile with the data.
|
||||
*
|
||||
* @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(profileData[0], Boolean.parseBoolean(profileData[1]), Integer.parseInt(profileData[2]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the software should keep running in the background
|
||||
*
|
||||
* @return <p>Whether the software should keep running in the background</p>
|
||||
*/
|
||||
public boolean getRunInBackground() {
|
||||
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) {
|
||||
this.runInBackground = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of seconds to delay startup
|
||||
*
|
||||
* @return <p>The number of seconds to delay startup</p>
|
||||
*/
|
||||
public int getDelayStartup() {
|
||||
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) {
|
||||
if (value >= 0) {
|
||||
this.delayStartup = value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all collections stored as part of this profile
|
||||
*
|
||||
* @return <p>All collections stored by this profile</p>
|
||||
*/
|
||||
public List<Collection> getCollections() {
|
||||
return this.collections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this profile
|
||||
*
|
||||
* @return <p>The name of this profile</p>
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a collection given its name
|
||||
*
|
||||
* @param name <p>The name of the collection to get</p>
|
||||
* @return <p>A collection or null if no collection exists with the given name</p>
|
||||
*/
|
||||
public Collection getCollection(String name) {
|
||||
for (Collection collection : this.collections) {
|
||||
if (collection.getName().equals(name)) {
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a collection to the profile if the name is valid
|
||||
*
|
||||
* @param name <p>The name of the collection and its elements</p>
|
||||
*/
|
||||
public void addCollection(String name) throws ConfigurationException {
|
||||
//Skip if no name was given
|
||||
if (name == null) {
|
||||
return;
|
||||
}
|
||||
if (getCollection(name) == null && !name.equals("All") && CommonFunctions.nameIsValid(name)) {
|
||||
collections.add(new Collection(name));
|
||||
} else {
|
||||
serverLauncherGui.showError("A server name must be unique and not empty. " +
|
||||
"In addition, a server cannot be named: \"All\". " +
|
||||
"It cannot contain any of the characters \"!\", \"?\" or \";\".");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the collection with the given name
|
||||
*
|
||||
* @param name <p>The name of the collection to remove</p>
|
||||
*/
|
||||
public void removeCollection(String name) {
|
||||
for (int i = 0; i < collections.size(); i++) {
|
||||
if (collections.get(i).getName().equals(name)) {
|
||||
this.collections.remove(i);
|
||||
serverLauncherGui.updateWithSavedProfileData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates console tabs with the current servers
|
||||
*/
|
||||
public void updateConsoles() {
|
||||
JTabbedPane consolesTab = ServerConsoles.getTabbedPane();
|
||||
consolesTab.removeAll();
|
||||
for (Collection collection : collections) {
|
||||
consolesTab.add(collection.getName(), collection.getServerConsole().getPanel());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command to a server, or all servers
|
||||
*
|
||||
* @param serverName <p>The target server</p>
|
||||
* @param command <p>The command to send</p>
|
||||
*/
|
||||
public void sendCommand(String serverName, String command) {
|
||||
if (serverName.equals("All")) {
|
||||
for (Collection collection : this.collections) {
|
||||
try {
|
||||
collection.getServer().sendCommand(command);
|
||||
} catch (IOException e) {
|
||||
serverLauncherGui.showError("Server " + collection.getName() + " caused an exception.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Collection collection = getCollection(serverName);
|
||||
if (collection != null) {
|
||||
Server target = collection.getServer();
|
||||
try {
|
||||
target.sendCommand(command);
|
||||
} catch (IOException e) {
|
||||
serverLauncherGui.showError("Server " + target.getName() + " caused an exception.");
|
||||
}
|
||||
} else {
|
||||
serverLauncherGui.showError("Server " + serverName + " is invalid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder saveString = new StringBuilder(String.format(
|
||||
"%s;%b;%d?",
|
||||
this.name,
|
||||
this.runInBackground,
|
||||
this.delayStartup)
|
||||
);
|
||||
for (Collection collection : this.collections) {
|
||||
saveString.append(collection.getServer().toString());
|
||||
}
|
||||
saveString = new StringBuilder(saveString.substring(0, saveString.length() - 1));
|
||||
return saveString.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Profile fromString(String profileString) throws ConfigurationException {
|
||||
Profile profile;
|
||||
if (profileString.equals("")) {
|
||||
return null;
|
||||
} else if (profileString.contains("?")) {
|
||||
String[] data = profileString.split("\\?");
|
||||
String[] profileData = data[0].split(";", -1);
|
||||
profile = parseProfile(profileData);
|
||||
if (data[1].contains("!")) {
|
||||
String[] servers = data[1].split("!", -1);
|
||||
for (String server : servers) {
|
||||
profile.collections.add(new Collection(ServerHandler.fromString(server)));
|
||||
}
|
||||
} else {
|
||||
profile.collections.add(new Collection(ServerHandler.fromString(data[1])));
|
||||
}
|
||||
} else {
|
||||
profile = parseProfile(profileString.split(";", -1));
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,424 @@
|
||||
package net.knarcraft.minecraftserverlauncher.profile;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.server.Server;
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
|
||||
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.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* This class handles profiles, GUI creation and session restoration
|
||||
*/
|
||||
public class ServerLauncherController {
|
||||
|
||||
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 ServerLauncherController controller;
|
||||
private String javaCommand = "java";
|
||||
private String oldJavaCommand = "java";
|
||||
|
||||
/**
|
||||
* Instantiates a new controller
|
||||
*/
|
||||
private ServerLauncherController() {
|
||||
this.profileList = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instance of the controller
|
||||
*
|
||||
* @return <p>An instance of the controller</p>
|
||||
*/
|
||||
public static ServerLauncherController getInstance() {
|
||||
if (controller == null) {
|
||||
controller = new ServerLauncherController();
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command for running java
|
||||
*
|
||||
* @return <p>The command for running Java</p>
|
||||
*/
|
||||
public String getJavaCommand() {
|
||||
return javaCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command for running older versions of Java
|
||||
*
|
||||
* <p>The command used to run older minecraft server versions. JRE 8 should probably work.
|
||||
* Can be just "java" or a file path.</p>
|
||||
*
|
||||
* @return <p>The command for running older versions of Java</p>
|
||||
*/
|
||||
public String getOldJavaCommand() {
|
||||
return oldJavaCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command for running Java
|
||||
*
|
||||
* <p>To play on the newest version of Minecraft, this needs to be JDK 16. Can be just "java" or a file path.</p>
|
||||
*
|
||||
* @param javaCommand <p>The command used for running Java</p>
|
||||
*/
|
||||
public void setJavaCommand(String javaCommand) {
|
||||
this.javaCommand = javaCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the command for running older versions of java
|
||||
*
|
||||
* @param oldJavaCommand <p>The command used for running older versions of Java</p>
|
||||
*/
|
||||
public void setOldJavaCommand(String oldJavaCommand) {
|
||||
this.oldJavaCommand = oldJavaCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
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("selectedProfile;%s\nguiWidth;%d\nguiHeight;%d\ndownloadAllJars;%b\njavaCommand;%s\noldJavaCommand;%s",
|
||||
currentProfile.getName(), guiWidth, guiHeight, downloadAllJars, javaCommand, oldJavaCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 <p>The name of the new profile</p>
|
||||
*/
|
||||
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 remove</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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the directory containing .jar files
|
||||
*
|
||||
* @return <p>The directory containing .jar files</p>
|
||||
*/
|
||||
public String getJarDirectory() {
|
||||
return this.jarDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the state of the entire application to disk
|
||||
*/
|
||||
public void saveState() {
|
||||
saveGUIStateToServer();
|
||||
try {
|
||||
CommonFunctions.createAllFolders();
|
||||
CommonFunctions.writeFile(mainFile, this.toString());
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Profile profile : profileList) {
|
||||
builder.append(profile.toString()).append("\n");
|
||||
}
|
||||
CommonFunctions.writeFile(profilesFile, builder.toString());
|
||||
} catch (IOException e) {
|
||||
serverLauncherGUI.showError("Unable to save data.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads profiles and servers from a text file
|
||||
*/
|
||||
public void loadState() throws ConfigurationException, IOException {
|
||||
loadState(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads profiles and servers from a text file
|
||||
*
|
||||
* @param silent <p>If silent, no GUI will be created</p>
|
||||
*/
|
||||
public void loadState(boolean silent) throws ConfigurationException, IOException {
|
||||
//Loads data regarding this controller
|
||||
String currentProfile = null;
|
||||
if (new File(mainFile).exists()) {
|
||||
currentProfile = this.fromString(silent);
|
||||
} else if (!silent) {
|
||||
this.serverLauncherGUI = new ServerLauncherGUI();
|
||||
}
|
||||
if (silent) {
|
||||
return;
|
||||
}
|
||||
//Loads all saved profiles
|
||||
loadProfiles(currentProfile);
|
||||
//Makes the GUI show the loaded data
|
||||
executeGUILoadingTasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads data about the controller from a save string
|
||||
*
|
||||
* @param silent <p>If silent, no GUI will be created</p>
|
||||
* @return <p>The currently selected profile</p>
|
||||
*/
|
||||
private String fromString(boolean silent) {
|
||||
Map<String, String> loadedData = new HashMap<>();
|
||||
|
||||
try {
|
||||
String currentData = CommonFunctions.readFile(mainFile);
|
||||
for (String line : currentData.split("\n")) {
|
||||
parseSaveLine(loadedData, line);
|
||||
}
|
||||
this.downloadAllJars = Boolean.parseBoolean(loadedData.get("downloadAllJars"));
|
||||
|
||||
if (!silent) {
|
||||
if (loadedData.get("guiWidth") != null && loadedData.get("guiHeight") != null) {
|
||||
this.serverLauncherGUI = new ServerLauncherGUI(Integer.parseInt(loadedData.get("guiWidth")),
|
||||
Integer.parseInt(loadedData.get("guiHeight")));
|
||||
} else {
|
||||
this.serverLauncherGUI = new ServerLauncherGUI();
|
||||
}
|
||||
} else {
|
||||
this.serverLauncherGUI = new ServerLauncherGUI(true);
|
||||
}
|
||||
|
||||
if (loadedData.get("javaCommand") != null) {
|
||||
this.javaCommand = loadedData.get("javaCommand");
|
||||
}
|
||||
if (loadedData.get("oldJavaCommand") != null) {
|
||||
this.oldJavaCommand = loadedData.get("oldJavaCommand");
|
||||
}
|
||||
return loadedData.get("selectedProfile");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves one config line to the provided map
|
||||
*
|
||||
* @param loadedData <p>The map to save the loaded configuration to</p>
|
||||
* @param line <p>The line to read</p>
|
||||
*/
|
||||
private void parseSaveLine(Map<String, String> loadedData, String line) {
|
||||
String[] lineData = line.split(";");
|
||||
if (lineData.length != 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadedData.put(lineData[0], lineData[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all saved profiles
|
||||
*
|
||||
* @param currentProfile <p>The profile saved as the current profile</p>
|
||||
* @throws ConfigurationException <p>If unable to load a profile</p>
|
||||
*/
|
||||
private void loadProfiles(String currentProfile) throws ConfigurationException {
|
||||
try (Scanner in = new Scanner(new File(profilesFile))) {
|
||||
while (in.hasNextLine()) {
|
||||
String profileData = in.nextLine();
|
||||
Profile loadedProfile = Profile.fromString(profileData);
|
||||
if (loadedProfile == null) {
|
||||
continue;
|
||||
}
|
||||
profileList.add(loadedProfile);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
addProfile("Default");
|
||||
}
|
||||
|
||||
this.currentProfile = getProfileByName(currentProfile);
|
||||
if (this.currentProfile == null) {
|
||||
this.currentProfile = this.profileList.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the GUI as necessary to display loaded data
|
||||
*/
|
||||
private void executeGUILoadingTasks() {
|
||||
this.serverLauncherGUI.getControlPanelTab().updateProfiles();
|
||||
this.serverLauncherGUI.updateWithSavedProfileData();
|
||||
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(ServerHandler::startServers);
|
||||
this.serverLauncherGUI.hideToTray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.isEnabled());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* The jar builder is responsible for building the newest Spigot and CraftBukkit .jar files using BuildTools
|
||||
*/
|
||||
public class JarBuilder {
|
||||
|
||||
private final String buildDirectory;
|
||||
private final String jarDirectory;
|
||||
private final ServerVersionContainer versionContainer;
|
||||
private final GUI gui;
|
||||
private final String javaCommand;
|
||||
|
||||
/**
|
||||
* Instantiates a new jar builder
|
||||
*
|
||||
* @param buildDirectory <p>The directory containing BuildTool files</p>
|
||||
* @param jarDirectory <p>The directory containing downloaded .jar files</p>
|
||||
* @param gui <p>The GUI to write messages to</p>
|
||||
*/
|
||||
public JarBuilder(String buildDirectory, String jarDirectory, GUI gui) {
|
||||
this.buildDirectory = buildDirectory;
|
||||
this.jarDirectory = jarDirectory;
|
||||
this.gui = gui;
|
||||
this.versionContainer = ServerVersionContainer.getInstance();
|
||||
this.javaCommand = ServerLauncherController.getInstance().getJavaCommand();
|
||||
try {
|
||||
CommonFunctions.createFolder(new File(buildDirectory));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the latest version of the spigot .jar file
|
||||
*/
|
||||
public boolean buildSpigotJar() {
|
||||
gui.setStatus("Building Spigot jar ...");
|
||||
downloadBuildTools();
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(javaCommand, "-jar", "BuildTools.jar", "--rev",
|
||||
"latest", "--output-dir", jarDirectory);
|
||||
if (executeBuildProcess(processBuilder) && moveBuiltJar("spigot-", "SpigotLatest.jar")) {
|
||||
gui.setStatus("Finished moving spigot.jar");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the latest version of the craftbukkit .jar file
|
||||
*/
|
||||
public boolean buildBukkitJar() {
|
||||
gui.setStatus("Building Bukkit jar ...");
|
||||
downloadBuildTools();
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(javaCommand, "-jar", "BuildTools.jar", "--compile",
|
||||
"craftbukkit", "--rev", "latest", "--output-dir", jarDirectory);
|
||||
if (executeBuildProcess(processBuilder) && moveBuiltJar("craftbukkit-", "BukkitLatest.jar")) {
|
||||
gui.setStatus("Finished moving craftbukkit.jar");
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the latest BuildTools version
|
||||
*/
|
||||
public void downloadBuildTools() {
|
||||
ServerLauncherGUI gui = Main.getController().getGUI();
|
||||
try {
|
||||
String latestVersion = getLatestBuildToolsVersion();
|
||||
boolean exists = new File(buildDirectory + "BuildTools.jar").exists();
|
||||
boolean isUpdated = latestVersion.equals(versionContainer.getDownloadedBuildToolsVersion());
|
||||
|
||||
if (!exists || !isUpdated) {
|
||||
String buildToolsURL = "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar";
|
||||
boolean success = CommonFunctions.downloadFile(buildToolsURL, Paths.get(buildDirectory + "BuildTools.jar"));
|
||||
if (!success) {
|
||||
gui.setStatus("Unable to download the latest BuildTools");
|
||||
gui.logError("Target: " + buildDirectory + "BuildTools.jar");
|
||||
gui.logError("URL: " + buildToolsURL);
|
||||
} else {
|
||||
versionContainer.setDownloadedBuildToolsVersion(latestVersion);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
gui.setStatus("Unable to download the latest BuildTools");
|
||||
gui.logMessage(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a built .jar file to its target file
|
||||
*
|
||||
* @param searchString <p>The start of the name of the built file used to find it</p>
|
||||
* @param newName <p>The new name of the built file</p>
|
||||
* @return <p>True if the .jar file was moved successfully</p>
|
||||
*/
|
||||
private boolean moveBuiltJar(String searchString, String newName) {
|
||||
File[] foundFiles = new File(jarDirectory).listFiles((file) -> file.isFile() && file.getName().startsWith(searchString));
|
||||
if (foundFiles != null && foundFiles.length == 1) {
|
||||
File newFileLocation = new File(jarDirectory + File.separator + newName);
|
||||
if (newFileLocation.exists()) {
|
||||
if (!newFileLocation.delete()) {
|
||||
gui.showError("Unable to delete previously built .jar");
|
||||
}
|
||||
}
|
||||
if (!foundFiles[0].renameTo(newFileLocation)) {
|
||||
gui.showError("Unable to move built .jar");
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the build process and initializes
|
||||
*
|
||||
* @param processBuilder <p>The process builder to execute</p>
|
||||
* @return <p>True if the process exited successfully</p>
|
||||
*/
|
||||
private boolean executeBuildProcess(ProcessBuilder processBuilder) {
|
||||
processBuilder.directory(new File(buildDirectory));
|
||||
processBuilder.redirectErrorStream(true);
|
||||
try {
|
||||
Process process = processBuilder.start();
|
||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
do {
|
||||
writer.write(CommonFunctions.readBufferedReader(reader));
|
||||
} while (process.isAlive());
|
||||
|
||||
writer.newLine();
|
||||
writer.flush();
|
||||
|
||||
if (process.exitValue() == 0) {
|
||||
gui.setStatus("Jar building process finished successfully.");
|
||||
return true;
|
||||
} else {
|
||||
gui.showError("Jar building process failed with exit code " + process.exitValue() +
|
||||
". Please check the BuildTools log for errors.");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the latest build tools version available
|
||||
*
|
||||
* @return <p>The latest build tools version available</p>
|
||||
* @throws IOException <p>If unable to read the version file</p>
|
||||
*/
|
||||
String getLatestBuildToolsVersion() throws IOException {
|
||||
String versionDocument;
|
||||
versionDocument = CommonFunctions.readRemoteFile("https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/");
|
||||
return CommonFunctions.stringBetween(versionDocument, "BuildTools #", " [");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,583 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
||||
/**
|
||||
* Contains all necessary information to create, runServer and manage a Minecraft server.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Server {
|
||||
|
||||
private static final String jarDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" +
|
||||
File.separator + "Jars" + File.separator;
|
||||
private final String name;
|
||||
private final ArrayList<String> playerList;
|
||||
private String path;
|
||||
private boolean enabled;
|
||||
private ServerType type;
|
||||
private String serverVersion;
|
||||
private String maxRam;
|
||||
private Process process;
|
||||
private BufferedWriter writer;
|
||||
private BufferedReader reader;
|
||||
private boolean started;
|
||||
private ScheduledExecutorService consoleOutputExecutor;
|
||||
private final ServerLauncherGUI gui = Main.getController().getGUI();
|
||||
|
||||
/**
|
||||
* Initializes a new server with default values
|
||||
*
|
||||
* @param name <p>The name of the server</p>
|
||||
*/
|
||||
public Server(String name) {
|
||||
this.name = name;
|
||||
this.path = "";
|
||||
this.enabled = false;
|
||||
this.playerList = new ArrayList<>();
|
||||
this.type = null;
|
||||
this.serverVersion = "";
|
||||
this.maxRam = ServerHandler.getRamList()[0];
|
||||
this.process = null;
|
||||
this.writer = null;
|
||||
this.reader = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a server with the given values
|
||||
*
|
||||
* @param name <p>The name of the server</p>
|
||||
* @param path <p>The file path of the folder containing the server files</p>
|
||||
* @param enabled <p>Whether the server is enabled to start the next time servers are started</p>
|
||||
* @param typeName <p>The name of the server type currently in use on the server</p>
|
||||
* @param serverVersion <p>The currently selected server version for the given server type</p>
|
||||
* @param maxRam <p>The maximum amount of ram the server is allowed to use</p>
|
||||
*/
|
||||
public Server(String name, String path, boolean enabled, String typeName, String serverVersion, String maxRam) throws ConfigurationException {
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
this.enabled = enabled;
|
||||
this.type = ServerTypeHandler.getByName(typeName);
|
||||
this.serverVersion = serverVersion;
|
||||
this.maxRam = maxRam;
|
||||
this.playerList = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the buffered reader used to read from this server
|
||||
*
|
||||
* @return <p>The buffered reader used to read from this server</p>
|
||||
*/
|
||||
private BufferedReader getReader() {
|
||||
return this.reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the server
|
||||
*
|
||||
* @return <p>The name of the server</p>
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the server has been started
|
||||
*
|
||||
* @return <p>True if the server has been started. False otherwise</p>
|
||||
*/
|
||||
public boolean isStarted() {
|
||||
return started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the server type used by this server
|
||||
*
|
||||
* @return <p>The name of the server type used by this server</p>
|
||||
*/
|
||||
public String getTypeName() {
|
||||
return this.type.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server type used by this server
|
||||
*
|
||||
* @return <p>The server type used by this server</p>
|
||||
*/
|
||||
public ServerType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version used given server type used
|
||||
*
|
||||
* @return <p>The server version given server type</p>
|
||||
*/
|
||||
public String getServerVersion() {
|
||||
return this.serverVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the server's server version to a valid version, or ignores the request
|
||||
*
|
||||
* @param serverVersion <p>The new server version</p>
|
||||
*/
|
||||
public void setServerVersion(String serverVersion) throws IllegalArgumentException {
|
||||
if (this.type.getName().equals("Custom")) {
|
||||
this.serverVersion = serverVersion;
|
||||
} else {
|
||||
String[] versions = this.type.getVersions();
|
||||
for (String version : versions) {
|
||||
if (version.equals(serverVersion)) {
|
||||
this.serverVersion = serverVersion;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid server version.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether this server is a proxy server
|
||||
*
|
||||
* <p>A proxy server is a server running BungeeCord, Waterfall or Travertine.</p>
|
||||
*
|
||||
* @return <p>True if this server is a proxy server</p>
|
||||
*/
|
||||
public boolean isProxy() {
|
||||
return this.type.isProxy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this server as stopped
|
||||
*/
|
||||
public void setStopped() {
|
||||
this.started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the writer used to write to this server
|
||||
*
|
||||
* @return <p>The writer used.</p>
|
||||
*/
|
||||
public BufferedWriter getWriter() {
|
||||
return this.writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the writer used to write to this server
|
||||
*
|
||||
* @param writer <p>The new writer to use.</p>
|
||||
*/
|
||||
public void setWriter(BufferedWriter writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path for this server's files
|
||||
*
|
||||
* @return <p>The path of this server's files</p>
|
||||
*/
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the path of this server's files
|
||||
*
|
||||
* @param path <p>The new path of the server's files</p>
|
||||
*/
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the process of the server
|
||||
*
|
||||
* @return <p>The server process</p>
|
||||
*/
|
||||
public Process getProcess() {
|
||||
return this.process;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum amount of ram usable by this server
|
||||
*
|
||||
* @return <p>The maximum amount of ram this server can use</p>
|
||||
*/
|
||||
public String getMaxRam() {
|
||||
return this.maxRam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max ram to be used by the server
|
||||
*
|
||||
* @param ram <p>The new maximum ram amount</p>
|
||||
*/
|
||||
public void setMaxRam(String ram) {
|
||||
this.maxRam = ram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all players connected to this server
|
||||
*
|
||||
* @return <p>A list of all players connected to the server</p>
|
||||
*/
|
||||
public List<String> getPlayers() {
|
||||
return this.playerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all information about the server's process, writer and reader
|
||||
*/
|
||||
private void cleanStoppedServerValues() {
|
||||
consoleOutputExecutor.shutdown();
|
||||
process = null;
|
||||
writer = null;
|
||||
reader = null;
|
||||
started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this server is currently enabled
|
||||
*
|
||||
* @return <p>True if the server is currently enabled</p>
|
||||
*/
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this server is currently enabled
|
||||
*
|
||||
* @param value <p>Whether the server is currently enabled</p>
|
||||
*/
|
||||
public void setEnabled(boolean value) {
|
||||
this.enabled = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this server has a given player
|
||||
*
|
||||
* @param name <p>The name of the player to check</p>
|
||||
* @return <p>True if the player is connected</p>
|
||||
*/
|
||||
private boolean hasPlayer(String name) {
|
||||
for (String player : this.playerList) {
|
||||
if (player.equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a player to the GUI and this server's player list
|
||||
*
|
||||
* @param name <p>The name of the player to add</p>
|
||||
*/
|
||||
private void addPlayer(String name) {
|
||||
this.playerList.add(name);
|
||||
gui.getServerControlTab().addPlayer(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a player with the selected name from the player list
|
||||
*
|
||||
* @param name <p>The name of the player to remove</p>
|
||||
*/
|
||||
private void removePlayer(String name) {
|
||||
playerList.removeIf(player -> player.equals(name));
|
||||
gui.getServerControlTab().removePlayer(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the server type to be used by the server
|
||||
*
|
||||
* @param type <p>The new server type to be used by the server</p>
|
||||
*/
|
||||
public void setType(ServerType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a Minecraft server
|
||||
*
|
||||
* @param skipDelay <p>Whether to skip the startup delay for this server</p>
|
||||
* @return <p>True if nothing went wrong</p>
|
||||
*/
|
||||
public boolean runServer(boolean skipDelay) {
|
||||
if (ServerHandler.stoppingServers()) {
|
||||
gui.logMessage("Stopping servers. Cannot start yet.");
|
||||
return false;
|
||||
}
|
||||
//Ignore a disabled server
|
||||
if (!this.enabled) {
|
||||
this.started = false;
|
||||
return true;
|
||||
}
|
||||
//Tries to do necessary pre-start work
|
||||
if (!initializeJarDownload() || (!skipDelay && !delayStartup())) {
|
||||
gui.logError("Failed to perform startup tasks.");
|
||||
this.started = false;
|
||||
return false;
|
||||
}
|
||||
if (ServerHandler.stoppingServers()) {
|
||||
gui.logMessage("Stopping servers. Cannot start yet.");
|
||||
return false;
|
||||
}
|
||||
//Starts the server if possible
|
||||
try {
|
||||
startServerProcess();
|
||||
gui.setStatus("Servers are running");
|
||||
this.started = true;
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
gui.setStatus("Could not start server");
|
||||
this.started = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the correct java command to use for the selected server version
|
||||
*
|
||||
* @return <p>The java version to run</p>
|
||||
*/
|
||||
private String getJavaCommand() {
|
||||
ServerLauncherController controller = ServerLauncherController.getInstance();
|
||||
|
||||
if (serverVersion.toLowerCase().contains("latest")) {
|
||||
return controller.getJavaCommand();
|
||||
} else if (serverVersion.contains(".") && serverVersion.split("\\.").length >= 2) {
|
||||
try {
|
||||
if (Integer.parseInt(serverVersion.split("\\.")[1]) >= 17) {
|
||||
return controller.getJavaCommand();
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
return controller.getOldJavaCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the process running this server
|
||||
*
|
||||
* @throws IOException <p>If the process cannot be started</p>
|
||||
*/
|
||||
private void startServerProcess() throws IOException {
|
||||
ProcessBuilder builder;
|
||||
String serverPath;
|
||||
//Decide the path of the .jar file to be executed
|
||||
if (type.getName().equals("Custom")) {
|
||||
serverPath = this.path + File.separator + serverVersion;
|
||||
} else {
|
||||
serverPath = jarDirectory + this.type.getName() + serverVersion + ".jar";
|
||||
}
|
||||
builder = new ProcessBuilder(getJavaCommand(), "-Xmx" + this.maxRam, "-Xms512M",
|
||||
"-Djline.terminal=jline.UnsupportedTerminal", "-Dcom.mojang.eula.agree=true", "-jar", serverPath,
|
||||
"nogui");
|
||||
builder.directory(new File(this.path));
|
||||
builder.redirectErrorStream(true);
|
||||
this.process = builder.start();
|
||||
this.writer = new BufferedWriter(new OutputStreamWriter(this.process.getOutputStream()));
|
||||
this.reader = new BufferedReader(new InputStreamReader(this.process.getInputStream()));
|
||||
|
||||
//Start the process for reading from the server's console
|
||||
consoleOutputExecutor = Executors.newSingleThreadScheduledExecutor();
|
||||
consoleOutputExecutor.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
updateConsole();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, 10, 500, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a single console with process output
|
||||
*
|
||||
* @throws IOException <p>If unable to read from the server's buffered reader</p>
|
||||
*/
|
||||
private void updateConsole() throws IOException {
|
||||
String readText = CommonFunctions.readBufferedReader(getReader());
|
||||
if (!readText.equals("")) {
|
||||
Main.getController().getCurrentProfile().getCollection(getName()).getServerConsole().output(readText);
|
||||
updatePlayerList(readText);
|
||||
}
|
||||
if (!getProcess().isAlive()) {
|
||||
cleanStoppedServerValues();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for strings implying a player has joined or left, and updates the appropriate lists
|
||||
*
|
||||
* @param text <p>The text to search</p>
|
||||
*/
|
||||
private void updatePlayerList(String text) {
|
||||
if (!getType().isProxy()) {
|
||||
String joinedPlayer = getPlayer(text, true);
|
||||
String leftPlayer = getPlayer(text, false);
|
||||
if (!joinedPlayer.equals("")) {
|
||||
if (!hasPlayer(joinedPlayer)) {
|
||||
addPlayer(joinedPlayer);
|
||||
}
|
||||
} else if (!leftPlayer.equals("")) {
|
||||
if (hasPlayer(leftPlayer)) {
|
||||
removePlayer(leftPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches a string for players joining or leaving
|
||||
*
|
||||
* @param text <p>The text string to search through</p>
|
||||
* @param joined <p>Whether to search for a joining player</p>
|
||||
* @return <p>The name of a player, or an empty string</p>
|
||||
*/
|
||||
private String getPlayer(String text, boolean joined) {
|
||||
String playerName;
|
||||
|
||||
String loginPattern1 = " ([A-Z0-9a-z_]+)\\[/[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+:[0-9]+] logged in";
|
||||
String loginPattern2 = "UUID of player ([A-Z0-9a-z_]+) is";
|
||||
|
||||
String logoutPattern1 = "INFO]: ([A-Z0-9a-z_]+) lost connection";
|
||||
String logoutPattern2 = " ([A-Z0-9a-z_]+) left the game";
|
||||
|
||||
if (joined) {
|
||||
playerName = getFirstRegexCaptureGroup(loginPattern1, text);
|
||||
if (playerName.equals("")) {
|
||||
playerName = getFirstRegexCaptureGroup(loginPattern2, text);
|
||||
}
|
||||
} else {
|
||||
playerName = getFirstRegexCaptureGroup(logoutPattern1, text);
|
||||
if (playerName.equals("")) {
|
||||
playerName = getFirstRegexCaptureGroup(logoutPattern2, text);
|
||||
}
|
||||
}
|
||||
return playerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first regex capture group found in a pattern
|
||||
*
|
||||
* @param pattern <p>The regex pattern to use</p>
|
||||
* @param text <p>The string to execute the pattern on</p>
|
||||
* @return <p>The first capture group if a match is found. An empty string otherwise</p>
|
||||
*/
|
||||
private String getFirstRegexCaptureGroup(String pattern, String text) {
|
||||
Pattern compiledPattern = Pattern.compile(pattern);
|
||||
Matcher patternMatcher = compiledPattern.matcher(text);
|
||||
if (patternMatcher.find()) {
|
||||
return patternMatcher.group(1);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delays the server's startup for the given amount of time
|
||||
*
|
||||
* @return <p>True if the delay was successful</p>
|
||||
*/
|
||||
private boolean delayStartup() {
|
||||
try {
|
||||
gui.setStatus("Delaying startup");
|
||||
TimeUnit.SECONDS.sleep(Main.getController().getCurrentProfile().getDelayStartup());
|
||||
return true;
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
this.started = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts downloading the necessary .jar file
|
||||
*
|
||||
* @return <p>True if nothing went wrong</p>
|
||||
*/
|
||||
private boolean initializeJarDownload() {
|
||||
try {
|
||||
gui.setStatus("Downloading jar...");
|
||||
this.downloadJar();
|
||||
gui.setStatus("File downloaded");
|
||||
} catch (IOException e) {
|
||||
gui.setStatus("Error: Jar file could not be found, downloaded or built.");
|
||||
gui.logError("Unable to get required .jar file: " + e.getMessage());
|
||||
this.started = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads necessary .jar file for the server
|
||||
*
|
||||
* @throws FileNotFoundException <p>If the file was not found and could not be acquired</p>
|
||||
*/
|
||||
private void downloadJar() throws IOException {
|
||||
String path;
|
||||
if (this.type.getName().equals("Custom")) {
|
||||
path = this.path + File.separator + this.serverVersion;
|
||||
} else {
|
||||
path = jarDirectory;
|
||||
}
|
||||
File file = new File(path);
|
||||
if (!(file.isFile() || type.downloadJar(path, this.serverVersion))) {
|
||||
throw new FileNotFoundException("Jar file could not be downloaded.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command to this server through its writer
|
||||
*
|
||||
* @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) {
|
||||
this.writer.write(command + "\n");
|
||||
this.writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"%s;%s;%b;%s;%s;%s;!",
|
||||
this.getName(),
|
||||
this.getPath(),
|
||||
this.isEnabled(),
|
||||
this.getTypeName(),
|
||||
this.getServerVersion(),
|
||||
this.getMaxRam()
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.Collection;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.ServerLauncherGUI;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ServerHandler {
|
||||
|
||||
/**
|
||||
* Available ram sizes. For ServerLauncherGUI combo
|
||||
*/
|
||||
private static final String[] ramList = {"512M", "1G", "2G", "3G", "4G", "5G", "6G", "7G", "8G", "9G", "10G",
|
||||
"11G", "12G", "13G", "14G", "15G", "16G"};
|
||||
|
||||
private static boolean stoppingServers = false;
|
||||
private static final ServerLauncherGUI gui = Main.getController().getGUI();
|
||||
|
||||
/**
|
||||
* Gets the list of available RAM choices allowed
|
||||
*
|
||||
* @return <p>All available RAM choices</p>
|
||||
*/
|
||||
public static String[] getRamList() {
|
||||
return ramList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the servers are currently in the process of stopping
|
||||
*
|
||||
* @return <p>True if the servers are in the process of stopping.</p>
|
||||
*/
|
||||
public static boolean stoppingServers() {
|
||||
return stoppingServers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the servers as finished stopping when a stop is confirmed
|
||||
*/
|
||||
public static void serversStopped() {
|
||||
if (stoppingServers) {
|
||||
stoppingServers = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to stop all enabled servers
|
||||
*
|
||||
* @throws IOException <p>If a writer's process is already closed but not null</p>
|
||||
*/
|
||||
public static void stop() throws IOException, InterruptedException {
|
||||
if (stoppingServers) {
|
||||
killServers();
|
||||
return;
|
||||
}
|
||||
|
||||
stoppingServers = true;
|
||||
int serversRunning = 0;
|
||||
|
||||
for (Collection collection : Main.getController().getCurrentProfile().getCollections()) {
|
||||
Server server = collection.getServer();
|
||||
BufferedWriter writer = server.getWriter();
|
||||
if (writer != null) {
|
||||
serversRunning++;
|
||||
if (server.isProxy()) {
|
||||
writer.write("end\n");
|
||||
} else {
|
||||
writer.write("stop\n");
|
||||
}
|
||||
writer.flush();
|
||||
server.setWriter(null);
|
||||
server.setStopped();
|
||||
}
|
||||
}
|
||||
|
||||
if (serversRunning == 0) {
|
||||
stoppingServers = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kills all server processes
|
||||
*
|
||||
* @throws InterruptedException <p>If interrupted waiting for any of the servers to stop</p>
|
||||
*/
|
||||
private static void killServers() throws InterruptedException {
|
||||
for (Collection collection : Main.getController().getCurrentProfile().getCollections()) {
|
||||
Server server = collection.getServer();
|
||||
killServer(server);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kills the given server after waiting 30 seconds for it to terminate normally
|
||||
*
|
||||
* @param server <p>The server to kill</p>
|
||||
* @throws InterruptedException <p>If interrupted waiting for the server to stop</p>
|
||||
*/
|
||||
private static void killServer(Server server) throws InterruptedException {
|
||||
Process serverProcess = server.getProcess();
|
||||
if (serverProcess != null) {
|
||||
if (!serverProcess.waitFor(30, TimeUnit.SECONDS)) {
|
||||
serverProcess.destroyForcibly();
|
||||
serverProcess.waitFor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all enabled servers with their settings
|
||||
*/
|
||||
public static void startServers() {
|
||||
ServerLauncherController controller = Main.getController();
|
||||
gui.setStatus("Starting servers");
|
||||
Server previouslyStartedServer = null;
|
||||
|
||||
for (Collection collection : controller.getCurrentProfile().getCollections()) {
|
||||
Server server = collection.getServer();
|
||||
if (!server.runServer(previouslyStartedServer == null || previouslyStartedServer.isProxy())) {
|
||||
gui.showError("An error occurred. Start aborted. Please check relevant log files.");
|
||||
try {
|
||||
stop();
|
||||
} catch (IOException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
gui.updateGUIElementsWhenServersStartOrStop(false);
|
||||
return;
|
||||
}
|
||||
if (server.isEnabled()) {
|
||||
previouslyStartedServer = server;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a server object from a server save string
|
||||
*
|
||||
* @param saveString <p>The string containing necessary data regarding the server</p>
|
||||
* @return <p>A server in the same state it was saved in</p>
|
||||
*/
|
||||
public static Server fromString(String saveString) throws ConfigurationException {
|
||||
String[] data = saveString.split(";");
|
||||
return new Server(data[0], data[1], Boolean.parseBoolean(data[2]), data[3], data[4], data[5]);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.BungeeCord;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.CraftBukkit;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.Custom;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.MCPCPlus;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.Paper;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.Spigot;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.SpongeForge;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.SpongeVanilla;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.Travertine;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.Vanilla;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.Waterfall;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner;
|
||||
|
||||
/**
|
||||
* A class which keeps track of available server types
|
||||
*/
|
||||
public class ServerTypeHandler {
|
||||
|
||||
private static final ArrayList<ServerType> serverTypes = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Gets a list of all server types' names
|
||||
*
|
||||
* @return <p>A list containing the names of all server types</p>
|
||||
*/
|
||||
public static String[] getTypeNames() throws ConfigurationException {
|
||||
if (serverTypes.isEmpty()) {
|
||||
loadServerTypes();
|
||||
}
|
||||
ArrayList<ServerType> types = getServerTypes();
|
||||
String[] serverTypeNames = new String[types.size()];
|
||||
for (int i = 0; i < types.size(); i++) {
|
||||
serverTypeNames[i] = types.get(i).getName();
|
||||
}
|
||||
return serverTypeNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all instantiated server types
|
||||
*
|
||||
* @return <p>A list of server types</p>
|
||||
*/
|
||||
public static ArrayList<ServerType> getServerTypes() throws ConfigurationException {
|
||||
if (serverTypes.isEmpty()) {
|
||||
loadServerTypes();
|
||||
}
|
||||
return serverTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a server type by the given name
|
||||
*
|
||||
* @param name <p>Then name of the server type</p>
|
||||
* @return <p>A AbstractServerType</p>
|
||||
*/
|
||||
public static ServerType getByName(String name) throws ConfigurationException {
|
||||
if (serverTypes.isEmpty()) {
|
||||
loadServerTypes();
|
||||
}
|
||||
for (ServerType serverType : serverTypes) {
|
||||
if (serverType.getName().equals(name)) {
|
||||
return serverType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads valid server types and version from a file, and creates their objects
|
||||
*
|
||||
* @throws ConfigurationException <p>If anything goes wrong</p>
|
||||
*/
|
||||
private static void loadServerTypes() throws ConfigurationException {
|
||||
Scanner file;
|
||||
try {
|
||||
file = getResourceAsScanner("servertypes.csv");
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new ConfigurationException("Server type configuration file is missing.");
|
||||
}
|
||||
while (file.hasNextLine()) {
|
||||
String nextLine = file.nextLine();
|
||||
if (nextLine.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//Splits the next file line into arguments
|
||||
String[] serverTypeInfo = nextLine.split(";", -1);
|
||||
|
||||
//Gets list of server versions from file line
|
||||
String[] serverVersions;
|
||||
if (serverTypeInfo[1].contains(",")) {
|
||||
serverVersions = serverTypeInfo[1].split(",", -1);
|
||||
} else {
|
||||
serverVersions = new String[]{serverTypeInfo[1]};
|
||||
}
|
||||
|
||||
addServerType(serverTypeInfo, serverVersions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new server type
|
||||
*
|
||||
* @param serverTypeInfo <p>A list containing necessary information for initializing the server type</p>
|
||||
* @param serverVersions <p>A list of all server versions for the server type</p>
|
||||
*/
|
||||
private static void addServerType(String[] serverTypeInfo, String[] serverVersions) {
|
||||
ServerType newType;
|
||||
switch (serverTypeInfo[0]) {
|
||||
case "Craftbukkit":
|
||||
newType = new CraftBukkit("Bukkit", false, serverVersions, serverTypeInfo[2],
|
||||
serverTypeInfo[3]);
|
||||
break;
|
||||
case "Spigot":
|
||||
newType = new Spigot("Spigot", false, serverVersions, serverTypeInfo[2],
|
||||
serverTypeInfo[3]);
|
||||
break;
|
||||
case "Vanilla":
|
||||
newType = new Vanilla("Vanilla", false, serverVersions, serverTypeInfo[2],
|
||||
serverTypeInfo[3]);
|
||||
break;
|
||||
case "MCPCplus":
|
||||
newType = new MCPCPlus("MCPCplus", false, serverVersions, serverTypeInfo[2],
|
||||
serverTypeInfo[3]);
|
||||
break;
|
||||
case "Paper":
|
||||
newType = new Paper("Paper", false, serverVersions, serverTypeInfo[2],
|
||||
serverTypeInfo[3], serverTypeInfo[4], serverTypeInfo[5]);
|
||||
break;
|
||||
case "Bungee":
|
||||
newType = new BungeeCord("Bungee", true, serverVersions, serverTypeInfo[2],
|
||||
serverTypeInfo[3], serverTypeInfo[4], serverTypeInfo[5], serverTypeInfo[6], serverTypeInfo[7]);
|
||||
break;
|
||||
case "Travertine":
|
||||
newType = new Travertine("Travertine", true, serverVersions, serverTypeInfo[2],
|
||||
serverTypeInfo[3], serverTypeInfo[4], serverTypeInfo[5]);
|
||||
break;
|
||||
case "Waterfall":
|
||||
newType = new Waterfall("Waterfall", true, serverVersions, serverTypeInfo[2],
|
||||
serverTypeInfo[3], serverTypeInfo[4], serverTypeInfo[5]);
|
||||
break;
|
||||
case "SpongeVanilla":
|
||||
newType = new SpongeVanilla("SpongeVanilla", false, serverVersions,
|
||||
serverTypeInfo[2], serverTypeInfo[3], serverTypeInfo[4], serverTypeInfo[5], serverTypeInfo[6]);
|
||||
break;
|
||||
case "SpongeForge":
|
||||
newType = new SpongeForge("SpongeForge", false, serverVersions,
|
||||
serverTypeInfo[2], serverTypeInfo[3], serverTypeInfo[4], serverTypeInfo[5], serverTypeInfo[6]);
|
||||
break;
|
||||
case "Custom":
|
||||
newType = new Custom("Custom");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown server type defined in config file.");
|
||||
}
|
||||
serverTypes.add(newType);
|
||||
}
|
||||
}
|
@ -0,0 +1,384 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class acts as a container for all "latest" server versions
|
||||
*/
|
||||
public class ServerVersionContainer {
|
||||
|
||||
private static ServerVersionContainer serverVersionContainer;
|
||||
private final String versionFile = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator + "versions.csv";
|
||||
private String vanillaVersion;
|
||||
private String snapshotVersion;
|
||||
private String bungeeVersion;
|
||||
private Map<String, String> waterfallVersions;
|
||||
private Map<String, String> travertineVersions;
|
||||
private Map<String, String> paperVersions;
|
||||
private Map<String, String> spongeVanillaVersions;
|
||||
private Map<String, String> spongeForgeVersions;
|
||||
private String downloadedBuildToolsVersion;
|
||||
|
||||
/**
|
||||
* Initializes a new server version container
|
||||
*/
|
||||
private ServerVersionContainer() {
|
||||
this.waterfallVersions = new HashMap<>();
|
||||
this.travertineVersions = new HashMap<>();
|
||||
this.paperVersions = new HashMap<>();
|
||||
this.spongeVanillaVersions = new HashMap<>();
|
||||
this.spongeForgeVersions = new HashMap<>();
|
||||
loadState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a server version container instance
|
||||
*
|
||||
* @return <p>A server version container instance</p>
|
||||
*/
|
||||
public static ServerVersionContainer getInstance() {
|
||||
if (serverVersionContainer == null) {
|
||||
serverVersionContainer = new ServerVersionContainer();
|
||||
}
|
||||
return serverVersionContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the state of the server version container
|
||||
*/
|
||||
void reset() {
|
||||
this.vanillaVersion = null;
|
||||
this.snapshotVersion = null;
|
||||
this.bungeeVersion = null;
|
||||
this.waterfallVersions = new HashMap<>();
|
||||
this.travertineVersions = new HashMap<>();
|
||||
this.paperVersions = new HashMap<>();
|
||||
this.spongeVanillaVersions = new HashMap<>();
|
||||
this.spongeForgeVersions = new HashMap<>();
|
||||
this.downloadedBuildToolsVersion = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "vanillaVersion;" + vanillaVersion + "\n" +
|
||||
"snapshotVersion;" + snapshotVersion + "\n" +
|
||||
"bungeeVersion;" + bungeeVersion + "\n" +
|
||||
"waterfallVersions;" + mapToString(waterfallVersions) + "\n" +
|
||||
"travertineVersions;" + mapToString(travertineVersions) + "\n" +
|
||||
"paperVersions;" + mapToString(paperVersions) + "\n" +
|
||||
"spongeVanillaVersions;" + mapToString(spongeVanillaVersions) + "\n" +
|
||||
"spongeForgeVersions;" + mapToString(spongeForgeVersions) + "\n" +
|
||||
"downloadedBuildToolsVersion;" + downloadedBuildToolsVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a map to a string given a map
|
||||
*
|
||||
* @param targetMap <p>The map to format</p>
|
||||
* @return <p>A string representing the map</p>
|
||||
*/
|
||||
private String mapToString(Map<?, ?> targetMap) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
int mapSize = targetMap.keySet().size();
|
||||
int mapIndex = 0;
|
||||
for (Object key : targetMap.keySet()) {
|
||||
stringBuilder.append(key).append("!").append(targetMap.get(key));
|
||||
if (mapIndex < mapSize) {
|
||||
stringBuilder.append(",");
|
||||
}
|
||||
mapIndex++;
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to save the state of this server version container
|
||||
*/
|
||||
void saveState() {
|
||||
File saveFile = new File(versionFile);
|
||||
PrintWriter file;
|
||||
try {
|
||||
if (!saveFile.exists()) {
|
||||
if (!saveFile.getParentFile().exists() && !saveFile.getParentFile().mkdirs()) {
|
||||
throw new FileNotFoundException("Unable to create folder for version file");
|
||||
}
|
||||
if (!saveFile.createNewFile()) {
|
||||
throw new FileNotFoundException("Unable to create version file");
|
||||
}
|
||||
}
|
||||
file = new PrintWriter(versionFile);
|
||||
file.println(this);
|
||||
file.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the object state from the save file
|
||||
*/
|
||||
private void loadState() {
|
||||
if (!new File(versionFile).exists()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String currentData = CommonFunctions.readFile(versionFile);
|
||||
for (String line : currentData.split("\n")) {
|
||||
parseSaveLine(line);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses one line in the version save file and updates the appropriate variable
|
||||
*
|
||||
* @param line <p>The line from the save file to parse</p>
|
||||
*/
|
||||
private void parseSaveLine(String line) {
|
||||
String[] lineData = line.split(";");
|
||||
if (lineData.length != 2) {
|
||||
return;
|
||||
}
|
||||
String variableKey = lineData[0];
|
||||
String variableValue = lineData[1];
|
||||
switch (variableKey) {
|
||||
case "vanillaVersion":
|
||||
vanillaVersion = variableValue;
|
||||
break;
|
||||
case "snapshotVersion":
|
||||
snapshotVersion = variableValue;
|
||||
break;
|
||||
case "bungeeVersion":
|
||||
bungeeVersion = variableValue;
|
||||
break;
|
||||
case "waterfallVersions":
|
||||
parseVersionsToMap(waterfallVersions, variableValue);
|
||||
break;
|
||||
case "travertineVersions":
|
||||
parseVersionsToMap(travertineVersions, variableValue);
|
||||
break;
|
||||
case "paperVersions":
|
||||
parseVersionsToMap(paperVersions, variableValue);
|
||||
break;
|
||||
case "spongeVanillaVersions":
|
||||
parseVersionsToMap(spongeVanillaVersions, variableValue);
|
||||
break;
|
||||
case "spongeForgeVersions":
|
||||
parseVersionsToMap(spongeForgeVersions, variableValue);
|
||||
break;
|
||||
case "downloadedBuildToolsVersion":
|
||||
downloadedBuildToolsVersion = variableValue;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid key encountered in the server version file.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads versions from a text string and updates the version map
|
||||
*
|
||||
* @param targetMap <p>The map to update</p>
|
||||
* @param data <p>The data string to parse</p>
|
||||
*/
|
||||
private void parseVersionsToMap(Map<String, String> targetMap, String data) {
|
||||
String[] versions = data.split(",");
|
||||
for (String version : versions) {
|
||||
String[] versionData = version.split("!");
|
||||
targetMap.put(versionData[0], versionData[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the current vanilla version
|
||||
*
|
||||
* @return <p>The current vanilla version</p>
|
||||
*/
|
||||
public String getVanillaVersion() {
|
||||
return this.vanillaVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the vanilla server version
|
||||
*
|
||||
* @param newVersion <p>The new vanilla server version</p>
|
||||
*/
|
||||
public void setVanillaVersion(String newVersion) {
|
||||
this.vanillaVersion = newVersion;
|
||||
saveState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current snapshot version
|
||||
*
|
||||
* @return <p>The current snapshot version</p>
|
||||
*/
|
||||
public String getSnapshotVersion() {
|
||||
return this.snapshotVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the snapshot server version
|
||||
*
|
||||
* @param newVersion <p>The new snapshot server version</p>
|
||||
*/
|
||||
public void setSnapshotVersion(String newVersion) {
|
||||
this.snapshotVersion = newVersion;
|
||||
saveState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current bungee version
|
||||
*
|
||||
* @return <p>The current bungee version</p>
|
||||
*/
|
||||
public String getBungeeVersion() {
|
||||
return this.bungeeVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bungee server version
|
||||
*
|
||||
* @param newVersion <p>The new bungee server version</p>
|
||||
*/
|
||||
public void setBungeeVersion(String newVersion) {
|
||||
this.bungeeVersion = newVersion;
|
||||
saveState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific waterfall version
|
||||
*
|
||||
* @param versionKey <p>The version to check current version of</p>
|
||||
* @return <p>The current waterfall version</p>
|
||||
*/
|
||||
public String getWaterfallVersion(String versionKey) {
|
||||
return this.waterfallVersions.get(versionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current version for a given waterfall version
|
||||
*
|
||||
* @param mapKey <p>The version key to set version for</p>
|
||||
* @param newValue <p>The new current version</p>
|
||||
*/
|
||||
public void setWaterfallVersion(String mapKey, String newValue) {
|
||||
this.waterfallVersions.put(mapKey, newValue);
|
||||
saveState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific travertine version
|
||||
*
|
||||
* @param versionKey <p>The version to check current version of</p>
|
||||
* @return <p>The current travertine version</p>
|
||||
*/
|
||||
public String getTravertineVersion(String versionKey) {
|
||||
return this.travertineVersions.get(versionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current version for a given travertine version
|
||||
*
|
||||
* @param mapKey <p>The version key to set version for</p>
|
||||
* @param newValue <p>The new current version</p>
|
||||
*/
|
||||
public void setTravertineVersion(String mapKey, String newValue) {
|
||||
this.travertineVersions.put(mapKey, newValue);
|
||||
saveState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific paper version
|
||||
*
|
||||
* @param versionKey <p>The version to check the current version of</p>
|
||||
* @return <p>The current paper version</p>
|
||||
*/
|
||||
public String getPaperVersion(String versionKey) {
|
||||
return this.paperVersions.get(versionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current version for a given paper version
|
||||
*
|
||||
* @param mapKey <p>The version key to set version for</p>
|
||||
* @param newValue <p>The new current version</p>
|
||||
*/
|
||||
public void setPaperVersion(String mapKey, String newValue) {
|
||||
this.paperVersions.put(mapKey, newValue);
|
||||
saveState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific sponge vanilla version
|
||||
*
|
||||
* @param versionKey <p>The version to check current version of</p>
|
||||
* @return <p>The current sponge vanilla version</p>
|
||||
*/
|
||||
public String getSpongeVanillaVersion(String versionKey) {
|
||||
return spongeVanillaVersions.get(versionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current version for a given sponge vanilla version
|
||||
*
|
||||
* @param mapKey <p>The version key to set version for</p>
|
||||
* @param newValue <p>The new current version</p>
|
||||
*/
|
||||
public void setSpongeVanillaVersion(String mapKey, String newValue) {
|
||||
spongeVanillaVersions.put(mapKey, newValue);
|
||||
saveState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific sponge forge version
|
||||
*
|
||||
* @param versionKey <p>The version to check current version of</p>
|
||||
* @return <p>The current sponge forge version</p>
|
||||
*/
|
||||
public String getSpongeForgeVersion(String versionKey) {
|
||||
return spongeForgeVersions.get(versionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current version for a given sponge forge version
|
||||
*
|
||||
* @param mapKey <p>The version key to set version for</p>
|
||||
* @param newValue <p>The new current version</p>
|
||||
*/
|
||||
public void setSpongeForgeVersion(String mapKey, String newValue) {
|
||||
spongeForgeVersions.put(mapKey, newValue);
|
||||
saveState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version of the downloaded BuildTools file
|
||||
*
|
||||
* @return <p>The version of the downloaded BuildTools file</p>
|
||||
*/
|
||||
public String getDownloadedBuildToolsVersion() {
|
||||
return this.downloadedBuildToolsVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the version of the downloaded BuildTools file
|
||||
*
|
||||
* @param newValue <p>The new version</p></p>
|
||||
*/
|
||||
public void setDownloadedBuildToolsVersion(String newValue) {
|
||||
this.downloadedBuildToolsVersion = newValue;
|
||||
saveState();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
/**
|
||||
* Contains the bare minimum to be a functional server type.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public abstract class AbstractServerType implements ServerType {
|
||||
final String downloadURL;
|
||||
private final String typeName;
|
||||
private final boolean isProxy;
|
||||
private final String[] versions;
|
||||
|
||||
/**
|
||||
* Instantiates a new server type
|
||||
*
|
||||
* @param typeName <p>The typeName of the server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>A list of one or more server versions for the type</p>
|
||||
* @param downloadURL <p>The URL used for downloading .jar files</p>
|
||||
*/
|
||||
AbstractServerType(String typeName, boolean isProxy, String[] versions, String downloadURL) {
|
||||
this.typeName = typeName;
|
||||
this.isProxy = isProxy;
|
||||
this.versions = versions;
|
||||
this.downloadURL = downloadURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.typeName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProxy() {
|
||||
return this.isProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getVersions() {
|
||||
return this.versions;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerVersionContainer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readRemoteFile;
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween;
|
||||
|
||||
/**
|
||||
* This class represents the BungeeCord proxy server type
|
||||
*/
|
||||
public class BungeeCord extends AbstractServerType {
|
||||
|
||||
private final String versionURL;
|
||||
private final String srcStart;
|
||||
private final String srcEnd;
|
||||
private final String oldVersionsURL;
|
||||
private final String oldVersionsPrefix;
|
||||
|
||||
/**
|
||||
* Instantiates a new BungeeCord server type
|
||||
*
|
||||
* @param typeName <p>The name of the server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>The available versions for the server type</p>
|
||||
* @param versionURL <p>The URL used to finding the newest version</p>
|
||||
* @param srcStart <p>The string after which the version id starts</p>
|
||||
* @param srcEnd <p>The string marking the end of the version id</p>
|
||||
* @param downloadURL <p>The URL used for downloading the latest version</p>
|
||||
*/
|
||||
public BungeeCord(String typeName, boolean isProxy, String[] versions, String versionURL, String srcStart,
|
||||
String srcEnd, String downloadURL, String oldVersionsURL, String oldVersionsPrefix) {
|
||||
super(typeName, isProxy, versions, downloadURL);
|
||||
this.versionURL = versionURL;
|
||||
this.srcStart = srcStart;
|
||||
this.srcEnd = srcEnd;
|
||||
this.oldVersionsURL = oldVersionsURL;
|
||||
this.oldVersionsPrefix = oldVersionsPrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean downloadJar(String folder, String version) throws IOException {
|
||||
String targetFile = this.getName() + version + ".jar";
|
||||
File filePath = new File(folder + targetFile);
|
||||
|
||||
if (version.equals("Latest")) {
|
||||
return downloadLatestJar(filePath);
|
||||
} else {
|
||||
String file = oldVersionsPrefix + version + ".jar";
|
||||
return filePath.isFile() || downloadFile(oldVersionsURL + file, Paths.get(filePath.toURI()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the latest BungeeCord .jar file
|
||||
*
|
||||
* @param filePath <p>The file path to download the new jar to</p>
|
||||
* @return <p>True if the jar exists or was successfully downloaded</p>
|
||||
* @throws IOException <p>If unable to download the new jar</p>
|
||||
*/
|
||||
private boolean downloadLatestJar(File filePath) throws IOException {
|
||||
ServerVersionContainer versionContainer = ServerVersionContainer.getInstance();
|
||||
|
||||
String newestVersion = stringBetween(readRemoteFile(versionURL), srcStart, srcEnd);
|
||||
String oldVersion = versionContainer.getBungeeVersion();
|
||||
//The file is already the newest version
|
||||
if (filePath.isFile() && newestVersion.equals(oldVersion)) {
|
||||
return true;
|
||||
}
|
||||
//The new jar file could not be downloaded
|
||||
if (!downloadFile(downloadURL, Paths.get(filePath.toURI()))) {
|
||||
return false;
|
||||
}
|
||||
versionContainer.setBungeeVersion(newestVersion);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
import net.knarcraft.minecraftserverlauncher.server.JarBuilder;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
|
||||
|
||||
/**
|
||||
* This class represents the CraftBukkit Minecraft server type
|
||||
*/
|
||||
public class CraftBukkit extends AbstractServerType {
|
||||
|
||||
private final String downloadURLPart;
|
||||
|
||||
/**
|
||||
* Instantiates a new CraftBukkit server type
|
||||
*
|
||||
* @param typeName <p>The name of the server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>A list of one or more server versions for the type</p>
|
||||
* @param downloadURL <p>The URL used for downloading .jar files</p>
|
||||
* @param downloadURLPart <p>A string used after the download url as an additional part of the URL</p>
|
||||
*/
|
||||
public CraftBukkit(String typeName, boolean isProxy, String[] versions, String downloadURL, String downloadURLPart) {
|
||||
super(typeName, isProxy, versions, downloadURL);
|
||||
this.downloadURLPart = downloadURLPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean downloadJar(String folder, String version) {
|
||||
String targetFile = this.getName() + version + ".jar";
|
||||
String file = downloadURLPart + version + ".jar";
|
||||
File filePath = new File(folder + targetFile);
|
||||
|
||||
if (version.equals("Latest")) {
|
||||
return filePath.isFile() || buildJar(folder);
|
||||
} else {
|
||||
return filePath.isFile() || downloadFile(downloadURL + file, Paths.get(filePath.toURI()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the necessary .jar file
|
||||
*
|
||||
* @param folder <p>The folder the build file should be moved to</p>
|
||||
* @return <p>True if the build was successful</p>
|
||||
*/
|
||||
private boolean buildJar(String folder) {
|
||||
String buildToolsDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator +
|
||||
"BuildTools" + File.separator;
|
||||
|
||||
GUI gui = ServerLauncherController.getInstance().getGUI();
|
||||
JarBuilder jarBuilder = new JarBuilder(buildToolsDirectory, folder, gui);
|
||||
if (this instanceof Spigot) {
|
||||
return jarBuilder.buildSpigotJar();
|
||||
} else {
|
||||
return jarBuilder.buildBukkitJar();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class Custom extends AbstractServerType {
|
||||
/**
|
||||
* Instantiates a new custom server type
|
||||
*
|
||||
* @param typeName <p>The name of the server type</p>
|
||||
*/
|
||||
public Custom(String typeName) {
|
||||
super(typeName, false, new String[]{}, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean downloadJar(String folder, String version) {
|
||||
File filePath = new File(folder + version);
|
||||
return filePath.isFile();
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
/**
|
||||
* This class represents the MCPC+ Minecraft server type
|
||||
*/
|
||||
public class MCPCPlus extends CraftBukkit {
|
||||
|
||||
/**
|
||||
* Instantiates a new MCPCplus server type
|
||||
*
|
||||
* @param typeName <p>The name of the server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>A list of one or more server versions for the type</p>
|
||||
* @param downloadURL <p>The URL used for downloading .jar files</p>
|
||||
* @param downloadURLPart <p>A string used after the download url as an additional part of the URL</p>
|
||||
*/
|
||||
public MCPCPlus(String typeName, boolean isProxy, String[] versions, String downloadURL, String downloadURLPart) {
|
||||
super(typeName, isProxy, versions, downloadURL, downloadURLPart);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
/**
|
||||
* This class represents the Paper Minecraft server type
|
||||
*/
|
||||
public class Paper extends Waterfall {
|
||||
|
||||
/**
|
||||
* Instantiates a new Paper server type
|
||||
*
|
||||
* @param typeName <p>The name of the server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>The available versions for the server type</p>
|
||||
* @param versionURL <p>The URL used to finding the newest version</p>
|
||||
* @param srcStart <p>The string after which the version id starts</p>
|
||||
* @param srcEnd <p>The string marking the end of the version id</p>
|
||||
* @param downloadURL <p>The URL used for downloading the latest version</p>
|
||||
*/
|
||||
public Paper(String typeName, boolean isProxy, String[] versions, String versionURL, String srcStart,
|
||||
String srcEnd, String downloadURL) {
|
||||
super(typeName, isProxy, versions, versionURL, srcStart, srcEnd, downloadURL);
|
||||
|
||||
this.oldVersionFunction = serverVersionContainer::getPaperVersion;
|
||||
this.versionUpdateFunction = serverVersionContainer::setPaperVersion;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Describes a server type
|
||||
*/
|
||||
public interface ServerType {
|
||||
|
||||
/**
|
||||
* Gets whether this server type is a proxy server
|
||||
*
|
||||
* @return <p>True if this server type is a proxy server</p>
|
||||
*/
|
||||
boolean isProxy();
|
||||
|
||||
/**
|
||||
* Gets the name of the server type
|
||||
*
|
||||
* @return <p>Server type name</p>
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Gets a list of versions available for the server type
|
||||
*
|
||||
* @return <p>A list of server versions</p>
|
||||
*/
|
||||
String[] getVersions();
|
||||
|
||||
/**
|
||||
* Downloads a .jar file for this server type
|
||||
*
|
||||
* @param folder <p>The folder to save the downloaded file to</p>
|
||||
* @param version <p>The server type version to use</p>
|
||||
* @return <p>True if the file exists or was downloaded</p>
|
||||
*/
|
||||
boolean downloadJar(String folder, String version) throws IOException;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
/**
|
||||
* This class represents the CraftBukkit Minecraft server type
|
||||
*/
|
||||
public class Spigot extends CraftBukkit {
|
||||
|
||||
/**
|
||||
* Instantiates a new Spigot server type
|
||||
*
|
||||
* @param typeName <p>The name of the server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>A list of one or more server versions for the type</p>
|
||||
* @param downloadURL <p>The URL used for downloading .jar files</p>
|
||||
* @param downloadURLPart <p>A string used after the download url as an additional part of the URL</p>
|
||||
*/
|
||||
public Spigot(String typeName, boolean isProxy, String[] versions, String downloadURL, String downloadURLPart) {
|
||||
super(typeName, isProxy, versions, downloadURL, downloadURLPart);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
/**
|
||||
* This class represents the SpongeForge Minecraft server type
|
||||
*/
|
||||
public class SpongeForge extends SpongeVanilla {
|
||||
|
||||
/**
|
||||
* Instantiates a new SpongeForge server type
|
||||
*
|
||||
* @param typeName <p>The name of this server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>Available versions for this server type</p>
|
||||
* @param versionURL <p>The URL used for downloading the version document</p>
|
||||
* @param srcStart <p>The string to search for to determine newest version</p>
|
||||
* @param srcEnd <p>The string marking the end of the newest version statement</p>
|
||||
* @param downloadURL <p>The URL used for downloading the new file</p>
|
||||
* @param downloadURLPart <p>A string used after the download url as an additional part of the URL</p>
|
||||
*/
|
||||
public SpongeForge(String typeName, boolean isProxy, String[] versions, String versionURL, String srcStart, String srcEnd, String downloadURL, String downloadURLPart) {
|
||||
super(typeName, isProxy, versions, versionURL, srcStart, srcEnd, downloadURL, downloadURLPart);
|
||||
this.oldVersionFunction = serverVersionContainer::getSpongeForgeVersion;
|
||||
this.versionUpdateFunction = serverVersionContainer::setSpongeForgeVersion;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerVersionContainer;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
|
||||
|
||||
/**
|
||||
* This class represents the SpongeVanilla Minecraft server type
|
||||
*/
|
||||
public class SpongeVanilla extends AbstractServerType {
|
||||
|
||||
private final String versionURL;
|
||||
private final String srcStart;
|
||||
private final String srcEnd;
|
||||
private final String downloadURLPart;
|
||||
Function<String, String> oldVersionFunction;
|
||||
BiConsumer<String, String> versionUpdateFunction;
|
||||
final ServerVersionContainer serverVersionContainer;
|
||||
|
||||
/**
|
||||
* Instantiates a new SpongeVanilla server type
|
||||
*
|
||||
* @param typeName <p>The name of this server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>Available versions for this server type</p>
|
||||
* @param versionURL <p>The URL used for downloading the version document</p>
|
||||
* @param srcStart <p>The string to search for to determine newest version</p>
|
||||
* @param srcEnd <p>The string marking the end of the newest version statement</p>
|
||||
* @param downloadURL <p>The URL used for downloading the new file</p>
|
||||
* @param downloadURLPart <p>A string used after the download url as an additional part of the URL</p>
|
||||
*/
|
||||
public SpongeVanilla(String typeName, boolean isProxy, String[] versions, String versionURL, String srcStart, String srcEnd,
|
||||
String downloadURL, String downloadURLPart) {
|
||||
super(typeName, isProxy, versions, downloadURL);
|
||||
this.serverVersionContainer = ServerVersionContainer.getInstance();
|
||||
this.versionURL = versionURL;
|
||||
this.srcStart = srcStart;
|
||||
this.srcEnd = srcEnd;
|
||||
this.downloadURLPart = downloadURLPart;
|
||||
this.oldVersionFunction = serverVersionContainer::getSpongeVanillaVersion;
|
||||
this.versionUpdateFunction = serverVersionContainer::setSpongeVanillaVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean downloadJar(String folder, String version) throws IOException {
|
||||
String file = this.getName() + version + ".jar";
|
||||
File filePath = new File(folder + file);
|
||||
|
||||
String versionText = CommonFunctions.readRemoteFile(versionURL + version);
|
||||
String newestVersion = CommonFunctions.stringBetween(versionText, srcStart, srcEnd);
|
||||
|
||||
String jarURL = downloadURL + newestVersion + downloadURLPart + newestVersion + ".jar";
|
||||
|
||||
String oldVersion = this.oldVersionFunction.apply(version);
|
||||
//The file is already the newest version
|
||||
if (filePath.isFile() && newestVersion.equals(oldVersion)) {
|
||||
return true;
|
||||
}
|
||||
//The new jar file could not be downloaded
|
||||
if (!downloadFile(jarURL, Paths.get(filePath.toURI()))) {
|
||||
return false;
|
||||
}
|
||||
versionUpdateFunction.accept(version, newestVersion);
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
/**
|
||||
* This class represents the Travertine proxy server type
|
||||
*/
|
||||
public class Travertine extends Waterfall {
|
||||
|
||||
/**
|
||||
* Instantiates a new Travertine server type
|
||||
*
|
||||
* @param typeName <p>The name of the server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>The available versions for the server type</p>
|
||||
* @param versionURL <p>The URL used to finding the newest version</p>
|
||||
* @param srcStart <p>The string after which the version id starts</p>
|
||||
* @param srcEnd <p>The string marking the end of the version id</p>
|
||||
* @param downloadURL <p>The URL used for downloading the latest version</p>
|
||||
*/
|
||||
public Travertine(String typeName, boolean isProxy, String[] versions, String versionURL, String srcStart,
|
||||
String srcEnd, String downloadURL) {
|
||||
super(typeName, isProxy, versions, versionURL, srcStart, srcEnd, downloadURL);
|
||||
this.oldVersionFunction = serverVersionContainer::getTravertineVersion;
|
||||
this.versionUpdateFunction = serverVersionContainer::setTravertineVersion;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerVersionContainer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readRemoteFile;
|
||||
|
||||
/**
|
||||
* This class represents the regular vanilla Minecraft server type
|
||||
*/
|
||||
public class Vanilla extends AbstractServerType {
|
||||
|
||||
private final String versionURL;
|
||||
|
||||
/**
|
||||
* Instantiates a vanilla server type
|
||||
*
|
||||
* @param typeName <p>The name of this server type to display</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>Available versions for this server type</p>
|
||||
* @param versionURL <p>The URL used for downloading the version document</p>
|
||||
* @param downloadURL <p>The URL used for downloading the new file</p>
|
||||
*/
|
||||
public Vanilla(String typeName, boolean isProxy, String[] versions, String versionURL, String downloadURL) {
|
||||
super(typeName, isProxy, versions, downloadURL);
|
||||
this.versionURL = versionURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean downloadJar(String folder, String version) throws IOException {
|
||||
ServerVersionContainer versionContainer = ServerVersionContainer.getInstance();
|
||||
String file = this.getName() + version + ".jar";
|
||||
File filePath = new File(folder + file);
|
||||
if (version.equals("Latest") || version.equals("Snapshot")) {
|
||||
String releaseType = version.equals("Latest") ? "release" : "snapshot";
|
||||
String lastVersion = version.equals("Latest") ? versionContainer.getVanillaVersion() :
|
||||
versionContainer.getSnapshotVersion();
|
||||
return downloadLatestJar(filePath, releaseType, lastVersion, versionContainer);
|
||||
} else {
|
||||
String downloadURL = getVanillaDownloadURL(getServerFileVersionURL(version));
|
||||
return filePath.isFile() || downloadFile(downloadURL, Paths.get(filePath.toURI()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the latest .jar file found if necessary
|
||||
*
|
||||
* @param filePath <p>The path of the jar file to download</p>
|
||||
* @param releaseType <p>The release type used for downloading</p>
|
||||
* @param lastVersion <p>The last server version found</p>
|
||||
* @param versionContainer <p>The version container to use</p>
|
||||
* @return <p>True if the jar exists and is the latest version or was downloaded</p>
|
||||
* @throws IOException <p>If the .jar cannot be downloaded</p>
|
||||
*/
|
||||
private boolean downloadLatestJar(File filePath, String releaseType, String lastVersion,
|
||||
ServerVersionContainer versionContainer) throws IOException {
|
||||
String[] latestData = getLatestFile(releaseType);
|
||||
String latest = latestData[0];
|
||||
String jarFile = latestData[1];
|
||||
//The file is already the newest version
|
||||
if (filePath.isFile() && latest.equals(lastVersion)) {
|
||||
return true;
|
||||
}
|
||||
//The new jar file could not be downloaded
|
||||
if (!downloadFile(jarFile, Paths.get(filePath.toURI()))) {
|
||||
return false;
|
||||
}
|
||||
if (releaseType.equals("release")) {
|
||||
versionContainer.setVanillaVersion(latest);
|
||||
} else {
|
||||
versionContainer.setSnapshotVersion(latest);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL to the .jar file for the newest version
|
||||
*
|
||||
* @param releaseType <p>The type of release to read latest version from</p>
|
||||
* @return <p>An array containing the latest version and a link to its file</p>
|
||||
* @throws IOException <p>If the remote resource cannot be readFromServer</p>
|
||||
*/
|
||||
private String[] getLatestFile(String releaseType) throws IOException {
|
||||
String versionText = readRemoteFile(versionURL);
|
||||
JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
|
||||
String latest = jsonObject.getAsJsonObject("latest").get(releaseType).getAsString();
|
||||
String versionURL = getServerFileVersionURL(latest);
|
||||
String jarURL = getVanillaDownloadURL(versionURL);
|
||||
return new String[]{latest, jarURL};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL necessary for downloading a given minecraft .jar file
|
||||
*
|
||||
* @param versionURL <p>The URL to the version document describing the .jar file</p>
|
||||
* @return <p>The URL necessary do download the .jar file</p>
|
||||
* @throws IOException <p>If the remote resource cannot be readFromServer</p>
|
||||
*/
|
||||
private String getVanillaDownloadURL(String versionURL) throws IOException {
|
||||
String versionText = readRemoteFile(versionURL);
|
||||
JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
|
||||
return jsonObject.getAsJsonObject("downloads").getAsJsonObject("server").get("url").getAsString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version URL from the Minecraft vanilla version document
|
||||
*
|
||||
* @param targetVersion <p>The version to download</p>
|
||||
* @return <p>The URL to the file</p>
|
||||
* @throws IOException <p>If the file cannot be downloaded</p>
|
||||
*/
|
||||
private String getServerFileVersionURL(String targetVersion) throws IOException {
|
||||
String versionText = readRemoteFile(versionURL);
|
||||
JsonObject jsonObject = new JsonParser().parse(versionText).getAsJsonObject();
|
||||
JsonArray availableVersions = jsonObject.getAsJsonArray("versions");
|
||||
for (JsonElement availableVersion : availableVersions) {
|
||||
JsonObject versionObject = availableVersion.getAsJsonObject();
|
||||
if (!versionObject.get("id").getAsString().equals(targetVersion)) {
|
||||
continue;
|
||||
}
|
||||
return versionObject.get("url").getAsString();
|
||||
}
|
||||
throw new FileNotFoundException("Unable to find the requested Minecraft vanilla .jar file.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server.servertypes;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerVersionContainer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readRemoteFile;
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween;
|
||||
|
||||
/**
|
||||
* This class represents the Travertine proxy server type
|
||||
*/
|
||||
public class Waterfall extends AbstractServerType {
|
||||
|
||||
private final String srcStart;
|
||||
private final String srcEnd;
|
||||
private final String versionURL;
|
||||
Function<String, String> oldVersionFunction;
|
||||
BiConsumer<String, String> versionUpdateFunction;
|
||||
final ServerVersionContainer serverVersionContainer;
|
||||
|
||||
/**
|
||||
* Instantiates a new Waterfall server type
|
||||
*
|
||||
* @param typeName <p>The name of the server type</p>
|
||||
* @param isProxy <p>Whether this server type is a proxy server</p>
|
||||
* @param versions <p>The available versions for the server type</p>
|
||||
* @param versionURL <p>The URL used to finding the newest version</p>
|
||||
* @param srcStart <p>The string after which the version id starts</p>
|
||||
* @param srcEnd <p>The string marking the end of the version id</p>
|
||||
* @param downloadURL <p>The URL used for downloading the latest version</p>
|
||||
*/
|
||||
public Waterfall(String typeName, boolean isProxy, String[] versions, String versionURL, String srcStart,
|
||||
String srcEnd, String downloadURL) {
|
||||
super(typeName, isProxy, versions, downloadURL);
|
||||
this.serverVersionContainer = ServerVersionContainer.getInstance();
|
||||
this.srcStart = srcStart;
|
||||
this.srcEnd = srcEnd;
|
||||
this.versionURL = versionURL;
|
||||
this.oldVersionFunction = serverVersionContainer::getWaterfallVersion;
|
||||
this.versionUpdateFunction = serverVersionContainer::setWaterfallVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean downloadJar(String folder, String version) throws IOException {
|
||||
String file = this.getName() + version + ".jar";
|
||||
File filePath = new File(folder + file);
|
||||
String versionFileContents = readRemoteFile(versionURL + version);
|
||||
String[] versions = stringBetween(versionFileContents, srcStart, srcEnd).split(",");
|
||||
String newestVersion = versions[versions.length - 1];
|
||||
String oldVersion = oldVersionFunction.apply(version);
|
||||
|
||||
//The file is already the newest version
|
||||
if (filePath.isFile() && newestVersion.equals(oldVersion)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//Get necessary information for downloading the latest version
|
||||
String newestVersionInfoURL = versionURL + version + "/builds/" + newestVersion;
|
||||
String fileName = stringBetween(readRemoteFile(newestVersionInfoURL), "\"name\":\"", "\"");
|
||||
String fullURL = downloadURL + version + "/builds/" + newestVersion + "/downloads/" + fileName;
|
||||
|
||||
//The new jar file could not be downloaded
|
||||
if (!downloadFile(fullURL, Paths.get(filePath.toURI()))) {
|
||||
return false;
|
||||
}
|
||||
versionUpdateFunction.accept(version, newestVersion);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.IOException;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
|
||||
|
||||
/**
|
||||
* The Backup GUI is used to display backup progress
|
||||
*/
|
||||
public class BackupGUI implements ActionListener {
|
||||
private static JFrame frame;
|
||||
private static JTextArea progressTextArea;
|
||||
private static JProgressBar progressBar;
|
||||
private static JButton cancelButton;
|
||||
|
||||
/**
|
||||
* Instantiates a new GUI
|
||||
*/
|
||||
public BackupGUI() {
|
||||
instantiate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the server consoles frame
|
||||
*/
|
||||
public void instantiate() {
|
||||
if (frame != null) {
|
||||
return;
|
||||
}
|
||||
frame = new JFrame("Running backup...");
|
||||
frame.setBounds(100, 100, 500, 140);
|
||||
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||
ImageIcon img;
|
||||
try {
|
||||
img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png")));
|
||||
frame.setIconImage(img.getImage());
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
|
||||
progressTextArea = new JTextArea();
|
||||
progressTextArea.setEditable(false);
|
||||
progressBar = new JProgressBar();
|
||||
cancelButton = new JButton("Cancel");
|
||||
JPanel panel = new JPanel();
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
|
||||
panel.add(progressTextArea);
|
||||
panel.add(Box.createRigidArea(new Dimension(0, 5)));
|
||||
panel.add(progressBar);
|
||||
|
||||
JPanel buttonPane = new JPanel();
|
||||
buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
|
||||
buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10));
|
||||
buttonPane.add(Box.createHorizontalGlue());
|
||||
buttonPane.add(cancelButton);
|
||||
cancelButton.addActionListener(BackupGUI.this);
|
||||
|
||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
Container contentPane = frame.getContentPane();
|
||||
contentPane.add(panel, BorderLayout.CENTER);
|
||||
contentPane.add(buttonPane, BorderLayout.PAGE_END);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates information about the backup progress
|
||||
*
|
||||
* @param infoText <p>The text to display</p>
|
||||
* @param progressPercent <p>The new percent of the progress bar</p>
|
||||
*/
|
||||
public static void updateProgress(String infoText, int progressPercent) {
|
||||
if (progressTextArea != null) {
|
||||
progressTextArea.setText(infoText);
|
||||
}
|
||||
if (progressBar != null) {
|
||||
progressBar.setValue(progressPercent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the backup GUI
|
||||
*/
|
||||
public static void destroy() {
|
||||
if (frame != null) {
|
||||
frame.dispose();
|
||||
frame = null;
|
||||
progressBar = null;
|
||||
progressTextArea = null;
|
||||
cancelButton = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
if (actionEvent.getSource() == cancelButton) {
|
||||
BackupUtil.abortBackup();
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
/**
|
||||
* Listener for clicking the close button of a server tab
|
||||
*/
|
||||
public class CloseTabActionListener implements ActionListener {
|
||||
|
||||
private final String tabName;
|
||||
private final JTabbedPane tabPane;
|
||||
|
||||
/**
|
||||
* Instantiates a new close tab action listener
|
||||
*
|
||||
* @param tabPane <p>The tab pane containing all tabs</p>
|
||||
* @param tabName <p>The name of the tab connected to this action listener</p>
|
||||
*/
|
||||
public CloseTabActionListener(JTabbedPane tabPane, String tabName) {
|
||||
this.tabName = tabName;
|
||||
this.tabPane = tabPane;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
int index = tabPane.indexOfTab(tabName);
|
||||
if (index >= 0) {
|
||||
//Abort if the user just mis-clicked
|
||||
int answer = JOptionPane.showConfirmDialog(null,
|
||||
String.format("Do you really want to remove the server %s?", tabName), "Remove server",
|
||||
JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
if (answer == JOptionPane.YES_NO_OPTION) {
|
||||
//Remove the server
|
||||
ServerLauncherController controller = Main.getController();
|
||||
controller.getCurrentProfile().removeCollection(tabName);
|
||||
controller.getGUI().updateWithSavedProfileData();
|
||||
controller.getCurrentProfile().updateConsoles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.DefaultCaret;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static javax.swing.text.DefaultCaret.ALWAYS_UPDATE;
|
||||
|
||||
/**
|
||||
* Acts as a single writable/readable tab
|
||||
*
|
||||
* <p>Has a box for user input, and a textArea for server output.</p>
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Console extends KeyAdapter implements ActionListener, KeyListener {
|
||||
private final JTextField textInput;
|
||||
private final JTextArea textOutput;
|
||||
private final String name;
|
||||
private final JPanel panel;
|
||||
private final ArrayList<String> commands = new ArrayList<>();
|
||||
private int commandIndex;
|
||||
private final int maxConsoleLines = 1000;
|
||||
|
||||
/**
|
||||
* Instantiates a new console
|
||||
*
|
||||
* @param tab <p>The tabbed pane used for displaying the console</p>
|
||||
* @param name <p>The name of the console tab</p>
|
||||
*/
|
||||
Console(JTabbedPane tab, String name) {
|
||||
this.name = name;
|
||||
panel = new JPanel();
|
||||
tab.addTab(name, null, panel, null);
|
||||
panel.setLayout(new BorderLayout(0, 0));
|
||||
textInput = new JTextField();
|
||||
panel.add(textInput, BorderLayout.SOUTH);
|
||||
textInput.setColumns(10);
|
||||
textInput.addActionListener(this);
|
||||
textOutput = new JTextArea();
|
||||
JScrollPane scroll = new JScrollPane(textOutput);
|
||||
panel.add(scroll, BorderLayout.CENTER);
|
||||
textOutput.setEditable(false);
|
||||
DefaultCaret caret = (DefaultCaret) textOutput.getCaret();
|
||||
caret.setUpdatePolicy(ALWAYS_UPDATE);
|
||||
textOutput.setLineWrap(true);
|
||||
textInput.addKeyListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the JPanel this console is drawn on
|
||||
*
|
||||
* @return <p>The JPanel this console is drawn on</p>
|
||||
*/
|
||||
public JPanel getPanel() {
|
||||
return this.panel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a string to the console's output
|
||||
*
|
||||
* @param text <p>The string to print</p>
|
||||
*/
|
||||
public void output(String text) {
|
||||
int outputLines = this.textOutput.getLineCount();
|
||||
if (outputLines > maxConsoleLines) {
|
||||
truncateConsole(outputLines);
|
||||
}
|
||||
this.textOutput.setText(this.textOutput.getText() + "\n" + text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates the first 50 lines if the console output has reached the max limit
|
||||
*
|
||||
* @param outputLines <p>The currently readable lines in the console output field</p>
|
||||
*/
|
||||
private void truncateConsole(int outputLines) {
|
||||
String oldText = this.textOutput.getText();
|
||||
String[] oldTextList = oldText.split("\n");
|
||||
for (int i = 0; i < outputLines - maxConsoleLines + 50; i++) {
|
||||
oldTextList[i] = "";
|
||||
}
|
||||
StringBuilder newTextBuilder = new StringBuilder();
|
||||
for (String line : oldTextList) {
|
||||
if (!line.equals("")) {
|
||||
newTextBuilder.append(line).append("\n");
|
||||
}
|
||||
}
|
||||
this.textOutput.setText(newTextBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
//Sends the command from the input to the server with the same name.
|
||||
if (e.getSource() == textInput) {
|
||||
java.lang.String text = textInput.getText();
|
||||
Main.getController().getCurrentProfile().sendCommand(this.name, text);
|
||||
commands.add(text);
|
||||
if (commands.size() > 25) {
|
||||
commands.remove(0);
|
||||
}
|
||||
commandIndex = commands.size();
|
||||
textInput.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
//Cycles through previously used commands
|
||||
if (e.getKeyCode() == KeyEvent.VK_UP) {
|
||||
showPreviousCommand();
|
||||
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
|
||||
showNextCommand();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,218 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.BackupUtil;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class ControlPanelTab implements ActionListener {
|
||||
|
||||
private JButton startServerButton;
|
||||
private JButton stopServerButton;
|
||||
private JButton backupButton;
|
||||
private JButton addProfileButton;
|
||||
private JButton showConsolesButton;
|
||||
private JButton deleteProfileButton;
|
||||
private JComboBox<String> profiles;
|
||||
private final JPanel controlPanelPanel;
|
||||
private final ServerLauncherController controller;
|
||||
private final JLabel statusLabel = new JLabel("Servers are stopped");
|
||||
|
||||
public ControlPanelTab(JPanel controlPanelPanel) {
|
||||
this.controlPanelPanel = controlPanelPanel;
|
||||
this.controller = Main.getController();
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text of the status label
|
||||
*
|
||||
* @param text <p>The new text of the status label</p>
|
||||
*/
|
||||
public void setStatusText(String text) {
|
||||
this.statusLabel.setText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ServerLauncherGUI components to block a user from doing illegal actions
|
||||
*
|
||||
* @param running <p>Whether the servers are currently running</p>
|
||||
*/
|
||||
public void updateGUIElementsWhenServersStartOrStop(boolean running) {
|
||||
boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running.
|
||||
profiles.setEnabled(stopped);
|
||||
addProfileButton.setEnabled(stopped);
|
||||
deleteProfileButton.setEnabled(stopped);
|
||||
startServerButton.setEnabled(stopped);
|
||||
stopServerButton.setEnabled(running);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all servers
|
||||
*/
|
||||
public void stopServers() {
|
||||
GUI gui = Main.getController().getGUI();
|
||||
try {
|
||||
gui.setStatus("Servers are stopping...");
|
||||
ServerHandler.stop();
|
||||
} catch (IOException e1) {
|
||||
gui.showError("Could not stop server.");
|
||||
e1.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
gui.showError("Could not kill server.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently selected profile
|
||||
*
|
||||
* @return <p>The currently selected profile or null</p>
|
||||
*/
|
||||
public String getSelectedProfile() {
|
||||
Object selectedProfile = profiles.getSelectedItem();
|
||||
if (selectedProfile != null) {
|
||||
return selectedProfile.toString();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the profiles combo
|
||||
*/
|
||||
public void updateProfiles() {
|
||||
String selectedProfile = Main.getController().getCurrentProfile().getName();
|
||||
this.profiles.removeAllItems();
|
||||
for (String profile : Main.getController().getProfileNames()) {
|
||||
this.profiles.addItem(profile);
|
||||
}
|
||||
this.profiles.setSelectedItem(selectedProfile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the selected profile
|
||||
*/
|
||||
private void deleteProfile() {
|
||||
Object selected = profiles.getSelectedItem();
|
||||
int answer = JOptionPane.showConfirmDialog(null,
|
||||
String.format("Do you really want to remove the profile %s?", selected), "Remove profile",
|
||||
JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
if (answer == JOptionPane.YES_NO_OPTION) {
|
||||
if (selected != null) {
|
||||
controller.removeProfile(selected.toString());
|
||||
updateProfiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the previous profile and loads data from the new profile
|
||||
*/
|
||||
private void changeProfile() {
|
||||
controller.saveState();
|
||||
Object current = this.profiles.getSelectedItem();
|
||||
if (current != null) {
|
||||
controller.setCurrentProfile(current.toString());
|
||||
}
|
||||
controller.getGUI().updateWithSavedProfileData();
|
||||
controller.getCurrentProfile().updateConsoles();
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
SpringLayout springLayout = new SpringLayout();
|
||||
controlPanelPanel.setLayout(springLayout);
|
||||
|
||||
JLabel lblBasicControls = new JLabel("Basic controls");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, lblBasicControls, 10, SpringLayout.NORTH, controlPanelPanel);
|
||||
controlPanelPanel.add(lblBasicControls);
|
||||
|
||||
startServerButton = new JButton("Start servers");
|
||||
springLayout.putConstraint(SpringLayout.WEST, lblBasicControls, 0, SpringLayout.WEST, startServerButton);
|
||||
springLayout.putConstraint(SpringLayout.NORTH, startServerButton, 6, SpringLayout.SOUTH, lblBasicControls);
|
||||
springLayout.putConstraint(SpringLayout.WEST, startServerButton, 10, SpringLayout.WEST, controlPanelPanel);
|
||||
controlPanelPanel.add(startServerButton);
|
||||
startServerButton.addActionListener(this);
|
||||
|
||||
stopServerButton = new JButton("Stop servers");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, stopServerButton, 0, SpringLayout.NORTH, startServerButton);
|
||||
springLayout.putConstraint(SpringLayout.WEST, stopServerButton, 6, SpringLayout.EAST, startServerButton);
|
||||
controlPanelPanel.add(stopServerButton);
|
||||
stopServerButton.addActionListener(this);
|
||||
|
||||
showConsolesButton = new JButton("View server consoles");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, showConsolesButton, 0, SpringLayout.NORTH, stopServerButton);
|
||||
springLayout.putConstraint(SpringLayout.WEST, showConsolesButton, 6, SpringLayout.EAST, stopServerButton);
|
||||
controlPanelPanel.add(showConsolesButton);
|
||||
showConsolesButton.addActionListener(this);
|
||||
|
||||
backupButton = new JButton("Backup");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, backupButton, 0, SpringLayout.NORTH, showConsolesButton);
|
||||
springLayout.putConstraint(SpringLayout.WEST, backupButton, 6, SpringLayout.EAST, showConsolesButton);
|
||||
controlPanelPanel.add(backupButton);
|
||||
backupButton.addActionListener(this);
|
||||
|
||||
JLabel profileLabel = new JLabel("Profile");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, profileLabel, 6, SpringLayout.SOUTH, startServerButton);
|
||||
springLayout.putConstraint(SpringLayout.WEST, profileLabel, 10, SpringLayout.WEST, controlPanelPanel);
|
||||
controlPanelPanel.add(profileLabel);
|
||||
|
||||
addProfileButton = new JButton("+");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, addProfileButton, 6, SpringLayout.SOUTH, profileLabel);
|
||||
springLayout.putConstraint(SpringLayout.WEST, addProfileButton, 10, SpringLayout.WEST, controlPanelPanel);
|
||||
controlPanelPanel.add(addProfileButton);
|
||||
addProfileButton.addActionListener(this);
|
||||
|
||||
deleteProfileButton = new JButton("-");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, deleteProfileButton, 0, SpringLayout.NORTH, addProfileButton);
|
||||
springLayout.putConstraint(SpringLayout.WEST, deleteProfileButton, 6, SpringLayout.EAST, addProfileButton);
|
||||
controlPanelPanel.add(deleteProfileButton);
|
||||
deleteProfileButton.addActionListener(this);
|
||||
|
||||
profiles = new JComboBox<>();
|
||||
springLayout.putConstraint(SpringLayout.NORTH, profiles, 0, SpringLayout.NORTH, addProfileButton);
|
||||
springLayout.putConstraint(SpringLayout.WEST, profiles, 6, SpringLayout.EAST, deleteProfileButton);
|
||||
springLayout.putConstraint(SpringLayout.EAST, profiles, 124, SpringLayout.EAST, deleteProfileButton);
|
||||
controlPanelPanel.add(profiles);
|
||||
profiles.addActionListener(this);
|
||||
|
||||
springLayout.putConstraint(SpringLayout.NORTH, statusLabel, 6, SpringLayout.SOUTH, addProfileButton);
|
||||
springLayout.putConstraint(SpringLayout.SOUTH, statusLabel, -10, SpringLayout.SOUTH, controlPanelPanel);
|
||||
springLayout.putConstraint(SpringLayout.WEST, statusLabel, 10, SpringLayout.WEST, controlPanelPanel);
|
||||
springLayout.putConstraint(SpringLayout.EAST, statusLabel, -10, SpringLayout.EAST, controlPanelPanel);
|
||||
statusLabel.setFont(new Font("", Font.BOLD, 12));
|
||||
controlPanelPanel.add(statusLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
Object actionSource = actionEvent.getSource();
|
||||
if (actionSource == startServerButton) {
|
||||
controller.saveState();
|
||||
Executors.newSingleThreadExecutor().execute(ServerHandler::startServers);
|
||||
} else if (actionSource == stopServerButton) {
|
||||
stopServers();
|
||||
} else if (actionSource == backupButton) {
|
||||
//Run backup in its own thread to prevent locking up
|
||||
Executors.newSingleThreadExecutor().execute(() -> BackupUtil.backup(controller.getGUI()));
|
||||
} else if (actionSource == addProfileButton) {
|
||||
controller.addProfile(JOptionPane.showInputDialog("Profile name: "));
|
||||
updateProfiles();
|
||||
} else if (actionSource == deleteProfileButton) {
|
||||
deleteProfile();
|
||||
} else if (actionSource == profiles) {
|
||||
changeProfile();
|
||||
} else if (actionSource == showConsolesButton) {
|
||||
ServerConsoles.setAsVisible();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Describes a generic GUI
|
||||
*/
|
||||
public interface GUI {
|
||||
|
||||
/**
|
||||
* Displays a message to the user in the GUI message field
|
||||
*
|
||||
* @param message <p>The message contents</p>
|
||||
*/
|
||||
void setStatus(String message);
|
||||
|
||||
/**
|
||||
* Displays an error to the user as an independent box
|
||||
*
|
||||
* @param title <p>The title of the error message</p>
|
||||
* @param message <p>The error message contents</p>
|
||||
*/
|
||||
void showError(String title, String message);
|
||||
|
||||
/**
|
||||
* Displays an error to the user as an independent box
|
||||
*
|
||||
* @param message <p>The error message contents</p>
|
||||
*/
|
||||
void showError(String message);
|
||||
|
||||
/**
|
||||
* Displays a message to the user as an independent box
|
||||
*
|
||||
* @param title <p>The title of the message</p>
|
||||
* @param message <p>The message contents</p>
|
||||
*/
|
||||
void showMessage(String title, String message);
|
||||
|
||||
/**
|
||||
* Displays a message to the user as an independent box
|
||||
*
|
||||
* @param message <p>The message contents</p>
|
||||
*/
|
||||
void showMessage(String message);
|
||||
|
||||
/**
|
||||
* Logs a message to the logfile
|
||||
*
|
||||
* @param message <p>The message to log</p>
|
||||
*/
|
||||
void logMessage(String message);
|
||||
|
||||
/**
|
||||
* Logs an error to the logfile
|
||||
*
|
||||
* @param error <p>The error to log</p>
|
||||
*/
|
||||
void logError(String error);
|
||||
|
||||
/**
|
||||
* Asks the user for a directory as a file object
|
||||
*
|
||||
* @param prompt <p>The prompt to show the user</p>
|
||||
* @return <p>The directory given by the user</p>
|
||||
*/
|
||||
File askForDirectory(String prompt);
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
/**
|
||||
* This class handles displaying messages to the user
|
||||
*/
|
||||
public abstract class MessageHandler implements GUI {
|
||||
|
||||
private final boolean silent;
|
||||
private final BufferedWriter writer;
|
||||
private final String logFile = Main.getApplicationWorkDirectory() + File.separator + "latestrun.log";
|
||||
|
||||
/***
|
||||
* Initializes a new message handler
|
||||
*
|
||||
* @param silent <p>Whether to print to cli instead of showing a GUI element</p>
|
||||
*/
|
||||
public MessageHandler(boolean silent) {
|
||||
this.silent = silent;
|
||||
this.writer = new BufferedWriter(new OutputStreamWriter(System.out));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logMessage(String message) {
|
||||
try {
|
||||
CommonFunctions.appendFile(logFile, "[Info]: " + message);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logError(String message) {
|
||||
try {
|
||||
CommonFunctions.appendFile(logFile, "[Error]: " + message);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String title, String message) {
|
||||
if (silent) {
|
||||
try {
|
||||
writer.write("[Error]: ");
|
||||
writer.write(message);
|
||||
writer.newLine();
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
System.out.println(message);
|
||||
}
|
||||
} else {
|
||||
showJOptionPane(title, message, JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
logError(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showError(String message) {
|
||||
showError("Error", message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage(String title, String message) {
|
||||
if (silent) {
|
||||
try {
|
||||
writer.write("[Info]: " + message);
|
||||
writer.newLine();
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
System.out.println(message);
|
||||
}
|
||||
} else {
|
||||
showJOptionPane(title, message, JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
logMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMessage(String message) {
|
||||
showMessage("Info", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a JOptionPane
|
||||
*
|
||||
* @param title <p>The title of the pane</p>
|
||||
* @param message <p>The message of the pane</p>
|
||||
* @param paneType <p>The type of the pane</p>
|
||||
*/
|
||||
private void showJOptionPane(String title, String message, int paneType) {
|
||||
JOptionPane.showMessageDialog(null, message, title, paneType);
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
|
||||
|
||||
/**
|
||||
* This class keeps track of all consoles
|
||||
*
|
||||
* <p>A parent window for server consoles. Should be toggled with the "View server consoles" button.
|
||||
* Keeps track of all consoles.</p>
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ServerConsoles {
|
||||
private static JFrame frame;
|
||||
private static JTabbedPane consolesTabbedPane;
|
||||
|
||||
private ServerConsoles() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the server consoles frame
|
||||
*/
|
||||
public static void instantiate() {
|
||||
if (frame == null || consolesTabbedPane == null) {
|
||||
frame = new JFrame();
|
||||
frame.setBounds(100, 100, 450, 300);
|
||||
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
consolesTabbedPane = new JTabbedPane(JTabbedPane.TOP);
|
||||
frame.getContentPane().add(consolesTabbedPane, BorderLayout.CENTER);
|
||||
ImageIcon img;
|
||||
try {
|
||||
img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png")));
|
||||
frame.setIconImage(img.getImage());
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the server consoles frame as visible
|
||||
*/
|
||||
public static void setAsVisible() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tabbed pane containing the server consoles
|
||||
*
|
||||
* @return <p>The tabbed pane containing the server consoles</p>
|
||||
*/
|
||||
public static JTabbedPane getTabbedPane() {
|
||||
return consolesTabbedPane;
|
||||
}
|
||||
}
|
@ -0,0 +1,263 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.profile.Collection;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This class takes care of all server controls on the server control tab
|
||||
*/
|
||||
public class ServerControlTab implements ActionListener {
|
||||
|
||||
private JComboBox<String> targetServerCombo;
|
||||
private JComboBox<String> targetPlayerCombo;
|
||||
private JButton kickButton;
|
||||
private JButton banButton;
|
||||
private JButton opButton;
|
||||
private JButton deopButton;
|
||||
private JButton customCommandButton;
|
||||
private JButton saveServerButton;
|
||||
private JButton reloadButton;
|
||||
private JTextField customCommandTextField;
|
||||
|
||||
private final ServerLauncherController controller = ServerLauncherController.getInstance();
|
||||
private final ArrayList<String> globalPlayers;
|
||||
|
||||
/**
|
||||
* Instantiates a new server control tab
|
||||
*
|
||||
* @param mainFrame <p>The main frame of the GUI</p>
|
||||
* @param controlServers <p>The JPanel to attach the server controls to</p>
|
||||
*/
|
||||
public ServerControlTab(JFrame mainFrame, JPanel controlServers) {
|
||||
this.globalPlayers = new ArrayList<>();
|
||||
initialize(mainFrame, controlServers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes GUI elements for the server control tab
|
||||
*
|
||||
* @param mainFrame <p>The main frame of the GUI</p>
|
||||
* @param controlServers <p>The JPanel to attach the server controls to</p>
|
||||
*/
|
||||
private void initialize(JFrame mainFrame, JPanel controlServers) {
|
||||
SpringLayout springLayout = new SpringLayout();
|
||||
controlServers.setLayout(springLayout);
|
||||
targetServerCombo = new JComboBox<>();
|
||||
springLayout.putConstraint(SpringLayout.NORTH, targetServerCombo, 10, SpringLayout.NORTH, controlServers);
|
||||
controlServers.add(targetServerCombo);
|
||||
targetServerCombo.addActionListener(this);
|
||||
|
||||
targetPlayerCombo = new JComboBox<>();
|
||||
springLayout.putConstraint(SpringLayout.NORTH, targetPlayerCombo, 6, SpringLayout.SOUTH, targetServerCombo);
|
||||
targetPlayerCombo.setEditable(true);
|
||||
controlServers.add(targetPlayerCombo);
|
||||
|
||||
kickButton = new JButton("Kick");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, kickButton, 10, SpringLayout.NORTH, controlServers);
|
||||
springLayout.putConstraint(SpringLayout.WEST, kickButton, 6, SpringLayout.EAST, targetServerCombo);
|
||||
springLayout.putConstraint(SpringLayout.EAST, kickButton, 104, SpringLayout.WEST, kickButton);
|
||||
springLayout.putConstraint(SpringLayout.SOUTH, targetServerCombo, 0, SpringLayout.SOUTH, kickButton);
|
||||
controlServers.add(kickButton);
|
||||
kickButton.addActionListener(this);
|
||||
|
||||
banButton = new JButton("Ban");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, banButton, 6, SpringLayout.SOUTH, kickButton);
|
||||
springLayout.putConstraint(SpringLayout.WEST, banButton, 6, SpringLayout.EAST, targetPlayerCombo);
|
||||
springLayout.putConstraint(SpringLayout.EAST, banButton, 104, SpringLayout.WEST, banButton);
|
||||
springLayout.putConstraint(SpringLayout.SOUTH, targetPlayerCombo, 0, SpringLayout.SOUTH, banButton);
|
||||
controlServers.add(banButton);
|
||||
banButton.addActionListener(this);
|
||||
|
||||
opButton = new JButton("OP");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, opButton, 10, SpringLayout.NORTH, controlServers);
|
||||
springLayout.putConstraint(SpringLayout.WEST, opButton, 6, SpringLayout.EAST, kickButton);
|
||||
springLayout.putConstraint(SpringLayout.EAST, opButton, -10, SpringLayout.EAST, controlServers);
|
||||
controlServers.add(opButton);
|
||||
opButton.addActionListener(this);
|
||||
|
||||
deopButton = new JButton("DEOP");
|
||||
springLayout.putConstraint(SpringLayout.WEST, deopButton, 6, SpringLayout.EAST, banButton);
|
||||
springLayout.putConstraint(SpringLayout.NORTH, deopButton, 5, SpringLayout.SOUTH, opButton);
|
||||
springLayout.putConstraint(SpringLayout.EAST, deopButton, -10, SpringLayout.EAST, controlServers);
|
||||
controlServers.add(deopButton);
|
||||
deopButton.addActionListener(this);
|
||||
|
||||
JLabel lblTargetServer = new JLabel("Target server");
|
||||
springLayout.putConstraint(SpringLayout.WEST, targetServerCombo, 6, SpringLayout.EAST, lblTargetServer);
|
||||
springLayout.putConstraint(SpringLayout.EAST, targetServerCombo, 121, SpringLayout.EAST, lblTargetServer);
|
||||
springLayout.putConstraint(SpringLayout.NORTH, lblTargetServer, 10, SpringLayout.NORTH, controlServers);
|
||||
springLayout.putConstraint(SpringLayout.SOUTH, lblTargetServer, 0, SpringLayout.SOUTH, targetServerCombo);
|
||||
springLayout.putConstraint(SpringLayout.WEST, lblTargetServer, 10, SpringLayout.WEST, controlServers);
|
||||
controlServers.add(lblTargetServer);
|
||||
|
||||
JLabel lblTargetPlayer = new JLabel("Target player");
|
||||
springLayout.putConstraint(SpringLayout.WEST, targetPlayerCombo, 7, SpringLayout.EAST, lblTargetPlayer);
|
||||
springLayout.putConstraint(SpringLayout.EAST, targetPlayerCombo, 122, SpringLayout.EAST, lblTargetPlayer);
|
||||
springLayout.putConstraint(SpringLayout.NORTH, lblTargetPlayer, 6, SpringLayout.SOUTH, lblTargetServer);
|
||||
springLayout.putConstraint(SpringLayout.SOUTH, lblTargetPlayer, 0, SpringLayout.SOUTH, targetPlayerCombo);
|
||||
springLayout.putConstraint(SpringLayout.WEST, lblTargetPlayer, 0, SpringLayout.WEST, lblTargetServer);
|
||||
controlServers.add(lblTargetPlayer);
|
||||
|
||||
customCommandButton = new JButton("Custom command");
|
||||
springLayout.putConstraint(SpringLayout.WEST, customCommandButton, 250, SpringLayout.WEST, controlServers);
|
||||
springLayout.putConstraint(SpringLayout.EAST, customCommandButton, 0, SpringLayout.EAST, opButton);
|
||||
controlServers.add(customCommandButton);
|
||||
customCommandButton.addActionListener(this);
|
||||
mainFrame.getRootPane().setDefaultButton(customCommandButton);
|
||||
|
||||
customCommandTextField = new JTextField();
|
||||
springLayout.putConstraint(SpringLayout.WEST, customCommandTextField, 10, SpringLayout.WEST, controlServers);
|
||||
springLayout.putConstraint(SpringLayout.EAST, customCommandTextField, -6, SpringLayout.WEST, customCommandButton);
|
||||
springLayout.putConstraint(SpringLayout.NORTH, customCommandButton, 0, SpringLayout.NORTH, customCommandTextField);
|
||||
springLayout.putConstraint(SpringLayout.SOUTH, customCommandTextField, 0, SpringLayout.SOUTH, customCommandButton);
|
||||
controlServers.add(customCommandTextField);
|
||||
customCommandTextField.setColumns(10);
|
||||
|
||||
saveServerButton = new JButton("Save server");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, customCommandTextField, 6, SpringLayout.SOUTH, saveServerButton);
|
||||
springLayout.putConstraint(SpringLayout.NORTH, saveServerButton, 6, SpringLayout.SOUTH, banButton);
|
||||
springLayout.putConstraint(SpringLayout.WEST, saveServerButton, 0, SpringLayout.WEST, kickButton);
|
||||
springLayout.putConstraint(SpringLayout.EAST, saveServerButton, 104, SpringLayout.WEST, kickButton);
|
||||
springLayout.putConstraint(SpringLayout.EAST, saveServerButton, 104, SpringLayout.WEST, kickButton);
|
||||
controlServers.add(saveServerButton);
|
||||
saveServerButton.addActionListener(this);
|
||||
|
||||
reloadButton = new JButton("Reload");
|
||||
springLayout.putConstraint(SpringLayout.NORTH, reloadButton, 6, SpringLayout.SOUTH, deopButton);
|
||||
springLayout.putConstraint(SpringLayout.WEST, reloadButton, 0, SpringLayout.WEST, deopButton);
|
||||
springLayout.putConstraint(SpringLayout.EAST, reloadButton, 0, SpringLayout.EAST, opButton);
|
||||
controlServers.add(reloadButton);
|
||||
reloadButton.addActionListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates available servers according to existing collections
|
||||
*/
|
||||
public void update() {
|
||||
this.targetServerCombo.removeAllItems();
|
||||
this.targetServerCombo.addItem("All");
|
||||
for (Collection collection : ServerLauncherController.getInstance().getCurrentProfile().getCollections()) {
|
||||
this.targetServerCombo.addItem(collection.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
//Registers actions on the server control tab
|
||||
handleServerControlTabButtons(actionEvent.getSource());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles buttons and combos on the server control tab
|
||||
*
|
||||
* @param actionSource <p>The object being interacted with</p>
|
||||
*/
|
||||
private void handleServerControlTabButtons(Object actionSource) {
|
||||
String selectedServerValue = null;
|
||||
String selectedPlayerValue = null;
|
||||
Object selectedServer = targetServerCombo.getSelectedItem();
|
||||
if (selectedServer != null) {
|
||||
selectedServerValue = selectedServer.toString();
|
||||
}
|
||||
Object selectedPlayer = targetPlayerCombo.getSelectedItem();
|
||||
if (selectedPlayer != null) {
|
||||
selectedPlayerValue = selectedPlayer.toString();
|
||||
}
|
||||
//Register actions on all commands executed on a specific player
|
||||
handlePlayerCommands(actionSource, selectedServerValue, selectedPlayerValue);
|
||||
//Registers actions on all commands executed on a specific server
|
||||
handleServerCommands(actionSource, selectedServerValue);
|
||||
|
||||
if (actionSource == targetServerCombo) {
|
||||
updatePlayers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the list of players currently online on the selected server
|
||||
*/
|
||||
private void updatePlayers() {
|
||||
String selectedServerValue;
|
||||
Object selectedServer = targetServerCombo.getSelectedItem();
|
||||
if (selectedServer != null) {
|
||||
targetPlayerCombo.removeAllItems();
|
||||
selectedServerValue = selectedServer.toString();
|
||||
if (selectedServerValue.equals("All")) {
|
||||
for (String player : this.globalPlayers) {
|
||||
targetPlayerCombo.addItem(player);
|
||||
}
|
||||
} else {
|
||||
for (String player : controller.getCurrentProfile().getCollection(selectedServerValue).getServer().getPlayers()) {
|
||||
targetPlayerCombo.addItem(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a player to the global player list, and updates the players combo
|
||||
*
|
||||
* @param name <p>The name of the player to add</p>
|
||||
*/
|
||||
public void addPlayer(String name) {
|
||||
this.globalPlayers.add(name);
|
||||
this.updatePlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a player from the global list of players
|
||||
*
|
||||
* @param name <p>The name of the player to remove</p>
|
||||
*/
|
||||
public void removePlayer(String name) {
|
||||
globalPlayers.removeIf(playerName -> playerName.equals(name));
|
||||
this.updatePlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles command buttons acting on a specific server
|
||||
*
|
||||
* @param actionSource <p>The object being interacted with</p>
|
||||
* @param selectedServerValue <p>The server currently selected</p>
|
||||
*/
|
||||
private void handleServerCommands(Object actionSource, String selectedServerValue) {
|
||||
if (selectedServerValue == null) {
|
||||
return;
|
||||
}
|
||||
if (actionSource == customCommandButton) {
|
||||
controller.getCurrentProfile().sendCommand(selectedServerValue, customCommandTextField.getText());
|
||||
customCommandTextField.setText("");
|
||||
} else if (actionSource == saveServerButton) {
|
||||
controller.getCurrentProfile().sendCommand(selectedServerValue, "save-all");
|
||||
} else if (actionSource == reloadButton) {
|
||||
controller.getCurrentProfile().sendCommand(selectedServerValue, "reload");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles command buttons which act on a player
|
||||
*
|
||||
* @param actionSource <p>The clicked object</p>
|
||||
* @param selectedServerValue <p>The server currently selected</p>
|
||||
* @param selectedPlayerValue <p>The player currently selected</p>
|
||||
*/
|
||||
private void handlePlayerCommands(Object actionSource, String selectedServerValue, String selectedPlayerValue) {
|
||||
if (selectedServerValue == null || selectedPlayerValue == null) {
|
||||
return;
|
||||
}
|
||||
if (actionSource == kickButton) {
|
||||
controller.getCurrentProfile().sendCommand(selectedServerValue, "kick " + selectedPlayerValue);
|
||||
} else if (actionSource == banButton) {
|
||||
controller.getCurrentProfile().sendCommand(selectedServerValue, "ban " + selectedPlayerValue);
|
||||
} else if (actionSource == opButton) {
|
||||
controller.getCurrentProfile().sendCommand(selectedServerValue, "op " + selectedPlayerValue);
|
||||
} else if (actionSource == deopButton) {
|
||||
controller.getCurrentProfile().sendCommand(selectedServerValue, "deop " + selectedPlayerValue);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,368 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.Collection;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.naming.ConfigurationException;
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.basic.BasicButtonUI;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE;
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner;
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsStream;
|
||||
|
||||
/**
|
||||
* Generates a ServerLauncherGUI.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ServerLauncherGUI extends MessageHandler implements ActionListener, GUI {
|
||||
|
||||
private final ServerLauncherController controller;
|
||||
private Map<String, String> textStrings;
|
||||
private Tray applicationTray;
|
||||
|
||||
private JFrame frame;
|
||||
private JTabbedPane mainTabbedPane;
|
||||
private JTabbedPane serversPane;
|
||||
private ServerControlTab serverControlTab;
|
||||
private ControlPanelTab controlPanelTab;
|
||||
private ServerLauncherMenu serverLauncherMenu;
|
||||
|
||||
private JButton addServerTabButton;
|
||||
private JButton addServerPaneButton;
|
||||
|
||||
/**
|
||||
* Creates the application window
|
||||
*/
|
||||
public ServerLauncherGUI() throws IOException {
|
||||
super(false);
|
||||
initialize(440, 170);
|
||||
loadMessages();
|
||||
this.controller = Main.getController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the application window
|
||||
*
|
||||
* @param silent <p>Whether to make the GUI silent (hidden, for testing)</p>
|
||||
*/
|
||||
public ServerLauncherGUI(boolean silent) throws IOException {
|
||||
super(silent);
|
||||
if (!silent) {
|
||||
initialize(440, 170);
|
||||
}
|
||||
loadMessages();
|
||||
this.controller = Main.getController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the application window with a preferred width and height
|
||||
*
|
||||
* @param width <p>The preferred width</p>
|
||||
* @param height <p>The preferred height</p>
|
||||
*/
|
||||
public ServerLauncherGUI(int width, int height) throws IOException {
|
||||
super(false);
|
||||
initialize(width, height);
|
||||
loadMessages();
|
||||
this.controller = Main.getController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pane used for server configurations
|
||||
*
|
||||
* @return <p>The pane used for server configurations</p>
|
||||
*/
|
||||
public JTabbedPane getPane() {
|
||||
return this.serversPane;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this GUI's control panel tab
|
||||
*
|
||||
* @return <p>The control panel tab for this GUI</p>
|
||||
*/
|
||||
public ControlPanelTab getControlPanelTab() {
|
||||
return this.controlPanelTab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(String text) {
|
||||
controlPanelTab.setStatusText(text);
|
||||
this.logMessage(text);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server control tab used by this GUI
|
||||
*
|
||||
* @return <p>The server control tab used by this GUI</p>
|
||||
*/
|
||||
public ServerControlTab getServerControlTab() {
|
||||
return this.serverControlTab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the main JFrame
|
||||
*
|
||||
* @return <p>The Dimension of the main JFrame</p>
|
||||
*/
|
||||
public Dimension getSize() {
|
||||
return frame.getContentPane().getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates ServerLauncherGUI according to current profile settings
|
||||
*/
|
||||
public void updateWithSavedProfileData() {
|
||||
ServerLauncherController controller = Main.getController();
|
||||
serversPane.removeAll();
|
||||
serverLauncherMenu.update();
|
||||
serverControlTab.update();
|
||||
for (Collection collection : controller.getCurrentProfile().getCollections()) {
|
||||
serversPane.addTab(collection.getName(), collection.getServerTab().getPanel());
|
||||
addCloseButtonToServerTab(collection.getName());
|
||||
}
|
||||
addAddButtonToServerTab();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an add button to the servers tab's tabs
|
||||
*/
|
||||
private void addAddButtonToServerTab() {
|
||||
JPanel tabPanel = new JPanel();
|
||||
tabPanel.setLayout(new GridLayout());
|
||||
tabPanel.setOpaque(false);
|
||||
|
||||
JPanel tabContentsPanel = new JPanel(new SpringLayout());
|
||||
serversPane.addTab("Add tab", tabContentsPanel);
|
||||
|
||||
addServerTabButton = getAddServerButton(true);
|
||||
addServerTabButton.addActionListener(this);
|
||||
addServerPaneButton = getAddServerButton(false);
|
||||
addServerPaneButton.addActionListener(this);
|
||||
|
||||
tabContentsPanel.add(addServerTabButton);
|
||||
tabPanel.add(addServerPaneButton);
|
||||
serversPane.setTabComponentAt(serversPane.getTabCount() - 1, tabPanel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a button for adding a new server
|
||||
*
|
||||
* @param displayButtonStyle <p>Whether to show or hide the button's style</p>
|
||||
* @return <p>A new add server button</p>
|
||||
*/
|
||||
private JButton getAddServerButton(boolean displayButtonStyle) {
|
||||
JButton addButton = new JButton("+ Add server");
|
||||
if (!displayButtonStyle) {
|
||||
addButton.setBorder(BorderFactory.createEtchedBorder());
|
||||
addButton.setFocusable(false);
|
||||
addButton.setBorderPainted(false);
|
||||
addButton.setContentAreaFilled(false);
|
||||
addButton.setRolloverEnabled(true);
|
||||
addButton.setUI(new BasicButtonUI());
|
||||
}
|
||||
return addButton;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param serverName <p>The name of the server/tab to add a close button to</p>
|
||||
*/
|
||||
private void addCloseButtonToServerTab(String serverName) {
|
||||
int index = serversPane.indexOfTab(serverName);
|
||||
JPanel tabPanel = new JPanel(new GridBagLayout());
|
||||
tabPanel.setOpaque(false);
|
||||
JLabel serverTitleLabel = new JLabel(serverName);
|
||||
JButton removeServerButton = new JButton("(X)");
|
||||
removeServerButton.setBorder(BorderFactory.createEtchedBorder());
|
||||
removeServerButton.setFocusable(false);
|
||||
removeServerButton.setBorderPainted(false);
|
||||
removeServerButton.setContentAreaFilled(false);
|
||||
removeServerButton.setRolloverEnabled(true);
|
||||
removeServerButton.setPreferredSize(new Dimension(18, 17));
|
||||
removeServerButton.setUI(new BasicButtonUI());
|
||||
|
||||
GridBagConstraints gridBagConstraints = new GridBagConstraints();
|
||||
gridBagConstraints.gridx = 0;
|
||||
gridBagConstraints.gridy = 0;
|
||||
gridBagConstraints.weightx = 1;
|
||||
|
||||
tabPanel.add(serverTitleLabel, gridBagConstraints);
|
||||
|
||||
gridBagConstraints.gridx++;
|
||||
gridBagConstraints.weightx = 0;
|
||||
tabPanel.add(removeServerButton, gridBagConstraints);
|
||||
|
||||
serversPane.setTabComponentAt(index, tabPanel);
|
||||
|
||||
removeServerButton.addActionListener(new CloseTabActionListener(serversPane, serverName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the server launcher GUI
|
||||
*
|
||||
* @param width <p>The width of the GUI</p>
|
||||
* @param height <p>The height of the GUI</p>
|
||||
* @throws IOException <p>If unable to load the GUI icon</p>
|
||||
*/
|
||||
private void initialize(int width, int height) throws IOException {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (ClassNotFoundException |
|
||||
UnsupportedLookAndFeelException |
|
||||
InstantiationException |
|
||||
IllegalAccessException e
|
||||
) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
frame = new JFrame("Minecraft server launcher");
|
||||
frame.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
||||
frame.getContentPane().setPreferredSize(new Dimension(width, height));
|
||||
|
||||
ImageIcon img = new ImageIcon(ImageIO.read(getResourceAsStream("GUIIcon.png")));
|
||||
|
||||
frame.setIconImage(img.getImage());
|
||||
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
frame.setJMenuBar(menuBar);
|
||||
|
||||
this.serverLauncherMenu = new ServerLauncherMenu(menuBar, this);
|
||||
|
||||
mainTabbedPane = new JTabbedPane(JTabbedPane.TOP);
|
||||
frame.getContentPane().add(mainTabbedPane);
|
||||
|
||||
JPanel controlPanelPanel = new JPanel();
|
||||
mainTabbedPane.addTab("Control panel", null, controlPanelPanel, null);
|
||||
controlPanelTab = new ControlPanelTab(controlPanelPanel);
|
||||
|
||||
JPanel controlServersPanel = new JPanel();
|
||||
mainTabbedPane.addTab("Control servers", null, controlServersPanel, null);
|
||||
serverControlTab = new ServerControlTab(frame, controlServersPanel);
|
||||
|
||||
JPanel serversPanel = new JPanel();
|
||||
mainTabbedPane.addTab("Servers", null, serversPanel, null);
|
||||
SpringLayout serversPanelSpringLayout = new SpringLayout();
|
||||
serversPanel.setLayout(serversPanelSpringLayout);
|
||||
|
||||
serversPane = new JTabbedPane(JTabbedPane.TOP);
|
||||
serversPanelSpringLayout.putConstraint(SpringLayout.NORTH, serversPane, 0, SpringLayout.NORTH, serversPanel);
|
||||
serversPanelSpringLayout.putConstraint(SpringLayout.WEST, serversPane, 0, SpringLayout.WEST, serversPanel);
|
||||
serversPanelSpringLayout.putConstraint(SpringLayout.SOUTH, serversPane, 0, SpringLayout.SOUTH, serversPanel);
|
||||
serversPanelSpringLayout.putConstraint(SpringLayout.EAST, serversPane, 0, SpringLayout.EAST, serversPanel);
|
||||
serversPanel.add(serversPane);
|
||||
|
||||
serversPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
|
||||
|
||||
frame.validate();
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
applicationTray = new Tray(frame, this);
|
||||
updateGUIElementsWhenServersStartOrStop(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the GUI to the system tray
|
||||
*/
|
||||
public void hideToTray() {
|
||||
applicationTray.hideToTray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Object actionSource = e.getSource();
|
||||
//Register actions on the main tab
|
||||
handleMainTabButtons(actionSource);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles buttons and the combo on the main tab
|
||||
*
|
||||
* @param actionSource <p>The object being interacted with</p>
|
||||
*/
|
||||
private void handleMainTabButtons(Object actionSource) {
|
||||
if (actionSource == addServerTabButton || actionSource == addServerPaneButton) {
|
||||
addServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new server with a server tab
|
||||
*/
|
||||
private void addServer() {
|
||||
String serverName = JOptionPane.showInputDialog("Name of server: ");
|
||||
try {
|
||||
controller.getCurrentProfile().addCollection(serverName);
|
||||
} catch (ConfigurationException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
this.updateWithSavedProfileData();
|
||||
controller.getCurrentProfile().updateConsoles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ServerLauncherGUI components to block a user from doing illegal actions
|
||||
*
|
||||
* @param running <p>Whether the servers are currently running</p>
|
||||
*/
|
||||
public void updateGUIElementsWhenServersStartOrStop(boolean running) {
|
||||
boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running.
|
||||
mainTabbedPane.setEnabledAt(1, !stopped);
|
||||
mainTabbedPane.setEnabledAt(2, stopped);
|
||||
controlPanelTab.updateGUIElementsWhenServersStartOrStop(running);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a specific message from its key
|
||||
*
|
||||
* @param stringKey <p>The key for the string to get</p>
|
||||
* @return <p>The corresponding string</p>
|
||||
*/
|
||||
public String getMessage(String stringKey) {
|
||||
return textStrings.get(stringKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads popup messages from a text file
|
||||
*/
|
||||
private void loadMessages() throws FileNotFoundException {
|
||||
textStrings = new HashMap<>();
|
||||
Scanner file = getResourceAsScanner("menumsg.csv");
|
||||
while (file.hasNextLine()) {
|
||||
String nextLine = file.nextLine();
|
||||
String[] line = nextLine.split("=");
|
||||
String content = line[1].replaceAll("_BREAK_", System.getProperty("line.separator"));
|
||||
textStrings.put(line[0], content);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,284 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.profile.Profile;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class takes care of the GUI's top menu
|
||||
*/
|
||||
public class ServerLauncherMenu implements ActionListener {
|
||||
|
||||
private final JMenuBar menuBar;
|
||||
//Options
|
||||
private JCheckBoxMenuItem runInBackgroundCheckBoxMenuItem;
|
||||
private JCheckBoxMenuItem delayStartupCheckBoxMenuItem;
|
||||
private JCheckBoxMenuItem downloadJarsCheckBoxMenuItem;
|
||||
private JMenuItem javaCommandMenuItem;
|
||||
private JMenuItem oldJavaCommandMenuItem;
|
||||
private JMenuItem deleteBuiltJarsMenuItem;
|
||||
//Help
|
||||
private JMenuItem errorsMenuItem;
|
||||
private JMenuItem setupMenuItem;
|
||||
private JMenuItem manualUpdateMenuItem;
|
||||
//Info/options
|
||||
private JMenuItem runInBackgroundMenuItem;
|
||||
private JMenuItem delayStartupMenuItem;
|
||||
private JMenuItem downloadJarsMenuItem;
|
||||
private JMenuItem javaCommandInfoMenuItem;
|
||||
private JMenuItem oldJavaCommandInfoMenuItem;
|
||||
private JMenuItem deleteBuiltJarsInfoMenuItem;
|
||||
//Info/about
|
||||
private JMenuItem aboutMenuItem;
|
||||
private JMenuItem storyMenuItem;
|
||||
|
||||
private final ServerLauncherController controller;
|
||||
private final ServerLauncherGUI serverLauncherGUI;
|
||||
|
||||
/**
|
||||
* Initializes a new server launcher menu
|
||||
*
|
||||
* @param menuBar <p>The menu bar to attach items to</p>
|
||||
* @param serverLauncherGUI <p>The server launcher GUI to use</p>
|
||||
*/
|
||||
public ServerLauncherMenu(JMenuBar menuBar, ServerLauncherGUI serverLauncherGUI) {
|
||||
this.controller = ServerLauncherController.getInstance();
|
||||
this.menuBar = menuBar;
|
||||
this.serverLauncherGUI = serverLauncherGUI;
|
||||
initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes all GUI elements
|
||||
*/
|
||||
public void initialize() {
|
||||
JMenu mnOptions = new JMenu("Options");
|
||||
menuBar.add(mnOptions);
|
||||
generateOptionsMenuItems(mnOptions);
|
||||
|
||||
JMenu mnHelp = new JMenu("Help");
|
||||
menuBar.add(mnHelp);
|
||||
|
||||
errorsMenuItem = createMenuItem("Errors", mnHelp);
|
||||
setupMenuItem = createMenuItem("Setup", mnHelp);
|
||||
manualUpdateMenuItem = createMenuItem("Manual update", mnHelp);
|
||||
|
||||
JMenu mnInfo = new JMenu("Info");
|
||||
menuBar.add(mnInfo);
|
||||
generateInfoMenuItems(mnInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the state of checkboxes based on whether options are enabled
|
||||
*/
|
||||
public void update() {
|
||||
runInBackgroundCheckBoxMenuItem.setState(controller.getRunInBackground());
|
||||
delayStartupCheckBoxMenuItem.setState(controller.getDelayStartup() > 0);
|
||||
downloadJarsCheckBoxMenuItem.setState(controller.getDownloadAllJars());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent actionEvent) {
|
||||
Object actionSource = actionEvent.getSource();
|
||||
if (actionSource == runInBackgroundCheckBoxMenuItem) {
|
||||
background();
|
||||
} else if (actionSource == delayStartupCheckBoxMenuItem) {
|
||||
delay();
|
||||
} else if (actionSource == downloadJarsCheckBoxMenuItem) {
|
||||
downloadJars();
|
||||
} else if (actionSource == javaCommandMenuItem) {
|
||||
configureJava(false);
|
||||
} else if (actionSource == oldJavaCommandMenuItem) {
|
||||
configureJava(true);
|
||||
} else if (actionSource == deleteBuiltJarsMenuItem) {
|
||||
deleteBuiltJars();
|
||||
} else if (actionSource == errorsMenuItem) {
|
||||
CommonFunctions.goToURL(serverLauncherGUI.getMessage("infoURL"));
|
||||
} else if (actionSource == setupMenuItem) {
|
||||
serverLauncherGUI.showMessage("Setup", serverLauncherGUI.getMessage("setupText"));
|
||||
} else if (actionSource == manualUpdateMenuItem) {
|
||||
CommonFunctions.goToURL(serverLauncherGUI.getMessage("manualUpdateURL"));
|
||||
} else if (actionSource == runInBackgroundMenuItem) {
|
||||
serverLauncherGUI.showMessage("Run in background", serverLauncherGUI.getMessage("runInBackgroundText"));
|
||||
} else if (actionSource == delayStartupMenuItem) {
|
||||
serverLauncherGUI.showMessage("Delay startup", serverLauncherGUI.getMessage("delayStartupText"));
|
||||
} else if (actionSource == downloadJarsMenuItem) {
|
||||
serverLauncherGUI.showMessage("Download jars", serverLauncherGUI.getMessage("downloadJarsText"));
|
||||
} else if (actionSource == javaCommandInfoMenuItem) {
|
||||
serverLauncherGUI.showMessage("Java command", serverLauncherGUI.getMessage("javaCommandText"));
|
||||
} else if (actionSource == oldJavaCommandInfoMenuItem) {
|
||||
serverLauncherGUI.showMessage("Old Java command", serverLauncherGUI.getMessage("oldJavaCommandText"));
|
||||
} else if (actionSource == deleteBuiltJarsInfoMenuItem) {
|
||||
serverLauncherGUI.showMessage("Delete built jar files", serverLauncherGUI.getMessage("deleteBuiltJarFilesText"));
|
||||
} else if (actionSource == aboutMenuItem) {
|
||||
serverLauncherGUI.showMessage("About", serverLauncherGUI.getMessage("aboutText"));
|
||||
} else if (actionSource == storyMenuItem) {
|
||||
CommonFunctions.goToURL(serverLauncherGUI.getMessage("storyURL"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the children of the options menu
|
||||
*
|
||||
* @param mnOptions <p>A reference to the options menu</p>
|
||||
*/
|
||||
private void generateOptionsMenuItems(JMenu mnOptions) {
|
||||
runInBackgroundCheckBoxMenuItem = createCheckBoxMenuItem("Run in background on exit", mnOptions);
|
||||
delayStartupCheckBoxMenuItem = createCheckBoxMenuItem("Delay Startup", mnOptions);
|
||||
downloadJarsCheckBoxMenuItem = createCheckBoxMenuItem("Download jars", mnOptions);
|
||||
javaCommandMenuItem = createMenuItem("Java command", mnOptions);
|
||||
oldJavaCommandMenuItem = createMenuItem("Old Java command", mnOptions);
|
||||
deleteBuiltJarsMenuItem = createMenuItem("Delete built jar files", mnOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the children of the info menu
|
||||
*
|
||||
* @param mnInfo <p>A reference to the info menu</p>
|
||||
*/
|
||||
private void generateInfoMenuItems(JMenu mnInfo) {
|
||||
JMenu mnOptionsInfo = new JMenu("Options");
|
||||
mnInfo.add(mnOptionsInfo);
|
||||
|
||||
runInBackgroundMenuItem = createMenuItem("Run in background on exit", mnOptionsInfo);
|
||||
delayStartupMenuItem = createMenuItem("Delay Startup", mnOptionsInfo);
|
||||
downloadJarsMenuItem = createMenuItem("Download jars", mnOptionsInfo);
|
||||
javaCommandInfoMenuItem = createMenuItem("Java command", mnOptionsInfo);
|
||||
oldJavaCommandInfoMenuItem = createMenuItem("Old Java command", mnOptionsInfo);
|
||||
deleteBuiltJarsInfoMenuItem = createMenuItem("Delete built jar files", mnOptionsInfo);
|
||||
|
||||
JMenu mnAbout = new JMenu("About");
|
||||
mnInfo.add(mnAbout);
|
||||
|
||||
aboutMenuItem = createMenuItem("About", mnAbout);
|
||||
storyMenuItem = createMenuItem("Story", mnAbout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a checkbox menu item
|
||||
*
|
||||
* @param itemName <p>The name of the new checkbox item</p>
|
||||
* @param parent <p>The parent menu the item belongs to</p>
|
||||
* @return <p>The created checkbox menu item</p>
|
||||
*/
|
||||
private JCheckBoxMenuItem createCheckBoxMenuItem(String itemName, JMenu parent) {
|
||||
JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(itemName);
|
||||
parent.add(menuItem);
|
||||
menuItem.addActionListener(this);
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a menu item
|
||||
*
|
||||
* @param itemName <p>The name of the new item</p>
|
||||
* @param parent <p>The parent menu the item belongs to</p>
|
||||
* @return <p>The created menu item</p>
|
||||
*/
|
||||
private JMenuItem createMenuItem(String itemName, JMenu parent) {
|
||||
JMenuItem menuItem = new JMenuItem(itemName);
|
||||
parent.add(menuItem);
|
||||
menuItem.addActionListener(this);
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the user for the new Java path
|
||||
*
|
||||
* @param old <p>Whether asking for the path to the old java version</p>
|
||||
*/
|
||||
private void configureJava(boolean old) {
|
||||
if (old) {
|
||||
String response = JOptionPane.showInputDialog("Command or path to Java: ", controller.getOldJavaCommand());
|
||||
if (response != null) {
|
||||
controller.setOldJavaCommand(response);
|
||||
}
|
||||
} else {
|
||||
String response = JOptionPane.showInputDialog("Command or path to Java: ", controller.getJavaCommand());
|
||||
if (response != null) {
|
||||
controller.setJavaCommand(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes build Spigot and Bukkit .jar files if the user accepts
|
||||
*/
|
||||
private void deleteBuiltJars() {
|
||||
int answer = JOptionPane.showConfirmDialog(null, "This will delete built .jar files, causing them " +
|
||||
"to be rebuilt on the next run. Do you want to continue?", "Delete built .jar files",
|
||||
JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
if (answer == JOptionPane.YES_NO_OPTION) {
|
||||
String jarDirectory = controller.getJarDirectory();
|
||||
File spigotFile = new File(jarDirectory + "SpigotLatest.jar");
|
||||
File bukkitFile = new File(jarDirectory + "BukkitLatest.jar");
|
||||
boolean success = true;
|
||||
if (spigotFile.exists() && !spigotFile.delete()) {
|
||||
serverLauncherGUI.showError("Unable to delete latest spigot .jar");
|
||||
success = false;
|
||||
}
|
||||
if (bukkitFile.exists() && !bukkitFile.delete()) {
|
||||
serverLauncherGUI.showError("Unable to delete latest bukkit .jar");
|
||||
success = false;
|
||||
}
|
||||
if (success) {
|
||||
serverLauncherGUI.showMessage("Deletion successful", "Deleted built .jar files");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the user for a delay if checked, and sets the value to the current profile
|
||||
*/
|
||||
private void delay() {
|
||||
String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
|
||||
if (selectedProfile != null) {
|
||||
Profile profile = controller.getProfileByName(selectedProfile);
|
||||
if (delayStartupCheckBoxMenuItem.isSelected()) {
|
||||
String response = JOptionPane.showInputDialog("Seconds to delay: ");
|
||||
if (response == null) {
|
||||
delayStartupCheckBoxMenuItem.setState(false);
|
||||
return;
|
||||
}
|
||||
int parsed = Integer.parseInt(response);
|
||||
Objects.requireNonNull(profile).setDelayStartup(parsed);
|
||||
} else {
|
||||
Objects.requireNonNull(profile).setDelayStartup(0);
|
||||
}
|
||||
} else {
|
||||
serverLauncherGUI.showError("No profile selected");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the runInBackground setting to the current profile
|
||||
*/
|
||||
private void background() {
|
||||
String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
|
||||
if (selectedProfile != null) {
|
||||
Profile profile = controller.getProfileByName(selectedProfile);
|
||||
Objects.requireNonNull(profile).setRunInBackground(runInBackgroundCheckBoxMenuItem.isSelected());
|
||||
} else {
|
||||
serverLauncherGUI.showError("No profile selected");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the downloadJars setting to the current profile
|
||||
*/
|
||||
private void downloadJars() {
|
||||
String selectedProfile = serverLauncherGUI.getControlPanelTab().getSelectedProfile();
|
||||
if (selectedProfile != null) {
|
||||
controller.setDownloadAllJars(downloadJarsCheckBoxMenuItem.isSelected());
|
||||
} else {
|
||||
serverLauncherGUI.showError("No profile selected");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,51 +1,41 @@
|
||||
package net.knarcraft.serverlauncher.userinterface;
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.serverlauncher.profile.Profile;
|
||||
import net.knarcraft.serverlauncher.server.Server;
|
||||
import net.knarcraft.serverlauncher.server.ServerType;
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerHandler;
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerTypeHandler;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Contains all buttons for configuring a server.
|
||||
* Does some visual stuff by itself, but otherwise reads user inputs.
|
||||
* Represents a visual server tab used to configure a server
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ServerTab implements ActionListener {
|
||||
private final JComboBox<String> serverTypes, serverVersions, maxRam;
|
||||
private final JCheckBox chckbxEnabled;
|
||||
private final JButton btnRemoveServer, btnBrowse;
|
||||
private final JComboBox<String> serverTypes;
|
||||
private final JComboBox<String> serverVersions;
|
||||
private final JComboBox<String> maxRam;
|
||||
private final JCheckBox enabledCheckbox;
|
||||
private final JButton browseButton;
|
||||
private final JTextField directory;
|
||||
private final JPanel panel;
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Updates the server tab components according to the received parameters.
|
||||
* Initializes a new server tab with the given name
|
||||
*
|
||||
* @param path The new path
|
||||
* @param enabled The enabled status of the server
|
||||
* @param typeName The name of the selected server type
|
||||
* @param serverVersion The version of the server
|
||||
* @param maxRam The max usable ram for the server
|
||||
* @param name <p>The name of the new server tab</p>
|
||||
* @throws ConfigurationException <p>If unable to create the new tab</p>
|
||||
*/
|
||||
public void setData(String path, boolean enabled, String typeName, String serverVersion, String maxRam) {
|
||||
this.directory.setText(path);
|
||||
this.chckbxEnabled.setSelected(enabled);
|
||||
this.serverTypes.setSelectedItem(typeName);
|
||||
this.serverTypes();
|
||||
this.serverVersions.setSelectedItem(serverVersion);
|
||||
this.maxRam.setSelectedItem(maxRam);
|
||||
}
|
||||
|
||||
public ServerTab(String name) {
|
||||
this.name = name;
|
||||
public ServerTab(String name) throws ConfigurationException {
|
||||
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();
|
||||
panel.setLayout(sl_panel_3);
|
||||
|
||||
@ -59,7 +49,7 @@ public class ServerTab implements ActionListener {
|
||||
sl_panel_3.putConstraint(SpringLayout.SOUTH, lblServerVersion, 26, SpringLayout.SOUTH, lblServerType);
|
||||
panel.add(lblServerVersion);
|
||||
|
||||
serverTypes = new JComboBox<>(ServerType.getTypeNames());
|
||||
serverTypes = new JComboBox<>(ServerTypeHandler.getTypeNames());
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, serverTypes, 10, SpringLayout.NORTH, panel);
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, serverTypes, 5, SpringLayout.EAST, lblServerVersion);
|
||||
sl_panel_3.putConstraint(SpringLayout.EAST, serverTypes, 154, SpringLayout.WEST, serverTypes);
|
||||
@ -68,7 +58,7 @@ public class ServerTab implements ActionListener {
|
||||
panel.add(serverTypes);
|
||||
serverTypes.addActionListener(this);
|
||||
|
||||
serverVersions = new JComboBox<>(ServerType.getServerTypes().get(0).getVersions());
|
||||
serverVersions = new JComboBox<>(ServerTypeHandler.getServerTypes().get(0).getVersions());
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, serverVersions, 6, SpringLayout.SOUTH, serverTypes);
|
||||
sl_panel_3.putConstraint(SpringLayout.EAST, serverVersions, 0, SpringLayout.EAST, serverTypes);
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, serverVersions, 6, SpringLayout.EAST, lblServerVersion);
|
||||
@ -83,58 +73,83 @@ public class ServerTab implements ActionListener {
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, lblMaxRam, 6, SpringLayout.EAST, serverTypes);
|
||||
panel.add(lblMaxRam);
|
||||
|
||||
maxRam = new JComboBox<>(Server.getRamList());
|
||||
maxRam = new JComboBox<>(ServerHandler.getRamList());
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, maxRam, 0, SpringLayout.NORTH, serverTypes);
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, maxRam, 6, SpringLayout.EAST, lblMaxRam);
|
||||
sl_panel_3.putConstraint(SpringLayout.EAST, maxRam, -10, SpringLayout.EAST, panel);
|
||||
panel.add(maxRam);
|
||||
maxRam.addActionListener(this);
|
||||
|
||||
chckbxEnabled = new JCheckBox("Enabled");
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, chckbxEnabled, 10, SpringLayout.WEST, panel);
|
||||
panel.add(chckbxEnabled);
|
||||
chckbxEnabled.addActionListener(this);
|
||||
|
||||
btnRemoveServer = new JButton("Remove server");
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, btnRemoveServer, 0, SpringLayout.NORTH, serverVersions);
|
||||
sl_panel_3.putConstraint(SpringLayout.SOUTH, btnRemoveServer, 0, SpringLayout.SOUTH, serverVersions);
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, btnRemoveServer, 6, SpringLayout.EAST, serverVersions);
|
||||
sl_panel_3.putConstraint(SpringLayout.EAST, btnRemoveServer, -10, SpringLayout.EAST, panel);
|
||||
panel.add(btnRemoveServer);
|
||||
btnRemoveServer.addActionListener(this);
|
||||
enabledCheckbox = new JCheckBox("Enabled");
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, enabledCheckbox, 10, SpringLayout.WEST, panel);
|
||||
panel.add(enabledCheckbox);
|
||||
enabledCheckbox.addActionListener(this);
|
||||
|
||||
JLabel lblDirectory = new JLabel("Directory");
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, lblDirectory, 6, SpringLayout.EAST, chckbxEnabled);
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, lblDirectory, 6, SpringLayout.EAST, enabledCheckbox);
|
||||
panel.add(lblDirectory);
|
||||
|
||||
directory = new JTextField();
|
||||
sl_panel_3.putConstraint(SpringLayout.WEST, directory, 6, SpringLayout.EAST, lblDirectory);
|
||||
sl_panel_3.putConstraint(SpringLayout.SOUTH, lblDirectory, 0, SpringLayout.SOUTH, directory);
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, lblDirectory, 0, SpringLayout.NORTH, directory);
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, chckbxEnabled, 0, SpringLayout.NORTH, directory);
|
||||
sl_panel_3.putConstraint(SpringLayout.SOUTH, chckbxEnabled, 0, SpringLayout.SOUTH, directory);
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, enabledCheckbox, 0, SpringLayout.NORTH, directory);
|
||||
sl_panel_3.putConstraint(SpringLayout.SOUTH, enabledCheckbox, 0, SpringLayout.SOUTH, directory);
|
||||
panel.add(directory);
|
||||
directory.setColumns(10);
|
||||
directory.addActionListener(this);
|
||||
|
||||
btnBrowse = new JButton("Browse");
|
||||
sl_panel_3.putConstraint(SpringLayout.EAST, directory, -6, SpringLayout.WEST, btnBrowse);
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, btnBrowse, 3, SpringLayout.SOUTH, btnRemoveServer);
|
||||
sl_panel_3.putConstraint(SpringLayout.EAST, btnBrowse, -10, SpringLayout.EAST, panel);
|
||||
sl_panel_3.putConstraint(SpringLayout.SOUTH, directory, 0, SpringLayout.SOUTH, btnBrowse);
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, directory, 0, SpringLayout.NORTH, btnBrowse);
|
||||
panel.add(btnBrowse);
|
||||
btnBrowse.addActionListener(this);
|
||||
browseButton = new JButton("Browse");
|
||||
sl_panel_3.putConstraint(SpringLayout.EAST, directory, -6, SpringLayout.WEST, browseButton);
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, browseButton, 3, SpringLayout.SOUTH, serverVersions);
|
||||
sl_panel_3.putConstraint(SpringLayout.EAST, browseButton, -10, SpringLayout.EAST, panel);
|
||||
sl_panel_3.putConstraint(SpringLayout.SOUTH, directory, 0, SpringLayout.SOUTH, browseButton);
|
||||
sl_panel_3.putConstraint(SpringLayout.NORTH, directory, 0, SpringLayout.NORTH, browseButton);
|
||||
panel.add(browseButton);
|
||||
browseButton.addActionListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the server tab components according to the received parameters
|
||||
*
|
||||
* @param path <p>The new path of the server tab</p>
|
||||
* @param isEnabled <p>Whether to mark the server as enabled</p>
|
||||
* @param typeName <p>The name of the selected server type</p>
|
||||
* @param serverVersion <p>The version of the server</p>
|
||||
* @param maxRam <p>The maximum usable ram for the server</p>
|
||||
*/
|
||||
public void setData(String path, boolean isEnabled, String typeName, String serverVersion, String maxRam) throws ConfigurationException {
|
||||
this.directory.setText(path);
|
||||
this.enabledCheckbox.setSelected(isEnabled);
|
||||
this.serverTypes.setSelectedItem(typeName);
|
||||
this.updateServerVersion();
|
||||
this.serverVersions.setSelectedItem(serverVersion);
|
||||
this.maxRam.setSelectedItem(maxRam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the JPanel containing the server tab's elements
|
||||
*
|
||||
* @return <p>The JPanel containing the server tab's elements</p>
|
||||
*/
|
||||
public JPanel getPanel() {
|
||||
return this.panel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file path selected by the user
|
||||
*
|
||||
* @return <p>The file path selected by the user</p>
|
||||
*/
|
||||
public String getPath() {
|
||||
return this.directory.getText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum RAM selected by the user
|
||||
*
|
||||
* @return <p>The maximum RAM selected by the user</p>
|
||||
*/
|
||||
public String getMaxRam() {
|
||||
Object selected = this.maxRam.getSelectedItem();
|
||||
if (selected != null) {
|
||||
@ -144,6 +159,11 @@ public class ServerTab implements ActionListener {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server type selected by the user
|
||||
*
|
||||
* @return <p>The server type selected by the user</p>
|
||||
*/
|
||||
public String getType() {
|
||||
Object selected = this.serverTypes.getSelectedItem();
|
||||
if (selected != null) {
|
||||
@ -154,9 +174,9 @@ public class ServerTab implements ActionListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selected version from the serverVersion combo
|
||||
* Gets the server version selected by the user
|
||||
*
|
||||
* @return The combo value, or defaults to "Latest" on null
|
||||
* @return <p>The server version selected by the user</p>
|
||||
*/
|
||||
public String getVersion() {
|
||||
Object selected = this.serverVersions.getSelectedItem();
|
||||
@ -168,74 +188,63 @@ public class ServerTab implements ActionListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the server is enabled
|
||||
* Checks whether this server is enabled
|
||||
*
|
||||
* @return True if the checkbox is checked. False otherwise.
|
||||
* @return <p>True if this server is enabled</p>
|
||||
*/
|
||||
public boolean enabled() {
|
||||
return this.chckbxEnabled.isSelected();
|
||||
public boolean isEnabled() {
|
||||
return this.enabledCheckbox.isSelected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (e.getSource() == btnRemoveServer) {
|
||||
remove();
|
||||
} else if (e.getSource() == btnBrowse) {
|
||||
if (e.getSource() == browseButton) {
|
||||
browse();
|
||||
} else if (e.getSource() == serverTypes) {
|
||||
serverTypes();
|
||||
try {
|
||||
updateServerVersion();
|
||||
} catch (ConfigurationException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the collection containing this ServerTab, and updates everything necessary.
|
||||
*/
|
||||
private void remove() {
|
||||
Profile.getCurrent().removeCollection(this.name);
|
||||
Profile.getGUI().update();
|
||||
Profile.getCurrent().updateConsoles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the user for the server folder.
|
||||
* Sets the directory input's value if successful.
|
||||
* Asks the user for server location and updates the GUI if given a valid value
|
||||
*/
|
||||
private void browse() {
|
||||
JFileChooser chooser = new JFileChooser();
|
||||
chooser.setCurrentDirectory(new java.io.File("/"));
|
||||
chooser.setDialogTitle("Server folder");
|
||||
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
|
||||
chooser.setAcceptAllFileFilterUsed(false);
|
||||
if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
|
||||
directory.setText(chooser.getSelectedFile().toString());
|
||||
File chosenFolder = Main.getController().getGUI().askForDirectory("Server folder");
|
||||
if (chosenFolder != null) {
|
||||
directory.setText(chosenFolder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the versions combo according to the value of the server type combo.
|
||||
* Updates server version choices according to the server type
|
||||
*/
|
||||
private void serverTypes() {
|
||||
private void updateServerVersion() throws ConfigurationException {
|
||||
serverVersions.removeAllItems();
|
||||
String selectedserverTypes = null;
|
||||
String selectedServerTypes = null;
|
||||
Object selectedType = serverTypes.getSelectedItem();
|
||||
if (selectedType != null) {
|
||||
selectedserverTypes = selectedType.toString();
|
||||
selectedServerTypes = selectedType.toString();
|
||||
}
|
||||
if (selectedserverTypes != null) {
|
||||
if (selectedserverTypes.equals("Custom")) {
|
||||
serverVersions.setEditable(true);
|
||||
} else {
|
||||
serverVersions.setEditable(false);
|
||||
ServerType current = null;
|
||||
for (ServerType servertype : ServerType.getServerTypes()) {
|
||||
if (servertype.getName().equals(selectedserverTypes)) {
|
||||
current = servertype;
|
||||
}
|
||||
if (selectedServerTypes == null) {
|
||||
return;
|
||||
}
|
||||
if (selectedServerTypes.equals("Custom")) {
|
||||
serverVersions.setEditable(true);
|
||||
} else {
|
||||
serverVersions.setEditable(false);
|
||||
ServerType current = null;
|
||||
for (ServerType servertype : ServerTypeHandler.getServerTypes()) {
|
||||
if (servertype.getName().equals(selectedServerTypes)) {
|
||||
current = servertype;
|
||||
}
|
||||
if (current != null) {
|
||||
for (String version : current.getVersions()) {
|
||||
serverVersions.addItem(version);
|
||||
}
|
||||
}
|
||||
if (current != null) {
|
||||
for (String version : current.getVersions()) {
|
||||
serverVersions.addItem(version);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static java.awt.Frame.NORMAL;
|
||||
|
||||
/**
|
||||
* This class adds a tray to the GUI
|
||||
*/
|
||||
public class Tray {
|
||||
|
||||
private SystemTray tray;
|
||||
private TrayIcon trayIcon;
|
||||
private final ServerLauncherController controller;
|
||||
private final ServerLauncherGUI serverLauncherGUI;
|
||||
private final JFrame mainFrame;
|
||||
|
||||
/**
|
||||
* Instantiates a new tray
|
||||
*
|
||||
* @param mainFrame <p>The main frame of the GUI</p>
|
||||
* @param serverLauncherGUI <p>The server launcher GUI to use</p>
|
||||
*/
|
||||
public Tray(JFrame mainFrame, ServerLauncherGUI serverLauncherGUI) {
|
||||
this.controller = Main.getController();
|
||||
this.mainFrame = mainFrame;
|
||||
this.serverLauncherGUI = serverLauncherGUI;
|
||||
initializeTray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the system tray if available
|
||||
*/
|
||||
private void initializeTray() {
|
||||
if (SystemTray.isSupported()) {
|
||||
tray = SystemTray.getSystemTray();
|
||||
InputStream imageStream = CommonFunctions.getResourceAsStream("GUIIcon.png");
|
||||
Image trayImage;
|
||||
try {
|
||||
trayImage = ImageIO.read(imageStream);
|
||||
} catch (IOException e) {
|
||||
trayImage = Toolkit.getDefaultToolkit().getImage("resources/GUIIcon.png");
|
||||
e.printStackTrace();
|
||||
}
|
||||
PopupMenu popup = new PopupMenu();
|
||||
trayIcon = new TrayIcon(trayImage, "Minecraft Server Launcher", popup);
|
||||
trayIcon.setImageAutoSize(true);
|
||||
ActionListener exitListener = e -> {
|
||||
serverLauncherGUI.getControlPanelTab().stopServers();
|
||||
controller.saveState();
|
||||
System.exit(0);
|
||||
};
|
||||
|
||||
MenuItem restoreItem = new MenuItem("Restore");
|
||||
popup.add(restoreItem);
|
||||
restoreItem.addActionListener(e -> {
|
||||
mainFrame.setExtendedState(NORMAL);
|
||||
tray.remove(trayIcon);
|
||||
mainFrame.setVisible(true);
|
||||
});
|
||||
MenuItem exitItem = new MenuItem("Exit");
|
||||
exitItem.addActionListener(exitListener);
|
||||
popup.add(exitItem);
|
||||
mainFrame.addWindowStateListener(e -> {
|
||||
if (e.getNewState() == NORMAL) {
|
||||
tray.remove(trayIcon);
|
||||
mainFrame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
mainFrame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
if (controller.getRunInBackground()) {
|
||||
try {
|
||||
tray.add(trayIcon);
|
||||
mainFrame.setVisible(false);
|
||||
} catch (AWTException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
serverLauncherGUI.getControlPanelTab().stopServers();
|
||||
controller.saveState();
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
trayIcon.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (e.getClickCount() >= 1 && e.getButton() == MouseEvent.BUTTON1) {
|
||||
mainFrame.setExtendedState(NORMAL);
|
||||
tray.remove(trayIcon);
|
||||
mainFrame.setVisible(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mainFrame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
controller.saveState();
|
||||
serverLauncherGUI.getControlPanelTab().stopServers();
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the gui to the tray
|
||||
*/
|
||||
public void hideToTray() {
|
||||
mainFrame.setVisible(false);
|
||||
try {
|
||||
tray.add(trayIcon);
|
||||
} catch (AWTException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class allows for displaying web pages
|
||||
*/
|
||||
public class WebBrowser {
|
||||
|
||||
private static JFrame browserFrame;
|
||||
private static JTextPane editorPane;
|
||||
|
||||
private WebBrowser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new web browser
|
||||
*/
|
||||
private static void instantiate() {
|
||||
editorPane = new JTextPane();
|
||||
editorPane.setEditable(false);
|
||||
browserFrame = new JFrame("Web Browser");
|
||||
JScrollPane scrollPane = new JScrollPane(editorPane);
|
||||
browserFrame.add(scrollPane);
|
||||
|
||||
browserFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
browserFrame.setBounds(100, 100, 800, 600);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the web page with the given URL
|
||||
*
|
||||
* @param url <p>The URL to open</p>
|
||||
*/
|
||||
public static void displayPage(String url) {
|
||||
if (browserFrame == null) {
|
||||
instantiate();
|
||||
}
|
||||
browserFrame.setVisible(true);
|
||||
try {
|
||||
browserFrame.setTitle("Browsing: " + url);
|
||||
editorPane.setPage(url);
|
||||
editorPane.setContentType("text/html");
|
||||
editorPane.addHyperlinkListener(hyperlinkEvent -> {
|
||||
if (hyperlinkEvent.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
|
||||
displayPage(hyperlinkEvent.getURL().toString());
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
editorPane.setContentType("text/html");
|
||||
editorPane.setText("<html>Could not load</html>");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,269 @@
|
||||
package net.knarcraft.minecraftserverlauncher.utility;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.Collection;
|
||||
import net.knarcraft.minecraftserverlauncher.server.Server;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.BackupGUI;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A helper class for performing server backup
|
||||
*/
|
||||
public final class BackupUtil {
|
||||
|
||||
private static boolean backupAborted;
|
||||
private static boolean backupRunning = false;
|
||||
|
||||
private BackupUtil() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts the currently running backup
|
||||
*/
|
||||
public static void abortBackup() {
|
||||
backupAborted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively copies a folder to another location
|
||||
*
|
||||
* @param source <p>The folder to copy</p>
|
||||
* @param destination <p>Target destination</p>
|
||||
* @param backupFileSize <p>The total file size of the backup in progress</p>
|
||||
* @param alreadyCopied <p>The amount of bytes already copied</p>
|
||||
* @throws IOException <p>If we can't start a file stream</p>
|
||||
*/
|
||||
private static long backupFolder(File source, File destination, long backupFileSize,
|
||||
long alreadyCopied) throws IOException {
|
||||
if (backupAborted) {
|
||||
return 0L;
|
||||
}
|
||||
if (!source.isDirectory()) {
|
||||
long copiedFileSize = copyFile(source, destination);
|
||||
BackupGUI.updateProgress("Copying " + source + "\n to " + destination,
|
||||
(int) ((alreadyCopied + copiedFileSize) * 100 / backupFileSize));
|
||||
return copiedFileSize;
|
||||
} else {
|
||||
if (!destination.exists() && !destination.mkdir()) {
|
||||
return 0L;
|
||||
}
|
||||
String[] files = source.list();
|
||||
long copiedFilesSize = 0;
|
||||
if (files != null) {
|
||||
for (String file : files) {
|
||||
File srcFile = new File(source, file);
|
||||
File destinationFile = new File(destination, file);
|
||||
copiedFilesSize += backupFolder(srcFile, destinationFile, backupFileSize,
|
||||
alreadyCopied + copiedFilesSize);
|
||||
BackupGUI.updateProgress("Copying " + source + "\n to " + destination,
|
||||
(int) ((alreadyCopied + copiedFilesSize) * 100 / backupFileSize));
|
||||
}
|
||||
}
|
||||
return copiedFilesSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a file from one location to another
|
||||
*
|
||||
* @param source <p>The file to copy</p>
|
||||
* @param destination <p>The location of the copied file</p>
|
||||
* @throws IOException <p>If reading or writing fails</p>
|
||||
*/
|
||||
private static long copyFile(File source, File destination) throws IOException {
|
||||
InputStream in = new FileInputStream(source);
|
||||
OutputStream out = new FileOutputStream(destination);
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, length);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
return Files.size(source.toPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all server directories to a folder specified by the user
|
||||
*
|
||||
* @param gui <p>The GUI to use for informing the user</p>
|
||||
*/
|
||||
public static void backup(GUI gui) {
|
||||
backupAborted = false;
|
||||
if (backupRunning) {
|
||||
gui.setStatus("A backup is already running");
|
||||
return;
|
||||
} else {
|
||||
backupRunning = true;
|
||||
}
|
||||
|
||||
//Get the folder to save the backed up files in
|
||||
File path = gui.askForDirectory("Backup folder");
|
||||
if (path == null || !path.isDirectory()) {
|
||||
backupRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
gui.setStatus("Backup running...");
|
||||
List<List<File>> serverFolders = getFoldersOfEnabledServers(path);
|
||||
|
||||
gui.setStatus("Calculating backup size...");
|
||||
long backupFileSize = getFolderSize(gui, serverFolders);
|
||||
|
||||
long locationFreeSpace = path.getFreeSpace();
|
||||
if (locationFreeSpace < (backupFileSize + 2048000000)) {
|
||||
gui.setStatus("Not enough available space. " + (backupFileSize / 1000000) + "MB necessary, but only " +
|
||||
(locationFreeSpace / 1000000) + "MB available");
|
||||
backupRunning = false;
|
||||
backupAborted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
gui.setStatus("Backing up " + (backupFileSize / 1000000) + "MB");
|
||||
|
||||
performBackup(gui, serverFolders, backupFileSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the actual backup after checks have passed and necessary info is available
|
||||
*
|
||||
* @param gui <p>The GUI to use for informing the user</p>
|
||||
* @param serverFolders <p>The folders of the servers to backup</p>
|
||||
* @param backupFileSize <p>The total size of the folders to backup</p>
|
||||
*/
|
||||
private static void performBackup(GUI gui, List<List<File>> serverFolders, long backupFileSize) {
|
||||
new BackupGUI();
|
||||
BackupGUI.updateProgress("Backup starting...", 0);
|
||||
long alreadyCopied = 0;
|
||||
for (List<File> serverFolder : serverFolders) {
|
||||
if (backupAborted || !backupRunning) {
|
||||
gui.setStatus("Backup aborted");
|
||||
backupRunning = false;
|
||||
return;
|
||||
}
|
||||
alreadyCopied = backupServerFiles(gui, serverFolder, backupFileSize, alreadyCopied);
|
||||
}
|
||||
backupRunning = false;
|
||||
if (backupAborted) {
|
||||
gui.setStatus("Backup aborted");
|
||||
} else {
|
||||
BackupGUI.destroy();
|
||||
gui.setStatus("Backup finished");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Backs up the files for a single server
|
||||
*
|
||||
* @param gui <p>The GUI to use for informing the user</p>
|
||||
* @param serverFolder <p>The server's input and output folders</p>
|
||||
* @param backupFileSize <p>The total size of the files to backup</p>
|
||||
* @param alreadyCopied <p>The amount of bytes already copied</p>
|
||||
* @return <p>The new amount of bytes copied</p>
|
||||
*/
|
||||
private static long backupServerFiles(GUI gui, List<File> serverFolder, long backupFileSize, long alreadyCopied) {
|
||||
File srcFolder = serverFolder.get(0);
|
||||
File destinationFolder = serverFolder.get(1);
|
||||
|
||||
//Create child folders
|
||||
if (!destinationFolder.exists() && !destinationFolder.mkdirs()) {
|
||||
backupRunning = false;
|
||||
gui.logError("Unable to create necessary sub-folder in the backup folder");
|
||||
throw new IllegalArgumentException("Unable to create necessary sub-folder in the backup folder");
|
||||
}
|
||||
//Backup
|
||||
try {
|
||||
alreadyCopied += backupFolder(srcFolder, destinationFolder, backupFileSize, alreadyCopied);
|
||||
} catch (IOException e) {
|
||||
gui.showError("Backup caused an error: " + e.getMessage());
|
||||
gui.logError(Arrays.toString(e.getStackTrace()));
|
||||
BackupGUI.destroy();
|
||||
backupRunning = false;
|
||||
}
|
||||
return alreadyCopied;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of a list of folders
|
||||
*
|
||||
* @param gui <p>The GUI to write any errors to</p>
|
||||
* @param serverFolders <p>The folder to find the size of</p>
|
||||
* @return <p>The size of the given folders</p>
|
||||
*/
|
||||
private static long getFolderSize(GUI gui, List<List<File>> serverFolders) {
|
||||
long folderSize = 0;
|
||||
for (List<File> serverFolder : serverFolders) {
|
||||
File srcFolder = serverFolder.get(0);
|
||||
try (Stream<Path> walk = Files.walk(srcFolder.toPath())) {
|
||||
folderSize += walk.filter(Files::isRegularFile).mapToLong(BackupUtil::getFileSize).sum();
|
||||
} catch (IOException e) {
|
||||
gui.setStatus(String.format("IO errors %s", e));
|
||||
}
|
||||
}
|
||||
return folderSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input and output folders for enabled servers
|
||||
*
|
||||
* <p>The input folders are the folders to copy, while the output folders are the folders to write the backup to.
|
||||
* Each list element contains a list of exactly two File items. The first one is the input folder, and the second
|
||||
* one is the output folder</p>
|
||||
*
|
||||
* @param path <p>The path of the backup folder, as given by the user</p>
|
||||
* @return <p>The folders to copy from/to</p>
|
||||
*/
|
||||
private static List<List<File>> getFoldersOfEnabledServers(File path) {
|
||||
List<List<File>> serverFolders = new ArrayList<>();
|
||||
|
||||
//Get folders of servers to back up
|
||||
List<Collection> collections = Main.getController().getCurrentProfile().getCollections();
|
||||
for (Collection collection : collections) {
|
||||
//Ignore disabled and invalid servers
|
||||
if (collection.getServer().getPath().equals("") || !collection.getServer().isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
//Decide sub-folders
|
||||
Server targetServer = collection.getServer();
|
||||
String name = targetServer.getName();
|
||||
File srcFolder = new File(targetServer.getPath());
|
||||
File destinationFolder = new File(path, name);
|
||||
|
||||
List<File> serverFolder = new ArrayList<>();
|
||||
serverFolder.add(srcFolder);
|
||||
serverFolder.add(destinationFolder);
|
||||
serverFolders.add(serverFolder);
|
||||
}
|
||||
return serverFolders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of a file given its path
|
||||
*
|
||||
* @param path <p>The path to a file</p>
|
||||
* @return <p>The size of the file in bytes, or 0 if an exception is thrown</p>
|
||||
*/
|
||||
private static long getFileSize(Path path) {
|
||||
try {
|
||||
return Files.size(path);
|
||||
} catch (IOException exception) {
|
||||
System.out.printf("Failed to get size of %s%n%s", path, exception);
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,284 @@
|
||||
package net.knarcraft.minecraftserverlauncher.utility;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.WebBrowser;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* A holding class for methods shared between classes
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public final class CommonFunctions {
|
||||
|
||||
private static final String filesDirectory = Main.getApplicationWorkDirectory() + File.separator + "files";
|
||||
|
||||
/**
|
||||
* Creates all folders necessary for tests and normal operation
|
||||
*
|
||||
* @throws FileNotFoundException <p>If unable to create a folder</p>
|
||||
*/
|
||||
public static void createAllFolders() throws FileNotFoundException {
|
||||
createFolder(new File(filesDirectory));
|
||||
createFolder(new File(filesDirectory + File.separator + "Jars"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a given folder
|
||||
*
|
||||
* @param folder <p>The folder to create</p>
|
||||
* @throws FileNotFoundException <p>If unable to create the folder</p>
|
||||
*/
|
||||
public static void createFolder(File folder) throws FileNotFoundException {
|
||||
if (!folder.exists()) {
|
||||
if (!folder.mkdirs()) {
|
||||
throw new FileNotFoundException("Cannot create necessary directory.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a resource as an InputStream
|
||||
*
|
||||
* @param resourceName <p>The name of the resource you want to readFromServer</p>
|
||||
* @return <p>An input stream which can be used to access the resource</p>
|
||||
*/
|
||||
public static InputStream getResourceAsStream(String resourceName) {
|
||||
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
|
||||
return classloader.getResourceAsStream(resourceName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a resource as a Scanner
|
||||
*
|
||||
* @param resourceName <p>The name of the resource you want to readFromServer</p>
|
||||
* @return <p>A scanner which can be used to readFromServer contents of the resource</p>
|
||||
* @throws FileNotFoundException <p>If the resource is not found</p>
|
||||
*/
|
||||
public static Scanner getResourceAsScanner(String resourceName) throws FileNotFoundException {
|
||||
InputStream is = getResourceAsStream(resourceName);
|
||||
if (is == null) {
|
||||
throw new FileNotFoundException("The resource was not found.");
|
||||
}
|
||||
return new Scanner(is);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a substring between two substrings in a string
|
||||
*
|
||||
* @param string <p>The string containing the substrings</p>
|
||||
* @param start <p>The substring before the wanted substring</p>
|
||||
* @param end <p>The substring after the wanted substring</p>
|
||||
* @return <p>The wanted substring</p>
|
||||
*/
|
||||
public static String stringBetween(String string, String start, String end) {
|
||||
int startPos = string.indexOf(start) + start.length();
|
||||
if (!string.contains(start) || string.indexOf(end, startPos) < startPos) {
|
||||
return "";
|
||||
}
|
||||
return string.substring(startPos, string.indexOf(end, startPos));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a file from a website
|
||||
*
|
||||
* <p>This is used to find the newest version of jars and the software.</p>
|
||||
*
|
||||
* @param path <p>The full url of the file to readFromServer</p>
|
||||
* @return <p>True if successful. False otherwise</p>
|
||||
* @throws IOException <p>If unable to find or read the file</p>
|
||||
*/
|
||||
public static String readRemoteFile(String path) throws IOException {
|
||||
URL url = new URL(path);
|
||||
return new Scanner(url.openStream()).useDelimiter("\\Z").next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a buffered reader for reading a given file
|
||||
*
|
||||
* @param path <p>The path of the file to read</p>
|
||||
* @return <p>A buffered reader for reading the file</p>
|
||||
* @throws FileNotFoundException <p>If the file does not exist</p>
|
||||
*/
|
||||
public static BufferedReader getFileReader(String path) throws FileNotFoundException {
|
||||
return new BufferedReader(new InputStreamReader(new FileInputStream(path)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a buffered writer for writing to a given file
|
||||
*
|
||||
* @param path <p>The path to the file to write to</p>
|
||||
* @return <p>A buffered writer for writing to the file</p>
|
||||
* @throws FileNotFoundException <p>If the file does not exist</p>
|
||||
*/
|
||||
public static BufferedWriter getFileWriter(String path) throws FileNotFoundException {
|
||||
return new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a file from disk
|
||||
*
|
||||
* @param path <p>The path of the file to read</p>
|
||||
* @return <p>The contents of the file</p>
|
||||
* @throws IOException <p>If unable to find or read the file</p>
|
||||
*/
|
||||
public static String readFile(String path) throws IOException {
|
||||
return CommonFunctions.readBufferedReader(getFileReader(path));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Writes text to a file and adds a trailing newline
|
||||
*
|
||||
* @param path <p>The path of the file to write to</p>
|
||||
* @param text <p>The text to write</p>
|
||||
* @throws IOException <p>If unable to write to the file</p>
|
||||
*/
|
||||
public static void writeFile(String path, String text) throws IOException {
|
||||
writeFile(path, text, !text.equals(""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes text to a file
|
||||
*
|
||||
* @param path <p>The path of the file to write to</p>
|
||||
* @param text <p>The text to write</p>
|
||||
* @param addTrailingNewline <p>Whether to add a new line at the end of the file</p>
|
||||
* @throws IOException <p>If unable to write to the file</p>
|
||||
*/
|
||||
public static void writeFile(String path, String text, Boolean addTrailingNewline) throws IOException {
|
||||
BufferedWriter writer = getFileWriter(path);
|
||||
writer.write(text);
|
||||
if (addTrailingNewline) {
|
||||
writer.newLine();
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends text to a file
|
||||
*
|
||||
* @param path <p>The path to the file to append to</p>
|
||||
* @param text <p>The text to append</p>
|
||||
* @throws IOException <p>If unable to append to the file</p>
|
||||
*/
|
||||
public static void appendFile(String path, String text) throws IOException {
|
||||
BufferedWriter writer = new BufferedWriter(new FileWriter(path, true));
|
||||
writer.write(text);
|
||||
writer.newLine();
|
||||
writer.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a file from a website and replaces the target file
|
||||
*
|
||||
* @param path <p>The full url of the file to download</p>
|
||||
* @param outfile <p>The file to save to</p>
|
||||
* @return <p>True if successful. False otherwise</p>
|
||||
*/
|
||||
public static boolean downloadFile(String path, Path outfile) {
|
||||
try {
|
||||
URL url = new URL(path);
|
||||
InputStream in = url.openStream();
|
||||
Files.copy(in, outfile, StandardCopyOption.REPLACE_EXISTING);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens an url in the user's default application.
|
||||
*
|
||||
* @param url <p>The 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 | UnsupportedOperationException e1) {
|
||||
WebBrowser.displayPage(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all lines from a buffered reader
|
||||
*
|
||||
* @param reader <p>The buffered reader to read from</p>
|
||||
* @return <p>All lines currently readable from the reader, split by the \n character</p>
|
||||
* @throws IOException <p>If unable to read from the buffered reader</p>
|
||||
*/
|
||||
public static String readBufferedReader(BufferedReader reader) throws IOException {
|
||||
//String line;
|
||||
StringBuilder text = new StringBuilder();
|
||||
char[] readCharacters = new char[1000];
|
||||
while (reader.ready()) {
|
||||
if (reader.read(readCharacters) > 0) {
|
||||
text.append(readCharacters);
|
||||
readCharacters = new char[1000];
|
||||
} else {
|
||||
return text.toString().trim();
|
||||
}
|
||||
}
|
||||
return text.toString().trim();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 != null && !name.equals("") && name.matches("[^!?;,]+");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all files within a folder
|
||||
*
|
||||
* @param target <p>The folder to delete from</p>
|
||||
*/
|
||||
public static void removeFilesRecursively(File target) {
|
||||
File[] oldFiles = target.listFiles();
|
||||
if (oldFiles == null) {
|
||||
throw new IllegalArgumentException("Unable to list files in directory");
|
||||
}
|
||||
for (File file : oldFiles) {
|
||||
if (file.isFile()) {
|
||||
if (!file.delete()) {
|
||||
throw new IllegalArgumentException("Unable to delete a file from the directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
for (File file : oldFiles) {
|
||||
if (file.isDirectory()) {
|
||||
removeFilesRecursively(file);
|
||||
if (!file.delete()) {
|
||||
throw new IllegalArgumentException("Unable to delete a file from the directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package net.knarcraft.minecraftserverlauncher.utility;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerTypeHandler;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.GUI;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class handles all downloading of .jar files
|
||||
*/
|
||||
public final class JarDownloader {
|
||||
|
||||
private final String jarDirectory;
|
||||
private final GUI gui;
|
||||
|
||||
/**
|
||||
* Initializes a jar downloader
|
||||
*
|
||||
* @param gui <p>The GUI to use for displaying messages</p>
|
||||
* @param jarDirectory <p>The directory to download jar files to</p>
|
||||
*/
|
||||
public JarDownloader(GUI gui, String jarDirectory) {
|
||||
this.gui = gui;
|
||||
this.jarDirectory = jarDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads all jars to the program directory.
|
||||
*
|
||||
* @throws IOException On version file failure or folder creation failure
|
||||
*/
|
||||
public void downloadJars() throws IOException {
|
||||
if (!new File(jarDirectory).exists() && !new File(jarDirectory).mkdirs()) {
|
||||
gui.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 {
|
||||
gui.setStatus("Downloading all jars...");
|
||||
downloadAll();
|
||||
gui.setStatus("Finished downloading jars");
|
||||
} catch (FileNotFoundException | ConfigurationException e) {
|
||||
gui.setStatus(e.getMessage());
|
||||
throw new FileNotFoundException("One or more downloads failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads jar files for all possible server versions
|
||||
*
|
||||
* @throws IOException <p>If a jar fails to download</p>
|
||||
*/
|
||||
private void downloadAll() throws IOException, ConfigurationException {
|
||||
for (ServerType type : ServerTypeHandler.getServerTypes()) {
|
||||
if (type.getName().equals("Custom")) {
|
||||
continue;
|
||||
}
|
||||
for (String version : type.getVersions()) {
|
||||
if ((type.getName().equals("Spigot") || type.getName().equals("Bukkit")) && version.equals("Latest")) {
|
||||
continue;
|
||||
}
|
||||
gui.setStatus("Downloading " + type.getName() + version + "...");
|
||||
boolean success = type.downloadJar(jarDirectory, version);
|
||||
if (!success) {
|
||||
throw new FileNotFoundException("Unable to download the jar file for " + type.getName() + version);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package net.knarcraft.minecraftserverlauncher.utility;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Scanner;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.downloadFile;
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.getResourceAsScanner;
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.readRemoteFile;
|
||||
|
||||
/**
|
||||
* A utility used for updating the software
|
||||
*/
|
||||
public final class Updater {
|
||||
|
||||
private static final String updaterFile = Main.getApplicationWorkDirectory() + File.separator + "Updater.jar";
|
||||
private static final String updaterURL = "https://jenkins.knarcraft.net/job/KnarCraft/job/Jar-Updater/job/master/" +
|
||||
"lastSuccessfulBuild/artifact/target/jar-updater-1.0-SNAPSHOT.jar";
|
||||
private static final String targetFile = "minecraft-server-launcher.jar";
|
||||
|
||||
/**
|
||||
* Gets the version channel and version of this software instance
|
||||
*
|
||||
* @return <p>An array of Channel, Version</p>
|
||||
* @throws FileNotFoundException <p>If unable to find or read currentversion.csv</p>
|
||||
*/
|
||||
public static String[] getCurrentVersion() throws FileNotFoundException {
|
||||
Scanner file = getResourceAsScanner("currentversion.csv");
|
||||
if (!file.hasNextLine()) {
|
||||
throw new FileNotFoundException("File currentversion.csv is invalid");
|
||||
}
|
||||
String oldType = file.nextLine();
|
||||
if (!file.hasNextLine()) {
|
||||
throw new FileNotFoundException("File currentversion.csv is invalid");
|
||||
}
|
||||
String oldVer = file.nextLine();
|
||||
file.close();
|
||||
return new String[]{oldType, oldVer};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a newer version is available
|
||||
*
|
||||
* @param updateURL <p>The URL used for checking for updates</p>
|
||||
* @param updateChannel <p>The release channel to use</p>
|
||||
* @throws IOException <p>If the update data cannot be read</p>
|
||||
*/
|
||||
public static void checkForUpdate(String updateURL, String updateChannel) throws IOException {
|
||||
String[] oldData = getCurrentVersion();
|
||||
String oldType = oldData[0];
|
||||
String oldVer = oldData[1];
|
||||
|
||||
String data = readRemoteFile(updateURL);
|
||||
JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
|
||||
String latest = jsonObject.getAsJsonObject("latest").get(updateChannel).getAsString();
|
||||
|
||||
if (!oldType.equals(updateChannel) || isVersionHigher(oldVer, latest)) {
|
||||
JsonArray versionList = jsonObject.getAsJsonArray("versions");
|
||||
String url = "";
|
||||
for (JsonElement elem : versionList) {
|
||||
JsonObject obj = elem.getAsJsonObject();
|
||||
String ver = obj.get("id").getAsString();
|
||||
String type = obj.get("type").getAsString();
|
||||
if (ver.equals(latest) && type.equals(updateChannel)) {
|
||||
url = obj.get("url").getAsString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!new File(updaterFile).exists()) {
|
||||
downloadFile(updaterURL, Paths.get(updaterFile));
|
||||
}
|
||||
|
||||
int answer = JOptionPane.showConfirmDialog(null,
|
||||
"An update is available. Do you want to update?", "Update available",
|
||||
JOptionPane.YES_NO_OPTION
|
||||
);
|
||||
if (answer == JOptionPane.YES_NO_OPTION) {
|
||||
runUpdater(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides whether one version number is higher than another
|
||||
*
|
||||
* @param oldVersion <p>The old version to check</p>
|
||||
* @param newVersion <p>The new version to check</p>
|
||||
* @return <p>True if the new version is higher than the old one</p>
|
||||
*/
|
||||
public static boolean isVersionHigher(String oldVersion, String newVersion) {
|
||||
String[] oldVersionParts = oldVersion.split("\\.");
|
||||
String[] newVersionParts = newVersion.split("\\.");
|
||||
int versionLength = Math.max(oldVersionParts.length, newVersionParts.length);
|
||||
for (int i = 0; i < versionLength; i++) {
|
||||
int oldVersionNumber = oldVersionParts.length > i ? Integer.parseInt(oldVersionParts[i]) : 0;
|
||||
int newVersionNumber = newVersionParts.length > i ? Integer.parseInt(newVersionParts[i]) : 0;
|
||||
if (newVersionNumber != oldVersionNumber) {
|
||||
return newVersionNumber > oldVersionNumber;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the software
|
||||
*
|
||||
* @param url <p>The URL of the new file to download</p>
|
||||
* @throws IOException <p>If unable to run the updater</p>
|
||||
*/
|
||||
private static void runUpdater(String url) throws IOException {
|
||||
String javaCommand = ServerLauncherController.getInstance().getJavaCommand();
|
||||
ProcessBuilder builder;
|
||||
builder = new ProcessBuilder(javaCommand, "-jar", "Updater.jar", url, "yes", targetFile, "5", "nogui");
|
||||
builder.directory(new File(Main.getApplicationWorkDirectory()));
|
||||
builder.redirectErrorStream(true);
|
||||
builder.start();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
2
src/main/resources/currentversion.csv
Normal file
2
src/main/resources/currentversion.csv
Normal file
@ -0,0 +1,2 @@
|
||||
beta
|
||||
1.4.3
|
|
11
src/main/resources/menumsg.csv
Normal file
11
src/main/resources/menumsg.csv
Normal file
@ -0,0 +1,11 @@
|
||||
setupText=1. Create a new profile, or use the default._BREAK_2. Click on the add server button and insert the name of your server._BREAK_3. Navigate to the servers tab, and find your server._BREAK_4. Fill in all the settings with what you want, and remember to check Enabled._BREAK_5. Navigate back to the Control panel and click Start servers
|
||||
runInBackgroundText=The program will run in the background. You don't need to have the gui open all the time._BREAK_When in background mode, you can left click on the tray icon to open the gui again. To exit the program, right click the tray icon and press exit.
|
||||
delayStartupText=This adds a delay (in seconds) between the start of each server._BREAK_This option should be used for heavy servers with many plugins, but may not be needed on a single server or servers using a few plugins.
|
||||
downloadJarsText=This option will download all the .jar files available in the program._BREAK_Instead of downloading .jar files when you start servers, it will download all files you don't already have, on startup._BREAK_This will be faster and more reliable than usual._BREAK_You need to restart the software for this setting to take action.
|
||||
aboutText=This software was created to start and manage several servers simultaneously._BREAK_You no longer have to do the tedious work of manually downloading different .jar files every time you want to try something new.
|
||||
infoURL=https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherInfo/
|
||||
manualUpdateURL=https://git.knarcraft.net/KnarCraft/Minecraft-Server-Launcher/releases
|
||||
storyURL=https://archive.knarcraft.net/Scripts/BungeeMinecraftServerLauncherStory/
|
||||
javaCommandText=This option allows you to set a custom command/path to the Java executable used for Minecraft 1.17 and above._BREAK_If "java" is currently pointing to Java 8, you can use this to set a custom one for running new Minecraft servers and BuildTools.
|
||||
oldJavaCommandText=This option allows you to set a custom command/path to the Java executable used for Minecraft 1.16 and below._BREAK_If "java" is currently pointing to Java 16, you can use this to set a custom one for running old Minecraft servers.
|
||||
deleteBuiltJarFilesText=This option allows you to easily delete built Spigot and Bukkit .jar files._BREAK_You should occasionally run this option to update the built .jar files to ensure you're running the latest update.
|
Can't render this file because it contains an unexpected character in line 9 and column 136.
|
11
src/main/resources/servertypes.csv
Normal file
11
src/main/resources/servertypes.csv
Normal file
@ -0,0 +1,11 @@
|
||||
Vanilla;Latest,Snapshot,1.18.1,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.9,1.7.10,1.6.4,1.5.2,1.4.7,1.3.2,1.2.5;https://launchermeta.mojang.com/mc/game/version_manifest.json;"release":";";https://s3.amazonaws.com/Minecraft.Download/versions/
|
||||
Spigot;Latest,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.9.4,1.8.8,1.7.10,1.6.4-R2.1,1.5.2-R1.1,1.4.7-R1.1;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Spigot/;spigot-
|
||||
Paper;1.18.1,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8;https://papermc.io/api/v2/projects/paper/versions/;"builds":[;];https://papermc.io/api/v2/projects/paper/versions/
|
||||
#SpongeVanilla;1.12.2,1.11.2,1.10.2,1.8.9;https://dl-api.spongepowered.org/v1/org.spongepowered/spongevanilla/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongevanilla/;/spongevanilla-
|
||||
Craftbukkit;Latest,1.17.1,1.16.5,1.15.2,1.14.4,1.13.2,1.12.2,1.11.2,1.10.2,1.9.4,1.8.8,1.7.10-R0.1,1.6.4-R2.0,1.5.2-R1.0,1.4.6-R0.3,1.3.2-R3.0,1.2.5-R2.0,1.1-R6,1.0.1-R1,b1.8.1,b1.7.3;https://static.knarcraft.net/archive/downloads/minecraftserverjars/Bukkit/;craftbukkit-
|
||||
#SpongeForge;1.12.2,1.11.2,1.10.2;https://dl-api.spongepowered.org/v1/org.spongepowered/spongeforge/downloads?type=stable&minecraft=;"version":";",;https://repo.spongepowered.org/maven/org/spongepowered/spongeforge/;/spongeforge-
|
||||
MCPCplus;1.6.4,1.6.2,1.5.2,1.4.7;https://static.knarcraft.net/archive/downloads/minecraftserverjars/MCPC+/;mcpcplus
|
||||
Bungee;Latest,1.7.10,1.6.4,1.5.2,1.4.7;https://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/;Artifacts of BungeeCord #; ;http://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/artifact/bootstrap/target/BungeeCord.jar;https://static.knarcraft.net/archive/downloads/minecraftserverjars/BungeeCord/;BungeeCord-
|
||||
Waterfall;1.18,1.17,1.16,1.15,1.14,1.13,1.12,1.11;https://papermc.io/api/v2/projects/waterfall/versions/;"builds":[;];https://papermc.io/api/v2/projects/waterfall/versions/
|
||||
Travertine;1.16,1.15,1.14,1.13,1.12;https://papermc.io/api/v2/projects/travertine/versions/;"builds":[;];https://papermc.io/api/v2/projects/travertine/versions/
|
||||
Custom;
|
Can't render this file because it contains an unexpected character in line 1 and column 207.
|
@ -1,168 +0,0 @@
|
||||
package net.knarcraft.serverlauncher;
|
||||
|
||||
import net.knarcraft.serverlauncher.profile.Collection;
|
||||
import net.knarcraft.serverlauncher.profile.Profile;
|
||||
import net.knarcraft.serverlauncher.server.Server;
|
||||
import net.knarcraft.serverlauncher.server.ServerType;
|
||||
import net.knarcraft.serverlauncher.userinterface.ServerConsoles;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static net.knarcraft.serverlauncher.Shared.stringBetween;
|
||||
//Java 8 required.
|
||||
|
||||
/**
|
||||
* A software for managing Minecraft servers.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
public class Main {
|
||||
@SuppressWarnings("CanBeFinal")
|
||||
private static String appDir;
|
||||
private static boolean running = false;
|
||||
|
||||
static {
|
||||
try {
|
||||
appDir = String.valueOf(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile());
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
try (PrintWriter file = new PrintWriter(Main.getAppDir() + File.separator + "latestrun.log")) {
|
||||
file.print("");
|
||||
} catch (IOException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
EventQueue.invokeLater(() -> {
|
||||
try {
|
||||
setup();
|
||||
new ServerConsoles();
|
||||
Profile.load();
|
||||
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
|
||||
exec.scheduleAtFixedRate(Main::updateConsoles, 10, 500, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void setup() {
|
||||
try {
|
||||
ServerType.loadServerTypes();
|
||||
} catch (ConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getAppDir() {
|
||||
return appDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from server processes, and writes the output to consoles.
|
||||
*/
|
||||
private static void updateConsoles() {
|
||||
try {
|
||||
for (Collection collection : Profile.getCurrent().getCollections()) {
|
||||
Server server = collection.getServer();
|
||||
if (server.isEnabled() && server.getProcess() != null) {
|
||||
try {
|
||||
String readText = server.read();
|
||||
if (!readText.equals("")) {
|
||||
collection.getServerConsole().output(readText);
|
||||
updatePlayerList(readText, server);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!server.getProcess().isAlive()) {
|
||||
server.stopped();
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean runningNew = serversRunning();
|
||||
if (!runningNew && running) {
|
||||
Profile.getGUI().updateRunning(false);
|
||||
Profile.getGUI().setStatus("Servers are stopped");
|
||||
} else if (runningNew && !running) {
|
||||
Profile.getGUI().updateRunning(true);
|
||||
}
|
||||
running = runningNew;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Goes through all servers and looks for any running servers.
|
||||
*
|
||||
* @return Is at least one server running?
|
||||
*/
|
||||
private static boolean serversRunning() {
|
||||
int num = 0;
|
||||
for (Collection collection : Profile.getCurrent().getCollections()) {
|
||||
if (collection.getServer().isStarted() || (collection.getServer().getProcess() != null && collection.getServer().getProcess().isAlive())) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return num > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for strings implying a player has joined or left, and updates the appropriate lists.
|
||||
*
|
||||
* @param text The text to search.
|
||||
* @param server The server which sent the text.
|
||||
*/
|
||||
private static void updatePlayerList(String text, Server server) {
|
||||
if (!server.getTypeName().equals("Bungee")) {
|
||||
String joinedPlayer = getPlayer(text, true);
|
||||
String leftPlayer = getPlayer(text, false);
|
||||
if (!joinedPlayer.equals("")) {
|
||||
if (!server.hasPlayer(joinedPlayer)) {
|
||||
server.addPlayer(joinedPlayer);
|
||||
}
|
||||
} else if (!leftPlayer.equals("")) {
|
||||
if (server.hasPlayer(leftPlayer)) {
|
||||
server.removePlayer(leftPlayer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches a string for players joining or leaving.
|
||||
*
|
||||
* @param text The string to search
|
||||
* @param joined Are we searching for a joining player or not
|
||||
* @return The name of a player or an empty string
|
||||
*/
|
||||
private static String getPlayer(String text, boolean joined) {
|
||||
String playerName;
|
||||
if (joined) {
|
||||
playerName = stringBetween(text, "[Server thread/INFO]: ", " joined the game");
|
||||
if (playerName.equals("")) {
|
||||
playerName = stringBetween(text, "UUID of player ", " is ");
|
||||
}
|
||||
} else {
|
||||
playerName = stringBetween(text, "INFO]: ", " lost connection");
|
||||
if (playerName.equals("")) {
|
||||
playerName = stringBetween(text, "[Server thread/INFO]: ", " left the game");
|
||||
}
|
||||
}
|
||||
return playerName;
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package net.knarcraft.serverlauncher;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* A holding class for methods shared between classes.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Shared {
|
||||
/**
|
||||
* Finds a substring between two substrings in a string.
|
||||
*
|
||||
* @param string The string containing the substrings
|
||||
* @param start The substring before the wanted substring
|
||||
* @param end The substring after the wanted substring
|
||||
* @return The wanted substring.
|
||||
*/
|
||||
public static String stringBetween(String string, String start, String end) {
|
||||
int startPos = string.indexOf(start) + start.length();
|
||||
if (!string.contains(start) || string.indexOf(end, startPos) < startPos) {
|
||||
return "";
|
||||
}
|
||||
return string.substring(startPos, string.indexOf(end, startPos));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a file from a website.
|
||||
* This is used to find the newest version of jars and the software.
|
||||
*
|
||||
* @param path The full url of the file to read
|
||||
* @return True if successful. False otherwise
|
||||
*/
|
||||
public static String readFile(String path) throws IOException {
|
||||
URL url = new URL(path);
|
||||
return new Scanner(url.openStream()).useDelimiter("\\Z").next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a file from a website.
|
||||
*
|
||||
* @param path The full url of the file to download.
|
||||
* @param outfile The file to save to
|
||||
* @return True if successful. False otherwise
|
||||
*/
|
||||
public static boolean downloadFile(String path, Path outfile) {
|
||||
try {
|
||||
URL url = new URL(path);
|
||||
InputStream in = url.openStream();
|
||||
Files.copy(in, outfile, StandardCopyOption.REPLACE_EXISTING);
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
package net.knarcraft.serverlauncher.profile;
|
||||
|
||||
import net.knarcraft.serverlauncher.server.Server;
|
||||
import net.knarcraft.serverlauncher.userinterface.ServerConsoles;
|
||||
import net.knarcraft.serverlauncher.userinterface.ServerTab;
|
||||
import net.knarcraft.serverlauncher.userinterface.Console;
|
||||
|
||||
/**
|
||||
* Acts as a wrapper for objects necessary for each server.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Collection {
|
||||
private final Server server;
|
||||
private final ServerTab serverTab;
|
||||
private final Console serverConsole;
|
||||
private final String name;
|
||||
|
||||
Collection(String name) {
|
||||
this.serverTab = new ServerTab(name);
|
||||
this.server = new Server(name);
|
||||
this.serverConsole = ServerConsoles.addTab(name);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
Collection(String name,
|
||||
String path,
|
||||
boolean enabled,
|
||||
String typeName,
|
||||
String serverVersion,
|
||||
String maxRam,
|
||||
String vanillaVersion,
|
||||
String snapshotVersion,
|
||||
String spongeVanillaVersion,
|
||||
String bungeeVersion
|
||||
) {
|
||||
this.serverTab = new ServerTab(name);
|
||||
this.server = new Server(
|
||||
name,
|
||||
path,
|
||||
enabled,
|
||||
typeName,
|
||||
serverVersion,
|
||||
maxRam,
|
||||
vanillaVersion,
|
||||
snapshotVersion,
|
||||
spongeVanillaVersion,
|
||||
bungeeVersion
|
||||
);
|
||||
this.serverConsole = ServerConsoles.addTab(name);
|
||||
this.name = name;
|
||||
this.serverTab.setData(path, enabled, typeName, serverVersion, maxRam);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
public ServerTab getServerTab() {
|
||||
return this.serverTab;
|
||||
}
|
||||
|
||||
public Console getServerConsole() {
|
||||
return this.serverConsole;
|
||||
}
|
||||
}
|
@ -1,616 +0,0 @@
|
||||
package net.knarcraft.serverlauncher.profile;
|
||||
|
||||
import net.knarcraft.serverlauncher.server.AdvancedServerType;
|
||||
import net.knarcraft.serverlauncher.server.Server;
|
||||
import net.knarcraft.serverlauncher.server.ServerType;
|
||||
import net.knarcraft.serverlauncher.userinterface.GUI;
|
||||
import net.knarcraft.serverlauncher.userinterface.ServerConsoles;
|
||||
import net.knarcraft.serverlauncher.userinterface.ServerTab;
|
||||
import net.knarcraft.serverlauncher.Main;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.*;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
import java.util.Scanner;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static net.knarcraft.serverlauncher.Shared.downloadFile;
|
||||
import static net.knarcraft.serverlauncher.Shared.readFile;
|
||||
import static net.knarcraft.serverlauncher.Shared.stringBetween;
|
||||
|
||||
/**
|
||||
* Contains all user settings, and a list of servers.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
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 final ArrayList<Collection> collections;
|
||||
private final String name;
|
||||
private boolean runInBackground;
|
||||
private int delayStartup;
|
||||
private boolean downloadJars;
|
||||
private static String vanillaVersion;
|
||||
private static String snapshotVersion;
|
||||
private static String bungeeVersion;
|
||||
|
||||
private Profile(String name) {
|
||||
this.collections = new ArrayList<>();
|
||||
this.name = name;
|
||||
this.runInBackground = false;
|
||||
this.delayStartup = 0;
|
||||
this.downloadJars = false;
|
||||
profiles.add(this);
|
||||
if (current == null) {
|
||||
current = this;
|
||||
}
|
||||
}
|
||||
|
||||
private Profile(String name, boolean runInBackground, int delayStartup, boolean downloadJars) {
|
||||
this.collections = new ArrayList<>();
|
||||
this.name = name;
|
||||
this.runInBackground = runInBackground;
|
||||
this.delayStartup = delayStartup;
|
||||
this.downloadJars = downloadJars;
|
||||
profiles.add(this);
|
||||
if (current == null) {
|
||||
current = this;
|
||||
}
|
||||
}
|
||||
|
||||
public static GUI getGUI() {
|
||||
return gui;
|
||||
}
|
||||
|
||||
public boolean getRunInBackground() {
|
||||
return this.runInBackground;
|
||||
}
|
||||
|
||||
public int getDelayStartup() {
|
||||
return this.delayStartup;
|
||||
}
|
||||
|
||||
public boolean getDownloadJars() {
|
||||
return this.downloadJars;
|
||||
}
|
||||
|
||||
public static Profile getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
public ArrayList<Collection> getCollections() {
|
||||
return this.collections;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Collection object by name.
|
||||
*
|
||||
* @param name The name of the collection.
|
||||
* @return A collection object.
|
||||
*/
|
||||
public Collection getCollection(String name) {
|
||||
for (Collection collection : this.collections) {
|
||||
if (collection.getName().equals(name)) {
|
||||
return collection;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void setRunInBackground(boolean value) {
|
||||
this.runInBackground = value;
|
||||
}
|
||||
|
||||
public void setDelayStartup(int value) {
|
||||
if (value >= 0) {
|
||||
this.delayStartup = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void setDownloadJars(boolean value) {
|
||||
this.downloadJars = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a collection to the profile if the name is valid.
|
||||
*
|
||||
* @param name The name of the collection and its elements.
|
||||
*/
|
||||
public void addCollection(String name) {
|
||||
if (name == null) { //If a user cancels or crosses out window
|
||||
return;
|
||||
}
|
||||
if (getCollection(name) == null &&
|
||||
!name.equals("") &&
|
||||
!name.equals("All") &&
|
||||
!name.contains("!") &&
|
||||
!name.contains("?") &&
|
||||
!name.contains(";")
|
||||
) {
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.contains("!") && !name.contains("?") && !name.contains(";")) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"Profile name can't be blank.",
|
||||
"Error",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
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
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
new Profile(name);
|
||||
}
|
||||
|
||||
public void removeCollection(String name) {
|
||||
for (int i = 0; i < collections.size(); i++) {
|
||||
if (collections.get(i).getName().equals(name)) {
|
||||
this.collections.remove(i);
|
||||
gui.update();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeProfile(String name) {
|
||||
if (profiles.size() > 1) {
|
||||
for (int i = 0; i < profiles.size(); i++) {
|
||||
if (profiles.get(i).name.equals((name))) {
|
||||
profiles.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateConsoles() {
|
||||
JTabbedPane consolesTab = ServerConsoles.getTab();
|
||||
consolesTab.removeAll();
|
||||
for (Collection collection : collections) {
|
||||
consolesTab.add(collection.getName(), collection.getServerConsole().getPanel());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command to a server, or all servers
|
||||
*
|
||||
* @param serverName The target server
|
||||
* @param command The command to send.
|
||||
*/
|
||||
public void sendCommand(String serverName, String command) {
|
||||
if (serverName.equals("All")) {
|
||||
for (Collection collection : this.collections) {
|
||||
try {
|
||||
collection.getServer().sendCommand(command);
|
||||
} catch (IOException e) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"Server " + collection.getName() + " caused an exception.",
|
||||
"Error",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Collection collection = getCollection(serverName);
|
||||
if (collection != null) {
|
||||
Server target = collection.getServer();
|
||||
try {
|
||||
target.sendCommand(command);
|
||||
} catch (IOException e) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"Server " + target.getName() + " caused an exception.",
|
||||
"Error",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"Server " + serverName + " is invalid.",
|
||||
"Error", JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all server tabs, and saves it to the variables of the corresponding servers.
|
||||
* Saves all profiles and servers to a text file.
|
||||
*/
|
||||
public void save() throws FileNotFoundException {
|
||||
for (Collection collection : this.collections) {
|
||||
Server server = collection.getServer();
|
||||
ServerTab serverTab = collection.getServerTab();
|
||||
server.setPath(serverTab.getPath());
|
||||
server.setMaxRam(serverTab.getMaxRam());
|
||||
server.setType(ServerType.getByName(serverTab.getType()));
|
||||
try {
|
||||
server.setServerVersion(serverTab.getVersion());
|
||||
} catch (IllegalArgumentException e) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"Invalid server version for " + server.getName(),
|
||||
"Error",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
}
|
||||
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
|
||||
);
|
||||
throw new FileNotFoundException("Unable to create the profiles folder: " + profilesDir);
|
||||
}
|
||||
try (PrintWriter file = new PrintWriter(profilesFile)) {
|
||||
file.println(String.format(
|
||||
"%s;%s;%s;%s;%d;%d",
|
||||
current.name,
|
||||
vanillaVersion,
|
||||
snapshotVersion,
|
||||
bungeeVersion,
|
||||
gui.getSize().width,
|
||||
gui.getSize().height
|
||||
));
|
||||
file.close();
|
||||
for (Profile profile : profiles) {
|
||||
StringBuilder saveString = new StringBuilder(String.format(
|
||||
"%s;%b;%d;%b?",
|
||||
profile.name,
|
||||
profile.runInBackground,
|
||||
profile.delayStartup,
|
||||
profile.downloadJars)
|
||||
);
|
||||
for (Collection collection : profile.collections) {
|
||||
Server server = collection.getServer();
|
||||
saveString.append(String.format(
|
||||
"%s;%s;%b;%s;%s;%s;%s;%s;%s;%s!",
|
||||
server.getName(),
|
||||
server.getPath(),
|
||||
server.isEnabled(),
|
||||
server.getTypeName(),
|
||||
server.getServerVersion(),
|
||||
server.getMaxRam(),
|
||||
server.getVanillaVersion(),
|
||||
server.getSnapshotVersion(),
|
||||
server.getSpongeVanillaVersion(),
|
||||
server.getBungeeVersion()
|
||||
)
|
||||
);
|
||||
}
|
||||
saveString = new StringBuilder(saveString.substring(0, saveString.length() - 1));
|
||||
try (PrintWriter fileAppend = new PrintWriter(new FileWriter(
|
||||
profilesFile,
|
||||
true
|
||||
))) {
|
||||
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
|
||||
);
|
||||
throw new FileNotFoundException("Unable to save to the profiles file.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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
|
||||
);
|
||||
}
|
||||
throw new FileNotFoundException("Unable to create the profiles file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads profiles and servers from a text file.
|
||||
*/
|
||||
public static void load() {
|
||||
try (Scanner in = new Scanner(new File(profilesFile))) {
|
||||
try {
|
||||
String[] staticData = in.nextLine().split(";", -1);
|
||||
String profileName = staticData[0];
|
||||
vanillaVersion = staticData[1];
|
||||
snapshotVersion = staticData[2];
|
||||
bungeeVersion = staticData[3];
|
||||
int guiWidth = Integer.parseInt(staticData[4]);
|
||||
int guiHeight = Integer.parseInt(staticData[5]);
|
||||
gui = new GUI(guiWidth, guiHeight);
|
||||
while (in.hasNextLine()) {
|
||||
String line = in.nextLine();
|
||||
if (line.contains("?")) {
|
||||
String[] data = line.split("\\?");
|
||||
String[] profileData = data[0].split(";", -1);
|
||||
Profile profile = parseProfile(profileData);
|
||||
if (data[1].contains("!")) {
|
||||
String[] servers = data[1].split("!", -1);
|
||||
for (String server : servers) {
|
||||
String[] serverData = server.split(";", -1);
|
||||
parseServer(profile, serverData);
|
||||
}
|
||||
} else {
|
||||
String[] serverData = data[1].split(";", -1);
|
||||
parseServer(profile, serverData);
|
||||
}
|
||||
} else {
|
||||
String[] profileData = line.split(";", -1);
|
||||
parseProfile(profileData);
|
||||
}
|
||||
}
|
||||
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
|
||||
);
|
||||
System.exit(1);
|
||||
}
|
||||
if (profiles.size() == 0) {
|
||||
addProfile("Default");
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"A profiles file was not found. Default profile was created.",
|
||||
"Info",
|
||||
JOptionPane.INFORMATION_MESSAGE
|
||||
);
|
||||
gui = new GUI();
|
||||
addProfile("Default");
|
||||
}
|
||||
gui.update();
|
||||
gui.updateProfiles();
|
||||
current.updateConsoles();
|
||||
if (current.downloadJars) {
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
try {
|
||||
downloadJars();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (current.runInBackground) {
|
||||
Executors.newSingleThreadExecutor().execute(Server::startServers);
|
||||
gui.hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a profile, and creates a profile with the data.
|
||||
*
|
||||
* @param profileData The data of the new profile
|
||||
* @return The new profile
|
||||
*/
|
||||
private static Profile parseProfile(String[] profileData) {
|
||||
return new Profile(
|
||||
profileData[0],
|
||||
Boolean.parseBoolean(profileData[1]),
|
||||
Integer.parseInt(profileData[2]),
|
||||
Boolean.parseBoolean(profileData[3])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a server, and creates a new collection.
|
||||
*
|
||||
* @param profile The profile which to add the collection
|
||||
* @param serverData The data to parse
|
||||
*/
|
||||
private static void parseServer(Profile profile, String[] serverData) {
|
||||
profile.collections.add(new Collection(
|
||||
serverData[0],
|
||||
serverData[1],
|
||||
Boolean.parseBoolean(serverData[2]),
|
||||
serverData[3],
|
||||
serverData[4],
|
||||
serverData[5],
|
||||
serverData[6],
|
||||
serverData[7],
|
||||
serverData[8],
|
||||
serverData[9])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads all jars to the program directory.
|
||||
*
|
||||
* @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
|
||||
);
|
||||
throw new FileNotFoundException("Unable to create jars folder");
|
||||
}
|
||||
try {
|
||||
downloadAll();
|
||||
gui.setStatus("Finished downloading jars");
|
||||
} catch (FileNotFoundException e) {
|
||||
gui.setStatus("One or more downloads failed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads jar files for all possible server versions.
|
||||
*
|
||||
* @throws IOException If a jar fails to download.
|
||||
*/
|
||||
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;
|
||||
for (String version : type.getVersions()) {
|
||||
Boolean success;
|
||||
if (gui != null) {
|
||||
gui.setStatus("Downloading: " + name + version + ".jar");
|
||||
}
|
||||
File file = new File(jarDir + type.getName() + version + ".jar");
|
||||
Path filePath = Paths.get(jarDir + type.getName() + version + ".jar");
|
||||
switch (type.getName()) {
|
||||
case "Vanilla":
|
||||
case "Snapshot":
|
||||
if (version.equals("Latest")) {
|
||||
newestVersion = stringBetween(readFile(Objects.requireNonNull(advType).getVersionURL()), advType.getSrcStart(), advType.getSrcEnd());
|
||||
setVersion(name, newestVersion);
|
||||
success = (file.isFile() && newestVersion.equals(getVersion(name))) || downloadFile(url + newestVersion + advType.getDownloadURLPart() + newestVersion + ".jar", filePath);
|
||||
} else {
|
||||
success = file.isFile() || downloadFile(url + version + Objects.requireNonNull(advType).getDownloadURLPart() + version + ".jar", filePath);
|
||||
}
|
||||
break;
|
||||
case "Spigot":
|
||||
case "Craftbukkit":
|
||||
case "MCPCplus":
|
||||
success = file.isFile() || downloadFile(url + name + version + ".jar", 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);
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
success = true;
|
||||
}
|
||||
if (!success) {
|
||||
if (gui != null) {
|
||||
gui.setStatus("Error downloading: " + name + version + ".jar");
|
||||
}
|
||||
throw new FileNotFoundException("Error downloading: " + name + version + ".jar");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current version of a type
|
||||
*
|
||||
* @param type The version type
|
||||
* @return The version string
|
||||
*/
|
||||
private static String getVersion(String type) {
|
||||
switch (type) {
|
||||
case "Vanilla":
|
||||
return vanillaVersion;
|
||||
case "Snapshot":
|
||||
return snapshotVersion;
|
||||
case "Bungee":
|
||||
return bungeeVersion;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a server type's last downloaded version.
|
||||
*
|
||||
* @param type The version type
|
||||
* @param version The version string
|
||||
*/
|
||||
private static void setVersion(String type, String version) {
|
||||
if (!type.equals("")) {
|
||||
switch (type) {
|
||||
case "Vanilla":
|
||||
vanillaVersion = version;
|
||||
break;
|
||||
case "Snapshot":
|
||||
snapshotVersion = version;
|
||||
break;
|
||||
case "Bungee":
|
||||
bungeeVersion = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package net.knarcraft.serverlauncher.server;
|
||||
|
||||
/**
|
||||
* A more advanced servertype for particularly tricky jar downloads.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class AdvancedServerType extends ServerType {
|
||||
private final String versionURL;
|
||||
private final String downloadURLPart;
|
||||
private final String srcStart;
|
||||
private final String srcEnd;
|
||||
|
||||
AdvancedServerType(String name, String[] versions, String versionURL, String srcStart, String srcEnd, String downloadURL, String downloadURLPart) {
|
||||
super(name, versions, downloadURL);
|
||||
this.srcStart = srcStart;
|
||||
this.srcEnd = srcEnd;
|
||||
this.versionURL = versionURL;
|
||||
this.downloadURLPart = downloadURLPart;
|
||||
}
|
||||
|
||||
public String getVersionURL() {
|
||||
return this.versionURL;
|
||||
}
|
||||
|
||||
public String getDownloadURLPart() {
|
||||
return this.downloadURLPart;
|
||||
}
|
||||
|
||||
public String getSrcStart() {
|
||||
return this.srcStart;
|
||||
}
|
||||
|
||||
public String getSrcEnd() {
|
||||
return this.srcEnd;
|
||||
}
|
||||
}
|
@ -1,479 +0,0 @@
|
||||
package net.knarcraft.serverlauncher.server;
|
||||
|
||||
import net.knarcraft.serverlauncher.Main;
|
||||
import net.knarcraft.serverlauncher.profile.Collection;
|
||||
import net.knarcraft.serverlauncher.profile.Profile;
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static net.knarcraft.serverlauncher.Shared.downloadFile;
|
||||
import static net.knarcraft.serverlauncher.Shared.readFile;
|
||||
import static net.knarcraft.serverlauncher.Shared.stringBetween;
|
||||
|
||||
|
||||
/**
|
||||
* Contains all necessary information to create, run and manage a Minecraft server.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Server {
|
||||
/** Available ram sizes. For GUI dropdown */
|
||||
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 final String name;
|
||||
private String path;
|
||||
private boolean enabled;
|
||||
private final ArrayList<String> playerList;
|
||||
private ServerType type;
|
||||
private String serverVersion;
|
||||
private String maxRam;
|
||||
private Process process;
|
||||
private BufferedWriter writer;
|
||||
private BufferedReader reader;
|
||||
private String vanillaVersion;
|
||||
private String snapshotVersion;
|
||||
private String spongeVanillaVersion;
|
||||
private String bungeeVersion;
|
||||
private boolean started;
|
||||
|
||||
public Server(String name) {
|
||||
this.name = name;
|
||||
this.path = "";
|
||||
this.enabled = false;
|
||||
this.playerList = new ArrayList<>();
|
||||
this.type = null;
|
||||
this.serverVersion = "";
|
||||
this.maxRam = ramList[0];
|
||||
this.process = null;
|
||||
this.writer = null;
|
||||
this.reader = null;
|
||||
this.vanillaVersion = "";
|
||||
this.snapshotVersion = "";
|
||||
this.spongeVanillaVersion = "";
|
||||
this.bungeeVersion = "";
|
||||
}
|
||||
|
||||
public Server(
|
||||
String name,
|
||||
String path,
|
||||
boolean enabled,
|
||||
String typeName,
|
||||
String serverVersion,
|
||||
String maxRam,
|
||||
String vanillaVersion,
|
||||
String snapshotVersion,
|
||||
String spongeVanillaVersion,
|
||||
String bungeeVersion
|
||||
) {
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
this.enabled = enabled;
|
||||
this.type = ServerType.getByName(typeName);
|
||||
this.serverVersion = serverVersion;
|
||||
this.maxRam = maxRam;
|
||||
this.vanillaVersion = vanillaVersion;
|
||||
this.snapshotVersion = snapshotVersion;
|
||||
this.spongeVanillaVersion = spongeVanillaVersion;
|
||||
this.bungeeVersion = bungeeVersion;
|
||||
this.playerList = new ArrayList<>();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public boolean isStarted() {
|
||||
return started;
|
||||
}
|
||||
|
||||
public String getTypeName() {
|
||||
return this.type.getName();
|
||||
}
|
||||
|
||||
public String getServerVersion() {
|
||||
return this.serverVersion;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
}
|
||||
|
||||
public Process getProcess() {
|
||||
return this.process;
|
||||
}
|
||||
|
||||
public String getMaxRam() {
|
||||
return this.maxRam;
|
||||
}
|
||||
|
||||
public static String[] getRamList() {
|
||||
return ramList;
|
||||
}
|
||||
|
||||
public String getVanillaVersion() {
|
||||
return this.vanillaVersion;
|
||||
}
|
||||
|
||||
public String getSnapshotVersion() {
|
||||
return this.snapshotVersion;
|
||||
}
|
||||
|
||||
public String getSpongeVanillaVersion() {
|
||||
return this.spongeVanillaVersion;
|
||||
}
|
||||
|
||||
public String getBungeeVersion() {
|
||||
return this.bungeeVersion;
|
||||
}
|
||||
|
||||
public ArrayList<String> getPlayers() {
|
||||
return this.playerList;
|
||||
}
|
||||
|
||||
public void stopped() {
|
||||
process = null;
|
||||
writer = null;
|
||||
reader = null;
|
||||
started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A representation of the name of a jarfile.
|
||||
*/
|
||||
private String getType() {
|
||||
if (this.type.getName().equals("Custom")) {
|
||||
return this.serverVersion;
|
||||
} else {
|
||||
return this.type.getName() + this.serverVersion + ".jar";
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void toggle(boolean value) {
|
||||
this.enabled = value;
|
||||
}
|
||||
|
||||
public boolean hasPlayer(String name) {
|
||||
for (String player : this.playerList) {
|
||||
if (player.equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addPlayer(String name) {
|
||||
this.playerList.add(name);
|
||||
Profile.getGUI().addPlayer(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a player with the selected name from the playerlist.
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
Profile.getGUI().removePlayer(name);
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public void setType(ServerType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setMaxRam(String ram) {
|
||||
this.maxRam = ram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the server's server version to a valid version, or ignores the request.
|
||||
*
|
||||
* @param serverVersion Version number.
|
||||
*/
|
||||
public void setServerVersion(String serverVersion) throws IllegalArgumentException {
|
||||
if (this.type.getName().equals("Custom")) {
|
||||
this.serverVersion = serverVersion;
|
||||
} else {
|
||||
String[] versions = this.type.getVersions();
|
||||
for (String version : versions) {
|
||||
if (version.equals(serverVersion)) {
|
||||
this.serverVersion = serverVersion;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid server version.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to stop all enabled servers.
|
||||
*
|
||||
* @throws IOException If a writer's process is already closed but not null.
|
||||
*/
|
||||
public static void stop() throws IOException {
|
||||
for (Collection collection : Profile.getCurrent().getCollections()) {
|
||||
Server server = collection.getServer();
|
||||
if (server.writer != null) {
|
||||
if (server.type.getName().equals("Bungee")) {
|
||||
server.writer.write("end\n");
|
||||
} else {
|
||||
server.writer.write("stop\n");
|
||||
}
|
||||
server.writer.flush();
|
||||
server.writer = null;
|
||||
server.started = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all enabled servers with their settings.
|
||||
*/
|
||||
public static void startServers() {
|
||||
Profile.getGUI().setStatus("Starting servers");
|
||||
for (Collection collection : Profile.getCurrent().getCollections()) {
|
||||
if (!collection.getServer().run()) {
|
||||
Profile.getGUI().setStatus("An error occurred. Start aborted");
|
||||
try {
|
||||
Server.stop();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Profile.getGUI().updateRunning(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the Minecraft server.
|
||||
*/
|
||||
private boolean run() {
|
||||
if (this.enabled) {
|
||||
this.started = true;
|
||||
if (!Profile.getCurrent().getDownloadJars()) {
|
||||
try {
|
||||
Profile.getGUI().setStatus("Downloading jar...");
|
||||
this.downloadJar();
|
||||
Profile.getGUI().setStatus("File downloaded");
|
||||
} catch (FileNotFoundException e) {
|
||||
Profile.getGUI().setStatus("Error: Jar file not found");
|
||||
e.printStackTrace();
|
||||
this.started = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
try {
|
||||
Profile.getGUI().setStatus("Delaying startup");
|
||||
TimeUnit.SECONDS.sleep(Profile.getCurrent().getDelayStartup());
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
this.started = false;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
ProcessBuilder builder;
|
||||
String serverPath;
|
||||
if (Profile.getCurrent().getDownloadJars() && !type.getName().equals("Custom")) {
|
||||
serverPath = jarDir + this.getType();
|
||||
} else {
|
||||
serverPath = this.path + File.separator + this.getType();
|
||||
}
|
||||
builder = new ProcessBuilder(
|
||||
"java",
|
||||
"-Xmx" + this.maxRam,
|
||||
"-Xms512M",
|
||||
"-Djline.terminal=jline.UnsupportedTerminal",
|
||||
"-Dcom.mojang.eula.agree=true",
|
||||
"-jar",
|
||||
serverPath,
|
||||
"nogui"
|
||||
);
|
||||
builder.directory(new File(this.path));
|
||||
builder.redirectErrorStream(true);
|
||||
this.process = builder.start();
|
||||
this.writer = new BufferedWriter(new OutputStreamWriter(this.process.getOutputStream()));
|
||||
this.reader = new BufferedReader (new InputStreamReader(this.process.getInputStream()));
|
||||
Profile.getGUI().setStatus("Servers are running");
|
||||
this.started = true;
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
Profile.getGUI().setStatus("Could not start server");
|
||||
this.started = false;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
this.started = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all available output from the server process.
|
||||
*
|
||||
* @return The server output
|
||||
* @throws IOException If reading from the reader fails
|
||||
*/
|
||||
public String read() throws IOException {
|
||||
String line;
|
||||
StringBuilder text = new StringBuilder();
|
||||
while (reader.ready() && (line = reader.readLine()) != null) {
|
||||
text.append(line).append("\n");
|
||||
}
|
||||
return text.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
AdvancedServerType type;
|
||||
File file = new File(this.path + File.separator + this.getType());
|
||||
Path filePath = Paths.get(this.path + File.separator + this.getType());
|
||||
String versionText, newestVersion, url = this.type.getDownloadURL(), name = this.type.getName(), ver = this.serverVersion;
|
||||
switch (this.type.getName()) {
|
||||
case "Custom":
|
||||
if (!file.isFile()) {
|
||||
throw new FileNotFoundException("Specified custom jar was not found.");
|
||||
}
|
||||
break;
|
||||
case "Spigot":
|
||||
case "Craftbukkit":
|
||||
case "MCPCplus":
|
||||
if (!(file.isFile() || downloadFile(url + name + ver + ".jar", filePath))) {
|
||||
throw new FileNotFoundException("Jar file could not be downloaded.");
|
||||
}
|
||||
break;
|
||||
case "Vanilla":
|
||||
case "Snapshot":
|
||||
type = (AdvancedServerType) this.type;
|
||||
if (this.serverVersion.equals("Latest")) {
|
||||
try {
|
||||
versionText = readFile(type.getVersionURL());
|
||||
} catch (IOException e) {
|
||||
throw new FileNotFoundException("Version file could not be downloaded.");
|
||||
}
|
||||
newestVersion = stringBetween(versionText, type.getSrcStart(), type.getSrcEnd());
|
||||
if (!file.isFile() || !newestVersion.equals(this.getVersion(name))) {
|
||||
this.setVersion(name, newestVersion);
|
||||
if (!downloadFile(url + newestVersion + type.getDownloadURLPart() + newestVersion + ".jar", filePath)) {
|
||||
throw new FileNotFoundException("Jar file could not be downloaded.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!(file.isFile() || downloadFile(url + ver + type.getDownloadURLPart() + ver + ".jar", filePath))) {
|
||||
throw new FileNotFoundException("Jar file could not be downloaded.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "SpongeVanilla":
|
||||
type = (AdvancedServerType) this.type;
|
||||
try {
|
||||
versionText = readFile(type.getVersionURL() + this.serverVersion);
|
||||
} catch (IOException e) {
|
||||
throw new FileNotFoundException("Version file could not be downloaded.");
|
||||
}
|
||||
newestVersion = stringBetween(versionText, type.getSrcStart(), type.getSrcEnd());
|
||||
if (!file.isFile() || !newestVersion.equals(this.getVersion(name))) {
|
||||
this.setVersion(name, newestVersion);
|
||||
if (!downloadFile(url + newestVersion + type.getDownloadURLPart() + newestVersion + ".jar", filePath)) {
|
||||
throw new FileNotFoundException("Jar file could not be downloaded.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "Bungee":
|
||||
type = (AdvancedServerType) this.type;
|
||||
try {
|
||||
versionText = readFile(type.getVersionURL());
|
||||
} catch (IOException e) {
|
||||
throw new FileNotFoundException("Version file could not be downloaded.");
|
||||
}
|
||||
newestVersion = stringBetween(versionText, type.getSrcStart(), type.getSrcEnd());
|
||||
if (!file.isFile() || !newestVersion.equals(this.getVersion(name))) {
|
||||
this.setVersion(name, newestVersion);
|
||||
if (!downloadFile(url, filePath)) {
|
||||
throw new FileNotFoundException("Jar file could not be downloaded.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current version of a type
|
||||
*
|
||||
* @param type The version type
|
||||
* @return The version string
|
||||
*/
|
||||
private String getVersion(String type) {
|
||||
switch (type) {
|
||||
case "Vanilla":
|
||||
return this.vanillaVersion;
|
||||
case "Snapshot":
|
||||
return this.snapshotVersion;
|
||||
case "SpongeVanilla":
|
||||
return this.spongeVanillaVersion;
|
||||
case "Bungee":
|
||||
return this.bungeeVersion;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a server type's last downloaded version.
|
||||
*
|
||||
* @param type The version type
|
||||
* @param version The version string
|
||||
*/
|
||||
private void setVersion(String type, String version) {
|
||||
if (!type.equals("")) {
|
||||
switch (type) {
|
||||
case "Vanilla":
|
||||
this.vanillaVersion = version;
|
||||
break;
|
||||
case "Snapshot":
|
||||
this.snapshotVersion = version;
|
||||
break;
|
||||
case "SpongeVanilla":
|
||||
this.spongeVanillaVersion = version;
|
||||
break;
|
||||
case "Bungee":
|
||||
this.bungeeVersion = version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a command to this server through its writer.
|
||||
*
|
||||
* @param command Command to send to the server
|
||||
* @throws IOException If write fails
|
||||
*/
|
||||
public void sendCommand(String command) throws IOException {
|
||||
if (this.process != null && this.writer != null) {
|
||||
this.writer.write(command + "\n");
|
||||
this.writer.flush();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
package net.knarcraft.serverlauncher.server;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* Contains the bare minimum to be a functional server type.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ServerType {
|
||||
private final String name;
|
||||
private final String[] versions;
|
||||
private final String downloadURL;
|
||||
private static final ArrayList<ServerType> serverTypes = new ArrayList<>();
|
||||
|
||||
ServerType(String name, String[] versions, String downloadURL) {
|
||||
this.name = name;
|
||||
this.versions = versions;
|
||||
this.downloadURL = downloadURL;
|
||||
serverTypes.add(this);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String[] getVersions() {
|
||||
return this.versions;
|
||||
}
|
||||
|
||||
public String getDownloadURL() {
|
||||
return this.downloadURL;
|
||||
}
|
||||
|
||||
public static ArrayList<ServerType> getServerTypes() {
|
||||
return serverTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all server types' names.
|
||||
*
|
||||
* @return A list of strings
|
||||
*/
|
||||
public static String[] getTypeNames() {
|
||||
ArrayList<ServerType> types = ServerType.getServerTypes();
|
||||
String[] serverTypes = new String[types.size()];
|
||||
for (int i = 0; i < types.size(); i++) {
|
||||
serverTypes[i] = types.get(i).getName();
|
||||
}
|
||||
return serverTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a server type by name.
|
||||
*
|
||||
* @param name Then name of the server type
|
||||
* @return A ServerType
|
||||
*/
|
||||
public static ServerType getByName(String name) {
|
||||
for (ServerType serverType : serverTypes) {
|
||||
if (serverType.getName().equals(name)) {
|
||||
return serverType;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads valid server types and version from a file, and creates their objects.
|
||||
*
|
||||
* @throws ConfigurationException if anything goes wrong.
|
||||
*/
|
||||
public static void loadServerTypes() throws ConfigurationException {
|
||||
if (serverTypes.isEmpty()) {
|
||||
Scanner file;
|
||||
try {
|
||||
file = new Scanner(new File("config/servertypes.csv"));
|
||||
} catch (FileNotFoundException e) {
|
||||
file = new Scanner(ServerType.class.getResourceAsStream("/config/servertypes.csv"));
|
||||
}
|
||||
|
||||
while (file.hasNextLine()) {
|
||||
String[] str = file.nextLine().split(";", -1);
|
||||
int len = str.length;
|
||||
String[] ver;
|
||||
if (str[1].contains(",")) {
|
||||
ver = str[1].split(",", -1);
|
||||
} else {
|
||||
ver = new String[]{str[1]};
|
||||
}
|
||||
switch (len) {
|
||||
case 7:
|
||||
new AdvancedServerType(str[0], ver, str[2], str[3], str[4], str[5], str[6]);
|
||||
break;
|
||||
case 3:
|
||||
new ServerType(str[0], ver, str[2]);
|
||||
break;
|
||||
default:
|
||||
throw new ConfigurationException("Error: Configuration file invalid.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new ConfigurationException("Error: Configuration already loaded.");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
package net.knarcraft.serverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.serverlauncher.profile.Profile;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.DefaultCaret;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static javax.swing.text.DefaultCaret.ALWAYS_UPDATE;
|
||||
|
||||
/**
|
||||
* Acts as a single writable/readable tab
|
||||
* Has a box for user input, and a textArea for server output.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class Console implements ActionListener, KeyListener {
|
||||
private final JTextField textInput;
|
||||
private final JTextArea textOutput;
|
||||
private final String name;
|
||||
private final JPanel panel;
|
||||
private final ArrayList<String> commands = new ArrayList<>();
|
||||
private int commandIndex;
|
||||
|
||||
Console(JTabbedPane tab, String name) {
|
||||
this.name = name;
|
||||
panel = new JPanel();
|
||||
tab.addTab(name, null, panel, null);
|
||||
panel.setLayout(new BorderLayout(0, 0));
|
||||
textInput = new JTextField();
|
||||
panel.add(textInput, BorderLayout.SOUTH);
|
||||
textInput.setColumns(10);
|
||||
textInput.addActionListener(this);
|
||||
textOutput = new JTextArea();
|
||||
JScrollPane scroll = new JScrollPane(textOutput);
|
||||
panel.add(scroll, BorderLayout.CENTER);
|
||||
textOutput.setEditable(false);
|
||||
DefaultCaret caret = (DefaultCaret) textOutput.getCaret();
|
||||
caret.setUpdatePolicy(ALWAYS_UPDATE);
|
||||
textOutput.setLineWrap(true);
|
||||
textInput.addKeyListener(this);
|
||||
}
|
||||
|
||||
public JPanel getPanel() {
|
||||
return this.panel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a string to the textArea.
|
||||
*
|
||||
* @param text The text to print
|
||||
*/
|
||||
public void output(String text) {
|
||||
this.textOutput.setText(this.textOutput.getText() + "\n" + text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (e.getSource() == textInput) { //Sends the command from the input to the server with the same name.
|
||||
java.lang.String text = textInput.getText();
|
||||
Profile.getCurrent().sendCommand(this.name, text);
|
||||
commands.add(text);
|
||||
if (commands.size() > 25) {
|
||||
commands.remove(0);
|
||||
}
|
||||
commandIndex = commands.size();
|
||||
textInput.setText("");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_UP) {
|
||||
if (commands.size() > 0 && commandIndex > 0) {
|
||||
textInput.setText(commands.get(--commandIndex));
|
||||
}
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {
|
||||
}
|
||||
}
|
@ -1,908 +0,0 @@
|
||||
package net.knarcraft.serverlauncher.userinterface;
|
||||
|
||||
import net.knarcraft.serverlauncher.Main;
|
||||
import net.knarcraft.serverlauncher.profile.Collection;
|
||||
import net.knarcraft.serverlauncher.server.Server;
|
||||
import net.knarcraft.serverlauncher.profile.Profile;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
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;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import static java.awt.Frame.NORMAL;
|
||||
import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE;
|
||||
|
||||
/**
|
||||
* Generates a GUI.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class GUI implements ActionListener {
|
||||
|
||||
private JFrame frame;
|
||||
private JTabbedPane tabbedPane;
|
||||
private JTabbedPane serversPane;
|
||||
//Menu
|
||||
private JCheckBoxMenuItem chckbxmntmRunInBackground, chckbxmntmDelayStartup, chckbxmntmDownloadJars; //Options
|
||||
private JMenuItem mntmErrors, mntmSetup, mntmManualUpdate; //Help
|
||||
private JMenuItem mntmRunInBackground, mntmDelayStartup, mntmDownloadJars; //Info/options
|
||||
private JMenuItem mntmAbout, mntmStory; //Info/about
|
||||
//Basic controls
|
||||
private JButton btnStartServer, btnStopServer, addServer, backup, addProfile, delProfile;
|
||||
private JComboBox<String> profiles;
|
||||
private final JLabel lblStatuslabel = new JLabel("Servers are stopped");
|
||||
//Server controls
|
||||
private JComboBox<String> targetServer;
|
||||
private JComboBox<String> targetPlayer;
|
||||
private JButton btnKick, btnBan, btnOp, btnDeop, btnCustomCommand, btnSaveserver, btnReload, btnServerConsoles;
|
||||
private JTextField customCommand;
|
||||
//Text
|
||||
private String setupText;
|
||||
private String runInBackgroundText;
|
||||
private String delayStartupText;
|
||||
private String downloadJarsText;
|
||||
private String aboutText;
|
||||
|
||||
private final ArrayList<String> globalPlayers;
|
||||
private SystemTray tray;
|
||||
private TrayIcon trayIcon;
|
||||
|
||||
/**
|
||||
* Create the application window.
|
||||
*/
|
||||
public GUI() {
|
||||
initialize(440, 170);
|
||||
loadMessages();
|
||||
this.globalPlayers = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the application window with a preferred width and height.
|
||||
*
|
||||
* @param width The preferred width
|
||||
* @param height The preferred height
|
||||
*/
|
||||
public GUI(int width, int height) {
|
||||
initialize(width, height);
|
||||
loadMessages();
|
||||
this.globalPlayers = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pane used for server configurations
|
||||
*
|
||||
* @return A JTabbedPane
|
||||
*/
|
||||
public JTabbedPane getPane() {
|
||||
return this.serversPane;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text of the status label.
|
||||
*
|
||||
* @param text The new text
|
||||
*/
|
||||
public void setStatus(String text) {
|
||||
this.lblStatuslabel.setText(text);
|
||||
try (PrintWriter file = new PrintWriter(new FileWriter(Main.getAppDir() + File.separator + "latestrun.log", true))) {
|
||||
file.println(text);
|
||||
} catch (IOException e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a player to the global playerlist, and updates the players combo.
|
||||
*
|
||||
* @param name The name of the player to add
|
||||
*/
|
||||
public void addPlayer(String name) {
|
||||
this.globalPlayers.add(name);
|
||||
this.updatePlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a player from the global list of players.
|
||||
*
|
||||
* @param name The name of the player to remove.
|
||||
*/
|
||||
public void removePlayer(String name) {
|
||||
for (int i = 0; i < this.globalPlayers.size(); i++) {
|
||||
if (this.globalPlayers.get(i).equals(name)) {
|
||||
this.globalPlayers.remove(i);
|
||||
}
|
||||
}
|
||||
this.updatePlayers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the profiles combo.
|
||||
*/
|
||||
public void updateProfiles() {
|
||||
this.profiles.removeAllItems();
|
||||
for (Profile profile : Profile.getProfiles()) {
|
||||
this.profiles.addItem(profile.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the size of the main JFrame
|
||||
*
|
||||
* @return The Dimension of the frame
|
||||
*/
|
||||
public Dimension getSize() {
|
||||
return frame.getContentPane().getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates GUI according to current profile settings.
|
||||
*/
|
||||
public void update() {
|
||||
serversPane.removeAll();
|
||||
for (Collection collection : Profile.getCurrent().getCollections()) {
|
||||
serversPane.addTab(collection.getName(), collection.getServerTab().getPanel());
|
||||
}
|
||||
chckbxmntmRunInBackground.setState(Profile.getCurrent().getRunInBackground());
|
||||
chckbxmntmDelayStartup.setState(Profile.getCurrent().getDelayStartup() > 0);
|
||||
chckbxmntmDownloadJars.setState(Profile.getCurrent().getDownloadJars());
|
||||
this.targetServer.removeAllItems();
|
||||
this.targetServer.addItem("All");
|
||||
for (Collection collection : Profile.getCurrent().getCollections()) {
|
||||
this.targetServer.addItem(collection.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the GUI,
|
||||
*/
|
||||
private void initialize(int width, int height) {
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (ClassNotFoundException |
|
||||
UnsupportedLookAndFeelException |
|
||||
InstantiationException |
|
||||
IllegalAccessException e
|
||||
) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
frame = new JFrame("Minecraft server launcher");
|
||||
frame.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
||||
frame.getContentPane().setPreferredSize(new Dimension(width, height));
|
||||
ImageIcon img;
|
||||
try {
|
||||
img = new ImageIcon(ImageIO.read(GUI.class.getResourceAsStream("/files/GUIIcon.png")));
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
img = new ImageIcon("files/GUIIcon.png");
|
||||
}
|
||||
frame.setIconImage(img.getImage());
|
||||
|
||||
JMenuBar menuBar = new JMenuBar();
|
||||
frame.setJMenuBar(menuBar);
|
||||
|
||||
JMenu mnOptions = new JMenu("Options");
|
||||
menuBar.add(mnOptions);
|
||||
|
||||
chckbxmntmRunInBackground = new JCheckBoxMenuItem("Run in background on exit");
|
||||
mnOptions.add(chckbxmntmRunInBackground);
|
||||
chckbxmntmRunInBackground.addActionListener(this);
|
||||
|
||||
chckbxmntmDelayStartup = new JCheckBoxMenuItem("Delay Startup");
|
||||
mnOptions.add(chckbxmntmDelayStartup);
|
||||
chckbxmntmDelayStartup.addActionListener(this);
|
||||
|
||||
chckbxmntmDownloadJars = new JCheckBoxMenuItem("Download jars");
|
||||
mnOptions.add(chckbxmntmDownloadJars);
|
||||
chckbxmntmDownloadJars.addActionListener(this);
|
||||
|
||||
JMenu mnHelp = new JMenu("Help");
|
||||
menuBar.add(mnHelp);
|
||||
|
||||
mntmErrors = new JMenuItem("Errors");
|
||||
mnHelp.add(mntmErrors);
|
||||
mntmErrors.addActionListener(this);
|
||||
|
||||
mntmSetup = new JMenuItem("Setup");
|
||||
mnHelp.add(mntmSetup);
|
||||
mntmSetup.addActionListener(this);
|
||||
|
||||
mntmManualUpdate = new JMenuItem("Manual update");
|
||||
mnHelp.add(mntmManualUpdate);
|
||||
mntmManualUpdate.addActionListener(this);
|
||||
|
||||
JMenu mnInfo = new JMenu("Info");
|
||||
menuBar.add(mnInfo);
|
||||
|
||||
JMenu mnOptionsInfo = new JMenu("Options");
|
||||
mnInfo.add(mnOptionsInfo);
|
||||
|
||||
mntmRunInBackground = new JMenuItem("Run in background on exit");
|
||||
mnOptionsInfo.add(mntmRunInBackground);
|
||||
mntmRunInBackground.addActionListener(this);
|
||||
|
||||
mntmDelayStartup = new JMenuItem("Delay Startup");
|
||||
mnOptionsInfo.add(mntmDelayStartup);
|
||||
mntmDelayStartup.addActionListener(this);
|
||||
|
||||
mntmDownloadJars = new JMenuItem("Download jars");
|
||||
mnOptionsInfo.add(mntmDownloadJars);
|
||||
mntmDownloadJars.addActionListener(this);
|
||||
|
||||
JMenu mnAbout = new JMenu("About");
|
||||
mnInfo.add(mnAbout);
|
||||
|
||||
mntmAbout = new JMenuItem("About");
|
||||
mnAbout.add(mntmAbout);
|
||||
mntmAbout.addActionListener(this);
|
||||
|
||||
mntmStory = new JMenuItem("Story");
|
||||
mnAbout.add(mntmStory);
|
||||
mntmStory.addActionListener(this);
|
||||
|
||||
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
|
||||
frame.getContentPane().add(tabbedPane);
|
||||
|
||||
JPanel panelBasic = new JPanel();
|
||||
tabbedPane.addTab("Control panel", null, panelBasic, null);
|
||||
SpringLayout sl_panel = new SpringLayout();
|
||||
panelBasic.setLayout(sl_panel);
|
||||
|
||||
JLabel lblBasicControls = new JLabel("Basic controls");
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, lblBasicControls, 10, SpringLayout.NORTH, panelBasic);
|
||||
panelBasic.add(lblBasicControls);
|
||||
|
||||
btnStartServer = new JButton("Start servers");
|
||||
sl_panel.putConstraint(SpringLayout.WEST, lblBasicControls, 0, SpringLayout.WEST, btnStartServer);
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, btnStartServer, 6, SpringLayout.SOUTH, lblBasicControls);
|
||||
sl_panel.putConstraint(SpringLayout.WEST, btnStartServer, 10, SpringLayout.WEST, panelBasic);
|
||||
panelBasic.add(btnStartServer);
|
||||
btnStartServer.addActionListener(this);
|
||||
|
||||
btnStopServer = new JButton("Stop servers");
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, btnStopServer, 0, SpringLayout.NORTH, btnStartServer);
|
||||
sl_panel.putConstraint(SpringLayout.WEST, btnStopServer, 6, SpringLayout.EAST, btnStartServer);
|
||||
panelBasic.add(btnStopServer);
|
||||
btnStopServer.addActionListener(this);
|
||||
|
||||
JLabel lblProfile = new JLabel("Profile");
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, lblProfile, 6, SpringLayout.SOUTH, btnStartServer);
|
||||
sl_panel.putConstraint(SpringLayout.WEST, lblProfile, 10, SpringLayout.WEST, panelBasic);
|
||||
panelBasic.add(lblProfile);
|
||||
|
||||
addProfile = new JButton("+");
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, addProfile, 6, SpringLayout.SOUTH, lblProfile);
|
||||
sl_panel.putConstraint(SpringLayout.WEST, addProfile, 10, SpringLayout.WEST, panelBasic);
|
||||
panelBasic.add(addProfile);
|
||||
addProfile.addActionListener(this);
|
||||
|
||||
delProfile = new JButton("-");
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, delProfile, 0, SpringLayout.NORTH, addProfile);
|
||||
sl_panel.putConstraint(SpringLayout.WEST, delProfile, 6, SpringLayout.EAST, addProfile);
|
||||
panelBasic.add(delProfile);
|
||||
delProfile.addActionListener(this);
|
||||
|
||||
profiles = new JComboBox<>();
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, profiles, 0, SpringLayout.NORTH, addProfile);
|
||||
sl_panel.putConstraint(SpringLayout.WEST, profiles, 6, SpringLayout.EAST, delProfile);
|
||||
sl_panel.putConstraint(SpringLayout.EAST, profiles, 124, SpringLayout.EAST, delProfile);
|
||||
panelBasic.add(profiles);
|
||||
profiles.addActionListener(this);
|
||||
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, lblStatuslabel, 6, SpringLayout.SOUTH, addProfile);
|
||||
sl_panel.putConstraint(SpringLayout.SOUTH, lblStatuslabel, -10, SpringLayout.SOUTH, panelBasic);
|
||||
sl_panel.putConstraint(SpringLayout.WEST, lblStatuslabel, 10, SpringLayout.WEST, panelBasic);
|
||||
sl_panel.putConstraint(SpringLayout.EAST, lblStatuslabel, -10, SpringLayout.EAST, panelBasic);
|
||||
panelBasic.add(lblStatuslabel);
|
||||
|
||||
addServer = new JButton("Add server");
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, addServer, 0, SpringLayout.NORTH, btnStartServer);
|
||||
sl_panel.putConstraint(SpringLayout.WEST, addServer, 6, SpringLayout.EAST, btnStopServer);
|
||||
panelBasic.add(addServer);
|
||||
addServer.addActionListener(this);
|
||||
|
||||
backup = new JButton("Backup");
|
||||
sl_panel.putConstraint(SpringLayout.NORTH, backup, 0, SpringLayout.NORTH, btnStartServer);
|
||||
sl_panel.putConstraint(SpringLayout.WEST, backup, 6, SpringLayout.EAST, addServer);
|
||||
panelBasic.add(backup);
|
||||
backup.addActionListener(this);
|
||||
|
||||
JPanel controlServers = new JPanel();
|
||||
tabbedPane.addTab("Control servers", null, controlServers, null);
|
||||
SpringLayout sl_panel_1 = new SpringLayout();
|
||||
controlServers.setLayout(sl_panel_1);
|
||||
|
||||
targetServer = new JComboBox<>();
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, targetServer, 10, SpringLayout.NORTH, controlServers);
|
||||
controlServers.add(targetServer);
|
||||
targetServer.addActionListener(this);
|
||||
|
||||
targetPlayer = new JComboBox<>();
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, targetPlayer, 6, SpringLayout.SOUTH, targetServer);
|
||||
targetPlayer.setEditable(true);
|
||||
controlServers.add(targetPlayer);
|
||||
|
||||
btnKick = new JButton("Kick");
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, btnKick, 10, SpringLayout.NORTH, controlServers);
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, btnKick, 6, SpringLayout.EAST, targetServer);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, btnKick, 104, SpringLayout.WEST, btnKick);
|
||||
sl_panel_1.putConstraint(SpringLayout.SOUTH, targetServer, 0, SpringLayout.SOUTH, btnKick);
|
||||
controlServers.add(btnKick);
|
||||
btnKick.addActionListener(this);
|
||||
|
||||
btnBan = new JButton("Ban");
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, btnBan, 6, SpringLayout.SOUTH, btnKick);
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, btnBan, 6, SpringLayout.EAST, targetPlayer);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, btnBan, 104, SpringLayout.WEST, btnBan);
|
||||
sl_panel_1.putConstraint(SpringLayout.SOUTH, targetPlayer, 0, SpringLayout.SOUTH, btnBan);
|
||||
controlServers.add(btnBan);
|
||||
btnBan.addActionListener(this);
|
||||
|
||||
btnOp = new JButton("OP");
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, btnOp, 10, SpringLayout.NORTH, controlServers);
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, btnOp, 6, SpringLayout.EAST, btnKick);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, btnOp, -10, SpringLayout.EAST, controlServers);
|
||||
controlServers.add(btnOp);
|
||||
btnOp.addActionListener(this);
|
||||
|
||||
btnDeop = new JButton("DEOP");
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, btnDeop, 6, SpringLayout.EAST, btnBan);
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, btnDeop, 5, SpringLayout.SOUTH, btnOp);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, btnDeop, -10, SpringLayout.EAST, controlServers);
|
||||
controlServers.add(btnDeop);
|
||||
btnDeop.addActionListener(this);
|
||||
|
||||
JLabel lblTargetServer = new JLabel("Target server");
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, targetServer, 6, SpringLayout.EAST, lblTargetServer);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, targetServer, 121, SpringLayout.EAST, lblTargetServer);
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, lblTargetServer, 10, SpringLayout.NORTH, controlServers);
|
||||
sl_panel_1.putConstraint(SpringLayout.SOUTH, lblTargetServer, 0, SpringLayout.SOUTH, targetServer);
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, lblTargetServer, 10, SpringLayout.WEST, controlServers);
|
||||
controlServers.add(lblTargetServer);
|
||||
|
||||
JLabel lblTargetPlayer = new JLabel("Target player");
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, targetPlayer, 7, SpringLayout.EAST, lblTargetPlayer);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, targetPlayer, 122, SpringLayout.EAST, lblTargetPlayer);
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, lblTargetPlayer, 6, SpringLayout.SOUTH, lblTargetServer);
|
||||
sl_panel_1.putConstraint(SpringLayout.SOUTH, lblTargetPlayer, 0, SpringLayout.SOUTH, targetPlayer);
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, lblTargetPlayer, 0, SpringLayout.WEST, lblTargetServer);
|
||||
controlServers.add(lblTargetPlayer);
|
||||
|
||||
btnCustomCommand = new JButton("Custom command");
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, btnCustomCommand, 250, SpringLayout.WEST, controlServers);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, btnCustomCommand, 0, SpringLayout.EAST, btnOp);
|
||||
controlServers.add(btnCustomCommand);
|
||||
btnCustomCommand.addActionListener(this);
|
||||
frame.getRootPane().setDefaultButton(btnCustomCommand);
|
||||
|
||||
customCommand = new JTextField();
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, customCommand, 10, SpringLayout.WEST, controlServers);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, customCommand, -6, SpringLayout.WEST, btnCustomCommand);
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, btnCustomCommand, 0, SpringLayout.NORTH, customCommand);
|
||||
sl_panel_1.putConstraint(SpringLayout.SOUTH, customCommand, 0, SpringLayout.SOUTH, btnCustomCommand);
|
||||
controlServers.add(customCommand);
|
||||
customCommand.setColumns(10);
|
||||
|
||||
btnSaveserver = new JButton("Save server");
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, customCommand, 6, SpringLayout.SOUTH, btnSaveserver);
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, btnSaveserver, 6, SpringLayout.SOUTH, btnBan);
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, btnSaveserver, 0, SpringLayout.WEST, btnKick);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, btnSaveserver, 104, SpringLayout.WEST, btnKick);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, btnSaveserver, 104, SpringLayout.WEST, btnKick);
|
||||
controlServers.add(btnSaveserver);
|
||||
btnSaveserver.addActionListener(this);
|
||||
|
||||
btnReload = new JButton("Reload");
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, btnReload, 6, SpringLayout.SOUTH, btnDeop);
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, btnReload, 0, SpringLayout.WEST, btnDeop);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, btnReload, 0, SpringLayout.EAST, btnOp);
|
||||
controlServers.add(btnReload);
|
||||
btnReload.addActionListener(this);
|
||||
|
||||
btnServerConsoles = new JButton("View server consoles");
|
||||
sl_panel_1.putConstraint(SpringLayout.NORTH, btnServerConsoles, 0, SpringLayout.NORTH, btnSaveserver);
|
||||
sl_panel_1.putConstraint(SpringLayout.WEST, btnServerConsoles, 0, SpringLayout.WEST, lblTargetServer);
|
||||
sl_panel_1.putConstraint(SpringLayout.EAST, btnServerConsoles, 0, SpringLayout.EAST, targetServer);
|
||||
controlServers.add(btnServerConsoles);
|
||||
btnServerConsoles.addActionListener(this);
|
||||
|
||||
JPanel panel_2 = new JPanel();
|
||||
tabbedPane.addTab("Servers", null, panel_2, null);
|
||||
SpringLayout sl_panel_2 = new SpringLayout();
|
||||
panel_2.setLayout(sl_panel_2);
|
||||
|
||||
JTabbedPane tabbedPane_1 = new JTabbedPane(JTabbedPane.TOP);
|
||||
sl_panel_2.putConstraint(SpringLayout.NORTH, tabbedPane_1, 0, SpringLayout.NORTH, panel_2);
|
||||
sl_panel_2.putConstraint(SpringLayout.WEST, tabbedPane_1, 0, SpringLayout.WEST, panel_2);
|
||||
sl_panel_2.putConstraint(SpringLayout.SOUTH, tabbedPane_1, 0, SpringLayout.SOUTH, panel_2);
|
||||
sl_panel_2.putConstraint(SpringLayout.EAST, tabbedPane_1, 0, SpringLayout.EAST, panel_2);
|
||||
panel_2.add(tabbedPane_1);
|
||||
|
||||
this.serversPane = tabbedPane_1;
|
||||
tabbedPane_1.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
|
||||
|
||||
frame.validate();
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
tray();
|
||||
updateRunning(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the system tray if available.
|
||||
*/
|
||||
private void tray() {
|
||||
if (SystemTray.isSupported()) {
|
||||
tray = SystemTray.getSystemTray();
|
||||
Image trayImage = Toolkit.getDefaultToolkit().getImage("files/GUIIcon.png");
|
||||
PopupMenu popup = new PopupMenu();
|
||||
trayIcon = new TrayIcon(trayImage, "Minecraft Server Launcher", popup);
|
||||
trayIcon.setImageAutoSize(true);
|
||||
ActionListener exitListener= e -> {
|
||||
stop();
|
||||
try {
|
||||
Profile.getCurrent().save();
|
||||
} catch (FileNotFoundException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
System.exit(0);
|
||||
};
|
||||
|
||||
MenuItem restoreItem = new MenuItem("Restore");
|
||||
popup.add(restoreItem);
|
||||
restoreItem.addActionListener(e -> {
|
||||
frame.setExtendedState(NORMAL);
|
||||
tray.remove(trayIcon);
|
||||
frame.setVisible(true);
|
||||
});
|
||||
MenuItem exitItem = new MenuItem("Exit");
|
||||
exitItem.addActionListener(exitListener);
|
||||
popup.add(exitItem);
|
||||
frame.addWindowStateListener(e -> {
|
||||
if (e.getNewState() == NORMAL) {
|
||||
tray.remove(trayIcon);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
if (Profile.getCurrent().getRunInBackground() && SystemTray.isSupported()) {
|
||||
try {
|
||||
tray.add(trayIcon);
|
||||
frame.setVisible(false);
|
||||
} catch (AWTException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
stop();
|
||||
try {
|
||||
Profile.getCurrent().save();
|
||||
} catch (FileNotFoundException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
trayIcon.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if(e.getClickCount() >= 1 && e.getButton() == MouseEvent.BUTTON1){
|
||||
frame.setExtendedState(NORMAL);
|
||||
tray.remove(trayIcon);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e) {
|
||||
try {
|
||||
Profile.getCurrent().save();
|
||||
} catch (FileNotFoundException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
stop();
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hides the gui to the tray,
|
||||
*/
|
||||
public void hide() {
|
||||
frame.setVisible(false);
|
||||
try {
|
||||
tray.add(trayIcon);
|
||||
} catch (AWTException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String selectedServerValue = null, selectedPlayerValue = null;
|
||||
Object selectedServer = targetServer.getSelectedItem();
|
||||
if (selectedServer != null) {
|
||||
selectedServerValue = selectedServer.toString();
|
||||
}
|
||||
Object selectedPlayer = targetPlayer.getSelectedItem();
|
||||
if (selectedPlayer != null) {
|
||||
selectedPlayerValue = selectedPlayer.toString();
|
||||
}
|
||||
if (e.getSource() == chckbxmntmRunInBackground) {
|
||||
background();
|
||||
} else if (e.getSource() == chckbxmntmDelayStartup) {
|
||||
delay();
|
||||
} else if (e.getSource() == chckbxmntmDownloadJars) {
|
||||
downloadJars();
|
||||
} else if (e.getSource() == mntmErrors) {
|
||||
goToURL("https://knarcraft.net/Bungeeminecraftserverlauncher/Info/");
|
||||
} else if (e.getSource() == mntmSetup) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
setupText,
|
||||
"Setup",
|
||||
JOptionPane.INFORMATION_MESSAGE
|
||||
);
|
||||
} else if (e.getSource() == mntmManualUpdate) {
|
||||
goToURL("https://knarcraft.net/Downloads/Bungeeminecraftserverlauncher/");
|
||||
} else if (e.getSource() == mntmRunInBackground) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
runInBackgroundText,
|
||||
"Run in background",
|
||||
JOptionPane.INFORMATION_MESSAGE
|
||||
);
|
||||
} else if (e.getSource() == mntmDelayStartup) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
delayStartupText,
|
||||
"Delay startup",
|
||||
JOptionPane.INFORMATION_MESSAGE
|
||||
);
|
||||
} else if (e.getSource() == mntmDownloadJars) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
downloadJarsText,
|
||||
"Download jars",
|
||||
JOptionPane.INFORMATION_MESSAGE
|
||||
);
|
||||
} else if (e.getSource() == mntmAbout) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
aboutText,
|
||||
"About",
|
||||
JOptionPane.INFORMATION_MESSAGE
|
||||
);
|
||||
} else if (e.getSource() == mntmStory) {
|
||||
goToURL("https://knarcraft.net/Bungeeminecraftserverlauncher/Story/");
|
||||
} else if (e.getSource() == btnStartServer) {
|
||||
try {
|
||||
Profile.getCurrent().save();
|
||||
} catch (FileNotFoundException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
Executors.newSingleThreadExecutor().execute(Server::startServers);
|
||||
} else if (e.getSource() == btnStopServer) {
|
||||
stop();
|
||||
} else if (e.getSource() == addServer) {
|
||||
String serverName = JOptionPane.showInputDialog("Name of server: ");
|
||||
Profile.getCurrent().addCollection(serverName);
|
||||
this.update();
|
||||
Profile.getCurrent().updateConsoles();
|
||||
} else if (e.getSource() == backup) {
|
||||
backup();
|
||||
} else if (e.getSource() == addProfile) {
|
||||
Profile.addProfile(JOptionPane.showInputDialog("Profile name: "));
|
||||
updateProfiles();
|
||||
} else if (e.getSource() == delProfile) {
|
||||
Object selected = profiles.getSelectedItem();
|
||||
if (selected != null) {
|
||||
Profile.removeProfile(selected.toString());
|
||||
updateProfiles();
|
||||
}
|
||||
} else if (e.getSource() == profiles) {
|
||||
try {
|
||||
changeProfile();
|
||||
} catch (FileNotFoundException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
} else if (e.getSource() == btnKick) {
|
||||
if (selectedServerValue != null && selectedPlayerValue != null) {
|
||||
Profile.getCurrent().sendCommand(selectedServerValue, "kick " + selectedPlayerValue);
|
||||
}
|
||||
} else if (e.getSource() == btnBan) {
|
||||
if (selectedServerValue != null && selectedPlayerValue != null) {
|
||||
Profile.getCurrent().sendCommand(selectedServerValue, "ban " + selectedPlayerValue);
|
||||
}
|
||||
} else if (e.getSource() == btnOp) {
|
||||
if (selectedServerValue != null && selectedPlayerValue != null) {
|
||||
Profile.getCurrent().sendCommand(selectedServerValue, "op " + selectedPlayerValue);
|
||||
}
|
||||
} else if (e.getSource() == btnDeop) {
|
||||
if (selectedServerValue != null && selectedPlayerValue != null) {
|
||||
Profile.getCurrent().sendCommand(selectedServerValue, "deop " + selectedPlayerValue);
|
||||
}
|
||||
} else if (e.getSource() == btnCustomCommand) {
|
||||
if (selectedServerValue != null) {
|
||||
Profile.getCurrent().sendCommand(selectedServerValue, customCommand.getText());
|
||||
customCommand.setText("");
|
||||
}
|
||||
} else if (e.getSource() == btnSaveserver) {
|
||||
if (selectedServerValue != null) {
|
||||
Profile.getCurrent().sendCommand(selectedServerValue, "save-all");
|
||||
}
|
||||
} else if (e.getSource() == btnReload) {
|
||||
if (selectedServerValue != null) {
|
||||
Profile.getCurrent().sendCommand(selectedServerValue, "reload");
|
||||
}
|
||||
} else if (e.getSource() == btnServerConsoles) {
|
||||
ServerConsoles.show();
|
||||
} else if (e.getSource() == targetServer) {
|
||||
updatePlayers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the GUI components to block a user from doing illegal actions.
|
||||
*
|
||||
* @param running Are the servers currently running?
|
||||
*/
|
||||
public void updateRunning(boolean running) {
|
||||
boolean stopped = !running; //Most gui is only enabled when the server is stopped rather than running.
|
||||
profiles.setEnabled(stopped);
|
||||
addProfile.setEnabled(stopped);
|
||||
delProfile.setEnabled(stopped);
|
||||
btnStartServer.setEnabled(stopped);
|
||||
addServer.setEnabled(stopped);
|
||||
tabbedPane.setEnabledAt(2, stopped);
|
||||
btnStopServer.setEnabled(running);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the previous profile and loads data from the new profile.
|
||||
*/
|
||||
private void changeProfile() throws FileNotFoundException {
|
||||
Profile.getCurrent().save();
|
||||
Object current = this.profiles.getSelectedItem();
|
||||
if (current != null) {
|
||||
Profile.setCurrent(current.toString());
|
||||
}
|
||||
this.update();
|
||||
Profile.getCurrent().updateConsoles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops all servers
|
||||
*/
|
||||
private void stop() {
|
||||
try {
|
||||
setStatus("Servers are stopping...");
|
||||
Server.stop();
|
||||
} catch (IOException e1) {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"Could not stop server.",
|
||||
"Error",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks the user for a delay if checked, and sets the value to the current profile.
|
||||
*/
|
||||
private void delay() {
|
||||
Object selected = profiles.getSelectedItem();
|
||||
if (selected != null) {
|
||||
Profile profile = Profile.getProfile(selected.toString());
|
||||
if (chckbxmntmDelayStartup.isSelected()) {
|
||||
Objects.requireNonNull(profile).setDelayStartup(
|
||||
Integer.parseInt(JOptionPane.showInputDialog("Seconds to delay: "))
|
||||
);
|
||||
} else {
|
||||
Objects.requireNonNull(profile).setDelayStartup(0);
|
||||
}
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"No profile selected",
|
||||
"Error",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the runInBackground setting to the current profile.
|
||||
*/
|
||||
private void background() {
|
||||
Object selected = profiles.getSelectedItem();
|
||||
if (selected != null) {
|
||||
Profile profile = Profile.getProfile(selected.toString());
|
||||
Objects.requireNonNull(profile).setRunInBackground(chckbxmntmRunInBackground.isSelected());
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"No profile selected",
|
||||
"Error",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the downloadJars setting to the current profile.
|
||||
*/
|
||||
private void downloadJars() {
|
||||
Object selected = profiles.getSelectedItem();
|
||||
if (selected != null) {
|
||||
Profile profile = Profile.getProfile(selected.toString());
|
||||
Objects.requireNonNull(profile).setDownloadJars(chckbxmntmDownloadJars.isSelected());
|
||||
} else {
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"No profile selected",
|
||||
"Error",
|
||||
JOptionPane.ERROR_MESSAGE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
copyFolder(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,
|
||||
*/
|
||||
private void updatePlayers() {
|
||||
String selectedServerValue;
|
||||
Object selectedServer = targetServer.getSelectedItem();
|
||||
if (selectedServer != null) {
|
||||
targetPlayer.removeAllItems();
|
||||
selectedServerValue = selectedServer.toString();
|
||||
if (selectedServerValue.equals("All")) {
|
||||
for (String player : this.globalPlayers) {
|
||||
targetPlayer.addItem(player);
|
||||
}
|
||||
} else {
|
||||
for (String player : Profile.getCurrent().getCollection(selectedServerValue).getServer().getPlayers()) {
|
||||
targetPlayer.addItem(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private void loadMessages() {
|
||||
Scanner file;
|
||||
try {
|
||||
file = new Scanner(new File("config/menumsg.csv"));
|
||||
} catch (FileNotFoundException e) {
|
||||
file = new Scanner(GUI.class.getResourceAsStream("/config/menumsg.csv"));
|
||||
}
|
||||
while (file.hasNextLine()) {
|
||||
String[] line = file.nextLine().split("=");
|
||||
String content = line[1].replaceAll("_BREAK_", System.getProperty("line.separator"));
|
||||
switch (line[0]) {
|
||||
case "setup":
|
||||
setupText = content;
|
||||
break;
|
||||
case "runinbk":
|
||||
runInBackgroundText = content;
|
||||
break;
|
||||
case "delaystartup":
|
||||
delayStartupText = content;
|
||||
break;
|
||||
case "downloadjars":
|
||||
downloadJarsText = content;
|
||||
break;
|
||||
case "about":
|
||||
aboutText = content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package net.knarcraft.serverlauncher.userinterface;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JTabbedPane;
|
||||
import java.awt.BorderLayout;
|
||||
|
||||
/**
|
||||
* A parent window for server consoles.
|
||||
* Should be toggled with the "View server consoles" button.
|
||||
* Keeps track of all consoles.
|
||||
*
|
||||
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
||||
* @version 1.0.0
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ServerConsoles {
|
||||
private static JFrame frame;
|
||||
private static JTabbedPane consolesTab;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public static Console addTab(String name) {
|
||||
return new Console(consolesTab, name);
|
||||
}
|
||||
|
||||
public static void show() {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
public static JTabbedPane getTab() {
|
||||
return consolesTab;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.profile.ServerLauncherController;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.FakeGUI;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.MethodOrderer;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class JarBuilderTest {
|
||||
|
||||
private static JarBuilder jarBuilder;
|
||||
private static String targetDirectory;
|
||||
private static String jarDirectory;
|
||||
|
||||
@BeforeAll
|
||||
public static void preSetUp() {
|
||||
try {
|
||||
ServerLauncherController.getInstance().loadState(true);
|
||||
} catch (ConfigurationException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
targetDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator +
|
||||
"BuildTools" + File.separator;
|
||||
jarDirectory = Main.getApplicationWorkDirectory() + File.separator + "files" + File.separator +
|
||||
"testjars" + File.separator;
|
||||
jarBuilder = new JarBuilder(targetDirectory, jarDirectory, new FakeGUI());
|
||||
removeBuildToolsFiles();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDown() {
|
||||
removeBuildToolsFiles();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
public void buildLatestSpigotJarTest() {
|
||||
File spigotFile = new File(jarDirectory + "SpigotLatest.jar");
|
||||
if (spigotFile.exists() && !spigotFile.delete()) {
|
||||
throw new IllegalArgumentException("Unable to remove existing spigot .jar");
|
||||
}
|
||||
jarBuilder.buildSpigotJar();
|
||||
assertTrue(spigotFile.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
public void buildLatestBukkitJarTest() {
|
||||
File bukkitFile = new File(jarDirectory + "BukkitLatest.jar");
|
||||
if (bukkitFile.exists() && !bukkitFile.delete()) {
|
||||
throw new IllegalArgumentException("Unable to remove existing bukkit .jar");
|
||||
}
|
||||
jarBuilder.buildBukkitJar();
|
||||
assertTrue(new File(jarDirectory + "BukkitLatest.jar").exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
public void downloadLatestBuildToolsJarTest() {
|
||||
jarBuilder.downloadBuildTools();
|
||||
assertTrue(new File(targetDirectory + "BuildTools.jar").exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
public void getLatestBuildToolsVersionTest() {
|
||||
try {
|
||||
String latestVersion = jarBuilder.getLatestBuildToolsVersion();
|
||||
assertNotEquals("", latestVersion);
|
||||
int newVersion = Integer.parseInt(latestVersion);
|
||||
assertNotEquals(newVersion, 0);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes build tools files
|
||||
*/
|
||||
private static void removeBuildToolsFiles() {
|
||||
File target = new File(targetDirectory);
|
||||
if (!target.exists() && !target.mkdirs()) {
|
||||
throw new IllegalArgumentException("Unable to create the test files directory");
|
||||
}
|
||||
CommonFunctions.removeFilesRecursively(target);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
public class ServerTest {
|
||||
|
||||
@Test
|
||||
public void fromStringTest() throws ConfigurationException {
|
||||
Server server = ServerHandler.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());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ServerTypeHandlerTest {
|
||||
|
||||
@Test
|
||||
public void getTypeNamesTest() throws ConfigurationException {
|
||||
String[] serverTypeNames = ServerTypeHandler.getTypeNames();
|
||||
|
||||
String[] typeNames = new String[serverTypeNames.length];
|
||||
int index = 0;
|
||||
for (ServerType serverType : ServerTypeHandler.getServerTypes()) {
|
||||
typeNames[index++] = serverType.getName();
|
||||
}
|
||||
assertEquals(Arrays.asList(typeNames), Arrays.asList(serverTypeNames));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTypeFromNameTest() throws ConfigurationException {
|
||||
ServerType targetType = null;
|
||||
for (ServerType serverType : ServerTypeHandler.getServerTypes()) {
|
||||
if (serverType.getName().equals("Vanilla")) {
|
||||
targetType = serverType;
|
||||
}
|
||||
}
|
||||
ServerType typeFromName = ServerTypeHandler.getByName("Vanilla");
|
||||
assertEquals(targetType, typeFromName);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package net.knarcraft.minecraftserverlauncher.server;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.createAllFolders;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ServerVersionContainerTest {
|
||||
|
||||
private final String filesDirectory = Main.getApplicationWorkDirectory() + File.separator + "files";
|
||||
private final String versionFile = filesDirectory + File.separator + "versions.csv";
|
||||
private ServerVersionContainer serverVersionContainer;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
try {
|
||||
createAllFolders();
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
File versionFileFile = new File(versionFile);
|
||||
if (versionFileFile.exists() && !versionFileFile.delete()) {
|
||||
throw new IllegalArgumentException("Unable to remove old version file.");
|
||||
}
|
||||
serverVersionContainer = ServerVersionContainer.getInstance();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringTest() {
|
||||
serverVersionContainer.reset();
|
||||
System.out.println(serverVersionContainer.toString());
|
||||
assertEquals("vanillaVersion;null\nsnapshotVersion;null\nbungeeVersion;null\nwaterfallVersions;\n" +
|
||||
"travertineVersions;\npaperVersions;\nspongeVanillaVersions;\nspongeForgeVersions;\ndownloadedBuildToolsVersion;null",
|
||||
serverVersionContainer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveStateTest() throws IOException {
|
||||
serverVersionContainer.saveState();
|
||||
BufferedReader reader = CommonFunctions.getFileReader(versionFile);
|
||||
String savedData = CommonFunctions.readBufferedReader(reader);
|
||||
reader.close();
|
||||
assertEquals(serverVersionContainer.toString(), savedData);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package net.knarcraft.minecraftserverlauncher.userinterface;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
public class FakeGUI extends MessageHandler implements GUI {
|
||||
|
||||
private final BufferedWriter writer;
|
||||
|
||||
/***
|
||||
* Initializes a new fake gui
|
||||
*/
|
||||
public FakeGUI() {
|
||||
super(true);
|
||||
this.writer = new BufferedWriter(new OutputStreamWriter(System.out));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(String message) {
|
||||
try {
|
||||
writer.write(message);
|
||||
writer.newLine();
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File askForDirectory(String prompt) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package net.knarcraft.minecraftserverlauncher.utility;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class CommonFunctionsTest {
|
||||
|
||||
@Test
|
||||
public void stringBetweenTest() {
|
||||
String substring = stringBetween("fish'nchips", "f", "'");
|
||||
assertEquals("ish", substring);
|
||||
substring = stringBetween("something", "whale", "fish");
|
||||
assertEquals("", substring);
|
||||
substring = stringBetween("something", "so", "fish");
|
||||
assertEquals("", substring);
|
||||
substring = stringBetween("something", "asd", "ing");
|
||||
assertEquals("", substring);
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
package net.knarcraft.minecraftserverlauncher.utility;
|
||||
|
||||
import net.knarcraft.minecraftserverlauncher.Main;
|
||||
import net.knarcraft.minecraftserverlauncher.server.ServerTypeHandler;
|
||||
import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType;
|
||||
import net.knarcraft.minecraftserverlauncher.userinterface.FakeGUI;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
public class JarDownloaderTest {
|
||||
private static String targetDirectory;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() {
|
||||
String filesDirectory = Main.getApplicationWorkDirectory() + File.separator + "files";
|
||||
try {
|
||||
CommonFunctions.createFolder(new File(filesDirectory + File.separator + "testjars"));
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
targetDirectory = filesDirectory + File.separator + "testjars" + File.separator;
|
||||
removeDownloadedFiles();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void cleanUp() {
|
||||
removeDownloadedFiles();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void downloadJarsTest() throws IOException {
|
||||
JarDownloader downloader = new JarDownloader(new FakeGUI(), targetDirectory);
|
||||
downloader.downloadJars();
|
||||
}
|
||||
|
||||
/*@Test
|
||||
public void spongeVanillaDownloadTest() throws IOException, ConfigurationException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("SpongeVanilla"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void spongeForgeDownloadTest() throws IOException, ConfigurationException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("SpongeForge"));
|
||||
}*/
|
||||
|
||||
@Test
|
||||
public void spigotDownloadTest() throws ConfigurationException, IOException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("Spigot"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mcpcPlusDownloadTest() throws ConfigurationException, IOException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("MCPCplus"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void craftBukkitDownloadTest() throws ConfigurationException, IOException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("Bukkit"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void paperDownloadTest() throws ConfigurationException, IOException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("Paper"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bungeeDownloadTest() throws ConfigurationException, IOException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("Bungee"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void waterfallDownloadTest() throws ConfigurationException, IOException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("Waterfall"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void travertineDownloadTest() throws ConfigurationException, IOException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("Travertine"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vanillaDownloadTest() throws ConfigurationException, IOException {
|
||||
singleDownloadTest(ServerTypeHandler.getByName("Vanilla"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads all .jar files for a single server type and asserts it works
|
||||
*
|
||||
* @param serverType <p>The server type to test</p>
|
||||
* @throws IOException <p>If unable to download any of the .jar files</p>
|
||||
*/
|
||||
private void singleDownloadTest(ServerType serverType) throws IOException {
|
||||
assertNotNull(serverType);
|
||||
for (String serverVersion : serverType.getVersions()) {
|
||||
if ((serverType.getName().equals("Spigot") || serverType.getName().equals("Bukkit"))
|
||||
&& serverVersion.equals("Latest")) {
|
||||
continue;
|
||||
}
|
||||
System.out.println("Downloading " + serverType.getName() + serverVersion + ".jar");
|
||||
serverType.downloadJar(targetDirectory, serverVersion);
|
||||
assertTrue(new File(targetDirectory + serverType.getName() + serverVersion + ".jar").exists());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes downloaded test jars
|
||||
*/
|
||||
private static void removeDownloadedFiles() {
|
||||
File target = new File(targetDirectory);
|
||||
if (!target.exists() && !target.mkdirs()) {
|
||||
throw new IllegalArgumentException("Unable to create the test files directory");
|
||||
}
|
||||
CommonFunctions.removeFilesRecursively(target);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package net.knarcraft.minecraftserverlauncher.utility;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class UpdaterTest {
|
||||
|
||||
@Test
|
||||
public void isVersionHigherTest() {
|
||||
assertTrue(Updater.isVersionHigher("1.1.1", "1.1.2"));
|
||||
assertFalse(Updater.isVersionHigher("1.1.1", "1.1.1"));
|
||||
assertFalse(Updater.isVersionHigher("1.1.1", "1.1.0"));
|
||||
assertTrue(Updater.isVersionHigher("1.1.1", "1.2.1"));
|
||||
assertFalse(Updater.isVersionHigher("1.2.1", "1.1.6"));
|
||||
assertTrue(Updater.isVersionHigher("1.2.1", "2.1.6"));
|
||||
assertTrue(Updater.isVersionHigher("1.2.1", "2.0.0"));
|
||||
assertTrue(Updater.isVersionHigher("1.2", "1.2.1"));
|
||||
assertTrue(Updater.isVersionHigher("1.1.2", "1.2"));
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
import net.knarcraft.serverlauncher.profile.Profile;
|
||||
import net.knarcraft.serverlauncher.server.ServerType;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.io.IOException;
|
||||
|
||||
public class DownloadTests {
|
||||
@Test
|
||||
public void downloadJarsTest() throws IOException, ConfigurationException {
|
||||
// Will currently always fail since knarcraft.net is down.
|
||||
ServerType.loadServerTypes();
|
||||
Profile.downloadJars();
|
||||
}
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
import net.knarcraft.serverlauncher.profile.Profile;
|
||||
import net.knarcraft.serverlauncher.server.ServerType;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.naming.ConfigurationException;
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import static net.knarcraft.serverlauncher.Shared.stringBetween;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class Tests {
|
||||
@Test
|
||||
public void loadServerVersions() throws ConfigurationException { //Make sure the server versions file has correct syntax
|
||||
ServerType.loadServerTypes();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveProfile() throws FileNotFoundException { //Make sure we can write profiles to disk
|
||||
Profile.addProfile("Test");
|
||||
Profile.getCurrent().save();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringBetweenTest() { //Make sure stringBetween is not creating exceptions
|
||||
String substring = stringBetween("fish'nchips", "f", "'");
|
||||
assertEquals("ish", substring);
|
||||
substring = stringBetween("something", "whale", "fish");
|
||||
assertEquals("", substring);
|
||||
substring = stringBetween("something", "so", "fish");
|
||||
assertEquals("", substring);
|
||||
substring = stringBetween("something", "asd", "ing");
|
||||
assertEquals("", substring);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user