package com.cardshifter.core.game;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.cardshifter.api.outgoing.ClientDisconnectedMessage;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import com.cardshifter.api.ClientIO;
import com.cardshifter.api.messages.Message;
import com.cardshifter.api.outgoing.GameOverMessage;
import com.cardshifter.api.outgoing.NewGameMessage;
import com.cardshifter.modapi.base.ECSGame;
import com.cardshifter.modapi.base.ECSGameState;
/**
* Handles the state of the game and knows the current players
*
* @author Simon Forsberg
*/
public abstract class ServerGame {
private static final Logger logger = LogManager.getLogger(ServerGame.class);
private final List<ClientIO> players;
private final int id;
private Instant active;
protected final ECSGame game;
// private final Set<ClientIO> observers;
// private final ChatArea chat;
/**
* Initializes the player collection, sets the initial game state
*
* @param id ID of the game
* @param game ECS Game object
*/
public ServerGame(int id, ECSGame game) {
this.id = id;
this.players = Collections.synchronizedList(new ArrayList<>());
this.active = Instant.now();
this.game = game;
// this.chat = server.newChatRoom(this.toString());
}
/**
* Sends information to clients that the game has been ended
*/
public void endGame() {
logger.info("Game Ended: " + this + " with players " + players);
this.send(new GameOverMessage());
this.active = Instant.now();
}
/**
*
* @return Whether or not the game is in the ended state
*/
public boolean isGameOver() {
return game.isGameOver();
}
/**
* This is where the players are added to the ServerGame, also sets the game state
*
* @param players The players to add to the game
*/
public void start(List<ClientIO> players) {
if (game.getGameState() != ECSGameState.NOT_STARTED) {
throw new IllegalStateException("Game can only be started once");
}
players.forEach(this::addPlayer);
for (ClientIO player : players) {
player.sendToClient(new NewGameMessage(this.id, players.indexOf(player)));
}
this.onStart();
this.active = Instant.now();
}
/**
* Called when the game starts
*/
protected abstract void onStart();
/**
* Sends a message to all players in the game
*
* @param data Message to send
*/
public void send(Message data) {
players.forEach(player -> player.sendToClient(data));
}
/**
*
* @return The ID of the ServerGame
*/
public int getId() {
return id;
}
/**
*
* @return The time elapsed since active time was stored
*/
public Duration getLastActive() {
return Duration.between(active, Instant.now());
}
/**
*
* @return The current state of the game
*/
public ECSGameState getState() {
return game.getGameState();
}
public ECSGame getGameModel() {
return game;
}
/**
*
* @return The current players for this game
*/
public List<ClientIO> getPlayers() {
return Collections.unmodifiableList(players);
}
/**
*
* @param client Which client to look for
* @return Whether or not the given player is in this game
*/
public boolean hasPlayer(ClientIO client) {
return players.contains(client);
}
public void addPlayer(ClientIO client) {
this.players.add(client);
}
public void disconnect(ClientIO client) {
ClientDisconnectedMessage data = new ClientDisconnectedMessage(client.getName(), this.getPlayers().indexOf(client));
players.stream().filter(player -> player != client).forEach(player -> player.sendToClient(data));
}
}