From 9fe0c6f08259a61e30a5bbf0de9827749cc92827 Mon Sep 17 00:00:00 2001 From: Mike Thomas Date: Tue, 5 Oct 2010 20:56:24 +0000 Subject: [PATCH] Fix a bug where the client & server happen to attempt to change location nearly simultaneously. Rather than ignoring all forced moves from the server, let's instead ignore those which are truly duplicates of our pending move, but merely postpone those which are a separate move until our pending move is complete. (This works very similarly to the change to LocationDirector in narya) Relatedly, if a portal traversal is ignored due to staleness (again, due to near-simultaneous client & server moves), tell the client about it so that it doesn't wait around forever thinking it's got a pending move in progress. git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@970 c613c5cb-e716-0410-b11b-feb51c14d237 --- .../whirled/client/SceneDirector.as | 37 +++++- .../whirled/spot/client/SpotSceneDirector.as | 43 ++++++- .../whirled/spot/client/SpotService.as | 3 +- .../whirled/spot/data/SpotMarshaller.as | 7 +- .../whirled/zone/client/ZoneDirector.as | 12 +- .../whirled/client/SceneDirector.java | 47 ++++++- .../spot/client/SpotSceneDirector.java | 30 ++++- .../whirled/spot/client/SpotService.java | 13 +- .../whirled/spot/data/SpotMarshaller.java | 117 +++++++++++++++++- .../whirled/spot/server/SpotDispatcher.java | 4 +- .../whirled/spot/server/SpotProvider.java | 3 +- .../spot/server/SpotSceneRegistry.java | 4 +- .../whirled/zone/client/ZoneDirector.java | 18 ++- 13 files changed, 309 insertions(+), 29 deletions(-) diff --git a/src/as/com/threerings/whirled/client/SceneDirector.as b/src/as/com/threerings/whirled/client/SceneDirector.as index 65e8c465..5b744535 100644 --- a/src/as/com/threerings/whirled/client/SceneDirector.as +++ b/src/as/com/threerings/whirled/client/SceneDirector.as @@ -265,6 +265,8 @@ public class SceneDirector extends BasicDirector // and finally create a display scene instance with the model and the place config _scene = _fact.createScene(_model, config); + + handlePendingForcedMove(); } // from interface SceneService_SceneMoveListener @@ -361,6 +363,8 @@ public class SceneDirector extends BasicDirector // let our observers know that something has gone horribly awry _locdir.failedToMoveTo(sceneId, reason); + + handlePendingForcedMove(); } // from interface LocationObserver @@ -421,8 +425,16 @@ public class SceneDirector extends BasicDirector // just finish up what we're doing and assume that the repeated move request was the // spurious one as it would be in the case of lag causing rapid-fire repeat requests if (movePending()) { - log.info("Dropping forced move because we have a move pending", - "pendId", _pendingData.sceneId, "reqId", sceneId); + if (_pendingData.sceneId == sceneId) { + log.info("Dropping forced move because we have a move pending", + "pendId", _pendingData.sceneId, "reqId", sceneId); + } else { + log.info("Delaying forced move because we have a move pending", + "pendId", _pendingData.sceneId, "reqId", sceneId); + addPendingForcedMove(new function() :void { + forcedMove(sceneId); + }); + } return; } @@ -488,6 +500,12 @@ public class SceneDirector extends BasicDirector _sservice = null; } + public function cancelMoveRequest () :void + { + _pendingData = null; + handlePendingForcedMove(); + } + /** * Issues the scene move request using information from the supplied pending data. */ @@ -530,6 +548,18 @@ public class SceneDirector extends BasicDirector _scene = null; } + public function addPendingForcedMove (move :Function) :void + { + _pendingForcedMoves.push(move); + } + + protected function handlePendingForcedMove () :void + { + if (!_pendingForcedMoves.length == 0) { + _ctx.getClient().callLater(_pendingForcedMoves.pop()); + } + } + /** * Loads a scene from the repository. If the scene is cached, it will be returned from the * cache instead. @@ -619,5 +649,8 @@ public class SceneDirector extends BasicDirector /** Reference to our move handler. */ protected var _moveHandler :SceneDirector_MoveHandler = null; + + /** Forced move actions we should take once we complete the move we're in the middle of. */ + protected var _pendingForcedMoves :Array = []; } } diff --git a/src/as/com/threerings/whirled/spot/client/SpotSceneDirector.as b/src/as/com/threerings/whirled/spot/client/SpotSceneDirector.as index 23f84ba8..29b20073 100644 --- a/src/as/com/threerings/whirled/spot/client/SpotSceneDirector.as +++ b/src/as/com/threerings/whirled/spot/client/SpotSceneDirector.as @@ -159,7 +159,7 @@ public class SpotSceneDirector extends BasicDirector // issue a traversePortal request log.info("Issuing traversePortal(" + sceneId + ", " + dest + ", " + sceneVer + ")."); - _sservice.traversePortal(sceneId, portalId, sceneVer, _scdir); + _sservice.traversePortal(sceneId, portalId, sceneVer, new SceneDirectorWrapper(_scdir)); return true; } @@ -461,3 +461,44 @@ public class SpotSceneDirector extends BasicDirector protected var _clobj :DObject; } } + +import com.threerings.crowd.data.PlaceConfig; +import com.threerings.whirled.client.SceneDirector; +import com.threerings.whirled.data.SceneModel; +import com.threerings.whirled.spot.client.SpotService_SpotSceneMoveListener; + +class SceneDirectorWrapper + implements SpotService_SpotSceneMoveListener +{ + public function SceneDirectorWrapper (scdir :SceneDirector) { + _scdir = scdir; + } + + public function requestFailed (cause :String) :void { + _scdir.requestFailed(cause); + } + + public function moveSucceeded (placeId :int, config :PlaceConfig) :void { + _scdir.moveSucceeded(placeId, config); + } + + public function moveSucceededWithUpdates ( + placeId :int, config :PlaceConfig, updates :TypedArray) :void{ + _scdir.moveSucceededWithUpdates(placeId, config, updates); + } + + public function moveSucceededWithScene (placeId :int, config :PlaceConfig, + model :SceneModel) :void { + _scdir.moveSucceededWithScene(placeId, config, model); + } + + public function moveRequiresServerSwitch (hostname :String, ports :TypedArray) :void { + _scdir.moveRequiresServerSwitch(hostname, ports); + } + + public function requestCancelled () :void { + _scdir.cancelMoveRequest(); + } + + protected var _scdir :SceneDirector; +} \ No newline at end of file diff --git a/src/as/com/threerings/whirled/spot/client/SpotService.as b/src/as/com/threerings/whirled/spot/client/SpotService.as index 19779161..b9c100ae 100644 --- a/src/as/com/threerings/whirled/spot/client/SpotService.as +++ b/src/as/com/threerings/whirled/spot/client/SpotService.as @@ -24,7 +24,6 @@ package com.threerings.whirled.spot.client { import com.threerings.presents.client.Client; import com.threerings.presents.client.InvocationService; import com.threerings.presents.client.InvocationService_ConfirmListener; -import com.threerings.whirled.client.SceneService_SceneMoveListener; import com.threerings.whirled.spot.data.Location; /** @@ -42,6 +41,6 @@ public interface SpotService extends InvocationService function joinCluster (arg1 :int, arg2 :InvocationService_ConfirmListener) :void; // from Java interface SpotService - function traversePortal (arg1 :int, arg2 :int, arg3 :int, arg4 :SceneService_SceneMoveListener) :void; + function traversePortal (arg1 :int, arg2 :int, arg3 :int, arg4 :SpotService_SpotSceneMoveListener) :void; } } diff --git a/src/as/com/threerings/whirled/spot/data/SpotMarshaller.as b/src/as/com/threerings/whirled/spot/data/SpotMarshaller.as index e6f6450e..9f365961 100644 --- a/src/as/com/threerings/whirled/spot/data/SpotMarshaller.as +++ b/src/as/com/threerings/whirled/spot/data/SpotMarshaller.as @@ -27,9 +27,8 @@ import com.threerings.presents.data.InvocationMarshaller; import com.threerings.presents.data.InvocationMarshaller_ConfirmMarshaller; import com.threerings.util.Byte; import com.threerings.util.Integer; -import com.threerings.whirled.client.SceneService_SceneMoveListener; -import com.threerings.whirled.data.SceneMarshaller_SceneMoveMarshaller; import com.threerings.whirled.spot.client.SpotService; +import com.threerings.whirled.spot.client.SpotService_SpotSceneMoveListener; /** * Provides the implementation of the SpotService interface @@ -82,9 +81,9 @@ public class SpotMarshaller extends InvocationMarshaller public static const TRAVERSE_PORTAL :int = 4; // from interface SpotService - public function traversePortal (arg1 :int, arg2 :int, arg3 :int, arg4 :SceneService_SceneMoveListener) :void + public function traversePortal (arg1 :int, arg2 :int, arg3 :int, arg4 :SpotService_SpotSceneMoveListener) :void { - var listener4 :SceneMarshaller_SceneMoveMarshaller = new SceneMarshaller_SceneMoveMarshaller(); + var listener4 :SpotMarshaller_SpotSceneMoveMarshaller = new SpotMarshaller_SpotSceneMoveMarshaller(); listener4.listener = arg4; sendRequest(TRAVERSE_PORTAL, [ Integer.valueOf(arg1), Integer.valueOf(arg2), Integer.valueOf(arg3), listener4 diff --git a/src/as/com/threerings/whirled/zone/client/ZoneDirector.as b/src/as/com/threerings/whirled/zone/client/ZoneDirector.as index 1a96ad79..1c7ce013 100644 --- a/src/as/com/threerings/whirled/zone/client/ZoneDirector.as +++ b/src/as/com/threerings/whirled/zone/client/ZoneDirector.as @@ -232,8 +232,16 @@ public class ZoneDirector extends BasicDirector // just finish up what we're doing and assume that the repeated move request was the // spurious one as it would be in the case of lag causing rapid-fire repeat requests if (_scdir.movePending()) { - log.info("Dropping forced move because we have a move pending", - "pend", _scdir.getPendingModel(), "rzId", zoneId, "rsId", sceneId); + if (_scdir.getPendingSceneId() == sceneId) { + log.info("Dropping forced move because we have a move pending", + "pend", _scdir.getPendingModel(), "rzId", zoneId, "rsId", sceneId); + } else { + log.info("Delaying forced move because we have a move pending", + "pend", _scdir.getPendingModel(), "rzId", zoneId, "rsId", sceneId); + _scdir.addPendingForcedMove(new function() :void { + forcedMove(zoneId, sceneId); + }); + } return; } diff --git a/src/java/com/threerings/whirled/client/SceneDirector.java b/src/java/com/threerings/whirled/client/SceneDirector.java index ef5a66ab..f952c2e4 100644 --- a/src/java/com/threerings/whirled/client/SceneDirector.java +++ b/src/java/com/threerings/whirled/client/SceneDirector.java @@ -21,10 +21,13 @@ package com.threerings.whirled.client; +import java.util.ArrayList; import java.util.Map; import java.io.IOException; +import com.google.common.collect.Lists; + import com.samskivert.util.LRUHashMap; import com.samskivert.util.ResultListener; import com.threerings.presents.client.BasicDirector; @@ -248,6 +251,8 @@ public class SceneDirector extends BasicDirector // and finally create a display scene instance with the model and the place config _scene = _fact.createScene(_model, config); + + handlePendingForcedMove(); } // from interface SceneService.SceneMoveListener @@ -377,14 +382,24 @@ public class SceneDirector extends BasicDirector } // from interface SceneReceiver - public void forcedMove (int sceneId) + public void forcedMove (final int sceneId) { // if we're in the middle of a move, we can't abort it or we will screw everything up, so // just finish up what we're doing and assume that the repeated move request was the // spurious one as it would be in the case of lag causing rapid-fire repeat requests if (movePending()) { - log.info("Dropping forced move because we have a move pending", - "pendId", _pendingSceneId, "reqId", sceneId); + if (_pendingSceneId == sceneId) { + log.info("Dropping forced move because we have a move pending", + "pendId", _pendingSceneId, "reqId", sceneId); + } else { + log.info("Delaying forced move because we have a move pending", + "pendId", _pendingSceneId, "reqId", sceneId); + addPendingForcedMove(new Runnable() { + public void run () { + forcedMove(sceneId); + } + }); + } return; } @@ -420,6 +435,8 @@ public class SceneDirector extends BasicDirector moveTo(_previousSceneId); } } + + handlePendingForcedMove(); } protected void sendMoveRequest () @@ -502,10 +519,18 @@ public class SceneDirector extends BasicDirector _scache.clear(); _pendingSceneId = -1; _pendingModel = null; + _pendingForcedMoves.clear(); _previousSceneId = -1; _sservice = null; } + public void cancelMoveRequest () + { + _pendingSceneId = -1; + _pendingModel = null; + handlePendingForcedMove(); + } + @Override protected void registerServices (Client client) { @@ -519,6 +544,18 @@ public class SceneDirector extends BasicDirector _sservice = client.requireService(SceneService.class); } + public void addPendingForcedMove (Runnable move) + { + _pendingForcedMoves.add(move); + } + + protected void handlePendingForcedMove () + { + if (!_pendingForcedMoves.isEmpty()) { + _ctx.getClient().getRunQueue().postRunnable(_pendingForcedMoves.remove(0)); + } + } + /** Access to general client services. */ protected WhirledContext _ctx; @@ -558,4 +595,8 @@ public class SceneDirector extends BasicDirector /** Reference to our move handler. */ protected MoveHandler _moveHandler = null; + + /** Forced move actions we should take once we complete the move we're in the middle of. */ + protected ArrayList _pendingForcedMoves = Lists.newArrayList(); + } diff --git a/src/java/com/threerings/whirled/spot/client/SpotSceneDirector.java b/src/java/com/threerings/whirled/spot/client/SpotSceneDirector.java index 7c8da3bc..a4360a6c 100644 --- a/src/java/com/threerings/whirled/spot/client/SpotSceneDirector.java +++ b/src/java/com/threerings/whirled/spot/client/SpotSceneDirector.java @@ -43,6 +43,7 @@ import com.threerings.crowd.data.PlaceObject; import com.threerings.whirled.client.SceneDirector; import com.threerings.whirled.data.SceneModel; import com.threerings.whirled.data.ScenePlace; +import com.threerings.whirled.data.SceneUpdate; import com.threerings.whirled.spot.data.ClusteredBodyObject; import com.threerings.whirled.spot.data.Location; import com.threerings.whirled.spot.data.Portal; @@ -161,7 +162,34 @@ public class SpotSceneDirector extends BasicDirector // issue a traversePortal request log.info("Issuing traversePortal(" + sceneId + ", " + dest + ", " + sceneVer + ")."); - _sservice.traversePortal(_ctx.getClient(), sceneId, portalId, sceneVer, _scdir); + _sservice.traversePortal(_ctx.getClient(), sceneId, portalId, sceneVer, + new SpotService.SpotSceneMoveListener() { + public void requestFailed (String cause) { + _scdir.requestFailed(cause); + } + + public void moveSucceeded (int placeId, PlaceConfig config) { + _scdir.moveSucceeded(placeId, config); + } + + public void moveSucceededWithUpdates ( + int placeId, PlaceConfig config, SceneUpdate[] updates) { + _scdir.moveSucceededWithUpdates(placeId, config, updates); + } + + public void moveSucceededWithScene (int placeId, PlaceConfig config, + SceneModel model) { + _scdir.moveSucceededWithScene(placeId, config, model); + } + + public void moveRequiresServerSwitch (String hostname, int[] ports) { + _scdir.moveRequiresServerSwitch(hostname, ports); + } + + public void requestCancelled () { + _scdir.cancelMoveRequest(); + } + }); return true; } diff --git a/src/java/com/threerings/whirled/spot/client/SpotService.java b/src/java/com/threerings/whirled/spot/client/SpotService.java index dc1818f3..3e35fd9d 100644 --- a/src/java/com/threerings/whirled/spot/client/SpotService.java +++ b/src/java/com/threerings/whirled/spot/client/SpotService.java @@ -35,6 +35,17 @@ import com.threerings.whirled.spot.data.Location; */ public interface SpotService extends InvocationService { + /** + * Used to communicate the response to a {@link SceneService#moveTo} request. + */ + public static interface SpotSceneMoveListener extends SceneMoveListener + { + /** + * The request is not going through because it was cancelled due to some other action. + */ + public void requestCancelled (); + } + /** * Requests to traverse the specified portal. * @@ -46,7 +57,7 @@ public interface SpotService extends InvocationService */ public void traversePortal ( Client client, int sceneId, int portalId, int destSceneVer, - SceneMoveListener listener); + SpotSceneMoveListener listener); /** * Requests that this client's body be made to move to the specified diff --git a/src/java/com/threerings/whirled/spot/data/SpotMarshaller.java b/src/java/com/threerings/whirled/spot/data/SpotMarshaller.java index 49a4d6d1..aa107ea7 100644 --- a/src/java/com/threerings/whirled/spot/data/SpotMarshaller.java +++ b/src/java/com/threerings/whirled/spot/data/SpotMarshaller.java @@ -23,11 +23,13 @@ package com.threerings.whirled.spot.data; import javax.annotation.Generated; +import com.threerings.crowd.data.PlaceConfig; import com.threerings.presents.client.Client; import com.threerings.presents.client.InvocationService; import com.threerings.presents.data.InvocationMarshaller; -import com.threerings.whirled.client.SceneService; -import com.threerings.whirled.data.SceneMarshaller; +import com.threerings.presents.dobj.InvocationResponseEvent; +import com.threerings.whirled.data.SceneModel; +import com.threerings.whirled.data.SceneUpdate; import com.threerings.whirled.spot.client.SpotService; /** @@ -42,6 +44,113 @@ import com.threerings.whirled.spot.client.SpotService; public class SpotMarshaller extends InvocationMarshaller implements SpotService { + /** + * Marshalls results to implementations of {@link SpotService.SpotSceneMoveListener}. + */ + public static class SpotSceneMoveMarshaller extends ListenerMarshaller + implements SpotSceneMoveListener + { + /** The method id used to dispatch {@link #moveRequiresServerSwitch} + * responses. */ + public static final int MOVE_REQUIRES_SERVER_SWITCH = 1; + + // from interface SpotSceneMoveMarshaller + public void moveRequiresServerSwitch (String arg1, int[] arg2) + { + _invId = null; + omgr.postEvent(new InvocationResponseEvent( + callerOid, requestId, MOVE_REQUIRES_SERVER_SWITCH, + new Object[] { arg1, arg2 }, transport)); + } + + /** The method id used to dispatch {@link #moveSucceeded} + * responses. */ + public static final int MOVE_SUCCEEDED = 2; + + // from interface SpotSceneMoveMarshaller + public void moveSucceeded (int arg1, PlaceConfig arg2) + { + _invId = null; + omgr.postEvent(new InvocationResponseEvent( + callerOid, requestId, MOVE_SUCCEEDED, + new Object[] { Integer.valueOf(arg1), arg2 }, transport)); + } + + /** The method id used to dispatch {@link #moveSucceededWithScene} + * responses. */ + public static final int MOVE_SUCCEEDED_WITH_SCENE = 3; + + // from interface SpotSceneMoveMarshaller + public void moveSucceededWithScene (int arg1, PlaceConfig arg2, SceneModel arg3) + { + _invId = null; + omgr.postEvent(new InvocationResponseEvent( + callerOid, requestId, MOVE_SUCCEEDED_WITH_SCENE, + new Object[] { Integer.valueOf(arg1), arg2, arg3 }, transport)); + } + + /** The method id used to dispatch {@link #moveSucceededWithUpdates} + * responses. */ + public static final int MOVE_SUCCEEDED_WITH_UPDATES = 4; + + // from interface SpotSceneMoveMarshaller + public void moveSucceededWithUpdates (int arg1, PlaceConfig arg2, SceneUpdate[] arg3) + { + _invId = null; + omgr.postEvent(new InvocationResponseEvent( + callerOid, requestId, MOVE_SUCCEEDED_WITH_UPDATES, + new Object[] { Integer.valueOf(arg1), arg2, arg3 }, transport)); + } + + /** The method id used to dispatch {@link #requestCancelled} + * responses. */ + public static final int REQUEST_CANCELLED = 5; + + // from interface SpotSceneMoveMarshaller + public void requestCancelled () + { + _invId = null; + omgr.postEvent(new InvocationResponseEvent( + callerOid, requestId, REQUEST_CANCELLED, + new Object[] { }, transport)); + } + + @Override // from InvocationMarshaller + public void dispatchResponse (int methodId, Object[] args) + { + switch (methodId) { + case MOVE_REQUIRES_SERVER_SWITCH: + ((SpotSceneMoveListener)listener).moveRequiresServerSwitch( + (String)args[0], (int[])args[1]); + return; + + case MOVE_SUCCEEDED: + ((SpotSceneMoveListener)listener).moveSucceeded( + ((Integer)args[0]).intValue(), (PlaceConfig)args[1]); + return; + + case MOVE_SUCCEEDED_WITH_SCENE: + ((SpotSceneMoveListener)listener).moveSucceededWithScene( + ((Integer)args[0]).intValue(), (PlaceConfig)args[1], (SceneModel)args[2]); + return; + + case MOVE_SUCCEEDED_WITH_UPDATES: + ((SpotSceneMoveListener)listener).moveSucceededWithUpdates( + ((Integer)args[0]).intValue(), (PlaceConfig)args[1], (SceneUpdate[])args[2]); + return; + + case REQUEST_CANCELLED: + ((SpotSceneMoveListener)listener).requestCancelled( + ); + return; + + default: + super.dispatchResponse(methodId, args); + return; + } + } + } + /** The method id used to dispatch {@link #changeLocation} requests. */ public static final int CHANGE_LOCATION = 1; @@ -83,9 +192,9 @@ public class SpotMarshaller extends InvocationMarshaller public static final int TRAVERSE_PORTAL = 4; // from interface SpotService - public void traversePortal (Client arg1, int arg2, int arg3, int arg4, SceneService.SceneMoveListener arg5) + public void traversePortal (Client arg1, int arg2, int arg3, int arg4, SpotService.SpotSceneMoveListener arg5) { - SceneMarshaller.SceneMoveMarshaller listener5 = new SceneMarshaller.SceneMoveMarshaller(); + SpotMarshaller.SpotSceneMoveMarshaller listener5 = new SpotMarshaller.SpotSceneMoveMarshaller(); listener5.listener = arg5; sendRequest(arg1, TRAVERSE_PORTAL, new Object[] { Integer.valueOf(arg2), Integer.valueOf(arg3), Integer.valueOf(arg4), listener5 diff --git a/src/java/com/threerings/whirled/spot/server/SpotDispatcher.java b/src/java/com/threerings/whirled/spot/server/SpotDispatcher.java index 2d95bc3d..65224be8 100644 --- a/src/java/com/threerings/whirled/spot/server/SpotDispatcher.java +++ b/src/java/com/threerings/whirled/spot/server/SpotDispatcher.java @@ -27,7 +27,7 @@ import com.threerings.presents.client.InvocationService; import com.threerings.presents.data.ClientObject; import com.threerings.presents.server.InvocationDispatcher; import com.threerings.presents.server.InvocationException; -import com.threerings.whirled.client.SceneService; +import com.threerings.whirled.spot.client.SpotService; import com.threerings.whirled.spot.data.Location; import com.threerings.whirled.spot.data.SpotMarshaller; @@ -79,7 +79,7 @@ public class SpotDispatcher extends InvocationDispatcher case SpotMarshaller.TRAVERSE_PORTAL: ((SpotProvider)provider).traversePortal( - source, ((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), ((Integer)args[2]).intValue(), (SceneService.SceneMoveListener)args[3] + source, ((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), ((Integer)args[2]).intValue(), (SpotService.SpotSceneMoveListener)args[3] ); return; diff --git a/src/java/com/threerings/whirled/spot/server/SpotProvider.java b/src/java/com/threerings/whirled/spot/server/SpotProvider.java index aed35e27..afd801a7 100644 --- a/src/java/com/threerings/whirled/spot/server/SpotProvider.java +++ b/src/java/com/threerings/whirled/spot/server/SpotProvider.java @@ -27,7 +27,6 @@ import com.threerings.presents.client.InvocationService; import com.threerings.presents.data.ClientObject; import com.threerings.presents.server.InvocationException; import com.threerings.presents.server.InvocationProvider; -import com.threerings.whirled.client.SceneService; import com.threerings.whirled.spot.client.SpotService; import com.threerings.whirled.spot.data.Location; @@ -58,6 +57,6 @@ public interface SpotProvider extends InvocationProvider /** * Handles a {@link SpotService#traversePortal} request. */ - void traversePortal (ClientObject caller, int arg1, int arg2, int arg3, SceneService.SceneMoveListener arg4) + void traversePortal (ClientObject caller, int arg1, int arg2, int arg3, SpotService.SpotSceneMoveListener arg4) throws InvocationException; } diff --git a/src/java/com/threerings/whirled/spot/server/SpotSceneRegistry.java b/src/java/com/threerings/whirled/spot/server/SpotSceneRegistry.java index 2358c0b1..a52d61a1 100644 --- a/src/java/com/threerings/whirled/spot/server/SpotSceneRegistry.java +++ b/src/java/com/threerings/whirled/spot/server/SpotSceneRegistry.java @@ -115,7 +115,7 @@ public class SpotSceneRegistry extends SceneRegistry // from interface SpotProvider public void traversePortal (ClientObject caller, int sceneId, int portalId, - int destSceneVer, SceneService.SceneMoveListener listener) + int destSceneVer, SpotService.SpotSceneMoveListener listener) throws InvocationException { // le sanity check @@ -125,7 +125,7 @@ public class SpotSceneRegistry extends SceneRegistry log.info("Ignoring stale traverse portal request [caller=" + caller.who() + ", oSceneId=" + sceneId + ", portalId=" + portalId + ", cSceneId=" + cSceneId + "]."); - InvocationMarshaller.setNoResponse(listener); + listener.requestCancelled(); return; } diff --git a/src/java/com/threerings/whirled/zone/client/ZoneDirector.java b/src/java/com/threerings/whirled/zone/client/ZoneDirector.java index 3693e317..c0f13b85 100644 --- a/src/java/com/threerings/whirled/zone/client/ZoneDirector.java +++ b/src/java/com/threerings/whirled/zone/client/ZoneDirector.java @@ -253,14 +253,26 @@ public class ZoneDirector extends BasicDirector } // documentation inherited from interface - public void forcedMove (int zoneId, int sceneId) + public void forcedMove (final int zoneId, final int sceneId) { // if we're in the middle of a move, we can't abort it or we will screw everything up, so // just finish up what we're doing and assume that the repeated move request was the // spurious one as it would be in the case of lag causing rapid-fire repeat requests if (_scdir.movePending()) { - log.info("Dropping forced move because we have a move pending", - "pend", _scdir.getPendingModel(), "rzId", zoneId, "rsId", sceneId); + if (_scdir.getPendingSceneId() == sceneId) { + log.info("Dropping forced move because we have a move pending", + "pend", _scdir.getPendingModel(), "rzId", zoneId, "rsId", sceneId); + } else { + log.info("Delaying forced move because we have a move pending", + "pend", _scdir.getPendingModel(), "rzId", zoneId, "rsId", sceneId); + // We have a move pending to a DIFFERENT scene - we'll do this as soon as that's + // done. + _scdir.addPendingForcedMove(new Runnable() { + public void run () { + forcedMove(zoneId, sceneId); + } + }); + } return; }