diff --git a/src/as/com/threerings/io/ObjectOutputStream.as b/src/as/com/threerings/io/ObjectOutputStream.as
index ad4677a9f..fe7bac5eb 100644
--- a/src/as/com/threerings/io/ObjectOutputStream.as
+++ b/src/as/com/threerings/io/ObjectOutputStream.as
@@ -1,3 +1,6 @@
+//
+// $Id$
+
package com.threerings.io {
import flash.utils.ByteArray;
@@ -86,8 +89,7 @@ public class ObjectOutputStream
}
/**
- * This is equivalent to marshalling a field for which there
- * is a basic streamer.
+ * This is equivalent to marshalling a field for which there is a basic streamer.
*/
public function writeField (val :Object) :void
//throws IOError
@@ -100,10 +102,9 @@ public class ObjectOutputStream
}
/**
- * Uses the default streamable mechanism to write the contents of the
- * object currently being streamed. This can only be called from
- * within a writeObject implementation in a {@link
- * Streamable} object.
+ * Uses the default streamable mechanism to write the contents of the object currently being
+ * streamed. This can only be called from within a writeObject implementation in a
+ * {@link Streamable} object.
*/
public function defaultWriteObject () :void
//throws IOError
@@ -166,8 +167,7 @@ public class ObjectOutputStream
_targ.writeUTF(value);
}
- // these two are defined in IDataOutput, but have no java equivalent so
- // we skip them.
+ // these two are defined in IDataOutput, but have no java equivalent so we skip them.
//public function writeUnsignedInt (value :int) :void
//public function writeUTFBytes (value :int) :void
diff --git a/src/as/com/threerings/io/TypedArray.as b/src/as/com/threerings/io/TypedArray.as
index d1503f60e..6246615bd 100644
--- a/src/as/com/threerings/io/TypedArray.as
+++ b/src/as/com/threerings/io/TypedArray.as
@@ -50,6 +50,18 @@ public dynamic class TypedArray extends Array
_jtype = jtype;
}
+ /**
+ * Adds all of the elements of the supplied array to this typed array. The types of the
+ * elements of the target array must, of course, be of the type specified for this array
+ * otherwise badness will ensue.
+ */
+ public function addAll (other :Array) :void
+ {
+ for (var ii :int = 0; ii < other.length; ii++) {
+ this[ii] = other[ii];
+ }
+ }
+
public function getJavaType () :String
{
return _jtype;
diff --git a/src/as/com/threerings/io/streamers/ArrayStreamer.as b/src/as/com/threerings/io/streamers/ArrayStreamer.as
index fc072d909..3b170a0a1 100644
--- a/src/as/com/threerings/io/streamers/ArrayStreamer.as
+++ b/src/as/com/threerings/io/streamers/ArrayStreamer.as
@@ -30,6 +30,9 @@ public class ArrayStreamer extends Streamer
baseClass = Translations.getFromServer(baseClass);
_elementType = ClassUtil.getClassByName(baseClass);
_isFinal = ClassUtil.isFinal(_elementType);
+ if (_elementType == String) {
+ _delegate = new StringStreamer();
+ }
} else if (secondChar === "I") {
_elementType = int;
@@ -76,8 +79,7 @@ public class ArrayStreamer extends Streamer
return ta;
}
- override public function writeObject (obj :Object, out :ObjectOutputStream)
- :void
+ override public function writeObject (obj :Object, out :ObjectOutputStream) :void
{
var arr :Array = (obj as Array);
var ii :int;
@@ -115,8 +117,7 @@ public class ArrayStreamer extends Streamer
}
}
- override public function readObject (obj :Object, ins :ObjectInputStream)
- :void
+ override public function readObject (obj :Object, ins :ObjectInputStream) :void
{
var arr :Array = (obj as Array);
var ii :int;
diff --git a/src/as/com/threerings/presents/client/BasicDirector.as b/src/as/com/threerings/presents/client/BasicDirector.as
index 1accac256..6bc1aeb79 100644
--- a/src/as/com/threerings/presents/client/BasicDirector.as
+++ b/src/as/com/threerings/presents/client/BasicDirector.as
@@ -49,6 +49,9 @@ public class BasicDirector
// if we're already logged on, fire off a call to fetch services
if (client.isLoggedOn()) {
+ // this is a sanity check: it will fail if this post-logon initialized director claims
+ // to need service groups (it must make that known prior to logon)
+ registerServices(client);
fetchServices(client);
clientObjectUpdated(client);
}
diff --git a/src/as/com/threerings/presents/client/Client.as b/src/as/com/threerings/presents/client/Client.as
index 7c957852e..9d542d1db 100644
--- a/src/as/com/threerings/presents/client/Client.as
+++ b/src/as/com/threerings/presents/client/Client.as
@@ -1,3 +1,6 @@
+//
+// $Id$
+
package com.threerings.presents.client {
import flash.display.Stage;
@@ -59,9 +62,8 @@ public class Client extends EventDispatcher
}
/**
- * Unregisters the supplied observer. Upon return of this function,
- * the observer will no longer receive notifications of state changes
- * within the client.
+ * Unregisters the supplied observer. Upon return of this function, the observer will no longer
+ * receive notifications of state changes within the client.
*/
public function removeClientObserver (observer :SessionObserver) :void
{
@@ -176,8 +178,11 @@ public class Client extends EventDispatcher
*/
public function addServiceGroup (group :String) :void
{
+ if (isLoggedOn()) {
+ throw new Error("Services must be registered prior to logon().");
+ }
if (_bootGroups.indexOf(group) == -1) {
- _bootGroups.concat(group);
+ _bootGroups.push(group);
}
}
@@ -226,28 +231,35 @@ public class Client extends EventDispatcher
return false;
}
+ // let our observers know that we're logging on (this will give directors a chance to
+ // register invocation service groups)
notifyObservers(ClientEvent.CLIENT_WILL_LOGON);
+ // we need to wait for the CLIENT_WILL_LOGON to have been dispatched before we actually
+ // tell the communicator to logon, so we run this through the callLater pipeline
_comm = new Communicator(this);
- _comm.logon();
+ callLater(function () :void {
+ _comm.logon();
+ });
+ // it is safe, however, to start up our tick interval immediately
if (_tickInterval == null) {
_tickInterval = new Timer(5000);
_tickInterval.addEventListener(TimerEvent.TIMER, tick);
_tickInterval.start();
}
+
return true;
}
/**
* Requests that the client log off of the server to which it is connected.
*
- * @param abortable if true, the client will call clientWillDisconnect
- * on allthe client observers and abort the logoff process if any of them
- * return false. If false, clientWillDisconnect will not be called.
+ * @param abortable if true, the client will call clientWillDisconnect on allthe client
+ * observers and abort the logoff process if any of them return false. If false,
+ * clientWillDisconnect will not be called.
*
- * @return true if the logoff succeeded, false if it failed due to a
- * disagreeable observer.
+ * @return true if the logoff succeeded, false if it failed due to a disagreeable observer.
*/
public function logoff (abortable :Boolean) :Boolean
{
@@ -256,9 +268,8 @@ public class Client extends EventDispatcher
return true;
}
- // if the request is abortable, let's run it past the observers.
- // if any of them call preventDefault() then the logoff will be
- // cancelled
+ // if the request is abortable, let's run it past the observers. if any of them call
+ // preventDefault() then the logoff will be cancelled
if (abortable && !notifyObservers(ClientEvent.CLIENT_WILL_LOGOFF)) {
return false;
}
@@ -285,8 +296,8 @@ public class Client extends EventDispatcher
}
/**
- * Called every five seconds; ensures that we ping the server if we
- * haven't communicated in a long while.
+ * Called every five seconds; ensures that we ping the server if we haven't communicated in a
+ * long while.
*/
protected function tick (event :TimerEvent) :void
{
@@ -301,8 +312,8 @@ public class Client extends EventDispatcher
}
/**
- * Called by the {@link Communicator} if it is experiencing trouble logging
- * on but is still trying fallback strategies.
+ * Called by the {@link Communicator} if it is experiencing trouble logging on but is still
+ * trying fallback strategies.
*/
internal function reportLogonTribulations (cause :LogonError) :void
{
@@ -310,8 +321,8 @@ public class Client extends EventDispatcher
}
/**
- * Called by the invocation director when it successfully subscribes
- * to the client object immediately following logon.
+ * Called by the invocation director when it successfully subscribes to the client object
+ * immediately following logon.
*/
public function gotClientObject (clobj :ClientObject) :void
{
@@ -320,8 +331,7 @@ public class Client extends EventDispatcher
}
/**
- * Called by the invocation director if it fails to subscribe to the
- * client object after logon.
+ * Called by the invocation director if it fails to subscribe to the client object after logon.
*/
public function getClientObjectFailed (cause :Error) :void
{
@@ -329,8 +339,7 @@ public class Client extends EventDispatcher
}
/**
- * Called by the invocation director when it discovers that the client
- * object has changed.
+ * Called by the invocation director when it discovers that the client object has changed.
*/
protected function clientObjectDidChange (clobj :ClientObject) :void
{
@@ -351,9 +360,8 @@ public class Client extends EventDispatcher
// and let our invocation director know we're logged off
_invdir.cleanup();
- // if this was due to a logon error, we can notify our listeners
- // now that we're cleaned up: they may want to retry logon on
- // another port, or something
+ // if this was due to a logon error, we can notify our listeners now that we're cleaned up:
+ // they may want to retry logon on another port, or something
if (logonError != null) {
notifyObservers(ClientEvent.CLIENT_FAILED_TO_LOGON, logonError);
} else {
diff --git a/src/as/com/threerings/presents/net/AuthRequest.as b/src/as/com/threerings/presents/net/AuthRequest.as
index a9bbf08e3..7a744fb8c 100644
--- a/src/as/com/threerings/presents/net/AuthRequest.as
+++ b/src/as/com/threerings/presents/net/AuthRequest.as
@@ -1,3 +1,6 @@
+//
+// $Id$
+
package com.threerings.presents.net {
import com.threerings.io.ObjectInputStream;
@@ -13,7 +16,7 @@ public class AuthRequest extends UpstreamMessage
_creds = creds;
_version = version;
_bootGroups = new TypedArray("[Ljava.lang.String;");
- _bootGroups.concat(bootGroups);
+ _bootGroups.addAll(bootGroups);
// magic up a timezone in the format "GMT+XX:XX"
// Of course, the sign returned from getTimezoneOffset() is wrong