private void onUpdateClientConfig(ClientConfigChangedEvent event) {
    String key = event.getKey();

    if (key.startsWith("r_")) {
      updateGraphicSettings();

      if (key.equals(ClientConfigConstants.r_resolution)) {
        String resolutionString = ClientConfig.getString(ClientConfigConstants.r_resolution);
        String[] resParts = resolutionString.split("x");
        Integer width = Integer.valueOf(resParts[0]);
        Integer height = Integer.valueOf(resParts[1]);

        cam.resize(width, height, true);

        ScreenUtils.reset();

        eventBus.fireEvent(new UpdateGraphicsConfigEvent(key, event.getValue()));
      }
    }
  }
  public void init(boolean clientConfigExisted) throws Exception {
    stateManager.detach(stateManager.getState(FlyCamAppState.class));
    stateManager.detach(stateManager.getState(StatsAppState.class));

    guiNode.detachAllChildren();

    guiNode.addControl(screen);

    consoleState = new ConsoleStateImpl(screen, rootNode, guiNode);
    stateManager.attach(consoleState);
    consoleState.setEnabled(false);

    menuState = new MenuStateImpl(screen, rootNode, guiNode);
    stateManager.attach(menuState);

    if (clientConfigExisted) {
      menuState.setEnabled(true);
    } else {
      usernameInputState = new UsernameInputStateImpl(screen, rootNode, guiNode);
      stateManager.attach(usernameInputState);
      usernameInputState.setEnabled(true);
      menuState.setEnabled(false);
    }

    playersContainer = new ClientPlayersContainer();
    entityIdProvider = new ClientEntityIdProvider();
    entityFactory = new ClientEntityFactory(assetManager, entityIdProvider);

    final ClientFactory clientFactory =
        new ClientFactory() {
          @Override
          public NetworkClient createClient() {
            return Network.createClient();
          }
        };

    clientState = new ClientStateImpl(clientFactory);
    syncState = new ClientSyncState(enqueueHelper, clientState, playersContainer);

    FPSState fpsState = new FPSStateImpl(screen, rootNode, guiNode);
    stateManager.attach(fpsState);
    fpsState.setEnabled(true);

    ingameState = new ClientIngameStateImpl(rootNode, guiNode);
    stateManager.attach(ingameState);
    ingameState.setEnabled(false);
    stateManager.attach(syncState);
    syncState.setEnabled(false);

    bulletAppState = new BulletAppState();
    bulletAppState.setThreadingType(ThreadingType.SEQUENTIAL);
    stateManager.attach(bulletAppState);
    bulletAppState.setEnabled(false);

    PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace();
    physicsSpace.setGravity(new Vector3f());

    physicsWrapper = new PhysicsWrapperImpl();
    physicsWrapper.setPhysicsSpace(physicsSpace);

    entityAttacher = new EntityAttacher(ingameState.getRootNode(), syncState, physicsWrapper);

    teamsContainer = new TeamsContainer();

    dataContainer =
        new ClientDataContainer(
            entityFactory,
            teamsContainer,
            enqueueHelper,
            entityAttacher,
            clientState,
            playersContainer,
            syncState);
    clientMessageListener = new ClientMessageListener(dataContainer);
    setupNetwork();
    stateManager.attach(clientState);

    respawnLocalPlayerHandler = new RespawnLocalPlayerHandler(cam);
    eventBus.addHandler(RespawnPlayerEvent.TYPE, respawnLocalPlayerHandler);

    initInput();

    initEventBus();
  }
  private void initEventBus() {
    eventBus.addHandler(
        UsernameSelectedEvent.TYPE,
        new UsernameSelectedHandler() {
          @Override
          public void onUsernameSelected(UsernameSelectedEvent event) {
            try {
              ClientConfig.setUsername(event.getUsername());
            } catch (IOException e) {
              // TODO
              e.printStackTrace();
            }

            stateManager.detach(usernameInputState);
            menuState.setEnabled(true);
          }
        });

    eventBus.addHandler(
        QuitEvent.TYPE,
        new QuitHandler() {
          @Override
          public void onQuit(QuitEvent e) {
            stopClient();
          }
        });

    eventBus.addHandler(
        CloseGameEvent.TYPE,
        new CloseGameHandler() {
          @Override
          public void onCloseGame(CloseGameEvent event) {
            closeGame(false);
          }
        });

    eventBus.addHandler(
        LoadGameEvent.TYPE,
        new LoadGameHandler() {
          @Override
          public void onLoadGame(final LoadGameEvent event) {
            enqueueHelper.enqueue(
                new Callable<Void>() {
                  @Override
                  public Void call() throws Exception {
                    loadGame(event.getData());
                    return null;
                  }
                });
          }
        });

    eventBus.addHandler(
        GameStateResponseEvent.TYPE,
        new GameStateResponseHandler() {
          @Override
          public void onGameStateResponse(GameStateResponseEvent event) {
            processGameState(event.getMessage());
          }
        });

    eventBus.addHandler(
        ToggleMainMenuEvent.TYPE,
        new ToggleMainMenuHandler() {
          @Override
          public void onChange(ToggleMainMenuEvent event) {
            if (localPlayer != null) {
              if (menuState.isEnabled()) {
                hudState.setEnabled(hudStateWasEnabled);
                spawnMenuState.setEnabled(!hudStateWasEnabled);
                menuState.setEnabled(false);
                ingameState.setEnabled(true);
              } else {
                hudStateWasEnabled = hudState.isEnabled();

                hudState.setEnabled(false);
                spawnMenuState.setEnabled(false);
                menuState.setEnabled(true);
                ingameState.setEnabled(false);
              }
            }
          }
        });

    eventBus.addHandler(
        ToggleConsoleEvent.TYPE,
        new ToggleConsoleHandler() {
          @Override
          public void onToggleConsole(ToggleConsoleEvent event) {
            consoleState.setEnabled(!consoleState.isEnabled());
          }
        });

    eventBus.addHandler(
        ToggleSpawnMenuEvent.TYPE,
        new ToggleSpawnMenuHandler() {
          @Override
          public void onChange(ToggleSpawnMenuEvent event) {
            if (ingameState.isEnabled() && endState == null) {
              hudState.setEnabled(!hudState.isEnabled());
              spawnMenuState.setEnabled(!spawnMenuState.isEnabled());
            }
          }
        });

    eventBus.addHandler(
        RespawnPlayerEvent.TYPE,
        new RespawnPlayerHandler() {
          @Override
          public void onRespawnPlayer(RespawnPlayerEvent event) {
            event.getPlayer().setRespawned();
          }
        });

    eventBus.addHandler(
        WinConditionReachedEvent.TYPE,
        new WinConditionReachedHandler() {
          @Override
          public void onWinConditionReached(WinConditionReachedEvent event) {
            endState = new EndStateImpl(screen, rootNode, guiNode);
            endState.setEnabled(true);
            stateManager.attach(endState);
            hudState.setEnabled(false);
            spawnMenuState.setEnabled(false);
          }
        });

    eventBus.addHandler(
        ToggleScoreBoardEvent.TYPE,
        new ToggleScoreBoardHandler() {
          @Override
          public void onToggleScoreBoard(ToggleScoreBoardEvent event) {
            if (endState == null && !consoleState.isEnabled()) {
              scoreBoardState.setEnabled(event.isShow());
            }
          }
        });

    eventBus.addHandler(
        RestartGameEvent.TYPE,
        new RestartGameHandler() {
          @Override
          public void onRestartGame(RestartGameEvent event) {
            closeGame(true);
          }
        });

    eventBus.addHandler(
        ClientConfigChangedEvent.TYPE,
        new ClientConfigChangedHandler() {
          @Override
          public void onChanged(ClientConfigChangedEvent event) {
            onUpdateClientConfig(event);
          }
        });

    eventBus.addHandler(
        UpdateDebugOptionEvent.TYPE,
        new UpdateDebugOptionHandler() {
          @Override
          public void onUpdate(UpdateDebugOptionEvent event) {
            if (enableDebug) {
              clientState.sendMessage(
                  new DebugConfigChangeRequestMessage(event.getDebugCommandKey()));
            }
          }
        });
  }
