diff --git a/src/java/com/threerings/parlor/client/ParlorCodes.java b/src/java/com/threerings/parlor/client/ParlorCodes.java
index 92ea6f30e..98d9755a7 100644
--- a/src/java/com/threerings/parlor/client/ParlorCodes.java
+++ b/src/java/com/threerings/parlor/client/ParlorCodes.java
@@ -1,5 +1,5 @@
//
-// $Id: ParlorCodes.java,v 1.7 2001/10/19 22:02:36 mdb Exp $
+// $Id: ParlorCodes.java,v 1.8 2001/10/23 02:22:16 mdb Exp $
package com.threerings.parlor.client;
@@ -64,25 +64,20 @@ public interface ParlorCodes extends InvocationCodes
/** The response identifier for a table created response. This is
* mapped by the invocation services to a call to {@link
- * ParlorDirector#handleTableCreated}. */
+ * TableManager#handleTableCreated}. */
public static final String TABLE_CREATED_RESPONSE = "TableCreated";
/** The response identifier for a create failed response. This is
* mapped by the invocation services to a call to {@link
- * ParlorDirector#handleCreateFailed}. */
+ * TableManager#handleCreateFailed}. */
public static final String CREATE_FAILED_RESPONSE = "CreateFailed";
/** The message identifier for a join table request. */
public static final String JOIN_TABLE_REQUEST = "JoinTable";
- /** The response identifier for a table joined response. This is
- * mapped by the invocation services to a call to {@link
- * ParlorDirector#handleTableJoined}. */
- public static final String TABLE_JOINED_RESPONSE = "TableJoined";
-
/** The response identifier for a join failed response. This is mapped
* by the invocation services to a call to {@link
- * ParlorDirector#handleJoinFailed}. */
+ * TableManager#handleJoinFailed}. */
public static final String JOIN_FAILED_RESPONSE = "JoinFailed";
/** An error code returned when a user requests to join a table that
diff --git a/src/java/com/threerings/parlor/client/ParlorDirector.java b/src/java/com/threerings/parlor/client/ParlorDirector.java
index 55e489d30..5777275ed 100644
--- a/src/java/com/threerings/parlor/client/ParlorDirector.java
+++ b/src/java/com/threerings/parlor/client/ParlorDirector.java
@@ -1,5 +1,5 @@
//
-// $Id: ParlorDirector.java,v 1.12 2001/10/22 23:56:25 mdb Exp $
+// $Id: ParlorDirector.java,v 1.13 2001/10/23 02:22:16 mdb Exp $
package com.threerings.parlor.client;
@@ -377,22 +377,6 @@ public class ParlorDirector
}
}
- public void handleTableCreated (int invid, int tableId)
- {
- }
-
- public void handleCreateFailed (int invid, String reason)
- {
- }
-
- public void handleTableJoined (int invid, int tableId)
- {
- }
-
- public void handleJoinFailed (int invid, String reason)
- {
- }
-
/**
* The invitation class is used to track information related to
* outstanding invitations generated by or targeted to this client.
diff --git a/src/java/com/threerings/parlor/client/ParlorService.java b/src/java/com/threerings/parlor/client/ParlorService.java
index a63ab5f75..97e69759f 100644
--- a/src/java/com/threerings/parlor/client/ParlorService.java
+++ b/src/java/com/threerings/parlor/client/ParlorService.java
@@ -1,5 +1,5 @@
//
-// $Id: ParlorService.java,v 1.7 2001/10/11 21:08:21 mdb Exp $
+// $Id: ParlorService.java,v 1.8 2001/10/23 02:22:16 mdb Exp $
package com.threerings.parlor.client;
@@ -103,4 +103,57 @@ public class ParlorService implements ParlorCodes
"[inviteId=" + inviteId + "].");
return invdir.invoke(MODULE_NAME, CANCEL_INVITE_ID, args, rsptarget);
}
+
+ /**
+ * You probably don't want to call this directly, but want to call
+ * {@link TableManager#createTable}. Requests that a new table be
+ * created.
+ *
+ * @param client a connected, operational client instance.
+ * @param lobbyOid the oid of the lobby that will contain the newly
+ * created table.
+ * @param config the game config for the game to be matchmade by the
+ * table.
+ * @param rsptarget the object reference that will receive and process
+ * the response.
+ *
+ * @return the invocation request id of the generated request.
+ */
+ public static int createTable (
+ Client client, int lobbyOid, GameConfig config, Object rsptarget)
+ {
+ InvocationDirector invdir = client.getInvocationDirector();
+ Object[] args = new Object[] { new Integer(lobbyOid), config };
+ Log.info("Sending table creation request " +
+ "[lobbyOid=" + lobbyOid + ", config=" + config + "].");
+ return invdir.invoke(
+ MODULE_NAME, CREATE_TABLE_REQUEST, args, rsptarget);
+ }
+
+ /**
+ * You probably don't want to call this directly, but want to call
+ * {@link TableManager#joinTable}. Requests that the current user
+ * be added to the specified table at the specified position.
+ *
+ * @param client a connected, operational client instance.
+ * @param tableId the unique id of the table to which this user wishes
+ * to be added.
+ * @param position the position at the table to which this user desires
+ * to be added.
+ * @param rsptarget the object reference that will receive and process
+ * the response.
+ *
+ * @return the invocation request id of the generated request.
+ */
+ public static int joinTable (
+ Client client, int tableId, int position, Object rsptarget)
+ {
+ InvocationDirector invdir = client.getInvocationDirector();
+ Object[] args = new Object[] { new Integer(tableId),
+ new Integer(position) };
+ Log.info("Sending join table request " +
+ "[tableId=" + tableId + ", position=" + position + "].");
+ return invdir.invoke(
+ MODULE_NAME, JOIN_TABLE_REQUEST, args, rsptarget);
+ }
}
diff --git a/src/java/com/threerings/parlor/client/TableDirector.java b/src/java/com/threerings/parlor/client/TableDirector.java
new file mode 100644
index 000000000..17a9c0346
--- /dev/null
+++ b/src/java/com/threerings/parlor/client/TableDirector.java
@@ -0,0 +1,253 @@
+//
+// $Id: TableDirector.java,v 1.1 2001/10/23 02:22:16 mdb Exp $
+
+package com.threerings.parlor.client;
+
+import com.threerings.presents.dobj.ElementAddedEvent;
+import com.threerings.presents.dobj.ElementUpdatedEvent;
+import com.threerings.presents.dobj.ElementRemovedEvent;
+import com.threerings.presents.dobj.SetListener;
+
+import com.threerings.crowd.data.BodyObject;
+import com.threerings.crowd.data.PlaceObject;
+
+import com.threerings.parlor.Log;
+import com.threerings.parlor.data.Table;
+import com.threerings.parlor.data.TableLobbyObject;
+import com.threerings.parlor.game.GameConfig;
+import com.threerings.parlor.util.ParlorContext;
+
+/**
+ * As tables are created and managed within the scope of a place (a
+ * lobby), we want to fold the table management functionality into the
+ * standard hierarchy of place controllers that deal with place-related
+ * functionality on the client. Thus, instead of forcing places that
+ * expect to have tables to extend a TableLobbyController or
+ * something similar, we instead provide the table manager which can be
+ * instantiated by the place controller (or specific table related views)
+ * to handle the table matchmaking services.
+ *
+ *
Entites that do so, will need to implement the {@link + * TableObserver} interface so that the table manager can notify them when + * table related things happen. + * + *
The table services expect that the place object being used as a + * lobby in which the table matchmaking takes place implements the {@link + * TableLobbyObject} interface. + */ +public class TableManager + implements SetListener +{ + /** + * Creates a new table manager to manage tables with the specified + * observer which will receive callbacks when interesting table + * related things happen. + * + * @param ctx the parlor context in use by the client. + * @param tableField the field name of the distributed set that + * contains the tables we will be managing. + * @param observer the entity that will receive callbacks when things + * happen to the tables. + */ + public TableManager ( + ParlorContext ctx, String tableField, TableObserver observer) + { + // keep track of this stuff + _ctx = ctx; + _tableField = tableField; + _observer = observer; + } + + /** + * This must be called by the entity that uses the table manager when + * the using entity prepares to enter and display a place. It is + * assumed that the client is already subscribed to the provided place + * object. + */ + public void willEnterPlace (PlaceObject place) + { + // add ourselves as a listener to the place object + place.addListener(this); + + // and remember this for later + _lobby = place; + } + + /** + * This must be called by the entity that uses the table manager when + * the using entity has left and is done displaying a place. + */ + public void didLeavePlace (PlaceObject place) + { + // remove our listenership + place.removeListener(this); + + // clear out our lobby reference + _lobby = null; + } + + /** + * Sends a request to create a table with the specified game + * configuration. This user will become the owner of this table and + * will be added to the first position in the table. The response will + * be communicated via the {@link TableObserver} interface. + */ + public void createTable (GameConfig config) + { + // if we're already in a table, refuse the request + if (_ourTable != null) { + Log.warning("Ignoring request to create table as we're " + + "already in a table [table=" + _ourTable + "]."); + return; + } + + // make sure we're currently in a place + if (_lobby == null) { + Log.warning("Requested to create a table but we're not " + + "currently in a place [config=" + config + "]."); + return; + } + + // go ahead and issue the create request + ParlorService.createTable( + _ctx.getClient(), _lobby.getOid(), config, this); + } + + /** + * Sends a request to join the specified table at the specified + * position. The response will be communicated via the {@link + * TableObserver} interface. + */ + public void joinTable (int tableId, int position) + { + // if we're already in a table, refuse the request + if (_ourTable != null) { + Log.warning("Ignoring request to join table as we're " + + "already in a table [table=" + _ourTable + "]."); + return; + } + + // make sure we're currently in a place + if (_lobby == null) { + Log.warning("Requested to join a table but we're not " + + "currently in a place [tableId=" + tableId + "]."); + return; + } + + // go ahead and issue the create request + ParlorService.joinTable( + _ctx.getClient(), tableId, position, this); + } + + // documentation inherited + public void elementAdded (ElementAddedEvent event) + { + if (event.getName().equals(_tableField)) { + Table table = (Table)event.getElement(); + _observer.tableAdded(table); + + // check to see if we just joined a table + checkForOurTable(table); + } + } + + // documentation inherited + public void elementUpdated (ElementUpdatedEvent event) + { + if (event.getName().equals(_tableField)) { + Table table = (Table)event.getElement(); + _observer.tableUpdated(table); + + // check to see if we just joined or left a table + checkForOurTable(table); + } + } + + // documentation inherited + public void elementRemoved (ElementRemovedEvent event) + { + if (event.getName().equals(_tableField)) { + Integer tableId = (Integer)event.getKey(); + _observer.tableRemoved(tableId.intValue()); + + // check to see if our table just disappeared + if (_ourTable != null && tableId.equals(_ourTable.tableId)) { + _ourTable = null; + } + } + } + + /** + * Called by the invocation services when a table creation request was + * received by the server and the table was successfully created. + * + * @param invid the invocation id of the invitation request. + */ + public void handleTableCreated (int invid, int tableId) + { + // nothing much to do here + Log.info("Table creation succeeded [tableId=" + tableId + "]."); + } + + /** + * Called by the invocation services when a table creation request + * failed or was rejected for some reason. + * + * @param invid the invocation id of the creation request. + * @param reason a reason code explaining the failure. + */ + public void handleCreateFailed (int invid, String reason) + { + Log.warning("Table creation failed [reason=" + reason + "]."); + } + + /** + * Called by the invocation services when a join table request failed + * or was rejected for some reason. + * + * @param invid the invocation id of the join request. + * @param reason a reason code explaining the failure. + */ + public void handleJoinFailed (int invid, String reason) + { + Log.warning("Join table failed [reason=" + reason + "]."); + } + + /** + * Checks to see if we're a member of this table and notes it as our + * table, if so. + */ + protected void checkForOurTable (Table table) + { + // if this is the same table as our table, clear out our table + // reference and allow it to be added back if we are still in the + // table + if (table.equals(_ourTable)) { + _ourTable = null; + } + + // look for our username in the occupants array + BodyObject self = (BodyObject)_ctx.getClient().getClientObject(); + for (int i = 0; i < table.occupants.length; i++) { + if (self.username.equals(table.occupants[i])) { + _ourTable = table; + return; + } + } + } + + /** A context by which we can access necessary client services. */ + protected ParlorContext _ctx; + + /** The place object in which we're currently managing tables. */ + protected PlaceObject _lobby; + + /** The field name of the distributed set that contains our tables. */ + protected String _tableField; + + /** The entity that we talk to when table stuff happens. */ + protected TableObserver _observer; + + /** The table of which we are a member if any. */ + protected Table _ourTable; +} diff --git a/src/java/com/threerings/parlor/client/TableObserver.java b/src/java/com/threerings/parlor/client/TableObserver.java new file mode 100644 index 000000000..97253fbbe --- /dev/null +++ b/src/java/com/threerings/parlor/client/TableObserver.java @@ -0,0 +1,30 @@ +// +// $Id: TableObserver.java,v 1.1 2001/10/23 02:22:16 mdb Exp $ + +package com.threerings.parlor.client; + +import com.threerings.parlor.data.Table; + +/** + * The {@link TableManager} converts distributed object events into higher + * level callbacks to implementers of this interface, which are expected + * to render these events sensically in a user interface. + */ +public interface TableObserver +{ + /** + * Called when a new table is created. + */ + public void tableAdded (Table table); + + /** + * Called when something has changed about a table (occupant list + * updated, state changed from matchmaking to in-play, etc.). + */ + public void tableUpdated (Table table); + + /** + * Called when a table goes away. + */ + public void tableRemoved (int tableId); +} diff --git a/src/java/com/threerings/parlor/data/Table.java b/src/java/com/threerings/parlor/data/Table.java index d0c70ec49..5ce707723 100644 --- a/src/java/com/threerings/parlor/data/Table.java +++ b/src/java/com/threerings/parlor/data/Table.java @@ -1,5 +1,5 @@ // -// $Id: Table.java,v 1.3 2001/10/22 23:56:01 mdb Exp $ +// $Id: Table.java,v 1.4 2001/10/23 02:22:16 mdb Exp $ package com.threerings.parlor.data; @@ -181,6 +181,19 @@ public class Table _tconfig = (TableConfig)config; } + /** + * Returns true if this table is equal to the supplied object (which + * must be a table with the same table id). + */ + public boolean equals (Object other) + { + if (other != null && other instanceof Table) { + return ((Table)other).tableId.equals(tableId); + } else { + return false; + } + } + /** * Generates a string representation of this table instance. */ diff --git a/src/java/com/threerings/parlor/server/ParlorManager.java b/src/java/com/threerings/parlor/server/ParlorManager.java index 2936e212e..e9cb513db 100644 --- a/src/java/com/threerings/parlor/server/ParlorManager.java +++ b/src/java/com/threerings/parlor/server/ParlorManager.java @@ -1,5 +1,5 @@ // -// $Id: ParlorManager.java,v 1.12 2001/10/19 22:02:36 mdb Exp $ +// $Id: ParlorManager.java,v 1.13 2001/10/23 02:22:17 mdb Exp $ package com.threerings.parlor.server; @@ -240,10 +240,20 @@ public class ParlorManager // create a brand spanking new table Table table = new Table(placeOid, config); - // and stick it into the table lobby object + // stick the creator into position zero + String error = table.setOccupant(0, creator.username); + if (error != null) { + Log.warning("Unable to add creator to position zero of " + + "table!? [table=" + table + + ", creator=" + creator + "]."); + // bail out now and abort the table creation process + throw new ServiceFailedException(error); + } + + // stick the table into the table lobby object tlobj.addToTables(table); - // also stick the table into our tables table + // also stick it into our tables table _tables.put(table.getTableId(), table); // finally let the caller know what the new table id is @@ -373,8 +383,7 @@ public class ParlorManager CrowdServer.omgr.getObject(table.lobbyOid); if (tlobj == null) { Log.warning("Can't update in-play table as lobby's gone " + - "missing [table=" + table + - ", gameOid=" + plobj.getOid() + "]."); + "missing [table=" + table + "]."); return; } tlobj.updateTables(table);