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;
|
||||
|
||||
@@ -44,11 +44,11 @@ public interface SpotService extends InvocationService
|
||||
* location.
|
||||
*
|
||||
* @param loc the 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 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -14,4 +14,7 @@ public class SpotSceneObject extends SceneObject
|
||||
/** A distributed set containing {@link SceneLocation} records for all
|
||||
* occupants of this scene. */
|
||||
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;
|
||||
|
||||
@@ -14,10 +14,16 @@ public class SpotSceneObject extends SceneObject
|
||||
/** The field name of the <code>occupantLocs</code> field. */
|
||||
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
|
||||
* occupants of this scene. */
|
||||
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
|
||||
* <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;
|
||||
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;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.util.Iterator;
|
||||
|
||||
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.spot.Log;
|
||||
import com.threerings.whirled.spot.data.Cluster;
|
||||
import com.threerings.whirled.spot.data.ClusterObject;
|
||||
import com.threerings.whirled.spot.data.ClusteredBodyObject;
|
||||
import com.threerings.whirled.spot.data.Location;
|
||||
@@ -171,6 +173,8 @@ public class SpotSceneManager extends SceneManager
|
||||
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
|
||||
// indicate to the client that their avatar should be moved from
|
||||
// its current position to their new position
|
||||
@@ -186,16 +190,10 @@ public class SpotSceneManager extends SceneManager
|
||||
}
|
||||
|
||||
// handle the cluster situation
|
||||
switch (cluster) {
|
||||
case 0:
|
||||
createNewCluster(source);
|
||||
break;
|
||||
case -1:
|
||||
if (cluster == -1) {
|
||||
removeFromCluster(source.getOid());
|
||||
break;
|
||||
default:
|
||||
addToCluster(cluster, source);
|
||||
break;
|
||||
} else {
|
||||
createOrJoinCluster(cluster, source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,25 +217,38 @@ public class SpotSceneManager extends SceneManager
|
||||
|
||||
/**
|
||||
* 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);
|
||||
if (clrec == null) {
|
||||
// this isn't completely impossible as the last user might
|
||||
// leave a cluster just as another user is entering it, but
|
||||
// before the entering user's client was informed that the
|
||||
// cluster went away
|
||||
Log.info("Can't add user to non-existent cluster; " +
|
||||
"creating a new one just for them " +
|
||||
"[memberOid=" + memberOid +
|
||||
", joiner=" + joiner.who() + "].");
|
||||
clrec = new ClusterRecord();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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
|
||||
* one another.
|
||||
*/
|
||||
protected static class ClusterRecord extends HashIntMap
|
||||
protected class ClusterRecord extends HashIntMap
|
||||
implements Subscriber
|
||||
{
|
||||
public ClusterRecord ()
|
||||
@@ -284,11 +323,14 @@ public class SpotSceneManager extends SceneManager
|
||||
public boolean addBody (BodyObject body)
|
||||
{
|
||||
if (body instanceof ClusteredBodyObject) {
|
||||
put(body.getOid(), body);
|
||||
_cluster.occupants++;
|
||||
recomputeCenter();
|
||||
if (_clobj != null) {
|
||||
_ssobj.updateClusters(_cluster);
|
||||
_clobj.addToOccupants(body.getOid());
|
||||
((ClusteredBodyObject)body).setClusterOid(_clobj.getOid());
|
||||
}
|
||||
put(body.getOid(), body);
|
||||
_clobj.addToOccupants(body.getOid());
|
||||
return true;
|
||||
|
||||
} else {
|
||||
@@ -308,7 +350,12 @@ public class SpotSceneManager extends SceneManager
|
||||
", size=" + size() + ", who=" + bodyOid + "].");
|
||||
} else {
|
||||
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
|
||||
@@ -327,11 +374,16 @@ public class SpotSceneManager extends SceneManager
|
||||
// keep this feller around
|
||||
_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
|
||||
Iterator iter = values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
ClusteredBodyObject body = (ClusteredBodyObject)iter.next();
|
||||
body.setClusterOid(_clobj.getOid());
|
||||
_clobj.addToOccupants(((BodyObject)body).getOid());
|
||||
}
|
||||
|
||||
// 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 ()
|
||||
{
|
||||
Log.info("Cluster empty, going away " +
|
||||
@@ -362,6 +437,8 @@ 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. */
|
||||
|
||||
Reference in New Issue
Block a user