use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCServerMessageHandler method handleSITDOWN.
/**
* handle "sit down" message
*
* @param c the connection that sent the message
* @param mes the message
* @since 1.0.0
*/
private void handleSITDOWN(Connection c, SOCSitDown mes) {
if (c == null)
return;
final String gaName = mes.getGame();
SOCGame ga = gameList.getGameData(gaName);
if (ga == null) {
// Out of date client info, or may be observing a deleted game.
// Already authenticated (c != null), so replying is OK by security.
// "Game not found."
srv.messageToPlayerKeyed(c, gaName, "reply.game.not.found");
// <--- Early return: No active game found ---
return;
}
/**
* make sure this player isn't already sitting
*/
boolean canSit = true;
boolean gameIsFull = false, gameAlreadyStarted = false;
/*
for (int i = 0; i < SOCGame.MAXPLAYERS; i++) {
if (ga.getPlayer(i).getName() == c.getData()) {
canSit = false;
break;
}
}
*/
// D.ebugPrintln("ga.isSeatVacant(mes.getPlayerNumber()) = "+ga.isSeatVacant(mes.getPlayerNumber()));
/**
* if this is a robot, remove it from the request list
*/
boolean isBotJoinRequest = false;
{
Hashtable<Connection, Object> joinRequests = srv.robotJoinRequests.get(gaName);
if (joinRequests != null)
isBotJoinRequest = (null != joinRequests.remove(c));
}
/**
* make sure a person isn't sitting here already;
* if a robot is sitting there, dismiss the robot.
* Can't sit at a vacant seat after everyone has
* placed 1st settlement+road (state >= START2A).
*
* If a human leaves after game is started, seat will appear vacant when the
* requested bot sits to replace them, so let the bot sit at that vacant seat.
*/
final int pn = mes.getPlayerNumber();
ga.takeMonitor();
try {
if (ga.isSeatVacant(pn)) {
gameAlreadyStarted = (ga.getGameState() >= SOCGame.START2A);
if (!gameAlreadyStarted)
gameIsFull = (1 > ga.getAvailableSeatCount());
if (gameIsFull || (gameAlreadyStarted && !isBotJoinRequest))
canSit = false;
} else {
SOCPlayer seatedPlayer = ga.getPlayer(pn);
if (seatedPlayer.isRobot() && (ga.getSeatLock(pn) != SOCGame.SeatLockState.LOCKED) && (ga.getCurrentPlayerNumber() != pn)) {
/**
* boot the robot out of the game
*/
Connection robotCon = srv.getConnection(seatedPlayer.getName());
robotCon.put(SOCRobotDismiss.toCmd(gaName));
/**
* this connection has to wait for the robot to leave
* and then it can sit down
*/
Vector<SOCReplaceRequest> disRequests = srv.robotDismissRequests.get(gaName);
SOCReplaceRequest req = new SOCReplaceRequest(c, robotCon, mes);
if (disRequests == null) {
disRequests = new Vector<SOCReplaceRequest>();
disRequests.addElement(req);
srv.robotDismissRequests.put(gaName, disRequests);
} else {
disRequests.addElement(req);
}
}
canSit = false;
}
} catch (Exception e) {
D.ebugPrintStackTrace(e, "Exception caught at handleSITDOWN");
}
ga.releaseMonitor();
// D.ebugPrintln("canSit 2 = "+canSit);
if (canSit) {
srv.sitDown(ga, c, pn, mes.isRobot(), false);
} else {
/**
* if the robot can't sit, tell it to go away.
* otherwise if game is full, tell the player.
*/
if (mes.isRobot()) {
c.put(SOCRobotDismiss.toCmd(gaName));
} else if (gameAlreadyStarted) {
srv.messageToPlayerKeyed(c, gaName, "member.sit.game.started");
// "This game has already started; to play you must take over a robot."
} else if (gameIsFull) {
srv.messageToPlayerKeyed(c, gaName, "member.sit.game.full");
// "This game is full; you cannot sit down."
}
}
}
use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCServerMessageHandler method handleLEAVEGAME_member.
/**
* Handle a member leaving the game, from
* {@link #handleLEAVEGAME(Connection, SOCLeaveGame)}.
* @since 1.1.07
*/
private void handleLEAVEGAME_member(Connection c, final String gaName) {
boolean gameDestroyed = false;
if (!gameList.takeMonitorForGame(gaName)) {
// <--- Early return: game not in gamelist ---
return;
}
try {
gameDestroyed = srv.leaveGame(c, gaName, true, false);
} catch (Exception e) {
D.ebugPrintStackTrace(e, "Exception in handleLEAVEGAME (leaveGame)");
}
gameList.releaseMonitorForGame(gaName);
if (gameDestroyed) {
srv.broadcast(SOCDeleteGame.toCmd(gaName));
} else {
/*
SOCLeaveGame leaveMessage = new SOCLeaveGame(c.getData(), c.host(), gaName);
messageToGame(gaName, leaveMessage);
recordGameEvent(gaName, leaveMessage);
*/
}
/**
* if it's a robot, remove it from the request list
*/
Vector<SOCReplaceRequest> requests = srv.robotDismissRequests.get(gaName);
if (requests != null) {
Enumeration<SOCReplaceRequest> reqEnum = requests.elements();
SOCReplaceRequest req = null;
while (reqEnum.hasMoreElements()) {
SOCReplaceRequest tempReq = reqEnum.nextElement();
if (tempReq.getLeaving() == c) {
req = tempReq;
break;
}
}
if (req != null) {
requests.removeElement(req);
/**
* Taking over a robot spot: let the person replacing the robot sit down
*/
SOCGame ga = gameList.getGameData(gaName);
final int pn = req.getSitDownMessage().getPlayerNumber();
final boolean isRobot = req.getSitDownMessage().isRobot();
if (!isRobot) {
// Don't keep the robot face icon
ga.getPlayer(pn).setFaceId(1);
}
srv.sitDown(ga, req.getArriving(), pn, isRobot, false);
}
}
}
use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCServerMessageHandler method handleRESETBOARDVOTE.
/**
* handle message of player's vote for a "reset-board" request.
* Register the player's vote with {@link SOCServer#resetBoardVoteNotifyOne(SOCGame, int, String, boolean)}.
* If all votes have now arrived and the vote is unanimous,
* resets the game to a copy with same name and players, new layout.
*
* @param c the connection
* @param mes the message
* @see #handleRESETBOARDREQUEST(Connection, SOCResetBoardRequest)
* @see SOCServer#resetBoardAndNotify(String, int)
* @since 1.1.00
*/
private void handleRESETBOARDVOTE(Connection c, final SOCResetBoardVote mes) {
final String gaName = mes.getGame();
SOCGame ga = gameList.getGameData(gaName);
if (ga == null)
return;
final String plName = c.getData();
SOCPlayer reqPlayer = ga.getPlayer(plName);
if (reqPlayer == null) {
// Not playing in that game (security)
return;
}
// Register this player's vote, and let game members know.
// If vote succeeded, go ahead and reset the game.
// If vote rejected, let everyone know.
srv.resetBoardVoteNotifyOne(ga, reqPlayer.getPlayerNumber(), plName, mes.getPlayerVote());
}
use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCServerMessageHandler method handleRESETBOARDREQUEST.
/**
* handle "reset-board request" message.
* If {@link SOCGame#getResetVoteActive()} already or {@link SOCPlayer#hasAskedBoardReset()} this turn,
* ignore. Otherwise: If multiple human players, start a vote with {@link SOCGame#resetVoteBegin(int)}.
* If requester is sole human player, reset the game to a copy with same name and (copy of) same players,
* new layout, by calling {@link SOCServer#resetBoardAndNotify(String, int)}.
*<P>
* The requesting player doesn't vote, but server still sends them a vote-request message to tell that client their
* request was accepted and voting has begun.
*<P>
* If only one player remains (all other humans have left at end), ask them to start a new game instead.
* This is a rare occurrence and we shouldn't bring in new robots and all,
* since we already have an interface to set up a game.
*<P>
* If any human player's client is too old to vote for reset, assume they vote Yes.
*
* @param c the connection
* @param mes the message
* @see #handleRESETBOARDVOTE(Connection, SOCResetBoardVote)
* @since 1.1.00
*/
private void handleRESETBOARDREQUEST(Connection c, final SOCResetBoardRequest mes) {
final String gaName = mes.getGame();
SOCGame ga = gameList.getGameData(gaName);
if (ga == null)
return;
SOCPlayer reqPlayer = ga.getPlayer(c.getData());
if (reqPlayer == null) {
// Not playing in that game (Security)
return;
}
/**
* Is voting already active from another player?
* Or, has this player already asked for voting this turn?
*/
if (ga.getResetVoteActive() || reqPlayer.hasAskedBoardReset()) {
// that would end the already-active round of voting.
return;
}
/**
* Is there more than one human player?
* Grab connection information for humans and robots.
*/
Connection[] humanConns = new Connection[ga.maxPlayers];
Connection[] robotConns = new Connection[ga.maxPlayers];
final int numHuman = SOCGameBoardReset.sortPlayerConnections(ga, null, gameList.getMembers(gaName), humanConns, robotConns);
final int reqPN = reqPlayer.getPlayerNumber();
if (numHuman < 2) {
// Are there robots? Go ahead and reset if so.
boolean hadRobot = false, hadUnlockedRobot = false;
for (int i = robotConns.length - 1; i >= 0; --i) {
if (robotConns[i] != null) {
hadRobot = true;
if (ga.getSeatLock(i) == SOCGame.SeatLockState.UNLOCKED) {
hadUnlockedRobot = true;
break;
}
}
}
if (hadUnlockedRobot) {
srv.resetBoardAndNotify(gaName, reqPN);
} else if (hadRobot) {
srv.messageToPlayerKeyed(c, gaName, "resetboard.request.unlock.bot");
// "Please unlock at least one bot, so you will have an opponent."
} else {
srv.messageToGameKeyed(ga, true, "resetboard.request.everyone.left");
// "Everyone has left this game. Please start a new game with players or bots."
}
} else {
// Probably put it to a vote.
gameList.takeMonitorForGame(gaName);
// First, Count number of other players who can vote (connected, version chk)
int votingPlayers = 0;
for (int i = ga.maxPlayers - 1; i >= 0; --i) {
if ((i != reqPN) && !ga.isSeatVacant(i)) {
Connection pc = srv.getConnection(ga.getPlayer(i).getName());
if ((pc != null) && pc.isConnected() && (pc.getVersion() >= 1100))
++votingPlayers;
}
}
if (votingPlayers == 0) {
// No one else is capable of voting.
// Reset the game immediately.
srv.messageToGameKeyed(ga, false, "resetboard.vote.request.alloldcli", c.getData());
// ">>> {0} is resetting the game - other connected players are unable to vote (client too old)."
gameList.releaseMonitorForGame(gaName);
srv.resetBoardAndNotify(gaName, reqPN);
} else {
// Put it to a vote
srv.messageToGameKeyed(ga, false, "resetboard.vote.request", c.getData());
// "requests a board reset - other players please vote."
String vrCmd = SOCResetBoardVoteRequest.toCmd(gaName, reqPN);
ga.resetVoteBegin(reqPN);
gameList.releaseMonitorForGame(gaName);
for (int i = 0; i < ga.maxPlayers; ++i) if (humanConns[i] != null)
if (humanConns[i].getVersion() >= 1100)
humanConns[i].put(vrCmd);
else
ga.resetVoteRegister(ga.getPlayer(humanConns[i].getData()).getPlayerNumber(), true);
}
}
}
use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCServerMessageHandler method handleSTARTGAME.
/**
* handle "start game" message. Game state must be NEW, or this message is ignored.
* {@link SOCServer#readyGameAskRobotsJoin(SOCGame, Connection[], int) Ask some robots} to fill
* empty seats, or {@link GameHandler#startGame(SOCGame) begin the game} if no robots needed.
*<P>
* Called when clients have sat at a new game and a client asks to start it,
* not called during game board reset.
*<P>
* For robot debugging, a client can start and observe a robots-only game if the
* {@link SOCServer#PROP_JSETTLERS_BOTS_BOTGAMES_TOTAL} property != 0 (including < 0).
*<P>
* Visibility is package-level, not private, so {@link SOCServer} can start robot-only games.
*
* @param c the connection that sent the message
* @param mes the message
* @param botsOnly_maxBots For bot debugging, maximum number of bots to add to the game,
* or 0 to fill all empty seats. This parameter is used only when requesting a new
* robots-only game using the *STARTBOTGAME* debug command; ignored otherwise.
* @since 1.0.0
*/
void handleSTARTGAME(Connection c, final SOCStartGame mes, final int botsOnly_maxBots) {
final String gn = mes.getGame();
SOCGame ga = gameList.getGameData(gn);
if (ga == null)
return;
ga.takeMonitor();
try {
if (ga.getGameState() == SOCGame.NEW) {
boolean allowStart = true;
boolean seatsFull = true;
boolean anyLocked = false;
int numEmpty = 0;
int numPlayers = 0;
//
for (int i = 0; i < ga.maxPlayers; i++) {
if (ga.isSeatVacant(i)) {
if (ga.getSeatLock(i) == SOCGame.SeatLockState.UNLOCKED) {
seatsFull = false;
++numEmpty;
} else {
anyLocked = true;
}
} else {
++numPlayers;
}
}
// Check vs max-players allowed in game (option "PL").
// Like seat locks, this can cause robots to be unwanted
// in otherwise-empty seats.
{
final int numAvail = ga.getAvailableSeatCount();
if (numAvail < numEmpty) {
numEmpty = numAvail;
if (numEmpty == 0)
seatsFull = true;
}
}
if (numPlayers == 0) {
if (0 == srv.getConfigIntProperty(SOCServer.PROP_JSETTLERS_BOTS_BOTGAMES_TOTAL, 0)) {
allowStart = false;
srv.messageToGameKeyed(ga, true, "start.player.must.sit");
// "To start the game, at least one player must sit down."
} else {
if ((botsOnly_maxBots != 0) && (botsOnly_maxBots < numEmpty))
numEmpty = botsOnly_maxBots;
}
}
if (seatsFull && (numPlayers < 2)) {
// Don't start the game; client must have more humans sit or unlock some seats for bots.
allowStart = false;
numEmpty = 3;
srv.messageToGameKeyed(ga, true, "start.only.cannot.lock.all");
// "The only player cannot lock all seats. To start the game, other players or robots must join."
} else if (allowStart && !seatsFull) {
// Look for some bots
final int numBots = srv.getRobotCount();
if (numBots == 0) {
if (numPlayers < SOCGame.MINPLAYERS)
srv.messageToGameKeyed(ga, true, "start.no.robots.on.server", SOCGame.MINPLAYERS);
else
// "No robots on this server, please fill at least {0} seats before starting."
// Enough players to start game.
seatsFull = true;
} else {
//
if (numEmpty > numBots) {
final String m;
if (anyLocked)
m = "start.not.enough.robots";
else
// "Not enough robots to fill all the seats. Only {0} robots are available."
m = "start.not.enough.robots.lock";
// "Not enough robots to fill all the seats. Lock some seats. Only {0} robots are available."
srv.messageToGameKeyed(ga, true, m, numBots);
} else {
ga.setGameState(SOCGame.READY);
/**
* Fill all the unlocked empty seats with robots.
* Build a Vector of Connections of robots asked
* to join, and add it to the robotJoinRequests table.
*/
try {
srv.readyGameAskRobotsJoin(ga, null, numEmpty);
} catch (IllegalStateException e) {
System.err.println("Robot-join problem in game " + gn + ": " + e);
// recover, so that human players can still start a game
ga.setGameState(SOCGame.NEW);
allowStart = false;
gameList.takeMonitorForGame(gn);
srv.messageToGameKeyed(ga, false, "start.robots.cannot.join.problem", e.getMessage());
// "Sorry, robots cannot join this game: {0}"
srv.messageToGameKeyed(ga, false, "start.to.start.without.robots");
// "To start the game without robots, lock all empty seats."
gameList.releaseMonitorForGame(gn);
}
}
}
}
/**
* If this doesn't need robots, then start the game.
* Otherwise wait for them to sit before starting the game.
*/
if (seatsFull && allowStart) {
GameHandler hand = gameList.getGameTypeHandler(gn);
if (hand != null)
hand.startGame(ga);
}
}
} catch (Throwable e) {
D.ebugPrintStackTrace(e, "Exception caught");
}
ga.releaseMonitor();
}
Aggregations