use of com.faforever.server.entity.Game in project faf-java-server by FAForever.
the class GameService method createGame.
/**
* Creates a new, transient game with the specified options and tells the client to start the game process. The
* player's current game is set to the new game.
*
* @return a future that will be completed as soon as the player's game has been started and is ready to be joined. Be
* aware that there are various reasons for the game to never start (crash, disconnect, abort) so never wait without a
* timeout.
*/
@Transactional(readOnly = true)
public CompletableFuture<Game> createGame(String title, String featuredModName, String mapFileName, String password, GameVisibility visibility, Integer minRating, Integer maxRating, Player player) {
Game currentGame = player.getCurrentGame();
if (currentGame != null && currentGame.getState() == GameState.INITIALIZING) {
/* Apparently, the user's game crashed before it reached the lobby, leaving it in state INITIALIZING. One solution
is to let the game time out, but as usual, that's not a good solution since no matter what timeout one chooses,
there is always some drawback. Therefore, we don't timeout games but reset a player's game state when he tries
to create a new game. Or when he logs out. */
removePlayer(currentGame, player);
}
Requests.verify(currentGame == null, ErrorCode.ALREADY_IN_GAME);
int gameId = this.lastGameId.incrementAndGet();
Game game = new Game(gameId);
game.setHost(player);
modService.getFeaturedMod(featuredModName).map(game::setFeaturedMod).orElseThrow(() -> new RequestException(ErrorCode.INVALID_FEATURED_MOD, featuredModName));
game.setTitle(title);
mapService.findMap(mapFileName).ifPresent(game::setMapVersion);
game.setMapName(mapFileName);
game.setPassword(password);
game.setGameVisibility(visibility);
game.setMinRating(minRating);
game.setMaxRating(maxRating);
activeGamesById.put(game.getId(), game);
counterService.increment(String.format(Metrics.GAMES_STATE_FORMAT, game.getState()));
log.debug("Player '{}' created game '{}'", player, game);
clientService.startGameProcess(game, player);
player.setCurrentGame(game);
changePlayerGameState(player, PlayerGameState.INITIALIZING);
CompletableFuture<Game> gameJoinedFuture = new CompletableFuture<>();
player.setGameFuture(gameJoinedFuture);
return game.getJoinableFuture();
}
use of com.faforever.server.entity.Game in project faf-java-server by FAForever.
the class GameService method updatePlayerOption.
/**
* Updates an option value of a specific player. Only the host of a game is allowed to report such options and for
* unstarted games, otherwise an exception will be thrown.
*
* @throws RequestException if the reporting player is not the host, or if the game is not in state {@link
* GameState#OPEN}
*/
public void updatePlayerOption(Player reporter, int playerId, String key, Object value) {
Game game = reporter.getCurrentGame();
if (game == null) {
// Since this is called repeatedly, throwing exceptions here would not be a good idea. Happens after restarts.
log.warn("Received player option for player w/o game: {}", reporter);
return;
}
Requests.verify(game.getState() == GameState.OPEN, ErrorCode.INVALID_GAME_STATE, game.getState(), GameState.OPEN);
Requests.verify(Objects.equals(reporter.getCurrentGame().getHost(), reporter), ErrorCode.HOST_ONLY_OPTION, key);
if (!game.getConnectedPlayers().containsKey(playerId)) {
log.warn("Player '{}' reported option '{}' with value '{}' for unknown player '{}' in game '{}'", reporter, key, value, playerId, game);
return;
}
log.trace("Updating option for player '{}' in game '{}': '{}' = '{}'", playerId, game.getId(), key, value);
game.getPlayerOptions().computeIfAbsent(playerId, id -> new HashMap<>()).put(key, value);
markDirty(game, DEFAULT_MIN_DELAY, DEFAULT_MAX_DELAY);
}
use of com.faforever.server.entity.Game in project faf-java-server by FAForever.
the class GameService method restoreGameSession.
/**
* Associates the specified player with the specified game, if this player was previously part of the game and the
* game is still running. This is requested by the client after it lost connection to the server.
*/
public void restoreGameSession(Player player, int gameId) {
if (player.getCurrentGame() != null) {
log.warn("Player '{}' requested game session restoration but is still associated with game '{}'", player, player.getCurrentGame());
return;
}
Optional<Game> gameOptional = getActiveGame(gameId);
Requests.verify(gameOptional.isPresent(), ErrorCode.CANT_RESTORE_GAME_DOESNT_EXIST);
Game game = gameOptional.get();
GameState gameState = game.getState();
Requests.verify(gameState == GameState.OPEN || gameState == GameState.PLAYING, ErrorCode.CANT_RESTORE_GAME_DOESNT_EXIST);
Requests.verify(game.getState() != GameState.PLAYING || game.getPlayerStats().containsKey(player.getId()), ErrorCode.CANT_RESTORE_GAME_NOT_PARTICIPANT);
log.debug("Reassociating player '{}' with game '{}'", player, game);
player.setGameFuture(CompletableFuture.completedFuture(game));
addPlayer(game, player);
changePlayerGameState(player, PlayerGameState.INITIALIZING);
changePlayerGameState(player, PlayerGameState.LOBBY);
if (gameState == GameState.PLAYING) {
changePlayerGameState(player, PlayerGameState.LAUNCHING);
}
}
use of com.faforever.server.entity.Game in project faf-java-server by FAForever.
the class GameService method updateAiOption.
/**
* Updates an option value of a specific AI player. Only the host of a game is allowed to report such options,
* otherwise an exception will be thrown.
*
* @throws RequestException if the reporting player is not the host
*/
public void updateAiOption(Player reporter, String aiName, String key, Object value) {
Game game = reporter.getCurrentGame();
if (game == null) {
// Since this is called repeatedly, throwing exceptions here would not be a good idea. Happens after restarts.
log.warn("Received AI option for player w/o game: {}", reporter);
return;
}
Requests.verify(Objects.equals(reporter.getCurrentGame().getHost(), reporter), ErrorCode.HOST_ONLY_OPTION, key);
if (!OPTION_ARMY.equals(key)) {
log.trace("Ignoring option '{}' = '{}' for AI '{}' in game '{}' because only the option 'Army' is currently sent with the correct, final AI name", key, value, aiName, game.getId());
return;
}
log.trace("Updating option for AI '{}' in game '{}': '{}' = '{}'", aiName, game.getId(), key, value);
game.getAiOptions().computeIfAbsent(aiName, s -> new HashMap<>()).put(key, value);
markDirty(game, DEFAULT_MIN_DELAY, DEFAULT_MAX_DELAY);
}
use of com.faforever.server.entity.Game in project faf-java-server by FAForever.
the class GameService method reportDesync.
/**
* Increments the desync counter for a player's game. If the specified player is currently not in a game, this method
* does nothing.
*/
public void reportDesync(Player reporter) {
Game game = reporter.getCurrentGame();
if (game == null) {
log.warn("Desync reported by player w/o game: {}", reporter);
return;
}
int desyncCount = game.getDesyncCounter().incrementAndGet();
log.debug("Player '{}' increased desync count to '{}' for game: {}", reporter, desyncCount, game);
}
Aggregations