diff --git a/src/net/knarcraft/serverlauncher/Main.java b/src/net/knarcraft/serverlauncher/Main.java index fb15930..75c7942 100644 --- a/src/net/knarcraft/serverlauncher/Main.java +++ b/src/net/knarcraft/serverlauncher/Main.java @@ -28,6 +28,7 @@ import static net.knarcraft.serverlauncher.Shared.stringBetween; public class Main { @SuppressWarnings("CanBeFinal") public static String appDir; + private static boolean running = false; static { try { @@ -63,34 +64,45 @@ public class Main { } /** - * Reads from server processes, and writes the output to our custom consoles. + * Reads from server processes, and writes the output to consoles. */ private static void updateConsoles() { - 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); + 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(); } - } catch (IOException e) { - e.printStackTrace(); - } - if (!server.getProcess().isAlive()) { - server.stopped(); } } - } - if (!serversRunning()) { - Profile.getGUI().stopped(); - Profile.getGUI().setStatus("Servers are stopped"); - } else { - Profile.getGUI().running(); + 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()) { @@ -105,38 +117,44 @@ public class Main { * 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. + * @param server The server which sent the text. */ private static void updatePlayerList(String text, Server server) { if (!server.getTypeName().equals("Bungee")) { - String joinedPlayer = stringBetween(text, "[Server thread/INFO]: ", " joined the game"); - if (!joinedPlayer.equals("")) { + String joinedPlayer = getPlayer(text, true); + String leftPlayer = getPlayer(text, false); + if (!joinedPlayer.equals("")) { if (!server.hasPlayer(joinedPlayer)) { server.addPlayer(joinedPlayer); } - } else { - joinedPlayer = stringBetween(text, "UUID of player ", " is "); - if (!joinedPlayer.equals("")) { - if (!server.hasPlayer(joinedPlayer)) { - server.addPlayer(joinedPlayer); - } - } - } - if (joinedPlayer.equals("")) { - String leftPlayer = stringBetween(text, "INFO]: ", " lost connection"); - if (!leftPlayer.equals("")) { - if (server.hasPlayer(leftPlayer)) { - server.removePlayer(leftPlayer); - } - } else { - leftPlayer = stringBetween(text, "[Server thread/INFO]: ", " left the game"); - if (!leftPlayer.equals("")) { - if (server.hasPlayer(leftPlayer)) { - server.removePlayer(leftPlayer); - } - } + } 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; + } } \ No newline at end of file diff --git a/src/net/knarcraft/serverlauncher/Shared.java b/src/net/knarcraft/serverlauncher/Shared.java index 88e5ffc..e6327c3 100644 --- a/src/net/knarcraft/serverlauncher/Shared.java +++ b/src/net/knarcraft/serverlauncher/Shared.java @@ -8,6 +8,13 @@ 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 + * @version 0.0.0.1 + * @since 0.0.0.1 + */ public class Shared { /** * Finds a substring between two substrings in a string. @@ -27,7 +34,7 @@ public class Shared { /** * Reads a file from a website. - * This is used to find the newest version of the software. + * 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 @@ -40,9 +47,9 @@ public class Shared { /** * 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 + * @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 { diff --git a/src/net/knarcraft/serverlauncher/profile/Profile.java b/src/net/knarcraft/serverlauncher/profile/Profile.java index e266cf1..4e80d3c 100644 --- a/src/net/knarcraft/serverlauncher/profile/Profile.java +++ b/src/net/knarcraft/serverlauncher/profile/Profile.java @@ -441,10 +441,6 @@ public class Profile { gui.update(); gui.updateProfiles(); current.updateConsoles(); - if (current.runInBackground) { - gui.hide(); - Executors.newSingleThreadExecutor().execute(Server::startServers); - } if (current.downloadJars) { Executors.newSingleThreadExecutor().execute(() -> { try { @@ -454,6 +450,10 @@ public class Profile { } }); } + if (current.runInBackground) { + Executors.newSingleThreadExecutor().execute(Server::startServers); + gui.hide(); + } } private static Profile parseProfile(String[] profileData) { diff --git a/src/net/knarcraft/serverlauncher/server/Server.java b/src/net/knarcraft/serverlauncher/server/Server.java index dee0ffc..0cd3ee6 100644 --- a/src/net/knarcraft/serverlauncher/server/Server.java +++ b/src/net/knarcraft/serverlauncher/server/Server.java @@ -177,6 +177,11 @@ public class Server { 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))) { @@ -221,7 +226,7 @@ public class Server { /** * Tries to stop all enabled servers. * - * @throws IOException If a writer's process is already closed. + * @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()) { @@ -252,7 +257,7 @@ public class Server { } catch (IOException e) { e.printStackTrace(); } - Profile.getGUI().stopped(); + Profile.getGUI().updateRunning(false); return; } } @@ -286,36 +291,27 @@ public class Server { } try { ProcessBuilder builder; + String serverPath; if (Profile.getCurrent().getDownloadJars() && !type.getName().equals("Custom")) { - builder = new ProcessBuilder( - "java", - "-Xmx" + this.maxRam, - "-Xms512M", - "-Djline.terminal=jline.UnsupportedTerminal", - "-Dcom.mojang.eula.agree=true", - "-jar", - "\"" + jarDir + this.getType() + "\"", - "nogui" - ); - } else { - builder = new ProcessBuilder( - "java", - "-Xmx" + this.maxRam, - "-Xms512M", - "-Djline.terminal=jline.UnsupportedTerminal", - "-Dcom.mojang.eula.agree=true", - "-jar", - "\"" + this.path + File.separator + this.getType() + "\"", - "nogui" - ); + 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(); - OutputStream stdin = this.process.getOutputStream(); - this.writer = new BufferedWriter(new OutputStreamWriter(stdin)); - InputStream stdout = this.process.getInputStream(); - this.reader = new BufferedReader (new InputStreamReader(stdout)); + 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; @@ -330,6 +326,12 @@ public class Server { } } + /** + * 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(); diff --git a/src/net/knarcraft/serverlauncher/userinterface/Console.java b/src/net/knarcraft/serverlauncher/userinterface/Console.java index 2fc5128..932beb7 100644 --- a/src/net/knarcraft/serverlauncher/userinterface/Console.java +++ b/src/net/knarcraft/serverlauncher/userinterface/Console.java @@ -52,6 +52,11 @@ public class Console implements ActionListener, KeyListener { 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); } diff --git a/src/net/knarcraft/serverlauncher/userinterface/GUI.java b/src/net/knarcraft/serverlauncher/userinterface/GUI.java index c06a8a3..798b514 100644 --- a/src/net/knarcraft/serverlauncher/userinterface/GUI.java +++ b/src/net/knarcraft/serverlauncher/userinterface/GUI.java @@ -29,6 +29,8 @@ import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE; 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 @@ -51,13 +53,9 @@ public class GUI implements ActionListener { private String aboutText; private final ArrayList globalPlayers; - - private JTabbedPane serversPane; - private SystemTray tray; private TrayIcon trayIcon; - /** * Create the application window. */ @@ -67,25 +65,51 @@ public class GUI implements ActionListener { 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); } + /** + * 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)) { @@ -95,6 +119,9 @@ public class GUI implements ActionListener { this.updatePlayers(); } + /** + * Updates the profiles combo. + */ public void updateProfiles() { this.profiles.removeAllItems(); for (Profile profile : Profile.getProfiles()) { @@ -102,12 +129,17 @@ public class GUI implements ActionListener { } } + /** + * 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 settings. + * Updates GUI according to current profile settings. */ public void update() { serversPane.removeAll(); @@ -211,7 +243,7 @@ public class GUI implements ActionListener { mnAbout.add(mntmStory); mntmStory.addActionListener(this); - JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP); + tabbedPane = new JTabbedPane(JTabbedPane.TOP); frame.getContentPane().add(tabbedPane); JPanel panelBasic = new JPanel(); @@ -396,6 +428,7 @@ public class GUI implements ActionListener { frame.pack(); frame.setVisible(true); tray(); + updateRunning(false); } /** @@ -620,18 +653,20 @@ public class GUI implements ActionListener { } } - public void running() { - profiles.setEnabled(false); - addProfile.setEnabled(false); - delProfile.setEnabled(false); - btnStartServer.setEnabled(false); - } - - public void stopped() { - profiles.setEnabled(true); - addProfile.setEnabled(true); - delProfile.setEnabled(true); - btnStartServer.setEnabled(true); + /** + * 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); } /** @@ -652,9 +687,8 @@ public class GUI implements ActionListener { */ private void stop() { try { - setStatus("Servers are stopping"); + setStatus("Servers are stopping..."); Server.stop(); - setStatus("Servers are stopped"); } catch (IOException e1) { JOptionPane.showMessageDialog( null, @@ -758,6 +792,7 @@ public class GUI implements ActionListener { } } } + this.setStatus("Backup finished"); } /** @@ -845,11 +880,11 @@ public class GUI implements ActionListener { } in.close(); out.close(); - this.setStatus("File copied from " + src + " to " + dest); + this.setStatus("Copied file " + src); } else { if(!dest.exists()){ if (dest.mkdir()) { - this.setStatus("Directory copied from " + src + " to " + dest); + this.setStatus("Copied directory " + src); } else { return; } diff --git a/src/net/knarcraft/serverlauncher/userinterface/ServerConsoles.java b/src/net/knarcraft/serverlauncher/userinterface/ServerConsoles.java index 0183043..ec89687 100644 --- a/src/net/knarcraft/serverlauncher/userinterface/ServerConsoles.java +++ b/src/net/knarcraft/serverlauncher/userinterface/ServerConsoles.java @@ -21,7 +21,6 @@ public class 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); } diff --git a/src/net/knarcraft/serverlauncher/userinterface/ServerTab.java b/src/net/knarcraft/serverlauncher/userinterface/ServerTab.java index 1bbfba7..63b59cc 100644 --- a/src/net/knarcraft/serverlauncher/userinterface/ServerTab.java +++ b/src/net/knarcraft/serverlauncher/userinterface/ServerTab.java @@ -24,6 +24,15 @@ public class ServerTab implements ActionListener { private final JPanel panel; private final String name; + /** + * Updates the server tab components according to the received parameters. + * + * @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 + */ public void setData(String path, boolean enabled, String typeName, String serverVersion, String maxRam) { this.directory.setText(path); this.chckbxEnabled.setSelected(enabled); @@ -144,6 +153,11 @@ public class ServerTab implements ActionListener { } } + /** + * Gets the selected version from the serverVersion combo + * + * @return The combo value, or defaults to "Latest" on null + */ public String getVersion() { Object selected = this.serverVersions.getSelectedItem(); if (selected != null) { @@ -153,6 +167,11 @@ public class ServerTab implements ActionListener { } } + /** + * Checks if the server is enabled + * + * @return True if the checkbox is checked. False otherwise. + */ public boolean enabled() { return this.chckbxEnabled.isSelected(); } @@ -168,12 +187,19 @@ public class ServerTab implements ActionListener { } } + /** + * Removes the collection containing this ServerTab, and updates everything necessary. + */ private void remove() { - Profile.getCurrent().removeCollection(name); + 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. + */ private void browse() { JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(new java.io.File("/")); @@ -185,6 +211,9 @@ public class ServerTab implements ActionListener { } } + /** + * Updates the versions combo according to the value of the server type combo. + */ private void serverTypes() { serverVersions.removeAllItems(); String selectedserverTypes = null;