The table system now supports the party game types better.

The creator of a party game isn't joining, but I think that's a problem
with the msoy client...


git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@168 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Ray Greenwell
2007-02-10 01:36:06 +00:00
parent e6c3bc3dd2
commit 729335a4a5
8 changed files with 189 additions and 80 deletions
@@ -29,6 +29,10 @@ public class EZGameConfig extends GameConfig
// For now, the configData is either a classname or url. // For now, the configData is either a classname or url.
public var configData :String; public var configData :String;
// TODO: this is separate right now, but may eventually be extracted
// from configData? Do not read this value, use getPartyGameType()
public var partyGameType :int = PartyGameCodes.NOT_PARTY_GAME;
/** If non-zero, a game id used to persistently identify the game. /** If non-zero, a game id used to persistently identify the game.
* This could be thought of as a new-style rating id. */ * This could be thought of as a new-style rating id. */
public var persistentGameId:int; public var persistentGameId:int;
@@ -68,8 +72,7 @@ public class EZGameConfig extends GameConfig
// from PartyGameConfig // from PartyGameConfig
public function getPartyGameType () :int public function getPartyGameType () :int
{ {
// TODO return partyGameType;
return PartyGameCodes.NOT_PARTY_GAME;
} }
override public function hashCode () :int override public function hashCode () :int
@@ -93,6 +96,7 @@ public class EZGameConfig extends GameConfig
super.readObject(ins); super.readObject(ins);
configData = (ins.readField(String) as String); configData = (ins.readField(String) as String);
partyGameType = ins.readByte();
persistentGameId = ins.readInt(); persistentGameId = ins.readInt();
} }
@@ -102,6 +106,7 @@ public class EZGameConfig extends GameConfig
super.writeObject(out); super.writeObject(out);
out.writeField(configData); out.writeField(configData);
out.writeByte(partyGameType);
out.writeInt(persistentGameId); out.writeInt(persistentGameId);
} }
} }
+30 -21
View File
@@ -65,7 +65,15 @@ public class Table
/** The body oids of the occupants of this table, or null if a party game. /** The body oids of the occupants of this table, or null if a party game.
* (This is not propagated to remote instances.) */ * (This is not propagated to remote instances.) */
public var bodyOids :TypedArray; public /*transient*/ var bodyOids :TypedArray;
/** For a running game, the total number of players. For FFA party games,
* this is everyone. */
public var playerCount :int;
/** For a running game, the total number of watchers. For FFA party games,
* this is always 0. */
public var watcherCount :int;
/** The game config for the game that is being matchmade. */ /** The game config for the game that is being matchmade. */
public var config :GameConfig; public var config :GameConfig;
@@ -84,9 +92,11 @@ public class Table
public function getOccupiedCount () :int public function getOccupiedCount () :int
{ {
var count :int = 0; var count :int = 0;
for (var ii :int = 0; ii < occupants.length; ii++) { if (occupants != null) {
if (occupants[ii] != null) { for (var ii :int = 0; ii < occupants.length; ii++) {
count++; if (occupants[ii] != null) {
count++;
}
} }
} }
return count; return count;
@@ -101,10 +111,6 @@ public class Table
*/ */
public function getPlayers () :Array public function getPlayers () :Array
{ {
if (isPartyGame()) {
return occupants;
}
// create and populate the players array // create and populate the players array
var players :Array = new Array(); var players :Array = new Array();
for (var ii :int = 0; ii < occupants.length; ii++) { for (var ii :int = 0; ii < occupants.length; ii++) {
@@ -288,7 +294,8 @@ public class Table
*/ */
public function shouldBeStarted () :Boolean public function shouldBeStarted () :Boolean
{ {
return tconfig.desiredPlayerCount <= getOccupiedCount(); return isPartyGame() ||
(tconfig.desiredPlayerCount <= getOccupiedCount());
} }
/** /**
@@ -332,18 +339,18 @@ public class Table
return tableId; return tableId;
} }
/** // /**
* Returns true if there is no one sitting at this table. // * Returns true if there is no one sitting at this table.
*/ // */
public function isEmpty () :Boolean // public function isEmpty () :Boolean
{ // {
for (var ii :int = 0; ii < bodyOids.length; ii++) { // for (var ii :int = 0; ii < bodyOids.length; ii++) {
if ((bodyOids[ii] as int) !== 0) { // if ((bodyOids[ii] as int) !== 0) {
return false; // return false;
} // }
} // }
return true; // return true;
} // }
// from Streamable // from Streamable
public function readObject (ins :ObjectInputStream) :void public function readObject (ins :ObjectInputStream) :void
@@ -352,6 +359,8 @@ public class Table
lobbyOid = ins.readInt(); lobbyOid = ins.readInt();
gameOid = ins.readInt(); gameOid = ins.readInt();
occupants = (ins.readObject() as TypedArray); occupants = (ins.readObject() as TypedArray);
playerCount = ins.readShort();
watcherCount = ins.readShort();
config = (ins.readObject() as GameConfig); config = (ins.readObject() as GameConfig);
tconfig = (ins.readObject() as TableConfig); tconfig = (ins.readObject() as TableConfig);
} }
@@ -32,9 +32,9 @@ import com.threerings.io.TypedArray;
*/ */
public class TableConfig extends SimpleStreamableObject public class TableConfig extends SimpleStreamableObject
{ {
/** The total number of players that are desired for the table, /** The total number of players that are desired for the table.
* or -1 for a party game. For team games, this should be set to the * For team games, this should be set to the total number of players
* total number of players overall, as teams may be unequal. */ * overall, as teams may be unequal. */
public var desiredPlayerCount :int; public var desiredPlayerCount :int;
/** The minimum number of players needed overall (or per-team if a /** The minimum number of players needed overall (or per-team if a
@@ -24,6 +24,10 @@ public class EZGameConfig extends GameConfig
// For now, the configData is either a classname or url. // For now, the configData is either a classname or url.
public String configData; public String configData;
// TODO: this is separate right now, but may eventually be extracted
// from configData? Do not read this value, use getPartyGameType()
public byte partyGameType = NOT_PARTY_GAME;
/** If non-zero, a game id used to persistently identify the game. /** If non-zero, a game id used to persistently identify the game.
* This could be thought of as a new-style rating id. */ * This could be thought of as a new-style rating id. */
public int persistentGameId; public int persistentGameId;
@@ -62,8 +66,7 @@ public class EZGameConfig extends GameConfig
// from PartyGameConfig // from PartyGameConfig
public byte getPartyGameType () public byte getPartyGameType ()
{ {
// TODO return partyGameType;
return NOT_PARTY_GAME;
} }
@Override @Override
@@ -424,6 +424,7 @@ public class EZGameManager extends GameManager
@Override @Override
protected void didShutdown () protected void didShutdown ()
{ {
System.err.println("didShutdown!");
CrowdServer.invmgr.clearDispatcher(_gameObj.ezGameService); CrowdServer.invmgr.clearDispatcher(_gameObj.ezGameService);
stopTickers(); stopTickers();
+38 -19
View File
@@ -62,6 +62,14 @@ public class Table
* (This is not propagated to remote instances.) */ * (This is not propagated to remote instances.) */
public transient int[] bodyOids; public transient int[] bodyOids;
/** For a running game, the total number of players. For FFA party games,
* this is everyone. */
public short playerCount;
/** For a running game, the total number of watchers. For FFA party games,
* this is always 0. */
public short watcherCount;
/** The game config for the game that is being matchmade. */ /** The game config for the game that is being matchmade. */
public GameConfig config; public GameConfig config;
@@ -98,7 +106,7 @@ public class Table
this.config = config; this.config = config;
// make room for the maximum number of players // make room for the maximum number of players
if (tconfig.desiredPlayerCount != -1) { if (!isPartyGame()) {
occupants = new Name[tconfig.desiredPlayerCount]; occupants = new Name[tconfig.desiredPlayerCount];
bodyOids = new int[occupants.length]; bodyOids = new int[occupants.length];
@@ -130,9 +138,11 @@ public class Table
public int getOccupiedCount () public int getOccupiedCount ()
{ {
int count = 0; int count = 0;
for (int ii = 0; ii < occupants.length; ii++) { if (occupants != null) {
if (occupants[ii] != null) { for (int ii = 0; ii < occupants.length; ii++) {
count++; if (occupants[ii] != null) {
count++;
}
} }
} }
return count; return count;
@@ -147,15 +157,19 @@ public class Table
*/ */
public Name[] getPlayers () public Name[] getPlayers ()
{ {
if (isPartyGame()) { // seated party games need a spot for every seat
return occupants; if (PartyGameConfig.SEATED_PARTY_GAME == getPartyGameType()) {
return new Name[tconfig.desiredPlayerCount];
} }
// create and populate the players array // FFA party games have 0-length players array, and non-party
// games will have the players who are ready-to-go for the game start.
Name[] players = new Name[getOccupiedCount()]; Name[] players = new Name[getOccupiedCount()];
for (int ii = 0, dex = 0; ii < occupants.length; ii++) { if (occupants != null) {
if (occupants[ii] != null) { for (int ii = 0, dex = 0; ii < occupants.length; ii++) {
players[dex++] = occupants[ii]; if (occupants[ii] != null) {
players[dex++] = occupants[ii];
}
} }
} }
@@ -262,10 +276,12 @@ public class Table
*/ */
public boolean clearOccupant (Name username) public boolean clearOccupant (Name username)
{ {
for (int i = 0; i < occupants.length; i++) { if (occupants != null) {
if (username.equals(occupants[i])) { for (int i = 0; i < occupants.length; i++) {
clearOccupantPos(i); if (username.equals(occupants[i])) {
return true; clearOccupantPos(i);
return true;
}
} }
} }
return false; return false;
@@ -281,10 +297,12 @@ public class Table
*/ */
public boolean clearOccupantByOid (int bodyOid) public boolean clearOccupantByOid (int bodyOid)
{ {
for (int i = 0; i < bodyOids.length; i++) { if (bodyOids != null) {
if (bodyOid == bodyOids[i]) { for (int i = 0; i < bodyOids.length; i++) {
clearOccupantPos(i); if (bodyOid == bodyOids[i]) {
return true; clearOccupantPos(i);
return true;
}
} }
} }
return false; return false;
@@ -334,7 +352,8 @@ public class Table
*/ */
public boolean shouldBeStarted () public boolean shouldBeStarted ()
{ {
return tconfig.desiredPlayerCount <= getOccupiedCount(); return isPartyGame() ||
(tconfig.desiredPlayerCount <= getOccupiedCount());
} }
/** /**
@@ -29,9 +29,9 @@ import com.threerings.io.SimpleStreamableObject;
*/ */
public class TableConfig extends SimpleStreamableObject public class TableConfig extends SimpleStreamableObject
{ {
/** The total number of players that are desired for the table, /** The total number of players that are desired for the table.
* or -1 for a party game. For team games, this should be set to the * For team games, this should be set to the total number of players
* total number of players overall, as teams may be unequal. */ * overall, as teams may be unequal. */
public int desiredPlayerCount; public int desiredPlayerCount;
/** The minimum number of players needed overall (or per-team if a /** The minimum number of players needed overall (or per-team if a
@@ -29,12 +29,14 @@ import com.samskivert.util.StringUtil;
import com.threerings.util.Name; import com.threerings.util.Name;
import com.threerings.presents.dobj.ChangeListener; import com.threerings.presents.dobj.ChangeListener;
import com.threerings.presents.dobj.NamedEvent;
import com.threerings.presents.dobj.ObjectAddedEvent; import com.threerings.presents.dobj.ObjectAddedEvent;
import com.threerings.presents.dobj.ObjectDeathListener; import com.threerings.presents.dobj.ObjectDeathListener;
import com.threerings.presents.dobj.ObjectDestroyedEvent; import com.threerings.presents.dobj.ObjectDestroyedEvent;
import com.threerings.presents.dobj.ObjectRemovedEvent; import com.threerings.presents.dobj.ObjectRemovedEvent;
import com.threerings.presents.dobj.OidListListener; import com.threerings.presents.dobj.OidListListener;
import com.threerings.presents.server.InvocationException; import com.threerings.presents.server.InvocationException;
import com.threerings.presents.server.PresentsServer;
import com.threerings.crowd.data.BodyObject; import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.data.PlaceObject; import com.threerings.crowd.data.PlaceObject;
@@ -126,29 +128,38 @@ public class TableManager
} }
table.init(_plobj.getOid(), tableConfig, config); table.init(_plobj.getOid(), tableConfig, config);
// stick the creator into the first non-AI position boolean isParty = table.isPartyGame();
int cpos = (config.ais == null) ? 0 : config.ais.length; if (!isParty) {
String error = table.setOccupant(cpos, creator); // stick the creator into the first non-AI position
if (error != null) { int cpos = (config.ais == null) ? 0 : config.ais.length;
Log.warning("Unable to add creator to position zero of " + String error = table.setOccupant(cpos, creator);
"table!? [table=" + table + ", creator=" + creator + if (error != null) {
", error=" + error + "]."); Log.warning("Unable to add creator to position zero of " +
// bail out now and abort the table creation process "table!? [table=" + table + ", creator=" + creator +
throw new InvocationException(error); ", error=" + error + "].");
// bail out now and abort the table creation process
throw new InvocationException(error);
}
// make a mapping from the creator to this table
_boidMap.put(creator.getOid(), table);
} }
// stick the table into the table lobby object // stick the table into the table lobby object
_tlobj.addToTables(table); _tlobj.addToTables(table);
// make a mapping from the creator to this table
_boidMap.put(creator.getOid(), table);
// also stick it into our tables tables // also stick it into our tables tables
_tables.put(table.tableId, table); _tables.put(table.tableId, table);
// if the table has only one seat, start the game immediately // if the table has only one seat, start the game immediately
if (table.shouldBeStarted()) { if (table.shouldBeStarted()) {
createGame(table); int oid = createGame(table);
// the creator will not be moved automatically, so we do it for them
if (isParty) {
System.err.println("Trying to move creator");
CrowdServer.plreg.locprov.moveBody(creator, oid);
}
} }
// finally let the caller know what the new table id is // finally let the caller know what the new table id is
@@ -295,6 +306,9 @@ public class TableManager
_boidMap.remove(table.bodyOids[i]); _boidMap.remove(table.bodyOids[i]);
} }
// remove the mapping by gameOid
_goidMap.remove(table.gameOid); // no-op if gameOid == 0
// remove the table from the lobby object // remove the table from the lobby object
_tlobj.removeFromTables(table.tableId); _tlobj.removeFromTables(table.tableId);
} }
@@ -303,8 +317,10 @@ public class TableManager
* Called when we're ready to create a game (either an invitation has * Called when we're ready to create a game (either an invitation has
* been accepted or a table is ready to start. If there is a problem * been accepted or a table is ready to start. If there is a problem
* creating the game manager, it should be reported in the logs. * creating the game manager, it should be reported in the logs.
*
* @return the oid of the newly-created game.
*/ */
protected void createGame (final Table table) protected int createGame (final Table table)
throws InvocationException throws InvocationException
{ {
// fill the players array into the game config // fill the players array into the game config
@@ -312,7 +328,10 @@ public class TableManager
try { try {
PlaceManager pmgr = CrowdServer.plreg.createPlace(table.config); PlaceManager pmgr = CrowdServer.plreg.createPlace(table.config);
gameCreated(table, (GameObject)pmgr.getPlaceObject()); GameObject gobj = (GameObject) pmgr.getPlaceObject();
gameCreated(table, gobj);
return gobj.getOid();
} catch (Throwable t) { } catch (Throwable t) {
Log.warning("Failed to create manager for game " + Log.warning("Failed to create manager for game " +
"[config=" + table.config + "]: " + t); "[config=" + table.config + "]: " + t);
@@ -329,17 +348,22 @@ public class TableManager
// update the table with the newly created game object // update the table with the newly created game object
table.gameOid = gameobj.getOid(); table.gameOid = gameobj.getOid();
// add it to the gameOid map
_goidMap.put(table.gameOid, table);
// configure the privacy of the game // configure the privacy of the game
gameobj.setIsPrivate(table.tconfig.privateTable); gameobj.setIsPrivate(table.tconfig.privateTable);
// clear the occupant to table mappings as this game is underway if (!table.isPartyGame()) {
for (int i = 0; i < table.bodyOids.length; i++) { // clear the occupant to table mappings as this game is underway
_boidMap.remove(table.bodyOids[i]); for (int i = 0; i < table.bodyOids.length; i++) {
_boidMap.remove(table.bodyOids[i]);
}
} }
// add an object death listener to unmap the table when the game // add an object death listener to unmap the table when the game
// finally goes away // finally goes away
gameobj.addListener(_gameDeathListener); gameobj.addListener(_gameListener);
// and then update the lobby object that contains the table // and then update the lobby object that contains the table
_tlobj.updateTables(table); _tlobj.updateTables(table);
@@ -351,16 +375,36 @@ public class TableManager
*/ */
protected void unmapTable (int gameOid) protected void unmapTable (int gameOid)
{ {
// look through our tables table for a table with a matching game Table table = _goidMap.get(gameOid);
for (Table table : _tables.values()) { if (table != null) {
if (table.gameOid == gameOid) { purgeTable(table);
purgeTable(table);
return; // all done } else {
} Log.warning("Requested to unmap table that wasn't mapped " +
"[gameOid=" + gameOid + "].");
}
}
/**
* Called when the occupants in a game change: publish new info.
*/
protected void updateOccupants (int gameOid)
{
Table table = _goidMap.get(gameOid);
if (table == null) {
Log.warning("Unable to find table for running game " +
"[gameOid=" + gameOid + "].");
return;
} }
Log.warning("Requested to unmap table that wasn't mapped " + GameObject gameObj = (GameObject) PresentsServer.omgr.getObject(gameOid);
"[gameOid=" + gameOid + "]."); table.watcherCount = (short) gameObj.occupants.size();
// TODO: this will become more complicated
// As we separate watchers and players
// finally, update the table
_tlobj.updateTables(table);
} }
// documentation inherited // documentation inherited
@@ -415,10 +459,38 @@ public class TableManager
/** A mapping from body oid to table. */ /** A mapping from body oid to table. */
protected HashIntMap<Table> _boidMap = new HashIntMap<Table>(); protected HashIntMap<Table> _boidMap = new HashIntMap<Table>();
/** A listener that prunes tables after the game dies. */ /** Once a game starts, a mapping from gameOid to table. */
protected ChangeListener _gameDeathListener = new ObjectDeathListener() { protected HashIntMap<Table> _goidMap = new HashIntMap<Table>();
/** Listens to all games and updates the table objects as necessary. */
protected class GameListener
implements ObjectDeathListener, OidListListener
{
// from ObjectDeathListener
public void objectDestroyed (ObjectDestroyedEvent event) { public void objectDestroyed (ObjectDestroyedEvent event) {
unmapTable(event.getTargetOid()); unmapTable(event.getTargetOid());
} }
};
// from OidListListener
public void objectAdded (ObjectAddedEvent event) {
maybeCheckOccupants(event);
}
// from OidListListener
public void objectRemoved (ObjectRemovedEvent event) {
maybeCheckOccupants(event);
}
/**
* Check to see if the set event causes us to update the table.
*/
protected void maybeCheckOccupants (NamedEvent event) {
if (GameObject.OCCUPANTS.equals(event.getName())) {
updateOccupants(event.getTargetOid());
}
}
} // END: class GameDeathListener
/** A listener that prunes tables after the game dies. */
protected ChangeListener _gameListener = new GameListener();
} }