public static void runGame(String filename, int port, int rounds, int time) throws IOException, InterruptedException, ExecutionException { final World world; int users = 0; try { WorldParser wp = new WorldParser(); world = wp.parse(filename); users = world.getNumberOfSpawnpoints(); } catch (FileNotFoundException e) { logger.error("Map file not found: '" + filename + "'."); return; } Message info = new InfoMessage(time, rounds, filename, users); logger.info("Starting graphics server."); GraphicsServer graphics = new GraphicsServer(info, port + 10); graphics.start(); logger.info("Waiting for clients to connect."); ServerSocket socket = new ServerSocket(port); List<Player> players = new ArrayList<>(); for (int i = 0; i < users; i++) { Socket client = socket.accept(); Connection conn = new Connection(client); new Thread(conn).start(); conn.sendMessage(info); players.add(new Player(conn)); } logger.info("All clients connected."); logger.info("Setting spawnpoints."); Collections.shuffle(players); Queue<Vector2d> spawnpoints = world.getSpawnpoints(); for (Player player : players) { player.setSpawn(spawnpoints.poll()); } logger.info("Sending initial game state."); Message state0 = new GameStateMessage(0, world, players); players.stream().peek(p -> p.send(state0)); graphics.sendToAll(state0); logger.info("Recieved loadout from all."); logger.info("Starting game."); for (int round = 1; round <= rounds; round++) { for (Player player : players) { logger.info("Starting player '" + player.getName() + "' turn."); logger.info("Clearing all messages from player queue."); player.clear(); logger.info("Sending first round to all."); Message state = new GameStateMessage(round, world, players); players.stream().forEach(p -> p.send(state)); graphics.sendToAll(state); if (player.isDead()) { logger.info(player.getName() + " is dead. Respawning..."); player.respawn(); } else { List<ActionMessage> actions = new ArrayList<>(); Instant stop = Instant.now().plus(time, MILLIS); for (int a = 0; a < 3; a++) { logger.info("Waiting for action " + a + "."); long timeout = Math.max(0, MILLIS.between(Instant.now(), stop)); ActionMessage action = player.next(timeout, MILLISECONDS); if (action == null) { logger.debug( "==> Player '" + player.getName() + "' timed out in round " + round + "."); break; } try { logger.info("Performing action."); action.performAction(player, world); actions.add(action); logger.info("Successful message: " + action.toString()); players.stream().forEach(p -> p.send(action)); } catch (ProtocolException e) { logger.debug(e.getMessage()); player.send(new ErrorMessage(e)); } } logger.info("Waiting to complete round."); Thread.sleep(Math.max(0, MILLIS.between(Instant.now(), stop))); player.send(new EndTurnMessage()); logger.info("Sending actions to graphics."); for (Message m : actions) { graphics.sendToAll(m); } } } Collections.rotate(players, 1); } players.sort(comparing(Player::score)); Collections.reverse(players); players.removeIf(p -> p.score() < players.get(0).score()); String winner; if (players.size() > 1) { winner = String.format( "A %d-way tie between: %s", players.size(), String.join(", ", players.toArray(new String[players.size()]))); } else { winner = String.format("The winner is ", players.get(0)); } logger.info("Winner: " + winner); Message message = new GameFinishedMessage(winner); players.stream().forEach(p -> p.send(message)); graphics.sendToAll(message); socket.close(); }
public synchronized boolean doMove(JSONObject o) { // TODO verify that this is all exactly right try { String direction = o.getString("direction"); if (direction.equals("up")) { if (position.up != null && position.up.isAccessible()) { if (position.up.playerOnTile != null) { throw new ProtocolException( "Player " + position.up.playerOnTile.username + " is already on this tile."); } position.playerOnTile = null; position = position.up; position.playerOnTile = this; return true; } else { throw Util.throwInaccessibleTileException("up", position.up); } } else if (direction.equals("down")) { if (position.down != null && position.down.isAccessible()) { if (position.down.playerOnTile != null) { throw new ProtocolException( "Player " + position.down.playerOnTile.username + " is already on this tile."); } position.playerOnTile = null; position = position.down; position.playerOnTile = this; return true; } else { throw Util.throwInaccessibleTileException("down", position.down); } } else if (direction.equals("left-down")) { if (position.leftDown != null && position.leftDown.isAccessible()) { if (position.leftDown.playerOnTile != null) { throw new ProtocolException( "Player " + position.leftDown.playerOnTile.username + " is already on this tile."); } position.playerOnTile = null; position = position.leftDown; position.playerOnTile = this; return true; } else { throw Util.throwInaccessibleTileException("left-down", position.leftDown); } } else if (direction.equals("left-up")) { if (position.leftUp != null && position.leftUp.isAccessible()) { if (position.leftUp.playerOnTile != null) { throw new ProtocolException( "Player " + position.leftUp.playerOnTile.username + " is already on this tile."); } position.playerOnTile = null; position = position.leftUp; position.playerOnTile = this; return true; } else { throw Util.throwInaccessibleTileException("left-up", position.leftUp); } } else if (direction.equals("right-down")) { if (position.rightDown != null && position.rightDown.isAccessible()) { if (position.rightDown.playerOnTile != null) { throw new ProtocolException( "Player " + position.rightDown.playerOnTile.username + " is already on this tile."); } position.playerOnTile = null; position = position.rightDown; position.playerOnTile = this; return true; } else { throw Util.throwInaccessibleTileException("right-down", position.rightDown); } } else if (direction.equals("right-up")) { if (position.rightUp != null && position.rightUp.isAccessible()) { if (position.rightUp.playerOnTile != null) { throw new ProtocolException( "Player " + position.rightUp.playerOnTile.username + " is already on this tile."); } position.playerOnTile = null; position = position.rightUp; position.playerOnTile = this; return true; } else { throw Util.throwInaccessibleTileException("right-up", position.rightUp); } } else { throw new ProtocolException("Invalid direction: '" + direction + "'"); } } catch (JSONException e) { try { JSONObject errorMessage = new JSONObject().put("error", "Invalid move packet: " + e.getMessage()); sendMessage(errorMessage); } catch (JSONException f) { } catch (IOException g) { } return false; } catch (ProtocolException e) { try { JSONObject errorMessage = new JSONObject().put("error", "Invalid move packet: " + e.getMessage()); sendMessage(errorMessage); } catch (JSONException f) { } catch (IOException g) { } return false; } }