public abstract class Client {

  private static final Logger log = LoggerFactory.getLogger(Client.class);

  private final EventBus eventBus = EventBus.get();

  private UsernameInputState usernameInputState;
  private MenuState menuState;
  private ConsoleState consoleState;

  private ClientState clientState;

  private LoadingState loadingState;
  private LoadingThread loadingThread;

  private BulletAppState bulletAppState;

  private ClientIngameState ingameState;

  private SpawnMenuState spawnMenuState;
  private HUDState hudState;

  private EntityFactory entityFactory;

  private ClientSyncState syncState;

  private EntityAttacher entityAttacher;

  private ClientPlayersContainer playersContainer;

  private Player localPlayer;

  private EntityIdProvider entityIdProvider;
  private TeamsContainer teamsContainer;

  private PhysicsWrapper physicsWrapper;

  private ClientMessageListener clientMessageListener;

  private boolean hudStateWasEnabled;

  private RespawnLocalPlayerHandler respawnLocalPlayerHandler;

  private InputHandler inputHandler;

  private ScoreBoardState scoreBoardState;
  private EndState endState;

  private ClientDataContainer dataContainer;

  private final String mod;
  private final EnqueueHelper enqueueHelper;
  private final AppStateManager stateManager;
  private final AssetManager assetManager;
  private final InputManager inputManager;
  private final Node rootNode;
  private final Node guiNode;
  private final Screen screen;
  private final Camera cam;

