partial fix to 'logged off players automatically win all matches in tourneys'

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3639 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Elizabeth Fong
2005-07-01 00:50:13 +00:00
parent a213847eea
commit e1338dca1e
3 changed files with 118 additions and 109 deletions
@@ -28,6 +28,13 @@ import com.threerings.presents.data.InvocationCodes;
*/
public interface GameCodes extends InvocationCodes
{
/** The message bundle identifier for general game messages. */
public static final String GAME_MESSAGE_BUNDLE = "game.general";
/** The name of the message event to a placeObject that a player
* was knocked out of a puzzle. */
public static final String PLAYER_KNOCKED_OUT = "playerKnocked";
/** The name of the message event to a placeObject that reports
* the winners and losers of a game. */
public static final String WINNERS_AND_LOSERS = "winnersAndLosers";
@@ -53,6 +53,8 @@ import com.threerings.parlor.game.data.GameObject;
import com.threerings.parlor.game.data.PartyGameConfig;
import com.threerings.parlor.server.ParlorSender;
import com.threerings.util.MessageBundle;
/**
* The game manager handles the server side management of a game. It
* manipulates the game state in accordance with the logic of the game
@@ -412,6 +414,26 @@ public class GameManager extends PlaceManager
SpeakProvider.sendInfo(_gameobj, msgbundle, msg);
}
/**
* Report to the knocked-out player's room that they were knocked out.
*/
protected void reportPlayerKnockedOut (int pidx)
{
BodyObject user = getPlayer(pidx);
if (user == null) {
// body object can be null for ai players
return;
}
OidList knocky = new OidList(1);
knocky.add(user.getOid());
DObject place = CrowdServer.omgr.getObject(user.location);
if (place != null) {
place.postMessage(PLAYER_KNOCKED_OUT, new Object[] { knocky });
}
}
// documentation inherited
protected Class getPlaceObjectClass ()
{
@@ -594,11 +616,22 @@ public class GameManager extends PlaceManager
*/
protected void handlePartialNoShow ()
{
// cancel the game
if (_gameobj.state != GameObject.GAME_OVER &&
_gameobj.state != GameObject.CANCELLED) {
_gameobj.setState(GameObject.CANCELLED);
// mark the no-show players; this will cause allPlayersReady() to
// think that everyone has arrived, but still allow us to tell who
// has not shown up in gameDidStart()
for (int ii = 0; ii < _playerOids.length; ii++) {
if (_playerOids[ii] == 0) {
_playerOids[ii] = -1;
}
}
// go ahead and start the game; gameDidStart() will take care of
// giving the boot to anyone who isn't around
Log.info("Forcing start of partial no-show game " +
"[game=" + _gameobj.which() +
", players=" + StringUtil.toString(_gameobj.players) +
", poids=" + StringUtil.toString(_playerOids) + "].");
startGame();
}
/**
@@ -626,6 +659,18 @@ public class GameManager extends PlaceManager
// TEMP: clear out our game end tracker
_gameEndTracker.clear();
// TODO: find the right place to put this
// 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++) {
if (_playerOids[ii] == -1) {
Log.info("Booting no-show player [game=" + _gameobj.which() +
", player=" + getPlayerName(ii) + "].");
_playerOids[ii] = 0; // unfiddle the blank oid
endPlayerGame(ii);
}
}
// make sure everyone has turned up
if (!allPlayersReady()) {
Log.warning("Requested to start a game that is still " +
@@ -735,6 +780,65 @@ public class GameManager extends PlaceManager
applyToDelegates(_tickAIOp);
}
/**
* Ends the game for the given player.
*/
public void endPlayerGame (int pidx)
{
// go for a little transactional efficiency
_gameobj.startTransaction();
try {
// end the player's game
if (_gameobj.playerStatus != null) {
_gameobj.setPlayerStatusAt(GameObject.PLAYER_LEFT_GAME, pidx);
// let derived classes do some business
playerGameDidEnd(pidx);
}
String message = MessageBundle.tcompose(
"m.player_game_over", getPlayerName(pidx));
systemMessage(GAME_MESSAGE_BUNDLE, message);
} finally {
_gameobj.commitTransaction();
}
// if it's time to end the game, then do so
if (shouldEndGame()) {
endGame();
} else {
// otherwise report that the player was knocked out to other
// people in his/her room
reportPlayerKnockedOut(pidx);
}
}
/**
* Called when a player has been marked as knocked out but before the
* knock-out status update has been sent to the players. Any status
* information that needs be updated in light of the knocked out
* player can be updated here.
*/
protected void playerGameDidEnd (int pidx)
{
}
/**
* Called when a player leaves the game in order to determine whether
* the game should be ended based on its current state, which will
* include updated player status for the player in question. The
* default implementation returns true if the game is in play and
* there is only one player left. Derived classes may wish to
* override this method in order to customize the required end-game
* conditions.
*/
protected boolean shouldEndGame ()
{
return (_gameobj.isInPlay() && _gameobj.getActivePlayerCount() == 1);
}
/**
* Called when the game is known to be over. This will call some
* calldown functions to determine the winner of the game and then
@@ -124,46 +124,10 @@ public abstract class PuzzleManager extends GameManager
updateBoardSummary(pidx);
}
// go for a little transactional efficiency
_puzobj.startTransaction();
try {
// end the player's game
_puzobj.setPlayerStatusAt(GameObject.PLAYER_LEFT_GAME, pidx);
super.endPlayerGame(pidx);
// let derived classes do some business
playerGameDidEnd(pidx);
// force a status update
updateStatus();
// notify the players
String message = MessageBundle.tcompose(
"m.player_game_over", getPlayerName(pidx));
systemMessage(PUZZLE_MESSAGE_BUNDLE, message);
} finally {
_puzobj.commitTransaction();
}
// if it's time to end the game, then do so
if (shouldEndGame()) {
endGame();
} else {
// otherwise report that the player was knocked out to other
// people in his/her room
reportPlayerKnockedOut(pidx);
}
}
/**
* Called when a player has been marked as knocked out but before the
* knock-out status update has been sent to the players. Any status
* information that needs be updated in light of the knocked out
* player can be updated here.
*/
protected void playerGameDidEnd (int pidx)
{
// force a status update
updateStatus();
}
// documentation inherited
@@ -195,27 +159,6 @@ public abstract class PuzzleManager extends GameManager
_puzobj.setPuzzleGameService(service);
}
// documentation inherited
protected void handlePartialNoShow ()
{
// mark the no-show players; this will cause allPlayersReady() to
// think that everyone has arrived, but still allow us to tell who
// has not shown up in gameDidStart()
for (int ii = 0; ii < _playerOids.length; ii++) {
if (_playerOids[ii] == 0) {
_playerOids[ii] = -1;
}
}
// go ahead and start the game; gameDidStart() will take care of
// giving the boot to anyone who isn't around
Log.info("Forcing start of partial no-show game " +
"[game=" + _puzobj.which() +
", players=" + StringUtil.toString(_puzobj.players) +
", poids=" + StringUtil.toString(_playerOids) + "].");
startGame();
}
// documentation inherited
protected void gameWillStart ()
{
@@ -294,17 +237,6 @@ public abstract class PuzzleManager extends GameManager
{
super.gameDidStart();
// 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++) {
if (_playerOids[ii] == -1) {
Log.info("Booting no-show player [game=" + _puzobj.which() +
", player=" + getPlayerName(ii) + "].");
_playerOids[ii] = 0; // unfiddle the blank oid
endPlayerGame(ii);
}
}
// log the AI skill levels for games involving AIs as it's useful
// when tuning AI algorithms
if (_AIs != null) {
@@ -417,26 +349,6 @@ public abstract class PuzzleManager extends GameManager
super.gameDidEnd();
}
/**
* Report to the knocked-out player's room that they were knocked out.
*/
protected void reportPlayerKnockedOut (int pidx)
{
BodyObject user = getPlayer(pidx);
if (user == null) {
// body object can be null for ai players
return;
}
OidList knocky = new OidList(1);
knocky.add(user.getOid());
DObject place = CrowdServer.omgr.getObject(user.location);
if (place != null) {
place.postMessage(PLAYER_KNOCKED_OUT, new Object[] { knocky });
}
}
// documentation inherited
protected void didShutdown ()
{
@@ -559,20 +471,6 @@ public abstract class PuzzleManager extends GameManager
}
}
/**
* Called when a player leaves the game in order to determine whether
* the game should be ended based on its current state, which will
* include updated player status for the player in question. The
* default implementation returns true if the game is in play and
* there is only one player left. Derived classes may wish to
* override this method in order to customize the required end-game
* conditions.
*/
protected boolean shouldEndGame ()
{
return (_puzobj.isInPlay() && _puzobj.getActivePlayerCount() == 1);
}
/**
* Overrides the game manager implementation to mark all active
* players as winners. Derived classes may wish to override this