Widened, added getPlaceController().

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4616 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2007-03-06 01:57:37 +00:00
parent 0a1999c55f
commit f27faf9f49
@@ -43,11 +43,10 @@ import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.util.CrowdContext; import com.threerings.crowd.util.CrowdContext;
/** /**
* The location director provides a means by which entities on the client * The location director provides a means by which entities on the client can request to move from
* can request to move from place to place and can be notified if other * place to place and can be notified if other entities have caused the client to move to a new
* entities have caused the client to move to a new place. It also * place. It also provides a mechanism for ratifying a request to move to a new place before
* provides a mechanism for ratifying a request to move to a new place * actually issuing the request.
* before actually issuing the request.
*/ */
public class LocationDirector extends BasicDirector public class LocationDirector extends BasicDirector
implements Subscriber, LocationReceiver implements Subscriber, LocationReceiver
@@ -55,8 +54,8 @@ public class LocationDirector extends BasicDirector
private static const log :Log = Log.getLog(LocationDirector); private static const log :Log = Log.getLog(LocationDirector);
/** /**
* Constructs a location director which will configure itself for * Constructs a location director which will configure itself for operation using the supplied
* operation using the supplied context. * context.
*/ */
public function LocationDirector (ctx :CrowdContext) public function LocationDirector (ctx :CrowdContext)
{ {
@@ -71,9 +70,8 @@ public class LocationDirector extends BasicDirector
} }
/** /**
* Adds a location observer to the list. This observer will * Adds a location observer to the list. This observer will subsequently be notified of
* subsequently be notified of potential, effected and failed location * potential, effected and failed location changes.
* changes.
*/ */
public function addLocationObserver (observer :LocationObserver) :void public function addLocationObserver (observer :LocationObserver) :void
{ {
@@ -89,14 +87,23 @@ public class LocationDirector extends BasicDirector
} }
/** /**
* Returns the place object for the location we currently occupy or * Returns the place object for the location we currently occupy or null if we're not currently
* null if we're not currently occupying any location. * occupying any location.
*/ */
public function getPlaceObject () :PlaceObject public function getPlaceObject () :PlaceObject
{ {
return _plobj; return _plobj;
} }
/**
* Returns the controller for the location we currently occupy or null if we're not currently
* occupying any location.
*/
public function getPlaceController () :PlaceController
{
return _controller;
}
/** /**
* Returns true if there is a pending move request. * Returns true if there is a pending move request.
*/ */
@@ -106,13 +113,11 @@ public class LocationDirector extends BasicDirector
} }
/** /**
* Requests that this client be moved to the specified place. A * Requests that this client be moved to the specified place. A request will be made and when
* request will be made and when the response is received, the * the response is received, the location observers will be notified of success or failure.
* location observers will be notified of success or failure.
* *
* @return true if the move to request was issued, false if it was * @return true if the move to request was issued, false if it was rejected by a location
* rejected by a location observer or because we have another request * observer or because we have another request outstanding.
* outstanding.
*/ */
public function moveTo (placeId :int) :Boolean public function moveTo (placeId :int) :Boolean
{ {
@@ -122,31 +127,26 @@ public class LocationDirector extends BasicDirector
return false; return false;
} }
// first check to see if our observers are happy with this move // first check to see if our observers are happy with this move request
// request
if (!mayMoveTo(placeId, null)) { if (!mayMoveTo(placeId, null)) {
return false; return false;
} }
// we need to call this both to mark that we're issuing a move // we need to call this both to mark that we're issuing a move request and to check to see
// request and to check to see if the last issued request should // if the last issued request should be considered stale
// be considered stale
var refuse :Boolean = checkRepeatMove(); var refuse :Boolean = checkRepeatMove();
// complain if we're over-writing a pending request // complain if we're over-writing a pending request
if (_pendingPlaceId != -1) { if (_pendingPlaceId != -1) {
// if the pending request has been outstanding more than a // if the pending request has been outstanding more than a minute, go ahead and let
// minute, go ahead and let this new one through in an attempt // this new one through in an attempt to recover from dropped moveTo requests
// to recover from dropped moveTo requests
if (refuse) { if (refuse) {
log.warning("Refusing moveTo; We have a request outstanding " + log.warning("Refusing moveTo; We have a request outstanding " +
"[ppid=" + _pendingPlaceId + "[ppid=" + _pendingPlaceId + ", npid=" + placeId + "].");
", npid=" + placeId + "].");
return false; return false;
} else { } else {
log.warning("Overriding stale moveTo request " + log.warning("Overriding stale moveTo request [ppid=" + _pendingPlaceId +
"[ppid=" + _pendingPlaceId +
", npid=" + placeId + "]."); ", npid=" + placeId + "].");
} }
} }
@@ -169,8 +169,7 @@ public class LocationDirector extends BasicDirector
var placeId :int = _pendingPlaceId; var placeId :int = _pendingPlaceId;
_pendingPlaceId = -1; _pendingPlaceId = -1;
log.info("moveTo failed [pid=" + placeId + log.info("moveTo failed [pid=" + placeId + ", reason=" + reason + "].");
", reason=" + reason + "].");
// let our observers know that something has gone horribly awry // let our observers know that something has gone horribly awry
notifyFailure(placeId, reason); notifyFailure(placeId, reason);
@@ -178,17 +177,15 @@ public class LocationDirector extends BasicDirector
// issue a moveTo request // issue a moveTo request
log.info("Issuing moveTo(" + placeId + ")."); log.info("Issuing moveTo(" + placeId + ").");
_lservice.moveTo(_cctx.getClient(), placeId, _lservice.moveTo(_cctx.getClient(), placeId, new MoveAdapter(success, failure));
new MoveAdapter(success, failure));
return true; return true;
} }
/** /**
* Requests to move to the room that we last occupied, if such a room * Requests to move to the room that we last occupied, if such a room exists.
* exists.
* *
* @return true if we had a previous room and we requested to move to * @return true if we had a previous room and we requested to move to it, false if we had no
* it, false if we had no previous room. * previous room.
*/ */
public function moveBack () :Boolean public function moveBack () :Boolean
{ {
@@ -204,8 +201,8 @@ public class LocationDirector extends BasicDirector
/** /**
* Issues a request to leave our current location. * Issues a request to leave our current location.
* *
* @return true if we were able to leave, false if we are in the * @return true if we were able to leave, false if we are in the middle of moving somewhere and
* middle of moving somewhere and can't yet leave. * can't yet leave.
*/ */
public function leavePlace () :Boolean public function leavePlace () :Boolean
{ {
@@ -219,16 +216,15 @@ public class LocationDirector extends BasicDirector
} }
/** /**
* This can be called by cooperating directors that need to coopt the * This can be called by cooperating directors that need to coopt the moving process to extend
* moving process to extend it in some way or other. In such * it in some way or other. In such situations, they should call this method before moving to a
* situations, they should call this method before moving to a new * new location to check to be sure that all of the registered location observers are amenable
* location to check to be sure that all of the registered location * to a location change.
* observers are amenable to a location change.
* *
* @param placeId the place oid of our tentative new location. * @param placeId the place oid of our tentative new location.
* *
* @return true if everyone is happy with the move, false if it was * @return true if everyone is happy with the move, false if it was vetoed by one of the
* vetoed by one of the location observers. * location observers.
*/ */
public function mayMoveTo (placeId :int, rl :ResultListener) :Boolean public function mayMoveTo (placeId :int, rl :ResultListener) :Boolean
{ {
@@ -238,12 +234,11 @@ public class LocationDirector extends BasicDirector
vetoed = vetoed || !lobs.locationMayChange(placeId); vetoed = vetoed || !lobs.locationMayChange(placeId);
}); });
// if we're actually going somewhere, let the controller know that // if we're actually going somewhere, let the controller know that we might be leaving
// we might be leaving
mayLeavePlace(); mayLeavePlace();
// if we have a result listener, let it know if we failed // if we have a result listener, let it know if we failed or keep it for later if we're
// or keep it for later if we're still going // still going
if (rl != null) { if (rl != null) {
if (vetoed) { if (vetoed) {
rl.requestFailed(new MoveVetoedError()); rl.requestFailed(new MoveVetoedError());
@@ -256,8 +251,7 @@ public class LocationDirector extends BasicDirector
} }
/** /**
* Called to inform our controller that we may be leaving the current * Called to inform our controller that we may be leaving the current place.
* place.
*/ */
protected function mayLeavePlace () :void protected function mayLeavePlace () :void
{ {
@@ -265,19 +259,17 @@ public class LocationDirector extends BasicDirector
try { try {
_controller.mayLeavePlace(_plobj); _controller.mayLeavePlace(_plobj);
} catch (e :Error) { } catch (e :Error) {
log.warning("Place controller choked in " + log.warning("Place controller choked in mayLeavePlace [plobj=" + _plobj + "].");
"mayLeavePlace [plobj=" + _plobj + "].");
log.logStackTrace(e); log.logStackTrace(e);
} }
} }
} }
/** /**
* This can be called by cooperating directors that need to coopt the * This can be called by cooperating directors that need to coopt the moving process to extend
* moving process to extend it in some way or other. In such * it in some way or other. In such situations, they will be responsible for receiving the
* situations, they will be responsible for receiving the successful * successful move response and they should let the location director know that the move has
* move response and they should let the location director know that * been effected.
* the move has been effected.
* *
* @param placeId the place oid of our new location. * @param placeId the place oid of our new location.
* @param config the configuration information for the new place. * @param config the configuration information for the new place.
@@ -304,8 +296,7 @@ public class LocationDirector extends BasicDirector
// check whether we should use a custom class loader // check whether we should use a custom class loader
_controller = config.createController(); _controller = config.createController();
if (_controller == null) { if (_controller == null) {
log.warning("Place config returned null controller " + log.warning("Place config returned null controller [config=" + config + "].");
"[config=" + config + "].");
return; return;
} }
_controller.init(_cctx, config); _controller.init(_cctx, config);
@@ -315,9 +306,8 @@ public class LocationDirector extends BasicDirector
} }
/** /**
* Called when we're leaving our current location. Informs the * Called when we're leaving our current location. Informs the location's controller that we're
* location's controller that we're departing, unsubscribes from the * departing, unsubscribes from the location's place object, and clears out our internal place
* location's place object, and clears out our internal place
* information. * information.
*/ */
public function didLeavePlace () :void public function didLeavePlace () :void
@@ -328,16 +318,14 @@ public class LocationDirector extends BasicDirector
try { try {
_controller.didLeavePlace(_plobj); _controller.didLeavePlace(_plobj);
} catch (e :Error) { } catch (e :Error) {
log.warning("Place controller choked in " + log.warning("Place controller choked in didLeavePlace [plobj=" + _plobj + "].");
"didLeavePlace [plobj=" + _plobj + "].");
log.logStackTrace(e); log.logStackTrace(e);
} }
_controller = null; _controller = null;
} }
// unsubscribe from our old place object // unsubscribe from our old place object
_cctx.getDObjectManager().unsubscribeFromObject( _cctx.getDObjectManager().unsubscribeFromObject(_plobj.getOid(), this);
_plobj.getOid(), this);
_plobj = null; _plobj = null;
// and clear out the associated place id // and clear out the associated place id
@@ -346,10 +334,9 @@ public class LocationDirector extends BasicDirector
} }
/** /**
* This can be called by cooperating directors that need to coopt the * This can be called by cooperating directors that need to coopt the moving process to extend
* moving process to extend it in some way or other. If the coopted * it in some way or other. If the coopted move request fails, this failure can be propagated
* move request fails, this failure can be propagated to the location * to the location observers if appropriate.
* observers if appropriate.
* *
* @param placeId the place oid to which we failed to move. * @param placeId the place oid to which we failed to move.
* @param reason the reason code given for failure. * @param reason the reason code given for failure.
@@ -369,8 +356,8 @@ public class LocationDirector extends BasicDirector
} }
/** /**
* Called to test and set a time stamp that we use to determine if a * Called to test and set a time stamp that we use to determine if a pending moveTo request is
* pending moveTo request is stale. * stale.
*/ */
public function checkRepeatMove () :Boolean public function checkRepeatMove () :Boolean
{ {
@@ -392,17 +379,14 @@ public class LocationDirector extends BasicDirector
var success :Function = function (object :DObject) :void { var success :Function = function (object :DObject) :void {
gotBodyObject(object as BodyObject); gotBodyObject(object as BodyObject);
}; };
var failure :Function = function ( var failure :Function = function (oid :int, cause :ObjectAccessError) :void {
oid :int, cause :ObjectAccessError) :void { log.warning("Location director unable to fetch body object; all has gone horribly " +
log.warning("Location director unable to fetch body " + "wrong [cause=" + cause + "].");
"object; all has gone horribly wrong" +
"[cause=" + cause + "].");
}; };
var client :Client = event.getClient(); var client :Client = event.getClient();
var cloid :int = client.getClientOid(); client.getDObjectManager().subscribeToObject(
client.getDObjectManager().subscribeToObject(cloid, client.getClientOid(), new SubscriberAdapter(success, failure));
new SubscriberAdapter(success, failure));
} }
// documentation inherited // documentation inherited
@@ -417,8 +401,8 @@ public class LocationDirector extends BasicDirector
// let our observers know that we're no longer in a location // let our observers know that we're no longer in a location
_observers.apply(didChangeOp); _observers.apply(didChangeOp);
// clear out everything else (it's possible that we were logged // clear out everything else (it's possible that we were logged off in the middle of a
// off in the middle of a change location request) // change location request)
_pendingPlaceId = -1; _pendingPlaceId = -1;
_previousPlaceId = -1; _previousPlaceId = -1;
_lastRequestTime = 0; _lastRequestTime = 0;
@@ -440,8 +424,8 @@ public class LocationDirector extends BasicDirector
protected function gotBodyObject (clobj :BodyObject) :void protected function gotBodyObject (clobj :BodyObject) :void
{ {
// check to see if we are already in a location, in which case // check to see if we are already in a location, in which case we'll want to be going there
// we'll want to be going there straight away // straight away
} }
// documentation inherited from interface // documentation inherited from interface
@@ -470,8 +454,7 @@ public class LocationDirector extends BasicDirector
try { try {
_controller.willEnterPlace(_plobj); _controller.willEnterPlace(_plobj);
} catch (e :Error) { } catch (e :Error) {
log.warning("Controller choked in willEnterPlace " + log.warning("Controller choked in willEnterPlace [place=" + _plobj + "].");
"[place=" + _plobj + "].");
log.logStackTrace(e); log.logStackTrace(e);
} }
} }
@@ -483,10 +466,9 @@ public class LocationDirector extends BasicDirector
// documentation inherited from interface Subscriber // documentation inherited from interface Subscriber
public function requestFailed (oid :int, cause :ObjectAccessError) :void public function requestFailed (oid :int, cause :ObjectAccessError) :void
{ {
// aiya! we were unable to fetch our new place object; something // aiya! we were unable to fetch our new place object; something is badly wrong
// is badly wrong log.warning("Aiya! Unable to fetch place object for new location [plid=" + oid +
log.warning("Aiya! Unable to fetch place object for new location " + ", reason=" + cause + "].");
"[plid=" + oid + ", reason=" + cause + "].");
// clear out our half initialized place info // clear out our half initialized place info
var placeId :int = _placeId; var placeId :int = _placeId;
@@ -495,9 +477,8 @@ public class LocationDirector extends BasicDirector
// let the kids know shit be fucked // let the kids know shit be fucked
notifyFailure(placeId, "m.unable_to_fetch_place_object"); notifyFailure(placeId, "m.unable_to_fetch_place_object");
// we need to sort out what to do about the half-initialized place // we need to sort out what to do about the half-initialized place controller. presently we
// controller. presently we punt and hope that calling // punt and hope that calling didLeavePlace() without ever having called willEnterPlace()
// didLeavePlace() without ever having called willEnterPlace()
// does whatever's necessary // does whatever's necessary
// try to return to our previous location // try to return to our previous location
@@ -505,9 +486,8 @@ public class LocationDirector extends BasicDirector
_failureHandler.recoverFailedMove(placeId); _failureHandler.recoverFailedMove(placeId);
} else { } else {
// if we were previously somewhere (and that somewhere isn't // if we were previously somewhere (and that somewhere isn't where we just tried to
// where we just tried to go), try going back to that happy // go), try going back to that happy place
// place
if (_previousPlaceId != -1 && _previousPlaceId != placeId) { if (_previousPlaceId != -1 && _previousPlaceId != placeId) {
moveTo(_previousPlaceId); moveTo(_previousPlaceId);
} }
@@ -515,24 +495,20 @@ public class LocationDirector extends BasicDirector
} }
/** /**
* Sets the failure handler which will recover from place object * Sets the failure handler which will recover from place object fetching failures. In the
* fetching failures. In the event that we are unable to fetch our * event that we are unable to fetch our place object after making a successful moveTo request,
* place object after making a successful moveTo request, we attempt * we attempt to rectify the failure by moving back to the last known working location. Because
* to rectify the failure by moving back to the last known working * entites that cooperate with the location director may need to become involved in this
* location. Because entites that cooperate with the location director * failure recovery, we provide this interface whereby they can interject themseves into the
* may need to become involved in this failure recovery, we provide
* this interface whereby they can interject themseves into the
* failure recovery process and do their own failure recovery. * failure recovery process and do their own failure recovery.
*/ */
public function setFailureHandler ( public function setFailureHandler (handler :LocationDirector_FailureHandler) :void
handler :LocationDirector_FailureHandler) :void
{ {
if (_failureHandler != null) { if (_failureHandler != null) {
log.warning("Requested to set failure handler, but we've " + log.warning("Requested to set failure handler, but we've already got one. The " +
"already got one. The conflicting entities will " + "conflicting entities will likely need to perform more sophisticated " +
"likely need to perform more sophisticated " + "coordination to deal with failures. [old=" + _failureHandler +
"coordination to deal with failures. " + ", new=" + handler + "].");
"[old=" + _failureHandler + ", new=" + handler + "].");
} else { } else {
_failureHandler = handler; _failureHandler = handler;
@@ -561,8 +537,7 @@ public class LocationDirector extends BasicDirector
protected var _lservice :LocationService; protected var _lservice :LocationService;
/** Our location observer list. */ /** Our location observer list. */
protected var _observers :ObserverList = protected var _observers :ObserverList = new ObserverList(ObserverList.SAFE_IN_ORDER_NOTIFY);
new ObserverList(ObserverList.SAFE_IN_ORDER_NOTIFY);
/** The oid of the place we currently occupy. */ /** The oid of the place we currently occupy. */
protected var _placeId :int = -1; protected var _placeId :int = -1;
@@ -573,10 +548,8 @@ public class LocationDirector extends BasicDirector
/** The place controller in effect for our current place. */ /** The place controller in effect for our current place. */
protected var _controller :PlaceController; protected var _controller :PlaceController;
/** /** The oid of the place for which we have an outstanding moveTo request, or -1 if we have no
* The oid of the place for which we have an outstanding moveTo * outstanding request. */
* request, or -1 if we have no outstanding request.
*/
protected var _pendingPlaceId :int = -1; protected var _pendingPlaceId :int = -1;
/** The oid of the place we previously occupied. */ /** The oid of the place we previously occupied. */
@@ -585,16 +558,14 @@ public class LocationDirector extends BasicDirector
/** The last time we requested a move to. */ /** The last time we requested a move to. */
protected var _lastRequestTime :Number; protected var _lastRequestTime :Number;
/** The entity that deals when we fail to subscribe to a place /** The entity that deals when we fail to subscribe to a place object. */
* object. */
protected var _failureHandler :LocationDirector_FailureHandler; protected var _failureHandler :LocationDirector_FailureHandler;
/** A listener that wants to know if we succeeded or /** A listener that wants to know if we succeeded or how we failed to move. */
* how we failed to move. */
protected var _moveListener :ResultListener; protected var _moveListener :ResultListener;
/** We require that a moveTo request be outstanding for one minute /** We require that a moveTo request be outstanding for one minute before it is declared to be
* before it is declared to be stale. */ * stale. */
protected static const STALE_REQUEST_DURATION :int = 60 * 1000; protected static const STALE_REQUEST_DURATION :int = 60 * 1000;
} }
} }