diff --git a/src/main/java/net/knarcraft/minecraftserverlauncher/Main.java b/src/main/java/net/knarcraft/minecraftserverlauncher/Main.java index 101c326..60a588e 100644 --- a/src/main/java/net/knarcraft/minecraftserverlauncher/Main.java +++ b/src/main/java/net/knarcraft/minecraftserverlauncher/Main.java @@ -2,10 +2,8 @@ package net.knarcraft.minecraftserverlauncher; import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Controller; -import net.knarcraft.minecraftserverlauncher.server.Server; 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.*; @@ -16,8 +14,6 @@ import java.net.URISyntaxException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; - -import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween; //Java 8 required. /** @@ -29,12 +25,12 @@ import static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stri */ public class Main { - private static String applicationWorkDirectory; - private static boolean serversAreRunning = false; private static final String updateChannel = "beta"; private static final String updateURL = "https://api.knarcraft.net/minecraftserverlauncher"; - private static ServerLauncherGUI gui; private static final Controller controller = Controller.getInstance(); + private static String applicationWorkDirectory; + private static boolean serversAreRunning = false; + private static ServerLauncherGUI gui; public static void main(String[] args) throws IOException { Updater.checkForUpdate(updateURL, updateChannel); @@ -49,7 +45,7 @@ public class Main { controller.loadState(); gui = controller.getGUI(); ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor(); - exec.scheduleAtFixedRate(Main::updateConsoles, 10, 500, TimeUnit.MILLISECONDS); + exec.scheduleAtFixedRate(Main::updateServersRunningState, 10, 500, TimeUnit.MILLISECONDS); } catch (Exception e) { e.printStackTrace(); } @@ -83,98 +79,34 @@ public class Main { } /** - * Reads from server processes, and writes the output to consoles. + * Updates the software state if the servers' running state has changed */ - private static void updateConsoles() { - try { - for (Collection collection : controller.getCurrentProfile().getCollections()) { - Server server = collection.getServer(); - if (server.isEnabled() && server.getProcess() != null) { - try { - String readText = CommonFunctions.readBufferedReader(server.getReader()); - 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 && serversAreRunning) { - gui.updateGUIElementsWhenServersStartOrStop(false); - gui.setStatus("Servers are stopped"); - } else if (runningNew && !serversAreRunning) { - gui.updateGUIElementsWhenServersStartOrStop(true); - } - serversAreRunning = runningNew; - } catch (Exception e) { - e.printStackTrace(); + private static void updateServersRunningState() { + boolean runningNew = serversRunning(); + if (serversAreRunning && !runningNew) { + //Servers stopped running + 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. + * Goes through all servers and looks for any running servers * - * @return Is at least one server running? + * @return
Whether at least one server is running
*/ private static boolean serversRunning() { - int num = 0; + int serversRunning = 0; for (Collection collection : controller.getCurrentProfile().getCollections()) { if (collection.getServer().isStarted() || (collection.getServer().getProcess() != null && collection.getServer().getProcess().isAlive())) { - num++; + serversRunning++; } } - return num > 0; - } - - /** - * Looks for strings implying a player has joined or left, and updates the appropriate lists - * - * @param textThe text to search
- * @param serverThe server which sent the text
- */ - private static void updatePlayerList(String text, Server server) { - if (!server.getType().isProxy()) { - 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 textThe text string to search through
- * @param joinedWhether to search for a joining player
- * @returnThe 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; + return serversRunning > 0; } } \ No newline at end of file diff --git a/src/main/java/net/knarcraft/minecraftserverlauncher/server/Server.java b/src/main/java/net/knarcraft/minecraftserverlauncher/server/Server.java index dbc77d5..31c014c 100644 --- a/src/main/java/net/knarcraft/minecraftserverlauncher/server/Server.java +++ b/src/main/java/net/knarcraft/minecraftserverlauncher/server/Server.java @@ -4,6 +4,7 @@ import net.knarcraft.minecraftserverlauncher.Main; import net.knarcraft.minecraftserverlauncher.profile.Collection; import net.knarcraft.minecraftserverlauncher.profile.Controller; import net.knarcraft.minecraftserverlauncher.server.servertypes.ServerType; +import net.knarcraft.minecraftserverlauncher.utility.CommonFunctions; import javax.naming.ConfigurationException; import java.io.BufferedReader; @@ -15,8 +16,12 @@ 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 static net.knarcraft.minecraftserverlauncher.utility.CommonFunctions.stringBetween; + /** * Contains all necessary information to create, runServer and manage a Minecraft server. @@ -45,6 +50,7 @@ public class Server { private BufferedWriter writer; private BufferedReader reader; private boolean started; + private ScheduledExecutorService consoleOutputExecutor; /** * Initializes a new server with default values @@ -98,7 +104,7 @@ public class Server { * * @returnThe buffered reader used to read from this server
*/ - public BufferedReader getReader() { + private BufferedReader getReader() { return this.reader; } @@ -276,7 +282,8 @@ public class Server { /** * Checks whether this server is fully stopped */ - public void stopped() { + private void stopped() { + consoleOutputExecutor.shutdown(); process = null; writer = null; reader = null; @@ -307,7 +314,7 @@ public class Server { * @param nameThe name of the player to check
* @returnTrue if the player is connected
*/ - public boolean hasPlayer(String name) { + private boolean hasPlayer(String name) { for (String player : this.playerList) { if (player.equals(name)) { return true; @@ -321,7 +328,7 @@ public class Server { * * @param nameThe name of the player to add
*/ - public void addPlayer(String name) { + private void addPlayer(String name) { this.playerList.add(name); Main.getController().getGUI().getServerControlTab().addPlayer(name); } @@ -331,7 +338,7 @@ public class Server { * * @param nameThe name of the player to remove
*/ - public void removePlayer(String name) { + private void removePlayer(String name) { playerList.removeIf(player -> player.equals(name)); Main.getController().getGUI().getServerControlTab().removePlayer(name); } @@ -396,6 +403,79 @@ public class Server { 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 IOExceptionIf unable to read from the server's buffered reader
+ */ + 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()) { + stopped(); + } + } + + /** + * Looks for strings implying a player has joined or left, and updates the appropriate lists + * + * @param textThe text to search
+ */ + 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 textThe text string to search through
+ * @param joinedWhether to search for a joining player
+ * @returnThe name of a player, or an empty string
+ */ + private 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"); + } + if (playerName.equals("")) { + playerName = stringBetween(text, "INFO]: ", " left the game"); + } + } + return playerName; } /** diff --git a/src/main/java/net/knarcraft/minecraftserverlauncher/utility/CommonFunctions.java b/src/main/java/net/knarcraft/minecraftserverlauncher/utility/CommonFunctions.java index 801d18c..2df3127 100644 --- a/src/main/java/net/knarcraft/minecraftserverlauncher/utility/CommonFunctions.java +++ b/src/main/java/net/knarcraft/minecraftserverlauncher/utility/CommonFunctions.java @@ -195,10 +195,13 @@ public final class CommonFunctions { * @throws IOExceptionIf unable to read from the buffered reader
*/ public static String readBufferedReader(BufferedReader reader) throws IOException { - String line; + //String line; StringBuilder text = new StringBuilder(); - while (reader.ready() && (line = reader.readLine()) != null) { - text.append(line).append("\n"); + char[] readCharacters = new char[1000]; + while (reader.ready()) { + reader.read(readCharacters); + text.append(readCharacters); + readCharacters = new char[1000]; } return text.toString().trim(); }