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; }