use of soc.server.genericServer.Connection 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.server.genericServer.Connection in project JSettlers2 by jdmonin.
the class SOCGameMessageHandler method handlePICKRESOURCETYPE.
/**
* handle "pick resource type" (monopoly) message.
*<P>
* Before v2.0.00 this method was {@code handleMONOPOLYPICK}.
*
* @param c the connection that sent the message
* @param mes the message
* @since 1.0.0
*/
private void handlePICKRESOURCETYPE(SOCGame ga, Connection c, final SOCPickResourceType mes) {
ga.takeMonitor();
try {
final String gaName = ga.getName();
if (handler.checkTurn(c, ga)) {
if (ga.canDoMonopolyAction()) {
final int rsrc = mes.getResourceType();
final int[] monoPicks = ga.doMonopolyAction(rsrc);
final boolean[] isVictim = new boolean[ga.maxPlayers];
final String monoPlayerName = c.getData();
int monoTotal = 0;
for (int pn = 0; pn < ga.maxPlayers; ++pn) {
final int n = monoPicks[pn];
if (n > 0) {
monoTotal += n;
isVictim[pn] = true;
}
}
srv.gameList.takeMonitorForGame(gaName);
final SOCSimpleAction actMsg = new SOCSimpleAction(gaName, ga.getCurrentPlayerNumber(), SOCSimpleAction.RSRC_TYPE_MONOPOLIZED, monoTotal, rsrc);
if (ga.clientVersionLowest >= SOCStringManager.VERSION_FOR_I18N) {
srv.messageToGameWithMon(gaName, actMsg);
} else {
srv.messageToGameForVersions(ga, SOCStringManager.VERSION_FOR_I18N, Integer.MAX_VALUE, actMsg, false);
// Only pre-2.0.00 clients need this game text message. Since they're older than
// the i18n work: Always use english, send SOCGameTextMsg not SOCGameServerText.
final String monoTxt = monoPlayerName + " monopolized " + SOCStringManager.getFallbackServerManagerForClient().getSOCResourceCount(rsrc, monoTotal);
// "Joe monopolized 5 Sheep."
// If acting player's client is old, they'll see that instead of "You monopolized 5 sheep";
// that cosmetic change is OK.
srv.messageToGameForVersions(ga, -1, SOCStringManager.VERSION_FOR_I18N - 1, new SOCGameTextMsg(gaName, SOCGameTextMsg.SERVERNAME, monoTxt), false);
}
/**
* send each player's resource counts for the monopolized resource;
* set isNews flag for each victim player's count
*/
for (int pn = 0; pn < ga.maxPlayers; ++pn) {
/**
* Note: This works because SOCPlayerElement.CLAY == SOCResourceConstants.CLAY
*/
srv.messageToGameWithMon(gaName, new SOCPlayerElement(gaName, pn, SOCPlayerElement.SET, rsrc, ga.getPlayer(pn).getResources().getAmount(rsrc), isVictim[pn]));
}
srv.gameList.releaseMonitorForGame(gaName);
/**
* now that monitor is released, notify the
* victim(s) of resource amounts taken.
* Skip robot victims, they ignore text messages.
*/
for (int pn = 0; pn < ga.maxPlayers; ++pn) {
if (!isVictim[pn])
continue;
int picked = monoPicks[pn];
String viName = ga.getPlayer(pn).getName();
Connection viCon = srv.getConnection(viName);
if ((viCon != null) && !((SOCClientData) viCon.getAppData()).isRobot)
srv.messageToPlayerKeyedSpecial(viCon, ga, ((picked == 1) ? "action.mono.took.your.1" : "action.mono.took.your.n"), monoPlayerName, picked, rsrc);
// "Joe's Monopoly took your 3 sheep."
}
handler.sendGameState(ga);
} else {
srv.messageToPlayerKeyedSpecial(c, ga, "reply.playdevcard.cannot.now", SOCDevCardConstants.MONO);
// "You can't play a Monopoly card now." Before v2.0.00, was "You can't do a Monopoly pick now."
}
} else {
// "It's not your turn."
srv.messageToPlayerKeyed(c, gaName, "reply.not.your.turn");
}
} catch (Exception e) {
D.ebugPrintStackTrace(e, "Exception caught");
}
ga.releaseMonitor();
}
use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.
the class SOCChannelList method createChannel.
/**
* create a new channel. If channel already exists, do nothing.
*
* @param chName the name of the channel
* @param chOwner the game owner/creator's player name (added in 1.1.10)
* @throws NullPointerException if <tt>chOwner</tt> null
*/
public synchronized void createChannel(final String chName, final String chOwner) throws NullPointerException {
if (!isChannel(chName)) {
MutexFlag mutex = new MutexFlag();
channelMutexes.put(chName, mutex);
Vector<Connection> members = new Vector<Connection>();
channelMembers.put(chName, members);
// throws NullPointerException
channelOwners.put(chName, chOwner);
}
}
use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.
the class SOCServer method messageToGameWithMon.
/**
* Send a message to the given game.
*<P>
*<b>Locks:</b> MUST HAVE THE
* {@link SOCGameList#takeMonitorForGame(String) gameList.takeMonitorForGame(ga)}
* before calling this method.
*
* @param ga the name of the game
* @param mes the message to send
* @see #messageToGame(String, SOCMessage)
* @see #messageToGameKeyed(SOCGame, boolean, String)
* @see #messageToGameForVersions(SOCGame, int, int, SOCMessage, boolean)
*/
public void messageToGameWithMon(String ga, SOCMessage mes) {
Vector<Connection> v = gameList.getMembers(ga);
if (v == null)
return;
// D.ebugPrintln("M2G - "+mes);
final String mesCmd = mes.toCmd();
Enumeration<Connection> menum = v.elements();
while (menum.hasMoreElements()) {
Connection c = menum.nextElement();
if (c != null) {
// currentGameEventRecord.addMessageOut(new SOCMessageRecord(mes, "SERVER", c.getData()));
c.put(mesCmd);
}
}
}
use of soc.server.genericServer.Connection in project JSettlers2 by jdmonin.
the class SOCServer method messageToGameKeyedType.
/**
* Send a game a message containing data fields and also a text field to be localized.
* Same as {@link #messageToGame(String, SOCMessage)} but calls each member connection's
* {@link Connection#getLocalized(String) c.getLocalized(key)} for the localized text to send.
*<P>
* <B>Locks:</B> If {@code takeMon} is true, takes and releases
* {@link SOCGameList#takeMonitorForGame(String) gameList.takeMonitorForGame(gameName)}.
* Otherwise call {@link SOCGameList#takeMonitorForGame(String) gameList.takeMonitorForGame(gameName)}
* before calling this method.
*
* @param ga The game
* @param msg The data message to be sent after localizing text.
* This message object's fields are not changed here, the localization results are not kept with {@code msg}.
* @param takeMon Should this method take and release game's monitor via
* {@link SOCGameList#takeMonitorForGame(String) gameList.takeMonitorForGame(gameName)}?
* True unless caller already holds that monitor.
* @see #messageToGameKeyed(SOCGame, boolean, String)
* @see #messageToGameKeyed(SOCGame, boolean, String, Object...)
* @since 2.0.00
*/
public void messageToGameKeyedType(SOCGame ga, SOCKeyedMessage msg, final boolean takeMon) {
// Very similar code to impl_messageToGameKeyedSpecial:
// if you change code here, consider changing it there too
final boolean hasMultiLocales = ga.hasMultiLocales;
final String gaName = ga.getName();
boolean rsrcMissing = false;
if (takeMon)
gameList.takeMonitorForGame(gaName);
try {
Vector<Connection> v = gameList.getMembers(gaName);
if (v != null) {
Enumeration<Connection> menum = v.elements();
final String msgKey = msg.getKey();
// as rendered during prev. iter.
String gameLocalMsg = null, localText = null, gameTxtLocale = null;
while (menum.hasMoreElements()) {
Connection c = menum.nextElement();
if (c == null)
continue;
final String cliLocale = c.getI18NLocale();
if ((gameLocalMsg == null) || (hasMultiLocales && ((cliLocale == null) ? (gameTxtLocale != null) : !cliLocale.equals(gameTxtLocale)))) {
if (msgKey != null)
try {
localText = c.getLocalized(msgKey);
} catch (MissingResourceException e) {
// fallback so data fields will still be sent
localText = msgKey;
rsrcMissing = true;
}
gameLocalMsg = msg.toCmd(localText);
gameTxtLocale = cliLocale;
}
if (gameLocalMsg != null)
c.put(gameLocalMsg);
}
if (rsrcMissing)
D.ebugPrintln("Missing string key in messageToGameKeyedType: " + msgKey);
}
} catch (Throwable e) {
D.ebugPrintStackTrace(e, "Exception in messageToGameKeyedType");
}
if (takeMon)
gameList.releaseMonitorForGame(gaName);
}
Aggregations