More progress.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3861 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -11,6 +11,8 @@ Design decisions
|
|||||||
- I am embracing flash's event distribution model because it saved me a bunch
|
- I am embracing flash's event distribution model because it saved me a bunch
|
||||||
of work.
|
of work.
|
||||||
|
|
||||||
|
- We could use the setter methods on DObject properties to generate dobj
|
||||||
|
events, but so far I haven't gone there.
|
||||||
|
|
||||||
|
|
||||||
Notes
|
Notes
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class ObjectInputStream
|
|||||||
|
|
||||||
var target :*;
|
var target :*;
|
||||||
if (cmap.streamer === null) {
|
if (cmap.streamer === null) {
|
||||||
var clazz :Class = flash.util.getClassByName(cmap.cname);
|
var clazz :Class = flash.util.getClassByName(cmap.classname);
|
||||||
target = new clazz();
|
target = new clazz();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -87,8 +87,7 @@ public class ObjectInputStream
|
|||||||
{
|
{
|
||||||
// streamable objects
|
// streamable objects
|
||||||
if (streamer == null) {
|
if (streamer == null) {
|
||||||
var sable :Streamable = (obj as Streamable);
|
obj.readObject(this); // obj is a Streamable.
|
||||||
sable.readObject(this);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +116,7 @@ public class ObjectInputStream
|
|||||||
public function defaultReadObject () :void
|
public function defaultReadObject () :void
|
||||||
//throws IOError
|
//throws IOError
|
||||||
{
|
{
|
||||||
_streamer.readObject(_current, this, false);
|
_streamer.readObject(_current, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function readBoolean () :Boolean
|
public function readBoolean () :Boolean
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class ObjectOutputStream
|
|||||||
// create a class mapping if we've not got one
|
// create a class mapping if we've not got one
|
||||||
if (cmap === undefined) {
|
if (cmap === undefined) {
|
||||||
var streamer :Streamer = Streamer.getStreamer(obj);
|
var streamer :Streamer = Streamer.getStreamer(obj);
|
||||||
|
// streamer may be null to indicate a Streamable object
|
||||||
if (streamer === undefined) {
|
if (streamer === undefined) {
|
||||||
// TODO
|
// TODO
|
||||||
trace("OMG, cannot stream ", cname);
|
trace("OMG, cannot stream ", cname);
|
||||||
@@ -60,8 +61,7 @@ public class ObjectOutputStream
|
|||||||
{
|
{
|
||||||
// if it's Streamable, it goes straight through
|
// if it's Streamable, it goes straight through
|
||||||
if (streamer == null) {
|
if (streamer == null) {
|
||||||
var sable :Streamable = (obj as Streamable);
|
obj.writeObject(this); // obj is a Streamable
|
||||||
sable.writeObject(this);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ public class ObjectOutputStream
|
|||||||
}
|
}
|
||||||
|
|
||||||
// write the instance data
|
// write the instance data
|
||||||
_streamer.writeObject(_current, this, false)
|
_streamer.writeObject(_current, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeBoolean (value :Boolean) :void
|
public function writeBoolean (value :Boolean) :void
|
||||||
|
|||||||
@@ -40,11 +40,9 @@ public class Streamer
|
|||||||
createStreamers();
|
createStreamers();
|
||||||
}
|
}
|
||||||
|
|
||||||
var s :Streamer;
|
|
||||||
for (var ii :int = 0; ii < _streamers.lenght; ii++) {
|
for (var ii :int = 0; ii < _streamers.lenght; ii++) {
|
||||||
s = (_streamers[ii] as Streamer);
|
if (_streamers[ii].isStreamerFor(obj)) {
|
||||||
if (s.isStreamerFor(obj)) {
|
return _streamers[ii];
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,11 +55,9 @@ public class Streamer
|
|||||||
createStreamers();
|
createStreamers();
|
||||||
}
|
}
|
||||||
|
|
||||||
var s :Streamer;
|
|
||||||
for (var ii :int = 0; ii < _streamers.length; ii++) {
|
for (var ii :int = 0; ii < _streamers.length; ii++) {
|
||||||
s = (_streamers[ii] as Streamer);
|
if (_streamers[ii].getJavaClassName() === jname) {
|
||||||
if (s.getJavaClassName() === jname) {
|
return _streamers[ii];
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,8 +109,12 @@ public class Communicator
|
|||||||
protected function inputFrameReceived (event :FrameAvailableEvent) :void
|
protected function inputFrameReceived (event :FrameAvailableEvent) :void
|
||||||
{
|
{
|
||||||
// convert the frame data into a message from the server
|
// convert the frame data into a message from the server
|
||||||
_inStream.setSource(event.getFrameData());
|
var frameData :ByteArray = event.getFrameData();
|
||||||
|
_inStream.setSource(frameData);
|
||||||
var msg :DownstreamMessage = _inStream.readObject();
|
var msg :DownstreamMessage = _inStream.readObject();
|
||||||
|
if (frameData.bytesAvailable > 0) {
|
||||||
|
trace("OMG, we didn't fully read the frame. Surely there's a bug");
|
||||||
|
}
|
||||||
|
|
||||||
if (_omgr != null) {
|
if (_omgr != null) {
|
||||||
// if we're logged on, then just do the normal thing
|
// if we're logged on, then just do the normal thing
|
||||||
@@ -119,7 +123,7 @@ public class Communicator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, this would be the AuthResponse to our logon attempt.
|
// Otherwise, this would be the AuthResponse to our logon attempt.
|
||||||
var rsp :AuthResponse = (msg as AuthResponse); // TODO: as correct?
|
var rsp :AuthResponse = (msg as AuthResponse);
|
||||||
var data :AuthResponseData = rsp.getData();
|
var data :AuthResponseData = rsp.getData();
|
||||||
if (data.code !== AuthResponseData.SUCCESS) {
|
if (data.code !== AuthResponseData.SUCCESS) {
|
||||||
shutdown(new Error(data.code));
|
shutdown(new Error(data.code));
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.threerings.presents.client {
|
||||||
|
|
||||||
|
import com.threerings.presents.dobj.DObjectManager;
|
||||||
|
|
||||||
|
public class InvocationDirector
|
||||||
|
{
|
||||||
|
public function init (omgr :DObjectManager, cloid :int, client :Client) :void
|
||||||
|
{
|
||||||
|
if (_clobj != null) {
|
||||||
|
trace("Zoiks, client object around during invmgr init!");
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
_omgr = omgr;
|
||||||
|
_client = client;
|
||||||
|
|
||||||
|
// TODO : lots more
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cleanup () :void
|
||||||
|
{
|
||||||
|
_clobj = null;
|
||||||
|
|
||||||
|
// TODO: lots more
|
||||||
|
}
|
||||||
|
|
||||||
|
protected var _omgr :DObjectManager;
|
||||||
|
|
||||||
|
protected var _client :Client;
|
||||||
|
|
||||||
|
protected var _clobj :ClientObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An attribute changed event is dispatched when a single attribute of a
|
||||||
|
* distributed object has changed. It can also be constructed to request
|
||||||
|
* an attribute change on an object and posted to the dobjmgr.
|
||||||
|
*
|
||||||
|
* @see DObjectManager#postEvent
|
||||||
|
*/
|
||||||
|
public class AttributeChangedEvent extends NamedEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the new value of the attribute.
|
||||||
|
*/
|
||||||
|
public function getValue () :*
|
||||||
|
{
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the attribute prior to the application of this
|
||||||
|
* event.
|
||||||
|
*/
|
||||||
|
public function getOldValue () :*
|
||||||
|
{
|
||||||
|
return _oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies this attribute change to the object.
|
||||||
|
*/
|
||||||
|
public override function applyToObject (target :DObject) :Boolean
|
||||||
|
//throws ObjectAccessException
|
||||||
|
{
|
||||||
|
// if we have no old value, that means we're not running on the
|
||||||
|
// master server and we have not already applied this attribute
|
||||||
|
// change to the object, so we must grab the previous value and
|
||||||
|
// actually apply the attribute change
|
||||||
|
if (_oldValue === UNSET_OLD_ENTRY) {
|
||||||
|
_oldValue = target[_name]; // fucking wack-ass language
|
||||||
|
}
|
||||||
|
target[_name] = _value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new attribute changed event on the specified target
|
||||||
|
* object with the supplied attribute name and value. <em>Do not
|
||||||
|
* construct these objects by hand.</em> Use {@link
|
||||||
|
* DObject#changeAttribute} instead.
|
||||||
|
*
|
||||||
|
* @param targetOid the object id of the object whose attribute has
|
||||||
|
* changed.
|
||||||
|
* @param name the name of the attribute (data member) that has
|
||||||
|
* changed.
|
||||||
|
* @param value the new value of the attribute (in the case of
|
||||||
|
* primitive types, the reflection-defined object-alternative is
|
||||||
|
* used).
|
||||||
|
*/
|
||||||
|
protected function AttributeChangedEvent (
|
||||||
|
targetOid :int, name :String, value :*, oldValue :*)
|
||||||
|
{
|
||||||
|
super(targetOid, name);
|
||||||
|
_value = value;
|
||||||
|
_oldValue = oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function notifyListener (listener :*) :void
|
||||||
|
{
|
||||||
|
if (listener is AttributeChangeListener) {
|
||||||
|
listener.attributeChanged(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function toString (buf :StringBuilder) :void
|
||||||
|
{
|
||||||
|
buf.append("CHANGE:");
|
||||||
|
super.toString(buf);
|
||||||
|
buf.append(", value=", _value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected var _value :*;
|
||||||
|
protected var _oldValue :* = UNSET_OLD_ENTRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The various listener interfaces (e.g. {@link EventListener}, {@link
|
||||||
|
* AttributeChangeListener}, etc.) all extend this base interface so that
|
||||||
|
* the distributed object can check to make sure when an object is adding
|
||||||
|
* itself as a listener of some sort that it actually implements at least
|
||||||
|
* one of the listener interfaces. Thus, all listener interfaces must
|
||||||
|
* extend this one.
|
||||||
|
*/
|
||||||
|
public interface ChangeListener {
|
||||||
|
// nada
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
package com.threerings.presents.dobj {
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
public class DEvent extends Object
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
import com.threerings.io.Streamable;
|
||||||
|
|
||||||
|
public class DEvent
|
||||||
|
implements Streamable
|
||||||
{
|
{
|
||||||
public function DEvent ()
|
public function DEvent ()
|
||||||
{
|
{
|
||||||
@@ -11,12 +18,91 @@ public class DEvent extends Object
|
|||||||
_toid = targetOid;
|
_toid = targetOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the oid of the object that is the target of this event.
|
||||||
|
*/
|
||||||
public function getTargetOid () :int
|
public function getTargetOid () :int
|
||||||
{
|
{
|
||||||
return _toid;
|
return _toid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some events are used only internally on the server and need not be
|
||||||
|
* broadcast to subscribers, proxy or otherwise. Such events can
|
||||||
|
* return true here and short-circuit the normal proxy event dispatch
|
||||||
|
* mechanism.
|
||||||
|
*/
|
||||||
|
public function applyToObject (target :DObject) :void
|
||||||
|
{
|
||||||
|
trace("TODO: abstract methods?");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Events with associated listener interfaces should implement this
|
||||||
|
* function and notify the supplied listener if it implements their
|
||||||
|
* event listening interface. For example, the {@link
|
||||||
|
* AttributeChangedEvent} will notify listeners that implement {@link
|
||||||
|
* AttributeChangeListener}.
|
||||||
|
*/
|
||||||
|
protected function notifyListener (listener :*) :void
|
||||||
|
{
|
||||||
|
// the default is to do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs and returns a string representation of this event.
|
||||||
|
*/
|
||||||
|
public override function toString () :String
|
||||||
|
{
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
buf.append("[");
|
||||||
|
toString(buf);
|
||||||
|
buf.append("]");
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface Streamable
|
||||||
|
public function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
out.writeInt(_toid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface Streamable
|
||||||
|
public function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
_toid = ins.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should be overridden by derived classes (which should be sure
|
||||||
|
* to call <code>super.toString()</code>) to append the derived class
|
||||||
|
* specific event information to the string buffer.
|
||||||
|
*/
|
||||||
|
protected function toString (buf :StringBuilder) :void
|
||||||
|
{
|
||||||
|
buf.append("targetOid=", _toid);
|
||||||
|
}
|
||||||
|
|
||||||
/** The oid of the object that is the target of this event. */
|
/** The oid of the object that is the target of this event. */
|
||||||
protected var _toid :int;
|
protected var _toid :int;
|
||||||
|
|
||||||
|
protected static const UNSET_OLD_ENTRY :DSetEntry = new DummyEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DummyEntry implements DSetEntry
|
||||||
|
{
|
||||||
|
public function getKey () :Comparable
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package com.threerings.presents.dobj {
|
|||||||
|
|
||||||
import flash.events.EventDispatcher;
|
import flash.events.EventDispatcher;
|
||||||
|
|
||||||
|
import mx.collections.ArrayCollection;
|
||||||
|
|
||||||
import com.threerings.io.ObjectInputStream;
|
import com.threerings.io.ObjectInputStream;
|
||||||
import com.threerings.io.ObjectOutputStream;
|
import com.threerings.io.ObjectOutputStream;
|
||||||
import com.threerings.io.Streamable;
|
import com.threerings.io.Streamable;
|
||||||
|
|
||||||
public class DObject extends EventDispatcher
|
public class DObject // extends EventDispatcher
|
||||||
implements Streamable
|
implements Streamable
|
||||||
{
|
{
|
||||||
public function getOid ():int
|
public function getOid ():int
|
||||||
@@ -14,9 +16,152 @@ public class DObject extends EventDispatcher
|
|||||||
return _oid;
|
return _oid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getManager () :DObjectManager
|
||||||
|
{
|
||||||
|
return _omgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addListener (listener :ChangeListener) :void
|
||||||
|
{
|
||||||
|
if (_listeners == null) {
|
||||||
|
_listeners = new ArrayCollection();
|
||||||
|
|
||||||
|
} else if (_listeners.contains(listener)) {
|
||||||
|
trace("Refusing repeat listener registration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_listeners.addItem(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeListener (listener :ChangeListener) :void
|
||||||
|
{
|
||||||
|
if (_listeners != null) {
|
||||||
|
var dex :int = _listeners.getItemIndex(listener);
|
||||||
|
if (dex != -1) {
|
||||||
|
_listeners.removeItemAt(dex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notifyListeners (event :DEvent) :void
|
||||||
|
{
|
||||||
|
if (_listeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var ii :int = 0; ii < _listeners.length; ii++) {
|
||||||
|
var listener :* = _listeners.getItemAt(ii);
|
||||||
|
try {
|
||||||
|
event.notifyListener(listener);
|
||||||
|
|
||||||
|
if (listener is EventListener) {
|
||||||
|
listener.eventReceived(event);
|
||||||
|
}
|
||||||
|
} catch (e :Error) {
|
||||||
|
trace("Listener choked during notification");
|
||||||
|
trace(e.getStackTrace());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postMessage (name :String, args :Array) :void
|
||||||
|
{
|
||||||
|
postEvent(new MessageEvent(_oid, name, args));
|
||||||
|
}
|
||||||
|
|
||||||
public function postEvent (DEvent event) :void
|
public function postEvent (DEvent event) :void
|
||||||
{
|
{
|
||||||
|
// TODO: transactons?
|
||||||
|
if (_omgr != null) {
|
||||||
|
_omgr.postEvent(event);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
trace("Unable to post event, object has no omgr");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isActive () :Boolean
|
||||||
|
{
|
||||||
|
return (_omgr != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't call this function! It initializes this distributed object
|
||||||
|
* with the supplied distributed object manager. This is called by the
|
||||||
|
* distributed object manager when an object is created and registered
|
||||||
|
* with the system.
|
||||||
|
*
|
||||||
|
* @see DObjectManager#createObject
|
||||||
|
*/
|
||||||
|
public function setManager (omgr :DObjectManager) :void
|
||||||
|
{
|
||||||
|
_omgr = omgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by derived instances when an attribute setter method was
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
|
protected function requestAttributeChange (
|
||||||
|
name :String, value :*, oldValue :*) :void
|
||||||
|
{
|
||||||
|
postEvent(new AttributeChangedEvent(_oid, name, value, oldValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by derived instances when an element updater method was
|
||||||
|
* called.
|
||||||
|
*/
|
||||||
|
protected function requestElementUpdate (
|
||||||
|
name :String, index :int, value :*, oldValue :*) :void
|
||||||
|
{
|
||||||
|
// dispatch an attribute changed event
|
||||||
|
postEvent(new ElementUpdatedEvent(_oid, name, value, oldValue, index));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls by derived instances when an oid adder method was called.
|
||||||
|
*/
|
||||||
|
protected function requestOidAdd (name :String, oid :int) :void
|
||||||
|
{
|
||||||
|
// dispatch an object added event
|
||||||
|
postEvent(new ObjectAddedEvent(_oid, name, oid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls by derived instances when an oid remover method was called.
|
||||||
|
*/
|
||||||
|
protected function requestOidRemove (name :String, oid :int) :void
|
||||||
|
{
|
||||||
|
// dispatch an object removed event
|
||||||
|
postEvent(new ObjectRemovedEvent(_oid, name, oid));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls by derived instances when a set adder method was called.
|
||||||
|
*/
|
||||||
|
protected function requestEntryAdd (name :String, entry :DSet.Entry) :void
|
||||||
|
{
|
||||||
|
// dispatch an entry added event
|
||||||
|
postEvent(new EntryAddedEvent(_oid, name, entry, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls by derived instances when a set remover method was called.
|
||||||
|
*/
|
||||||
|
protected function requestEntryRemove (name :String, key :Comparable) :void
|
||||||
|
{
|
||||||
|
// dispatch an entry removed event
|
||||||
|
postEvent(new EntryRemovedEvent(_oid, name, key, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls by derived instances when a set updater method was called.
|
||||||
|
*/
|
||||||
|
protected function requestEntryUpdate (name :String, entry :DSet.Entry)
|
||||||
|
{
|
||||||
|
// dispatch an entry updated event
|
||||||
|
postEvent(new EntryUpdatedEvent(_oid, name, entry, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
// documentation inherited from interface Streamable
|
// documentation inherited from interface Streamable
|
||||||
@@ -32,5 +177,11 @@ public class DObject extends EventDispatcher
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected var _oid :int;
|
protected var _oid :int;
|
||||||
|
|
||||||
|
/** A reference to our object manager. */
|
||||||
|
protected var _omgr :DObjectManager;
|
||||||
|
|
||||||
|
/** Our event listeners. */
|
||||||
|
protected var _listeners :ArrayCollection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distributed object manager is responsible for managing the creation
|
||||||
|
* and destruction of distributed objects and propagating dobj events to
|
||||||
|
* the appropriate subscribers. On the client, objects are managed as
|
||||||
|
* proxies to the real objects managed by the server, so attribute change
|
||||||
|
* requests are forwarded to the server and events coming down from the
|
||||||
|
* server are delivered to the local subscribers. On the server, the
|
||||||
|
* objects are managed directly.
|
||||||
|
*/
|
||||||
|
public interface DObjectManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns true if this distributed object manager is the
|
||||||
|
* authoritative manager for the specified distributed object, or fals
|
||||||
|
* if we are only providing a proxy to the object.
|
||||||
|
*/
|
||||||
|
function isManager (obj :DObject) :Boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a distributed object instance of the supplied class and
|
||||||
|
* notifies the specified subscriber when it becomes available. This
|
||||||
|
* is the proper mechanism for constructing a new distributed object
|
||||||
|
* as it is the only way in which it can be properly registered with
|
||||||
|
* the dobj system.
|
||||||
|
*
|
||||||
|
* @param dclass The class object of the derived class of
|
||||||
|
* <code>DObject</code> (or <code>DObject.class</code> itself) that
|
||||||
|
* should be instantiated.
|
||||||
|
* @param target The subscriber to be notified when the object is
|
||||||
|
* created and available, or if there was a problem creating the
|
||||||
|
* object.
|
||||||
|
*/
|
||||||
|
function createObject (dclass :Class, target :Subscriber) :void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the specified subscriber be subscribed to the object
|
||||||
|
* identified by the supplied object id. That subscriber will be
|
||||||
|
* notified when the object is available or if the subscription
|
||||||
|
* request failed.
|
||||||
|
*
|
||||||
|
* @param oid The object id of the distributed object to which
|
||||||
|
* subscription is desired.
|
||||||
|
* @param target The subscriber to be subscribed.
|
||||||
|
*
|
||||||
|
* @see Subscriber#objectAvailable
|
||||||
|
* @see Subscriber#requestFailed
|
||||||
|
*/
|
||||||
|
function subscribeToObject (oid :int, target :Subscriber) :void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the specified subscriber be unsubscribed from the
|
||||||
|
* object identified by the supplied object id.
|
||||||
|
*
|
||||||
|
* @param oid The object id of the distributed object from which
|
||||||
|
* unsubscription is desired.
|
||||||
|
* @param target The subscriber to be unsubscribed.
|
||||||
|
*/
|
||||||
|
function unsubscribeFromObject (oid :int, target :Subscriber) :void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the specified object be destroyed. Once destroyed an
|
||||||
|
* object is removed from the runtime system and may no longer have
|
||||||
|
* events dispatched on it.
|
||||||
|
*
|
||||||
|
* @param oid The object id of the distributed object to be destroyed.
|
||||||
|
*/
|
||||||
|
function destroyObject (oid :int) :void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Posts a distributed object event into the system. Instead of
|
||||||
|
* requesting the modification of a distributed object attribute by
|
||||||
|
* calling the setter for that attribute on the object itself, an
|
||||||
|
* <code>AttributeChangedEvent</code> can be constructed and posted
|
||||||
|
* directly. This is true for all event types and is useful for
|
||||||
|
* situations where one doesn't have access to the object in question,
|
||||||
|
* but needs to affect some event.
|
||||||
|
*
|
||||||
|
* <p> This event will be forwarded to the ultimate manager of the
|
||||||
|
* object (on the client, this means it will be forwarded to the
|
||||||
|
* server) where it will be checked for validity and then applied to
|
||||||
|
* the object and dispatched to all its subscribers.
|
||||||
|
*
|
||||||
|
* @param event The event to be dispatched.
|
||||||
|
*/
|
||||||
|
function postEvent (event :DEvent) :void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a distributed object removes its last subscriber, it will call
|
||||||
|
* this function to let the object manager know. The manager might
|
||||||
|
* then choose to flush this object from the system or unregister from
|
||||||
|
* some upstream manager whose object it was proxying, for example.
|
||||||
|
*/
|
||||||
|
function removedLastSubscriber (obj :DObject, deathWish :Boolean) :void;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
import com.threerings.io.Streamable;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The distributed set class provides a means by which an unordered set of
|
||||||
|
* objects can be maintained as a distributed object field. Entries can be
|
||||||
|
* added to and removed from the set, requests for which will generate
|
||||||
|
* events much like other distributed object fields.
|
||||||
|
*
|
||||||
|
* <p> Classes that wish to act as set entries must implement the {@link
|
||||||
|
* Entry} interface which extends {@link Streamable} and adds the
|
||||||
|
* requirement that the object provide a key which will be used to
|
||||||
|
* identify entry equality. Thus an entry is declared to be in a set of
|
||||||
|
* the object returned by that entry's {@link Entry#getKey} method is
|
||||||
|
* equal (using {@link Object#equals}) to the entry returned by the {@link
|
||||||
|
* Entry#getKey} method of some other entry in the set. Additionally, in
|
||||||
|
* the case of entry removal, only the key for the entry to be removed
|
||||||
|
* will be transmitted with the removal event to save network
|
||||||
|
* bandwidth. Lastly, the object returned by {@link Entry#getKey} must be
|
||||||
|
* a {@link Streamable} type.
|
||||||
|
*/
|
||||||
|
public class DSet
|
||||||
|
implements Streamable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the number of entries in this set.
|
||||||
|
*/
|
||||||
|
public function size () :int
|
||||||
|
{
|
||||||
|
return _entries.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the set contains an entry whose
|
||||||
|
* <code>getKey()</code> method returns a key that
|
||||||
|
* <code>equals()</code> the key returned by <code>getKey()</code> of
|
||||||
|
* the supplied entry. Returns false otherwise.
|
||||||
|
*/
|
||||||
|
public function contains (elem :DSetEntry) :Boolean
|
||||||
|
{
|
||||||
|
return containsKey(elem.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if an entry in the set has a key that
|
||||||
|
* <code>equals()</code> the supplied key. Returns false otherwise.
|
||||||
|
*/
|
||||||
|
public function containsKey (key :Comparable) :Boolean
|
||||||
|
{
|
||||||
|
return getByKey(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entry that matches (<code>getKey().equals(key)</code>)
|
||||||
|
* the specified key or null if no entry could be found that matches
|
||||||
|
* the key.
|
||||||
|
*/
|
||||||
|
public function getByKey (key :Comparable) :DSetEntry
|
||||||
|
{
|
||||||
|
// o(n) for now
|
||||||
|
// TODO
|
||||||
|
for (var ii :int = 0; ii < _entries.length; ii++) {
|
||||||
|
var entry :DSetEntry = _entries[ii];
|
||||||
|
if (key.compareTo(entry.getKey()) == 0) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator over the entries of this set. It does not
|
||||||
|
* support modification (nor iteration while modifications are being
|
||||||
|
* made to the set). It should not be kept around as it can quickly
|
||||||
|
* become out of date.
|
||||||
|
*
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
// public Iterator entries ()
|
||||||
|
// {
|
||||||
|
// return iterator();
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an iterator over the entries of this set. It does not
|
||||||
|
* support modification (nor iteration while modifications are being
|
||||||
|
* made to the set). It should not be kept around as it can quickly
|
||||||
|
* become out of date.
|
||||||
|
*/
|
||||||
|
// public Iterator iterator ()
|
||||||
|
// {
|
||||||
|
// // the crazy sanity checks
|
||||||
|
// if (_size < 0 ||_size > _entries.length ||
|
||||||
|
// (_size > 0 && _entries[_size-1] == null)) {
|
||||||
|
// Log.warning("DSet in a bad way [size=" + _size +
|
||||||
|
// ", entries=" + StringUtil.toString(_entries) + "].");
|
||||||
|
// Thread.dumpStack();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return new Iterator() {
|
||||||
|
// public boolean hasNext () {
|
||||||
|
// checkComodification();
|
||||||
|
// return (_index < _size);
|
||||||
|
// }
|
||||||
|
// public Object next () {
|
||||||
|
// checkComodification();
|
||||||
|
// return _entries[_index++];
|
||||||
|
// }
|
||||||
|
// public void remove () {
|
||||||
|
// throw new UnsupportedOperationException();
|
||||||
|
// }
|
||||||
|
// protected void checkComodification () {
|
||||||
|
// if (_modCount != _expectedModCount) {
|
||||||
|
// throw new ConcurrentModificationException();
|
||||||
|
// }
|
||||||
|
// if (_ssize != _size) {
|
||||||
|
// Log.warning("Size changed during iteration " +
|
||||||
|
// "[ssize=" + _ssize + ", nsize=" + _size +
|
||||||
|
// ", entsries=" + StringUtil.toString(_entries) +
|
||||||
|
// "].");
|
||||||
|
// Thread.dumpStack();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// protected int _index = 0;
|
||||||
|
// protected int _ssize = _size;
|
||||||
|
// protected int _expectedModCount = _modCount;
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the elements of this distributed set into the supplied
|
||||||
|
* array. If the array is not large enough to hold all of the
|
||||||
|
* elements, as many as fit into the array will be copied. If the
|
||||||
|
* <code>array</code> argument is null, an object array of sufficient
|
||||||
|
* size to contain all of the elements of this set will be created and
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
public function toArray () :Array
|
||||||
|
{
|
||||||
|
return _entries.concat(null); // makes a copy
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the specified entry to the set. This should not be called
|
||||||
|
* directly, instead the associated <code>addTo{Set}()</code> method
|
||||||
|
* should be called on the distributed object that contains the set in
|
||||||
|
* question.
|
||||||
|
*
|
||||||
|
* @return true if the entry was added, false if it was already in
|
||||||
|
* the set.
|
||||||
|
*/
|
||||||
|
protected function add (elem :DSetEntry) :Boolean
|
||||||
|
{
|
||||||
|
if (contains(elem)) {
|
||||||
|
trace("Refusing to add duplicate entry [set=" + this +
|
||||||
|
", entry=" + elem + "].");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_entries.push(elem);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified entry from the set. This should not be called
|
||||||
|
* directly, instead the associated <code>removeFrom{Set}()</code>
|
||||||
|
* method should be called on the distributed object that contains the
|
||||||
|
* set in question.
|
||||||
|
*
|
||||||
|
* @return true if the entry was removed, false if it was not in the
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
protected function remove (elem :DSetEntry) :Boolean
|
||||||
|
{
|
||||||
|
return (null != removeKey(elem.getKey()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes from the set the entry whose key matches the supplied
|
||||||
|
* key. This should not be called directly, instead the associated
|
||||||
|
* <code>removeFrom{Set}()</code> method should be called on the
|
||||||
|
* distributed object that contains the set in question.
|
||||||
|
*
|
||||||
|
* @return the old matching entry if found and removed, null if not
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
protected function removeKey (key :Comparable) :DSetEntry
|
||||||
|
{
|
||||||
|
// o(n) for now
|
||||||
|
// TODO
|
||||||
|
for (var ii :int = 0; ii < _entries.length; ii++) {
|
||||||
|
var entry :DSetEntry = _entries[ii];
|
||||||
|
if (key.compareTo(entry.getKey()) == 0) {
|
||||||
|
_entries.splice(ii, 1);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the specified entry by locating an entry whose key matches
|
||||||
|
* the key of the supplied entry and overwriting it. This should not
|
||||||
|
* be called directly, instead the associated
|
||||||
|
* <code>update{Set}()</code> method should be called on the
|
||||||
|
* distributed object that contains the set in question.
|
||||||
|
*
|
||||||
|
* @return the old entry that was replaced, or null if it was not
|
||||||
|
* found (in which case nothing is updated).
|
||||||
|
*/
|
||||||
|
protected function update (elem :DSetEntry) :DSetEntry
|
||||||
|
{
|
||||||
|
var key :Comparable = elem.getKey();
|
||||||
|
for (var ii :int = 0; ii < _entries.length; ii++) {
|
||||||
|
var entry :DSetEntry = _entries[ii];
|
||||||
|
if (key.compareTo(entry.getKey()) == 0) {
|
||||||
|
_entries[ii] = elem;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a string representation of this set instance.
|
||||||
|
*/
|
||||||
|
public override function toString () :String
|
||||||
|
{
|
||||||
|
StringBuilder buf = new StringBuilder("(");
|
||||||
|
buf.append(_entries.toString());
|
||||||
|
buf.append(")");
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface Streamable
|
||||||
|
public function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
trace("TODO");
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface Streamable
|
||||||
|
public function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
_entries = ins.readField(Array);
|
||||||
|
_entries.length = ins.readInt(); // then read the length and limit it
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The entries of the set (in a sparse array). */
|
||||||
|
protected var _entries :Array;
|
||||||
|
|
||||||
|
// /** Used to check for concurrent modification. */
|
||||||
|
// protected transient int _modCount;
|
||||||
|
//
|
||||||
|
// /** The default capacity of a set instance. */
|
||||||
|
// protected static final int INITIAL_CAPACITY = 2;
|
||||||
|
//
|
||||||
|
// /** Used for lookups and to keep the set contents sorted on
|
||||||
|
// * insertions. */
|
||||||
|
// protected static Comparator ENTRY_COMP = new Comparator() {
|
||||||
|
// public int compare (Object o1, Object o2) {
|
||||||
|
// Comparable c1 = (o1 instanceof Entry) ?
|
||||||
|
// ((Entry)o1).getKey() : (Comparable)o1;
|
||||||
|
// Comparable c2 = (o2 instanceof Entry) ?
|
||||||
|
// ((Entry)o2).getKey() : (Comparable)o2;
|
||||||
|
// return c1.compareTo(c2);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import com.threerings.io.Streamable;
|
||||||
|
|
||||||
|
public interface DSetEntry extends Streamable
|
||||||
|
{
|
||||||
|
function getKey () :Comparable;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An element updated event is dispatched when an element of an array
|
||||||
|
* field in a distributed object is updated. It can also be constructed to
|
||||||
|
* request the update of an entry and posted to the dobjmgr.
|
||||||
|
*
|
||||||
|
* @see DObjectManager#postEvent
|
||||||
|
*/
|
||||||
|
public class ElementUpdatedEvent extends NamedEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new element updated event on the specified target
|
||||||
|
* object with the supplied attribute name, element and index.
|
||||||
|
*
|
||||||
|
* @param targetOid the object id of the object whose attribute has
|
||||||
|
* changed.
|
||||||
|
* @param name the name of the attribute (data member) for which an
|
||||||
|
* element has changed.
|
||||||
|
* @param value the new value of the element (in the case of primitive
|
||||||
|
* types, the reflection-defined object-alternative is used).
|
||||||
|
* @param oldValue the previous value of the element (in the case of
|
||||||
|
* primitive types, the reflection-defined object-alternative is
|
||||||
|
* used).
|
||||||
|
* @param index the index in the array of the updated element.
|
||||||
|
*/
|
||||||
|
public ElementUpdatedEvent (
|
||||||
|
targetOid :int, name :String, value :*, oldValue :*, index :int)
|
||||||
|
{
|
||||||
|
super(targetOid, name);
|
||||||
|
_value = value;
|
||||||
|
_oldValue = oldValue;
|
||||||
|
_index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the new value of the element.
|
||||||
|
*/
|
||||||
|
public function getValue () :*
|
||||||
|
{
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value of the element prior to the application of this
|
||||||
|
* event.
|
||||||
|
*/
|
||||||
|
public function getOldValue () :*
|
||||||
|
{
|
||||||
|
return _oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of the element.
|
||||||
|
*/
|
||||||
|
public function getIndex () :int
|
||||||
|
{
|
||||||
|
return _index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies this element update to the object.
|
||||||
|
*/
|
||||||
|
public override function applyToObject (target :DObject) :Boolean
|
||||||
|
//throws ObjectAccessException
|
||||||
|
{
|
||||||
|
if (_oldValue === UNSET_OLD_ENTRY) {
|
||||||
|
_oldValue = target[_name][_index];
|
||||||
|
}
|
||||||
|
target[_name][_index] = _value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public override function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
super.writeObject(out);
|
||||||
|
out.writeField(_value);
|
||||||
|
out.writeInt(_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public override function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
super.readObject(ins);
|
||||||
|
_value = ins.readField(Object);
|
||||||
|
_index = ins.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function notifyListener (listener :*) :void
|
||||||
|
{
|
||||||
|
if (listener is ElementUpdateListener) {
|
||||||
|
listener.elementUpdated(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function toString (buf :StringBuilder) :void
|
||||||
|
{
|
||||||
|
buf.append("UPDATE:");
|
||||||
|
super.toString(buf);
|
||||||
|
buf.append(", value=", _value);
|
||||||
|
buf.append(", index=", _index);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected var _value :*;
|
||||||
|
protected var _index :int;
|
||||||
|
protected var _oldValue :* = UNSET_OLD_ENTRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entry added event is dispatched when an entry is added to a {@link
|
||||||
|
* DSet} attribute of a distributed entry. It can also be constructed to
|
||||||
|
* request the addition of an entry to a set and posted to the dobjmgr.
|
||||||
|
*
|
||||||
|
* @see DObjectManager#postEvent
|
||||||
|
*/
|
||||||
|
public class EntryAddedEvent extends NamedEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new entry added event on the specified target object
|
||||||
|
* with the supplied set attribute name and entry to add.
|
||||||
|
*
|
||||||
|
* @param targetOid the object id of the object to whose set we will
|
||||||
|
* add an entry.
|
||||||
|
* @param name the name of the attribute to which to add the specified
|
||||||
|
* entry.
|
||||||
|
* @param entry the entry to add to the set attribute.
|
||||||
|
*/
|
||||||
|
public function EntryAddedEvent (
|
||||||
|
targetOid :int, name :String, entry :DSetEntry)
|
||||||
|
{
|
||||||
|
super(targetOid, name);
|
||||||
|
_entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entry that has been added.
|
||||||
|
*/
|
||||||
|
public function getEntry () :DSetEntry
|
||||||
|
{
|
||||||
|
return _entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies this event to the object.
|
||||||
|
*/
|
||||||
|
public override function applyToObject (target :DObject) :Boolean
|
||||||
|
//throws ObjectAccessException
|
||||||
|
{
|
||||||
|
var added :Boolean = target[_name].add(_entry);
|
||||||
|
if (!added) {
|
||||||
|
trace("Duplicate entry found [event=" + this + "].");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function notifyListener (listener :*) :void
|
||||||
|
{
|
||||||
|
if (listener is SetListener) {
|
||||||
|
listener.entryAdded(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function toString (StringBuilder buf)
|
||||||
|
{
|
||||||
|
buf.append("ELADD:");
|
||||||
|
super.toString(buf);
|
||||||
|
buf.append(", entry=", _entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
super.writeObject(out);
|
||||||
|
out.writeField(_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
super.readObject(ins);
|
||||||
|
_entry = ins.readField(DSetEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected var _entry :DSetEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entry removed event is dispatched when an entry is removed from a
|
||||||
|
* {@link DSet} attribute of a distributed object. It can also be
|
||||||
|
* constructed to request the removal of an entry from a set and posted to
|
||||||
|
* the dobjmgr.
|
||||||
|
*
|
||||||
|
* @see DObjectManager#postEvent
|
||||||
|
*/
|
||||||
|
public class EntryRemovedEvent extends NamedEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new entry removed event on the specified target object
|
||||||
|
* with the supplied set attribute name and entry key to remove.
|
||||||
|
*
|
||||||
|
* @param targetOid the object id of the object from whose set we will
|
||||||
|
* remove an entry.
|
||||||
|
* @param name the name of the attribute from which to remove the
|
||||||
|
* specified entry.
|
||||||
|
* @param key the entry key that identifies the entry to remove.
|
||||||
|
* @param oldEntry the previous value of the entry.
|
||||||
|
*/
|
||||||
|
public function EntryRemovedEvent (
|
||||||
|
targetOid :int, name :String, key :Comparable, oldEntry :DSetEntry)
|
||||||
|
{
|
||||||
|
super(targetOid, name);
|
||||||
|
_key = key;
|
||||||
|
_oldEntry = oldEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key that identifies the entry that has been removed.
|
||||||
|
*/
|
||||||
|
public function getKey () :Comparable
|
||||||
|
{
|
||||||
|
return _key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entry that was in the set prior to being updated.
|
||||||
|
*/
|
||||||
|
public function getOldEntry () :DSetEntry
|
||||||
|
{
|
||||||
|
return _oldEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies this event to the object.
|
||||||
|
*/
|
||||||
|
public override function applyToObject (target :DObject) :Boolean
|
||||||
|
//throws ObjectAccessException
|
||||||
|
{
|
||||||
|
if (_oldEntry == UNSET_OLD_ENTRY) {
|
||||||
|
var dset :DSet = target[_name];
|
||||||
|
// remove, fetch the previous value for interested callers
|
||||||
|
_oldEntry = dset.removeKey(_key);
|
||||||
|
if (_oldEntry == null) {
|
||||||
|
// complain if there was actually nothing there
|
||||||
|
trace("No matching entry to remove [key=" + _key +
|
||||||
|
", set=" + set + "].");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function notifyListener (listener :*) :void
|
||||||
|
{
|
||||||
|
if (listener is SetListener) {
|
||||||
|
listener.entryRemoved(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function toString (buf :StringBuilder)
|
||||||
|
{
|
||||||
|
buf.append("ELREM:");
|
||||||
|
super.toString(buf);
|
||||||
|
buf.append(", key=", _key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
super.writeObject(out);
|
||||||
|
out.writeField(_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
super.readObject(ins);
|
||||||
|
_key = ins.readField(Comparable);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected var _key :Comparable;
|
||||||
|
protected var _oldEntry :DSetEntry = UNSET_OLD_ENTRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entry updated event is dispatched when an entry of a {@link DSet} is
|
||||||
|
* updated. It can also be constructed to request the update of an entry
|
||||||
|
* and posted to the dobjmgr.
|
||||||
|
*
|
||||||
|
* @see DObjectManager#postEvent
|
||||||
|
*/
|
||||||
|
public class EntryUpdatedEvent extends NamedEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new entry updated event on the specified target object
|
||||||
|
* for the specified set name and with the supplied updated entry.
|
||||||
|
*
|
||||||
|
* @param targetOid the object id of the object to whose set we will
|
||||||
|
* add an entry.
|
||||||
|
* @param name the name of the attribute in which to update the
|
||||||
|
* specified entry.
|
||||||
|
* @param entry the entry to update.
|
||||||
|
* @param oldEntry the previous value of the entry.
|
||||||
|
*/
|
||||||
|
public function EntryUpdatedEvent (
|
||||||
|
targetOid :int, name :String, entry :DSetEntry, oldEntry :DSetEntry)
|
||||||
|
{
|
||||||
|
super(targetOid, name);
|
||||||
|
_entry = entry;
|
||||||
|
_oldEntry = oldEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entry that has been updated.
|
||||||
|
*/
|
||||||
|
public function getEntry () :DSetEntry
|
||||||
|
{
|
||||||
|
return _entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entry that was in the set prior to being updated.
|
||||||
|
*/
|
||||||
|
public function getOldEntry ():DSetEntry
|
||||||
|
{
|
||||||
|
return _oldEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies this event to the object.
|
||||||
|
*/
|
||||||
|
public override function applyToObject (target :DObject) :Boolean
|
||||||
|
//throws ObjectAccessException
|
||||||
|
{
|
||||||
|
// only apply the change if we haven't already
|
||||||
|
if (_oldEntry == UNSET_OLD_ENTRY) {
|
||||||
|
var dset :DSet = target[_name];
|
||||||
|
// fetch the previous value for interested callers
|
||||||
|
_oldEntry = dset.update(_entry);
|
||||||
|
if (_oldEntry == null) {
|
||||||
|
// complain if we didn't update anything
|
||||||
|
trace("No matching entry to update [entry=" + this +
|
||||||
|
", set=" + set + "].");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function notifyListener (listener :*) :void
|
||||||
|
{
|
||||||
|
if (listener is SetListener) {
|
||||||
|
listener.entryUpdated(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function toString (buf :StringBuilder) :void
|
||||||
|
{
|
||||||
|
buf.append("ELUPD:");
|
||||||
|
super.toString(buf);
|
||||||
|
buf.append(", entry=", _entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
super.writeObject(out);
|
||||||
|
out.writeField(_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
super.readObject(ins);
|
||||||
|
_entry = ins.readField(DSetEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected var _entry :DSetEntry;
|
||||||
|
protected var _oldEntry :DSetEntry = UNSET_OLD_ENTRY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message event is used to dispatch a message to all subscribers of a
|
||||||
|
* distributed object without actually changing any of the fields of the
|
||||||
|
* object. A message has a name, by which different subscribers of the
|
||||||
|
* same object can distinguish their different messages, and an array of
|
||||||
|
* arguments by which any contents of the message can be delivered.
|
||||||
|
*
|
||||||
|
* @see DObjectManager#postEvent
|
||||||
|
*/
|
||||||
|
public class MessageEvent extends NamedEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new message event on the specified target object with
|
||||||
|
* the supplied name and arguments.
|
||||||
|
*
|
||||||
|
* @param targetOid the object id of the object whose attribute has
|
||||||
|
* changed.
|
||||||
|
* @param name the name of the message event.
|
||||||
|
* @param args the arguments for this message. This array should
|
||||||
|
* contain only values of valid distributed object types.
|
||||||
|
*/
|
||||||
|
public function MessageEvent (targetOid :int, name :String, args :Array)
|
||||||
|
{
|
||||||
|
super(targetOid, name);
|
||||||
|
_args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the arguments to this message.
|
||||||
|
*/
|
||||||
|
public function getArgs () :Array
|
||||||
|
{
|
||||||
|
return _args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces the arguments associated with this message event.
|
||||||
|
* <em>Note:</em> this should only be called on events that have not
|
||||||
|
* yet been dispatched into the distributed object system.
|
||||||
|
*/
|
||||||
|
public function setArgs (args :Array) :void
|
||||||
|
{
|
||||||
|
_args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies this attribute change to the object.
|
||||||
|
*/
|
||||||
|
public override function applyToObject (target :DObject) :Boolean
|
||||||
|
//throws ObjectAccessException
|
||||||
|
{
|
||||||
|
// nothing to do here
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function notifyListener (listener :*) :void
|
||||||
|
{
|
||||||
|
if (listener is MessageListener) {
|
||||||
|
listener.messageReceived(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function toString (buf :StringBuilder) :void
|
||||||
|
{
|
||||||
|
buf.append("MSG:");
|
||||||
|
super.toString(buf);
|
||||||
|
buf.append(", args=", _args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected var _args :Array;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common parent class for all events that are associated with a name
|
||||||
|
* (in some cases a field name, in other cases just an identifying name).
|
||||||
|
*/
|
||||||
|
public class NamedEvent extends DEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new named event for the specified target object with
|
||||||
|
* the supplied attribute name.
|
||||||
|
*
|
||||||
|
* @param targetOid the object id of the object in question.
|
||||||
|
* @param name the name associated with this event.
|
||||||
|
*/
|
||||||
|
public NamedEvent (targetOid :int, name :String)
|
||||||
|
{
|
||||||
|
super(targetOid);
|
||||||
|
_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the attribute to which this event pertains.
|
||||||
|
*/
|
||||||
|
public function getName () :String
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override function toString (buf :StringBuilder) :void
|
||||||
|
{
|
||||||
|
super.toString(buf);
|
||||||
|
buf.append(", name=", _name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
super.writeObject(out);
|
||||||
|
out.writeField(_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
super.readObject(ins);
|
||||||
|
_name = ins.readField(String);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The name of the event. */
|
||||||
|
protected var _name :String;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import flash.util.StringBuilder;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object added event is dispatched when an object is added to an
|
||||||
|
* <code>OidList</code> attribute of a distributed object. It can also be
|
||||||
|
* constructed to request the addition of an oid to an
|
||||||
|
* <code>OidList</code> attribute of an object and posted to the dobjmgr.
|
||||||
|
*
|
||||||
|
* @see DObjectManager#postEvent
|
||||||
|
*/
|
||||||
|
public class ObjectAddedEvent extends NamedEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new object added event on the specified target object
|
||||||
|
* with the supplied oid list attribute name and object id to add.
|
||||||
|
*
|
||||||
|
* @param targetOid the object id of the object to whose oid list we
|
||||||
|
* will add an oid.
|
||||||
|
* @param name the name of the attribute (data member) to which to add
|
||||||
|
* the specified oid.
|
||||||
|
* @param oid the oid to add to the oid list attribute.
|
||||||
|
*/
|
||||||
|
public function ObjectAddedEvent (targetOid :int, name :String, oid :int)
|
||||||
|
{
|
||||||
|
super(targetOid, name);
|
||||||
|
_oid = oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the oid that has been added.
|
||||||
|
*/
|
||||||
|
public function getOid () :int
|
||||||
|
{
|
||||||
|
return _oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies this event to the object.
|
||||||
|
*/
|
||||||
|
public override function applyToObject (target :DObject) :void
|
||||||
|
//throws ObjectAccessException
|
||||||
|
{
|
||||||
|
var list :OidList = target[_name];
|
||||||
|
list.add(_oid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function notifyListener (listener :*) :void
|
||||||
|
{
|
||||||
|
if (listener is OidListListener) {
|
||||||
|
listener.objectAdded(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
super.writeObject(out);
|
||||||
|
out.writeInt(_oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
super.readObject(ins);
|
||||||
|
_oid = ins.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected override function toString (buf :StringBuilder) :void
|
||||||
|
{
|
||||||
|
buf.append("OBJADD:");
|
||||||
|
super.toString(buf);
|
||||||
|
buf.append(", oid=", _oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected var _oid :int;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
//
|
||||||
|
// $Id: ObjectRemovedEvent.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.dobj;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object removed event is dispatched when an object is removed from an
|
||||||
|
* <code>OidList</code> attribute of a distributed object. It can also be
|
||||||
|
* constructed to request the removal of an oid from an
|
||||||
|
* <code>OidList</code> attribute of an object and posted to the dobjmgr.
|
||||||
|
*
|
||||||
|
* @see DObjectManager#postEvent
|
||||||
|
*/
|
||||||
|
public class ObjectRemovedEvent extends NamedEvent
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Constructs a new object removed event on the specified target
|
||||||
|
* object with the supplied oid list attribute name and object id to
|
||||||
|
* remove.
|
||||||
|
*
|
||||||
|
* @param targetOid the object id of the object from whose oid list we
|
||||||
|
* will remove an oid.
|
||||||
|
* @param name the name of the attribute (data member) from which to
|
||||||
|
* remove the specified oid.
|
||||||
|
* @param oid the oid to remove from the oid list attribute.
|
||||||
|
*/
|
||||||
|
public ObjectRemovedEvent (int targetOid, String name, int oid)
|
||||||
|
{
|
||||||
|
super(targetOid, name);
|
||||||
|
_oid = oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a blank instance of this event in preparation for
|
||||||
|
* unserialization from the network.
|
||||||
|
*/
|
||||||
|
public ObjectRemovedEvent ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the oid that has been removed.
|
||||||
|
*/
|
||||||
|
public int getOid ()
|
||||||
|
{
|
||||||
|
return _oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies this event to the object.
|
||||||
|
*/
|
||||||
|
public boolean applyToObject (DObject target)
|
||||||
|
throws ObjectAccessException
|
||||||
|
{
|
||||||
|
OidList list = (OidList)target.getAttribute(_name);
|
||||||
|
list.remove(_oid);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected void notifyListener (Object listener)
|
||||||
|
{
|
||||||
|
if (listener is OidListListener) {
|
||||||
|
((OidListListener)listener).objectRemoved(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
protected void toString (StringBuffer buf)
|
||||||
|
{
|
||||||
|
buf.append("OBJREM:");
|
||||||
|
super.toString(buf);
|
||||||
|
buf.append(", oid=").append(_oid);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int _oid;
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.threerings.presents.dobj {
|
||||||
|
|
||||||
|
import com.threerings.io.Streamable;
|
||||||
|
|
||||||
|
import com.threerings.io.ObjectInputStream;
|
||||||
|
import com.threerings.io.ObjectOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An oid list is used to store lists of object ids. The list will not
|
||||||
|
* allow duplicate ids. This class is not synchronized, with the
|
||||||
|
* expectation that all modifications of instances will take place on the
|
||||||
|
* dobjmgr thread.
|
||||||
|
*/
|
||||||
|
public class OidList
|
||||||
|
implements Streamable
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Creates an empty oidlist.
|
||||||
|
*/
|
||||||
|
public function OidList ()
|
||||||
|
{
|
||||||
|
_oids = new Array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of object ids in the list.
|
||||||
|
*/
|
||||||
|
public function size () :int
|
||||||
|
{
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the specified object id to the list if it is not already
|
||||||
|
* there.
|
||||||
|
*
|
||||||
|
* @return true if the object was added, false if it was already in
|
||||||
|
* the list.
|
||||||
|
*/
|
||||||
|
public function add (oid :int) :Boolean
|
||||||
|
{
|
||||||
|
// check for existence
|
||||||
|
for (int i = 0; i < _size; i++) {
|
||||||
|
if (_oids[i] == oid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make room if necessary
|
||||||
|
if (_size+1 >= _oids.length) {
|
||||||
|
expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the oid
|
||||||
|
_oids[_size++] = oid;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified oid from the list.
|
||||||
|
*
|
||||||
|
* @return true if the oid was in the list and was removed, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public boolean remove (int oid)
|
||||||
|
{
|
||||||
|
// scan for the oid in question
|
||||||
|
for (int i = 0; i < _size; i++) {
|
||||||
|
if (_oids[i] == oid) {
|
||||||
|
// shift the rest of the list back one
|
||||||
|
System.arraycopy(_oids, i+1, _oids, i, --_size-i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the specified oid is in the list, false if not.
|
||||||
|
*/
|
||||||
|
public boolean contains (int oid)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _size; i++) {
|
||||||
|
if (_oids[i] == oid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the object id at the specified index. This does no boundary
|
||||||
|
* checking.
|
||||||
|
*/
|
||||||
|
public function getAt (index :int) :int
|
||||||
|
{
|
||||||
|
return _oids[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface Streamable
|
||||||
|
public function writeObject (out :ObjectOutputStream) :void
|
||||||
|
{
|
||||||
|
trace("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
// documentation inherited from interface Streamable
|
||||||
|
public function readObject (ins :ObjectInputStream) :void
|
||||||
|
{
|
||||||
|
// TODO: this is some custom shit. We need to work out array streaming
|
||||||
|
_oids = new Array();
|
||||||
|
var ecount :int = ins.readInt();
|
||||||
|
for (var ii :int = 0; ii < ecount; ii++) {
|
||||||
|
_oids.push(ins.readInt());
|
||||||
|
}
|
||||||
|
_oids.length = ins.readInt(); // then, limit the length to the size
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override function toString () :String
|
||||||
|
{
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
buf.append("{");
|
||||||
|
buf.append(_oids.toString());
|
||||||
|
buf.append("}");
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private var _oids :Array;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user