2018-02-02 22:02:57 +01:00
|
|
|
package net.knarcraft.serverlauncher;
|
|
|
|
|
2018-11-07 17:40:39 +01:00
|
|
|
import com.google.gson.JsonArray;
|
|
|
|
import com.google.gson.JsonElement;
|
|
|
|
import com.google.gson.JsonObject;
|
|
|
|
import com.google.gson.JsonParser;
|
2018-01-31 21:24:54 +01:00
|
|
|
import net.knarcraft.serverlauncher.profile.Collection;
|
2018-01-28 19:06:50 +01:00
|
|
|
import net.knarcraft.serverlauncher.profile.Profile;
|
2018-02-02 22:02:57 +01:00
|
|
|
import net.knarcraft.serverlauncher.server.Server;
|
2018-01-29 20:14:17 +01:00
|
|
|
import net.knarcraft.serverlauncher.server.ServerType;
|
2018-01-30 19:35:42 +01:00
|
|
|
import net.knarcraft.serverlauncher.userinterface.ServerConsoles;
|
2018-01-26 20:26:16 +01:00
|
|
|
|
2018-01-25 17:34:45 +01:00
|
|
|
import javax.naming.ConfigurationException;
|
2018-11-07 17:40:39 +01:00
|
|
|
import javax.swing.*;
|
2018-01-27 23:34:02 +01:00
|
|
|
import java.awt.*;
|
2018-02-17 22:04:06 +01:00
|
|
|
import java.io.*;
|
2018-02-13 12:21:39 +01:00
|
|
|
import java.net.URISyntaxException;
|
2018-11-07 17:40:39 +01:00
|
|
|
import java.util.Scanner;
|
2018-01-30 00:44:03 +01:00
|
|
|
import java.util.concurrent.Executors;
|
|
|
|
import java.util.concurrent.ScheduledExecutorService;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
2018-02-17 22:04:06 +01:00
|
|
|
|
2018-11-07 17:40:39 +01:00
|
|
|
import static net.knarcraft.serverlauncher.Shared.downloadFile;
|
|
|
|
import static net.knarcraft.serverlauncher.Shared.readFile;
|
2018-02-17 22:04:06 +01:00
|
|
|
import static net.knarcraft.serverlauncher.Shared.stringBetween;
|
2018-01-29 20:14:17 +01:00
|
|
|
//Java 8 required.
|
2018-01-24 12:18:06 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* A software for managing Minecraft servers.
|
2018-01-25 21:17:02 +01:00
|
|
|
*
|
2018-02-22 14:12:42 +01:00
|
|
|
* @author Kristian Knarvik <kristian.knarvik@knett.no>
|
|
|
|
* @version 1.0.0
|
|
|
|
* @since 1.0.0
|
2018-01-24 12:18:06 +01:00
|
|
|
*/
|
2018-01-26 23:15:19 +01:00
|
|
|
|
2018-02-02 22:02:57 +01:00
|
|
|
public class Main {
|
2018-02-23 21:38:42 +01:00
|
|
|
private static String appDir;
|
2018-02-22 11:49:12 +01:00
|
|
|
private static boolean running = false;
|
2018-11-07 17:40:39 +01:00
|
|
|
private static final String updateChannel = "alpha";
|
|
|
|
private static final String updateURL = "https://api.knarcraft.net/minecraftserverlauncher";
|
2018-02-02 22:02:57 +01:00
|
|
|
|
2018-11-07 17:40:39 +01:00
|
|
|
public static void main(String[] args) throws IOException {
|
|
|
|
checkForUpdate();
|
2018-02-23 21:38:42 +01:00
|
|
|
try (PrintWriter file = new PrintWriter(Main.getAppDir() + File.separator + "latestrun.log")) {
|
|
|
|
file.print("");
|
|
|
|
} catch (IOException e ) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2018-11-07 17:40:39 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
});
|
2018-02-13 12:21:39 +01:00
|
|
|
}
|
|
|
|
|
2018-11-07 17:40:39 +01:00
|
|
|
/**
|
|
|
|
* Loads all server types, so that they are ready for use
|
|
|
|
*/
|
|
|
|
private static void setup() {
|
|
|
|
try {
|
|
|
|
ServerType.loadServerTypes();
|
|
|
|
} catch (ConfigurationException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
System.exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves the directory the .jar file is running from
|
|
|
|
*
|
|
|
|
* @return A string path
|
|
|
|
*/
|
|
|
|
public static String getAppDir() {
|
|
|
|
if (appDir == null) {
|
|
|
|
try {
|
|
|
|
appDir = String.valueOf(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()).getParentFile());
|
|
|
|
} catch (URISyntaxException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
System.exit(1);
|
|
|
|
}
|
|
|
|
}
|
2018-02-23 21:38:42 +01:00
|
|
|
return appDir;
|
|
|
|
}
|
|
|
|
|
2018-02-02 22:02:57 +01:00
|
|
|
/**
|
2018-02-22 11:49:12 +01:00
|
|
|
* Reads from server processes, and writes the output to consoles.
|
2018-02-02 22:02:57 +01:00
|
|
|
*/
|
2018-11-07 17:40:39 +01:00
|
|
|
private static void updateConsoles() {
|
|
|
|
try {
|
2018-02-22 11:49:12 +01:00
|
|
|
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();
|
2018-02-02 22:02:57 +01:00
|
|
|
}
|
2018-02-20 13:39:21 +01:00
|
|
|
}
|
2018-02-02 22:02:57 +01:00
|
|
|
}
|
2018-02-22 11:49:12 +01:00
|
|
|
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) {
|
2018-11-07 17:40:39 +01:00
|
|
|
e.printStackTrace();
|
2018-02-20 22:13:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-22 11:49:12 +01:00
|
|
|
/**
|
|
|
|
* Goes through all servers and looks for any running servers.
|
|
|
|
*
|
|
|
|
* @return Is at least one server running?
|
|
|
|
*/
|
2018-02-20 22:13:57 +01:00
|
|
|
private static boolean serversRunning() {
|
2018-11-07 17:40:39 +01:00
|
|
|
int num = 0;
|
2018-02-20 22:13:57 +01:00
|
|
|
for (Collection collection : Profile.getCurrent().getCollections()) {
|
|
|
|
if (collection.getServer().isStarted() || (collection.getServer().getProcess() != null && collection.getServer().getProcess().isAlive())) {
|
|
|
|
num++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return num > 0;
|
2018-02-02 22:02:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Looks for strings implying a player has joined or left, and updates the appropriate lists.
|
|
|
|
*
|
|
|
|
* @param text The text to search.
|
2018-02-22 11:49:12 +01:00
|
|
|
* @param server The server which sent the text.
|
2018-02-02 22:02:57 +01:00
|
|
|
*/
|
2018-11-07 17:40:39 +01:00
|
|
|
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("")) {
|
2018-02-02 22:02:57 +01:00
|
|
|
if (!server.hasPlayer(joinedPlayer)) {
|
|
|
|
server.addPlayer(joinedPlayer);
|
2018-02-01 13:46:51 +01:00
|
|
|
}
|
2018-02-22 11:49:12 +01:00
|
|
|
} else if (!leftPlayer.equals("")) {
|
|
|
|
if (server.hasPlayer(leftPlayer)) {
|
|
|
|
server.removePlayer(leftPlayer);
|
2018-02-01 13:16:25 +01:00
|
|
|
}
|
2018-02-01 13:46:51 +01:00
|
|
|
}
|
2018-02-22 11:49:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
2018-11-07 17:40:39 +01:00
|
|
|
if (joined) {
|
2018-02-22 11:49:12 +01:00
|
|
|
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");
|
2018-02-01 13:16:25 +01:00
|
|
|
}
|
|
|
|
}
|
2018-02-22 11:49:12 +01:00
|
|
|
return playerName;
|
2018-02-01 13:16:25 +01:00
|
|
|
}
|
2018-11-07 17:40:39 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if a newer version is available
|
|
|
|
*
|
|
|
|
* @throws IOException
|
|
|
|
*/
|
|
|
|
private static void checkForUpdate() throws IOException {
|
|
|
|
Scanner file;
|
|
|
|
try {
|
|
|
|
file = new Scanner(new File("config/currentversion.csv"));
|
|
|
|
} catch (FileNotFoundException e) {
|
|
|
|
file = new Scanner(Main.class.getResourceAsStream("/config/currentversion.csv"));
|
|
|
|
}
|
|
|
|
|
|
|
|
String oldType = file.nextLine();
|
|
|
|
String oldVer = file.nextLine();
|
|
|
|
|
|
|
|
String data = readFile(updateURL);
|
|
|
|
JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
|
|
|
|
String latest = jsonObject.getAsJsonObject("latest").get(updateChannel).getAsString();
|
|
|
|
|
|
|
|
if (!oldType.equals(updateChannel) || !oldVer.equals(latest)) {
|
|
|
|
String dir = getAppDir() + File.separator;
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (downloadFile(url, new File(dir + "update.jar").toPath())) {
|
|
|
|
doUpdate(dir);
|
|
|
|
} else {
|
|
|
|
JOptionPane.showMessageDialog(
|
|
|
|
null,
|
|
|
|
"An update is available, but could not be downloaded.",
|
|
|
|
"Update available",
|
|
|
|
JOptionPane.ERROR_MESSAGE
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void doUpdate(String dir) {
|
|
|
|
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) {
|
|
|
|
if (new File (dir + "Minecraft-Server-Launcher.jar").renameTo(new File(dir + "Old.jar"))) {
|
|
|
|
if (new File(dir + "update.jar").renameTo(new File (dir + "Minecraft-Server-Launcher.jar"))) {
|
|
|
|
if (new File(dir + "Old.jar").delete()) {
|
|
|
|
JOptionPane.showMessageDialog(
|
|
|
|
null,
|
|
|
|
"Update finished. Please run the software again.",
|
|
|
|
"Update complete",
|
|
|
|
JOptionPane.INFORMATION_MESSAGE
|
|
|
|
);
|
|
|
|
System.exit(0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!new File(dir + "Old.jar").renameTo(new File (dir + "Minecraft-Server-Launcher.jar"))) {
|
|
|
|
System.out.println("Shit");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
JOptionPane.showMessageDialog(
|
|
|
|
null,
|
|
|
|
"Could not replace the main .jar with the downloaded .jar.",
|
|
|
|
"Update failed",
|
|
|
|
JOptionPane.ERROR_MESSAGE
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-01-23 23:39:37 +01:00
|
|
|
}
|