Make the zone handling appropriately peer-aware. It's worth noting that due to adding moveRequiresServerSwitch() to ZoneService, this will break some things which use this.
git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@913 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
@@ -7,6 +7,7 @@ import com.threerings.util.ResultListener;
|
|||||||
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.crowd.data.PlaceConfig;
|
import com.threerings.crowd.data.PlaceConfig;
|
||||||
|
|
||||||
@@ -97,22 +98,31 @@ public class ZoneDirector extends BasicDirector
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_pendingZoneId = zoneId;
|
||||||
|
|
||||||
|
sendMoveRequest();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function sendMoveRequest () :void
|
||||||
|
{
|
||||||
// let our zone observers know that we're attempting to switch zones
|
// let our zone observers know that we're attempting to switch zones
|
||||||
notifyObservers(zoneId);
|
notifyObservers(_pendingZoneId);
|
||||||
|
|
||||||
// check the version of our cached copy of the scene to which we're requesting to move; if
|
// 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
|
// we were unable to load it, assume a cached version of zero
|
||||||
var sceneVers :int = 0;
|
var sceneVers :int = 0;
|
||||||
|
var sceneId :int = -1;
|
||||||
var pendingModel :SceneModel = _scdir.getPendingModel();
|
var pendingModel :SceneModel = _scdir.getPendingModel();
|
||||||
if (pendingModel != null) {
|
if (pendingModel != null) {
|
||||||
sceneVers = pendingModel.version;
|
sceneVers = pendingModel.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
// issue a moveTo request
|
// issue a moveTo request
|
||||||
log.info("Issuing zoned moveTo(" + ZoneUtil.toString(zoneId) +
|
log.info("Issuing zoned moveTo(" + ZoneUtil.toString(_pendingZoneId) +
|
||||||
", " + sceneId + ", " + sceneVers + ").");
|
", " + sceneId + ", " + sceneVers + ").");
|
||||||
_zservice.moveTo(zoneId, sceneId, sceneVers, this);
|
_zservice.moveTo(_pendingZoneId, sceneId, sceneVers, this);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override protected function fetchServices (client :Client) :void
|
override protected function fetchServices (client :Client) :void
|
||||||
@@ -141,6 +151,9 @@ public class ZoneDirector extends BasicDirector
|
|||||||
// keep track of the summary
|
// keep track of the summary
|
||||||
_summary = summary;
|
_summary = summary;
|
||||||
|
|
||||||
|
// We're not heading there any more.
|
||||||
|
_pendingZoneId = -1;
|
||||||
|
|
||||||
// pass the rest off to the standard scene transition code
|
// pass the rest off to the standard scene transition code
|
||||||
_scdir.moveSucceeded(placeId, config);
|
_scdir.moveSucceeded(placeId, config);
|
||||||
|
|
||||||
@@ -156,6 +169,9 @@ public class ZoneDirector extends BasicDirector
|
|||||||
// keep track of the summary
|
// keep track of the summary
|
||||||
_summary = summary;
|
_summary = summary;
|
||||||
|
|
||||||
|
// We're not heading there any more.
|
||||||
|
_pendingZoneId = -1;
|
||||||
|
|
||||||
// pass the rest off to the standard scene transition code
|
// pass the rest off to the standard scene transition code
|
||||||
_scdir.moveSucceededWithUpdates(placeId, config, updates);
|
_scdir.moveSucceededWithUpdates(placeId, config, updates);
|
||||||
|
|
||||||
@@ -170,6 +186,9 @@ public class ZoneDirector extends BasicDirector
|
|||||||
// keep track of the summary
|
// keep track of the summary
|
||||||
_summary = summary;
|
_summary = summary;
|
||||||
|
|
||||||
|
// We're not heading there any more.
|
||||||
|
_pendingZoneId = -1;
|
||||||
|
|
||||||
// pass the rest off to the standard scene transition code
|
// pass the rest off to the standard scene transition code
|
||||||
_scdir.moveSucceededWithScene(placeId, config, model);
|
_scdir.moveSucceededWithScene(placeId, config, model);
|
||||||
|
|
||||||
@@ -177,6 +196,17 @@ public class ZoneDirector extends BasicDirector
|
|||||||
notifyObservers(summary);
|
notifyObservers(summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// from interface ZoneService_ZoneMoveListener
|
||||||
|
public function moveRequiresServerSwitch (hostname :String, ports :TypedArray) :void
|
||||||
|
{
|
||||||
|
log.info("Zone switch requires server switch", "host", hostname, "ports", ports);
|
||||||
|
// ship on over to the other server
|
||||||
|
_wCtx.getClient().moveToServer(hostname, ports, new ConfirmAdapter(
|
||||||
|
function () :void { // succeeded
|
||||||
|
sendMoveRequest();
|
||||||
|
}, requestFailed));
|
||||||
|
}
|
||||||
|
|
||||||
// from interface ZoneService.ZoneMoveListener
|
// from interface ZoneService.ZoneMoveListener
|
||||||
public function requestFailed (reason :String) :void
|
public function requestFailed (reason :String) :void
|
||||||
{
|
{
|
||||||
@@ -215,6 +245,9 @@ public class ZoneDirector extends BasicDirector
|
|||||||
return; // if we're currently somewhere, just stay there
|
return; // if we're currently somewhere, just stay there
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not gonna get there, so clear it.
|
||||||
|
_pendingZoneId = -1;
|
||||||
|
|
||||||
// otherwise if we were previously in a zone/scene, try going back there
|
// otherwise if we were previously in a zone/scene, try going back there
|
||||||
if (_previousZoneId != -1) {
|
if (_previousZoneId != -1) {
|
||||||
moveTo(_previousZoneId, previousSceneId);
|
moveTo(_previousZoneId, previousSceneId);
|
||||||
@@ -263,5 +296,8 @@ public class ZoneDirector extends BasicDirector
|
|||||||
|
|
||||||
/** Our previous zone id. */
|
/** Our previous zone id. */
|
||||||
protected var _previousZoneId :int = -1;
|
protected var _previousZoneId :int = -1;
|
||||||
|
|
||||||
|
/** Where we're headed. */
|
||||||
|
protected var _pendingZoneId :int = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ import com.threerings.whirled.zone.data.ZoneSummary;
|
|||||||
public interface ZoneService_ZoneMoveListener
|
public interface ZoneService_ZoneMoveListener
|
||||||
extends InvocationService_InvocationListener
|
extends InvocationService_InvocationListener
|
||||||
{
|
{
|
||||||
|
// from Java ZoneService_ZoneMoveListener
|
||||||
|
function moveRequiresServerSwitch (arg1 :String, arg2 :TypedArray /* of int */) :void
|
||||||
|
|
||||||
// from Java ZoneService_ZoneMoveListener
|
// from Java ZoneService_ZoneMoveListener
|
||||||
function moveSucceeded (arg1 :int, arg2 :PlaceConfig, arg3 :ZoneSummary) :void
|
function moveSucceeded (arg1 :int, arg2 :PlaceConfig, arg3 :ZoneSummary) :void
|
||||||
|
|
||||||
|
|||||||
@@ -33,19 +33,27 @@ import com.threerings.whirled.zone.client.ZoneService_ZoneMoveListener;
|
|||||||
public class ZoneMarshaller_ZoneMoveMarshaller
|
public class ZoneMarshaller_ZoneMoveMarshaller
|
||||||
extends InvocationMarshaller_ListenerMarshaller
|
extends InvocationMarshaller_ListenerMarshaller
|
||||||
{
|
{
|
||||||
|
/** The method id used to dispatch <code>moveRequiresServerSwitch</code> responses. */
|
||||||
|
public static const MOVE_REQUIRES_SERVER_SWITCH :int = 1;
|
||||||
|
|
||||||
/** The method id used to dispatch <code>moveSucceeded</code> responses. */
|
/** The method id used to dispatch <code>moveSucceeded</code> responses. */
|
||||||
public static const MOVE_SUCCEEDED :int = 1;
|
public static const MOVE_SUCCEEDED :int = 2;
|
||||||
|
|
||||||
/** The method id used to dispatch <code>moveSucceededWithScene</code> responses. */
|
/** The method id used to dispatch <code>moveSucceededWithScene</code> 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 <code>moveSucceededWithUpdates</code> responses. */
|
/** The method id used to dispatch <code>moveSucceededWithUpdates</code> 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 ZoneService_ZoneMoveListener).moveRequiresServerSwitch(
|
||||||
|
(args[0] as String), (args[1] as TypedArray /* of int */));
|
||||||
|
return;
|
||||||
|
|
||||||
case MOVE_SUCCEEDED:
|
case MOVE_SUCCEEDED:
|
||||||
(listener as ZoneService_ZoneMoveListener).moveSucceeded(
|
(listener as ZoneService_ZoneMoveListener).moveSucceeded(
|
||||||
(args[0] as int), (args[1] as PlaceConfig), (args[2] as ZoneSummary));
|
(args[0] as int), (args[1] as PlaceConfig), (args[2] as ZoneSummary));
|
||||||
|
|||||||
@@ -129,22 +129,31 @@ public class ZoneDirector extends BasicDirector
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_pendingZoneId = zoneId;
|
||||||
|
|
||||||
|
sendMoveRequest();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sendMoveRequest ()
|
||||||
|
{
|
||||||
// let our zone observers know that we're attempting to switch zones
|
// let our zone observers know that we're attempting to switch zones
|
||||||
notifyObservers(Integer.valueOf(zoneId));
|
notifyObservers(Integer.valueOf(_pendingZoneId));
|
||||||
|
|
||||||
// check the version of our cached copy of the scene to which we're requesting to move; if
|
// 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
|
// we were unable to load it, assume a cached version of zero
|
||||||
int sceneVers = 0;
|
int sceneVers = 0;
|
||||||
|
int sceneId = -1;
|
||||||
SceneModel pendingModel = _scdir.getPendingModel();
|
SceneModel pendingModel = _scdir.getPendingModel();
|
||||||
if (pendingModel != null) {
|
if (pendingModel != null) {
|
||||||
sceneVers = pendingModel.version;
|
sceneVers = pendingModel.version;
|
||||||
|
sceneId = pendingModel.sceneId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// issue a moveTo request
|
// issue a moveTo request
|
||||||
log.info("Issuing zoned moveTo(" + ZoneUtil.toString(zoneId) +
|
log.info("Issuing zoned moveTo(" + ZoneUtil.toString(_pendingZoneId) +
|
||||||
", " + sceneId + ", " + sceneVers + ").");
|
", " + sceneId + ", " + sceneVers + ").");
|
||||||
_zservice.moveTo(_ctx.getClient(), zoneId, sceneId, sceneVers, this);
|
_zservice.moveTo(_ctx.getClient(), _pendingZoneId, + sceneId, sceneVers, this);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -164,6 +173,21 @@ public class ZoneDirector extends BasicDirector
|
|||||||
_previousZoneId = -1;
|
_previousZoneId = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// from interface SceneService.SceneMoveListener
|
||||||
|
public void moveRequiresServerSwitch (String hostname, int[] ports)
|
||||||
|
{
|
||||||
|
// ship on over to the other server
|
||||||
|
_ctx.getClient().moveToServer(hostname, ports, new ZoneService.ConfirmListener() {
|
||||||
|
public void requestProcessed () {
|
||||||
|
// resend our move request now that we're connected to the new server
|
||||||
|
sendMoveRequest();
|
||||||
|
}
|
||||||
|
public void requestFailed (String reason) {
|
||||||
|
ZoneDirector.this.requestFailed(reason);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// from interface ZoneService.ZoneMoveListener
|
// from interface ZoneService.ZoneMoveListener
|
||||||
public void moveSucceeded (int placeId, PlaceConfig config, ZoneSummary summary)
|
public void moveSucceeded (int placeId, PlaceConfig config, ZoneSummary summary)
|
||||||
{
|
{
|
||||||
@@ -175,6 +199,9 @@ public class ZoneDirector extends BasicDirector
|
|||||||
// keep track of the summary
|
// keep track of the summary
|
||||||
_summary = summary;
|
_summary = summary;
|
||||||
|
|
||||||
|
// We're not heading there any more.
|
||||||
|
_pendingZoneId = -1;
|
||||||
|
|
||||||
// pass the rest off to the standard scene transition code
|
// pass the rest off to the standard scene transition code
|
||||||
_scdir.moveSucceeded(placeId, config);
|
_scdir.moveSucceeded(placeId, config);
|
||||||
|
|
||||||
@@ -189,6 +216,9 @@ public class ZoneDirector extends BasicDirector
|
|||||||
// keep track of the summary
|
// keep track of the summary
|
||||||
_summary = summary;
|
_summary = summary;
|
||||||
|
|
||||||
|
// We're not heading there any more.
|
||||||
|
_pendingZoneId = -1;
|
||||||
|
|
||||||
// pass the rest off to the standard scene transition code
|
// pass the rest off to the standard scene transition code
|
||||||
_scdir.moveSucceededWithUpdates(placeId, config, updates);
|
_scdir.moveSucceededWithUpdates(placeId, config, updates);
|
||||||
|
|
||||||
@@ -203,6 +233,9 @@ public class ZoneDirector extends BasicDirector
|
|||||||
// keep track of the summary
|
// keep track of the summary
|
||||||
_summary = summary;
|
_summary = summary;
|
||||||
|
|
||||||
|
// We're not heading there any more.
|
||||||
|
_pendingZoneId = -1;
|
||||||
|
|
||||||
// pass the rest off to the standard scene transition code
|
// pass the rest off to the standard scene transition code
|
||||||
_scdir.moveSucceededWithScene(placeId, config, model);
|
_scdir.moveSucceededWithScene(placeId, config, model);
|
||||||
|
|
||||||
@@ -247,6 +280,9 @@ public class ZoneDirector extends BasicDirector
|
|||||||
return; // if we're currently somewhere, just stay there
|
return; // if we're currently somewhere, just stay there
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not gonna get there, so clear it.
|
||||||
|
_pendingZoneId = -1;
|
||||||
|
|
||||||
// otherwise if we were previously in a zone/scene, try going back there
|
// otherwise if we were previously in a zone/scene, try going back there
|
||||||
if (_previousZoneId != -1) {
|
if (_previousZoneId != -1) {
|
||||||
moveTo(_previousZoneId, previousSceneId);
|
moveTo(_previousZoneId, previousSceneId);
|
||||||
@@ -295,4 +331,7 @@ public class ZoneDirector extends BasicDirector
|
|||||||
|
|
||||||
/** Our previous zone id. */
|
/** Our previous zone id. */
|
||||||
protected int _previousZoneId = -1;
|
protected int _previousZoneId = -1;
|
||||||
|
|
||||||
|
/** Where we're headed. */
|
||||||
|
protected int _pendingZoneId = -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,12 @@ public interface ZoneService extends InvocationService
|
|||||||
*/
|
*/
|
||||||
public void moveSucceededWithScene (
|
public void moveSucceededWithScene (
|
||||||
int placeId, PlaceConfig config, ZoneSummary summary, SceneModel model);
|
int placeId, PlaceConfig config, ZoneSummary summary, SceneModel model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the client must switch to the specified server and reissue its move
|
||||||
|
* request in order to relocate to its desired zone.
|
||||||
|
*/
|
||||||
|
public void moveRequiresServerSwitch (String hostname, int[] ports);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,9 +49,22 @@ public class ZoneMarshaller extends InvocationMarshaller
|
|||||||
public static class ZoneMoveMarshaller extends ListenerMarshaller
|
public static class ZoneMoveMarshaller extends ListenerMarshaller
|
||||||
implements ZoneMoveListener
|
implements ZoneMoveListener
|
||||||
{
|
{
|
||||||
|
/** The method id used to dispatch {@link #moveRequiresServerSwitch}
|
||||||
|
* responses. */
|
||||||
|
public static final int MOVE_REQUIRES_SERVER_SWITCH = 1;
|
||||||
|
|
||||||
|
// from interface ZoneMoveMarshaller
|
||||||
|
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}
|
/** 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 ZoneMoveMarshaller
|
// from interface ZoneMoveMarshaller
|
||||||
public void moveSucceeded (int arg1, PlaceConfig arg2, ZoneSummary arg3)
|
public void moveSucceeded (int arg1, PlaceConfig arg2, ZoneSummary arg3)
|
||||||
@@ -64,7 +77,7 @@ public class ZoneMarshaller 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 ZoneMoveMarshaller
|
// from interface ZoneMoveMarshaller
|
||||||
public void moveSucceededWithScene (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneModel arg4)
|
public void moveSucceededWithScene (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneModel arg4)
|
||||||
@@ -77,7 +90,7 @@ public class ZoneMarshaller 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 ZoneMoveMarshaller
|
// from interface ZoneMoveMarshaller
|
||||||
public void moveSucceededWithUpdates (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneUpdate[] arg4)
|
public void moveSucceededWithUpdates (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneUpdate[] arg4)
|
||||||
@@ -92,6 +105,11 @@ public class ZoneMarshaller 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:
|
||||||
|
((ZoneMoveListener)listener).moveRequiresServerSwitch(
|
||||||
|
(String)args[0], (int[])args[1]);
|
||||||
|
return;
|
||||||
|
|
||||||
case MOVE_SUCCEEDED:
|
case MOVE_SUCCEEDED:
|
||||||
((ZoneMoveListener)listener).moveSucceeded(
|
((ZoneMoveListener)listener).moveSucceeded(
|
||||||
((Integer)args[0]).intValue(), (PlaceConfig)args[1], (ZoneSummary)args[2]);
|
((Integer)args[0]).intValue(), (PlaceConfig)args[1], (ZoneSummary)args[2]);
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.threerings.whirled.zone.peer.data;
|
||||||
|
|
||||||
|
import com.threerings.io.SimpleStreamableObject;
|
||||||
|
|
||||||
|
import com.threerings.util.Name;
|
||||||
|
|
||||||
|
import com.threerings.presents.dobj.DSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a zone hosted on some node.
|
||||||
|
*/
|
||||||
|
public class HostedZone extends SimpleStreamableObject
|
||||||
|
implements DSet.Entry
|
||||||
|
{
|
||||||
|
/** The unique ID for the zone in question. */
|
||||||
|
public int zoneId;
|
||||||
|
|
||||||
|
/** The name of the zone being hosted. */
|
||||||
|
public Name name;
|
||||||
|
|
||||||
|
public HostedZone ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public HostedZone (int zoneId, Name name)
|
||||||
|
{
|
||||||
|
this.zoneId = zoneId;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// from DSet.Entry
|
||||||
|
public Comparable<?> getKey ()
|
||||||
|
{
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.threerings.whirled.zone.peer.server;
|
||||||
|
|
||||||
|
import com.threerings.whirled.zone.peer.server.PeeredZoneRegistry.PeerZoneShutdownListener;
|
||||||
|
import com.threerings.whirled.zone.server.ZoneManager;
|
||||||
|
|
||||||
|
public interface PeeredZoneManager
|
||||||
|
extends ZoneManager
|
||||||
|
{
|
||||||
|
/** Registers a shutdown listener with the zone. */
|
||||||
|
public void setShutdownListener (int zoneId, PeerZoneShutdownListener shutdowner);
|
||||||
|
}
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
package com.threerings.whirled.zone.peer.server;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.samskivert.util.ResultListener;
|
||||||
|
import com.samskivert.util.Tuple;
|
||||||
|
|
||||||
|
import com.threerings.presents.data.ClientObject;
|
||||||
|
import com.threerings.presents.data.InvocationCodes;
|
||||||
|
import com.threerings.presents.server.InvocationException;
|
||||||
|
import com.threerings.presents.server.InvocationManager;
|
||||||
|
|
||||||
|
import com.threerings.crowd.data.BodyObject;
|
||||||
|
import com.threerings.crowd.server.LocationManager;
|
||||||
|
|
||||||
|
import com.threerings.whirled.server.SceneRegistry;
|
||||||
|
import com.threerings.whirled.zone.client.ZoneService;
|
||||||
|
import com.threerings.whirled.zone.data.ZoneCodes;
|
||||||
|
import com.threerings.whirled.zone.data.ZoneSummary;
|
||||||
|
import com.threerings.whirled.zone.peer.data.HostedZone;
|
||||||
|
import com.threerings.whirled.zone.server.ZoneManager;
|
||||||
|
import com.threerings.whirled.zone.server.ZoneMoveHandler;
|
||||||
|
import com.threerings.whirled.zone.server.ZoneRegistry;
|
||||||
|
import com.threerings.whirled.zone.server.ZoneManager.ResolutionListener;
|
||||||
|
|
||||||
|
import static com.threerings.whirled.zone.Log.log;
|
||||||
|
|
||||||
|
public abstract class PeeredZoneRegistry extends ZoneRegistry
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Peer-awareness for finding out about zones.
|
||||||
|
*/
|
||||||
|
public static interface PeerZoneResolutionListener extends ResolutionListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Called when the zone is already hosted on another node.
|
||||||
|
*/
|
||||||
|
public void zoneOnNode (Tuple<String, HostedZone> nodeInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peered zones should be sure to call back to one of these when they're going away.
|
||||||
|
*/
|
||||||
|
public static interface PeerZoneShutdownListener
|
||||||
|
{
|
||||||
|
public void zoneDidShutdown (int zoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ZoneMoveHandler that can receive the sceneOnNode() callback.
|
||||||
|
*/
|
||||||
|
public abstract static class PeerZoneMoveHandler extends ZoneMoveHandler
|
||||||
|
implements PeerZoneResolutionListener
|
||||||
|
{
|
||||||
|
public PeerZoneMoveHandler (
|
||||||
|
LocationManager locman, ZoneManager zmgr, SceneRegistry scReg, BodyObject body,
|
||||||
|
int sceneId, int sceneVer, ZoneService.ZoneMoveListener listener)
|
||||||
|
{
|
||||||
|
super(locman, zmgr, scReg, body, sceneId, sceneVer, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract PeerZoneMoveHandler createMoveHandler (LocationManager locman,
|
||||||
|
ZoneManager zmgr, SceneRegistry scReg, BodyObject body, int sceneId, int sceneVer,
|
||||||
|
ZoneService.ZoneMoveListener listener);
|
||||||
|
|
||||||
|
@Inject public PeeredZoneRegistry (InvocationManager invmgr, ZonePeerManager peerMgr)
|
||||||
|
{
|
||||||
|
super(invmgr);
|
||||||
|
_peerMgr = peerMgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerZoneManager (byte zoneType, ZoneManager manager)
|
||||||
|
{
|
||||||
|
if (!(manager instanceof PeeredZoneManager)) {
|
||||||
|
throw new IllegalArgumentException("All ZoneManagers received by PeeredZoneRegistry " +
|
||||||
|
"must be PeeredZoneManagers");
|
||||||
|
}
|
||||||
|
super.registerZoneManager(zoneType, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PeeredZoneManager getZoneManager (int qualifiedZoneId)
|
||||||
|
{
|
||||||
|
return (PeeredZoneManager)super.getZoneManager(qualifiedZoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveTo (ClientObject caller, int zoneId, int sceneId,
|
||||||
|
int sceneVer, ZoneService.ZoneMoveListener listener)
|
||||||
|
throws InvocationException
|
||||||
|
{
|
||||||
|
if (!(caller instanceof BodyObject)) {
|
||||||
|
log.warning("Request to switch zones by non-BodyObject " +
|
||||||
|
"[clobj=" + caller.getClass() + "].");
|
||||||
|
throw new InvocationException(ZoneCodes.INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
BodyObject body = (BodyObject)caller;
|
||||||
|
|
||||||
|
PeerZoneMoveHandler handler = createMoveHandler(_locman, getZoneManager(zoneId),
|
||||||
|
_screg, body, sceneId, sceneVer, listener);
|
||||||
|
|
||||||
|
resolvePeerZone(zoneId, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resolveZone (int zoneId, ResolutionListener listener)
|
||||||
|
{
|
||||||
|
PeeredZoneManager zmgr = getZoneManager(zoneId);
|
||||||
|
if (zmgr == null) {
|
||||||
|
log.warning("Trying to resolve a zone for which we have no manager", "zoneId", zoneId);
|
||||||
|
listener.zoneFailedToResolve(zoneId, new Exception(InvocationCodes.INTERNAL_ERROR));
|
||||||
|
} else {
|
||||||
|
zmgr.resolveZone(zoneId, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a zone, or return the information on the peer on which it's hosted.
|
||||||
|
*/
|
||||||
|
public void resolvePeerZone (final int zoneId, final PeerZoneResolutionListener listener)
|
||||||
|
{
|
||||||
|
// check to see if the destination zone is already hosted on a server
|
||||||
|
Tuple<String, HostedZone> nodeInfo = _peerMgr.getZoneHost(zoneId);
|
||||||
|
|
||||||
|
// if it's already hosted...
|
||||||
|
if (nodeInfo != null) {
|
||||||
|
// it's hosted on this server! It should already be resolved...
|
||||||
|
if (_peerMgr.getNodeObject().nodeName.equals(nodeInfo.left)) {
|
||||||
|
resolveZone(zoneId, listener);
|
||||||
|
} else {
|
||||||
|
listener.zoneOnNode(nodeInfo); // somewhere else, pass the buck
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise the zone is not resolved here nor there; so we claim the zone by acquiring a
|
||||||
|
// distributed lock and then resolve it locally
|
||||||
|
_peerMgr.acquireLock(ZonePeerManager.getZoneLock(zoneId), new ResultListener<String>() {
|
||||||
|
public void requestCompleted (String nodeName) {
|
||||||
|
if (_peerMgr.getNodeObject().nodeName.equals(nodeName)) {
|
||||||
|
log.debug("Got lock, resolving zone", "zoneId", zoneId);
|
||||||
|
resolveZone(zoneId, new ResolutionListener() {
|
||||||
|
public void zoneWasResolved (ZoneSummary zonesum) {
|
||||||
|
releaseLock();
|
||||||
|
_peerMgr.zoneDidStartup(zonesum.zoneId, zonesum.name);
|
||||||
|
PeerZoneShutdownListener shutdowner = new PeerZoneShutdownListener() {
|
||||||
|
public void zoneDidShutdown (int zoneId) {
|
||||||
|
_peerMgr.zoneDidShutdown(zoneId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
getZoneManager(zonesum.zoneId).setShutdownListener(
|
||||||
|
zonesum.zoneId, shutdowner);
|
||||||
|
listener.zoneWasResolved(zonesum);
|
||||||
|
}
|
||||||
|
public void zoneFailedToResolve (int zoneId, Exception reason) {
|
||||||
|
releaseLock();
|
||||||
|
listener.zoneFailedToResolve(zoneId, reason);
|
||||||
|
}
|
||||||
|
protected void releaseLock () {
|
||||||
|
_peerMgr.releaseLock(ZonePeerManager.getZoneLock(zoneId),
|
||||||
|
new ResultListener.NOOP<String>());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// we didn't get the lock, so let's see what happened by re-checking
|
||||||
|
Tuple<String, HostedZone> nodeInfo = _peerMgr.getZoneHost(zoneId);
|
||||||
|
if (nodeName == null || nodeInfo == null || !nodeName.equals(nodeInfo.left)) {
|
||||||
|
log.warning("Zone resolved on wacked-out node?",
|
||||||
|
"zoneId", zoneId, "nodeName", nodeName, "nodeInfo", nodeInfo);
|
||||||
|
listener.zoneFailedToResolve(zoneId,
|
||||||
|
new Exception("Zone on bogus host node"));
|
||||||
|
} else {
|
||||||
|
listener.zoneOnNode(nodeInfo); // somewhere else
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void requestFailed (Exception cause) {
|
||||||
|
log.warning("Failed to acquire zone resolution lock", "id", zoneId, cause);
|
||||||
|
listener.zoneFailedToResolve(zoneId, cause);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pass on that the zone has shutdown.
|
||||||
|
*/
|
||||||
|
public void zoneDidShutdown (int zoneId)
|
||||||
|
{
|
||||||
|
_peerMgr.zoneDidShutdown(zoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ZonePeerManager _peerMgr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.threerings.whirled.zone.peer.server;
|
||||||
|
|
||||||
|
import javax.annotation.Generated;
|
||||||
|
import com.threerings.presents.dobj.DSet;
|
||||||
|
import com.threerings.crowd.peer.data.CrowdNodeObject;
|
||||||
|
|
||||||
|
import com.threerings.whirled.zone.peer.data.HostedZone;
|
||||||
|
|
||||||
|
public class ZoneNodeObject extends CrowdNodeObject
|
||||||
|
{
|
||||||
|
// AUTO-GENERATED: FIELDS START
|
||||||
|
/** The field name of the <code>hostedZones</code> field. */
|
||||||
|
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||||
|
public static final String HOSTED_ZONES = "hostedZones";
|
||||||
|
// AUTO-GENERATED: FIELDS END
|
||||||
|
|
||||||
|
/** Contains info on all zones hosted by this server. */
|
||||||
|
public DSet<HostedZone> hostedZones = DSet.newDSet();
|
||||||
|
|
||||||
|
|
||||||
|
// AUTO-GENERATED: METHODS START
|
||||||
|
/**
|
||||||
|
* Requests that the specified entry be added to the
|
||||||
|
* <code>hostedZones</code> set. The set will not change until the event is
|
||||||
|
* actually propagated through the system.
|
||||||
|
*/
|
||||||
|
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||||
|
public void addToHostedZones (HostedZone elem)
|
||||||
|
{
|
||||||
|
requestEntryAdd(HOSTED_ZONES, hostedZones, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the entry matching the supplied key be removed from
|
||||||
|
* the <code>hostedZones</code> set. The set will not change until the
|
||||||
|
* event is actually propagated through the system.
|
||||||
|
*/
|
||||||
|
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||||
|
public void removeFromHostedZones (Comparable<?> key)
|
||||||
|
{
|
||||||
|
requestEntryRemove(HOSTED_ZONES, hostedZones, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the specified entry be updated in the
|
||||||
|
* <code>hostedZones</code> set. The set will not change until the event is
|
||||||
|
* actually propagated through the system.
|
||||||
|
*/
|
||||||
|
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||||
|
public void updateHostedZones (HostedZone elem)
|
||||||
|
{
|
||||||
|
requestEntryUpdate(HOSTED_ZONES, hostedZones, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the <code>hostedZones</code> field be set to the
|
||||||
|
* specified value. Generally one only adds, updates and removes
|
||||||
|
* entries of a distributed set, but certain situations call for a
|
||||||
|
* complete replacement of the set value. The local value will be
|
||||||
|
* updated immediately and an event will be propagated through the
|
||||||
|
* system to notify all listeners that the attribute did
|
||||||
|
* change. Proxied copies of this object (on clients) will apply the
|
||||||
|
* value change when they received the attribute changed notification.
|
||||||
|
*/
|
||||||
|
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||||
|
public void setHostedZones (DSet<HostedZone> value)
|
||||||
|
{
|
||||||
|
requestAttributeChange(HOSTED_ZONES, value, this.hostedZones);
|
||||||
|
DSet<HostedZone> clone = (value == null) ? null : value.clone();
|
||||||
|
this.hostedZones = clone;
|
||||||
|
}
|
||||||
|
// AUTO-GENERATED: METHODS END
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package com.threerings.whirled.zone.peer.server;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.samskivert.util.Lifecycle;
|
||||||
|
import com.samskivert.util.Tuple;
|
||||||
|
|
||||||
|
import com.threerings.util.Name;
|
||||||
|
|
||||||
|
import com.threerings.presents.peer.data.NodeObject;
|
||||||
|
import com.threerings.crowd.peer.server.CrowdPeerManager;
|
||||||
|
|
||||||
|
import com.threerings.whirled.zone.peer.data.HostedZone;
|
||||||
|
|
||||||
|
import static com.threerings.whirled.zone.Log.log;
|
||||||
|
|
||||||
|
public abstract class ZonePeerManager extends CrowdPeerManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates an uninitialized peer manager.
|
||||||
|
*/
|
||||||
|
@Inject public ZonePeerManager (Lifecycle cycle)
|
||||||
|
{
|
||||||
|
super(cycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override // from CrowdPeerManager
|
||||||
|
protected NodeObject createNodeObject ()
|
||||||
|
{
|
||||||
|
return new ZoneNodeObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a lock used to claim resolution of the specified scene. */
|
||||||
|
public static NodeObject.Lock getZoneLock (int sceneId)
|
||||||
|
{
|
||||||
|
return new NodeObject.Lock("ZoneHost", sceneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the node name of the peer that is hosting the specified scene, or null if no peer
|
||||||
|
* has published that they are hosting the scene.
|
||||||
|
*/
|
||||||
|
public Tuple<String, HostedZone> getZoneHost (final int zoneId)
|
||||||
|
{
|
||||||
|
return lookupNodeDatum(new NodeFunc<Tuple<String, HostedZone>>() {
|
||||||
|
public Tuple<String, HostedZone> apply (ZoneNodeObject nodeobj) {
|
||||||
|
HostedZone info = nodeobj.hostedZones.get(zoneId);
|
||||||
|
return (info == null) ? null : Tuple.newTuple(nodeobj.nodeName, info);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the ZoneManager when it is hosting a zone.
|
||||||
|
*/
|
||||||
|
public void zoneDidStartup (int zoneId, Name name)
|
||||||
|
{
|
||||||
|
log.debug("Hosting zone", "id", zoneId, "name", name);
|
||||||
|
((ZoneNodeObject)_nodeobj).addToHostedZones(new HostedZone(zoneId, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the ZoneManager when it is no longer hosting a scene.
|
||||||
|
*/
|
||||||
|
public void zoneDidShutdown (int zoneId)
|
||||||
|
{
|
||||||
|
log.debug("No longer hosting zone", "id", zoneId);
|
||||||
|
((ZoneNodeObject)_nodeobj).removeFromHostedZones(zoneId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Useful with {@link #lookupNodeDatum}. */
|
||||||
|
public static abstract class NodeFunc<T> implements Function<NodeObject, T>
|
||||||
|
{
|
||||||
|
public abstract T apply (ZoneNodeObject mnobj);
|
||||||
|
|
||||||
|
public T apply (NodeObject nodeobj) {
|
||||||
|
return apply((ZoneNodeObject)nodeobj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user