Make it possible for a player to report in when they arrive in a room but not

cause the game to start. In Whirled we'll have all players report in
immediately for games that want to handle playerReady() themselves so that they
can do whatever they want before the game starts and then finally start it with
a call to playerReady() from all the players.


git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@417 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Michael Bayne
2007-08-24 23:40:21 +00:00
parent 74665f1663
commit 5392df8770
@@ -24,6 +24,7 @@ package com.threerings.parlor.game.server;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.logging.Level;
import com.samskivert.util.ArrayIntSet; import com.samskivert.util.ArrayIntSet;
import com.samskivert.util.IntListUtil; import com.samskivert.util.IntListUtil;
@@ -47,7 +48,6 @@ import com.threerings.crowd.server.CrowdServer;
import com.threerings.crowd.server.PlaceManager; import com.threerings.crowd.server.PlaceManager;
import com.threerings.crowd.server.PlaceManagerDelegate; import com.threerings.crowd.server.PlaceManagerDelegate;
import com.threerings.parlor.Log;
import com.threerings.parlor.data.ParlorCodes; import com.threerings.parlor.data.ParlorCodes;
import com.threerings.parlor.game.data.GameAI; import com.threerings.parlor.game.data.GameAI;
import com.threerings.parlor.game.data.GameCodes; import com.threerings.parlor.game.data.GameCodes;
@@ -57,6 +57,8 @@ import com.threerings.parlor.server.ParlorSender;
import com.threerings.util.MessageBundle; import com.threerings.util.MessageBundle;
import static com.threerings.parlor.Log.log;
/** /**
* The game manager handles the server side management of a game. It manipulates the game state in * The game manager handles the server side management of a game. It manipulates the game state in
* accordance with the logic of the game flow and generally manages the whole game playing process. * accordance with the logic of the game flow and generally manages the whole game playing process.
@@ -125,7 +127,7 @@ public class GameManager extends PlaceManager
// sanity-check the player index // sanity-check the player index
if (pidx == -1) { if (pidx == -1) {
Log.warning("Couldn't find free player index for player [game=" + where() + log.warning("Couldn't find free player index for player [game=" + where() +
", player=" + player + ", player=" + player +
", players=" + StringUtil.toString(_gameobj.players) + "]."); ", players=" + StringUtil.toString(_gameobj.players) + "].");
return -1; return -1;
@@ -147,14 +149,14 @@ public class GameManager extends PlaceManager
{ {
// make sure the specified player index is valid // make sure the specified player index is valid
if (pidx < 0 || pidx >= getPlayerSlots()) { if (pidx < 0 || pidx >= getPlayerSlots()) {
Log.warning("Attempt to add player at an invalid index [game=" + where() + log.warning("Attempt to add player at an invalid index [game=" + where() +
", player=" + player + ", pidx=" + pidx + "]."); ", player=" + player + ", pidx=" + pidx + "].");
return false; return false;
} }
// make sure the player index is available // make sure the player index is available
if (_gameobj.players[pidx] != null) { if (_gameobj.players[pidx] != null) {
Log.warning("Attempt to add player at occupied index [game=" + where() + log.warning("Attempt to add player at occupied index [game=" + where() +
", player=" + player + ", pidx=" + pidx + "]."); ", player=" + player + ", pidx=" + pidx + "].");
return false; return false;
} }
@@ -162,7 +164,7 @@ public class GameManager extends PlaceManager
// make sure the player isn't already somehow a part of the game to avoid any potential // make sure the player isn't already somehow a part of the game to avoid any potential
// badness that might ensue if we added them more than once // badness that might ensue if we added them more than once
if (_gameobj.getPlayerIndex(player) != -1) { if (_gameobj.getPlayerIndex(player) != -1) {
Log.warning("Attempt to add player to game that they're already playing " + log.warning("Attempt to add player to game that they're already playing " +
"[game=" + where() + ", player=" + player + "]."); "[game=" + where() + ", player=" + player + "].");
return false; return false;
} }
@@ -170,7 +172,7 @@ public class GameManager extends PlaceManager
// get the player's body object // get the player's body object
BodyObject bobj = CrowdServer.lookupBody(player); BodyObject bobj = CrowdServer.lookupBody(player);
if (bobj == null) { if (bobj == null) {
Log.warning("Unable to get body object while adding player [game=" + where() + log.warning("Unable to get body object while adding player [game=" + where() +
", player=" + player + "]."); ", player=" + player + "].");
return false; return false;
} }
@@ -205,7 +207,7 @@ public class GameManager extends PlaceManager
// sanity-check the player index // sanity-check the player index
if (pidx == -1) { if (pidx == -1) {
Log.warning("Attempt to remove non-player from players list [game=" + where() + log.warning("Attempt to remove non-player from players list [game=" + where() +
", player=" + player + ", player=" + player +
", players=" + StringUtil.toString(_gameobj.players) + "]."); ", players=" + StringUtil.toString(_gameobj.players) + "].");
return false; return false;
@@ -420,7 +422,7 @@ public class GameManager extends PlaceManager
{ {
// complain if we're already started // complain if we're already started
if (_gameobj.state == GameObject.IN_PLAY) { if (_gameobj.state == GameObject.IN_PLAY) {
Log.warning("Requested to start an already in-play game [game=" + where() + "]."); log.warning("Requested to start an already in-play game [game=" + where() + "].");
Thread.dumpStack(); Thread.dumpStack();
return false; return false;
} }
@@ -430,7 +432,7 @@ public class GameManager extends PlaceManager
// make sure everyone has turned up // make sure everyone has turned up
if (!allPlayersReady()) { if (!allPlayersReady()) {
Log.warning("Requested to start a game that is still awaiting players " + log.warning("Requested to start a game that is still awaiting players " +
"[game=" + where() + ", pnames=" + StringUtil.toString(_gameobj.players) + "[game=" + where() + ", pnames=" + StringUtil.toString(_gameobj.players) +
", poids=" + StringUtil.toString(_playerOids) + "]."); ", poids=" + StringUtil.toString(_playerOids) + "].");
return false; return false;
@@ -442,12 +444,12 @@ public class GameManager extends PlaceManager
if (_postponedStart) { if (_postponedStart) {
// We've already tried postponing once, doesn't do us any good to throw ourselves // We've already tried postponing once, doesn't do us any good to throw ourselves
// into a frenzy trying again. // into a frenzy trying again.
Log.warning("Tried to postpone the start of a still-ending game multiple times " + log.warning("Tried to postpone the start of a still-ending game multiple times " +
"[game=" + where() + "]."); "[game=" + where() + "].");
_postponedStart = false; _postponedStart = false;
return false; return false;
} }
Log.info("Postponing start of still-ending game [game=" + where() + "]."); log.info("Postponing start of still-ending game [game=" + where() + "].");
_postponedStart = true; _postponedStart = true;
// TEMP: track down weirdness // TEMP: track down weirdness
final Exception firstCall = new Exception(); final Exception firstCall = new Exception();
@@ -457,8 +459,7 @@ public class GameManager extends PlaceManager
boolean result = startGame(); boolean result = startGame();
// TEMP: track down weirdness // TEMP: track down weirdness
if (!result && !_postponedStart) { if (!result && !_postponedStart) {
Log.warning("First call to startGame: "); log.log(Level.WARNING, "First call to startGame: ", firstCall);
Log.logStackTrace(firstCall);
} }
// End: temp // End: temp
} }
@@ -523,7 +524,7 @@ public class GameManager extends PlaceManager
// END TEMP // END TEMP
if (!_gameobj.isInPlay()) { if (!_gameobj.isInPlay()) {
Log.info("Refusing to end game that was not in play [game=" + where() + "]."); log.info("Refusing to end game that was not in play [game=" + where() + "].");
return; return;
} }
@@ -591,26 +592,30 @@ public class GameManager extends PlaceManager
} }
/** /**
* Called by the client when the player is ready for the game to start. This method is * Called by the client when the player has arrived in the game room and has loaded their
* dispatched dynamically by {@link #messageReceived}. * bits. Most games will simply call {@link #playerReady} but games that wish to delay their
* actual start until players take some action must report ASAP with a call to {@link
* #playerInRoom} to let the server know that they have arrived and will later be calling
* {@link #playerReady} when they are ready for the game to actually start.
*/ */
public void playerReady (BodyObject caller) public void playerInRoom (BodyObject caller)
{ {
// get the user's player index
int pidx = _gameobj.getPlayerIndex(caller.getVisibleName()); int pidx = _gameobj.getPlayerIndex(caller.getVisibleName());
if (pidx == -1) { if (pidx == -1) {
// only complain if this is not a party game, since it's perfectly normal to receive a
// player ready notification from a user entering a party game in which they're not yet
// a participant
if (needsNoShowTimer()) {
Log.warning("Received playerReady() from non-player? [game=" + where() +
", who=" + caller.who() + "].");
}
return; return;
} }
// make a note of this player's oid // make a note of this player's oid
_playerOids[pidx] = caller.getOid(); _playerOids[pidx] = caller.getOid();
}
/**
* Called by the client when the player is ready for the game to start. This method is
* dispatched dynamically by {@link #messageReceived}.
*/
public void playerReady (BodyObject caller)
{
playerInRoom(caller);
// if everyone is now ready to go, get things underway // if everyone is now ready to go, get things underway
if (allPlayersReady()) { if (allPlayersReady()) {
@@ -775,7 +780,7 @@ public class GameManager extends PlaceManager
BodyObject bobj = CrowdServer.lookupBody(_gameobj.players[ii]); BodyObject bobj = CrowdServer.lookupBody(_gameobj.players[ii]);
if (bobj == null) { if (bobj == null) {
Log.warning("Unable to deliver game ready to non-existent player [game=" + where() + log.warning("Unable to deliver game ready to non-existent player [game=" + where() +
", player=" + _gameobj.players[ii] + "]."); ", player=" + _gameobj.players[ii] + "].");
continue; continue;
} }
@@ -836,7 +841,7 @@ public class GameManager extends PlaceManager
*/ */
protected void placeBecameEmpty () protected void placeBecameEmpty ()
{ {
// Log.info("Game room empty. Going away. [game=" + where() + "]."); // log.info("Game room empty. Going away. [game=" + where() + "].");
// if we're in play then move to game over // if we're in play then move to game over
if (_gameobj.state != GameObject.PRE_GAME && _gameobj.state != GameObject.GAME_OVER && if (_gameobj.state != GameObject.PRE_GAME && _gameobj.state != GameObject.GAME_OVER &&
@@ -878,7 +883,7 @@ public class GameManager extends PlaceManager
// if there's no one in the room, go ahead and clear it out // if there's no one in the room, go ahead and clear it out
if (_plobj.occupants.size() == 0) { if (_plobj.occupants.size() == 0) {
Log.info("Cancelling total no-show [game=" + where() + log.info("Cancelling total no-show [game=" + where() +
", players=" + StringUtil.toString(_gameobj.players) + ", players=" + StringUtil.toString(_gameobj.players) +
", poids=" + StringUtil.toString(_playerOids) + "]."); ", poids=" + StringUtil.toString(_playerOids) + "].");
placeBecameEmpty(); placeBecameEmpty();
@@ -913,14 +918,14 @@ public class GameManager extends PlaceManager
if ((humansHere == 0) && !startWithoutHumans()) { if ((humansHere == 0) && !startWithoutHumans()) {
// if there are no human players in the game, just cancel it // if there are no human players in the game, just cancel it
Log.info("Canceling no-show game [game=" + where() + log.info("Canceling no-show game [game=" + where() +
", players=" + StringUtil.toString(_playerOids) + "]."); ", players=" + StringUtil.toString(_playerOids) + "].");
cancelGame(); cancelGame();
} else { } else {
// go ahead and report that everyone is ready (which will start the game); // go ahead and report that everyone is ready (which will start the game);
// gameDidStart() will take care of giving the boot to anyone who isn't around // gameDidStart() will take care of giving the boot to anyone who isn't around
Log.info("Forcing start of partial no-show game [game=" + where() + log.info("Forcing start of partial no-show game [game=" + where() +
", poids=" + StringUtil.toString(_playerOids) + "]."); ", poids=" + StringUtil.toString(_playerOids) + "].");
playersAllHere(); playersAllHere();
} }
@@ -1023,7 +1028,7 @@ public class GameManager extends PlaceManager
// any players who have not claimed that they are ready should now be given le boote royale // any players who have not claimed that they are ready should now be given le boote royale
for (int ii = 0; ii < _playerOids.length; ii++) { for (int ii = 0; ii < _playerOids.length; ii++) {
if (_playerOids[ii] == -1) { if (_playerOids[ii] == -1) {
Log.info("Booting no-show player [game=" + where() + log.info("Booting no-show player [game=" + where() +
", player=" + getPlayerName(ii) + "]."); ", player=" + getPlayerName(ii) + "].");
_playerOids[ii] = 0; // unfiddle the blank oid _playerOids[ii] = 0; // unfiddle the blank oid
endPlayerGame(ii); endPlayerGame(ii);
@@ -1234,8 +1239,7 @@ public class GameManager extends PlaceManager
try { try {
gmgr.tick(now); gmgr.tick(now);
} catch (Exception e) { } catch (Exception e) {
Log.warning("Game manager choked during tick [gmgr=" + gmgr + "]."); log.log(Level.WARNING, "Game manager choked during tick [gmgr=" + gmgr + "].", e);
Log.logStackTrace(e);
} }
} }
} }