package net.knarcraft.serverlauncher; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; 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 javax.swing.*; import java.awt.*; import java.io.*; import java.net.URISyntaxException; import java.util.Scanner; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; 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; //Java 8 required. /** * A software for managing Minecraft servers. * * @author Kristian Knarvik * @version 1.0.0 * @since 1.0.0 */ public class Main { private static String appDir; private static boolean running = false; private static final String updateChannel = "alpha"; private static final String updateURL = "https://api.knarcraft.net/minecraftserverlauncher"; public static void main(String[] args) throws IOException { checkForUpdate(); try (PrintWriter file = new PrintWriter(Main.getAppDir() + File.separator + "latestrun.log")) { file.print(""); } catch (IOException e ) { e.printStackTrace(); } 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(); } }); } /** * 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); } } 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; } /** * 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(); file.close(); 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 ); } } }