diff --git a/README.md b/README.md index 8e29905..dd6d4e1 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,19 @@ For each input that does not have a custom key binding specified in `input.cfg`, ### General The entry point to the program is located in the `ClientMain.java` file. +### Developer Modes +The client has two special modes that are useful only to developers. + +**Fake mode**: Fake mode runs a local simulation without actually connecting a real Artemis server. Highly recommended for basic UI development, as you +will not need to continuously connect and reconnect to a real server, speeding cycle times. A lot of functionality is simulated (e.g. overheating a +system works), but some is not (damcon teams don't really work). You can put the client in this mode by passing the `--fake` command line flag. + +**Proxy mode**: Proxy mode allows a vanilla engineering client to connect to this client, which in turn connects to the server. With this setup, both clients will render the same data from the server, and either client can issue commands. This is a great way to check the behavior of the vanilla client +against this improved client without running afoul of the "one engineering console per ship" limit. You can put the client in this mode by passing +the `--proxy` command line flag. + +You can also supply the server hostname/IP and optionally the port as command line arguments. + ### IDE Configuration #### Dependencies diff --git a/src/com/brindyblitz/artemis/ClientMain.java b/src/com/brindyblitz/artemis/ClientMain.java index e4b11b3..13ff8c8 100644 --- a/src/com/brindyblitz/artemis/ClientMain.java +++ b/src/com/brindyblitz/artemis/ClientMain.java @@ -1,54 +1,81 @@ package com.brindyblitz.artemis; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import com.brindyblitz.artemis.engconsole.EngineeringConsoleManager; import com.brindyblitz.artemis.engconsole.FakeEngineeringConsoleManager; import com.brindyblitz.artemis.engconsole.RealEngineeringConsoleManager; import com.brindyblitz.artemis.engconsole.ui.UserInterfaceFrame; +import com.brindyblitz.artemis.protocol.WorldAwareRegularServer; import com.brindyblitz.artemis.protocol.WorldAwareRobustProxyListener; +import com.brindyblitz.artemis.protocol.WorldAwareServer; public class ClientMain { public static void main(String[] args) throws IOException { - String host = "localhost"; + String host = null; int port = 2010; - if (args.length > 2) { + List argList = new ArrayList<>(Arrays.asList(args)); + + boolean proxy = false; + boolean fake = false; + if (argList.contains("--proxy")) { + proxy = true; + argList.remove("--proxy"); + } + if (argList.contains("--fake")) { + fake = true; + argList.remove("--fake"); + } + + if (proxy && fake) { + System.err.println("Cannot use proxy and fake modes together"); + printUsage(); + return; + } + + if (!fake && (argList.size() > 2 || argList.size() < 1) || fake && argList.size() > 0) { System.err.println("Incorrect number of arguments (" + args.length + ")"); printUsage(); return; } - - if (args.length == 0) { - new ClientMain(); - } else { - - if (args.length >= 1) { - host = args[0]; - } - if (args.length == 2) { + + if (argList.size() > 0) { + host = argList.get(0); + if (argList.size() == 2) { try { - port = Integer.parseInt(args[1]); + port = Integer.parseInt(argList.get(1)); } catch (NumberFormatException e) { System.err.println("Unable to parse port: '" + args[1] + "'!"); printUsage(); return; } } - - new ClientMain(host, port); } + + new ClientMain(host, port, proxy, fake); } - public ClientMain() { - EngineeringConsoleManager engineeringConsoleManager = new FakeEngineeringConsoleManager(); - buildUIFrame(engineeringConsoleManager); - } - - public ClientMain(String host, int port) throws IOException { - WorldAwareRobustProxyListener worldAwareRobustProxyListener = new WorldAwareRobustProxyListener(host, port, port); - EngineeringConsoleManager engineeringConsoleManager = new RealEngineeringConsoleManager(worldAwareRobustProxyListener); + public ClientMain(String host, int port, boolean proxy, boolean fake) throws IOException { + EngineeringConsoleManager engineeringConsoleManager; + if (fake) { + engineeringConsoleManager = new FakeEngineeringConsoleManager(); + } + else { + WorldAwareServer worldAwareServer; + if (proxy) { + worldAwareServer = new WorldAwareRobustProxyListener(host, port, port); + } + else { + worldAwareServer = new WorldAwareRegularServer(host, port); + } + engineeringConsoleManager = new RealEngineeringConsoleManager(worldAwareServer); + } + buildUIFrame(engineeringConsoleManager); } @@ -59,8 +86,13 @@ private static UserInterfaceFrame buildUIFrame(EngineeringConsoleManager enginee } private static void printUsage() { - System.out.println("Either:\n" + - "Zero arguments: the client is set to local debug mode and where no network activity occurs\n" + - "Two arguments: (where host is either a hostname, e.g. 'localhost', or an IP address, e.g. '192.168.1.5')"); + System.err.println("\nUsage:\n" + + " Normal Mode\n" + + " engineeringClient [ [ this.updateGameState()); - this.worldAwareRobustProxyListener.getSystemManager().events.on(NotifyingSystemManager.Events.CHANGE, () -> this.systemManagerChange()); - this.worldAwareRobustProxyListener.getSystemManager().setSystemGrid(getShipSystemGrid()); + public RealEngineeringConsoleManager(WorldAwareServer worldAwareServer) { + this.worldAwareServer = worldAwareServer; + this.worldAwareServer.onEvent(WorldAwareServer.Events.CONNECTION_STATE_CHANGE, () -> this.updateGameState()); + this.worldAwareServer.getSystemManager().events.on(NotifyingSystemManager.Events.CHANGE, () -> this.systemManagerChange()); + this.worldAwareServer.getSystemManager().setSystemGrid(getShipSystemGrid()); } private void systemManagerChange() { @@ -38,10 +37,10 @@ private void systemManagerChange() { private void updateGameState() { GameState oldGameState = gameState; - if (!worldAwareRobustProxyListener.isConnected()) { + if (!worldAwareServer.isConnected()) { gameState = GameState.DISCONNECTED; } - else if ( this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) != null) { + else if ( this.worldAwareServer.getSystemManager().getPlayerShip(0) != null) { gameState = GameState.INGAME; } else { @@ -60,40 +59,40 @@ public GameState getGameState() { @Override public int getSystemEnergyAllocated(ShipSystem system) { - if (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) == null) { + if (this.worldAwareServer.getSystemManager().getPlayerShip(0) == null) { return 100; } - return (int)(this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0).getSystemEnergy(system) * 300); + return (int)(this.worldAwareServer.getSystemManager().getPlayerShip(0).getSystemEnergy(system) * 300); } @Override public int getSystemCoolantAllocated(ShipSystem system) { - if (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) == null) { + if (this.worldAwareServer.getSystemManager().getPlayerShip(0) == null) { return 0; } - return this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0).getSystemCoolant(system); + return this.worldAwareServer.getSystemManager().getPlayerShip(0).getSystemCoolant(system); } @Override public int getSystemHeat(ShipSystem system) { - if (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) == null) { + if (this.worldAwareServer.getSystemManager().getPlayerShip(0) == null) { return 0; } - return (int) (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0).getSystemHeat(system) * 100); + return (int) (this.worldAwareServer.getSystemManager().getPlayerShip(0).getSystemHeat(system) * 100); } @Override public int getSystemHealth(ShipSystem system) { - if (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) == null) { + if (this.worldAwareServer.getSystemManager().getPlayerShip(0) == null) { return 100; } - return (int) (this.worldAwareRobustProxyListener.getSystemManager().getHealthOfSystem(system) * 100); + return (int) (this.worldAwareServer.getSystemManager().getHealthOfSystem(system) * 100); } @Override public int getTotalCoolantRemaining() { - if (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) == null) { + if (this.worldAwareServer.getSystemManager().getPlayerShip(0) == null) { return Artemis.DEFAULT_COOLANT; } final int totalCoolantUsed = Arrays.stream(ShipSystem.values()).mapToInt(system -> this.getSystemCoolantAllocated(system)).sum(); @@ -102,16 +101,16 @@ public int getTotalCoolantRemaining() { @Override public int getTotalShipCoolant() { - if (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) == null) { + if (this.worldAwareServer.getSystemManager().getPlayerShip(0) == null) { return 8; } - return this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0).getAvailableCoolant(); + return this.worldAwareServer.getSystemManager().getPlayerShip(0).getAvailableCoolant(); } @Override public Map getGridHealth() { Map result = new HashMap<>(); - for (Entry entry : this.worldAwareRobustProxyListener.getSystemManager().getGridDamages()) { + for (Entry entry : this.worldAwareServer.getSystemManager().getGridDamages()) { result.put(entry.getKey(), 1.0f - entry.getValue()); } return result; @@ -121,7 +120,7 @@ public Map getGridHealth() { public List getRawDamconStatus() { List teams = new ArrayList<>(); for(int teamNumber = 0; teamNumber < 16; teamNumber++) { - DamconStatus damcon = this.worldAwareRobustProxyListener.getSystemManager().getDamcon(teamNumber); + DamconStatus damcon = this.worldAwareServer.getSystemManager().getDamcon(teamNumber); if (damcon != null) { teams.add(damcon); } @@ -131,16 +130,16 @@ public List getRawDamconStatus() { @Override public float getTotalEnergyRemaining() { - if (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) == null) { + if (this.worldAwareServer.getSystemManager().getPlayerShip(0) == null) { return 0; } - return this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0).getEnergy(); + return this.worldAwareServer.getSystemManager().getPlayerShip(0).getEnergy(); } @Override public void incrementSystemEnergyAllocated(ShipSystem system, int amount) { - if (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) == null) { + if (this.worldAwareServer.getSystemManager().getPlayerShip(0) == null) { return; } super.incrementSystemEnergyAllocated(system, amount); @@ -148,7 +147,7 @@ public void incrementSystemEnergyAllocated(ShipSystem system, int amount) { @Override public void incrementSystemCoolantAllocated(ShipSystem system, int amount) { - if (this.worldAwareRobustProxyListener.getSystemManager().getPlayerShip(0) == null) { + if (this.worldAwareServer.getSystemManager().getPlayerShip(0) == null) { return; } super.incrementSystemCoolantAllocated(system, amount); @@ -156,16 +155,16 @@ public void incrementSystemCoolantAllocated(ShipSystem system, int amount) { @Override protected void updateSystemEnergyAllocated(ShipSystem system, int amount) { - this.worldAwareRobustProxyListener.getServer().send(new EngSetEnergyPacket(system, amount)); + this.worldAwareServer.getServer().send(new EngSetEnergyPacket(system, amount)); } @Override protected void updateSystemCoolantAllocated(ShipSystem system, int amount) { - this.worldAwareRobustProxyListener.getServer().send(new EngSetCoolantPacket(system, amount)); + this.worldAwareServer.getServer().send(new EngSetCoolantPacket(system, amount)); } public void moveDamconTeam(int teamId, GridCoord coord) { System.out.println("Moving DAMCON team " + teamId + " to grid " + coord); - this.worldAwareRobustProxyListener.getServer().send(new EngSendDamconPacket(teamId, coord)); + this.worldAwareServer.getServer().send(new EngSendDamconPacket(teamId, coord)); } } diff --git a/src/com/brindyblitz/artemis/engconsole/ui/EnergySlider.java b/src/com/brindyblitz/artemis/engconsole/ui/EnergySlider.java index d214221..85a6930 100644 --- a/src/com/brindyblitz/artemis/engconsole/ui/EnergySlider.java +++ b/src/com/brindyblitz/artemis/engconsole/ui/EnergySlider.java @@ -30,7 +30,7 @@ public EnergySlider(ShipSystem system, EngineeringConsoleManager engineeringCons @Override protected int getStatusPctInt() { // TODO: >>> TESTME - return 100 * (int)(this.engineeringConsoleManager.getTotalEnergyRemaining() / 1000f); + return (int)(100 * (this.engineeringConsoleManager.getTotalEnergyRemaining() / 1000f)); } @Override diff --git a/src/com/brindyblitz/artemis/engconsole/ui/InGamePanel.java b/src/com/brindyblitz/artemis/engconsole/ui/InGamePanel.java index 6025417..a9e670b 100644 --- a/src/com/brindyblitz/artemis/engconsole/ui/InGamePanel.java +++ b/src/com/brindyblitz/artemis/engconsole/ui/InGamePanel.java @@ -122,6 +122,8 @@ public void handleKeyPress(KeyEvent e) { for (EnhancedDamconStatus damconStatus : this.engineeringConsoleManager.getDamconTeams()) { System.out.println(damconStatus); } + + System.out.println("Energy remaining: " + this.engineeringConsoleManager.getTotalEnergyRemaining()); System.out.println("\n\n\n"); } else if (kc == KeyEvent.VK_EQUALS) { diff --git a/src/com/brindyblitz/artemis/engconsole/ui/UserInterfaceFrame.java b/src/com/brindyblitz/artemis/engconsole/ui/UserInterfaceFrame.java index a34724b..8513353 100644 --- a/src/com/brindyblitz/artemis/engconsole/ui/UserInterfaceFrame.java +++ b/src/com/brindyblitz/artemis/engconsole/ui/UserInterfaceFrame.java @@ -11,6 +11,7 @@ import com.brindyblitz.artemis.engconsole.EngineeringConsoleManager; import com.brindyblitz.artemis.engconsole.EngineeringConsoleManager.Events; +import com.brindyblitz.artemis.engconsole.EngineeringConsoleManager.GameState; public class UserInterfaceFrame extends JFrame implements KeyListener { @@ -48,11 +49,18 @@ public UserInterfaceFrame(EngineeringConsoleManager engineeringConsoleManager) { getContentPane().add(loading); this.setVisible(true); + updateCurrentPanel(); engineeringConsoleManager.onEvent(Events.GAME_STATE_CHANGE, () -> { - switchToInGamePanel(); + updateCurrentPanel(); }); } + private void updateCurrentPanel() { + if (engineeringConsoleManager.getGameState() == GameState.INGAME) { + switchToInGamePanel(); + } + } + private void switchToInGamePanel() { if (inGamePanel != null) { this.getContentPane().remove(inGamePanel); diff --git a/src/com/brindyblitz/artemis/protocol/RobustProxyListener.java b/src/com/brindyblitz/artemis/protocol/RobustProxyListener.java index 8b0d53e..c9476aa 100644 --- a/src/com/brindyblitz/artemis/protocol/RobustProxyListener.java +++ b/src/com/brindyblitz/artemis/protocol/RobustProxyListener.java @@ -5,9 +5,6 @@ import java.net.ServerSocket; import java.net.Socket; -import com.brindyblitz.artemis.utils.EventEmitter; -import com.brindyblitz.artemis.utils.EventSubscriber; - import net.dhleong.acl.enums.ConnectionType; import net.dhleong.acl.iface.ArtemisNetworkInterface; import net.dhleong.acl.iface.BaseDebugger; @@ -27,9 +24,6 @@ public class RobustProxyListener implements Runnable { private ArtemisNetworkInterface server; private ArtemisNetworkInterface client; - - private EventEmitter eventEmitter = new EventEmitter<>(); - public final EventSubscriber events = eventEmitter.subscriber; public RobustProxyListener(String serverAddr, int serverPort, int proxyPort) { this.serverAddr = serverAddr; @@ -63,10 +57,10 @@ public void run() { this.client.addListener(this); this.onBeforeClientServerStart(); this.connected = true; - eventEmitter.emit(Events.CONNECTION_STATE_CHANGE); this.server.start(); this.client.start(); + this.onConnected(); System.out.println("connection established."); } catch (IOException ex) { ex.printStackTrace(); @@ -83,6 +77,10 @@ public void run() { protected void onBeforeClientServerStart() { + } + + protected void onConnected() { + } public ArtemisNetworkInterface getServer() { @@ -141,8 +139,4 @@ public void onRecvParsedPacket(ArtemisPacket pkt) { protected boolean shouldProxyPacket(ArtemisPacket packet) { return true; } - - public enum Events { - CONNECTION_STATE_CHANGE - } } diff --git a/src/com/brindyblitz/artemis/protocol/WorldAwareRegularServer.java b/src/com/brindyblitz/artemis/protocol/WorldAwareRegularServer.java new file mode 100644 index 0000000..62527fc --- /dev/null +++ b/src/com/brindyblitz/artemis/protocol/WorldAwareRegularServer.java @@ -0,0 +1,63 @@ +package com.brindyblitz.artemis.protocol; + +import java.io.IOException; + +import com.brindyblitz.artemis.utils.EventEmitter; + +import net.dhleong.acl.enums.Console; +import net.dhleong.acl.iface.ArtemisNetworkInterface; +import net.dhleong.acl.iface.ConnectionSuccessEvent; +import net.dhleong.acl.iface.Listener; +import net.dhleong.acl.iface.ThreadedArtemisNetworkInterface; +import net.dhleong.acl.protocol.core.setup.ReadyPacket; +import net.dhleong.acl.protocol.core.setup.SetConsolePacket; + +public class WorldAwareRegularServer implements WorldAwareServer { + + private ArtemisNetworkInterface server; + private NotifyingSystemManager systemManager; + private boolean connected = false; + private EventEmitter eventEmitter = new EventEmitter<>(); + + public WorldAwareRegularServer(String host, int port) { + try { + server = new ThreadedArtemisNetworkInterface(host, port); + } catch (IOException e) { + e.printStackTrace(); + } + + this.systemManager = new NotifyingSystemManager(); + + server.addListener(this); + server.addListener(this.systemManager); + server.start(); + } + + @Listener + public void onConnectSuccess(ConnectionSuccessEvent event) { + this.connected = true; + eventEmitter.emit(Events.CONNECTION_STATE_CHANGE); + server.send(new SetConsolePacket(Console.ENGINEERING, true)); + server.send(new ReadyPacket()); + } + + @Override + public NotifyingSystemManager getSystemManager() { + return this.systemManager; + } + + @Override + public ArtemisNetworkInterface getServer() { + return this.server; + } + + @Override + public boolean isConnected() { + return this.connected; + } + + @Override + public void onEvent(Events event, Runnable listener) { + eventEmitter.on(event, listener); + } +} diff --git a/src/com/brindyblitz/artemis/protocol/WorldAwareRobustProxyListener.java b/src/com/brindyblitz/artemis/protocol/WorldAwareRobustProxyListener.java index e99ccf1..247c1ef 100644 --- a/src/com/brindyblitz/artemis/protocol/WorldAwareRobustProxyListener.java +++ b/src/com/brindyblitz/artemis/protocol/WorldAwareRobustProxyListener.java @@ -1,8 +1,11 @@ package com.brindyblitz.artemis.protocol; -public class WorldAwareRobustProxyListener extends RobustProxyListener { +import com.brindyblitz.artemis.utils.EventEmitter; + +public class WorldAwareRobustProxyListener extends RobustProxyListener implements WorldAwareServer { private NotifyingSystemManager systemManager; + private EventEmitter eventEmitter = new EventEmitter<>(); public WorldAwareRobustProxyListener(String serverAddr, int serverPort, int proxyPort) { super(serverAddr, serverPort, proxyPort); @@ -17,4 +20,13 @@ protected void onBeforeClientServerStart() { public NotifyingSystemManager getSystemManager() { return systemManager; } + + @Override + protected void onConnected() { + eventEmitter.emit(Events.CONNECTION_STATE_CHANGE); + } + + public void onEvent(Events event, Runnable listener) { + eventEmitter.on(event, listener); + }; } diff --git a/src/com/brindyblitz/artemis/protocol/WorldAwareServer.java b/src/com/brindyblitz/artemis/protocol/WorldAwareServer.java new file mode 100644 index 0000000..89b3323 --- /dev/null +++ b/src/com/brindyblitz/artemis/protocol/WorldAwareServer.java @@ -0,0 +1,16 @@ +package com.brindyblitz.artemis.protocol; + +import net.dhleong.acl.iface.ArtemisNetworkInterface; + +public interface WorldAwareServer { + + NotifyingSystemManager getSystemManager(); + ArtemisNetworkInterface getServer(); + boolean isConnected(); + void onEvent(Events event, Runnable listener); + + public enum Events { + CONNECTION_STATE_CHANGE + } + +}