  private boolean enableDebug;

  public Client(
      String mod,
      EnqueueHelper enqueueHelper,
      AppStateManager stateManager,
      AssetManager assetManager,
      InputManager inputManager,
      Node rootNode,
      Node guiNode,
      Screen screen,
      Camera cam) {
    super();
    this.mod = mod;
    this.enqueueHelper = enqueueHelper;
    this.stateManager = stateManager;
    this.assetManager = assetManager;
    this.inputManager = inputManager;
    this.rootNode = rootNode;
    this.guiNode = guiNode;
    this.screen = screen;
    this.cam = cam;
  }

  public abstract void stopApp();

  public abstract void updateGraphicSettings();

  public void init(boolean clientConfigExisted) throws Exception {
    stateManager.detach(stateManager.getState(FlyCamAppState.class));
    stateManager.detach(stateManager.getState(StatsAppState.class));

    guiNode.detachAllChildren();

    guiNode.addControl(screen);

    consoleState = new ConsoleStateImpl(screen, rootNode, guiNode);
    stateManager.attach(consoleState);
    consoleState.setEnabled(false);

    menuState = new MenuStateImpl(screen, rootNode, guiNode);
    stateManager.attach(menuState);

    if (clientConfigExisted) {
      menuState.setEnabled(true);
    } else {
      usernameInputState = new UsernameInputStateImpl(screen, rootNode, guiNode);
      stateManager.attach(usernameInputState);
      usernameInputState.setEnabled(true);
      menuState.setEnabled(false);
    }

    playersContainer = new ClientPlayersContainer();
    entityIdProvider = new ClientEntityIdProvider();
    entityFactory = new ClientEntityFactory(assetManager, entityIdProvider);

    final ClientFactory clientFactory =
        new ClientFactory() {
          @Override
          public NetworkClient createClient() {
            return Network.createClient();
          }
        };

    clientState = new ClientStateImpl(clientFactory);
    syncState = new ClientSyncState(enqueueHelper, clientState, playersContainer);

    FPSState fpsState = new FPSStateImpl(screen, rootNode, guiNode);
    stateManager.attach(fpsState);
    fpsState.setEnabled(true);

    ingameState = new ClientIngameStateImpl(rootNode, guiNode);
    stateManager.attach(ingameState);
    ingameState.setEnabled(false);
    stateManager.attach(syncState);
    syncState.setEnabled(false);

    bulletAppState = new BulletAppState();
    bulletAppState.setThreadingType(ThreadingType.SEQUENTIAL);
    stateManager.attach(bulletAppState);
    bulletAppState.setEnabled(false);

    PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace();
    physicsSpace.setGravity(new Vector3f());

    physicsWrapper = new PhysicsWrapperImpl();
    physicsWrapper.setPhysicsSpace(physicsSpace);

    entityAttacher = new EntityAttacher(ingameState.getRootNode(), syncState, physicsWrapper);

    teamsContainer = new TeamsContainer();

    dataContainer =
        new ClientDataContainer(
            entityFactory,
            teamsContainer,
            enqueueHelper,
            entityAttacher,
            clientState,
            playersContainer,
            syncState);
    clientMessageListener = new ClientMessageListener(dataContainer);
    setupNetwork();
    stateManager.attach(clientState);

    respawnLocalPlayerHandler = new RespawnLocalPlayerHandler(cam);
    eventBus.addHandler(RespawnPlayerEvent.TYPE, respawnLocalPlayerHandler);

    initInput();

    initEventBus();
  }

