use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCGameListAtServer method createGame.
/**
* create a new game, and add to the list; game will expire in {@link #GAME_TIME_EXPIRE_MINUTES} minutes.
* If a game already exists (per {@link #isGame(String)}), do nothing.
*
* @param gaName the name of the game
* @param gaOwner the game owner/creator's player name, or null (added in 1.1.10)
* @param gaLocaleStr the game creator's locale, to later set {@link SOCGame#hasMultiLocales} if needed (added in 2.0.00)
* @param gaOpts if game has options, its {@link SOCGameOption}s; otherwise null.
* Must already be validated, by calling
* {@link SOCGameOption#adjustOptionsToKnown(Map, Map, boolean)}
* with <tt>doServerPreadjust</tt> true.
* That call is also needed to add any {@code "SC"} options into {@code gaOpts}.
* @param handler Game type handler for this game
* @return new game object, or null if it already existed
* @throws IllegalArgumentException if {@code handler} is null
*/
public synchronized SOCGame createGame(final String gaName, final String gaOwner, final String gaLocaleStr, final Map<String, SOCGameOption> gaOpts, final GameHandler handler) throws IllegalArgumentException {
if (isGame(gaName))
return null;
if (handler == null)
throw new IllegalArgumentException("handler");
// Double-check class in case server is started at client after a client SOCGame.
if ((SOCGame.boardFactory == null) || !(SOCGame.boardFactory instanceof SOCBoardAtServer.BoardFactoryAtServer))
SOCGame.boardFactory = new SOCBoardAtServer.BoardFactoryAtServer();
Vector<Connection> members = new Vector<Connection>();
gameMembers.put(gaName, members);
SOCGame game = new SOCGame(gaName, gaOpts);
if (gaOwner != null)
game.setOwner(gaOwner, gaLocaleStr);
// set the expiration to 90 min. from now
game.setExpiration(game.getStartTime().getTime() + (60 * 1000 * GAME_TIME_EXPIRE_MINUTES));
// also creates MutexFlag
gameInfo.put(gaName, new GameInfoAtServer(game.getGameOptions(), handler));
gameData.put(gaName, game);
return game;
}
use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCGameListAtServer method addMember.
/**
* add a member to the game.
* Also checks client's version against game's current range of client versions.
* Please call {@link #takeMonitorForGame(String)} before calling this.
*
* @param gaName the name of the game
* @param conn the member's connection; version should already be set
*/
public synchronized void addMember(Connection conn, String gaName) {
Vector<Connection> members = getMembers(gaName);
if ((members != null) && (!members.contains(conn))) {
final boolean firstMember = members.isEmpty();
members.addElement(conn);
// Check version range
SOCGame ga = getGameData(gaName);
final int cliVers = conn.getVersion();
if (firstMember) {
ga.clientVersionLowest = cliVers;
ga.clientVersionHighest = cliVers;
ga.hasOldClients = (cliVers < Version.versionNumber());
} else {
final int cliLowestAlready = ga.clientVersionLowest;
final int cliHighestAlready = ga.clientVersionHighest;
if (cliVers < cliLowestAlready) {
ga.clientVersionLowest = cliVers;
if (cliVers < Version.versionNumber())
ga.hasOldClients = true;
}
if (cliVers > cliHighestAlready) {
ga.clientVersionHighest = cliVers;
}
}
if (!ga.hasMultiLocales) {
final String gaLocale = ga.getOwnerLocale();
if (gaLocale != null) {
final SOCClientData scd = (SOCClientData) conn.getAppData();
if ((scd != null) && (scd.localeStr != null) && !gaLocale.equals(scd.localeStr))
// client's locale differs from other game members'
ga.hasMultiLocales = true;
}
}
}
}
use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCGameListAtServer method memberGames.
/**
* List of games containing this member.
*
* @param c Connection
* @param firstGameName Game name that should be first element of list
* (if <tt>newConn</tt> is a member of it), or null.
* @return The games, in no particular order (past firstGameName),
* or a 0-length Vector, if member isn't in any game.
*
* @see #replaceMemberAllGames(Connection, Connection)
* @since 1.1.08
*/
public List<SOCGame> memberGames(Connection c, final String firstGameName) {
List<SOCGame> cGames = new ArrayList<SOCGame>();
synchronized (gameData) {
SOCGame firstGame = null;
if (firstGameName != null) {
firstGame = getGameData(firstGameName);
if (firstGame != null) {
Vector<?> members = getMembers(firstGameName);
if ((members != null) && members.contains(c))
cGames.add(firstGame);
}
}
for (SOCGame ga : getGamesData()) {
if (ga == firstGame)
continue;
Vector<?> members = getMembers(ga.getName());
if ((members == null) || !members.contains(c))
continue;
cGames.add(ga);
}
}
return cGames;
}
use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCGameMessageHandler method handleROLLDICE.
// / Roll dice and pick resources ///
/**
* handle "roll dice" message.
*
* @param c the connection that sent the message
* @param mes the message
* @since 1.0.0
*/
private void handleROLLDICE(SOCGame ga, Connection c, final SOCRollDice mes) {
final String gn = ga.getName();
ga.takeMonitor();
try {
final String plName = c.getData();
final SOCPlayer pl = ga.getPlayer(plName);
if ((pl != null) && ga.canRollDice(pl.getPlayerNumber())) {
/**
* Roll dice, distribute resources in game
*/
SOCGame.RollResult roll = ga.rollDice();
/**
* Send roll results and then text to client.
* Note that only the total is sent, not the 2 individual dice.
* (Only the _SC_PIRI scenario cares about them indivdually, and
* in that case it prints the result when needed.)
*
* If a 7 is rolled, sendGameState will also say who must discard
* (in a GAMETEXTMSG).
* If a gold hex is rolled, sendGameState will also say who
* must pick resources to gain (in a GAMETEXTMSG).
*/
srv.messageToGame(gn, new SOCDiceResult(gn, ga.getCurrentDice()));
if (ga.clientVersionLowest < SOCGameTextMsg.VERSION_FOR_DICE_RESULT_INSTEAD) {
// backwards-compat: this text message is redundant to v2.0.00 and newer clients
// because they print the roll results from SOCDiceResult. Use SOCGameTextMsg
// because pre-2.0.00 clients don't understand SOCGameServerText messages.
srv.messageToGameForVersions(ga, 0, SOCGameTextMsg.VERSION_FOR_DICE_RESULT_INSTEAD - 1, new SOCGameTextMsg(gn, SOCGameTextMsg.SERVERNAME, // I18N
plName + " rolled a " + roll.diceA + " and a " + roll.diceB + "."), true);
}
// For 7, give visual feedback before sending discard request
handler.sendGameState(ga);
if (ga.isGameOptionSet(SOCGameOption.K_SC_PIRI)) {
// pirate moves on every roll
srv.messageToGame(gn, new SOCMoveRobber(gn, ga.getCurrentPlayerNumber(), -(((SOCBoardLarge) ga.getBoard()).getPirateHex())));
if (roll.sc_piri_fleetAttackVictim != null) {
final SOCResourceSet loot = roll.sc_piri_fleetAttackRsrcs;
final int lootTotal = (loot != null) ? loot.getTotal() : 0;
if (lootTotal != 0) {
// use same resource-loss messages sent in handleDISCARD
final boolean won = (loot.contains(SOCResourceConstants.GOLD_LOCAL));
SOCPlayer vic = roll.sc_piri_fleetAttackVictim;
final String vicName = vic.getName();
final Connection vCon = srv.getConnection(vicName);
final int vpn = vic.getPlayerNumber();
final int strength = (roll.diceA < roll.diceB) ? roll.diceA : roll.diceB;
if (won) {
srv.messageToGameKeyed(ga, true, "action.rolled.sc_piri.player.won.pick.free", vicName, strength);
// "{0} won against the pirate fleet (strength {1}) and will pick a free resource."
} else {
/**
* tell the victim client that the player lost the resources
*/
handler.reportRsrcGainLoss(gn, loot, true, true, vpn, -1, null, vCon);
srv.messageToPlayerKeyedSpecial(vCon, ga, "action.rolled.sc_piri.you.lost.rsrcs.to.fleet", loot, strength);
// "You lost {0,rsrcs} to the pirate fleet (strength {1,number})."
/**
* tell everyone else that the player lost unknown resources
*/
srv.messageToGameExcept(gn, vCon, new SOCPlayerElement(gn, vpn, SOCPlayerElement.LOSE, SOCPlayerElement.UNKNOWN, lootTotal), true);
srv.messageToGameKeyedSpecialExcept(ga, true, vCon, "action.rolled.sc_piri.player.lost.rsrcs.to.fleet", vicName, lootTotal, strength);
// "Joe lost 1 resource to pirate fleet attack (strength 3)." or
// "Joe lost 3 resources to pirate fleet attack (strength 3)."
}
}
}
}
/**
* if the roll is not 7, tell players what they got
* (if 7, sendGameState already told them what they lost).
*/
if (ga.getCurrentDice() != 7) {
boolean noPlayersGained = true;
/**
* Clients v2.0.00 and newer get an i18n-neutral SOCDiceResultResources message.
* Older clients get a string such as "Joe gets 3 sheep. Mike gets 1 clay."
*/
String rollRsrcTxtOldCli = null;
SOCDiceResultResources rollRsrcMsgNewCli = null;
if (ga.clientVersionHighest >= SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES) {
rollRsrcMsgNewCli = SOCDiceResultResources.buildForGame(ga);
noPlayersGained = (rollRsrcMsgNewCli == null);
}
if (ga.clientVersionLowest < SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES) {
// Build a string to announce to v1.x.xx clients
StringBuffer gainsText = new StringBuffer();
// for string spacing; might be false due to loop for new clients in game
noPlayersGained = true;
for (int pn = 0; pn < ga.maxPlayers; ++pn) {
if (!ga.isSeatVacant(pn)) {
SOCPlayer pp = ga.getPlayer(pn);
SOCResourceSet rsrcs = pp.getRolledResources();
if (rsrcs.getKnownTotal() != 0) {
if (noPlayersGained)
noPlayersGained = false;
else
gainsText.append(" ");
gainsText.append(c.getLocalizedSpecial(ga, "_nolocaliz.roll.gets.resources", pp.getName(), rsrcs));
// "{0} gets {1,rsrcs}."
// get it from any connection's StringManager, because that string is never localized
// Announce SOCPlayerElement.GAIN messages
handler.reportRsrcGainLoss(gn, rsrcs, false, false, pn, -1, null, null);
}
}
}
if (!noPlayersGained)
rollRsrcTxtOldCli = gainsText.toString();
}
if (noPlayersGained) {
String key;
if (roll.cloth == null)
// "No player gets anything."
key = "action.rolled.no.player.gets.anything";
else
// "No player gets resources."
key = "action.rolled.no.player.gets.resources";
// debug_printPieceDiceNumbers(ga, message);
srv.messageToGameKeyed(ga, true, key);
} else {
if (rollRsrcTxtOldCli == null)
srv.messageToGame(gn, rollRsrcMsgNewCli);
else if (rollRsrcMsgNewCli == null)
srv.messageToGame(gn, rollRsrcTxtOldCli);
else {
// neither is null: we have old and new clients
srv.messageToGameForVersions(ga, 0, (SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES - 1), new SOCGameTextMsg(gn, SOCGameTextMsg.SERVERNAME, rollRsrcTxtOldCli), true);
srv.messageToGameForVersions(ga, SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES, Integer.MAX_VALUE, rollRsrcMsgNewCli, true);
}
//
for (int pn = 0; pn < ga.maxPlayers; ++pn) {
final SOCPlayer pp = ga.getPlayer(pn);
Connection playerCon = srv.getConnection(pp.getName());
if (playerCon == null)
continue;
if (pp.getRolledResources().getKnownTotal() == 0)
// skip if player didn't gain; before v2.0.00 each player in game got these
continue;
// send CLAY, ORE, SHEEP, WHEAT, WOOD even if player's amount is 0
final SOCResourceSet resources = pp.getResources();
final int[] counts = resources.getAmounts(false);
if (playerCon.getVersion() >= SOCPlayerElements.MIN_VERSION)
srv.messageToPlayer(playerCon, new SOCPlayerElements(gn, pn, SOCPlayerElement.SET, SOCGameHandler.ELEM_RESOURCES, counts));
else
for (int i = 0; i < counts.length; ++i) srv.messageToPlayer(playerCon, new SOCPlayerElement(gn, pn, SOCPlayerElement.SET, SOCGameHandler.ELEM_RESOURCES[i], counts[i]));
if (ga.clientVersionLowest < SOCDiceResultResources.VERSION_FOR_DICERESULTRESOURCES)
srv.messageToGame(gn, new SOCResourceCount(gn, pn, resources.getTotal()));
// else, already-sent SOCDiceResultResources included players' new resource totals
// we'll send gold picks text, PLAYERELEMENT, and SIMPLEREQUEST(PROMPT_PICK_RESOURCES)
// after the per-player loop
}
}
if (roll.cloth != null) {
// Send village cloth trade distribution
final int coord = roll.cloth[1];
final SOCBoardLarge board = (SOCBoardLarge) (ga.getBoard());
SOCVillage vi = board.getVillageAtNode(coord);
if (vi != null)
srv.messageToGame(gn, new SOCPieceValue(gn, coord, vi.getCloth(), 0));
if (roll.cloth[0] > 0)
// some taken from board general supply
srv.messageToGame(gn, new SOCPlayerElement(gn, -1, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_CLOTH_COUNT, board.getCloth()));
// name of first player to receive cloth
String clplName = null;
// names of all players receiving cloth, if more than one
ArrayList<String> clpls = null;
for (int i = 2; i < roll.cloth.length; ++i) {
if (roll.cloth[i] == 0)
// this player didn't receive cloth
continue;
final int pn = i - 2;
final SOCPlayer clpl = ga.getPlayer(pn);
srv.messageToGame(gn, new SOCPlayerElement(gn, pn, SOCPlayerElement.SET, SOCPlayerElement.SCENARIO_CLOTH_COUNT, clpl.getCloth()));
if (clplName == null) {
// first pl to receive cloth
clplName = clpl.getName();
} else {
// second or further player
if (clpls == null) {
clpls = new ArrayList<String>();
clpls.add(clplName);
}
clpls.add(clpl.getName());
}
}
if (clpls == null)
srv.messageToGameKeyed(ga, true, "action.rolled.sc_clvi.received.cloth.1", clplName);
else
// "{0} received 1 cloth from a village."
srv.messageToGameKeyedSpecial(ga, true, "action.rolled.sc_clvi.received.cloth.n", clpls);
// "{0,list} each received 1 cloth from a village."
}
if (ga.getGameState() == SOCGame.WAITING_FOR_PICK_GOLD_RESOURCE)
// gold picks text, PLAYERELEMENT, and SIMPLEREQUEST(PROMPT_PICK_RESOURCES)s
handler.sendGameState_sendGoldPickAnnounceText(ga, gn, null, roll);
/*
if (D.ebugOn) {
for (int i=0; i < SOCGame.MAXPLAYERS; i++) {
SOCResourceSet rsrcs = ga.getPlayer(i).getResources();
String resourceMessage = "PLAYER "+i+" RESOURCES: ";
resourceMessage += rsrcs.getAmount(SOCResourceConstants.CLAY)+" ";
resourceMessage += rsrcs.getAmount(SOCResourceConstants.ORE)+" ";
resourceMessage += rsrcs.getAmount(SOCResourceConstants.SHEEP)+" ";
resourceMessage += rsrcs.getAmount(SOCResourceConstants.WHEAT)+" ";
resourceMessage += rsrcs.getAmount(SOCResourceConstants.WOOD)+" ";
resourceMessage += rsrcs.getAmount(SOCResourceConstants.UNKNOWN)+" ";
messageToGame(gn, new SOCGameTextMsg(gn, SERVERNAME, resourceMessage));
}
}
*/
} else {
/**
* player rolled 7
* If anyone needs to discard, prompt them.
*/
if (ga.getGameState() == SOCGame.WAITING_FOR_DISCARDS) {
handler.sendGameState_sendDiscardRequests(ga, gn);
} else if (ga.getGameState() == SOCGame.WAITING_FOR_PICK_GOLD_RESOURCE) {
// Used in _SC_PIRI, when 7 is rolled and a player wins against the pirate fleet
for (int pn = 0; pn < ga.maxPlayers; ++pn) {
final SOCPlayer pp = ga.getPlayer(pn);
final int numPick = pp.getNeedToPickGoldHexResources();
if ((!ga.isSeatVacant(pn)) && (numPick > 0)) {
Connection con = srv.getConnection(pp.getName());
if (con != null) {
srv.messageToGame(gn, new SOCPlayerElement(gn, pn, SOCPlayerElement.SET, SOCPlayerElement.NUM_PICK_GOLD_HEX_RESOURCES, numPick));
con.put(SOCSimpleRequest.toCmd(gn, pn, SOCSimpleRequest.PROMPT_PICK_RESOURCES, numPick, 0));
}
}
}
}
}
} else {
srv.messageToPlayer(c, gn, "You can't roll right now.");
}
} catch (Exception e) {
D.ebugPrintStackTrace(e, "Exception caught at handleROLLDICE" + e);
}
ga.releaseMonitor();
}
use of soc.game.SOCGame in project JSettlers2 by jdmonin.
the class SOCRobotClient method handleRESETBOARDAUTH.
/**
* handle board reset
* (new game with same players, same game name).
* Destroy old Game object.
* Unlike <tt>SOCDisplaylessPlayerClient.handleRESETBOARDAUTH</tt>, don't call {@link SOCGame#resetAsCopy()}.
*<P>
* Take robotbrain out of old game, don't yet put it in new game.
* Let server know we've done so, by sending LEAVEGAME via {@link #leaveGame(SOCGame, String, boolean, boolean)}.
* Server will soon send a BOTJOINGAMEREQUEST if we should join the new game.
*
* @param mes the message
*
* @see soc.server.SOCServer#resetBoardAndNotify(String, int)
* @see #handleBOTJOINGAMEREQUEST(SOCBotJoinGameRequest)
*/
@Override
protected void handleRESETBOARDAUTH(SOCResetBoardAuth mes) {
D.ebugPrintln("**** handleRESETBOARDAUTH ****");
String gname = mes.getGame();
SOCGame ga = games.get(gname);
if (ga == null)
// Not one of our games
return;
SOCRobotBrain brain = robotBrains.get(gname);
if (brain != null)
brain.kill();
// Same as in handleROBOTDISMISS
leaveGame(ga, "resetboardauth", false, false);
ga.destroyGame();
}
Aggregations