Revamped location and cluster handling so that we can implement the fancy

new dynamic cluster system all good and proper.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2330 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2003-03-26 02:06:06 +00:00
parent a3ff1486e0
commit 5d6883c75c
6 changed files with 245 additions and 234 deletions
@@ -1,5 +1,5 @@
//
// $Id: SpotSceneDirector.java,v 1.22 2003/03/25 19:28:58 mdb Exp $
// $Id: SpotSceneDirector.java,v 1.23 2003/03/26 02:06:06 mdb Exp $
package com.threerings.whirled.spot.client;
@@ -9,6 +9,7 @@ import com.samskivert.util.StringUtil;
import com.threerings.presents.client.BasicDirector;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService.ConfirmListener;
import com.threerings.presents.dobj.AttributeChangeListener;
import com.threerings.presents.dobj.AttributeChangedEvent;
@@ -39,27 +40,8 @@ import com.threerings.whirled.spot.data.SpotScene;
* locations within a scene.
*/
public class SpotSceneDirector extends BasicDirector
implements SpotCodes, Subscriber, SpotService.ChangeLocListener,
AttributeChangeListener
implements SpotCodes, Subscriber, AttributeChangeListener
{
/**
* This is used to communicate back to the caller of {@link
* #changeLocation}.
*/
public static interface ChangeObserver
{
/**
* Indicates that the requested location change succeeded.
*/
public void locationChangeSucceeded (Location loc);
/**
* Indicates that the requested location change failed and
* provides a reason code explaining the failure.
*/
public void locationChangeFailed (Location loc, String reason);
}
/**
* Creates a new spot scene director with the specified context and
* which will cooperate with the supplied scene director.
@@ -155,16 +137,9 @@ public class SpotSceneDirector extends BasicDirector
/**
* Issues a request to change our location within the scene to the
* specified location. Depending on the value of <code>cluster</code>
* the client will be made to create a new cluster, join and existing
* cluster or join no cluster at all.
* specified location.
*
* @param loc the new location to which to move.
* @param cluster if zero, a new cluster will be created and assigned
* to the calling user; if -1, the calling user will be removed from
* any cluster they currently occupy and not made to occupy a new
* cluster; if the bodyOid of another user, the calling user will be
* made to join the target user's cluster.
* @param obs will be notified of success or failure. Most client
* entities find out about location changes via changes to the
* occupant info data, but the initiator of a location change request
@@ -173,7 +148,7 @@ public class SpotSceneDirector extends BasicDirector
* starting a sprite moving toward the new location), but backtrack if
* it finds out that the location change failed.
*/
public void changeLocation (Location loc, int cluster, ChangeObserver obs)
public void changeLocation (Location loc, final ResultListener listener)
{
// refuse if there's a pending location change or if we're already
// at the specified location
@@ -190,11 +165,59 @@ public class SpotSceneDirector extends BasicDirector
return;
}
Log.info("Changing location [loc=" + loc + ", clus=" + cluster + "].");
Log.info("Changing location [loc=" + loc + "].");
_pendingLoc = (Location)loc.clone();
_changeObserver = obs;
_sservice.changeLoc(_ctx.getClient(), loc, cluster, this);
_sservice.changeLocation(_ctx.getClient(), loc, new ConfirmListener() {
public void requestProcessed () {
_location = _pendingLoc;
_pendingLoc = null;
if (listener != null) {
listener.requestCompleted(_location);
}
}
public void requestFailed (String reason) {
_pendingLoc = null;
if (listener != null) {
listener.requestFailed(new Exception(reason));
}
}
});
}
/**
* Issues a request to join the cluster associated with the specified
* user (starting one if necessary).
*
* @param froid the bodyOid of another user; the calling user will
* be made to join the target user's cluster.
* @param listener will be notified of success or failure.
*/
public void joinCluster (int froid, final ResultListener listener)
{
SpotScene scene = (SpotScene)_scdir.getScene();
if (scene == null) {
Log.warning("Requested to join cluster, but we're not " +
"currently in any scene [froid=" + froid + "].");
return;
}
Log.info("Joining cluster [friend=" + froid + "].");
_sservice.joinCluster(_ctx.getClient(), froid, new ConfirmListener() {
public void requestProcessed () {
if (listener != null) {
listener.requestCompleted(null);
}
}
public void requestFailed (String reason) {
if (listener != null) {
listener.requestFailed(new Exception(reason));
}
}
});
}
/**
@@ -237,38 +260,6 @@ public class SpotSceneDirector extends BasicDirector
return true;
}
// documentation inherited from interface
public void changeLocSucceeded ()
{
ChangeObserver obs = _changeObserver;
_location = _pendingLoc;
// clear out our pending location info
_pendingLoc = null;
_changeObserver = null;
// if we had an observer, let them know things went well
if (obs != null) {
obs.locationChangeSucceeded(_location);
}
}
// documentation inherited from interface
public void requestFailed (String reason)
{
ChangeObserver obs = _changeObserver;
Location loc = _pendingLoc;
// clear out our pending location info
_pendingLoc = null;
_changeObserver = null;
// if we had an observer, let them know things went well
if (obs != null) {
obs.locationChangeFailed(loc, reason);
}
}
// documentation inherited
public void objectAvailable (DObject object)
{
@@ -336,7 +327,6 @@ public class SpotSceneDirector extends BasicDirector
// clear out our business
_location = null;
_pendingLoc = null;
_changeObserver = null;
_sservice = null;
clearCluster();
@@ -403,8 +393,4 @@ public class SpotSceneDirector extends BasicDirector
/** The cluster chat object for the cluster we currently occupy. */
protected DObject _clobj;
/** An entity that wants to know if a requested location change
* succeeded or failed. */
protected ChangeObserver _changeObserver;
}
@@ -1,5 +1,5 @@
//
// $Id: SpotService.java,v 1.13 2003/02/13 21:55:22 mdb Exp $
// $Id: SpotService.java,v 1.14 2003/03/26 02:06:06 mdb Exp $
package com.threerings.whirled.spot.client;
@@ -28,30 +28,26 @@ public interface SpotService extends InvocationService
Client client, int portalId, int destSceneVer,
SceneMoveListener listener);
/**
* Used to communicate responses to a {@link #changeLoc} request.
*/
public static interface ChangeLocListener extends InvocationListener
{
/**
* Called when the change location request succeeds.
*/
public void changeLocSucceeded ();
}
/**
* Requests that this client's body be made to move to the specified
* location.
* location. The user will be removed from any cluster from which they
* are an occupant.
*
* @param loc the location to which to move.
* @param cluster if -1, the calling user will be removed from any
* cluster they currently occupy and not made to occupy a new cluster;
* if the bodyOid of another user, the calling user will be made to
* join the target user's cluster, or create a cluster with the target
* user if they are not already in one.
*/
public void changeLoc (Client client, Location loc, int cluster,
ChangeLocListener listener);
public void changeLocation (Client client, Location loc,
ConfirmListener listener);
/**
* Requests that this client start or join the specified cluster. They
* will be relocated appropriately by the scene manager.
*
* @param friendOid the bodyOid of another user; the calling user will
* be made to join the target user's cluster, or create a cluster with
* the target user if they are not already in one.
*/
public void joinCluster (Client client, int friendOid,
ConfirmListener listener);
/**
* Requests that the supplied message be delivered to listeners in the
@@ -1,15 +1,15 @@
//
// $Id: SpotMarshaller.java,v 1.3 2003/02/12 07:23:31 mdb Exp $
// $Id: SpotMarshaller.java,v 1.4 2003/03/26 02:06:06 mdb Exp $
package com.threerings.whirled.spot.data;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService.ConfirmListener;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.dobj.InvocationResponseEvent;
import com.threerings.whirled.client.SceneService.SceneMoveListener;
import com.threerings.whirled.data.SceneMarshaller.SceneMoveMarshaller;
import com.threerings.whirled.spot.client.SpotService;
import com.threerings.whirled.spot.client.SpotService.ChangeLocListener;
import com.threerings.whirled.spot.data.Location;
/**
@@ -22,37 +22,6 @@ import com.threerings.whirled.spot.data.Location;
public class SpotMarshaller extends InvocationMarshaller
implements SpotService
{
// documentation inherited
public static class ChangeLocMarshaller extends ListenerMarshaller
implements ChangeLocListener
{
/** The method id used to dispatch {@link #changeLocSucceeded}
* responses. */
public static final int CHANGE_LOC_SUCCEEDED = 1;
// documentation inherited from interface
public void changeLocSucceeded ()
{
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, CHANGE_LOC_SUCCEEDED,
new Object[] { }));
}
// documentation inherited
public void dispatchResponse (int methodId, Object[] args)
{
switch (methodId) {
case CHANGE_LOC_SUCCEEDED:
((ChangeLocListener)listener).changeLocSucceeded(
);
return;
default:
super.dispatchResponse(methodId, args);
}
}
}
/** The method id used to dispatch {@link #traversePortal} requests. */
public static final int TRAVERSE_PORTAL = 1;
@@ -66,21 +35,34 @@ public class SpotMarshaller extends InvocationMarshaller
});
}
/** The method id used to dispatch {@link #changeLoc} requests. */
public static final int CHANGE_LOC = 2;
/** The method id used to dispatch {@link #changeLocation} requests. */
public static final int CHANGE_LOCATION = 2;
// documentation inherited from interface
public void changeLoc (Client arg1, Location arg2, int arg3, ChangeLocListener arg4)
public void changeLocation (Client arg1, Location arg2, ConfirmListener arg3)
{
ChangeLocMarshaller listener4 = new ChangeLocMarshaller();
listener4.listener = arg4;
sendRequest(arg1, CHANGE_LOC, new Object[] {
arg2, new Integer(arg3), listener4
ConfirmMarshaller listener3 = new ConfirmMarshaller();
listener3.listener = arg3;
sendRequest(arg1, CHANGE_LOCATION, new Object[] {
arg2, listener3
});
}
/** The method id used to dispatch {@link #joinCluster} requests. */
public static final int JOIN_CLUSTER = 3;
// documentation inherited from interface
public void joinCluster (Client arg1, int arg2, ConfirmListener arg3)
{
ConfirmMarshaller listener3 = new ConfirmMarshaller();
listener3.listener = arg3;
sendRequest(arg1, JOIN_CLUSTER, new Object[] {
new Integer(arg2), listener3
});
}
/** The method id used to dispatch {@link #clusterSpeak} requests. */
public static final int CLUSTER_SPEAK = 3;
public static final int CLUSTER_SPEAK = 4;
// documentation inherited from interface
public void clusterSpeak (Client arg1, String arg2, byte arg3)
@@ -90,5 +72,4 @@ public class SpotMarshaller extends InvocationMarshaller
});
}
// Generated on 10:09:04 02/05/03.
}
@@ -1,9 +1,10 @@
//
// $Id: SpotDispatcher.java,v 1.3 2003/02/12 07:23:31 mdb Exp $
// $Id: SpotDispatcher.java,v 1.4 2003/03/26 02:06:06 mdb Exp $
package com.threerings.whirled.spot.server;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService.ConfirmListener;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.server.InvocationDispatcher;
@@ -11,7 +12,6 @@ import com.threerings.presents.server.InvocationException;
import com.threerings.whirled.client.SceneService.SceneMoveListener;
import com.threerings.whirled.data.SceneMarshaller.SceneMoveMarshaller;
import com.threerings.whirled.spot.client.SpotService;
import com.threerings.whirled.spot.client.SpotService.ChangeLocListener;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.SpotMarshaller;
@@ -48,10 +48,17 @@ public class SpotDispatcher extends InvocationDispatcher
);
return;
case SpotMarshaller.CHANGE_LOC:
((SpotProvider)provider).changeLoc(
case SpotMarshaller.CHANGE_LOCATION:
((SpotProvider)provider).changeLocation(
source,
(Location)args[0], ((Integer)args[1]).intValue(), (ChangeLocListener)args[2]
(Location)args[0], (ConfirmListener)args[1]
);
return;
case SpotMarshaller.JOIN_CLUSTER:
((SpotProvider)provider).joinCluster(
source,
((Integer)args[0]).intValue(), (ConfirmListener)args[1]
);
return;
@@ -66,6 +73,4 @@ public class SpotDispatcher extends InvocationDispatcher
super.dispatchRequest(source, methodId, args);
}
}
// Generated on 10:09:04 02/05/03.
}
@@ -1,5 +1,5 @@
//
// $Id: SpotProvider.java,v 1.16 2003/03/17 19:34:26 mdb Exp $
// $Id: SpotProvider.java,v 1.17 2003/03/26 02:06:06 mdb Exp $
package com.threerings.whirled.spot.server;
@@ -23,7 +23,7 @@ import com.threerings.whirled.server.SceneManager;
import com.threerings.whirled.server.SceneRegistry;
import com.threerings.whirled.spot.Log;
import com.threerings.whirled.spot.client.SpotService.ChangeLocListener;
import com.threerings.whirled.spot.client.SpotService;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SpotCodes;
@@ -137,10 +137,10 @@ public class SpotProvider
}
/**
* Processes a {@link SpotService#changeLog} request.
* Processes a {@link SpotService#changeLocation} request.
*/
public void changeLoc (ClientObject caller, Location loc, int cluster,
ChangeLocListener listener)
public void changeLocation (ClientObject caller, Location loc,
SpotService.ConfirmListener listener)
throws InvocationException
{
int sceneId = getCallerSceneId(caller);
@@ -150,17 +150,44 @@ public class SpotProvider
SpotSceneManager smgr = (SpotSceneManager)
_screg.getSceneManager(sceneId);
if (smgr == null) {
Log.warning("User requested to change location in " +
Log.warning("User requested to change location from " +
"non-existent scene [user=" + source.who() +
", sceneId=" + sceneId + ", loc=" + loc +"].");
throw new InvocationException(INTERNAL_ERROR);
}
// pass the buck to yon scene manager
smgr.handleChangeLocRequest(source, loc, cluster);
smgr.handleChangeLoc(source, loc);
// if that method finished, we're good to go
listener.changeLocSucceeded();
listener.requestProcessed();
}
/**
* Processes a {@link SpotService#joinCluster} request.
*/
public void joinCluster (ClientObject caller, int friendOid,
SpotService.ConfirmListener listener)
throws InvocationException
{
int sceneId = getCallerSceneId(caller);
BodyObject source = (BodyObject)caller;
// look up the scene manager for the specified scene
SpotSceneManager smgr = (SpotSceneManager)
_screg.getSceneManager(sceneId);
if (smgr == null) {
Log.warning("User requested to join cluster from " +
"non-existent scene [user=" + source.who() +
", sceneId=" + sceneId + ", foid=" + friendOid +"].");
throw new InvocationException(INTERNAL_ERROR);
}
// pass the buck to yon scene manager
smgr.handleJoinCluster(source, friendOid);
// if that method finished, we're good to go
listener.requestProcessed();
}
/**
@@ -1,5 +1,5 @@
//
// $Id: SpotSceneManager.java,v 1.29 2003/03/25 19:28:59 mdb Exp $
// $Id: SpotSceneManager.java,v 1.30 2003/03/26 02:06:06 mdb Exp $
package com.threerings.whirled.spot.server;
@@ -53,7 +53,7 @@ public class SpotSceneManager extends SceneManager
SpotScene scene = (SpotScene)mgr.getScene();
try {
Location eloc = scene.getDefaultEntrance().getLocation();
mgr.handleChangeLocRequest(body, eloc, -1);
mgr.handleChangeLoc(body, eloc);
} catch (InvocationException ie) {
Log.warning("Could not move user to default portal " +
"[where=" + mgr.where() + ", who=" + body.who() +
@@ -170,11 +170,9 @@ public class SpotSceneManager extends SceneManager
* join the other user's cluster.
*
* @exception InvocationException thrown with a reason code explaining
* the location change failure if there is a problem processing the
* location change request.
* the failure if there is a problem processing the request.
*/
protected void handleChangeLocRequest (
BodyObject source, Location loc, int cluster)
protected void handleChangeLoc (BodyObject source, Location loc)
throws InvocationException
{
// make sure they are in our scene
@@ -201,13 +199,50 @@ public class SpotSceneManager extends SceneManager
_ssobj.updateOccupantLocs(sloc);
}
// handle the cluster situation; -1 means remove, our own oid
// means leave us in whatever cluster we're already in; someone
// else's oid means join their cluster or start one with them
if (cluster == -1) {
removeFromCluster(source.getOid());
} else if (cluster != source.getOid()) {
createOrJoinCluster(cluster, source);
// remove them from any cluster as they've departed
removeFromCluster(source.getOid());
}
/**
* Called by the {@link SpotProvider} when we receive a request by a
* user to join a particular cluster.
*
* @param joiner the body to be moved.
* @param friendOid the bodyOid of another user; the moving user will
* be made to join the other user's cluster.
*
* @exception InvocationException thrown with a reason code explaining
* the failure if there is a problem processing the request.
*/
protected void handleJoinCluster (BodyObject joiner, int friendOid)
throws InvocationException
{
ClusterRecord clrec = (ClusterRecord)_clusters.get(friendOid);
if (clrec != null) {
// if the cluster already exists, add this user and be done
if (clrec.addBody(joiner)) {
_clusters.put(joiner.getOid(), clrec);
}
return;
}
// otherwise we have to create a new cluster and add our two
// charter members!
clrec = new ClusterRecord();
BodyObject member = (BodyObject)CrowdServer.omgr.getObject(friendOid);
if (member == null) {
Log.warning("Can't create cluster, missing target " +
"[creator=" + joiner.who() +
", friendOid=" + friendOid + "].");
return;
}
// add our two lovely users to the newly created cluster
if (clrec.addBody(joiner)) {
_clusters.put(joiner.getOid(), clrec);
}
if (clrec.addBody(member)) {
_clusters.put(member.getOid(), clrec);
}
}
@@ -229,42 +264,6 @@ public class SpotSceneManager extends SceneManager
// quietly off itself when it's done subscribing to its object
}
/**
* Adds the specified user to the cluster occupied by the specified
* other user or creates a new cluster for the two users if neither is
* already clustered.
*/
protected void createOrJoinCluster (int memberOid, BodyObject joiner)
{
ClusterRecord clrec = (ClusterRecord)_clusters.get(memberOid);
if (clrec != null) {
// if the cluster already exists, add this user and be done
if (clrec.addBody(joiner)) {
_clusters.put(joiner.getOid(), clrec);
}
return;
}
// otherwise we have to create a new cluster and add our two
// charter members!
clrec = new ClusterRecord();
BodyObject member = (BodyObject)CrowdServer.omgr.getObject(memberOid);
if (member == null) {
Log.warning("Can't create cluster, missing target " +
"[creator=" + joiner.who() +
", targetOid=" + memberOid + "].");
return;
}
// add our two lovely users to the newly created cluster
if (clrec.addBody(joiner)) {
_clusters.put(joiner.getOid(), clrec);
}
if (clrec.addBody(member)) {
_clusters.put(member.getOid(), clrec);
}
}
/**
* Removes the specified user from any cluster they occupy.
*/
@@ -322,6 +321,24 @@ public class SpotSceneManager extends SceneManager
loc.y = cy;
}
/**
* Called when a user is added to a cluster. The scene manager
* implementation should take this opportunity to rearrange everyone
* in the cluster appropriately for the new size.
*/
protected void bodyAdded (ClusterRecord clrec, BodyObject body)
{
}
/**
* Called when a user is removed from a cluster. The scene manager
* implementation should take this opportunity to rearrange everyone
* in the cluster appropriately for the new size.
*/
protected void bodyRemoved (ClusterRecord clrec, BodyObject body)
{
}
/**
* Used to manage clusters which are groups of users that can chat to
* one another.
@@ -344,11 +361,21 @@ public class SpotSceneManager extends SceneManager
put(body.getOid(), body);
_cluster.occupants++;
recomputeCenter();
if (_clobj != null) {
((ClusteredBodyObject)body).setClusterOid(_clobj.getOid());
_clobj.addToOccupants(body.getOid());
_ssobj.updateClusters(_cluster);
try {
body.startTransaction();
_ssobj.startTransaction();
bodyAdded(this, body); // do the hokey pokey
if (_clobj != null) {
((ClusteredBodyObject)body).setClusterOid(
_clobj.getOid());
_clobj.addToOccupants(body.getOid());
_ssobj.updateClusters(_cluster);
}
} finally {
_clobj.commitTransaction();
_ssobj.commitTransaction();
}
Log.info("Added " + body.who() + " to "+ this + ".");
@@ -364,7 +391,7 @@ public class SpotSceneManager extends SceneManager
public void removeBody (int bodyOid)
{
ClusteredBodyObject body = (ClusteredBodyObject)remove(bodyOid);
BodyObject body = (BodyObject)remove(bodyOid);
if (body == null) {
Log.warning("Requested to remove unknown body from cluster " +
"[cloid=" + _clobj.getOid() +
@@ -372,13 +399,23 @@ public class SpotSceneManager extends SceneManager
return;
}
body.setClusterOid(-1);
_cluster.occupants--;
recomputeCenter();
if (_clobj != null) {
_clobj.removeFromOccupants(bodyOid);
_ssobj.updateClusters(_cluster);
try {
body.startTransaction();
_ssobj.startTransaction();
((ClusteredBodyObject)body).setClusterOid(-1);
_cluster.occupants--;
bodyRemoved(this, body); // do the hokey pokey
if (_clobj != null) {
_clobj.removeFromOccupants(bodyOid);
_ssobj.updateClusters(_cluster);
}
} finally {
_ssobj.commitTransaction();
body.commitTransaction();
}
Log.info("Removed " + bodyOid + " from "+ this + ".");
// if we've removed our last body; stick a fork in ourselves
@@ -392,6 +429,11 @@ public class SpotSceneManager extends SceneManager
return _clobj;
}
public Cluster getCluster ()
{
return _cluster;
}
public void objectAvailable (DObject object)
{
// keep this feller around
@@ -434,31 +476,6 @@ public class SpotSceneManager extends SceneManager
return "[cluster=" + _cluster + ", size=" + size() + "]";
}
protected void recomputeCenter ()
{
int tx = 0, ty = 0, count = 0;
// compute the average x and y position of all our cluster
// occupants
Iterator iter = _ssobj.occupantLocs.entries();
while (iter.hasNext()) {
SceneLocation sloc = (SceneLocation)iter.next();
if (containsKey(sloc.bodyOid)) {
locationToCoords(sloc.x, sloc.y, _scratch);
tx += _scratch.x;
ty += _scratch.x;
count++;
}
}
if (count > 1) {
// convert the center back to "location" coordinates
coordsToLocation(tx/count, ty/count, _scratch);
_cluster.x = _scratch.x;
_cluster.y = _scratch.y;
}
}
protected void destroy ()
{
Log.info("Cluster empty, going away " +
@@ -469,7 +486,6 @@ public class SpotSceneManager extends SceneManager
protected ClusterObject _clobj;
protected Cluster _cluster = new Cluster();
protected Point _scratch = new Point();
}
/** A casted reference to our place object. */