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
This commit is contained in:
Mike Thomas
2010-10-05 20:56:24 +00:00
parent 86a348222f
commit 9fe0c6f082
13 changed files with 309 additions and 29 deletions
@@ -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 = [];
}
}
@@ -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;
}
@@ -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;
}
}
@@ -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 <code>SpotService</code> 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
@@ -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;
}