Added support for initiating a place/scene/zone transition from the

server; chat director no longer needs to wait until we're logged on to
register itself with the invocation director.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1393 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2002-05-26 02:24:46 +00:00
parent 8a7a046df8
commit 97197d49cc
10 changed files with 251 additions and 73 deletions
@@ -1,5 +1,5 @@
// //
// $Id: ChatDirector.java,v 1.21 2002/05/22 21:44:54 shaper Exp $ // $Id: ChatDirector.java,v 1.22 2002/05/26 02:24:45 mdb Exp $
package com.threerings.crowd.chat; package com.threerings.crowd.chat;
@@ -34,15 +34,9 @@ public class ChatDirector
// keep the context around // keep the context around
_ctx = ctx; _ctx = ctx;
// register a client observer that will register us as the chat // register for chat notifications
// receiver when we log on _ctx.getClient().getInvocationDirector().registerReceiver(
_ctx.getClient().addClientObserver(new ClientAdapter() { MODULE_NAME, this);
public void clientDidLogon (Client client)
{
client.getInvocationDirector().registerReceiver(
MODULE_NAME, ChatDirector.this);
}
});
// register ourselves as a location observer // register ourselves as a location observer
_ctx.getLocationDirector().addLocationObserver(this); _ctx.getLocationDirector().addLocationObserver(this);
@@ -1,5 +1,5 @@
// //
// $Id: LocationDirector.java,v 1.19 2002/05/22 21:46:53 shaper Exp $ // $Id: LocationDirector.java,v 1.20 2002/05/26 02:24:46 mdb Exp $
package com.threerings.crowd.client; package com.threerings.crowd.client;
@@ -10,6 +10,7 @@ import com.samskivert.util.ObserverList;
import com.samskivert.util.ObserverList.ObserverOp; import com.samskivert.util.ObserverList.ObserverOp;
import com.threerings.presents.client.Client; import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationReceiver;
import com.threerings.presents.client.SessionObserver; import com.threerings.presents.client.SessionObserver;
import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DObjectManager; import com.threerings.presents.dobj.DObjectManager;
@@ -18,6 +19,7 @@ import com.threerings.presents.dobj.Subscriber;
import com.threerings.crowd.Log; import com.threerings.crowd.Log;
import com.threerings.crowd.data.BodyObject; import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.data.LocationCodes;
import com.threerings.crowd.data.PlaceConfig; import com.threerings.crowd.data.PlaceConfig;
import com.threerings.crowd.data.PlaceObject; import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.util.CrowdContext; import com.threerings.crowd.util.CrowdContext;
@@ -30,7 +32,7 @@ import com.threerings.crowd.util.CrowdContext;
* before actually issuing the request. * before actually issuing the request.
*/ */
public class LocationDirector public class LocationDirector
implements SessionObserver, Subscriber implements LocationCodes, SessionObserver, Subscriber, InvocationReceiver
{ {
/** /**
* Used to recover from a moveTo request that was accepted but * Used to recover from a moveTo request that was accepted but
@@ -57,6 +59,10 @@ public class LocationDirector
// register ourselves as a client observer // register ourselves as a client observer
ctx.getClient().addClientObserver(this); ctx.getClient().addClientObserver(this);
// register for location notifications
_ctx.getClient().getInvocationDirector().registerReceiver(
MODULE_NAME, this);
} }
/** /**
@@ -174,11 +180,13 @@ public class LocationDirector
*/ */
public void didMoveTo (int placeId, PlaceConfig config) public void didMoveTo (int placeId, PlaceConfig config)
{ {
// keep track of our previous place id
_previousPlaceId = _placeId;
// do some cleaning up in case we were previously in a place // do some cleaning up in case we were previously in a place
didLeavePlace(); didLeavePlace();
// make a note that we're now mostly in the new location // make a note that we're now mostly in the new location
_previousPlaceId = _placeId;
_placeId = placeId; _placeId = placeId;
Class cclass = config.getControllerClass(); Class cclass = config.getControllerClass();
@@ -199,12 +207,12 @@ public class LocationDirector
} }
/** /**
* Called when we're leaving our current location. Informs the * Called when we're leaving our current location. Informs the
* location's controller that we're departing, unsubscribes from the * location's controller that we're departing, unsubscribes from the
* location's place object, and clears out our internal place * location's place object, and clears out our internal place
* information. * information.
*/ */
protected void didLeavePlace () public void didLeavePlace ()
{ {
if (_plobj != null) { if (_plobj != null) {
// let the old controller know that things are going away // let the old controller know that things are going away
@@ -244,6 +252,7 @@ public class LocationDirector
notifyFailure(placeId, reason); notifyFailure(placeId, reason);
} }
// documentation inherited from interface
public void clientDidLogon (Client client) public void clientDidLogon (Client client)
{ {
// get a copy of our body object // get a copy of our body object
@@ -270,6 +279,7 @@ public class LocationDirector
// we'll want to be going there straight away // we'll want to be going there straight away
} }
// documentation inherited from interface
public void clientDidLogoff (Client client) public void clientDidLogoff (Client client)
{ {
// clear ourselves out and inform observers of our departure // clear ourselves out and inform observers of our departure
@@ -307,6 +317,23 @@ public class LocationDirector
notifyFailure(placeId, reason); notifyFailure(placeId, reason);
} }
/**
* Called when the server has decided to forcibly move us to another
* room. The server first ejects us from our previous room and then
* sends us a notification with our new location. We then turn around
* and issue a standard moveTo request.
*/
public void handleMoveNotification (int placeId)
{
Log.info("Moving at request of server [placeId=" + placeId + "].");
// clear out our old place information
didLeavePlace();
// move to the new place
moveTo(placeId);
}
/** /**
* Called when we receive the place object to which we subscribed * Called when we receive the place object to which we subscribed
* after a successful moveTo request. * after a successful moveTo request.
@@ -1,5 +1,5 @@
// //
// $Id: LocationCodes.java,v 1.2 2002/04/15 18:06:19 mdb Exp $ // $Id: LocationCodes.java,v 1.3 2002/05/26 02:24:46 mdb Exp $
package com.threerings.crowd.data; package com.threerings.crowd.data;
@@ -27,6 +27,9 @@ public interface LocationCodes extends InvocationCodes
* LocationDirector#handleMoveFailed}. */ * LocationDirector#handleMoveFailed}. */
public static final String MOVE_FAILED_RESPONSE = "MoveFailed"; public static final String MOVE_FAILED_RESPONSE = "MoveFailed";
/** The message identifier for a move notification. */
public static final String MOVE_NOTIFICATION = "Move";
/** An error code indicating that a place identified by a particular /** An error code indicating that a place identified by a particular
* place id does not exist. Usually generated by a failed moveTo * place id does not exist. Usually generated by a failed moveTo
* request. */ * request. */
@@ -1,5 +1,5 @@
// //
// $Id: LocationProvider.java,v 1.13 2002/05/02 21:19:28 mdb Exp $ // $Id: LocationProvider.java,v 1.14 2002/05/26 02:24:46 mdb Exp $
package com.threerings.crowd.server; package com.threerings.crowd.server;
@@ -20,8 +20,8 @@ import com.threerings.crowd.data.PlaceObject;
/** /**
* This class provides the server end of the location services. * This class provides the server end of the location services.
*/ */
public class LocationProvider public class LocationProvider extends InvocationProvider
extends InvocationProvider implements LocationCodes implements LocationCodes
{ {
/** /**
* Constructs a location provider and registers it with the invocation * Constructs a location provider and registers it with the invocation
@@ -32,6 +32,7 @@ public class LocationProvider
InvocationManager invmgr, RootDObjectManager omgr, PlaceRegistry plreg) InvocationManager invmgr, RootDObjectManager omgr, PlaceRegistry plreg)
{ {
// we'll need these later // we'll need these later
_invmgr = invmgr;
_omgr = omgr; _omgr = omgr;
_plreg = plreg; _plreg = plreg;
@@ -42,8 +43,8 @@ public class LocationProvider
/** /**
* Processes a request from a client to move to a new place. * Processes a request from a client to move to a new place.
*/ */
public void handleMoveToRequest (BodyObject source, int invid, public void handleMoveToRequest (
int placeId) BodyObject source, int invid, int placeId)
{ {
try { try {
// do the move // do the move
@@ -90,62 +91,124 @@ public class LocationProvider
return pmgr.getConfig(); return pmgr.getConfig();
} }
// acquire a lock on the body object to ensure that rapid fire try {
// moveto requests don't break things // acquire a lock on the body object to ensure that rapid fire
if (!source.acquireLock("moveToLock")) { // moveTo requests don't break things
// if we're still locked, a previous moveTo request hasn't if (!source.acquireLock("moveToLock")) {
// been fully processed // if we're still locked, a previous moveTo request hasn't
throw new ServiceFailedException(MOVE_IN_PROGRESS); // been fully processed
throw new ServiceFailedException(MOVE_IN_PROGRESS);
}
PlaceObject place = pmgr.getPlaceObject();
try {
source.startTransaction();
// remove them from any previous location
leaveOccupiedPlace(source);
// set the body's new location
source.setLocation(place.getOid());
} finally {
source.commitTransaction();
}
try {
place.startTransaction();
// generate a new occupant info record and add it to the
// target location
OccupantInfo info = pmgr.buildOccupantInfo(source);
if (info != null) {
place.addToOccupantInfo(info);
}
// add the body oid to the place object's occupant list
place.addToOccupants(bodoid);
} finally {
place.commitTransaction();
}
} finally {
// and finally queue up a lock release event to release the
// lock once all these events are processed
source.releaseLock("moveToLock");
} }
// find out if they were previously in some other location return pmgr.getConfig();
if (source.location != -1) { }
// remove them from the occupant list of the previous location
try { /**
PlaceObject pold = (PlaceObject) * Removes the specified body from the place object they currently
_omgr.getObject(source.location); * occupy. Does nothing if the body is not currently in a place.
if (pold != null) { */
Object key = new Integer(bodoid); public static void leaveOccupiedPlace (BodyObject source)
{
int oldloc = source.location;
int bodoid = source.getOid();
// nothing to do if they weren't previously in some location
if (oldloc == -1) {
return;
}
// remove them from the occupant list
try {
PlaceObject pold = (PlaceObject)_omgr.getObject(oldloc);
if (pold != null) {
Object key = new Integer(bodoid);
try {
pold.startTransaction();
// remove their occupant info (which is keyed on oid) // remove their occupant info (which is keyed on oid)
pold.removeFromOccupantInfo(key); pold.removeFromOccupantInfo(key);
// and remove them from the occupant list // and remove them from the occupant list
pold.removeFromOccupants(bodoid); pold.removeFromOccupants(bodoid);
} else { } finally {
Log.info("Body's prior location no longer around? " + pold.commitTransaction();
"[boid=" + bodoid +
", poid=" + source.location + "].");
} }
} catch (ClassCastException cce) { } else {
Log.warning("Body claims to be at location which " + Log.info("Body's prior location no longer around? " +
"references non-PlaceObject!? " + "[boid=" + bodoid + ", poid=" + oldloc + "].");
"[boid=" + bodoid +
", poid=" + source.location + "].");
} }
} catch (ClassCastException cce) {
Log.warning("Body claims to occupy non-PlaceObject!? " +
"[boid=" + bodoid + ", poid=" + oldloc +
", error=" + cce + "].");
} }
// set the body's new location // clear out their location oid
PlaceObject place = pmgr.getPlaceObject(); source.setLocation(-1);
source.setLocation(place.getOid());
// generate a new occupant info record and add it to the target
// location
OccupantInfo info = pmgr.buildOccupantInfo(source);
if (info != null) {
place.addToOccupantInfo(info);
}
// add the body object id to the place object's occupant list
place.addToOccupants(bodoid);
// and finally queue up a lock release event to release the lock
// once all these events are processed
source.releaseLock("moveToLock");
return pmgr.getConfig();
} }
/**
* Forcibly moves the specified body object to the new place. This is
* accomplished by first removing the client from their old location
* and then sending the client a notification, instructing it to move
* to the new location (which it does using the normal moveTo
* service). This has the benefit that the client is removed from
* their old place regardless of whether or not they are cooperating.
* If they choose to ignore the forced move request, they will remain
* in limbo, unable to do much of anything.
*/
public void moveBody (BodyObject source, int placeId)
{
// first remove them from their old place
leaveOccupiedPlace(source);
// then send a move notification
_invmgr.sendNotification(
source.getOid(), MODULE_NAME, MOVE_NOTIFICATION,
new Object[] { new Integer(placeId) });
}
/** The invocation manager with which we interoperate. */
protected static InvocationManager _invmgr;
/** The distributed object manager with which we interoperate. */ /** The distributed object manager with which we interoperate. */
protected static RootDObjectManager _omgr; protected static RootDObjectManager _omgr;
@@ -1,5 +1,5 @@
// //
// $Id: SceneDirector.java,v 1.13 2002/05/22 21:48:44 shaper Exp $ // $Id: SceneDirector.java,v 1.14 2002/05/26 02:24:46 mdb Exp $
package com.threerings.whirled.client; package com.threerings.whirled.client;
@@ -234,6 +234,36 @@ public class SceneDirector
_locdir.failedToMoveTo(sceneId, reason); _locdir.failedToMoveTo(sceneId, reason);
} }
/**
* Called to clean up our place and scene state information when we
* leave a scene.
*/
public void didLeaveScene ()
{
// let the location director know what's up
_locdir.didLeavePlace();
// clear out our own scene state
clearScene();
}
/**
* Called when the server has decided to forcibly move us to another
* scene. The server first ejects us from our previous scene and then
* sends us a notification with our new location. We then turn around
* and issue a standard moveTo request.
*/
public void handleMoveNotification (int sceneId)
{
Log.info("Moving at request of server [sceneId=" + sceneId + "].");
// clear out our old scene and place data
didLeaveScene();
// move to the new scene
moveTo(sceneId);
}
/** /**
* Called when something breaks down in the process of performing a * Called when something breaks down in the process of performing a
* <code>moveTo</code> request. * <code>moveTo</code> request.
@@ -1,8 +1,9 @@
// //
// $Id: SceneProvider.java,v 1.8 2002/04/15 16:28:03 shaper Exp $ // $Id: SceneProvider.java,v 1.9 2002/05/26 02:24:46 mdb Exp $
package com.threerings.whirled.server; package com.threerings.whirled.server;
import com.threerings.presents.server.InvocationManager;
import com.threerings.presents.server.InvocationProvider; import com.threerings.presents.server.InvocationProvider;
import com.threerings.presents.server.ServiceFailedException; import com.threerings.presents.server.ServiceFailedException;
@@ -26,8 +27,9 @@ public class SceneProvider extends InvocationProvider
* Constructs a scene provider that will interact with the supplied * Constructs a scene provider that will interact with the supplied
* scene registry. * scene registry.
*/ */
public SceneProvider (SceneRegistry screg) public SceneProvider (InvocationManager invmgr, SceneRegistry screg)
{ {
_invmgr = invmgr;
_screg = screg; _screg = screg;
} }
@@ -101,6 +103,25 @@ public class SceneProvider extends InvocationProvider
} }
} }
/**
* Ejects the specified body from their current scene and sends them a
* request to move to the specified new scene. This is the
* scene-equivalent to {@link LocationProvider#moveBody}.
*/
public void moveBody (BodyObject source, int sceneId)
{
// first remove them from their old place
LocationProvider.leaveOccupiedPlace(source);
// then send a move notification
_invmgr.sendNotification(
source.getOid(), MODULE_NAME, MOVE_NOTIFICATION,
new Object[] { new Integer(sceneId) });
}
/** The invocation manager with which we interact. */
protected InvocationManager _invmgr;
/** The scene registry with which we interact. */ /** The scene registry with which we interact. */
protected SceneRegistry _screg; protected SceneRegistry _screg;
} }
@@ -1,5 +1,5 @@
// //
// $Id: SceneRegistry.java,v 1.14 2002/05/24 05:58:55 mdb Exp $ // $Id: SceneRegistry.java,v 1.15 2002/05/26 02:24:46 mdb Exp $
package com.threerings.whirled.server; package com.threerings.whirled.server;
@@ -50,7 +50,7 @@ public class SceneRegistry
_scfact = new DefaultRuntimeSceneFactory(); _scfact = new DefaultRuntimeSceneFactory();
// create/register a scene provider with the invocation services // create/register a scene provider with the invocation services
SceneProvider provider = new SceneProvider(this); SceneProvider provider = new SceneProvider(invmgr, this);
invmgr.registerProvider(SceneProvider.MODULE_NAME, provider); invmgr.registerProvider(SceneProvider.MODULE_NAME, provider);
} }
@@ -1,5 +1,5 @@
// //
// $Id: ZoneDirector.java,v 1.4 2001/12/17 04:11:40 mdb Exp $ // $Id: ZoneDirector.java,v 1.5 2002/05/26 02:24:46 mdb Exp $
package com.threerings.whirled.zone.client; package com.threerings.whirled.zone.client;
@@ -149,6 +149,24 @@ public class ZoneDirector
notifyObservers(reason); notifyObservers(reason);
} }
/**
* Called when the server has decided to forcibly move us to another
* zone and scene. The server first ejects us from our previous scene
* and then sends us a notification with our new location. We then
* turn around and issue a standard moveTo request.
*/
public void handleMoveNotification (int zoneId, int sceneId)
{
Log.info("Moving at request of server [zoneId=" + zoneId +
", sceneId=" + sceneId + "].");
// clear out our old scene and place data
_scdir.didLeaveScene();
// move to the new zone and scene
moveTo(zoneId, sceneId);
}
/** /**
* Notifies observers of success or failure, depending on the type of * Notifies observers of success or failure, depending on the type of
* object provided as data. * object provided as data.
@@ -1,8 +1,9 @@
// //
// $Id: ZoneProvider.java,v 1.7 2002/05/03 00:00:17 mdb Exp $ // $Id: ZoneProvider.java,v 1.8 2002/05/26 02:24:46 mdb Exp $
package com.threerings.whirled.zone.server; package com.threerings.whirled.zone.server;
import com.threerings.presents.server.InvocationManager;
import com.threerings.presents.server.InvocationProvider; import com.threerings.presents.server.InvocationProvider;
import com.threerings.presents.server.ServiceFailedException; import com.threerings.presents.server.ServiceFailedException;
@@ -33,8 +34,10 @@ public class ZoneProvider
* constructed and registered by the {@link ZoneRegistry}, which a * constructed and registered by the {@link ZoneRegistry}, which a
* zone-using system must create and initialize in their server. * zone-using system must create and initialize in their server.
*/ */
public ZoneProvider (ZoneRegistry zonereg, SceneRegistry screg) public ZoneProvider (
InvocationManager invmgr, ZoneRegistry zonereg, SceneRegistry screg)
{ {
_invmgr = invmgr;
_zonereg = zonereg; _zonereg = zonereg;
_screg = screg; _screg = screg;
} }
@@ -174,6 +177,25 @@ public class ZoneProvider
} }
} }
/**
* Ejects the specified body from their current scene and sends them a
* request to move to the specified new zone and scene. This is the
* zone-equivalent to {@link LocationProvider#moveBody}.
*/
public void moveBody (BodyObject source, int zoneId, int sceneId)
{
// first remove them from their old place
LocationProvider.leaveOccupiedPlace(source);
// then send a move notification
_invmgr.sendNotification(
source.getOid(), MODULE_NAME, MOVE_NOTIFICATION,
new Object[] { new Integer(zoneId), new Integer(sceneId) });
}
/** The invocation manager with which we interact. */
protected InvocationManager _invmgr;
/** The zone registry with which we communicate. */ /** The zone registry with which we communicate. */
protected ZoneRegistry _zonereg; protected ZoneRegistry _zonereg;
@@ -1,5 +1,5 @@
// //
// $Id: ZoneRegistry.java,v 1.6 2002/03/28 23:59:33 mdb Exp $ // $Id: ZoneRegistry.java,v 1.7 2002/05/26 02:24:46 mdb Exp $
package com.threerings.whirled.zone.server; package com.threerings.whirled.zone.server;
@@ -24,7 +24,7 @@ public class ZoneRegistry
{ {
// create a zone provider and register it with the invocation // create a zone provider and register it with the invocation
// services // services
ZoneProvider provider = new ZoneProvider(this, screg); ZoneProvider provider = new ZoneProvider(invmgr, this, screg);
invmgr.registerProvider(ZoneProvider.MODULE_NAME, provider); invmgr.registerProvider(ZoneProvider.MODULE_NAME, provider);
} }