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;
|
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
|
* The scene provider handles the server side of the scene related
|
||||||
* invocation services (e.g. moving from scene to scene).
|
* invocation services (e.g. moving from scene to scene).
|
||||||
*/
|
*/
|
||||||
public class SceneProvider
|
public class SceneProvider extends InvocationProvider
|
||||||
extends InvocationProvider implements SceneCodes
|
implements SceneCodes
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Processes a request from a client to move to a new scene.
|
* Processes a request from a client to move to a new scene.
|
||||||
@@ -88,8 +88,7 @@ public class SceneProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (ServiceFailedException sfe) {
|
} catch (ServiceFailedException sfe) {
|
||||||
sendResponse(source, invid, MOVE_FAILED_RESPONSE,
|
sendResponse(source, invid, MOVE_FAILED_RESPONSE, sfe.getMessage());
|
||||||
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;
|
package com.threerings.whirled.spot.client;
|
||||||
|
|
||||||
import com.threerings.crowd.chat.ChatCodes;
|
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.
|
* 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. */
|
/** The module name for the Spot services. */
|
||||||
public static final String MODULE_NAME = "whirled!spot";
|
public static final String MODULE_NAME = "whirled!spot";
|
||||||
|
|
||||||
/** The message identifier for a cluster speak request message. */
|
/** The message identifier for a traversePortal request. Such a
|
||||||
public static final String CLUSTER_SPEAK_REQUEST = "cspkreq";
|
* 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. */
|
/** The message identifier for a changeLoc request. */
|
||||||
public static final String CHANGE_LOC_REQUEST = "ChangeLoc";
|
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
|
/** An error code indicating that a location is occupied. Usually
|
||||||
* generated by a failed changeLoc request. */
|
* generated by a failed changeLoc request. */
|
||||||
public static final String LOCATION_OCCUPIED = "m.location_occupied";
|
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;
|
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.Log;
|
||||||
import com.threerings.whirled.spot.data.Location;
|
import com.threerings.whirled.spot.data.Location;
|
||||||
|
import com.threerings.whirled.spot.data.Portal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extends the standard scene director with facilities to move between
|
* Extends the standard scene director with facilities to move between
|
||||||
@@ -55,6 +56,59 @@ public class SpotSceneDirector extends SceneDirector
|
|||||||
super(ctx, screp, dsfact);
|
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
|
* Issues a request to change our location within the scene to the
|
||||||
* location identified by the specified id. Most client entities find
|
* 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;
|
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
|
* 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}.
|
* but instead should be accessed via the {@link SpotSceneDirector}.
|
||||||
*/
|
*/
|
||||||
public class SpotService implements SpotCodes
|
public class SpotService implements SpotCodes
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Requests that that this client's body be made to occupy the
|
* Requests to traverse the specified portal.
|
||||||
* specified location.
|
*/
|
||||||
|
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,
|
public static void changeLoc (Client client, int sceneId, int locationId,
|
||||||
SpotSceneDirector rsptarget)
|
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;
|
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.presents.server.ServiceFailedException;
|
||||||
|
|
||||||
import com.threerings.crowd.data.BodyObject;
|
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.SceneRegistry;
|
||||||
|
import com.threerings.whirled.server.WhirledServer;
|
||||||
|
|
||||||
import com.threerings.whirled.spot.Log;
|
import com.threerings.whirled.spot.Log;
|
||||||
import com.threerings.whirled.spot.client.SpotCodes;
|
import com.threerings.whirled.spot.client.SpotCodes;
|
||||||
|
import com.threerings.whirled.spot.data.SpotOccupantInfo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides the server side of the spot services.
|
* 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());
|
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.
|
* 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. */
|
/** The scene registry with which we interoperate. */
|
||||||
protected static SceneRegistry _screg;
|
protected static SceneRegistry _screg;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user