From 04b5bfba8c0c21c8041f1d07f6b5174c1d38fe44 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Mon, 20 Aug 2001 20:54:57 +0000 Subject: [PATCH] Initial revision of occupant management services. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@276 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../crowd/client/OccupantManager.java | 171 ++++++++++++++++++ .../crowd/client/OccupantObserver.java | 29 +++ .../threerings/crowd/data/OccupantInfo.java | 18 +- .../crowd/server/LocationProvider.java | 19 +- .../threerings/crowd/server/PlaceManager.java | 11 +- 5 files changed, 236 insertions(+), 12 deletions(-) create mode 100644 src/java/com/threerings/crowd/client/OccupantManager.java create mode 100644 src/java/com/threerings/crowd/client/OccupantObserver.java diff --git a/src/java/com/threerings/crowd/client/OccupantManager.java b/src/java/com/threerings/crowd/client/OccupantManager.java new file mode 100644 index 000000000..424fafb82 --- /dev/null +++ b/src/java/com/threerings/crowd/client/OccupantManager.java @@ -0,0 +1,171 @@ +// +// $Id: OccupantManager.java,v 1.1 2001/08/20 20:54:56 mdb Exp $ + +package com.threerings.cocktail.party.client; + +import java.util.ArrayList; + +import com.threerings.cocktail.cher.dobj.*; +import com.threerings.cocktail.cher.util.IntMap; + +import com.threerings.cocktail.party.Log; +import com.threerings.cocktail.party.data.OccupantInfo; +import com.threerings.cocktail.party.data.PlaceObject; +import com.threerings.cocktail.party.util.PartyContext; + +/** + * The occupant manager listens for occupants of places to enter and exit, + * and dispatches notices to interested parties about these events. + * + *

It will eventually provide a framework for keeping track of + * occupant information in a network efficient manner. The idea being that + * we want to store as little information about occupants as possible in + * the place object (probably just body oid and username), but upon + * entering a place, this will be all we know about the occupants. We then + * dispatch a request to get information about all of the occupants in the + * room (things like avatar information for a graphical display or perhaps + * their ratings in the game that is associated with a place for a gaming + * site) which we then pass on to the occupant observers when it becomes + * available. + * + *

