diff --git a/src/as/com/threerings/ezgame/data/EZGameConfig.as b/src/as/com/threerings/ezgame/data/EZGameConfig.as index f8a1a44f..c32d1535 100644 --- a/src/as/com/threerings/ezgame/data/EZGameConfig.as +++ b/src/as/com/threerings/ezgame/data/EZGameConfig.as @@ -29,6 +29,10 @@ public class EZGameConfig extends GameConfig // For now, the configData is either a classname or url. 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. * This could be thought of as a new-style rating id. */ public var persistentGameId:int; @@ -68,8 +72,7 @@ public class EZGameConfig extends GameConfig // from PartyGameConfig public function getPartyGameType () :int { - // TODO - return PartyGameCodes.NOT_PARTY_GAME; + return partyGameType; } override public function hashCode () :int @@ -93,6 +96,7 @@ public class EZGameConfig extends GameConfig super.readObject(ins); configData = (ins.readField(String) as String); + partyGameType = ins.readByte(); persistentGameId = ins.readInt(); } @@ -102,6 +106,7 @@ public class EZGameConfig extends GameConfig super.writeObject(out); out.writeField(configData); + out.writeByte(partyGameType); out.writeInt(persistentGameId); } } diff --git a/src/as/com/threerings/parlor/data/Table.as b/src/as/com/threerings/parlor/data/Table.as index abdba0d9..940f241c 100644 --- a/src/as/com/threerings/parlor/data/Table.as +++ b/src/as/com/threerings/parlor/data/Table.as @@ -65,7 +65,15 @@ public class Table /** The body oids of the occupants of this table, or null if a party game. * (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. */ public var config :GameConfig; @@ -84,9 +92,11 @@ public class Table public function getOccupiedCount () :int { var count :int = 0; - for (var ii :int = 0; ii < occupants.length; ii++) { - if (occupants[ii] != null) { - count++; + if (occupants != null) { + for (var ii :int = 0; ii < occupants.length; ii++) { + if (occupants[ii] != null) { + count++; + } } } return count; @@ -101,10 +111,6 @@ public class Table */ public function getPlayers () :Array { - if (isPartyGame()) { - return occupants; - } - // create and populate the players array var players :Array = new Array(); for (var ii :int = 0; ii < occupants.length; ii++) { @@ -288,7 +294,8 @@ public class Table */ public function shouldBeStarted () :Boolean { - return tconfig.desiredPlayerCount <= getOccupiedCount(); + return isPartyGame() || + (tconfig.desiredPlayerCount <= getOccupiedCount()); } /** @@ -332,18 +339,18 @@ public class Table return tableId; } - /** - * Returns true if there is no one sitting at this table. - */ - public function isEmpty () :Boolean - { - for (var ii :int = 0; ii < bodyOids.length; ii++) { - if ((bodyOids[ii] as int) !== 0) { - return false; - } - } - return true; - } +// /** +// * Returns true if there is no one sitting at this table. +// */ +// public function isEmpty () :Boolean +// { +// for (var ii :int = 0; ii < bodyOids.length; ii++) { +// if ((bodyOids[ii] as int) !== 0) { +// return false; +// } +// } +// return true; +// } // from Streamable public function readObject (ins :ObjectInputStream) :void @@ -352,6 +359,8 @@ public class Table lobbyOid = ins.readInt(); gameOid = ins.readInt(); occupants = (ins.readObject() as TypedArray); + playerCount = ins.readShort(); + watcherCount = ins.readShort(); config = (ins.readObject() as GameConfig); tconfig = (ins.readObject() as TableConfig); } diff --git a/src/as/com/threerings/parlor/data/TableConfig.as b/src/as/com/threerings/parlor/data/TableConfig.as index 4b54a1fc..cfc4c706 100644 --- a/src/as/com/threerings/parlor/data/TableConfig.as +++ b/src/as/com/threerings/parlor/data/TableConfig.as @@ -32,9 +32,9 @@ import com.threerings.io.TypedArray; */ public class TableConfig extends SimpleStreamableObject { - /** 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 - * total number of players overall, as teams may be unequal. */ + /** The total number of players that are desired for the table. + * For team games, this should be set to the total number of players + * overall, as teams may be unequal. */ public var desiredPlayerCount :int; /** The minimum number of players needed overall (or per-team if a diff --git a/src/java/com/threerings/ezgame/data/EZGameConfig.java b/src/java/com/threerings/ezgame/data/EZGameConfig.java index 759248ee..80e8c52b 100644 --- a/src/java/com/threerings/ezgame/data/EZGameConfig.java +++ b/src/java/com/threerings/ezgame/data/EZGameConfig.java @@ -24,6 +24,10 @@ public class EZGameConfig extends GameConfig // For now, the configData is either a classname or url. 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. * This could be thought of as a new-style rating id. */ public int persistentGameId; @@ -62,8 +66,7 @@ public class EZGameConfig extends GameConfig // from PartyGameConfig public byte getPartyGameType () { - // TODO - return NOT_PARTY_GAME; + return partyGameType; } @Override diff --git a/src/java/com/threerings/ezgame/server/EZGameManager.java b/src/java/com/threerings/ezgame/server/EZGameManager.java index 171f1467..ba8cfcef 100644 --- a/src/java/com/threerings/ezgame/server/EZGameManager.java +++ b/src/java/com/threerings/ezgame/server/EZGameManager.java @@ -424,6 +424,7 @@ public class EZGameManager extends GameManager @Override protected void didShutdown () { + System.err.println("didShutdown!"); CrowdServer.invmgr.clearDispatcher(_gameObj.ezGameService); stopTickers(); diff --git a/src/java/com/threerings/parlor/data/Table.java b/src/java/com/threerings/parlor/data/Table.java index 6e02003b..3c3c5be1 100644 --- a/src/java/com/threerings/parlor/data/Table.java +++ b/src/java/com/threerings/parlor/data/Table.java @@ -62,6 +62,14 @@ public class Table * (This is not propagated to remote instances.) */ 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. */ public GameConfig config; @@ -98,7 +106,7 @@ public class Table this.config = config; // make room for the maximum number of players - if (tconfig.desiredPlayerCount != -1) { + if (!isPartyGame()) { occupants = new Name[tconfig.desiredPlayerCount]; bodyOids = new int[occupants.length]; @@ -130,9 +138,11 @@ public class Table public int getOccupiedCount () { int count = 0; - for (int ii = 0; ii < occupants.length; ii++) { - if (occupants[ii] != null) { - count++; + if (occupants != null) { + for (int ii = 0; ii < occupants.length; ii++) { + if (occupants[ii] != null) { + count++; + } } } return count; @@ -147,15 +157,19 @@ public class Table */ public Name[] getPlayers () { - if (isPartyGame()) { - return occupants; + // seated party games need a spot for every seat + 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()]; - for (int ii = 0, dex = 0; ii < occupants.length; ii++) { - if (occupants[ii] != null) { - players[dex++] = occupants[ii]; + if (occupants != null) { + for (int ii = 0, dex = 0; ii < occupants.length; ii++) { + if (occupants[ii] != null) { + players[dex++] = occupants[ii]; + } } } @@ -262,10 +276,12 @@ public class Table */ public boolean clearOccupant (Name username) { - for (int i = 0; i < occupants.length; i++) { - if (username.equals(occupants[i])) { - clearOccupantPos(i); - return true; + if (occupants != null) { + for (int i = 0; i < occupants.length; i++) { + if (username.equals(occupants[i])) { + clearOccupantPos(i); + return true; + } } } return false; @@ -281,10 +297,12 @@ public class Table */ public boolean clearOccupantByOid (int bodyOid) { - for (int i = 0; i < bodyOids.length; i++) { - if (bodyOid == bodyOids[i]) { - clearOccupantPos(i); - return true; + if (bodyOids != null) { + for (int i = 0; i < bodyOids.length; i++) { + if (bodyOid == bodyOids[i]) { + clearOccupantPos(i); + return true; + } } } return false; @@ -334,7 +352,8 @@ public class Table */ public boolean shouldBeStarted () { - return tconfig.desiredPlayerCount <= getOccupiedCount(); + return isPartyGame() || + (tconfig.desiredPlayerCount <= getOccupiedCount()); } /** diff --git a/src/java/com/threerings/parlor/data/TableConfig.java b/src/java/com/threerings/parlor/data/TableConfig.java index d6d1355a..e1bf257e 100644 --- a/src/java/com/threerings/parlor/data/TableConfig.java +++ b/src/java/com/threerings/parlor/data/TableConfig.java @@ -29,9 +29,9 @@ import com.threerings.io.SimpleStreamableObject; */ public class TableConfig extends SimpleStreamableObject { - /** 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 - * total number of players overall, as teams may be unequal. */ + /** The total number of players that are desired for the table. + * For team games, this should be set to the total number of players + * overall, as teams may be unequal. */ public int desiredPlayerCount; /** The minimum number of players needed overall (or per-team if a diff --git a/src/java/com/threerings/parlor/server/TableManager.java b/src/java/com/threerings/parlor/server/TableManager.java index ec519711..a1b90984 100644 --- a/src/java/com/threerings/parlor/server/TableManager.java +++ b/src/java/com/threerings/parlor/server/TableManager.java @@ -29,12 +29,14 @@ import com.samskivert.util.StringUtil; import com.threerings.util.Name; import com.threerings.presents.dobj.ChangeListener; +import com.threerings.presents.dobj.NamedEvent; import com.threerings.presents.dobj.ObjectAddedEvent; import com.threerings.presents.dobj.ObjectDeathListener; import com.threerings.presents.dobj.ObjectDestroyedEvent; import com.threerings.presents.dobj.ObjectRemovedEvent; import com.threerings.presents.dobj.OidListListener; import com.threerings.presents.server.InvocationException; +import com.threerings.presents.server.PresentsServer; import com.threerings.crowd.data.BodyObject; import com.threerings.crowd.data.PlaceObject; @@ -126,29 +128,38 @@ public class TableManager } table.init(_plobj.getOid(), tableConfig, config); - // stick the creator into the first non-AI position - int cpos = (config.ais == null) ? 0 : config.ais.length; - String error = table.setOccupant(cpos, creator); - if (error != null) { - Log.warning("Unable to add creator to position zero of " + - "table!? [table=" + table + ", creator=" + creator + - ", error=" + error + "]."); - // bail out now and abort the table creation process - throw new InvocationException(error); + boolean isParty = table.isPartyGame(); + if (!isParty) { + // stick the creator into the first non-AI position + int cpos = (config.ais == null) ? 0 : config.ais.length; + String error = table.setOccupant(cpos, creator); + if (error != null) { + Log.warning("Unable to add creator to position zero of " + + "table!? [table=" + table + ", creator=" + creator + + ", 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 _tlobj.addToTables(table); - // make a mapping from the creator to this table - _boidMap.put(creator.getOid(), table); - // also stick it into our tables tables _tables.put(table.tableId, table); // if the table has only one seat, start the game immediately 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 @@ -295,6 +306,9 @@ public class TableManager _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 _tlobj.removeFromTables(table.tableId); } @@ -303,8 +317,10 @@ public class TableManager * 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 * 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 { // fill the players array into the game config @@ -312,7 +328,10 @@ public class TableManager try { 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) { Log.warning("Failed to create manager for game " + "[config=" + table.config + "]: " + t); @@ -329,17 +348,22 @@ public class TableManager // update the table with the newly created game object table.gameOid = gameobj.getOid(); + // add it to the gameOid map + _goidMap.put(table.gameOid, table); + // configure the privacy of the game gameobj.setIsPrivate(table.tconfig.privateTable); - // clear the occupant to table mappings as this game is underway - for (int i = 0; i < table.bodyOids.length; i++) { - _boidMap.remove(table.bodyOids[i]); + if (!table.isPartyGame()) { + // clear the occupant to table mappings as this game is underway + 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 // finally goes away - gameobj.addListener(_gameDeathListener); + gameobj.addListener(_gameListener); // and then update the lobby object that contains the table _tlobj.updateTables(table); @@ -351,16 +375,36 @@ public class TableManager */ protected void unmapTable (int gameOid) { - // look through our tables table for a table with a matching game - for (Table table : _tables.values()) { - if (table.gameOid == gameOid) { - purgeTable(table); - return; // all done - } + Table table = _goidMap.get(gameOid); + if (table != null) { + purgeTable(table); + + } 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 " + - "[gameOid=" + gameOid + "]."); + GameObject gameObj = (GameObject) PresentsServer.omgr.getObject(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 @@ -415,10 +459,38 @@ public class TableManager /** A mapping from body oid to table. */ protected HashIntMap