use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.
the class SOCServerMessageHandler method processDebugCommand_who.
/**
* Process unprivileged command {@code *WHO*} to show members of current game,
* or privileged {@code *WHO* gameName|all|*} to show all connected clients or some other game's members.
*<P>
* <B>Locks:</B> Takes/releases {@link SOCGameList#takeMonitorForGame(String) gameList.takeMonitorForGame(gaName)}
* to call {@link SOCGameListAtServer#getMembers(String)}.
*
* @param c Client sending the *WHO* command
* @param ga Game in which the command was sent
* @param cmdText Text of *WHO* command
* @since 1.1.20
*/
private void processDebugCommand_who(final Connection c, final SOCGame ga, final String cmdText) {
// name of game where c is connected and sent *WHO* command
final String gaName = ga.getName();
// name of game to find members; if sendToCli, not equal to gaName
String gaNameWho = gaName;
// if true, send member list only to c instead of whole game
boolean sendToCli = false;
int i = cmdText.indexOf(' ');
if (i != -1) {
// look for a game name or */all
String gname = cmdText.substring(i + 1).trim();
if (gname.length() > 0) {
// Check if using user admins; if not, if using debug user
final String uname = c.getData();
boolean isAdmin = srv.isUserDBUserAdmin(uname);
if (!isAdmin)
isAdmin = (srv.isDebugUserEnabled() && uname.equals("debug"));
if (!isAdmin) {
srv.messageToPlayerKeyed(c, gaName, "reply.must_be_admin.view");
// "Must be an administrator to view that."
return;
}
sendToCli = true;
if (gname.equals("*") || gname.toUpperCase(Locale.US).equals("ALL")) {
// Instead of listing the game's members, list all connected clients.
// Build list of StringBuilder not String to do as little as possible
// inside synchronization block.
final ArrayList<StringBuilder> sbs = new ArrayList<StringBuilder>();
sbs.add(new StringBuilder(c.getLocalized("reply.who.conn_to_srv")));
// "Currently connected to server:"
final Integer nUnnamed = srv.getConnectedClientNames(sbs);
if (nUnnamed.intValue() != 0) {
StringBuilder sb = new StringBuilder("- ");
sb.append(c.getLocalized("reply.who.and_unnamed", nUnnamed));
// "and {0} unnamed connections"
sbs.add(sb);
}
for (StringBuilder sbb : sbs) srv.messageToPlayer(c, gaName, sbb.toString());
// <--- Early return; Not listing a game's members ---
return;
}
if (gameList.isGame(gname)) {
gaNameWho = gname;
} else {
// "Game not found."
srv.messageToPlayerKeyed(c, gaName, "reply.game.not.found");
return;
}
}
}
Vector<Connection> gameMembers = null;
gameList.takeMonitorForGame(gaNameWho);
try {
gameMembers = gameList.getMembers(gaNameWho);
if (!sendToCli)
// "This game's members:"
srv.messageToGameKeyed(ga, false, "reply.game_members.this");
} catch (Exception e) {
D.ebugPrintStackTrace(e, "Exception in *WHO* (gameMembers)");
}
gameList.releaseMonitorForGame(gaNameWho);
if (gameMembers == null) {
// unlikely since empty games are destroyed
return;
}
if (sendToCli)
// "Members of game {0}:"
srv.messageToPlayerKeyed(c, gaName, "reply.game_members.of", gaNameWho);
Enumeration<Connection> membersEnum = gameMembers.elements();
while (membersEnum.hasMoreElements()) {
Connection conn = membersEnum.nextElement();
String mNameStr = "> " + conn.getData();
if (sendToCli)
srv.messageToPlayer(c, gaName, mNameStr);
else
srv.messageToGame(gaName, mNameStr);
}
}
use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.
the class SOCServerMessageHandler method handleIMAROBOT.
/**
* Handle the "I'm a robot" message.
* Robots send their {@link SOCVersion} before sending this message.
* Their version is checked here, must equal server's version.
* For stability and control, the cookie in this message must
* match this server's {@link SOCServer#robotCookie}.
* Otherwise the bot is rejected and they're disconnected by calling
* {@link SOCServer#removeConnection(Connection, boolean)}.
*<P>
* Bot tuning parameters are sent here to the bot, from
* {@link SOCDBHelper#retrieveRobotParams(String, boolean) SOCDBHelper.retrieveRobotParams(botName, true)}.
* See that method for default bot params.
* See {@link SOCServer#authOrRejectClientRobot(Connection, String, String, String)}
* for {@link SOCClientData} flags and fields set for the bot's connection
* and for other misc work done, such as {@link Server#cliConnDisconPrintsPending} updates.
*<P>
* The server's built-in bots are named and started in {@link SOCServer#setupLocalRobots(int, int)},
* then must authenticate with this message just like external or third-party bots.
*
* @param c the connection that sent the message
* @param mes the message
* @since 1.0.0
*/
private void handleIMAROBOT(final Connection c, final SOCImARobot mes) {
if (c == null)
return;
final String botName = mes.getNickname();
final String rejectReason = srv.authOrRejectClientRobot(c, botName, mes.getCookie(), mes.getRBClass());
if (rejectReason != null) {
if (rejectReason.equals(SOCServer.MSG_NICKNAME_ALREADY_IN_USE))
c.put(SOCStatusMessage.toCmd(SOCStatusMessage.SV_NAME_IN_USE, c.getVersion(), rejectReason));
c.put(new SOCRejectConnection(rejectReason).toCmd());
c.disconnectSoft();
// make an effort to send reject message before closing socket
final Connection rc = c;
srv.miscTaskTimer.schedule(new TimerTask() {
public void run() {
srv.removeConnection(rc, true);
}
}, 300);
// <--- Early return: rejected ---
return;
}
//
// send the current robot parameters
//
SOCRobotParameters params = null;
try {
params = SOCDBHelper.retrieveRobotParams(botName, true);
// or srv.ROBOT_PARAMS_DEFAULT (SOCRobotDM.FAST_STRATEGY).
if ((params != null) && (params != SOCServer.ROBOT_PARAMS_SMARTER) && (params != SOCServer.ROBOT_PARAMS_DEFAULT) && D.ebugIsEnabled())
D.ebugPrintln("*** Robot Parameters for " + botName + " = " + params);
} catch (SQLException sqle) {
System.err.println("Error retrieving robot parameters from db: Using defaults.");
}
if (params == null)
// fallback in case of SQLException
params = SOCServer.ROBOT_PARAMS_DEFAULT;
c.put(SOCUpdateRobotParams.toCmd(params));
}
use of soc.server.genericServer.Connection 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.server.genericServer.Connection in project JSettlers2 by jdmonin.
the class SOCGameListAtServer method playerGamesMinVersion.
/**
* For the games this player is in, what's the
* minimum required client version?
* Checks {@link SOCGame#getClientVersionMinRequired()}.
*<P>
* This method helps determine if a client's connection can be
* "taken over" after a network problem. It synchronizes on <tt>gameData</tt>.
*
* @param plConn the previous connection of the player, which might be taken over
* @return Minimum version, in same format as {@link SOCGame#getClientVersionMinRequired()},
* or 0 if player isn't in any games.
* @since 1.1.08
*/
public int playerGamesMinVersion(Connection plConn) {
int minVers = 0;
synchronized (gameData) {
for (SOCGame ga : getGamesData()) {
Vector<Connection> members = getMembers(ga.getName());
if ((members == null) || !members.contains(plConn))
continue;
// plConn is a member of this game.
int vers = ga.getClientVersionMinRequired();
if (vers > minVers)
minVers = vers;
}
}
return minVers;
}
use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.
the class SOCGameListAtServer method removeMember.
/**
* remove member from the game.
* Also updates game's client version range, with remaining connected members.
* Please call {@link #takeMonitorForGame(String)} before calling this.
*
* @param gaName the name of the game
* @param conn the member's connection
*/
public synchronized void removeMember(Connection conn, String gaName) {
Vector<Connection> members = getMembers(gaName);
if ((members != null)) {
members.removeElement(conn);
// Check version of remaining members
if (!members.isEmpty()) {
Connection c = members.firstElement();
int lowVers = c.getVersion();
int highVers = lowVers;
for (int i = members.size() - 1; i >= 1; --i) {
c = members.elementAt(i);
int v = c.getVersion();
if (v < lowVers)
lowVers = v;
if (v > highVers)
highVers = v;
}
SOCGame ga = getGameData(gaName);
ga.clientVersionLowest = lowVers;
ga.clientVersionHighest = highVers;
ga.hasOldClients = (lowVers < Version.versionNumber());
}
}
}
Aggregations