diff --git a/src/as/com/threerings/crowd/client/LocationDecoder.as b/src/as/com/threerings/crowd/client/LocationDecoder.as
new file mode 100644
index 000000000..5fce22e3d
--- /dev/null
+++ b/src/as/com/threerings/crowd/client/LocationDecoder.as
@@ -0,0 +1,70 @@
+//
+// $Id: LocationDecoder.java 3914 2006-03-06 21:51:59Z mdb $
+//
+// Narya library - tools for developing networked games
+// Copyright (C) 2002-2006 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.crowd.client.LocationReceiver;
+import com.threerings.presents.client.InvocationDecoder;
+
+/**
+ * Dispatches calls to a {@link LocationReceiver} instance.
+ */
+public class LocationDecoder extends InvocationDecoder
+{
+ /** The generated hash code used to identify this receiver class. */
+ public static const RECEIVER_CODE :String = "58f2830e027f4f3377e100ef12332497";
+
+ /** The method id used to dispatch {@link LocationReceiver#forcedMove}
+ * notifications. */
+ public static const FORCED_MOVE :int = 1;
+
+ /**
+ * Creates a decoder that may be registered to dispatch invocation
+ * service notifications to the specified receiver.
+ */
+ public function LocationDecoder (receiver :LocationReceiver)
+ {
+ this.receiver = receiver;
+ }
+
+ // documentation inherited
+ public override function getReceiverCode () :String
+ {
+ return RECEIVER_CODE;
+ }
+
+ // documentation inherited
+ public override function dispatchNotification (
+ methodId :int, args :Array) :void
+ {
+ switch (methodId) {
+ case FORCED_MOVE:
+ (receiver as LocationReceiver).forcedMove(
+ (args[0] as int)
+ );
+ return;
+
+ default:
+ super.dispatchNotification(methodId, args);
+ }
+ }
+}
+}
diff --git a/src/as/com/threerings/crowd/client/PlaceController.as b/src/as/com/threerings/crowd/client/PlaceController.as
new file mode 100644
index 000000000..827f8d09d
--- /dev/null
+++ b/src/as/com/threerings/crowd/client/PlaceController.as
@@ -0,0 +1,267 @@
+//
+// $Id: PlaceController.java 3440 2005-03-30 01:09:30Z 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.crowd.data.PlaceConfig;
+import com.threerings.crowd.data.PlaceObject;
+import com.threerings.crowd.util.CrowdContext;
+
+/**
+ * Controls the user interface that is used to display a place. When the
+ * client moves to a new place, the appropriate place controller is
+ * constructed and requested to create and display the appopriate user
+ * interface for that place.
+ */
+public /*abstract*/ class PlaceController /*extends Controller*/
+{
+ /**
+ * Initializes this place controller with a reference to the context
+ * that they can use to access client services and to the
+ * configuration record for this place. The controller should create
+ * as much of its user interface that it can without having access to
+ * the place object because this will be invoked in parallel with the
+ * fetching of the place object. When the place object is obtained,
+ * the controller will be notified and it can then finish the user
+ * interface configuration and put the user interface into operation.
+ *
+ * @param ctx the client context.
+ * @param config the place configuration for this place.
+ */
+ public function init (ctx :CrowdContext, config :PlaceConfig) :void
+ {
+ // keep these around
+ _ctx = ctx;
+ _config = config;
+
+ // create our user interface
+ _view = createPlaceView(_ctx);
+
+// // initialize our delegates
+// applyToDelegates(new DelegateOp() {
+// public void apply (PlaceControllerDelegate delegate) {
+// delegate.init(_ctx, _config);
+// }
+// });
+
+ // let the derived classes do any initialization stuff
+ didInit();
+ }
+
+ /**
+ * Derived classes can override this and perform any
+ * post-initialization processing they might need. They should of
+ * course be sure to call super.didInit().
+ */
+ protected function didInit () :void
+ {
+ }
+
+ /**
+ * Returns a reference to the place view associated with this
+ * controller. This is only valid after a call has been made to {@link
+ * #init}.
+ */
+ public function getPlaceView () :PlaceView
+ {
+ return _view;
+ }
+
+ /**
+ * Returns the {@link PlaceConfig} associated with this place.
+ */
+ public function getPlaceConfig () :PlaceConfig
+ {
+ return _config;
+ }
+
+ /**
+ * Creates the user interface that will be used to display this place.
+ * The view instance returned will later be configured with the place
+ * object, once it becomes available.
+ *
+ * @param ctx a reference to the {@link CrowdContext} associated with
+ * this controller.
+ */
+ protected function createPlaceView (ctx :CrowdContext) :PlaceView
+ {
+ return null;
+ }
+
+ /**
+ * This is called by the location director once the place object has
+ * been fetched. The place controller will dispatch the place object
+ * to the user interface hierarchy via {@link
+ * PlaceViewUtil#dispatchWillEnterPlace}. Derived classes can override
+ * this and perform any other starting up that they need to do
+ */
+ public function willEnterPlace (plobj :PlaceObject) :void
+ {
+ // keep a handle on our place object
+ _plobj = plobj;
+
+ if (_view != null ) {
+ // let the UI hierarchy know that we've got our place
+ PlaceViewUtil.dispatchWillEnterPlace(_view, plobj);
+ // and display the user interface
+ _ctx.setPlaceView(_view);
+ }
+
+// // let our delegates know what's up
+// applyToDelegates(new DelegateOp() {
+// public void apply (PlaceControllerDelegate delegate) {
+// delegate.willEnterPlace(plobj);
+// }
+// });
+ }
+
+ /**
+ * Called before a request is submitted to the server to leave the
+ * current place. As such, this method may be called multiple times
+ * before {@link #didLeavePlace} is finally called. The request to
+ * leave may be rejected, but if a place controller needs to flush any
+ * information to the place manager before it leaves, it should so do
+ * here. This is the only place in which the controller is guaranteed
+ * to be able to communicate to the place manager, as by the time
+ * {@link #didLeavePlace} is called, the place manager may have
+ * already been destroyed.
+ */
+ public function mayLeavePlace (plobj :PlaceObject) :void
+ {
+// // let our delegates know what's up
+// applyToDelegates(new DelegateOp() {
+// public void apply (PlaceControllerDelegate delegate) {
+// delegate.mayLeavePlace(plobj);
+// }
+// });
+ }
+
+ /**
+ * This is called by the location director when we are leaving this
+ * place and need to clean up after ourselves and shutdown. Derived
+ * classes should override this method (being sure to call
+ * super.didLeavePlace) and perform any necessary
+ * cleanup.
+ */
+ public function didLeavePlace (plobj :PlaceObject) :void
+ {
+// // let our delegates know what's up
+// applyToDelegates(new DelegateOp() {
+// public void apply (PlaceControllerDelegate delegate) {
+// delegate.didLeavePlace(plobj);
+// }
+// });
+
+ // let the UI hierarchy know that we're outta here
+ if (_view != null ) {
+ PlaceViewUtil.dispatchDidLeavePlace(_view, plobj);
+ _ctx.clearPlaceView(_view);
+ _view = null;
+ }
+
+ _plobj = null;
+ }
+
+ /**
+ * Handles basic place controller action events. Derived classes
+ * should be sure to call super.handleAction for events
+ * they don't specifically handle.
+ */
+// public boolean handleAction (final ActionEvent action)
+// {
+// final boolean[] handled = new boolean[1];
+//
+// // let our delegates have a crack at the action
+// applyToDelegates(new DelegateOp() {
+// public void apply (PlaceControllerDelegate delegate) {
+// // we take advantage of short-circuiting here
+// handled[0] = handled[0] || delegate.handleAction(action);
+// }
+// });
+//
+// // if they didn't handly it, pass it off to the super class
+// return handled[0] ? true : super.handleAction(action);
+// }
+
+ /**
+ * Adds the supplied delegate to the list for this controller.
+ */
+// protected void addDelegate (PlaceControllerDelegate delegate)
+// {
+// if (_delegates == null) {
+// _delegates = new ArrayList();
+// }
+// _delegates.add(delegate);
+// }
+
+ /**
+ * Used to call methods in delegates.
+ */
+// protected static interface DelegateOp
+// {
+// public void apply (PlaceControllerDelegate delegate);
+// }
+
+ /**
+ * Applies the supplied operation to the registered delegates.
+ */
+// protected void applyToDelegates (DelegateOp op)
+// {
+// if (_delegates != null) {
+// int dcount = _delegates.size();
+// for (int i = 0; i < dcount; i++) {
+// op.apply((PlaceControllerDelegate)_delegates.get(i));
+// }
+// }
+// }
+
+ /**
+ * Applies the supplied operation to the registered delegates that
+ * derive from the specified class.
+ */
+// protected void applyToDelegates (Class dclass, DelegateOp op)
+// {
+// if (_delegates != null) {
+// int dcount = _delegates.size();
+// for (int i = 0; i < dcount; i++) {
+// PlaceControllerDelegate delegate =
+// (PlaceControllerDelegate)_delegates.get(i);
+// if (dclass.isAssignableFrom(delegate.getClass())) {
+// op.apply(delegate);
+// }
+// }
+// }
+// }
+
+ /** A reference to the active client context. */
+ protected var _ctx :CrowdContext;
+
+ /** A reference to our place configuration. */
+ protected var _config :PlaceConfig;
+
+ /** A reference to the place object for which we're controlling a user
+ * interface. */
+ protected var _plobj :PlaceObject;
+
+ /** A reference to the root user interface component. */
+ protected var _view :PlaceView;
+}
+}
diff --git a/src/as/com/threerings/crowd/client/PlaceViewUtil.as b/src/as/com/threerings/crowd/client/PlaceViewUtil.as
new file mode 100644
index 000000000..1e7bde7c9
--- /dev/null
+++ b/src/as/com/threerings/crowd/client/PlaceViewUtil.as
@@ -0,0 +1,90 @@
+//
+// $Id: PlaceViewUtil.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 flash.display.DisplayObjectContainer;
+
+import com.threerings.crowd.Log;
+import com.threerings.crowd.data.PlaceObject;
+
+/**
+ * Provides a mechanism for dispatching notifications to all user
+ * interface elements in a hierarchy that implement the {@link PlaceView}
+ * interface. Look at the documentation for {@link PlaceView} for more
+ * explanation.
+ */
+public class PlaceViewUtil
+{
+ /**
+ * Dispatches a call to {@link PlaceView#willEnterPlace} to all UI
+ * elements in the hierarchy rooted at the component provided via the
+ * root parameter.
+ *
+ * @param root the component at which to start traversing the UI
+ * hierarchy.
+ * @param plobj the place object that is about to be entered.
+ */
+ public static function dispatchWillEnterPlace (
+ root :Object, plobj :PlaceObject) :void
+ {
+ dispatch(root, plobj, "willEnterPlace");
+ }
+
+ /**
+ * Dispatches a call to {@link PlaceView#didLeavePlace} to all UI
+ * elements in the hierarchy rooted at the component provided via the
+ * root parameter.
+ *
+ * @param root the component at which to start traversing the UI
+ * hierarchy.
+ * @param plobj the place object that is about to be entered.
+ */
+ public static function dispatchDidLeavePlace (
+ root :Object, plobj :PlaceObject) :void
+ {
+ dispatch(root, plobj, "didLeavePlace");
+ }
+
+ private static function dispatch (
+ root :Object, plobj :PlaceObject, funct :String) :void
+ {
+ // dispatch the call on this component if it implements PlaceView
+ if (root is PlaceView) {
+ try {
+ (root as PlaceView)[funct](plobj);
+ } catch (e :Error) {
+ Log.warning("Component choked on " + funct + "() " +
+ "[component=" + root + ", plobj=" + plobj + "].");
+ Log.logStackTrace(e);
+ }
+ }
+
+ // now traverse all of this component's children
+ if (root is DisplayObjectContainer) {
+ var cont :DisplayObjectContainer = (root as DisplayObjectContainer);
+ for (var ii :int = 0; ii < cont.numChildren; ii++) {
+ dispatch(cont.getChildAt(ii), plobj, funct);
+ }
+ }
+ }
+}
+}
diff --git a/src/as/com/threerings/util/ClassUtil.as b/src/as/com/threerings/util/ClassUtil.as
index 8568055a2..a64a78b14 100644
--- a/src/as/com/threerings/util/ClassUtil.as
+++ b/src/as/com/threerings/util/ClassUtil.as
@@ -1,7 +1,5 @@
package com.threerings.util {
-import flash.util.describeType;
-
public class ClassUtil
{
public static function getClassName (obj :Object) :String
@@ -37,7 +35,7 @@ public class ClassUtil
}
// TODO: there's currently no way to determine final from the class
- //var attrs :XMLList = describeType(type).elements("type");
+ //var attrs :XMLList = flash.util.describeType(type).elements("type");
return false;
}
}