diff --git a/src/java/com/threerings/presents/client/Client.java b/src/java/com/threerings/presents/client/Client.java index 9fb8dd5b1..c9bd7ba62 100644 --- a/src/java/com/threerings/presents/client/Client.java +++ b/src/java/com/threerings/presents/client/Client.java @@ -31,6 +31,8 @@ import com.samskivert.util.RunQueue; import com.threerings.presents.Log; import com.threerings.presents.data.ClientObject; import com.threerings.presents.data.InvocationCodes; +import com.threerings.presents.dobj.DEvent; +import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.DObjectManager; import com.threerings.presents.net.AuthResponseData; import com.threerings.presents.net.BootstrapData; @@ -483,6 +485,15 @@ public class Client // before turning the client loose to do things like request invocation services } + /** + * If this client is being used to proxy events from another server, this method can be + * overridden to adjust the event in any way needed prior to dispatching the event. + */ + protected void adjustForProxy (DObject target, DEvent event) + { + // nothing by default + } + /** * Called every five seconds; ensures that we ping the server if we haven't communicated in a * long while and periodically resyncs the client and server clock deltas. diff --git a/src/java/com/threerings/presents/client/ClientDObjectMgr.java b/src/java/com/threerings/presents/client/ClientDObjectMgr.java index 90ab95266..dc54b0e8b 100644 --- a/src/java/com/threerings/presents/client/ClientDObjectMgr.java +++ b/src/java/com/threerings/presents/client/ClientDObjectMgr.java @@ -159,7 +159,7 @@ public class ClientDObjectMgr } else if (obj instanceof EventNotification) { DEvent evt = ((EventNotification)obj).getEvent(); // Log.info("Dispatch event: " + evt); - dispatchEvent(evt); + dispatchEvent(evt, true); } else if (obj instanceof ObjectResponse) { registerObjectAndNotify((ObjectResponse)obj); @@ -201,18 +201,8 @@ public class ClientDObjectMgr * Called when a new event arrives from the server that should be dispatched to subscribers * here on the client. */ - protected void dispatchEvent (DEvent event) + protected void dispatchEvent (DEvent event, boolean notifyProxies) { - // if this is a compound event, we need to process its contained events in order - if (event instanceof CompoundEvent) { - List events = ((CompoundEvent)event).getEvents(); - int ecount = events.size(); - for (int i = 0; i < ecount; i++) { - dispatchEvent(events.get(i)); - } - return; - } - // look up the object on which we're dispatching this event int toid = event.getTargetOid(); DObject target = _ocache.get(toid); @@ -223,18 +213,32 @@ public class ClientDObjectMgr return; } - // because we might be acting as a proxy between servers, we rewrite the event's target oid - // using the oid currently configured on the distributed object (we will have it mapped in - // our remote server's oid space, but it may have been remapped into the oid space of the - // local server) - event.setTargetOid(target.getOid()); + // because we might be acting as a proxy between servers, we may need to fiddle with this + // event before we dispatch it + _client.adjustForProxy(target, event); + + // if this is a compound event, we need to process its contained events in order + if (event instanceof CompoundEvent) { + // notify our proxy subscribers in one fell swoop + target.notifyProxies(event); + + // now break the event up and dispatch each event individually + List events = ((CompoundEvent)event).getEvents(); + int ecount = events.size(); + for (int i = 0; i < ecount; i++) { + dispatchEvent(events.get(i), false); + } + return; + } try { // apply the event to the object boolean notify = event.applyToObject(target); - // forward to any proxies - target.notifyProxies(event); + // forward to any proxies (or not if we're dispatching part of a compound event) + if (notifyProxies) { + target.notifyProxies(event); + } // if this is an object destroyed event, we need to remove the object from our table if (event instanceof ObjectDestroyedEvent) { diff --git a/src/java/com/threerings/presents/peer/server/PeerManager.java b/src/java/com/threerings/presents/peer/server/PeerManager.java index f57d91d3d..4537f326b 100644 --- a/src/java/com/threerings/presents/peer/server/PeerManager.java +++ b/src/java/com/threerings/presents/peer/server/PeerManager.java @@ -47,6 +47,7 @@ import com.threerings.presents.client.ClientObserver; import com.threerings.presents.data.ClientObject; import com.threerings.presents.dobj.AttributeChangeListener; import com.threerings.presents.dobj.AttributeChangedEvent; +import com.threerings.presents.dobj.DEvent; import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.EntryAddedEvent; import com.threerings.presents.dobj.EntryRemovedEvent; @@ -702,7 +703,18 @@ public class PeerManager public PeerNode (NodeRecord record) { _record = record; - _client = new Client(null, PresentsServer.omgr); + _client = new Client(null, PresentsServer.omgr) { + protected void adjustForProxy (DObject target, DEvent event) { + super.adjustForProxy(target, event); + // rewrite the event's target oid using the oid currently configured on the + // distributed object (we will have it mapped in our remote server's oid space, + // but it may have been remapped into the oid space of the local server) + event.setTargetOid(target.getOid()); + // assign an eventId to this event so that our stale event detection code can + // properly deal with it + event.eventId = PresentsServer.omgr.getNextEventId(true); + } + }; _client.addClientObserver(this); }