  private void setupNetwork() {
    clientState.addMessageListener(clientMessageListener);
    clientState.addMessageListener(
        syncState, SyncMessageFactory.class, PhysicsSyncMessage.class, WeaponFireSyncMessage.class);
  }

  private void initInput() throws IllegalAccessException {
    inputManager.clearMappings();

    if (inputHandler != null) {
      inputHandler.cleanup();
    }

    inputHandler = new InputHandler(inputManager, clientState, cam);
    respawnLocalPlayerHandler.setInputHandler(inputHandler);

    new BaseInputHandler(inputManager);
  }

  private void initEventBus() {
    eventBus.addHandler(
        UsernameSelectedEvent.TYPE,
        new UsernameSelectedHandler() {
          @Override
          public void onUsernameSelected(UsernameSelectedEvent event) {
            try {
              ClientConfig.setUsername(event.getUsername());
            } catch (IOException e) {
              // TODO
              e.printStackTrace();
            }

            stateManager.detach(usernameInputState);
            menuState.setEnabled(true);
          }
        });

    eventBus.addHandler(
        QuitEvent.TYPE,
        new QuitHandler() {
          @Override
          public void onQuit(QuitEvent e) {
            stopClient();
          }
        });

    eventBus.addHandler(
        CloseGameEvent.TYPE,
        new CloseGameHandler() {
          @Override
          public void onCloseGame(CloseGameEvent event) {
            closeGame(false);
          }
        });

    eventBus.addHandler(
        LoadGameEvent.TYPE,
        new LoadGameHandler() {
          @Override
          public void onLoadGame(final LoadGameEvent event) {
            enqueueHelper.enqueue(
                new Callable<Void>() {
                  @Override
                  public Void call() throws Exception {
                    loadGame(event.getData());
                    return null;
                  }
                });
          }
        });

    eventBus.addHandler(
        GameStateResponseEvent.TYPE,
        new GameStateResponseHandler() {
          @Override
          public void onGameStateResponse(GameStateResponseEvent event) {
            processGameState(event.getMessage());
          }
        });

    eventBus.addHandler(
        ToggleMainMenuEvent.TYPE,
        new ToggleMainMenuHandler() {
          @Override
          public void onChange(ToggleMainMenuEvent event) {
            if (localPlayer != null) {
              if (menuState.isEnabled()) {
                hudState.setEnabled(hudStateWasEnabled);
                spawnMenuState.setEnabled(!hudStateWasEnabled);
                menuState.setEnabled(false);
                ingameState.setEnabled(true);
              } else {
                hudStateWasEnabled = hudState.isEnabled();

                hudState.setEnabled(false);
                spawnMenuState.setEnabled(false);
                menuState.setEnabled(true);
                ingameState.setEnabled(false);
              }
            }
          }
        });

    eventBus.addHandler(
        ToggleConsoleEvent.TYPE,
        new ToggleConsoleHandler() {
          @Override
          public void onToggleConsole(ToggleConsoleEvent event) {
            consoleState.setEnabled(!consoleState.isEnabled());
          }
        });

    eventBus.addHandler(
        ToggleSpawnMenuEvent.TYPE,
        new ToggleSpawnMenuHandler() {
          @Override
          public void onChange(ToggleSpawnMenuEvent event) {
            if (ingameState.isEnabled() && endState == null) {
              hudState.setEnabled(!hudState.isEnabled());
              spawnMenuState.setEnabled(!spawnMenuState.isEnabled());
            }
          }
        });

    eventBus.addHandler(
        RespawnPlayerEvent.TYPE,
        new RespawnPlayerHandler() {
          @Override
          public void onRespawnPlayer(RespawnPlayerEvent event) {
            event.getPlayer().setRespawned();
          }
        });

    eventBus.addHandler(
        WinConditionReachedEvent.TYPE,
        new WinConditionReachedHandler() {
          @Override
          public void onWinConditionReached(WinConditionReachedEvent event) {
            endState = new EndStateImpl(screen, rootNode, guiNode);
            endState.setEnabled(true);
            stateManager.attach(endState);
            hudState.setEnabled(false);
            spawnMenuState.setEnabled(false);
          }
        });

    eventBus.addHandler(
        ToggleScoreBoardEvent.TYPE,
        new ToggleScoreBoardHandler() {
          @Override
          public void onToggleScoreBoard(ToggleScoreBoardEvent event) {
            if (endState == null && !consoleState.isEnabled()) {
              scoreBoardState.setEnabled(event.isShow());
            }
          }
        });

    eventBus.addHandler(
        RestartGameEvent.TYPE,
        new RestartGameHandler() {
          @Override
          public void onRestartGame(RestartGameEvent event) {
            closeGame(true);
          }
        });

    eventBus.addHandler(
        ClientConfigChangedEvent.TYPE,
        new ClientConfigChangedHandler() {
          @Override
          public void onChanged(ClientConfigChangedEvent event) {
            onUpdateClientConfig(event);
          }
        });

    eventBus.addHandler(
        UpdateDebugOptionEvent.TYPE,
        new UpdateDebugOptionHandler() {
          @Override
          public void onUpdate(UpdateDebugOptionEvent event) {
            if (enableDebug) {
              clientState.sendMessage(
                  new DebugConfigChangeRequestMessage(event.getDebugCommandKey()));
            }
          }
        });
  }

