Checkpoint.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3954 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Ray Greenwell
2006-03-16 22:12:46 +00:00
parent b38081f60a
commit 8fb271be33
8 changed files with 252 additions and 88 deletions
+8
View File
@@ -187,6 +187,14 @@ ActionScript
I was trying to use it when pulling a value out of a hash, but if it I was trying to use it when pulling a value out of a hash, but if it
wasn't there it got booched. wasn't there it got booched.
***Update:
Just not casting is "implicit casting" and will result in a type error
at runtime. This may be what we want, but it's maddening that there's
no way to do it explicitely.
var o1 :String = someObject;
// checked at runtime, throws TypeError if failure
- Pitfall! This is perfectly legal: - Pitfall! This is perfectly legal:
var b :int = 3; var b :int = 3;
@@ -48,8 +48,7 @@ import com.threerings.crowd.util.CrowdContext;
* before actually issuing the request. * before actually issuing the request.
*/ */
public class LocationDirector extends BasicDirector public class LocationDirector extends BasicDirector
implements LocationCodes, Subscriber, LocationReceiver, implements Subscriber, LocationReceiver, MoveListener
LocationService.MoveListener
{ {
/** /**
* Used to recover from a moveTo request that was accepted but * Used to recover from a moveTo request that was accepted but
@@ -235,7 +234,7 @@ public class LocationDirector extends BasicDirector
// or keep it for later if we're still going // or keep it for later if we're still going
if (rl != null) { if (rl != null) {
if (vetoed) { if (vetoed) {
rl.requestFailed(new MoveVetoedException()); rl.requestFailed(new MoveVetoedError());
} else { } else {
_moveListener = rl; _moveListener = rl;
} }
@@ -248,12 +247,12 @@ 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 void mayLeavePlace () protected function mayLeavePlace () :void
{ {
if (_controller != null) { if (_controller != null) {
try { try {
_controller.mayLeavePlace(_plobj); _controller.mayLeavePlace(_plobj);
} catch (Exception e) { } 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);
@@ -271,7 +270,7 @@ public class LocationDirector extends BasicDirector
* @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.
*/ */
public void didMoveTo (int placeId, PlaceConfig config) public function didMoveTo (placeId :int, config :PlaceConfig) :void
{ {
if (_moveListener != null) { if (_moveListener != null) {
_moveListener.requestCompleted(config); _moveListener.requestCompleted(config);
@@ -291,20 +290,15 @@ public class LocationDirector extends BasicDirector
_placeId = placeId; _placeId = placeId;
// check whether we should use a custom class loader // check whether we should use a custom class loader
ClassLoader loader = getClassLoader(config); cclass :Class = config.getControllerClass();
if (loader != null) {
config.setClassLoader(loader);
}
Class cclass = config.getControllerClass();
try { try {
// start up a new place controller to manage the new place // start up a new place controller to manage the new place
_controller = (PlaceController)cclass.newInstance(); _controller = (new cclass() as PlaceController);
_controller.init(_cctx, config); _controller.init(_cctx, config);
} catch (Exception e) { } catch (e :Error) {
Log.warning("Error creating or initializing place controller " + Log.warning("Error creating or initializing place controller " +
"[cclass=" + cclass.getName() + "[cclass=" + cclass +
", config=" + config + "]."); ", config=" + config + "].");
Log.logStackTrace(e); Log.logStackTrace(e);
} }
@@ -319,14 +313,14 @@ public class LocationDirector extends BasicDirector
* location's place object, and clears out our internal place * location's place object, and clears out our internal place
* information. * information.
*/ */
public void didLeavePlace () public function didLeavePlace () :void
{ {
if (_plobj != null) { if (_plobj != null) {
// let the old controller know that things are going away // let the old controller know that things are going away
if (_controller != null) { if (_controller != null) {
try { try {
_controller.didLeavePlace(_plobj); _controller.didLeavePlace(_plobj);
} catch (Exception e) { } 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);
@@ -353,10 +347,10 @@ public class LocationDirector extends BasicDirector
* @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.
*/ */
public void failedToMoveTo (int placeId, String reason) public function failedToMoveTo (placeId :int, reason :String) :void
{ {
if (_moveListener != null) { if (_moveListener != null) {
_moveListener.requestFailed(new MoveFailedException(reason)); _moveListener.requestFailed(new MoveFailedError(reason));
_moveListener = null; _moveListener = null;
} }
@@ -371,9 +365,9 @@ 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 stale. * pending moveTo request is stale.
*/ */
public boolean checkRepeatMove () public function checkRepeatMove () :Boolean
{ {
long now = System.currentTimeMillis(); var now :Number = new Date().getTime();
if (now - _lastRequestTime < STALE_REQUEST_DURATION) { if (now - _lastRequestTime < STALE_REQUEST_DURATION) {
return true; return true;
@@ -384,32 +378,29 @@ public class LocationDirector extends BasicDirector
} }
// documentation inherited from interface // documentation inherited from interface
public void clientDidLogon (Client client) public override function clientDidLogon (event :ClientEvent) :void
{ {
super.clientDidLogon(client); super.clientDidLogon(event);
// subscribe to our body object // TODO: Work out new anonyclass construct
Subscriber sub = new Subscriber() { var sub :Subscriber = new SubscriberProxy();
public void objectAvailable (DObject object) sub.objectAvailable = function (object :DObject) :void {
{ gotBodyObject(object as BodyObject);
gotBodyObject((BodyObject)object);
}
public void requestFailed (int oid, ObjectAccessException cause)
{
Log.warning("Location director unable to fetch body " +
"object; all has gone horribly wrong" +
"[cause=" + cause + "].");
}
}; };
int cloid = client.getClientOid(); sub.requestFailed = function (oid :int, cause :ObjectAccessError) :void {
Log.warning("Location director unable to fetch body " +
"object; all has gone horribly wrong" +
"[cause=" + cause + "].");
};
var cloid :int = event.getClient().getClientOid();
client.getDObjectManager().subscribeToObject(cloid, sub); client.getDObjectManager().subscribeToObject(cloid, sub);
} }
// documentation inherited from interface // documentation inherited
public void clientDidLogoff (Client client) public override function clientDidLogoff (event :ClientEvent) :void
{ {
super.clientDidLogoff(client); super.clientDidLogoff(event);
// clear ourselves out and inform observers of our departure // clear ourselves out and inform observers of our departure
mayLeavePlace(); mayLeavePlace();
@@ -422,26 +413,26 @@ public class LocationDirector extends BasicDirector
// off in the middle of a change location request) // off in the middle of a change location request)
_pendingPlaceId = -1; _pendingPlaceId = -1;
_previousPlaceId = -1; _previousPlaceId = -1;
_lastRequestTime = 0L; _lastRequestTime = 0;
_lservice = null; _lservice = null;
} }
// documentation inherited // documentation inherited
protected void fetchServices (Client client) protected override function fetchServices (client :Client) :void
{ {
// obtain our service handle // obtain our service handle
_lservice = (LocationService) _lservice =
client.requireService(LocationService.class); (client.requireService(LocationService) as LocationService);
} }
protected void gotBodyObject (BodyObject clobj) 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 straight away // we'll want to be going there straight away
} }
// documentation inherited from interface // documentation inherited from interface
public void moveSucceeded (PlaceConfig config) public function moveSucceeded (config :PlaceConfig) :void
{ {
// handle the successful move // handle the successful move
didMoveTo(_pendingPlaceId, config); didMoveTo(_pendingPlaceId, config);
@@ -451,10 +442,10 @@ public class LocationDirector extends BasicDirector
} }
// documentation inherited from interface // documentation inherited from interface
public void requestFailed (String reason) public function requestFailed (reason :String) :void
{ {
// clear out our pending request oid // clear out our pending request oid
int placeId = _pendingPlaceId; var placeId :int = _pendingPlaceId;
_pendingPlaceId = -1; _pendingPlaceId = -1;
Log.info("moveTo failed [pid=" + placeId + Log.info("moveTo failed [pid=" + placeId +
@@ -465,7 +456,7 @@ public class LocationDirector extends BasicDirector
} }
// documentation inherited from interface // documentation inherited from interface
public void forcedMove (final int placeId) public function forcedMove (placeId :int) :void
{ {
Log.info("Moving at request of server [placeId=" + placeId + "]."); Log.info("Moving at request of server [placeId=" + placeId + "].");
@@ -483,16 +474,16 @@ public class LocationDirector extends BasicDirector
* Called when we receive the place object to which we subscribed * Called when we receive the place object to which we subscribed
* after a successful moveTo request. * after a successful moveTo request.
*/ */
public void objectAvailable (DObject object) public function objectAvailable (object :DObject) :void
{ {
// yay, we have our new place object // yay, we have our new place object
_plobj = (PlaceObject)object; _plobj = (object as PlaceObject);
// let the place controller know that we're ready to roll // let the place controller know that we're ready to roll
if (_controller != null) { if (_controller != null) {
try { try {
_controller.willEnterPlace(_plobj); _controller.willEnterPlace(_plobj);
} catch (Exception e) { } 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);
@@ -509,7 +500,7 @@ public class LocationDirector extends BasicDirector
* generally a bad scene and we do our best to recover by going back * generally a bad scene and we do our best to recover by going back
* to the previously known location. * to the previously known location.
*/ */
public void requestFailed (int oid, ObjectAccessException cause) 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
@@ -517,7 +508,7 @@ public class LocationDirector extends BasicDirector
"[plid=" + oid + ", reason=" + cause + "]."); "[plid=" + oid + ", reason=" + cause + "].");
// clear out our half initialized place info // clear out our half initialized place info
int placeId = _placeId; var placeId :int = _placeId;
_placeId = -1; _placeId = -1;
// let the kids know shit be fucked // let the kids know shit be fucked
@@ -566,58 +557,44 @@ public class LocationDirector extends BasicDirector
// } // }
// } // }
protected void notifyFailure (final int placeId, final String reason) protected function notifyFailure (placeId :int, reason :String) :void
{ {
_observers.apply(new ObserverOp() { _observers.apply(function (obs :Object) :Boolean {
public boolean apply (Object obs) { (obs as LocationObserver).locationChangeFailed(placeId, reason);
((LocationObserver)obs).locationChangeFailed(placeId, reason); return true;
return true;
}
}); });
} }
/**
* By overriding this method, it is possible to customize the location
* director to cause it to load the classes associated with a
* particular place via a custom class loader. That loader may enforce
* restricted privileges or obtain the classes from some special
* source.
*/
protected ClassLoader getClassLoader (PlaceConfig config)
{
return null;
}
/** The context through which we access needed services. */ /** The context through which we access needed services. */
protected CrowdContext _cctx; protected var _cctx :CrowdContext;
/** Provides access to location services. */ /** Provides access to location services. */
protected LocationService _lservice; protected var _lservice :LocationService;
/** Our location observer list. */ /** Our location observer list. */
protected ObserverList _observers = 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 int _placeId = -1; protected var _placeId :int = -1;
/** The place object that we currently occupy. */ /** The place object that we currently occupy. */
protected PlaceObject _plobj; protected var _plobj :PlaceObject;
/** The place controller in effect for our current place. */ /** The place controller in effect for our current place. */
protected PlaceController _controller; protected var _controller :PlaceController;
/** /**
* The oid of the place for which we have an outstanding moveTo * The oid of the place for which we have an outstanding moveTo
* request, or -1 if we have no outstanding request. * request, or -1 if we have no outstanding request.
*/ */
protected int _pendingPlaceId = -1; protected var _pendingPlaceId :int = -1;
/** The oid of the place we previously occupied. */ /** The oid of the place we previously occupied. */
protected int _previousPlaceId = -1; protected var _previousPlaceId :int = -1;
/** The last time we requested a move to. */ /** The last time we requested a move to. */
protected long _lastRequestTime; 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. */
@@ -625,18 +602,23 @@ public class LocationDirector extends BasicDirector
/** 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 ResultListener _moveListener; protected var _moveListener :ResultListener;
/** The operation used to inform observers that the location changed. */ /** The operation used to inform observers that the location changed. */
protected ObserverOp _didChangeOp = new ObserverOp() { protected var _didChangeOp :Function = function (obs :Object) :Boolean
public boolean apply (Object obs) { {
((LocationObserver)obs).locationDidChange(_plobj); (obs as LocationObserver).locationDidChange(_plobj);
return true; return true;
}
}; };
/** 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 stale. */ * before it is declared to be stale. */
protected static final long STALE_REQUEST_DURATION = 60L * 1000L; protected static const STALE_REQUEST_DURATION :int = 60 * 1000;
} }
} }
import com.threerings.presents.dobj.Subscriber;
dynamic class SubscriberProxy implements Subscriber
{
}
@@ -0,0 +1,40 @@
//
// $Id: LocationReceiver.java 3098 2004-08-27 02:12:55Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.crowd.client {
import com.threerings.presents.client.InvocationReceiver;
/**
* Defines, for the location services, a set of notifications delivered
* asynchronously by the server to the client.
*/
public interface LocationReceiver extends InvocationReceiver
{
/**
* Used to communicate a required move notification to the client. The
* server will have removed the client from their existing location
* and the client is then responsible for generating a {@link
* LocationService#moveTo} request to move to the new location.
*/
function forcedMove (placeId :int) :void;
}
}
@@ -0,0 +1,55 @@
//
// $Id: LocationService.java 3638 2005-06-30 00:02:13Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.crowd.client {
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.crowd.data.PlaceConfig;
/**
* The location services provide a mechanism by which the client can
* request to move from place to place in the server. These services
* should not be used directly, but instead should be accessed via the
* {@link LocationDirector}.
*/
public interface LocationService extends InvocationService
{
/**
* Requests that this client's body be moved to the specified
* location.
*
* @param client a reference to the client object that defines the
* context in which this invocation service should be executed.
* @param placeId the object id of the place object to which the body
* should be moved.
* @param listener the listener that will be informed of success or
* failure.
*/
function moveTo (
client :Client, placeId :int, listener :MoveListener) :void;
/**
* Requests that we leave our current place and move to nowhere land.
*/
function leavePlace (client :Client) :void;
}
@@ -0,0 +1,34 @@
//
// $Id: MoveFailedException.java 3098 2004-08-27 02:12:55Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.crowd.client {
/**
* An exception that indicates that the server did not allow us to move.
*/
public class MoveFailedError extends Error
{
public function MoveFailedError (message :String)
{
super(message);
}
}
}
@@ -0,0 +1,9 @@
package com.threerings.crowd.client {
import com.threerings.presents.client.InvocationListener;
public interface MoveListener extends InvocationListener
{
function moveSucceeded (config :PlaceConfig) :void;
}
}
@@ -0,0 +1,30 @@
//
// $Id: MoveVetoedException.java 3098 2004-08-27 02:12:55Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.crowd.client {
/**
* An exception that indicates that a LocationObserver vetoed our move request.
*/
public class MoveVetoedError extends Error
{
}
}
@@ -4,6 +4,8 @@ import flash.events.EventDispatcher;
import flash.events.TimerEvent; import flash.events.TimerEvent;
import flash.util.Timer; import flash.util.Timer;
import com.threerings.util.ObserverList;
import com.threerings.presents.data.ClientObject; import com.threerings.presents.data.ClientObject;
import com.threerings.presents.dobj.DObjectManager; import com.threerings.presents.dobj.DObjectManager;
@@ -345,6 +347,10 @@ public class Client extends EventDispatcher
/** The entity that manages our network communications. */ /** The entity that manages our network communications. */
protected var _comm :Communicator; protected var _comm :Communicator;
/** Our list of client observers. */
protected var _observers :ObserverList =
new ObserverList(ObserverList.SAFE_IN_ORDER_NOTIFY);
/** General startup information provided by the server. */ /** General startup information provided by the server. */
protected var _bstrap :BootstrapData; protected var _bstrap :BootstrapData;