/modules/hexx-network/src/main/java/de/bitrain/hexx/network/logic/GameClient.java
Java | 345 lines | 174 code | 58 blank | 113 comment | 9 complexity | 6745ee51c879b58f786fcd94d7a9fe56 MD5 | raw file
- package de.bitrain.hexx.network.logic;
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.util.List;
- import java.util.Observable;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import com.esotericsoftware.kryonet.Client;
- import com.esotericsoftware.kryonet.Connection;
- import de.bitrain.hexx.core.logic.Player;
- import de.bitrain.hexx.core.logic.SessionManager;
- import de.bitrain.hexx.core.logic.WeakObserverReference;
- import de.bitrain.hexx.core.logic.board.Position;
- import de.bitrain.hexx.core.logic.game.Game;
- import de.bitrain.hexx.core.logic.game.GameState;
- import de.bitrain.hexx.core.logic.game.interfaces.GameI;
- import de.bitrain.hexx.network.logic.match_making.MatchMakingStatus;
- import de.bitrain.hexx.network.logic.message.Message;
- import de.bitrain.hexx.network.logic.message.MessageListener;
- import de.bitrain.hexx.network.logic.message.types.GameStartMessage;
- import de.bitrain.hexx.network.logic.message.types.JoinRequest;
- import de.bitrain.hexx.network.logic.message.types.MatchMakingRequest;
- import de.bitrain.hexx.network.logic.message.types.MatchMakingResponse;
- import de.bitrain.hexx.network.logic.message.types.MoveMessage;
- import de.bitrain.hexx.network.logic.message.types.RoomCreateRequest;
- import de.bitrain.hexx.network.logic.message.types.RoomCreateResponse;
- import de.bitrain.hexx.network.logic.message.types.RoomListRequest;
- import de.bitrain.hexx.network.logic.message.types.RoomListResponse;
- import de.bitrain.hexx.network.logic.room.RoomInfo;
- /**
- * Represents a game client which can connect to a remote game server.
- */
- public class GameClient extends ObservableGameManager {
- private final static Logger logger = LoggerFactory.getLogger(GameClient.class);
- /**
- * Underlying kryo client responsible for communicating with the server.
- */
- private final Client kryoClient;
- /**
- * RemoteClient representing the server.
- */
- private RemoteClient server;
- /**
- * {@link RoomInfo} of the room the client is currently connected or
- * <code>null</code> if the client is not connected toany room at the moment.
- */
- private RoomInfo roomInfo;
- /**
- * Initializes the client.
- */
- public GameClient() {
- // Create client and add listener
- this.kryoClient = new Client();
- this.kryoClient.addListener(new InnerListener().setMessageProcessor(this));
- Message.registerClasses(this.kryoClient.getKryo());
- }
- /**
- * Tries to connect to the server.
- *
- * @return Returns true upon establishment of the connection or false on error or after the given
- * timeout.
- */
- public boolean connectToServer(final InetSocketAddress socketAddress,
- final int timeout) {
- try {
- // Start the client and connect to the server
- this.kryoClient.start();
- this.kryoClient.connect(timeout, socketAddress.getAddress(),
- socketAddress.getPort());
- }
- // If an error occurred, log it and shut the client down again
- catch (final IOException e) {
- logger.error("Error connecting to the server {}, exception: {}",
- socketAddress.toString(), e.getMessage());
- this.disconnect();
- return false;
- }
- // Create the remote client representing our connection to the server
- this.server = new RemoteClient(this.kryoClient, new Player(-1));
- logger.debug("Successfully connected to server {}",
- socketAddress.toString());
- return true;
- }
- /**
- * Tries to create a room on the connected server.
- */
- public boolean createRoom(final RoomInfo roomInfo, final GameI game) {
- // Abort if we are not connected
- // TODO throw exception?
- if (!this.isConnected()) {
- return false;
- }
- // Create the room request message and append the game state and room info
- final Message roomCreateRequest = new RoomCreateRequest();
- roomCreateRequest.append(roomInfo);
- roomCreateRequest.append(game.getGameState());
- // Send the message to the server
- this.server.sendMessage(roomCreateRequest);
- return true;
- }
- /**
- * Sends a match-making request to the connected server.
- */
- public boolean requestMatch() {
- // TODO throw exception?
- if (!this.isConnected()) {
- return false;
- }
- final Message matchMakingRequest = new MatchMakingRequest();
- matchMakingRequest.append(this.getLocalPlayer().getName());
- this.server.sendMessage(matchMakingRequest);
- return true;
- }
- /**
- * Disconnects the client from the server.
- */
- public void disconnect() {
- this.kryoClient.stop();
- }
- @Override
- public NetworkGame getGame() {
- return (NetworkGame) super.getGame();
- }
- /**
- * Returns the kryo client for this game client.
- */
- public Client getKryoClient() {
- return this.kryoClient;
- }
- /**
- * Returns the local player associated with this client.
- */
- public Player getLocalPlayer() {
- return this.server.getPlayer();
- }
- /**
- * Returns the {@link RoomInfo} of the room the client is currently connected
- * to, or <code>null</code> if the client is not connected to any room.
- */
- public RoomInfo getRoomInfo() {
- return this.roomInfo;
- }
- /**
- * Returns the server or null, if the client is not connected.
- */
- public RemoteClient getServer() {
- return this.server;
- }
- /**
- * Proxy to {@link Client#isConnected()}
- */
- public boolean isConnected() {
- return this.kryoClient.isConnected();
- }
- /**
- * Tries to join a room, announcing the given player name to the server.
- *
- * @param roomId id of the room to be joined
- */
- private void joinRoom(final Integer roomId) {
- // Abort if there's no connection to a server
- if (!this.isConnected()) {
- return;
- }
- // Send our local player to the server
- this.server.sendMessage(new JoinRequest()
- .append(this.server.getPlayer()).append(roomId));
- }
- /**
- * Tries to join the room with the given {@link RoomInfo}.
- *
- * @see #joinRoom(Integer)
- */
- public void joinRoom(final RoomInfo roomInfo) {
- this.roomInfo = roomInfo;
- this.joinRoom(roomInfo.getId());
- }
- /**
- * Processes GameStartMessages.
- */
- public void processMessage(final GameStartMessage message)
- throws Exception {
- final List<Object> contents = message.getContents();
- // Restore the game from the given game state
- final Game game = ((GameState) contents.get(0)).restoreAll();
- // Now take the player names from the second part of the contents
- final List<?> playersNamed = (List<?>) contents.get(1);
- final List<Player> playersUnnamed = game.getActivePlayers();
- Player playerNamed, playerUnnamed;
- // Walk though all players and carry the names over
- for (int i = 0; i < playersNamed.size(); i++) {
- logger.debug("Player {}: {}", i, playersNamed.get(i).toString());
- playerNamed = (Player) playersNamed.get(i);
- playerUnnamed = playersUnnamed.get(i);
- playerUnnamed.setName(playerNamed.getName());
- // If the current player is our local player, save it
- if (playerUnnamed.getName().equals(this.server.getPlayer().getName())) {
- logger.debug("Local player {}: {}", this.toString(),
- playerUnnamed.toString());
- this.server.setPlayer(playerUnnamed);
- }
- }
- // Store the game
- this.setGame(new NetworkGame(game, this.getLocalPlayer()));
- // Also store it in the session manager
- //SessionManager.getInstance().setCurrentGame(this.getGame());
- SessionManager.getInstance().setCurrentGame(game);
- // Register as listener with the game
- this.getGame().addObserver(new WeakObserverReference(this));
- // Notify observers that something changed
- super.processMessage(message);
- }
- /**
- * Processes MoveMessages from the server.
- */
- public void processMessage(final MoveMessage message) throws Exception {
- // TODO we need to catch IllegalMoveExceptions
- this.getGame().getGame()
- .tryMoveOnPosition((Position) message.getContent(0));
- // TODO move somewhere else?
- if (this.getGame().getGame().isOver()) {
- this.disconnect();
- }
- super.processMessage(message);
- }
- /**
- * Processes room creation responses and joins the room.
- *
- * TODO room creation failure?
- */
- public void processMessage(final RoomCreateResponse message) throws Exception {
- this.joinRoom((RoomInfo) message.getContent(0));
- }
- /**
- * Processes match-making responses.
- *
- * <p>Joins the provided room if a match was found.</p>
- */
- public void processMessage(final MatchMakingResponse message) throws Exception {
- if (message.getContent(0).equals(MatchMakingStatus.MATCH_FOUND)) {
- this.joinRoom((RoomInfo) message.getContent(1));
- }
- }
- /**
- * Processes incoming room lists and notifies observers.
- */
- public void processMessage(final RoomListResponse message) throws Exception {
- this.setChanged();
- this.notifyObservers(message);
- }
- /**
- * Sends a RoomListRequest to the server.
- */
- public void refreshRoomList() {
- this.server.sendMessage(new RoomListRequest());
- }
- /**
- * Sets the name of the local player.
- */
- public boolean setLocalPlayerName(final String name) {
- // Abort if not connected
- if (!this.isConnected()) {
- return false;
- }
- this.server.getPlayer().setName(name);
- return true;
- }
- /**
- * Sends local moves to the server.
- */
- @Override
- public void update(final Observable o, final Object position) {
- if (position instanceof Position) {
- this.server.sendMessage(new MoveMessage().append(position));
- }
- }
- /**
- * This listener monitors the kryo-server for incoming messages and processes
- * them.
- */
- private class InnerListener extends MessageListener {
- @Override
- public void disconnected(final Connection connection) {
- // TODO perform cleanup if needed?
- }
- }
- }