Use the new ObjectMarshaller.

Note that the default value of the encodeArrayElements has changed to reflect
the more general-purpose use.


git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@351 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Ray Greenwell
2007-07-06 22:27:16 +00:00
parent 54c571f7f5
commit 9b5d3cca12
5 changed files with 16 additions and 158 deletions
@@ -33,10 +33,8 @@ import flash.events.MouseEvent;
import flash.display.DisplayObject; import flash.display.DisplayObject;
import flash.display.InteractiveObject; import flash.display.InteractiveObject;
import flash.utils.IExternalizable;
import flash.utils.ByteArray; import flash.utils.ByteArray;
import flash.utils.Dictionary; import flash.utils.Dictionary;
import flash.utils.getQualifiedSuperclassName;
import com.threerings.io.TypedArray; import com.threerings.io.TypedArray;
@@ -46,6 +44,7 @@ import com.threerings.util.Integer;
import com.threerings.util.Iterator; import com.threerings.util.Iterator;
import com.threerings.util.MessageBundle; import com.threerings.util.MessageBundle;
import com.threerings.util.Name; import com.threerings.util.Name;
import com.threerings.util.ObjectMarshaller;
import com.threerings.util.StringUtil; import com.threerings.util.StringUtil;
import com.threerings.util.Wrapped; import com.threerings.util.Wrapped;
@@ -84,7 +83,6 @@ import com.threerings.ezgame.data.EZGameObject;
import com.threerings.ezgame.data.PropertySetEvent; import com.threerings.ezgame.data.PropertySetEvent;
import com.threerings.ezgame.data.PropertySetListener; import com.threerings.ezgame.data.PropertySetListener;
import com.threerings.ezgame.data.UserCookie; import com.threerings.ezgame.data.UserCookie;
import com.threerings.ezgame.util.EZObjectMarshaller;
/** /**
* Manages the backend of the game. * Manages the backend of the game.
@@ -248,7 +246,7 @@ public class GameControlBackend
validateConnected(); validateConnected();
validatePropertyChange(propName, value, index); validatePropertyChange(propName, value, index);
var encoded :Object = EZObjectMarshaller.encode(value, (index == -1)); var encoded :Object = ObjectMarshaller.encode(value, (index == -1));
_ezObj.ezGameService.setProperty( _ezObj.ezGameService.setProperty(
_ctx.getClient(), propName, encoded, index, _ctx.getClient(), propName, encoded, index,
false, null, createLoggingConfirmListener("setProperty")); false, null, createLoggingConfirmListener("setProperty"));
@@ -263,8 +261,8 @@ public class GameControlBackend
validateConnected(); validateConnected();
validatePropertyChange(propName, value, index); validatePropertyChange(propName, value, index);
var encodedValue :Object = EZObjectMarshaller.encode(value, (index == -1)); var encodedValue :Object = ObjectMarshaller.encode(value, (index == -1));
var encodedTestValue :Object = EZObjectMarshaller.encode(testValue, (index == -1)); var encodedTestValue :Object = ObjectMarshaller.encode(testValue, (index == -1));
_ezObj.ezGameService.setProperty( _ezObj.ezGameService.setProperty(
_ctx.getClient(), propName, encodedValue, index, _ctx.getClient(), propName, encodedValue, index,
true, encodedTestValue, createLoggingConfirmListener("setProperty")); true, encodedTestValue, createLoggingConfirmListener("setProperty"));
@@ -288,7 +286,7 @@ public class GameControlBackend
validateName(messageName); validateName(messageName);
validateValue(value); validateValue(value);
var encoded :Object = EZObjectMarshaller.encode(value, false); var encoded :Object = ObjectMarshaller.encode(value, false);
_ezObj.ezGameService.sendMessage(_ctx.getClient(), _ezObj.ezGameService.sendMessage(_ctx.getClient(),
messageName, encoded, playerId, messageName, encoded, playerId,
createLoggingConfirmListener("sendMessage")); createLoggingConfirmListener("sendMessage"));
@@ -409,7 +407,7 @@ public class GameControlBackend
var uc :UserCookie = var uc :UserCookie =
(_ezObj.userCookies.get(playerId) as UserCookie); (_ezObj.userCookies.get(playerId) as UserCookie);
if (uc != null) { if (uc != null) {
callback(EZObjectMarshaller.decode(uc.cookie)); callback(ObjectMarshaller.decode(uc.cookie));
return; return;
} }
} }
@@ -434,7 +432,7 @@ public class GameControlBackend
validateConnected(); validateConnected();
validateValue(cookie); validateValue(cookie);
var ba :ByteArray = var ba :ByteArray =
(EZObjectMarshaller.encode(cookie, false) as ByteArray); (ObjectMarshaller.encode(cookie, false) as ByteArray);
if (ba.length > MAX_USER_COOKIE) { if (ba.length > MAX_USER_COOKIE) {
// not saved! // not saved!
return false; return false;
@@ -544,7 +542,7 @@ public class GameControlBackend
validateValue(values); validateValue(values);
var encodedValues :TypedArray = var encodedValues :TypedArray =
(EZObjectMarshaller.encode(values) as TypedArray); (ObjectMarshaller.encode(values, true) as TypedArray);
_ezObj.ezGameService.addToCollection( _ezObj.ezGameService.addToCollection(
_ctx.getClient(), collName, encodedValues, clearExisting, _ctx.getClient(), collName, encodedValues, clearExisting,
@@ -721,47 +719,7 @@ public class GameControlBackend
*/ */
protected function validateValue (value :Object) :void protected function validateValue (value :Object) :void
{ {
if (value == null) { ObjectMarshaller.validateValue(value);
return;
} else if (value is IExternalizable) {
throw new ArgumentError(
"IExternalizable is not yet supported");
} else if (value is Array) {
if (ClassUtil.getClassName(value) != "Array") {
// We can't allow arrays to be serialized as IExternalizables
// because we need to know element values (opaquely) on the
// server. Also, we don't allow other types because we wouldn't
// create the right class on the other side.
throw new ArgumentError(
"Custom array subclasses are not supported");
}
// then, continue on with the sub-properties check (below)
} else {
var type :String = typeof(value);
if (type == "number" || type == "string" || type == "boolean" ) {
// kosher!
return;
}
if (value is ByteArray) {
return; // kosher
}
var clazz :Class = ClassUtil.getClass(value);
var clazzparentname :String = getQualifiedSuperclassName(clazz);
var rootclass :Boolean = (clazzparentname == null);
if (! rootclass) {
throw new ArgumentError(
"Non-simple properties may not be set.");
}
// fall through and verify the object's sub-properties
}
// check sub-properties (of arrays and objects)
for each (var arrValue :Object in (value as Array)) {
validateValue(arrValue);
}
} }
/** /**
@@ -900,7 +858,7 @@ public class GameControlBackend
if (EZGameObject.USER_MESSAGE == name) { if (EZGameObject.USER_MESSAGE == name) {
var args :Array = event.getArgs(); var args :Array = event.getArgs();
callUserCode("messageReceived_v1", (args[0] as String), callUserCode("messageReceived_v1", (args[0] as String),
EZObjectMarshaller.decode(args[1])); ObjectMarshaller.decode(args[1]));
} else if (EZGameObject.GAME_CHAT == name) { } else if (EZGameObject.GAME_CHAT == name) {
// this is chat send by the game, let's route it like // this is chat send by the game, let's route it like
@@ -925,7 +883,7 @@ public class GameControlBackend
if (msgName == event.getName()) { if (msgName == event.getName()) {
var args :Array = event.getArgs(); var args :Array = event.getArgs();
callUserCode("messageReceived_v1", (args[0] as String), callUserCode("messageReceived_v1", (args[0] as String),
EZObjectMarshaller.decode(args[1])); ObjectMarshaller.decode(args[1]));
} }
} }
@@ -940,7 +898,7 @@ public class GameControlBackend
delete _cookieCallbacks[cookie.playerId]; delete _cookieCallbacks[cookie.playerId];
for each (var fn :Function in arr) { for each (var fn :Function in arr) {
try { try {
fn(EZObjectMarshaller.decode(cookie.cookie)); fn(ObjectMarshaller.decode(cookie.cookie));
} catch (err :Error) { } catch (err :Error) {
// cope // cope
} }
@@ -35,7 +35,6 @@ import com.threerings.parlor.game.client.GameConfigurator;
import com.threerings.parlor.game.data.GameConfig; import com.threerings.parlor.game.data.GameConfig;
import com.threerings.ezgame.client.EZGameController; import com.threerings.ezgame.client.EZGameController;
import com.threerings.ezgame.util.EZObjectMarshaller;
/** /**
* A game config for a simple multiplayer ez game. * A game config for a simple multiplayer ez game.
@@ -26,6 +26,7 @@ import flash.events.Event;
import flash.utils.ByteArray; import flash.utils.ByteArray;
import com.threerings.util.Name; import com.threerings.util.Name;
import com.threerings.util.ObjectMarshaller;
import com.threerings.io.ObjectInputStream; import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream; import com.threerings.io.ObjectOutputStream;
@@ -36,8 +37,6 @@ import com.threerings.presents.dobj.DSet;
import com.threerings.parlor.game.data.GameObject; import com.threerings.parlor.game.data.GameObject;
import com.threerings.parlor.turn.data.TurnGameObject; import com.threerings.parlor.turn.data.TurnGameObject;
import com.threerings.ezgame.util.EZObjectMarshaller;
public class EZGameObject extends GameObject public class EZGameObject extends GameObject
implements TurnGameObject implements TurnGameObject
{ {
@@ -142,7 +141,7 @@ public class EZGameObject extends GameObject
var count :int = ins.readInt(); var count :int = ins.readInt();
while (count-- > 0) { while (count-- > 0) {
var key :String = ins.readUTF(); var key :String = ins.readUTF();
var value :Object = EZObjectMarshaller.decode(ins.readObject()); var value :Object = ObjectMarshaller.decode(ins.readObject());
_props[key] = value; _props[key] = value;
} }
} }
@@ -28,13 +28,12 @@ import com.threerings.io.ObjectInputStream;
import com.threerings.io.ObjectOutputStream; import com.threerings.io.ObjectOutputStream;
import com.threerings.io.Streamer; import com.threerings.io.Streamer;
import com.threerings.util.ObjectMarshaller;
import com.threerings.util.StringBuilder; import com.threerings.util.StringBuilder;
import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.NamedEvent; import com.threerings.presents.dobj.NamedEvent;
import com.threerings.ezgame.util.EZObjectMarshaller;
/** /**
* Represents a property change on the actionscript object we * Represents a property change on the actionscript object we
* use in FlashGameObject. * use in FlashGameObject.
@@ -86,7 +85,7 @@ public class PropertySetEvent extends NamedEvent
{ {
super.readObject(ins); super.readObject(ins);
_index = ins.readInt(); _index = ins.readInt();
_data = EZObjectMarshaller.decode(ins.readObject()); _data = ObjectMarshaller.decode(ins.readObject());
} }
// from interface Streamable // from interface Streamable
@@ -1,97 +0,0 @@
//
// $Id$
//
// Vilya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/vilya/
//
// 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.ezgame.util {
import flash.net.ObjectEncoding;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
import flash.utils.Endian;
import com.threerings.io.TypedArray;
/**
* Utility methods for transferring flash properties via
* the presents dobj system.
*/
public class EZObjectMarshaller
{
/**
* Encode the specified object as either a byte[] or a byte[][] if it
* is an array. The specific mechanism of encoding is not important,
* as long as decode returns a clone of the original object.
*
* Currently, cycles in the object graph are preserved on the other end.
* TODO: serialize IExternalizable implementations, and take
* into account the ApplicationDomain.
*/
public static function encode (
obj :Object, encodeArrayElements :Boolean = true) :Object
{
if (obj == null) {
return null;
}
if (encodeArrayElements && obj is Array) {
var src :Array = (obj as Array);
var dest :TypedArray = TypedArray.create(ByteArray);
for each (var o :Object in src) {
dest.push(encode(o, false));
}
return dest;
}
// TODO: Our own encoding, that takes into account
// the ApplicationDomain
var bytes :ByteArray = new ByteArray();
bytes.endian = Endian.BIG_ENDIAN;
bytes.objectEncoding = ObjectEncoding.AMF3;
bytes.writeObject(obj);
return bytes;
}
public static function decode (encoded :Object) :Object
{
if (encoded == null) {
return null;
}
if (encoded is TypedArray) {
var src :TypedArray = (encoded as TypedArray);
var dest :Array = [];
for each (var b :ByteArray in src) {
dest.push(decode(b));
}
return dest;
}
var bytes :ByteArray = (encoded as ByteArray);
// re-set the position in case we're decoding the actual same byte
// array used to encode (and not a network reconstruction)
bytes.position = 0;
// TODO: Our own decoding, that takes into account
// the ApplicationDomain
bytes.endian = Endian.BIG_ENDIAN;
bytes.objectEncoding = ObjectEncoding.AMF3;
return bytes.readObject();
}
}
}