  private void loadGame(GameInfoInitData data) throws Exception {
    final GameInfo gameInfo = data.getGameInfo();

    enableDebug = gameInfo.isEnableDebug();

    final long localPlayerId = data.getPlayerId();
    final Faction localPlayerFaction = data.getFaction();
    final long initMoney = gameInfo.getInitMoney();

    final Faction[] playerFactions = data.getPlayerFactions();
    final String[] playerNames = data.getPlayerNames();
    final String[] playerShipNames = data.getPlayerShipNames();
    final long[] playerShipIds = data.getPlayerShipIds();
    final long[] playerIds = data.getPlayerIds();

    final List<WeaponAddedMessage> weaponAddedMessages = data.getWeaponAddedMessages();

    syncState.setTickRate(gameInfo.getServerTickRate());

    loadingState = new LoadingStateImpl(screen, rootNode, guiNode);
    stateManager.attach(loadingState);

    final String mapName = gameInfo.getMapName();
    final MapData mapData =
        JsonHelper.get()
            .toPOJO(
                FileConstants.MAPS_PATH_COMPLETE + mapName + FileConstants.MAP_DATA_FILE,
                MapData.class);

    short teamId = 1;
    Team team1 = new Team(teamId, mapData.getFaction1(), playerIds.length);
    teamId++;
    Team team2 = new Team(teamId, mapData.getFaction2(), playerIds.length);

    teamsContainer.setTeam1(team1);
    teamsContainer.setTeam2(team2);

    final ClientLoadingStepsBuilder builder =
        new ClientLoadingStepsBuilder(
            assetManager,
            mapData,
            entityFactory,
            ingameState.getRootNode(),
            gameInfo,
            cam,
            entityAttacher,
            teamsContainer);
    final List<LoadingStep> steps = builder.createLoadingSteps();

    for (int i = 0; i < playerFactions.length; i++) {
      final int a = i;

      steps.add(
          new LoadingStep(10f, true) {
            @Override
            public void load() throws Exception {
              final long playerId = playerIds[a];

              if (localPlayerId != playerId) {
                final Faction faction = playerFactions[a];
                final String playerName = playerNames[a];
                final String shipName = playerShipNames[a];
                final long entityId = playerShipIds[a];

                final Team team = teamsContainer.getTeam(faction);
                final Player player =
                    new Player(
                        playerName,
                        playerId,
                        team,
                        initMoney,
                        false,
                        teamsContainer.getEnemyTeam(team));
                playersContainer.addPlayer(player);
                team.addPlayer(player);

                if (shipName != null) {
                  final Node ship = entityFactory.createShip(shipName);
                  ship.setUserData(EntityConstants.ID, entityId);
                  ship.setUserData(EntityConstants.PLAYER, player);
                  player.setShip(ship);
                }
              }
            }
          });
    }

    for (final WeaponAddedMessage wam : weaponAddedMessages) {
      final WeaponAddedMessageHandler handler = new WeaponAddedMessageHandler(dataContainer);

      steps.add(
          new LoadingStep(5f, true) {

            @Override
            public void load() throws Exception {
              handler.handleMessage(null, wam);
            }
          });
    }

    steps.add(
        new LoadingStep(1f, true) {
          @Override
          public void load() throws Exception {
            final Team team = teamsContainer.getTeam(localPlayerFaction);
            localPlayer =
                new Player(
                    ClientConfig.getString(ClientConfigConstants.c_username),
                    localPlayerId,
                    team,
                    initMoney,
                    true,
                    teamsContainer.getEnemyTeam(team));
            playersContainer.addPlayer(localPlayer);
            team.addPlayer(localPlayer);

            spawnMenuState = new SpawnMenuStateImpl(screen, rootNode, guiNode);
            stateManager.attach(spawnMenuState);

            hudState =
                new HUDStateImpl(screen, rootNode, guiNode, enqueueHelper, cam, assetManager);
            stateManager.attach(hudState);

            scoreBoardState =
                new ScoreBoardStateImpl(
                    screen, rootNode, guiNode, team, teamsContainer.getEnemyTeam(team));
            stateManager.attach(scoreBoardState);
            scoreBoardState.setEnabled(false);

            clientState.sendMessage(new GameStateRequestMessage());
          }
        });

    loadingThread = new LoadingThread(steps, enqueueHelper, loadingState);

    menuState.setEnabled(false);
    loadingState.setEnabled(true);
    loadingThread.start();
  }

