Small changes to the cluster services: cluster information is published in
the scene object; clusters are centered within their group of occupants; a player must start a cluster with another player rather than by themselves. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2278 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: SpotService.java,v 1.12 2003/02/12 07:23:31 mdb Exp $
|
// $Id: SpotService.java,v 1.13 2003/02/13 21:55:22 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.whirled.spot.client;
|
package com.threerings.whirled.spot.client;
|
||||||
|
|
||||||
@@ -44,11 +44,11 @@ public interface SpotService extends InvocationService
|
|||||||
* location.
|
* location.
|
||||||
*
|
*
|
||||||
* @param loc the location to which to move.
|
* @param loc the location to which to move.
|
||||||
* @param cluster if zero, a new cluster will be created and assigned
|
* @param cluster if -1, the calling user will be removed from any
|
||||||
* to the calling user; if -1, the calling user will be removed from
|
* cluster they currently occupy and not made to occupy a new cluster;
|
||||||
* any cluster they currently occupy and not made to occupy a new
|
* if the bodyOid of another user, the calling user will be made to
|
||||||
* cluster; if the bodyOid of another user, the calling user will be
|
* join the target user's cluster, or create a cluster with the target
|
||||||
* made to join the target user's cluster.
|
* user if they are not already in one.
|
||||||
*/
|
*/
|
||||||
public void changeLoc (Client client, Location loc, int cluster,
|
public void changeLoc (Client client, Location loc, int cluster,
|
||||||
ChangeLocListener listener);
|
ChangeLocListener listener);
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// $Id: Cluster.java,v 1.1 2003/02/13 21:55:22 mdb Exp $
|
||||||
|
|
||||||
|
package com.threerings.whirled.spot.data;
|
||||||
|
|
||||||
|
import com.threerings.presents.dobj.DSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains information on clusters.
|
||||||
|
*/
|
||||||
|
public class Cluster
|
||||||
|
implements DSet.Entry
|
||||||
|
{
|
||||||
|
/** A unique identifier for this cluster (also the distributed object
|
||||||
|
* id of the cluster chat object). */
|
||||||
|
public int clusterOid;
|
||||||
|
|
||||||
|
/** The x-coordinate of the cluster in the scene. */
|
||||||
|
public int x;
|
||||||
|
|
||||||
|
/** The y-coordinate of the cluster in the scene. */
|
||||||
|
public int y;
|
||||||
|
|
||||||
|
/** The number of occupants in this cluster. */
|
||||||
|
public int occupants;
|
||||||
|
|
||||||
|
// documentation inherited
|
||||||
|
public Comparable getKey ()
|
||||||
|
{
|
||||||
|
if (_key == null) {
|
||||||
|
_key = new Integer(clusterOid);
|
||||||
|
}
|
||||||
|
return _key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Used for {@link #geyKey}. */
|
||||||
|
protected transient Integer _key;
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: SpotSceneObject.dobj,v 1.1 2003/02/12 07:23:31 mdb Exp $
|
// $Id: SpotSceneObject.dobj,v 1.2 2003/02/13 21:55:22 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.whirled.spot.data;
|
package com.threerings.whirled.spot.data;
|
||||||
|
|
||||||
@@ -14,4 +14,7 @@ public class SpotSceneObject extends SceneObject
|
|||||||
/** A distributed set containing {@link SceneLocation} records for all
|
/** A distributed set containing {@link SceneLocation} records for all
|
||||||
* occupants of this scene. */
|
* occupants of this scene. */
|
||||||
public DSet occupantLocs = new DSet();
|
public DSet occupantLocs = new DSet();
|
||||||
|
|
||||||
|
/** Contains information on all {@link Cluster}s in this scene. */
|
||||||
|
public DSet clusters = new DSet();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// $Id: SpotSceneObject.java,v 1.1 2003/02/12 07:23:31 mdb Exp $
|
// $Id: SpotSceneObject.java,v 1.2 2003/02/13 21:55:22 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.whirled.spot.data;
|
package com.threerings.whirled.spot.data;
|
||||||
|
|
||||||
@@ -14,10 +14,16 @@ public class SpotSceneObject extends SceneObject
|
|||||||
/** The field name of the <code>occupantLocs</code> field. */
|
/** The field name of the <code>occupantLocs</code> field. */
|
||||||
public static final String OCCUPANT_LOCS = "occupantLocs";
|
public static final String OCCUPANT_LOCS = "occupantLocs";
|
||||||
|
|
||||||
|
/** The field name of the <code>clusters</code> field. */
|
||||||
|
public static final String CLUSTERS = "clusters";
|
||||||
|
|
||||||
/** A distributed set containing {@link SceneLocation} records for all
|
/** A distributed set containing {@link SceneLocation} records for all
|
||||||
* occupants of this scene. */
|
* occupants of this scene. */
|
||||||
public DSet occupantLocs = new DSet();
|
public DSet occupantLocs = new DSet();
|
||||||
|
|
||||||
|
/** Contains information on all {@link Cluster}s in this scene. */
|
||||||
|
public DSet clusters = new DSet();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests that the specified entry be added to the
|
* Requests that the specified entry be added to the
|
||||||
* <code>occupantLocs</code> set. The set will not change until the event is
|
* <code>occupantLocs</code> set. The set will not change until the event is
|
||||||
@@ -63,4 +69,50 @@ public class SpotSceneObject extends SceneObject
|
|||||||
this.occupantLocs = occupantLocs;
|
this.occupantLocs = occupantLocs;
|
||||||
requestAttributeChange(OCCUPANT_LOCS, occupantLocs);
|
requestAttributeChange(OCCUPANT_LOCS, occupantLocs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the specified entry be added to the
|
||||||
|
* <code>clusters</code> set. The set will not change until the event is
|
||||||
|
* actually propagated through the system.
|
||||||
|
*/
|
||||||
|
public void addToClusters (DSet.Entry elem)
|
||||||
|
{
|
||||||
|
requestEntryAdd(CLUSTERS, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the entry matching the supplied key be removed from
|
||||||
|
* the <code>clusters</code> set. The set will not change until the
|
||||||
|
* event is actually propagated through the system.
|
||||||
|
*/
|
||||||
|
public void removeFromClusters (Object key)
|
||||||
|
{
|
||||||
|
requestEntryRemove(CLUSTERS, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the specified entry be updated in the
|
||||||
|
* <code>clusters</code> set. The set will not change until the event is
|
||||||
|
* actually propagated through the system.
|
||||||
|
*/
|
||||||
|
public void updateClusters (DSet.Entry elem)
|
||||||
|
{
|
||||||
|
requestEntryUpdate(CLUSTERS, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests that the <code>clusters</code> field be set to the
|
||||||
|
* specified value. Generally one only adds, updates and removes
|
||||||
|
* entries of a distributed set, but certain situations call for a
|
||||||
|
* complete replacement of the set value. The local value will be
|
||||||
|
* updated immediately and an event will be propagated through the
|
||||||
|
* system to notify all listeners that the attribute did
|
||||||
|
* change. Proxied copies of this object (on clients) will apply the
|
||||||
|
* value change when they received the attribute changed notification.
|
||||||
|
*/
|
||||||
|
public void setClusters (DSet clusters)
|
||||||
|
{
|
||||||
|
this.clusters = clusters;
|
||||||
|
requestAttributeChange(CLUSTERS, clusters);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
//
|
//
|
||||||
// $Id: SpotSceneManager.java,v 1.25 2003/02/12 07:23:31 mdb Exp $
|
// $Id: SpotSceneManager.java,v 1.26 2003/02/13 21:55:22 mdb Exp $
|
||||||
|
|
||||||
package com.threerings.whirled.spot.server;
|
package com.threerings.whirled.spot.server;
|
||||||
|
|
||||||
|
import java.awt.Point;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import com.samskivert.util.ArrayIntSet;
|
import com.samskivert.util.ArrayIntSet;
|
||||||
@@ -22,6 +23,7 @@ import com.threerings.crowd.server.CrowdServer;
|
|||||||
import com.threerings.whirled.server.SceneManager;
|
import com.threerings.whirled.server.SceneManager;
|
||||||
|
|
||||||
import com.threerings.whirled.spot.Log;
|
import com.threerings.whirled.spot.Log;
|
||||||
|
import com.threerings.whirled.spot.data.Cluster;
|
||||||
import com.threerings.whirled.spot.data.ClusterObject;
|
import com.threerings.whirled.spot.data.ClusterObject;
|
||||||
import com.threerings.whirled.spot.data.ClusteredBodyObject;
|
import com.threerings.whirled.spot.data.ClusteredBodyObject;
|
||||||
import com.threerings.whirled.spot.data.Location;
|
import com.threerings.whirled.spot.data.Location;
|
||||||
@@ -171,6 +173,8 @@ public class SpotSceneManager extends SceneManager
|
|||||||
throw new InvocationException(INTERNAL_ERROR);
|
throw new InvocationException(INTERNAL_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: make sure the location isn't too close to another user
|
||||||
|
|
||||||
// update the user's location information in the scene which will
|
// update the user's location information in the scene which will
|
||||||
// indicate to the client that their avatar should be moved from
|
// indicate to the client that their avatar should be moved from
|
||||||
// its current position to their new position
|
// its current position to their new position
|
||||||
@@ -186,16 +190,10 @@ public class SpotSceneManager extends SceneManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handle the cluster situation
|
// handle the cluster situation
|
||||||
switch (cluster) {
|
if (cluster == -1) {
|
||||||
case 0:
|
|
||||||
createNewCluster(source);
|
|
||||||
break;
|
|
||||||
case -1:
|
|
||||||
removeFromCluster(source.getOid());
|
removeFromCluster(source.getOid());
|
||||||
break;
|
} else {
|
||||||
default:
|
createOrJoinCluster(cluster, source);
|
||||||
addToCluster(cluster, source);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,25 +217,38 @@ public class SpotSceneManager extends SceneManager
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the specified user to the cluster occupied by the specified
|
* Adds the specified user to the cluster occupied by the specified
|
||||||
* other user.
|
* other user or creates a new cluster for the two users if neither is
|
||||||
|
* already clustered.
|
||||||
*/
|
*/
|
||||||
protected void addToCluster (int memberOid, BodyObject joiner)
|
protected void createOrJoinCluster (int memberOid, BodyObject joiner)
|
||||||
{
|
{
|
||||||
ClusterRecord clrec = (ClusterRecord)_clusters.get(memberOid);
|
ClusterRecord clrec = (ClusterRecord)_clusters.get(memberOid);
|
||||||
if (clrec == null) {
|
if (clrec != null) {
|
||||||
// this isn't completely impossible as the last user might
|
// if the cluster already exists, add this user and be done
|
||||||
// leave a cluster just as another user is entering it, but
|
if (clrec.addBody(joiner)) {
|
||||||
// before the entering user's client was informed that the
|
_clusters.put(joiner.getOid(), clrec);
|
||||||
// cluster went away
|
}
|
||||||
Log.info("Can't add user to non-existent cluster; " +
|
return;
|
||||||
"creating a new one just for them " +
|
|
||||||
"[memberOid=" + memberOid +
|
|
||||||
", joiner=" + joiner.who() + "].");
|
|
||||||
clrec = new ClusterRecord();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)) {
|
if (clrec.addBody(joiner)) {
|
||||||
_clusters.put(joiner.getOid(), clrec);
|
_clusters.put(joiner.getOid(), clrec);
|
||||||
}
|
}
|
||||||
|
if (clrec.addBody(member)) {
|
||||||
|
_clusters.put(member.getOid(), clrec);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -269,11 +280,39 @@ public class SpotSceneManager extends SceneManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the x and y coordinates in the supplied location object to
|
||||||
|
* Cartesian coordinates that can be manipulated geometrically. The
|
||||||
|
* default implementation assumes the location coordinates are
|
||||||
|
* Cartesian, but systems that use different coordinate systems will
|
||||||
|
* want to override this method and perform the appropriate
|
||||||
|
* conversions.
|
||||||
|
*/
|
||||||
|
protected void locationToCoords (int lx, int ly, Point coords)
|
||||||
|
{
|
||||||
|
coords.x = lx;
|
||||||
|
coords.y = ly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the supplied x and y coordinates (obtained from a prior
|
||||||
|
* call to {@link #locationToCoords}) to location coordinates that can
|
||||||
|
* be sent back to the client. The default implementation assumes the
|
||||||
|
* location coordinates are Cartesian, but systems that use different
|
||||||
|
* coordinate systems will want to override this method and perform
|
||||||
|
* the appropriate conversions.
|
||||||
|
*/
|
||||||
|
protected void coordsToLocation (int cx, int cy, Point loc)
|
||||||
|
{
|
||||||
|
loc.x = cx;
|
||||||
|
loc.y = cy;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to manage clusters which are groups of users that can chat to
|
* Used to manage clusters which are groups of users that can chat to
|
||||||
* one another.
|
* one another.
|
||||||
*/
|
*/
|
||||||
protected static class ClusterRecord extends HashIntMap
|
protected class ClusterRecord extends HashIntMap
|
||||||
implements Subscriber
|
implements Subscriber
|
||||||
{
|
{
|
||||||
public ClusterRecord ()
|
public ClusterRecord ()
|
||||||
@@ -284,11 +323,14 @@ public class SpotSceneManager extends SceneManager
|
|||||||
public boolean addBody (BodyObject body)
|
public boolean addBody (BodyObject body)
|
||||||
{
|
{
|
||||||
if (body instanceof ClusteredBodyObject) {
|
if (body instanceof ClusteredBodyObject) {
|
||||||
|
put(body.getOid(), body);
|
||||||
|
_cluster.occupants++;
|
||||||
|
recomputeCenter();
|
||||||
if (_clobj != null) {
|
if (_clobj != null) {
|
||||||
|
_ssobj.updateClusters(_cluster);
|
||||||
|
_clobj.addToOccupants(body.getOid());
|
||||||
((ClusteredBodyObject)body).setClusterOid(_clobj.getOid());
|
((ClusteredBodyObject)body).setClusterOid(_clobj.getOid());
|
||||||
}
|
}
|
||||||
put(body.getOid(), body);
|
|
||||||
_clobj.addToOccupants(body.getOid());
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -308,7 +350,12 @@ public class SpotSceneManager extends SceneManager
|
|||||||
", size=" + size() + ", who=" + bodyOid + "].");
|
", size=" + size() + ", who=" + bodyOid + "].");
|
||||||
} else {
|
} else {
|
||||||
body.setClusterOid(-1);
|
body.setClusterOid(-1);
|
||||||
_clobj.removeFromOccupants(bodyOid);
|
_cluster.occupants--;
|
||||||
|
recomputeCenter();
|
||||||
|
if (_clobj != null) {
|
||||||
|
_clobj.removeFromOccupants(bodyOid);
|
||||||
|
_ssobj.updateClusters(_cluster);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we've removed our last body; stick a fork in ourselves
|
// if we've removed our last body; stick a fork in ourselves
|
||||||
@@ -327,11 +374,16 @@ public class SpotSceneManager extends SceneManager
|
|||||||
// keep this feller around
|
// keep this feller around
|
||||||
_clobj = (ClusterObject)object;
|
_clobj = (ClusterObject)object;
|
||||||
|
|
||||||
|
// configure our cluster record and publish it
|
||||||
|
_cluster.clusterOid = _clobj.getOid();
|
||||||
|
_ssobj.addToClusters(_cluster);
|
||||||
|
|
||||||
// let any mapped users know about our cluster
|
// let any mapped users know about our cluster
|
||||||
Iterator iter = values().iterator();
|
Iterator iter = values().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
ClusteredBodyObject body = (ClusteredBodyObject)iter.next();
|
ClusteredBodyObject body = (ClusteredBodyObject)iter.next();
|
||||||
body.setClusterOid(_clobj.getOid());
|
body.setClusterOid(_clobj.getOid());
|
||||||
|
_clobj.addToOccupants(((BodyObject)body).getOid());
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we didn't manage to add our creating user when we first
|
// if we didn't manage to add our creating user when we first
|
||||||
@@ -354,6 +406,29 @@ public class SpotSceneManager extends SceneManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert the center back to "location" coordinates
|
||||||
|
coordsToLocation(tx/count, ty/count, _scratch);
|
||||||
|
_cluster.x = _scratch.x;
|
||||||
|
_cluster.y = _scratch.y;
|
||||||
|
}
|
||||||
|
|
||||||
protected void destroy ()
|
protected void destroy ()
|
||||||
{
|
{
|
||||||
Log.info("Cluster empty, going away " +
|
Log.info("Cluster empty, going away " +
|
||||||
@@ -362,6 +437,8 @@ public class SpotSceneManager extends SceneManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected ClusterObject _clobj;
|
protected ClusterObject _clobj;
|
||||||
|
protected Cluster _cluster = new Cluster();
|
||||||
|
protected Point _scratch = new Point();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A casted reference to our place object. */
|
/** A casted reference to our place object. */
|
||||||
|
|||||||
Reference in New Issue
Block a user