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 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();
  }
  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();
  }