Beginnings of Spot services.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@618 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-11-13 02:25:36 +00:00
parent 17281a9db3
commit e82bc2b4fe
10 changed files with 807 additions and 2 deletions
@@ -0,0 +1,28 @@
//
// $Id: DisplaySpotScene.java,v 1.1 2001/11/13 02:25:35 mdb Exp $
package com.threerings.whirled.spot.client;
import com.threerings.whirled.client.DisplayScene;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
/**
* Makes available the spot scene information that the client needs to
* display a spot scene, to make requests to the server to move from
* location to location and to neighboring scenes and to display the same.
*/
public interface DisplaySpotScene extends DisplayScene
{
/**
* Returns an array of the locations in this scene (including portals
* which will be instances of {@link Portal}).
*/
public Location[] getLocations ();
/**
* Returns an array of the portals in this scene.
*/
public Portal[] getPortals ();
}
@@ -0,0 +1,85 @@
//
// $Id: DisplaySpotSceneImpl.java,v 1.1 2001/11/13 02:25:35 mdb Exp $
package com.threerings.whirled.spot.client;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.client.DisplaySceneImpl;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SpotSceneModel;
/**
* A basic implementation of the {@link DisplaySpotScene} interface which
* is used by default if no extended implementation is desired.
*/
public class DisplaySpotSceneImpl extends DisplaySceneImpl
{
/**
* Creates an instance that will obtain data from the supplied scene
* model and place config.
*/
public DisplaySpotSceneImpl (SpotSceneModel model, PlaceConfig config)
{
super(model, config);
// keep a casted reference to our model around
_model = model;
// sort out our locations and portals
int lcount = model.locationIds.length;
int pcount = model.portalIds.length;
_portals = new Portal[pcount];
_locations = new Location[lcount - pcount];
// because the portals ids are in the same order as the location
// ids, we can parse them in one pass
int pidx = 0;
for (int i = 0; i < lcount; i++) {
Location loc;
// stop checking for portals once we've parsed them all
int pid = (pidx < pcount) ? model.portalIds[pidx] : -1;
if (model.locationIds[i] == pid) {
// add this portal to the portals array
_portals[pidx] = new Portal(
pid, model.locationX[i], model.locationY[i],
model.locationOrients[i], model.neighborIds[pidx],
model.targetLocIds[pidx]);
loc = _portals[pidx];
pidx++;
} else {
loc = new Location(
model.locationIds[i], model.locationX[i],
model.locationY[i], model.locationOrients[i],
model.locationClusters[i]);
}
// everything goes into the locations array
_locations[i] = loc;
}
}
// documentation inherited
public Location[] getLocations ()
{
return _locations;
}
// documentation inherited
public Portal[] getPortals ()
{
return _portals;
}
/** The data that makes up our scene. */
protected SpotSceneModel _model;
/** An array of the locations (and portals) in this scene. */
protected Location[] _locations;
/** An array of just the portals in this scene. */
protected Portal[] _portals;
}
@@ -0,0 +1,97 @@
//
// $Id: Location.java,v 1.1 2001/11/13 02:25:35 mdb Exp $
package com.threerings.whirled.spot.data;
/**
* A location represents a place to stand in a scene. More specifically,
* it is a geometric location in a scene with an orientation that would be
* assumed by any body sprite standing in that location. Locations may
* optionally belong to a cluster, which associates them with a group of
* locations for speaking purposes (bodies in the same cluster can "hear"
* one another speak).
*/
public class Location
{
/** This location's unique identifier. */
public int locationId;
/** This location's x coordinate (interpreted by the display system). */
public int x;
/** This location's y coordinate (interpreted by the display system). */
public int y;
/** This location's y orientation (interpreted by the display system). */
public int orientation;
/** The cluster to which this location belongs or -1 if it belongs to
* no cluster. */
public int clusterIndex;
/**
* Constructs a location with the supplied values.
*/
public Location (int id, int x, int y, int orientation, int clusterIndex)
{
this.locationId = id;
this.x = x;
this.y = y;
this.orientation = orientation;
this.clusterIndex = clusterIndex;
}
/**
* Location equality is determined by location id unless the location
* id is zero, in which case equality is determined by equal x and y
* coordinates. This allows locations to be created by the editor,
* where location ids cannot yet have been assigned because they are
* assigned by the scene repository, and manipulated as comparable
* entities.
*/
public boolean equals (Object other)
{
if (other instanceof Location) {
Location oloc = (Location)other;
if (locationId == 0 && oloc.locationId == 0) {
return (x == oloc.x && y == oloc.y);
} else {
return (locationId == oloc.locationId);
}
} else {
return false;
}
}
/**
* Computes a reasonable hashcode for location instances.
*/
public int hashCode ()
{
return (locationId == 0) ? (x ^ y) : locationId;
}
/**
* Generates a string representation of this location instance.
*/
public String toString ()
{
StringBuffer buf = new StringBuffer("[");
toString(buf);
return buf.append("]").toString();
}
/**
* An efficient, extensible mechanism for generating a string
* representation of locations and derived classes.
*/
protected void toString (StringBuffer buf)
{
buf.append("id=").append(locationId);
buf.append(", x=").append(x);
buf.append(", y=").append(y);
buf.append(", orient=").append(orientation);
buf.append(", cluster=").append(clusterIndex);
}
}
@@ -0,0 +1,48 @@
//
// $Id: Portal.java,v 1.1 2001/11/13 02:25:35 mdb Exp $
package com.threerings.whirled.spot.data;
/**
* A portal is a location, but one that represents an exit to another
* scene rather than a place to stand in the current scene. A body sprite
* would walk over to a portal's coordinates and then either proceed off
* of the edge of the display, or open a door and walk through it, or
* fizzle away in a Star Trekkian transporter style or whatever is
* appropriate for the game in question. It contains information on the
* scene to which the body exits when using this portal and the location
* at which the body sprite should appear in that target scene.
*
* <p> Though portals extend locations, they generally would not occupy a
* cluster (because that wouldn't make much sense) and as such should
* always have a {@link #clusterIndex} of -1.
*/
public class Portal extends Location
{
/** The scene identifier of the scene to which a body will exit when
* they "use" this portal. */
public int targetSceneId;
/** The location identifier of the location at which a body will enter
* the target scene when they "use" this portal. */
public int targetLocationId;
/**
* Constructs a portal with the supplied values.
*/
public Portal (int id, int x, int y, int orientation,
int targetSceneId, int targetLocationId)
{
super(id, x, y, orientation, -1);
this.targetSceneId = targetSceneId;
this.targetLocationId = targetLocationId;
}
// documentation inherited
protected void toString (StringBuffer buf)
{
super.toString(buf);
buf.append(", targetScene=").append(targetSceneId);
buf.append(", targetLoc=").append(targetLocationId);
}
}
@@ -0,0 +1,129 @@
//
// $Id: SpotSceneModel.java,v 1.1 2001/11/13 02:25:35 mdb Exp $
package com.threerings.whirled.spot.data;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import com.threerings.whirled.data.SceneModel;
/**
* The spot scene model extends the standard scene model with information
* on locations, clusters and portals. Locations (and by extension,
* portals) are referenced by a globally unique identifier so that portals
* can stably reference the target location in the scene to which they
* connect. The scene repository is responsible for assigning this unique
* identifier. Clusters are tracked by index rather than unique
* identifier, but only exist as an attribute of locations (a location
* belongs to zero or one clusters).
*/
public class SpotSceneModel extends SceneModel
{
/** The unique identifier of each location in this scene (including
* portals). */
public int[] locationIds;
/** The x coordinates of the locations in this scene (including
* portals). */
public int[] locationX;
/** The y coordinates of the locations in this scene (including
* portals). */
public int[] locationY;
/** The orientations associated with the locations in this scene
* (including portals). */
public int[] locationOrients;
/** The cluster index of each location in this scene, which can be -1
* to indicate that the location is not a member of any cluster
* (including portals, which should always be -1). */
public int[] locationClusters;
/** The location id of the default entrance to this scene. If a body
* enters the scene without coming from another scene, this is the
* location at which they would appear. */
public int defaultEntranceId;
/** The location id of each portal in this scene. These must map, in
* order, to the neighboring scene ids specified in {@link
* #neighborIds}. The neighbor ids being the scene ids of the scenes
* to which these portals take a body when "used". Additionally, these
* must occur in the same order that the location ids appear in the
* above array. */
public int[] portalIds;
/** Contains the location ids of the entry location in the target
* scene to which this scene's portals connect. Portals in this scene
* connect to locations in other scenes as dictated by these
* values. */
public int[] targetLocIds;
// documentation inherited
public void writeTo (DataOutputStream out)
throws IOException
{
super.writeTo(out);
// write out our location info
int lcount = locationIds.length;
out.writeInt(lcount);
for (int i = 0; i < lcount; i++) {
out.writeInt(locationIds[i]);
out.writeInt(locationX[i]);
out.writeInt(locationY[i]);
out.writeInt(locationOrients[i]);
out.writeInt(locationClusters[i]);
}
// write out our default entrance id
out.writeInt(defaultEntranceId);
// write out our portal info; we need not serialize the portal
// count because our based class already did when writing out the
// neighborIds array
int pcount = portalIds.length;
for (int i = 0; i < pcount; i++) {
out.writeInt(portalIds[i]);
out.writeInt(targetLocIds[i]);
}
}
// documentation inherited
public void readFrom (DataInputStream in)
throws IOException
{
super.readFrom(in);
// read in our location info
int lcount = in.readInt();
locationIds = new int[lcount];
locationX = new int[lcount];
locationY = new int[lcount];
locationOrients = new int[lcount];
locationClusters = new int[lcount];
for (int i = 0; i < lcount;i++) {
locationIds[i] = in.readInt();
locationX[i] = in.readInt();
locationY[i] = in.readInt();
locationOrients[i] = in.readInt();
locationClusters[i] = in.readInt();
}
// read in our default entrance id
defaultEntranceId = in.readInt();
// and read in our portal info
int pcount = neighborIds.length;
portalIds = new int[pcount];
targetLocIds = new int[pcount];
for (int i = 0; i < pcount; i++) {
portalIds[i] = in.readInt();
targetLocIds[i] = in.readInt();
}
}
}
@@ -0,0 +1,47 @@
//
// $Id: RuntimeSpotScene.java,v 1.1 2001/11/13 02:25:35 mdb Exp $
package com.threerings.whirled.spot.server;
import com.threerings.whirled.server.RuntimeScene;
/**
* Makes available the spot scene information that the server needs to
* manage requests to move from location to location, to enter and exit a
* scene at a location and to manage speaking among bodies that occupy the
* same clusters.
*/
public interface RuntimeSpotScene extends RuntimeScene
{
/**
* Returns the total number of clusters in this scene.
*/
public int getClusterCount ();
/**
* Returns the cluster index associated with the specified location or
* -1 if the location is not associated with a cluster.
*/
public int getClusterIndex (int locationId);
/**
* Returns the location id of the default entrance to this scene. If a
* body enters the scene at logon time rather than entering from some
* other scene, this is the location at which they would appear.
*/
public int getDefaultEntranceId ();
/**
* Returns the target scene id associated with the specified portal
* (identified by its location id) or -1 if the location id specified
* is not a portal.
*/
public int getTargetSceneId (int locationId);
/**
* Returns the target location id associated with the specified portal
* (identified by its location id) or -1 if the location id specified
* is not a portal.
*/
public int getTargetLocationId (int locationId);
}
@@ -0,0 +1,109 @@
//
// $Id: RuntimeSpotSceneImpl.java,v 1.1 2001/11/13 02:25:35 mdb Exp $
package com.threerings.whirled.spot.server;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.server.RuntimeSceneImpl;
import com.threerings.whirled.spot.data.SpotSceneModel;
/**
* A basic implementation of the {@link RuntimeSpotScene} interface which
* is used by default if no extended implementation is desired.
*/
public class RuntimeSpotSceneImpl extends RuntimeSceneImpl
{
/**
* Creates an instance that will obtain data from the supplied scene
* model and place config.
*/
public RuntimeSpotSceneImpl (SpotSceneModel model, PlaceConfig config)
{
super(model, config);
// keep a casted reference to our scene model around
_model = model;
// determine the highest cluster index
int lcount = _model.locationIds.length;
for (int i = 0; i < lcount; i++) {
int cidx = _model.locationClusters[i];
if (cidx > _clusterCount) {
_clusterCount = cidx;
}
}
// now increment by one to get the count rather than the highest
// cluster index
_clusterCount++;
}
// documentation inherited
public int getClusterCount ()
{
return _clusterCount;
}
// documentation inherited
public int getClusterIndex (int locationId)
{
int lidx = getLocationIndex(locationId);
return (lidx == -1) ? -1 : _model.locationClusters[lidx];
}
// documentation inherited
public int getDefaultEntranceId ()
{
return _model.defaultEntranceId;
}
// documentation inherited
public int getTargetSceneId (int locationId)
{
int pidx = getPortalIndex(locationId);
return (pidx == -1) ? -1 : _model.neighborIds[pidx];
}
// documentation inherited
public int getTargetLocationId (int locationId)
{
int pidx = getPortalIndex(locationId);
return (pidx == -1) ? -1 : _model.targetLocIds[pidx];
}
/**
* Returns the index of the specified location in the model's internal
* location arrays.
*/
protected int getLocationIndex (int locationId)
{
int lcount = _model.locationIds.length;
for (int i = 0; i < lcount; i++) {
if (_model.locationIds[i] == locationId) {
return i;
}
}
return -1;
}
/**
* Returns the index of the specified portal in the model's internal
* portal arrays.
*/
protected int getPortalIndex (int portalId)
{
int pcount = _model.portalIds.length;
for (int i = 0; i < pcount; i++) {
if (_model.portalIds[i] == portalId) {
return i;
}
}
return -1;
}
/** A casted reference to our scene model. */
protected SpotSceneModel _model;
/** The total number of clusters in this scene. */
protected int _clusterCount = -1;
}
@@ -0,0 +1,60 @@
//
// $Id: EditableSpotScene.java,v 1.1 2001/11/13 02:25:36 mdb Exp $
package com.threerings.whirled.spot.tools;
import com.threerings.whirled.tools.EditableScene;
import com.threerings.whirled.spot.client.DisplaySpotScene;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SpotSceneModel;
/**
* The editable spot scene interface is used in the offline scene building
* tools as well as by the tools that load those prototype scenes into the
* runtime database. Accordingly, it provides a means for modifying scene
* values and for obtaining access to the underlying scene models that
* represent the underlying scene information.
*
* @see EditableScene
*/
public interface EditableSpotScene
extends DisplaySpotScene, EditableScene
{
/**
* Sets the location id of the default entrance to this scene.
*/
public void setDefaultEntranceId (int defaultEntranceId);
/**
* Adds a location to this scene.
*/
public void addLocation (Location location);
/**
* Removes the specified location from the scene.
*/
public void removeLocation (Location location);
/**
* Adds a portal to this scene (it should be added appropriately to
* both the location and portal arrays).
*/
public void addPortal (Portal portal);
/**
* Removes a portal from this scene (it should be removed accordingly
* from both the location and portal arrays).
*/
public void removePortal (Portal portal);
/**
* Implementations must provide a scene model that represents the
* current state of this editable scene in response to a call to this
* method. Whether they maintain an up to date scene model all along
* or generate one at the time this method is called is up to the
* implementation.
*/
public SpotSceneModel getSpotSceneModel ();
}
@@ -0,0 +1,203 @@
//
// $Id: EditableSpotSceneImpl.java,v 1.1 2001/11/13 02:25:36 mdb Exp $
package com.threerings.whirled.spot.tools;
import com.samskivert.util.ListUtil;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.tools.EditableSceneImpl;
import com.threerings.whirled.spot.client.DisplaySpotSceneImpl;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SpotSceneModel;
import com.threerings.whirled.spot.Log;
/**
* The editable spot scene interface is used in the offline scene building
* tools as well as by the tools that load those prototype scenes into the
* runtime database. Accordingly, it provides a means for modifying scene
* values and for obtaining access to the underlying scene models that
* represent the underlying scene information.
*
* <p> Scrutinizers of the code might cringe at the somewhat inefficient
* array manipulation used to preserve the integrity of the arrays
* returned by {@link #getLocations} and {@link #getPortals}. Since we
* expect reading to happen more often than modifying, this seemed a
* reasonable tradeoff, and one should also note that this class will only
* ever be used in the offline editor and not in any performance
* constrained runtime system.
*
* @see com.threerings.whirled.tools.EditableScene
*/
public class EditableSpotSceneImpl
extends DisplaySpotSceneImpl
implements EditableSpotScene
{
/**
* Creates an instance that will obtain data from the supplied scene
* model and update it when changes are made.
*/
public EditableSpotSceneImpl (SpotSceneModel model)
{
super(model, null);
// Java doesn't support multiple inheritance (we'll let the reader
// decide whether or not that's unfortunate), so we have to
// instantiate an EditableSceneImpl delegate to handle the
// extensions to DisplayScene provided by EditableScene because
// we're extending from the DisplaySceneImpl class chain
_edelegate = new EditableSceneImpl(model);
}
// documentation inherited
public void setId (int sceneId)
{
_edelegate.setId(sceneId);
}
// documentation inherited
public void setVersion (int version)
{
_edelegate.setVersion(version);
}
// documentation inherited
public void setNeighborIds (int[] neighborIds)
{
String errmsg = "Neighbor IDs can't be set directly in the " +
"EditableSpotScene because we need to know the associated " +
"location information to go along with our neighbor connections.";
throw new RuntimeException(errmsg);
}
// documentation inherited
public void setDefaultEntranceId (int defaultEntranceId)
{
_model.defaultEntranceId = defaultEntranceId;
}
// documentation inherited
public void addLocation (Location location)
{
// add this location to the end of the list
int lcount = _locations.length;
Location[] nlocs = new Location[lcount+1];
System.arraycopy(_locations, 0, nlocs, 0, lcount);
nlocs[lcount] = location;
_locations = nlocs;
}
// documentation inherited
public void removeLocation (Location location)
{
// obtain the index of this location
int lidx = ListUtil.indexOfEqual(_locations, location);
if (lidx == -1) {
Log.warning("Can't remove location that isn't in our array " +
"[loc=" + location + "].");
} else {
// create a new array minus this location
int lcount = _locations.length;
Location[] nlocs = new Location[lcount-1];
System.arraycopy(_locations, 0, nlocs, 0, lidx);
System.arraycopy(_locations, lidx+1, nlocs, lidx, lcount-lidx-1);
_locations = nlocs;
}
}
// documentation inherited
public void addPortal (Portal portal)
{
// add it to the locations array as well
addLocation(portal);
// now add it to the end of the _portals array
int pcount = _portals.length;
Portal[] nports = new Portal[pcount+1];
System.arraycopy(_portals, 0, nports, 0, pcount);
nports[pcount] = portal;
_portals = nports;
}
// documentation inherited
public void removePortal (Portal portal)
{
// remove it from the locations array
removeLocation(portal);
// and remove it from the portals array
int pidx = ListUtil.indexOfEqual(_portals, portal);
if (pidx == -1) {
Log.warning("Can't remove portal that isn't in our array " +
"[port=" + portal + "].");
} else {
// create a new array minus this portal
int pcount = _portals.length;
Portal[] nports = new Portal[pcount-1];
System.arraycopy(_portals, 0, nports, 0, pidx);
System.arraycopy(_portals, pidx+1, nports, pidx, pcount-pidx-1);
_portals = nports;
}
}
// documentation inherited
public SceneModel getSceneModel ()
{
flushToModel();
return _edelegate.getSceneModel();
}
// documentation inherited
public SpotSceneModel getSpotSceneModel ()
{
flushToModel();
return _model;
}
/**
* This ensures that the modifications we've made to the location and
* portal arrays are flushed to the model. It is called before
* returning our model back to the caller.
*/
protected void flushToModel ()
{
// flush the locations
int lcount = _locations.length;
_model.locationIds = new int[lcount];
_model.locationX = new int[lcount];
_model.locationY = new int[lcount];
_model.locationOrients = new int[lcount];
_model.locationClusters = new int[lcount];
for (int i = 0; i < lcount; i++) {
Location loc = _locations[i];
_model.locationIds[i] = loc.locationId;
_model.locationX[i] = loc.x;
_model.locationY[i] = loc.y;
_model.locationOrients[i] = loc.orientation;
_model.locationClusters[i] = loc.clusterIndex;
}
// flush the portals
int pcount = _portals.length;
_model.portalIds = new int[pcount];
_model.neighborIds = new int[pcount];
_model.targetLocIds = new int[pcount];
for (int i = 0; i < pcount; i++) {
Portal port = _portals[i];
_model.portalIds[i] = port.locationId;
_model.neighborIds[i] = port.targetSceneId;
_model.targetLocIds[i] = port.targetLocationId;
}
}
/** We have to delegate some methods to this guy. */
protected EditableSceneImpl _edelegate;
}
@@ -1,9 +1,8 @@
//
// $Id: EditableSceneImpl.java,v 1.1 2001/11/12 20:56:56 mdb Exp $
// $Id: EditableSceneImpl.java,v 1.2 2001/11/13 02:25:36 mdb Exp $
package com.threerings.whirled.tools;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.client.DisplaySceneImpl;
import com.threerings.whirled.data.SceneModel;