diff --git a/src/as/com/threerings/presents/client/Client.as b/src/as/com/threerings/presents/client/Client.as index 3d678c779..4b5540022 100644 --- a/src/as/com/threerings/presents/client/Client.as +++ b/src/as/com/threerings/presents/client/Client.as @@ -205,13 +205,13 @@ public class Client extends EventDispatcher } } - protected function gotClientObject (clobj :ClientObject) :void + internal function gotClientObject (clobj :ClientObject) :void { _clobj = clobj; notifyObservers(ClientEvent.CLIENT_DID_LOGON); } - protected function getClientObjectFailed (cause :Error) :void + internal function getClientObjectFailed (cause :Error) :void { notifyObservers(ClientEvent.CLIENT_FAILED_TO_LOGON, cause); } diff --git a/src/as/com/threerings/presents/client/InvocationDecoder.as b/src/as/com/threerings/presents/client/InvocationDecoder.as new file mode 100644 index 000000000..d30dc62d6 --- /dev/null +++ b/src/as/com/threerings/presents/client/InvocationDecoder.as @@ -0,0 +1,55 @@ +// +// $Id: InvocationDecoder.java 3099 2004-08-27 02:21:06Z 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.presents.client { + +import com.threerings.presents.Log; + +/** + * Provides the basic functionality used to dispatch invocation + * notification events. + */ +public /* abstract */ class InvocationDecoder +{ + /** The receiver for which we're decoding and dipatching + * notifications. */ + public var receiver :InvocationReceiver; + + /** + * Returns the generated hash code that is used to identify this + * invocation notification service. + */ + public /* abstract */ function getReceiverCode () :String + { + return "abstract"; + } + + /** + * Dispatches the specified method to our receiver. + */ + public function dispatchNotification (methodId :int, args :Array) :void + { + Log.warning("Requested to dispatch unknown method " + + "[receiver=" + receiver + ", methodId=" + methodId + + ", args=" + args + "]."); + } +} +} diff --git a/src/as/com/threerings/presents/client/InvocationDirector.as b/src/as/com/threerings/presents/client/InvocationDirector.as index 684b62a14..228b6cdd6 100644 --- a/src/as/com/threerings/presents/client/InvocationDirector.as +++ b/src/as/com/threerings/presents/client/InvocationDirector.as @@ -1,14 +1,22 @@ package com.threerings.presents.client { +import com.threerings.presents.dobj.DEvent; +import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.DObjectManager; +import com.threerings.presents.dobj.DSet; +import com.threerings.presents.dobj.EventListener; +import com.threerings.presents.dobj.ObjectAccessError; +import com.threerings.presents.dobj.Subscriber; import com.threerings.presents.data.ClientObject; import com.threerings.presents.Log; public class InvocationDirector + implements EventListener { - public function init (omgr :DObjectManager, cloid :int, client :Client) :void + public function init (omgr :DObjectManager, cloid :int, client :Client) + :void { if (_clobj != null) { Log.warning("Zoiks, client object around during invmgr init!"); @@ -18,7 +26,7 @@ public class InvocationDirector _omgr = omgr; _client = client; - // TODO : lots more + _omgr.subscribeToObject(cloid, new ClientSubscriber(this)); } public function cleanup () :void @@ -28,10 +36,111 @@ public class InvocationDirector // TODO: lots more } - protected var _omgr :DObjectManager; + /** + * Registers an invocation notification receiver by way of its + * notification event decoder. + */ + public function registerReceiver (decoder :InvocationDecoder) :void + { + _reclist.push(decoder); - protected var _client :Client; + // if we're already online, assign a recevier id now + if (_clobj != null) { + assignReceiverId(decoder); + } + } - protected var _clobj :ClientObject; + // documentation inherited from interface EventListener + public function eventReceived (event :DEvent) :void + { + // TODO + } + + /** + * Assigns a receiver id to this decoder and publishes it in the + * {@link ClientObject#receivers} field. + */ + internal function assignReceiverId (decoder :InvocationDecoder) :void + { + // TODO + } + + /** + * Called when we log on; generates mappings for all receivers + * registered prior to logon. + */ + internal function assignReceiverIds () :void + { + _clobj.startTransaction(); + try { + for each (var decoder :InvocationDecoder in _reclist) { + assignReceiverId(decoder); + } + } finally { + _clobj.commitTransaction(); + } + } + + /** + * Called by the ClientSubscriber helper class when the client object + * has been returned by the server. + */ + public function gotClientObject (clobj :ClientObject) :void + { + clobj.addListener(this); + clobj.setReceivers(new DSet()); + _clobj = clobj; + assignReceiverIds(); + + _client.gotClientObject(clobj); + } + + /** + * Called by the ClientSubscriber helper class when it fails. + */ + public function gotClientObjectFailed (oid :int, cause :ObjectAccessError) + :void + { + Log.warning("Invocation director unable to subscribe to " + + "client object [cloid=" + oid + ", cause=" + cause + "]!"); + _client.getClientObjectFailed(cause); + } + + internal var _omgr :DObjectManager; + + internal var _client :Client; + + internal var _clobj :ClientObject; + + /** All registered receivers are maintained in a list so that we can + * assign receiver ids to them when we go online. */ + internal var _reclist :Array = new Array(); } } + +import com.threerings.presents.client.InvocationDirector; +import com.threerings.presents.data.ClientObject; +import com.threerings.presents.dobj.DObject; +import com.threerings.presents.dobj.ObjectAccessError; +import com.threerings.presents.dobj.Subscriber; +import com.threerings.presents.Log; + +class ClientSubscriber implements Subscriber +{ + public function ClientSubscriber (invdir :InvocationDirector) + { + _invdir = invdir; + } + + public function objectAvailable (obj :DObject) :void + { + _invdir.gotClientObject(obj as ClientObject); + } + + public function requestFailed (oid :int, cause :ObjectAccessError) :void + { + _invdir.gotClientObjectFailed(oid, cause); + } + + protected var _invdir :InvocationDirector; +} diff --git a/src/as/com/threerings/presents/client/InvocationReceiver.as b/src/as/com/threerings/presents/client/InvocationReceiver.as new file mode 100644 index 000000000..7e8fc1cb5 --- /dev/null +++ b/src/as/com/threerings/presents/client/InvocationReceiver.as @@ -0,0 +1,51 @@ +// +// $Id: InvocationReceiver.java 3099 2004-08-27 02:21:06Z 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.presents.client { + +import com.threerings.presents.dobj.DSet; + +/** + * Invocation notification receipt interfaces should be defined as + * extending this interface. Actual notification receivers will implement + * the requisite receiver interface definition and register themselves + * with the {@link InvocationDirector} using the generated {@link + * InvocationDecoder} class specific to the notification receiver + * interface in question. For example: + * + *
+ * public class FooDirector implements FooReceiver
+ * {
+ * public FooDirector (PresentsContext ctx)
+ * {
+ * InvocationDirector idir = ctx.getClient().getInvocationDirector();
+ * idir.registerReceiver(new FooDecoder(this));
+ * }
+ * }
+ *
+ *
+ * @see InvocationDirector#registerReceiver
+ */
+public interface InvocationReceiver
+{
+ // nada, but see InvocationRegistration
+}
+}
diff --git a/src/as/com/threerings/presents/client/InvocationRegistration.as b/src/as/com/threerings/presents/client/InvocationRegistration.as
new file mode 100644
index 000000000..39cdb6c9a
--- /dev/null
+++ b/src/as/com/threerings/presents/client/InvocationRegistration.as
@@ -0,0 +1,61 @@
+package com.threerings.presents.client {
+
+import com.threerings.util.Comparable;
+
+import com.threerings.io.ObjectInputStream;
+import com.threerings.io.ObjectOutputStream;
+
+import com.threerings.presents.dobj.DSet;
+import com.threerings.presents.dobj.DSetEntry;
+
+/**
+ * Used to maintain a registry of invocation receivers that can be
+ * used to convert (large) hash codes into (small) registration
+ * numbers.
+ */
+public class InvocationRegistration
+ implements DSetEntry
+{
+ /** The unique hash code associated with this invocation receiver class. */
+ public var receiverCode :String;
+
+ /** The unique id assigned to this invocation receiver class at
+ * registration time. */
+ public var receiverId :int;
+
+ /** Creates and initializes a registration instance. */
+ public function Registration (receiverCode :String, receiverId :int)
+ {
+ this.receiverCode = receiverCode;
+ this.receiverId = receiverId;
+ }
+
+ // documentation inherited from interface DSetEntry
+ public function getKey () :Comparable
+ {
+ return null; // TODO receiverCode;
+ // TODO: maybe we drop the concept of Comparable and just
+ // use any old objects: screw performance
+ }
+
+ // documentation inherited
+ public function toString () :String
+ {
+ return "[" + receiverCode + " => " + receiverId + "]";
+ }
+
+ // documentation inherited from superinterface Streamable
+ public function writeObject (out :ObjectOutputStream) :void
+ {
+ out.writeField(receiverCode);
+ out.writeShort(receiverId);
+ }
+
+ // documentation inherited from superinterface Streamable
+ public function readObject (ins :ObjectInputStream) :void
+ {
+ receiverCode = (ins.readField(String) as String);
+ receiverId = ins.readShort();
+ }
+}
+}
diff --git a/src/as/com/threerings/presents/data/ClientObject.as b/src/as/com/threerings/presents/data/ClientObject.as
index b633bde30..fe33415dd 100644
--- a/src/as/com/threerings/presents/data/ClientObject.as
+++ b/src/as/com/threerings/presents/data/ClientObject.as
@@ -21,6 +21,8 @@
package com.threerings.presents.data {
+import mx.utils.ObjectUtil;
+
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DSet;
@@ -35,6 +37,11 @@ import com.threerings.io.ObjectOutputStream;
*/
public class ClientObject extends DObject
{
+ // AUTO-GENERATED: FIELDS START
+ /** The field name of the receivers field. */
+ public static const RECEIVERS :String = "receivers";
+ // AUTO-GENERATED: FIELDS END
+
/** Used to publish all invocation service receivers registered on
* this client. */
public var receivers :DSet;
@@ -58,5 +65,14 @@ public class ClientObject extends DObject
super.readObject(ins);
receivers = (ins.readObject() as DSet);
}
+
+ // AUTO-GENERATED: METHODS START
+ public function setReceivers (value :DSet) :void
+ {
+ requestAttributeChange(RECEIVERS, value, this.receivers);
+ this.receivers = (value == null) ? null
+ : (ObjectUtil.copy(value) as DSet);
+ }
+ // AUTO-GENERATED: METHODS END
}
}