Allow a SceneService.moveTo() to respond by requesting that the client move to

a new server and reissue its request, which it, in theory, now does.


git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@354 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Michael Bayne
2007-07-13 21:59:46 +00:00
parent 6a77a7e1f1
commit d5023554e8
9 changed files with 224 additions and 173 deletions
@@ -32,6 +32,7 @@ import com.threerings.io.TypedArray;
import com.threerings.presents.client.BasicDirector; import com.threerings.presents.client.BasicDirector;
import com.threerings.presents.client.Client; import com.threerings.presents.client.Client;
import com.threerings.presents.client.ClientEvent; import com.threerings.presents.client.ClientEvent;
import com.threerings.presents.client.ConfirmAdapter;
import com.threerings.presents.data.InvocationCodes; import com.threerings.presents.data.InvocationCodes;
import com.threerings.crowd.client.LocationDirector; import com.threerings.crowd.client.LocationDirector;
@@ -138,16 +139,8 @@ public class SceneDirector extends BasicDirector
return false; return false;
} }
// check the version of our cached copy of the scene to which we're requesting to move; if // do the deed
// we were unable to load it, assume a cached version of zero sendMoveRequest();
var sceneVers :int = 0;
if (_pendingModel != null) {
sceneVers = _pendingModel.version;
}
// issue a moveTo request
log.info("Issuing moveTo(" + sceneId + ", " + sceneVers + ").");
_sservice.moveTo(_wctx.getClient(), sceneId, sceneVers, this);
return true; return true;
} }
@@ -201,7 +194,7 @@ public class SceneDirector extends BasicDirector
return _pendingModel; return _pendingModel;
} }
// documentation inherited from interface SceneService_SceneMoveListener // from interface SceneService_SceneMoveListener
public function moveSucceeded (placeId :int, config :PlaceConfig) :void public function moveSucceeded (placeId :int, config :PlaceConfig) :void
{ {
// our move request was successful, deal with subscribing to our new place object // our move request was successful, deal with subscribing to our new place object
@@ -234,9 +227,9 @@ public class SceneDirector extends BasicDirector
_scene = _fact.createScene(_model, config); _scene = _fact.createScene(_model, config);
} }
// documentation inherited from interface SceneService_SceneMoveListener // from interface SceneService_SceneMoveListener
public function moveSucceededWithUpdates ( public function moveSucceededWithUpdates (
placeId :int, config :PlaceConfig, updates :Array) :void placeId :int, config :PlaceConfig, updates :TypedArray) :void
{ {
log.info("Got updates [placeId=" + placeId + ", config=" + config + log.info("Got updates [placeId=" + placeId + ", config=" + config +
", updates=" + updates + "]."); ", updates=" + updates + "].");
@@ -289,7 +282,7 @@ public class SceneDirector extends BasicDirector
moveSucceeded(placeId, config); moveSucceeded(placeId, config);
} }
// documentation inherited from interface SceneService-SceneMoveListener // from interface SceneService_SceneMoveListener
public function moveSucceededWithScene ( public function moveSucceededWithScene (
placeId :int, config :PlaceConfig, model :SceneModel) :void placeId :int, config :PlaceConfig, model :SceneModel) :void
{ {
@@ -306,6 +299,21 @@ public class SceneDirector extends BasicDirector
moveSucceeded(placeId, config); moveSucceeded(placeId, config);
} }
// from interface SceneService_SceneMoveListener
public function moveRequiresServerSwitch (hostname :String, ports :TypedArray) :void
{
// ship on over to the other server
_wctx.getClient().moveToServer(hostname, ports, new ConfirmAdapter(
function (reason :String) :void { // failed
requestFailed(reason);
},
function () :void { // succeeded
// resend our move request now that we're connected to the new server
sendMoveRequest();
}
));
}
// documentation inherited from interface // documentation inherited from interface
public function requestFailed (reason :String) :void public function requestFailed (reason :String) :void
{ {
@@ -391,6 +399,20 @@ public class SceneDirector extends BasicDirector
} }
} }
protected function sendMoveRequest () :void
{
// 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
var sceneVers :int = 0;
if (_pendingModel != null) {
sceneVers = _pendingModel.version;
}
// issue a moveTo request
log.info("Issuing moveTo(" + _pendingSceneId + ", " + sceneVers + ").");
_sservice.moveTo(_wctx.getClient(), _pendingSceneId, sceneVers, this);
}
/** /**
* Clears out our current scene information and releases the scene model for the loaded scene * Clears out our current scene information and releases the scene model for the loaded scene
* back to the cache. * back to the cache.
@@ -22,6 +22,7 @@
package com.threerings.whirled.client { package com.threerings.whirled.client {
import flash.utils.ByteArray; import flash.utils.ByteArray;
import com.threerings.io.TypedArray;
import com.threerings.crowd.data.PlaceConfig; import com.threerings.crowd.data.PlaceConfig;
import com.threerings.presents.client.Client; import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService; import com.threerings.presents.client.InvocationService;
@@ -23,6 +23,7 @@ package com.threerings.whirled.client {
import flash.utils.ByteArray; import flash.utils.ByteArray;
import com.threerings.util.*; // for Float, Integer, etc. import com.threerings.util.*; // for Float, Integer, etc.
import com.threerings.io.TypedArray;
import com.threerings.crowd.data.PlaceConfig; import com.threerings.crowd.data.PlaceConfig;
import com.threerings.presents.client.Client; import com.threerings.presents.client.Client;
@@ -39,6 +40,9 @@ import com.threerings.whirled.data.SceneUpdate;
public interface SceneService_SceneMoveListener public interface SceneService_SceneMoveListener
extends InvocationService_InvocationListener extends InvocationService_InvocationListener
{ {
// from Java SceneService_SceneMoveListener
function moveRequiresServerSwitch (arg1 :String, arg2 :TypedArray /* of int */) :void
// from Java SceneService_SceneMoveListener // from Java SceneService_SceneMoveListener
function moveSucceeded (arg1 :int, arg2 :PlaceConfig) :void function moveSucceeded (arg1 :int, arg2 :PlaceConfig) :void
@@ -46,6 +50,6 @@ public interface SceneService_SceneMoveListener
function moveSucceededWithScene (arg1 :int, arg2 :PlaceConfig, arg3 :SceneModel) :void function moveSucceededWithScene (arg1 :int, arg2 :PlaceConfig, arg3 :SceneModel) :void
// from Java SceneService_SceneMoveListener // from Java SceneService_SceneMoveListener
function moveSucceededWithUpdates (arg1 :int, arg2 :PlaceConfig, arg3 :Array) :void function moveSucceededWithUpdates (arg1 :int, arg2 :PlaceConfig, arg3 :TypedArray /* of class com.threerings.whirled.data.SceneUpdate */) :void
} }
} }
@@ -23,6 +23,7 @@ package com.threerings.whirled.data {
import flash.utils.ByteArray; import flash.utils.ByteArray;
import com.threerings.util.*; // for Float, Integer, etc. import com.threerings.util.*; // for Float, Integer, etc.
import com.threerings.io.TypedArray;
import com.threerings.crowd.data.PlaceConfig; import com.threerings.crowd.data.PlaceConfig;
import com.threerings.presents.client.Client; import com.threerings.presents.client.Client;
@@ -23,6 +23,7 @@ package com.threerings.whirled.data {
import flash.utils.ByteArray; import flash.utils.ByteArray;
import com.threerings.util.*; // for Float, Integer, etc. import com.threerings.util.*; // for Float, Integer, etc.
import com.threerings.io.TypedArray;
import com.threerings.crowd.data.PlaceConfig; import com.threerings.crowd.data.PlaceConfig;
import com.threerings.presents.client.Client; import com.threerings.presents.client.Client;
@@ -38,19 +39,27 @@ import com.threerings.whirled.data.SceneUpdate;
public class SceneMarshaller_SceneMoveMarshaller public class SceneMarshaller_SceneMoveMarshaller
extends InvocationMarshaller_ListenerMarshaller extends InvocationMarshaller_ListenerMarshaller
{ {
/** The method id used to dispatch {@link #moveRequiresServerSwitch} responses. */
public static const MOVE_REQUIRES_SERVER_SWITCH :int = 1;
/** The method id used to dispatch {@link #moveSucceeded} responses. */ /** The method id used to dispatch {@link #moveSucceeded} responses. */
public static const MOVE_SUCCEEDED :int = 1; public static const MOVE_SUCCEEDED :int = 2;
/** The method id used to dispatch {@link #moveSucceededWithScene} responses. */ /** The method id used to dispatch {@link #moveSucceededWithScene} responses. */
public static const MOVE_SUCCEEDED_WITH_SCENE :int = 2; public static const MOVE_SUCCEEDED_WITH_SCENE :int = 3;
/** The method id used to dispatch {@link #moveSucceededWithUpdates} responses. */ /** The method id used to dispatch {@link #moveSucceededWithUpdates} responses. */
public static const MOVE_SUCCEEDED_WITH_UPDATES :int = 3; public static const MOVE_SUCCEEDED_WITH_UPDATES :int = 4;
// from InvocationMarshaller_ListenerMarshaller // from InvocationMarshaller_ListenerMarshaller
override public function dispatchResponse (methodId :int, args :Array) :void override public function dispatchResponse (methodId :int, args :Array) :void
{ {
switch (methodId) { switch (methodId) {
case MOVE_REQUIRES_SERVER_SWITCH:
(listener as SceneService_SceneMoveListener).moveRequiresServerSwitch(
(args[0] as String), (args[1] as TypedArray /* of int */));
return;
case MOVE_SUCCEEDED: case MOVE_SUCCEEDED:
(listener as SceneService_SceneMoveListener).moveSucceeded( (listener as SceneService_SceneMoveListener).moveSucceeded(
(args[0] as int), (args[1] as PlaceConfig)); (args[0] as int), (args[1] as PlaceConfig));
@@ -63,7 +72,7 @@ public class SceneMarshaller_SceneMoveMarshaller
case MOVE_SUCCEEDED_WITH_UPDATES: case MOVE_SUCCEEDED_WITH_UPDATES:
(listener as SceneService_SceneMoveListener).moveSucceededWithUpdates( (listener as SceneService_SceneMoveListener).moveSucceededWithUpdates(
(args[0] as int), (args[1] as PlaceConfig), (args[2] as Array)); (args[0] as int), (args[1] as PlaceConfig), (args[2] as TypedArray /* of class com.threerings.whirled.data.SceneUpdate */));
return; return;
default: default:
@@ -45,15 +45,13 @@ import com.threerings.whirled.util.WhirledContext;
import com.threerings.whirled.data.SceneUpdate; import com.threerings.whirled.data.SceneUpdate;
/** /**
* The scene director is the client's interface to all things scene * The scene director is the client's interface to all things scene related. It interfaces with the
* related. It interfaces with the scene repository to ensure that scene * scene repository to ensure that scene objects are available when the client enters a particular
* objects are available when the client enters a particular scene. It * scene. It handles moving from scene to scene (it coordinates with the {@link LocationDirector}
* handles moving from scene to scene (it coordinates with the {@link * in order to do this).
* LocationDirector} in order to do this).
* *
* <p> Note that when the scene director is in use instead of the location * <p> Note that when the scene director is in use instead of the location director, scene ids
* director, scene ids instead of place oids will be supplied to {@link * instead of place oids will be supplied to {@link LocationObserver#locationMayChange} and {@link
* LocationObserver#locationMayChange} and {@link
* LocationObserver#locationChangeFailed}. * LocationObserver#locationChangeFailed}.
*/ */
public class SceneDirector extends BasicDirector public class SceneDirector extends BasicDirector
@@ -66,8 +64,8 @@ public class SceneDirector extends BasicDirector
public static interface MoveHandler public static interface MoveHandler
{ {
/** /**
* Should instruct the client to move the last known working * Should instruct the client to move the last known working location (as well as clean up
* location (as well as clean up after the failed moveTo request). * after the failed moveTo request).
*/ */
public void recoverMoveTo (int sceneId); public void recoverMoveTo (int sceneId);
} }
@@ -76,18 +74,16 @@ public class SceneDirector extends BasicDirector
* Creates a new scene director with the specified context. * Creates a new scene director with the specified context.
* *
* @param ctx the active client context. * @param ctx the active client context.
* @param locdir the location director in use on the client, with * @param locdir the location director in use on the client, with which the scene director will
* which the scene director will coordinate when changing location. * coordinate when changing location.
* @param screp the entity from which the scene director will load * @param screp the entity from which the scene director will load scene data from the local
* scene data from the local client scene storage. This may be null * client scene storage. This may be null when the SceneDirector is constructed, but it should
* when the SceneDirector is constructed, but it should be * be supplied via {@link #setSceneRepository} prior to really using this director.
* supplied via {@link #setSceneRepository} prior to really using * @param fact the factory that knows which derivation of {@link Scene} to create for the
* this director. * current system.
* @param fact the factory that knows which derivation of {@link
* Scene} to create for the current system.
*/ */
public SceneDirector (WhirledContext ctx, LocationDirector locdir, public SceneDirector (WhirledContext ctx, LocationDirector locdir, SceneRepository screp,
SceneRepository screp, SceneFactory fact) SceneFactory fact)
{ {
super(ctx); super(ctx);
@@ -97,13 +93,12 @@ public class SceneDirector extends BasicDirector
setSceneRepository(screp); setSceneRepository(screp);
_fact = fact; _fact = fact;
// set ourselves up as a failure handler with the location // set ourselves up as a failure handler with the location director because we need to do
// director because we need to do special processing // special processing
_locdir.setFailureHandler(this); _locdir.setFailureHandler(this);
// register for scene notifications // register for scene notifications
_ctx.getClient().getInvocationDirector().registerReceiver( _ctx.getClient().getInvocationDirector().registerReceiver(new SceneDecoder(this));
new SceneDecoder(this));
} }
/** /**
@@ -116,8 +111,8 @@ public class SceneDirector extends BasicDirector
} }
/** /**
* Returns the display scene object associated with the scene we * Returns the display scene object associated with the scene we currently occupy or null if we
* currently occupy or null if we currently occupy no scene. * currently occupy no scene.
*/ */
public Scene getScene () public Scene getScene ()
{ {
@@ -125,13 +120,11 @@ public class SceneDirector extends BasicDirector
} }
/** /**
* Requests that this client move the specified scene. A request will * Requests that this client move the specified scene. A request will be made and when the
* be made and when the response is received, the location observers * response is received, the location observers will be notified of success or failure.
* will be notified of success or failure.
* *
* @return true if the move to request was issued, false if it was * @return true if the move to request was issued, false if it was rejected by a location
* rejected by a location observer or because we have another request * observer or because we have another request outstanding.
* outstanding.
*/ */
public boolean moveTo (int sceneId) public boolean moveTo (int sceneId)
{ {
@@ -143,8 +136,7 @@ public class SceneDirector extends BasicDirector
// sanity-check the destination scene id // sanity-check the destination scene id
if (sceneId == _sceneId) { if (sceneId == _sceneId) {
Log.warning("Refusing request to move to the same scene " + Log.warning("Refusing request to move to the same scene [sceneId=" + sceneId + "].");
"[sceneId=" + sceneId + "].");
return false; return false;
} }
@@ -153,56 +145,41 @@ public class SceneDirector extends BasicDirector
return false; return false;
} }
// check the version of our cached copy of the scene to which // do the deed
// we're requesting to move; if we were unable to load it, assume sendMoveRequest();
// a cached version of zero
int sceneVers = 0;
if (_pendingModel != null) {
sceneVers = _pendingModel.version;
}
// issue a moveTo request
Log.info("Issuing moveTo(" + sceneId + ", " + sceneVers + ").");
_sservice.moveTo(_ctx.getClient(), sceneId, sceneVers, this);
return true; return true;
} }
/** /**
* Prepares to move to the requested scene. The location observers are * Prepares to move to the requested scene. The location observers are asked to ratify the move
* asked to ratify the move and our pending scene mode is loaded from * and our pending scene mode is loaded from the scene repository. This can be called by
* the scene repository. This can be called by cooperating directors * cooperating directors that need to coopt the moveTo process.
* that need to coopt the moveTo process.
*/ */
public boolean prepareMoveTo (int sceneId, ResultListener rl) public boolean prepareMoveTo (int sceneId, ResultListener rl)
{ {
// first check to see if our observers are happy with this move // first check to see if our observers are happy with this move request
// request
if (!_locdir.mayMoveTo(sceneId, rl)) { if (!_locdir.mayMoveTo(sceneId, rl)) {
return false; return false;
} }
// we need to call this both to mark that we're issuing a move // we need to call this both to mark that we're issuing a move request and to check to see
// request and to check to see if the last issued request should // if the last issued request should be considered stale
// be considered stale
boolean refuse = _locdir.checkRepeatMove(); boolean refuse = _locdir.checkRepeatMove();
// complain if we're over-writing a pending request // complain if we're over-writing a pending request
if (_pendingSceneId != -1) { if (_pendingSceneId != -1) {
if (refuse) { if (refuse) {
Log.warning("Refusing moveTo; We have a request outstanding " + Log.warning("Refusing moveTo; We have a request outstanding " +
"[psid=" + _pendingSceneId + "[psid=" + _pendingSceneId + ", nsid=" + sceneId + "].");
", nsid=" + sceneId + "].");
return false; return false;
} else { } else {
Log.warning("Overriding stale moveTo request " + Log.warning("Overriding stale moveTo request [psid=" + _pendingSceneId +
"[psid=" + _pendingSceneId +
", nsid=" + sceneId + "]."); ", nsid=" + sceneId + "].");
} }
} }
// load up the pending scene so that we can communicate it's most // load up the pending scene so that we can communicate it's most recent version to the
// recent version to the server // server
_pendingModel = loadSceneModel(sceneId); _pendingModel = loadSceneModel(sceneId);
// make a note of our pending scene id // make a note of our pending scene id
@@ -213,27 +190,24 @@ public class SceneDirector extends BasicDirector
} }
/** /**
* Returns the model loaded in preparation for a scene * Returns the model loaded in preparation for a scene transition. This is made available only
* transition. This is made available only for cooperating directors * for cooperating directors which may need to coopt the scene transition process. The pending
* which may need to coopt the scene transition process. The pending * model is only valid immediately following a call to {@link #prepareMoveTo}.
* model is only valid immediately following a call to {@link
* #prepareMoveTo}.
*/ */
public SceneModel getPendingModel () public SceneModel getPendingModel ()
{ {
return _pendingModel; return _pendingModel;
} }
// documentation inherited from interface // from interface SceneService.SceneMoveListener
public void moveSucceeded (int placeId, PlaceConfig config) public void moveSucceeded (int placeId, PlaceConfig config)
{ {
// our move request was successful, deal with subscribing to our // our move request was successful, deal with subscribing to our new place object
// new place object
_locdir.didMoveTo(placeId, config); _locdir.didMoveTo(placeId, config);
// since we're committed to moving to the new scene, we'll // since we're committed to moving to the new scene, we'll parallelize and go ahead and
// parallelize and go ahead and load up the new scene now rather // load up the new scene now rather than wait until subscription to our place object
// than wait until subscription to our place object succeeds // succeeds
// keep track of our previous scene info // keep track of our previous scene info
_previousSceneId = _sceneId; _previousSceneId = _sceneId;
@@ -250,19 +224,16 @@ public class SceneDirector extends BasicDirector
// complain if we didn't find a scene // complain if we didn't find a scene
if (_model == null) { if (_model == null) {
Log.warning("Aiya! Unable to load scene [sid=" + _sceneId + Log.warning("Aiya! Unable to load scene [sid=" + _sceneId + ", plid=" + placeId + "].");
", plid=" + placeId + "].");
return; return;
} }
// and finally create a display scene instance with the model and // and finally create a display scene instance with the model and the place config
// the place config
_scene = _fact.createScene(_model, config); _scene = _fact.createScene(_model, config);
} }
// documentation inherited from interface // from interface SceneService.SceneMoveListener
public void moveSucceededWithUpdates ( public void moveSucceededWithUpdates (int placeId, PlaceConfig config, SceneUpdate[] updates)
int placeId, PlaceConfig config, SceneUpdate[] updates)
{ {
Log.info("Got updates [placeId=" + placeId + ", config=" + config + Log.info("Got updates [placeId=" + placeId + ", config=" + config +
", updates=" + StringUtil.toString(updates) + "]."); ", updates=" + StringUtil.toString(updates) + "].");
@@ -275,8 +246,7 @@ public class SceneDirector extends BasicDirector
updates[ii].validate(model); updates[ii].validate(model);
} catch (IllegalStateException ise) { } catch (IllegalStateException ise) {
Log.warning("Scene update failed validation [model=" + model + Log.warning("Scene update failed validation [model=" + model +
", update=" + updates[ii] + ", update=" + updates[ii] + ", error=" + ise.getMessage() + "].");
", error=" + ise.getMessage() + "].");
failure = true; failure = true;
break; break;
} }
@@ -302,9 +272,8 @@ public class SceneDirector extends BasicDirector
Log.logStackTrace(ioe); Log.logStackTrace(ioe);
} }
// act as if the scene move failed, though we'll be in a funny // act as if the scene move failed; we'll be in a funny state because the server thinks
// state because the server thinks we've changed scenes, but // we've changed scenes, but the client can try again without its booched scene model
// the client can try again without its booched scene model
requestFailed(INTERNAL_ERROR); requestFailed(INTERNAL_ERROR);
return; return;
} }
@@ -316,13 +285,11 @@ public class SceneDirector extends BasicDirector
moveSucceeded(placeId, config); moveSucceeded(placeId, config);
} }
// documentation inherited from interface // from interface SceneService.SceneMoveListener
public void moveSucceededWithScene ( public void moveSucceededWithScene (int placeId, PlaceConfig config, SceneModel model)
int placeId, PlaceConfig config, SceneModel model)
{ {
Log.info("Got updated scene model [placeId=" + placeId + Log.info("Got updated scene model [placeId=" + placeId + ", config=" + config +
", config=" + config + ", scene=" + model.sceneId + "/" + ", scene=" + model.sceneId + "/" + model.name + "/" + model.version + "].");
model.name + "/" + model.version + "].");
// update the model in the repository // update the model in the repository
persistSceneModel(model); persistSceneModel(model);
@@ -334,7 +301,22 @@ public class SceneDirector extends BasicDirector
moveSucceeded(placeId, config); moveSucceeded(placeId, config);
} }
// documentation inherited from interface // from interface SceneService.SceneMoveListener
public void moveRequiresServerSwitch (String hostname, int[] ports)
{
// ship on over to the other server
_ctx.getClient().moveToServer(hostname, ports, new SceneService.ConfirmListener() {
public void requestProcessed () {
// resend our move request now that we're connected to the new server
sendMoveRequest();
}
public void requestFailed (String reason) {
SceneDirector.this.requestFailed(reason);
}
});
}
// from interface SceneService.SceneMoveListener
public void requestFailed (String reason) public void requestFailed (String reason)
{ {
// clear out our pending request oid // clear out our pending request oid
@@ -346,8 +328,7 @@ public class SceneDirector extends BasicDirector
} }
/** /**
* Called by SceneController instances to tell us about an update * Called by SceneController instances to tell us about an update to the current scene.
* to the current scene.
*/ */
public void updateReceived (SceneUpdate update) public void updateReceived (SceneUpdate update)
{ {
@@ -356,8 +337,7 @@ public class SceneDirector extends BasicDirector
} }
/** /**
* Called to clean up our place and scene state information when we * Called to clean up our place and scene state information when we leave a scene.
* leave a scene.
*/ */
public void didLeaveScene () public void didLeaveScene ()
{ {
@@ -386,11 +366,10 @@ public class SceneDirector extends BasicDirector
public void setMoveHandler (MoveHandler handler) public void setMoveHandler (MoveHandler handler)
{ {
if (_moveHandler != null) { if (_moveHandler != null) {
Log.warning("Requested to set move handler, but we've " + Log.warning("Requested to set move handler, but we've already got one. The " +
"already got one. The conflicting entities will " + "conflicting entities will likely need to perform more sophisticated " +
"likely need to perform more sophisticated " + "coordination to deal with failures. [old=" + _moveHandler +
"coordination to deal with failures. " + ", new=" + handler + "].");
"[old=" + _moveHandler + ", new=" + handler + "].");
} else { } else {
_moveHandler = handler; _moveHandler = handler;
@@ -398,8 +377,7 @@ public class SceneDirector extends BasicDirector
} }
/** /**
* Called when something breaks down in the process of performing a * Called when something breaks down in the process of performing a {@link #moveTo} request.
* <code>moveTo</code> request.
*/ */
public void recoverFailedMove (int placeId) public void recoverFailedMove (int placeId)
{ {
@@ -409,22 +387,35 @@ public class SceneDirector extends BasicDirector
// clear out our now bogus scene tracking info // clear out our now bogus scene tracking info
clearScene(); clearScene();
// if we were previously somewhere (and that somewhere isn't where // if we were previously somewhere (and that somewhere isn't where we just tried to go),
// we just tried to go), try going back to that happy place // try going back to that happy place
if (_previousSceneId != -1 && _previousSceneId != sceneId) { if (_previousSceneId != -1 && _previousSceneId != sceneId) {
// if we have a move handler use that // if we have a move handler use that
if (_moveHandler != null) { if (_moveHandler != null) {
_moveHandler.recoverMoveTo(_previousSceneId); _moveHandler.recoverMoveTo(_previousSceneId);
} else { } else {
moveTo(_previousSceneId); moveTo(_previousSceneId);
} }
} }
} }
protected void sendMoveRequest ()
{
// 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 sceneVers = 0;
if (_pendingModel != null) {
sceneVers = _pendingModel.version;
}
// issue a moveTo request
Log.info("Issuing moveTo(" + _pendingSceneId + ", " + sceneVers + ").");
_sservice.moveTo(_ctx.getClient(), _pendingSceneId, sceneVers, this);
}
/** /**
* Clears out our current scene information and releases the scene * Clears out our current scene information and releases the scene model for the loaded scene
* model for the loaded scene back to the cache. * back to the cache.
*/ */
protected void clearScene () protected void clearScene ()
{ {
@@ -437,8 +428,8 @@ public class SceneDirector extends BasicDirector
} }
/** /**
* Loads a scene from the repository. If the scene is cached, it will * Loads a scene from the repository. If the scene is cached, it will be returned from the
* be returned from the cache instead. * cache instead.
*/ */
protected SceneModel loadSceneModel (int sceneId) protected SceneModel loadSceneModel (int sceneId)
{ {
@@ -457,8 +448,7 @@ public class SceneDirector extends BasicDirector
} catch (IOException ioe) { } catch (IOException ioe) {
// complain first, then return null // complain first, then return null
Log.warning("Error loading scene [scid=" + sceneId + Log.warning("Error loading scene [scid=" + sceneId + ", error=" + ioe + "].");
", error=" + ioe + "].");
} }
} }
@@ -474,9 +464,8 @@ public class SceneDirector extends BasicDirector
try { try {
_screp.storeSceneModel(model); _screp.storeSceneModel(model);
} catch (IOException ioe) { } catch (IOException ioe) {
Log.warning("Failed to update repository with updated scene " + Log.warning("Failed to update repository with updated scene [sceneId=" + model.sceneId +
"[sceneId=" + model.sceneId + ", nvers=" + model.version + ", nvers=" + model.version + "].");
"].");
Log.logStackTrace(ioe); Log.logStackTrace(ioe);
} }
} }
@@ -535,12 +524,11 @@ public class SceneDirector extends BasicDirector
/** The id of the scene we currently occupy. */ /** The id of the scene we currently occupy. */
protected int _sceneId = -1; protected int _sceneId = -1;
/** Our most recent copy of the scene model for the scene we're about /** Our most recent copy of the scene model for the scene we're about to enter. */
* to enter. */
protected SceneModel _pendingModel; protected SceneModel _pendingModel;
/** The id of the scene for which we have an outstanding moveTo /** The id of the scene for which we have an outstanding moveTo request, or -1 if we have no
* request, or -1 if we have no outstanding request. */ * outstanding request. */
protected int _pendingSceneId = -1; protected int _pendingSceneId = -1;
/** The id of the scene we previously occupied. */ /** The id of the scene we previously occupied. */
@@ -30,8 +30,8 @@ import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate; import com.threerings.whirled.data.SceneUpdate;
/** /**
* The scene service class provides the client interface to the scene * The scene service class provides the client interface to the scene related invocation services
* related invocation services (e.g. moving from scene to scene). * (e.g. moving from scene to scene).
*/ */
public interface SceneService extends InvocationService public interface SceneService extends InvocationService
{ {
@@ -49,38 +49,39 @@ public interface SceneService extends InvocationService
public void moveSucceeded (int placeId, PlaceConfig config); public void moveSucceeded (int placeId, PlaceConfig config);
/** /**
* Indicates that a move succeeded and that the client's cached * Indicates that a move succeeded and that the client's cached scene information should be
* scene information should be updated with the supplied data. * updated with the supplied data.
* *
* @param placeId the place object id of the newly occupied scene. * @param placeId the place object id of the newly occupied scene.
* @param config metadata related to the newly occupied scene. * @param config metadata related to the newly occupied scene.
* @param updates updates that must be applied to the client's * @param updates updates that must be applied to the client's copy of a scene model to
* copy of a scene model to bring it up to date. * bring it up to date.
*/ */
public void moveSucceededWithUpdates (int placeId, PlaceConfig config, public void moveSucceededWithUpdates (
SceneUpdate[] updates); int placeId, PlaceConfig config, SceneUpdate[] updates);
/** /**
* Indicates that a move succeeded and that the client's cached * Indicates that a move succeeded and that the client's cached scene information should be
* scene information should be updated with the supplied data. * updated with the supplied data.
* *
* @param placeId the place object id of the newly occupied scene. * @param placeId the place object id of the newly occupied scene.
* @param config metadata related to the newly occupied scene. * @param config metadata related to the newly occupied scene.
* @param model a fresh copy of the most recent scene data for the * @param model a fresh copy of the most recent scene data for the newly occupied scene.
* newly occupied scene.
*/ */
public void moveSucceededWithScene (int placeId, PlaceConfig config, public void moveSucceededWithScene (int placeId, PlaceConfig config, SceneModel model);
SceneModel model);
/**
* Indicates that the client must switch to the specified server and reissue its move
* request in order to relocate to its desired scene.
*/
public void moveRequiresServerSwitch (String hostname, int[] ports);
} }
/** /**
* Requests that that this client's body be moved to the specified * Requests that that this client's body be moved to the specified scene.
* scene.
* *
* @param sceneId the scene id to which we want to move. * @param sceneId the scene id to which we want to move.
* @param version the version number of the scene object that we have * @param version the version number of the scene object that we have in our local repository.
* in our local repository.
*/ */
public void moveTo (Client client, int sceneId, int version, public void moveTo (Client client, int sceneId, int version, SceneMoveListener listener);
SceneMoveListener listener);
} }
@@ -45,9 +45,22 @@ public class SceneMarshaller extends InvocationMarshaller
public static class SceneMoveMarshaller extends ListenerMarshaller public static class SceneMoveMarshaller extends ListenerMarshaller
implements SceneMoveListener implements SceneMoveListener
{ {
/** The method id used to dispatch {@link #moveRequiresServerSwitch}
* responses. */
public static final int MOVE_REQUIRES_SERVER_SWITCH = 1;
// from interface SceneMoveMarshaller
public void moveRequiresServerSwitch (String arg1, int[] arg2)
{
_invId = null;
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, MOVE_REQUIRES_SERVER_SWITCH,
new Object[] { arg1, arg2 }));
}
/** The method id used to dispatch {@link #moveSucceeded} /** The method id used to dispatch {@link #moveSucceeded}
* responses. */ * responses. */
public static final int MOVE_SUCCEEDED = 1; public static final int MOVE_SUCCEEDED = 2;
// from interface SceneMoveMarshaller // from interface SceneMoveMarshaller
public void moveSucceeded (int arg1, PlaceConfig arg2) public void moveSucceeded (int arg1, PlaceConfig arg2)
@@ -60,7 +73,7 @@ public class SceneMarshaller extends InvocationMarshaller
/** The method id used to dispatch {@link #moveSucceededWithScene} /** The method id used to dispatch {@link #moveSucceededWithScene}
* responses. */ * responses. */
public static final int MOVE_SUCCEEDED_WITH_SCENE = 2; public static final int MOVE_SUCCEEDED_WITH_SCENE = 3;
// from interface SceneMoveMarshaller // from interface SceneMoveMarshaller
public void moveSucceededWithScene (int arg1, PlaceConfig arg2, SceneModel arg3) public void moveSucceededWithScene (int arg1, PlaceConfig arg2, SceneModel arg3)
@@ -73,7 +86,7 @@ public class SceneMarshaller extends InvocationMarshaller
/** The method id used to dispatch {@link #moveSucceededWithUpdates} /** The method id used to dispatch {@link #moveSucceededWithUpdates}
* responses. */ * responses. */
public static final int MOVE_SUCCEEDED_WITH_UPDATES = 3; public static final int MOVE_SUCCEEDED_WITH_UPDATES = 4;
// from interface SceneMoveMarshaller // from interface SceneMoveMarshaller
public void moveSucceededWithUpdates (int arg1, PlaceConfig arg2, SceneUpdate[] arg3) public void moveSucceededWithUpdates (int arg1, PlaceConfig arg2, SceneUpdate[] arg3)
@@ -88,6 +101,11 @@ public class SceneMarshaller extends InvocationMarshaller
public void dispatchResponse (int methodId, Object[] args) public void dispatchResponse (int methodId, Object[] args)
{ {
switch (methodId) { switch (methodId) {
case MOVE_REQUIRES_SERVER_SWITCH:
((SceneMoveListener)listener).moveRequiresServerSwitch(
(String)args[0], (int[])args[1]);
return;
case MOVE_SUCCEEDED: case MOVE_SUCCEEDED:
((SceneMoveListener)listener).moveSucceeded( ((SceneMoveListener)listener).moveSucceeded(
((Integer)args[0]).intValue(), (PlaceConfig)args[1]); ((Integer)args[0]).intValue(), (PlaceConfig)args[1]);
@@ -35,8 +35,8 @@ import com.threerings.whirled.server.persist.SceneRepository;
import com.threerings.whirled.util.SceneFactory; import com.threerings.whirled.util.SceneFactory;
/** /**
* The whirled server extends the {@link CrowdServer} and provides access * The Whirled server extends the {@link CrowdServer} and provides access to managers and the like
* to managers and the like that are needed by the Whirled serviecs. * that are needed by the Whirled serviecs.
*/ */
public abstract class WhirledServer extends CrowdServer public abstract class WhirledServer extends CrowdServer
{ {
@@ -66,17 +66,25 @@ public abstract class WhirledServer extends CrowdServer
_screp = createSceneRepository(); _screp = createSceneRepository();
// create our scene registry // create our scene registry
screg = new SceneRegistry(invmgr, _screp, createSceneFactory(), screg = createSceneRegistry();
createConfigFactory());
Log.info("Whirled server initialized."); Log.info("Whirled server initialized.");
} }
/**
* Creates the scene registry to be used on this server.
*/
protected SceneRegistry createSceneRegistry ()
throws Exception
{
return new SceneRegistry(invmgr, _screp, createSceneFactory(), createConfigFactory());
}
/** /**
* Creates the scene repository that will be used by this server. * Creates the scene repository that will be used by this server.
* *
* @exception Exception thrown if any error occurs while instantiating * @exception Exception thrown if any error occurs while instantiating or initializing the
* or initializing the scene repository. * scene repository.
*/ */
protected abstract SceneRepository createSceneRepository () protected abstract SceneRepository createSceneRepository ()
throws Exception; throws Exception;
@@ -84,18 +92,17 @@ public abstract class WhirledServer extends CrowdServer
/** /**
* Creates the scene factory that will be used by our scene registry. * Creates the scene factory that will be used by our scene registry.
* *
* @exception Exception thrown if any error occurs while instantiating * @exception Exception thrown if any error occurs while instantiating or initializing the
* or initializing the scene repository. * scene repository.
*/ */
protected abstract SceneFactory createSceneFactory () protected abstract SceneFactory createSceneFactory ()
throws Exception; throws Exception;
/** /**
* Creates the place config factory that will be used our scene * Creates the place config factory that will be used our scene registry.
* registry.
* *
* @exception Exception thrown if any error occurs while instantiating * @exception Exception thrown if any error occurs while instantiating or initializing the
* or initializing the scene repository. * scene repository.
*/ */
protected abstract SceneRegistry.ConfigFactory createConfigFactory () protected abstract SceneRegistry.ConfigFactory createConfigFactory ()
throws Exception; throws Exception;