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 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 name of the message event to a placeObject that reports
* the winners and losers of a game. */ * the winners and losers of a game. */
public static final String WINNERS_AND_LOSERS = "winnersAndLosers"; 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.game.data.PartyGameConfig;
import com.threerings.parlor.server.ParlorSender; import com.threerings.parlor.server.ParlorSender;
import com.threerings.util.MessageBundle;
/** /**
* The game manager handles the server side management of a game. It * The game manager handles the server side management of a game. It
* manipulates the game state in accordance with the logic of the game * 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); 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 // documentation inherited
protected Class getPlaceObjectClass () protected Class getPlaceObjectClass ()
{ {
@@ -594,11 +616,22 @@ public class GameManager extends PlaceManager
*/ */
protected void handlePartialNoShow () protected void handlePartialNoShow ()
{ {
// cancel the game // mark the no-show players; this will cause allPlayersReady() to
if (_gameobj.state != GameObject.GAME_OVER && // think that everyone has arrived, but still allow us to tell who
_gameobj.state != GameObject.CANCELLED) { // has not shown up in gameDidStart()
_gameobj.setState(GameObject.CANCELLED); 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 // TEMP: clear out our game end tracker
_gameEndTracker.clear(); _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 // make sure everyone has turned up
if (!allPlayersReady()) { if (!allPlayersReady()) {
Log.warning("Requested to start a game that is still " + Log.warning("Requested to start a game that is still " +
@@ -735,6 +780,65 @@ public class GameManager extends PlaceManager
applyToDelegates(_tickAIOp); 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 * Called when the game is known to be over. This will call some
* calldown functions to determine the winner of the game and then * calldown functions to determine the winner of the game and then
@@ -124,46 +124,10 @@ public abstract class PuzzleManager extends GameManager
updateBoardSummary(pidx); updateBoardSummary(pidx);
} }
// go for a little transactional efficiency super.endPlayerGame(pidx);
_puzobj.startTransaction();
try {
// end the player's game
_puzobj.setPlayerStatusAt(GameObject.PLAYER_LEFT_GAME, pidx);
// let derived classes do some business // force a status update
playerGameDidEnd(pidx); updateStatus();
// 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)
{
} }
// documentation inherited // documentation inherited
@@ -195,27 +159,6 @@ public abstract class PuzzleManager extends GameManager
_puzobj.setPuzzleGameService(service); _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 // documentation inherited
protected void gameWillStart () protected void gameWillStart ()
{ {
@@ -294,17 +237,6 @@ public abstract class PuzzleManager extends GameManager
{ {
super.gameDidStart(); 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 // log the AI skill levels for games involving AIs as it's useful
// when tuning AI algorithms // when tuning AI algorithms
if (_AIs != null) { if (_AIs != null) {
@@ -417,26 +349,6 @@ public abstract class PuzzleManager extends GameManager
super.gameDidEnd(); 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 // documentation inherited
protected void didShutdown () 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 * Overrides the game manager implementation to mark all active
* players as winners. Derived classes may wish to override this * players as winners. Derived classes may wish to override this