  private void processGameState(GameStateResponseMessage message) {
    final long[] alivePlayerIds = message.getAlivePlayers();
    final Vector3f[] alivePlayerPositions = message.getAlivePlayerPositions();

    for (int i = 0; i < alivePlayerIds.length; i++) {
      final long playerId = alivePlayerIds[i];
      final Vector3f position = alivePlayerPositions[i];

      final Player player = playersContainer.getPlayer(playerId);

      if (player != null) {
        enqueueHelper.enqueue(
            new Callable<Void>() {
              @Override
              public Void call() throws Exception {
                eventBus.fireEvent(new RespawnPlayerEvent(player, position, Vector3f.UNIT_Z));
                return null;
              }
            });
      } else {
        log.warn("Player with id " + playerId + " not found!");
      }
    }

    enqueueHelper.enqueue(
        new Callable<Void>() {

          @Override
          public Void call() throws Exception {
            loadingState.setEnabled(false);
            ingameState.setEnabled(true);
            spawnMenuState.setEnabled(true);

            bulletAppState.setEnabled(true);
            syncState.setEnabled(true);

            return null;
          }
        });
  }

  private void closeGame(boolean isServerRestart) {
    try {
      if (!isServerRestart) {
        clientState.cleanup();
        setupNetwork();
      }

      playersContainer.clear();
      syncState.cleanup();

      teamsContainer.clear();

      bulletAppState.setEnabled(false);
      physicsWrapper.cleanup(ingameState.getRootNode());

      ingameState.cleanup();

      initInput();
      stateManager.detach(hudState);
      stateManager.detach(spawnMenuState);
      stateManager.detach(scoreBoardState);

      ingameState.setEnabled(false);
      loadingState.setEnabled(false);
      syncState.setEnabled(false);

      localPlayer = null;

      if (endState != null) {
        stateManager.detach(endState);
        endState = null;
      }

      menuState.setEnabled(!isServerRestart);
    } catch (IllegalAccessException e) {
      // TODO
      e.printStackTrace();
    }
  }

  private void onUpdateClientConfig(ClientConfigChangedEvent event) {
    String key = event.getKey();

    if (key.startsWith("r_")) {
      updateGraphicSettings();

      if (key.equals(ClientConfigConstants.r_resolution)) {
        String resolutionString = ClientConfig.getString(ClientConfigConstants.r_resolution);
        String[] resParts = resolutionString.split("x");
        Integer width = Integer.valueOf(resParts[0]);
        Integer height = Integer.valueOf(resParts[1]);

        cam.resize(width, height, true);

        ScreenUtils.reset();

        eventBus.fireEvent(new UpdateGraphicsConfigEvent(key, event.getValue()));
      }
    }
  }

  private void stopClient() {
    clientState.disconnectFromServer();
    stopApp();
  }
}