Finished up implementation of portal traversal back-end.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@781 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: SceneProvider.java,v 1.5 2001/11/12 20:56:56 mdb Exp $
|
||||
// $Id: SceneProvider.java,v 1.6 2001/12/14 23:12:38 mdb Exp $
|
||||
|
||||
package com.threerings.whirled.server;
|
||||
|
||||
@@ -19,8 +19,8 @@ import com.threerings.whirled.data.SceneModel;
|
||||
* The scene provider handles the server side of the scene related
|
||||
* invocation services (e.g. moving from scene to scene).
|
||||
*/
|
||||
public class SceneProvider
|
||||
extends InvocationProvider implements SceneCodes
|
||||
public class SceneProvider extends InvocationProvider
|
||||
implements SceneCodes
|
||||
{
|
||||
/**
|
||||
* Processes a request from a client to move to a new scene.
|
||||
@@ -88,8 +88,7 @@ public class SceneProvider
|
||||
}
|
||||
|
||||
} catch (ServiceFailedException sfe) {
|
||||
sendResponse(source, invid, MOVE_FAILED_RESPONSE,
|
||||
sfe.getMessage());
|
||||
sendResponse(source, invid, MOVE_FAILED_RESPONSE, sfe.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
//
|
||||
// $Id: SpotCodes.java,v 1.1 2001/12/14 00:12:32 mdb Exp $
|
||||
// $Id: SpotCodes.java,v 1.2 2001/12/14 23:12:39 mdb Exp $
|
||||
|
||||
package com.threerings.whirled.spot.client;
|
||||
|
||||
import com.threerings.crowd.chat.ChatCodes;
|
||||
import com.threerings.crowd.client.LocationCodes;
|
||||
import com.threerings.whirled.client.SceneCodes;
|
||||
|
||||
/**
|
||||
* Contains codes used by the Spot invocation services.
|
||||
*/
|
||||
public interface SpotCodes extends ChatCodes, LocationCodes
|
||||
public interface SpotCodes extends ChatCodes, SceneCodes
|
||||
{
|
||||
/** The module name for the Spot services. */
|
||||
public static final String MODULE_NAME = "whirled!spot";
|
||||
|
||||
/** The message identifier for a cluster speak request message. */
|
||||
public static final String CLUSTER_SPEAK_REQUEST = "cspkreq";
|
||||
/** The message identifier for a traversePortal request. Such a
|
||||
* request generates a moveTo response rather than a specialized
|
||||
* response. */
|
||||
public static final String TRAVERSE_PORTAL_REQUEST = "TraversePortal";
|
||||
|
||||
/** An error code indicating that the portal specified in a
|
||||
* traversePortal request does not exist. */
|
||||
public static final String NO_SUCH_PORTAL = "m.no_such_portal";
|
||||
|
||||
/** The message identifier for a changeLoc request. */
|
||||
public static final String CHANGE_LOC_REQUEST = "ChangeLoc";
|
||||
@@ -34,4 +40,7 @@ public interface SpotCodes extends ChatCodes, LocationCodes
|
||||
/** An error code indicating that a location is occupied. Usually
|
||||
* generated by a failed changeLoc request. */
|
||||
public static final String LOCATION_OCCUPIED = "m.location_occupied";
|
||||
|
||||
/** The message identifier for a cluster speak request message. */
|
||||
public static final String CLUSTER_SPEAK_REQUEST = "cspkreq";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: SpotSceneDirector.java,v 1.2 2001/12/14 01:51:46 mdb Exp $
|
||||
// $Id: SpotSceneDirector.java,v 1.3 2001/12/14 23:12:39 mdb Exp $
|
||||
|
||||
package com.threerings.whirled.spot.client;
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.threerings.whirled.util.WhirledContext;
|
||||
|
||||
import com.threerings.whirled.spot.Log;
|
||||
import com.threerings.whirled.spot.data.Location;
|
||||
import com.threerings.whirled.spot.data.Portal;
|
||||
|
||||
/**
|
||||
* Extends the standard scene director with facilities to move between
|
||||
@@ -55,6 +56,59 @@ public class SpotSceneDirector extends SceneDirector
|
||||
super(ctx, screp, dsfact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that this client move to the location specified by the
|
||||
* supplied portal id. A request will be made and when the response is
|
||||
* received, the location observers will be notified of success or
|
||||
* failure.
|
||||
*/
|
||||
public void traversePortal (int portalId)
|
||||
{
|
||||
// look up the destination scene and location
|
||||
if (_scene == null) {
|
||||
Log.warning("Requested to traverse portal when we have " +
|
||||
"no scene [portalId=" + portalId + "].");
|
||||
return;
|
||||
}
|
||||
|
||||
// find the portal they're talking about
|
||||
int targetSceneId = -1, targetLocId = -1;
|
||||
DisplaySpotScene ds = (DisplaySpotScene)_scene;
|
||||
Iterator portals = ds.getPortals().iterator();
|
||||
while (portals.hasNext()) {
|
||||
Portal portal = (Portal)portals.next();
|
||||
if (portal.locationId == portalId) {
|
||||
targetSceneId = portal.targetSceneId;
|
||||
targetLocId = portal.targetLocId;
|
||||
}
|
||||
}
|
||||
|
||||
// make sure we found the portal
|
||||
if (targetSceneId == -1) {
|
||||
Log.warning("Requested to traverse non-existent portal " +
|
||||
"[portalId=" + portalId +
|
||||
", portals=" +
|
||||
StringUtil.toString(ds.getPortals().iterator()) + "].");
|
||||
}
|
||||
|
||||
// prepare to move to this scene (sets up pending data)
|
||||
if (!prepareMoveTo(targetSceneId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check the version of our cached copy of the scene to which
|
||||
// we're requesting to move; if we were unable to load it, assume
|
||||
// a cached version of zero
|
||||
int sceneVer = 0;
|
||||
if (_pendingModel != null) {
|
||||
sceneVer = _pendingModel.version;
|
||||
}
|
||||
|
||||
// issue a traversePortal request
|
||||
SpotService.traversePortal(
|
||||
_ctx.getClient(), _sceneId, portalId, sceneVer, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issues a request to change our location within the scene to the
|
||||
* location identified by the specified id. Most client entities find
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: SpotService.java,v 1.1 2001/12/14 00:12:32 mdb Exp $
|
||||
// $Id: SpotService.java,v 1.2 2001/12/14 23:12:39 mdb Exp $
|
||||
|
||||
package com.threerings.whirled.spot.client;
|
||||
|
||||
@@ -10,14 +10,31 @@ import com.threerings.whirled.spot.Log;
|
||||
|
||||
/**
|
||||
* Provides a mechanism by which the client can request to move between
|
||||
* locations within a scene. These services should not be used directly,
|
||||
* locations within a scene and between scenes (taking exit and entry
|
||||
* locations into account). These services should not be used directly,
|
||||
* but instead should be accessed via the {@link SpotSceneDirector}.
|
||||
*/
|
||||
public class SpotService implements SpotCodes
|
||||
{
|
||||
/**
|
||||
* Requests that that this client's body be made to occupy the
|
||||
* specified location.
|
||||
* Requests to traverse the specified portal.
|
||||
*/
|
||||
public static void traversePortal (
|
||||
Client client, int sceneId, int portalId, int sceneVer,
|
||||
SpotSceneDirector rsptarget)
|
||||
{
|
||||
InvocationDirector invdir = client.getInvocationDirector();
|
||||
Object[] args = new Object[] {
|
||||
new Integer(sceneId), new Integer(portalId),
|
||||
new Integer(sceneVer) };
|
||||
invdir.invoke(MODULE_NAME, TRAVERSE_PORTAL_REQUEST, args, rsptarget);
|
||||
Log.info("Sent traversePortal request [sceneId=" + sceneId +
|
||||
", portalId=" + portalId + ", sceneVer=" + sceneVer + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that this client's body be made to occupy the specified
|
||||
* location.
|
||||
*/
|
||||
public static void changeLoc (Client client, int sceneId, int locationId,
|
||||
SpotSceneDirector rsptarget)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// $Id: SpotClient.java,v 1.1 2001/12/14 23:12:39 mdb Exp $
|
||||
|
||||
package com.threerings.whirled.spot.server;
|
||||
|
||||
import com.threerings.whirled.server.WhirledClient;
|
||||
|
||||
/**
|
||||
* Extends the Whirled client and handles the necessary notifications that
|
||||
* take place when a user logs off to let the clients displaying the scene
|
||||
* they were occupying know that they didn't exit via a portal, but
|
||||
* instead just disappeared.
|
||||
*/
|
||||
public class SpotClient extends WhirledClient
|
||||
{
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// $Id: SpotProvider.java,v 1.1 2001/12/14 00:12:32 mdb Exp $
|
||||
// $Id: SpotProvider.java,v 1.2 2001/12/14 23:12:39 mdb Exp $
|
||||
|
||||
package com.threerings.whirled.spot.server;
|
||||
|
||||
@@ -8,10 +8,18 @@ import com.threerings.presents.server.InvocationProvider;
|
||||
import com.threerings.presents.server.ServiceFailedException;
|
||||
|
||||
import com.threerings.crowd.data.BodyObject;
|
||||
import com.threerings.crowd.data.PlaceConfig;
|
||||
import com.threerings.crowd.data.PlaceObject;
|
||||
import com.threerings.crowd.server.LocationProvider;
|
||||
|
||||
import com.threerings.whirled.data.SceneModel;
|
||||
import com.threerings.whirled.server.SceneManager;
|
||||
import com.threerings.whirled.server.SceneRegistry;
|
||||
import com.threerings.whirled.server.WhirledServer;
|
||||
|
||||
import com.threerings.whirled.spot.Log;
|
||||
import com.threerings.whirled.spot.client.SpotCodes;
|
||||
import com.threerings.whirled.spot.data.SpotOccupantInfo;
|
||||
|
||||
/**
|
||||
* This class provides the server side of the spot services.
|
||||
@@ -34,6 +42,141 @@ public class SpotProvider extends InvocationProvider
|
||||
invmgr.registerProvider(MODULE_NAME, new SpotProvider());
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a request from a client to traverse a portal.
|
||||
*
|
||||
* @param source the body object of the client making the request.
|
||||
* @param invid the invocation service invocation id.
|
||||
* @param sceneId the source scene id.
|
||||
* @param portalId the portal in the source scene that is being
|
||||
* traversed.
|
||||
* @param sceneVer the version of the destination scene data that the
|
||||
* client has cached.
|
||||
*/
|
||||
public void handleTraversePortalRequest (
|
||||
BodyObject source, int invid, int sceneId, int portalId, int sceneVer)
|
||||
{
|
||||
try {
|
||||
// obtain the source scene
|
||||
SpotSceneManager smgr = (SpotSceneManager)
|
||||
_screg.getSceneManager(sceneId);
|
||||
if (smgr == null) {
|
||||
Log.warning("Traverse portal missing source scene " +
|
||||
"[user=" + source.username +
|
||||
", sceneId=" + sceneId +
|
||||
", portalId=" + portalId + "].");
|
||||
throw new ServiceFailedException(INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
// obtain the destination scene and location id
|
||||
RuntimeSpotScene rss = (RuntimeSpotScene)smgr.getScene();
|
||||
int destSceneId = rss.getTargetSceneId(portalId);
|
||||
final int destLocId = rss.getTargetLocationId(portalId);
|
||||
|
||||
// make sure this portal has valid info
|
||||
if (destSceneId == -1) {
|
||||
Log.warning("Traverse portal provided with invalid portal " +
|
||||
"[user=" + source.username +
|
||||
", sceneId=" + sceneId +
|
||||
", portalId=" + portalId +
|
||||
", destSceneId=" + destSceneId + "].");
|
||||
throw new ServiceFailedException(NO_SUCH_PORTAL);
|
||||
}
|
||||
|
||||
// avoid cluttering up the method declaration with final
|
||||
// keywords
|
||||
final BodyObject fsource = source;
|
||||
final int finvid = invid;
|
||||
final int fportalId = portalId;
|
||||
final int fsceneVer = sceneVer;
|
||||
|
||||
// create a callback object that will handle the resolution or
|
||||
// failed resolution of the scene
|
||||
SceneRegistry.ResolutionListener rl =
|
||||
new SceneRegistry.ResolutionListener() {
|
||||
public void sceneWasResolved (SceneManager scmgr) {
|
||||
finishTraversePortalRequest(
|
||||
fsource, finvid, scmgr, fsceneVer,
|
||||
fportalId, destLocId);
|
||||
}
|
||||
|
||||
public void sceneFailedToResolve (
|
||||
int rsceneId, Exception reason) {
|
||||
Log.warning("Unable to resolve target scene " +
|
||||
"[sceneId=" + rsceneId +
|
||||
", reason=" + reason + "].");
|
||||
// pretend like the scene doesn't exist to the client
|
||||
sendResponse(fsource, finvid, MOVE_FAILED_RESPONSE,
|
||||
NO_SUCH_PLACE);
|
||||
}
|
||||
};
|
||||
|
||||
// make sure the scene they are headed to is actually loaded into
|
||||
// the server
|
||||
WhirledServer.screg.resolveScene(destSceneId, rl);
|
||||
|
||||
} catch (ServiceFailedException sfe) {
|
||||
sendResponse(source, invid, MOVE_FAILED_RESPONSE, sfe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called after the scene to which we are moving is guaranteed
|
||||
* to have been loaded into the server.
|
||||
*/
|
||||
protected void finishTraversePortalRequest (
|
||||
BodyObject source, int invid, SceneManager scmgr,
|
||||
int sceneVer, int exitPortalId, int destLocId)
|
||||
{
|
||||
// move to the place object associated with this scene
|
||||
PlaceObject plobj = scmgr.getPlaceObject();
|
||||
int ploid = plobj.getOid();
|
||||
|
||||
// if they were in a scene (and at a location) prior to issuing
|
||||
// this traverse portal request, we need to send a notification to
|
||||
// that scene indicating that they are headed to the portal from
|
||||
// which they depart. we unfortunately can't do it deep in the
|
||||
// bowels of LocationProvider.moveTo() which is where we'd like to
|
||||
// do it to ensure that nothing else ran amuck in the process.
|
||||
// since we can't, we simply send another response putting the
|
||||
// user back where they were in the event that anything fails
|
||||
// during the moveTo process. it's a hack, but it's better than
|
||||
// ripping apart moveTo and restructuring the code with this
|
||||
// requirement in mind
|
||||
int oldLocId =
|
||||
updateLocation(source.location, source.getOid(), exitPortalId);
|
||||
|
||||
try {
|
||||
// try doing the actual move
|
||||
PlaceConfig config = LocationProvider.moveTo(source, ploid);
|
||||
|
||||
// now that the move succeeded, we need to update the occupant
|
||||
// info in the new place object with this user's entry
|
||||
// location
|
||||
updateLocation(ploid, source.getOid(), destLocId);
|
||||
|
||||
// check to see if they need a newer version of the scene data
|
||||
SceneModel model = scmgr.getSceneModel();
|
||||
if (sceneVer < model.version) {
|
||||
// then send the moveTo response
|
||||
sendResponse(source, invid, MOVE_SUCCEEDED_PLUS_UPDATE_RESPONSE,
|
||||
new Integer(ploid), config, model);
|
||||
|
||||
} else {
|
||||
// then send the moveTo response
|
||||
sendResponse(source, invid, MOVE_SUCCEEDED_RESPONSE,
|
||||
new Integer(ploid), config);
|
||||
}
|
||||
|
||||
} catch (ServiceFailedException sfe) {
|
||||
sendResponse(source, invid, MOVE_FAILED_RESPONSE, sfe.getMessage());
|
||||
|
||||
// we need to undo the move to the exit portal location that
|
||||
// we enacted earlier
|
||||
updateLocation(source.location, source.getOid(), oldLocId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a request from a client to move to a new location.
|
||||
*/
|
||||
@@ -61,6 +204,44 @@ public class SpotProvider extends InvocationProvider
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the specified place object, obtains the occupant info for
|
||||
* the specified body object and updates the location id in said
|
||||
* occupant info.
|
||||
*
|
||||
* @return old location id or -1 if no update took place (because
|
||||
* something was not in order, like the place object didn't exist,
|
||||
* etc.).
|
||||
*/
|
||||
protected static int updateLocation (
|
||||
int placeOid, int bodyOid, int locationId)
|
||||
{
|
||||
PlaceObject place = null;
|
||||
int oldLocId = -1;
|
||||
|
||||
if (placeOid != -1 && locationId != -1) {
|
||||
place = (PlaceObject)WhirledServer.omgr.getObject(placeOid);
|
||||
}
|
||||
|
||||
if (place != null) {
|
||||
Integer key = new Integer(bodyOid);
|
||||
SpotOccupantInfo info = (SpotOccupantInfo)
|
||||
place.occupantInfo.get(key);
|
||||
if (info != null) {
|
||||
oldLocId = info.locationId;
|
||||
// we need to clone the info because moveTo() down below
|
||||
// is going to update the actual info record and post it
|
||||
// in its own event, which would mess us up if we were
|
||||
// using the real thing
|
||||
info = (SpotOccupantInfo)info.clone();
|
||||
info.locationId = locationId;
|
||||
place.updateOccupantInfo(info);
|
||||
}
|
||||
}
|
||||
|
||||
return oldLocId;
|
||||
}
|
||||
|
||||
/** The scene registry with which we interoperate. */
|
||||
protected static SceneRegistry _screg;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user