This information would be cached and we could return cached + * information for occupants for which we have cached info. We will + * probably want to still make a request for the occupant info so that we + * can update non-static occupant data rather than permanently using + * what's in the cache. + */ +public class OccupantManager + implements LocationObserver, Subscriber +{ + /** + * Constructs a new occupant manager with the supplied context. + */ + public OccupantManager (PartyContext ctx) + { + // register ourselves as a location observer + ctx.getLocationManager().addLocationObserver(this); + } + + /** + * Adds the specified occupant observer to the list. + */ + public void addOccupantObserver (OccupantObserver obs) + { + _observers.add(obs); + } + + /** + * Removes the specified occupant observer from the list. + */ + public void removeOccupantObserver (OccupantObserver obs) + { + _observers.remove(obs); + } + + // inherit documentation + public boolean locationMayChange (int placeId) + { + // we've got no opinion + return true; + } + + // inherit documentation + public void locationDidChange (PlaceObject place) + { + // unsubscribe from the old place object if there was one + if (_place != null) { + _place.removeSubscriber(this); + } + + // subscribe to the new one + _place = place; + _place.addSubscriber(this); + } + + // inherit documentation + public void locationChangeFailed (int placeId, String reason) + { + // nothing to do here either + } + + // inherit documentation + public void objectAvailable (DObject object) + { + // nothing doing + } + + // inherit documentation + public void requestFailed (int oid, ObjectAccessException cause) + { + // nothing doing + } + + // inherit documentation + public boolean handleEvent (DEvent event, DObject target) + { + // we care about occupant added and removed events only + if (event instanceof ObjectAddedEvent) { + ObjectAddedEvent oe = (ObjectAddedEvent)event; + if (oe.getName().equals(PlaceObject.OCCUPANTS)) { + handleOccupantAdded(oe.getOid()); + } + + } else if (event instanceof ObjectRemovedEvent) { + ObjectRemovedEvent oe = (ObjectRemovedEvent)event; + if (oe.getName().equals(PlaceObject.OCCUPANTS)) { + handleOccupantRemoved(oe.getOid()); + } + } + + return true; + } + + /** + * Deals with all of the processing when an occupant shows up. + */ + protected void handleOccupantAdded (int bodyOid) + { + Object key = new Integer(bodyOid); + + // get the occupant info from the place object + OccupantInfo info = (OccupantInfo)_place.occupantInfo.get(key); + if (info == null) { + Log.warning("Occupant entered but we have no info for them! " + + "[boid=" + bodyOid + ", place=" + _place + "]."); + return; + } + + // put the info in our cache for use when we get a left event + _ocache.put(bodyOid, info); + + // now let the occupant observers know what's up + for (int i = 0; i < _observers.size(); i++) { + OccupantObserver obs = (OccupantObserver)_observers.get(i); + obs.occupantEntered(info); + } + } + + /** + * Deals with all of the processing when an occupant leaves. + */ + protected void handleOccupantRemoved (int bodyOid) + { + // see if we have an occupant object for this body + OccupantInfo info = (OccupantInfo)_ocache.get(bodyOid); + if (info == null) { + Log.warning("Occupant removed but no cached info for them? " + + "[boid=" + bodyOid + ", place=" + _place + "]."); + return; + } + + // let the occupant observers know what's up + for (int i = 0; i < _observers.size(); i++) { + OccupantObserver obs = (OccupantObserver)_observers.get(i); + obs.occupantEntered(info); + } + } + + protected ArrayList _observers = new ArrayList(); + protected PlaceObject _place; + protected IntMap _ocache = new IntMap(); +} diff --git a/src/java/com/threerings/crowd/client/OccupantObserver.java b/src/java/com/threerings/crowd/client/OccupantObserver.java new file mode 100644 index 000000000..b29fa5b73 --- /dev/null +++ b/src/java/com/threerings/crowd/client/OccupantObserver.java @@ -0,0 +1,29 @@ +// +// $Id: OccupantObserver.java,v 1.1 2001/08/20 20:54:56 mdb Exp $ + +package com.threerings.cocktail.party.client; + +import com.threerings.cocktail.party.data.OccupantInfo; + +/** + * An entity that is interested in hearing about bodies that enter and + * leave a location (as well as disconnect and reconnect) can implement + * this interface and register itself with the {@link OccupantManager}. + */ +public interface OccupantObserver +{ + /** + * Called when a body enters the place. + */ + public void occupantEntered (OccupantInfo info); + + /** + * Called when a body leaves the place. + */ + public void occupantLeft (OccupantInfo info); + + /** + * Called an occupant is updated. + */ + public void occupantUpdated (OccupantInfo info); +} diff --git a/src/java/com/threerings/crowd/data/OccupantInfo.java b/src/java/com/threerings/crowd/data/OccupantInfo.java index 1545030d6..328e99550 100644 --- a/src/java/com/threerings/crowd/data/OccupantInfo.java +++ b/src/java/com/threerings/crowd/data/OccupantInfo.java @@ -1,5 +1,5 @@ // -// $Id: OccupantInfo.java,v 1.1 2001/08/16 04:28:36 mdb Exp $ +// $Id: OccupantInfo.java,v 1.2 2001/08/20 20:54:57 mdb Exp $ package com.threerings.cocktail.party.data; @@ -23,19 +23,29 @@ import com.threerings.cocktail.cher.dobj.DSet; */ public class OccupantInfo implements DSet.Element { + /** The body object id of this occupant (and our element key). */ + public Integer bodyOid; + /** The username of this occupant. */ public String username; + /** Access to the body object id as an int. */ + public int getBodyOid () + { + return bodyOid.intValue(); + } + // documentation inherited public Object getKey () { - return username; + return bodyOid; } // documentation inherited public void writeTo (DataOutputStream out) throws IOException { + out.writeInt(bodyOid.intValue()); out.writeUTF(username); } @@ -43,6 +53,7 @@ public class OccupantInfo implements DSet.Element public void readFrom (DataInputStream in) throws IOException { + bodyOid = new Integer(in.readInt()); username = in.readUTF(); } @@ -67,6 +78,7 @@ public class OccupantInfo implements DSet.Element */ protected void toString (StringBuffer buf) { - buf.append("username=").append(username); + buf.append("boid=").append(bodyOid); + buf.append(", username=").append(username); } } diff --git a/src/java/com/threerings/crowd/server/LocationProvider.java b/src/java/com/threerings/crowd/server/LocationProvider.java index d8da440f4..0e9d461d4 100644 --- a/src/java/com/threerings/crowd/server/LocationProvider.java +++ b/src/java/com/threerings/crowd/server/LocationProvider.java @@ -1,5 +1,5 @@ // -// $Id: LocationProvider.java,v 1.6 2001/08/16 04:28:36 mdb Exp $ +// $Id: LocationProvider.java,v 1.7 2001/08/20 20:54:57 mdb Exp $ package com.threerings.cocktail.party.server; @@ -42,6 +42,8 @@ public class LocationProvider extends InvocationProvider */ public static String moveTo (BodyObject source, int placeId) { + int bodoid = source.getOid(); + // make sure the place in question actually exists PlaceManager pmgr = PartyServer.plreg.getPlaceManager(placeId); if (pmgr == null) { @@ -71,21 +73,22 @@ public class LocationProvider extends InvocationProvider PlaceObject pold = (PlaceObject) PartyServer.omgr.getObject(source.location); if (pold != null) { - pold.removeFromOccupants(source.getOid()); - // also remove their occupant info (which is keyed on - // username) - pold.removeFromOccupantInfo(source.username); + Object key = new Integer(bodoid); + // remove their occupant info (which is keyed on oid) + pold.removeFromOccupantInfo(key); + // and remove them from the occupant list + pold.removeFromOccupants(bodoid); } else { Log.info("Body's prior location no longer around? " + - "[boid=" + source.getOid() + + "[boid=" + bodoid + ", poid=" + source.location + "]."); } } catch (ClassCastException cce) { Log.warning("Body claims to be at location which " + "references non-PlaceObject!? " + - "[boid=" + source.getOid() + + "[boid=" + bodoid + ", poid=" + source.location + "]."); } } @@ -102,7 +105,7 @@ public class LocationProvider extends InvocationProvider } // add the body object id to the place object's occupant list - place.addToOccupants(source.getOid()); + place.addToOccupants(bodoid); // and finally queue up a lock release event to release the lock // once all these events are processed diff --git a/src/java/com/threerings/crowd/server/PlaceManager.java b/src/java/com/threerings/crowd/server/PlaceManager.java index 0134de4dd..e0f06fc97 100644 --- a/src/java/com/threerings/crowd/server/PlaceManager.java +++ b/src/java/com/threerings/crowd/server/PlaceManager.java @@ -1,5 +1,5 @@ // -// $Id: PlaceManager.java,v 1.8 2001/08/16 04:28:36 mdb Exp $ +// $Id: PlaceManager.java,v 1.9 2001/08/20 20:54:57 mdb Exp $ package com.threerings.cocktail.party.server; @@ -126,6 +126,7 @@ public class PlaceManager implements Subscriber protected void populateOccupantInfo (OccupantInfo info, BodyObject body) { // the base occupant info is only their username + info.bodyOid = new Integer(body.getOid()); info.username = body.username; } @@ -145,6 +146,14 @@ public class PlaceManager implements Subscriber { Log.info("Body left [ploid=" + _plobj.getOid() + ", oid=" + bodyOid + "]."); + + // if their occupant info hasn't been removed (which may be the + // case if they logged off rather than left via a MoveTo request), + // we need to get it on out of here + Object key = new Integer(bodyOid); + if (_plobj.occupantInfo.containsKey(key)) { + _plobj.removeFromOccupantInfo(key); + } } /**