The amazing refactor forteen hundred billion: eliminated "locations",

portals will by dynamically created, combined display/runtime/editable
scenes into one, enhanced support for modifying scenes and distributing
updates to the clients, various other small stuff that should not be
sweated.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2274 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2003-02-12 07:23:32 +00:00
parent a54b3e279c
commit 2a4385ad33
67 changed files with 2073 additions and 2724 deletions
@@ -1,20 +0,0 @@
//
// $Id: DefaultDisplaySceneFactory.java,v 1.1 2001/11/18 04:09:23 mdb Exp $
package com.threerings.whirled.client;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.data.SceneModel;
/**
* The default display scene factory creates {@link DisplaySceneImpl}
* instances.
*/
public class DefaultDisplaySceneFactory implements DisplaySceneFactory
{
// documentation inherited
public DisplayScene createScene (SceneModel model, PlaceConfig config)
{
return new DisplaySceneImpl(model, config);
}
}
@@ -1,50 +0,0 @@
//
// $Id: DisplayScene.java,v 1.2 2001/12/12 19:06:15 mdb Exp $
package com.threerings.whirled.client;
import com.threerings.crowd.data.PlaceConfig;
/**
* This interface makes available the scene information that is needed by
* a client to display a scene. At this basic level, not much information
* is available, but extensions to this interface begin to create a more
* comprehensive picture of a scene in a system built from the Whirled
* services.
*
* <p> Additionally, at this basic level, the <code>DisplayScene</code>
* does not differ greatly (or at all) from the {@link
* com.threerings.whirled.server.RuntimeScene} interface, but the
* distinction provides a mechanism for handling the more substantial
* differences that appear in more sophisticated extensions to the base
* scene services.
*/
public interface DisplayScene
{
/**
* Returns the unique identifier for this scene.
*/
public int getId ();
/**
* Returns the name of this scene.
*/
public String getName ();
/**
* Returns the version number of this scene.
*/
public int getVersion ();
/**
* Returns the list of scene ids of this scene's neighbors.
*/
public int[] getNeighborIds ();
/**
* Returns the place config that can be used to determine which place
* controller instance should be used to display this scene as well as
* to obtain runtime configuration information.
*/
public PlaceConfig getPlaceConfig ();
}
@@ -1,24 +0,0 @@
//
// $Id: DisplaySceneFactory.java,v 1.1 2001/11/12 20:56:55 mdb Exp $
package com.threerings.whirled.client;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.data.SceneModel;
/**
* When resolving a scene, the scene director loads a scene model from the
* scene repository, but it needs an external entity to convert that scene
* model into the appropriate implementation of {@link DisplayScene}. The
* display scene factory interface provides the mechanism by which users
* of the Whirled system can create the appropriate instances.
*/
public interface DisplaySceneFactory
{
/**
* This is called by the scene director after it has loaded the scene
* model from the scene repository and obtained the place config from
* a successful <code>moveTo</code> request.
*/
public DisplayScene createScene (SceneModel model, PlaceConfig config);
}
@@ -1,60 +0,0 @@
//
// $Id: DisplaySceneImpl.java,v 1.2 2001/12/12 19:06:15 mdb Exp $
package com.threerings.whirled.client;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.data.SceneModel;
/**
* A basic implementation of the {@link DisplayScene} interface which is
* used by default if no extended implementation is desired.
*/
public class DisplaySceneImpl implements DisplayScene
{
/**
* Creates an instance that will obtain data from the supplied scene
* model and place config.
*/
public DisplaySceneImpl (SceneModel model, PlaceConfig config)
{
_model = model;
_config = config;
}
// documentation inherited
public int getId ()
{
return _model.sceneId;
}
// documentation inherited
public String getName ()
{
return _model.sceneName;
}
// documentation inherited
public int getVersion ()
{
return _model.version;
}
// documentation inherited
public int[] getNeighborIds ()
{
return _model.neighborIds;
}
// documentation inherited
public PlaceConfig getPlaceConfig ()
{
return _config;
}
/** A reference to our scene model. */
protected SceneModel _model;
/** A reference to our place configuration. */
protected PlaceConfig _config;
}
@@ -1,5 +1,5 @@
//
// $Id: SceneDirector.java,v 1.23 2002/12/09 04:44:33 shaper Exp $
// $Id: SceneDirector.java,v 1.24 2003/02/12 07:23:30 mdb Exp $
package com.threerings.whirled.client;
@@ -19,10 +19,13 @@ import com.threerings.crowd.data.PlaceObject;
import com.threerings.whirled.Log;
import com.threerings.whirled.client.persist.SceneRepository;
import com.threerings.whirled.data.Scene;
import com.threerings.whirled.data.SceneCodes;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.util.NoSuchSceneException;
import com.threerings.whirled.util.SceneFactory;
import com.threerings.whirled.util.WhirledContext;
import com.threerings.whirled.data.SceneUpdate;
/**
* The scene director is the client's interface to all things scene
@@ -49,10 +52,10 @@ public class SceneDirector extends BasicDirector
* @param screp the entity from which the scene director will load
* scene data from the local client scene storage.
* @param dsfact the factory that knows which derivation of {@link
* DisplayScene} to create for the current system.
* Scene} to create for the current system.
*/
public SceneDirector (WhirledContext ctx, LocationDirector locdir,
SceneRepository screp, DisplaySceneFactory dsfact)
SceneRepository screp, SceneFactory fact)
{
super(ctx);
@@ -60,7 +63,7 @@ public class SceneDirector extends BasicDirector
_ctx = ctx;
_locdir = locdir;
_screp = screp;
_dsfact = dsfact;
_fact = fact;
// set ourselves up as a failure handler with the location
// director because we need to do special processing
@@ -75,7 +78,7 @@ public class SceneDirector extends BasicDirector
* Returns the display scene object associated with the scene we
* currently occupy or null if we currently occupy no scene.
*/
public DisplayScene getScene ()
public Scene getScene ()
{
return _scene;
}
@@ -202,25 +205,84 @@ public class SceneDirector extends BasicDirector
if (_model == null) {
Log.warning("Aiya! Unable to load scene [sid=" + _sceneId +
", plid=" + placeId + "].");
return;
}
// and finally create a display scene instance with the model and
// the place config
_scene = _dsfact.createScene(_model, config);
_scene = _fact.createScene(_model, config);
}
// documentation inherited from interface
public void moveSucceededPlusUpdate (
public void moveSucceededWithUpdates (
int placeId, PlaceConfig config, SceneUpdate[] updates)
{
// apply the updates to our cached scene
SceneModel model = loadSceneModel(_pendingSceneId);
boolean failure = false;
for (int ii = 0; ii < updates.length; ii++) {
try {
updates[ii].validate(model);
} catch (IllegalStateException ise) {
Log.warning("Scene update failed validation [model=" + model +
", update=" + updates[ii] +
", error=" + ise.getMessage() + "].");
failure = true;
break;
}
try {
updates[ii].apply(model);
} catch (Exception e) {
Log.warning("Failure applying scene update [model=" + model +
", update=" + updates[ii] + "].");
Log.logStackTrace(e);
failure = true;
break;
}
}
if (failure) {
// delete the now half-booched scene model from the repository
try {
_screp.deleteSceneModel(_pendingSceneId);
} catch (IOException ioe) {
Log.warning("Failure removing booched scene model " +
"[sceneId=" + _pendingSceneId + "].");
Log.logStackTrace(ioe);
}
// act as if the scene move failed, though we'll be in a funny
// state because the server thinks we've changed scenes, but
// the client can try again without its booched scene model
requestFailed(INTERNAL_ERROR);
return;
}
// store the updated scene in the repository
try {
_screp.storeSceneModel(model);
} catch (IOException ioe) {
Log.warning("Failed to update repository with updated scene " +
"[sceneId=" + model.sceneId + "].");
Log.logStackTrace(ioe);
}
// finally pass through to the normal success handler
moveSucceeded(placeId, config);
}
// documentation inherited from interface
public void moveSucceededWithScene (
int placeId, PlaceConfig config, SceneModel model)
{
// update the model in the repository
try {
_screp.updateSceneModel(model);
_screp.storeSceneModel(model);
} catch (IOException ioe) {
Log.warning("Danger Will Robinson! We were unable to update " +
"our scene cache with a new version of a scene " +
"provided by the server " +
"[newVersion=" + model.version + "].");
Log.warning("Failed to update repository with new version " +
"[sceneId=" + model.sceneId +
", nvers=" + model.version + "].");
Log.logStackTrace(ioe);
}
@@ -376,14 +438,14 @@ public class SceneDirector extends BasicDirector
/** The entity via which we load scene data. */
protected SceneRepository _screp;
/** The entity we use to create display scenes from scene models. */
protected DisplaySceneFactory _dsfact;
/** The entity we use to create scenes from scene models. */
protected SceneFactory _fact;
/** A cache of scene model information. */
protected HashIntMap _scache = new HashIntMap();
/** The display scene object for the scene we currently occupy. */
protected DisplayScene _scene;
protected Scene _scene;
/** The scene model for the scene we currently occupy. */
protected SceneModel _model;
@@ -1,5 +1,5 @@
//
// $Id: SceneService.java,v 1.9 2002/08/14 19:07:57 mdb Exp $
// $Id: SceneService.java,v 1.10 2003/02/12 07:23:30 mdb Exp $
package com.threerings.whirled.client;
@@ -7,7 +7,9 @@ import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
/**
* The scene service class provides the client interface to the scene
@@ -34,11 +36,23 @@ public interface SceneService extends InvocationService
*
* @param placeId the place object id of the newly occupied scene.
* @param config metadata related to the newly occupied scene.
* @param model the most recent scene data for the newly occupied
* scene.
* @param updates updates that must be applied to the client's
* copy of a scene model to bring it up to date.
*/
public void moveSucceededPlusUpdate (
int placeId, PlaceConfig config, SceneModel model);
public void moveSucceededWithUpdates (int placeId, PlaceConfig config,
SceneUpdate[] updates);
/**
* Indicates that a move succeeded and that the client's cached
* scene information should be updated with the supplied data.
*
* @param placeId the place object id of the newly occupied scene.
* @param config metadata related to the newly occupied scene.
* @param model a fresh copy of the most recent scene data for the
* newly occupied scene.
*/
public void moveSucceededWithScene (int placeId, PlaceConfig config,
SceneModel model);
}
/**
@@ -46,9 +60,9 @@ public interface SceneService extends InvocationService
* scene.
*
* @param sceneId the scene id to which we want to move.
* @param sceneVers the version number of the scene object that we
* have in our local repository.
* @param version the version number of the scene object that we have
* in our local repository.
*/
public void moveTo (Client client, int sceneId,
int sceneVers, SceneMoveListener listener);
public void moveTo (Client client, int sceneId, int version,
SceneMoveListener listener);
}
@@ -1,5 +1,5 @@
//
// $Id: SceneRepository.java,v 1.3 2001/11/12 20:56:55 mdb Exp $
// $Id: SceneRepository.java,v 1.4 2003/02/12 07:23:30 mdb Exp $
package com.threerings.whirled.client.persist;
@@ -10,17 +10,14 @@ import com.threerings.whirled.util.NoSuchSceneException;
/**
* The scene repository provides access to a persistent repository of
* scene information. The scene models in the repository can be updated
* with scene data fetched from the server as well as with new scene
* bundles that are periodically distributed to bring all clients into
* sync with the latest snapshot of the scene database.
* scene information.
*
* @see SceneModel
*/
public interface SceneRepository
{
/**
* Fetches the mode for the scene with the specified scene id.
* Fetches the model for the scene with the specified id.
*
* @exception IOException thrown if an error occurs attempting to load
* the scene data.
@@ -31,13 +28,20 @@ public interface SceneRepository
throws IOException, NoSuchSceneException;
/**
* Updates this scene model in the repository. This is generally only
* called when the server has provided us with a newer version of a
* scene than we previously had in our local repository.
* Updates or inserts this scene model as appropriate.
*
* @exception IOException thrown if an error occurs attempting to
* update the scene data.
* access the repository.
*/
public void updateSceneModel (SceneModel model)
public void storeSceneModel (SceneModel model)
throws IOException;
/**
* Deletes the specified scene model from the repository.
*
* @exception IOException thrown if an error occurs attempting to
* access the repository.
*/
public void deleteSceneModel (int sceneId)
throws IOException;
}
@@ -0,0 +1,18 @@
//
// $Id: AuxModel.java,v 1.1 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.data;
import com.threerings.io.Streamable;
/**
* An interface that must be implemented by auxiliary scene models.
*/
public interface AuxModel extends Streamable, Cloneable
{
/**
* Creates a clone of this auxiliary model.
*/
public Object clone ()
throws CloneNotSupportedException;
}
@@ -0,0 +1,57 @@
//
// $Id: Scene.java,v 1.8 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.data;
import com.threerings.crowd.data.PlaceConfig;
/**
* This interface makes available basic scene information. At this basic
* level, not much information is available, but extensions to this
* interface begin to create a more comprehensive picture of a scene in a
* system built from the Whirled services.
*/
public interface Scene
{
/**
* Returns the unique identifier for this scene.
*/
public int getId ();
/**
* Returns the human readable name of this scene.
*/
public String getName ();
/**
* Returns the version number of this scene.
*/
public int getVersion ();
/**
* Returns the place config that can be used to determine which place
* controller instance should be used to display this scene as well as
* to obtain runtime configuration information.
*/
public PlaceConfig getPlaceConfig ();
/**
* Sets this scene's unique identifier.
*/
public void setId (int sceneId);
/**
* Sets the human readable name of this scene.
*/
public void setName (String name);
/**
* Sets this scene's version number.
*/
public void setVersion (int version);
/**
* Returns the scene model from which this scene was created.
*/
public SceneModel getSceneModel ();
}
@@ -0,0 +1,94 @@
//
// $Id: SceneImpl.java,v 1.1 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.data;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.data.SceneModel;
/**
* An implementation of the {@link Scene} interface.
*/
public class SceneImpl implements Scene
{
/**
* Creates an instance that will obtain data from the supplied scene
* model and place config.
*/
public SceneImpl (SceneModel model, PlaceConfig config)
{
_model = model;
_config = config;
}
/**
* Instantiates a blank scene implementation. No place config will be
* associated with this scene.
*/
public SceneImpl ()
{
_model = SceneModel.blankSceneModel();
}
// documentation inherited
public int getId ()
{
return _model.sceneId;
}
// documentation inherited
public String getName ()
{
return _model.name;
}
// documentation inherited
public int getVersion ()
{
return _model.version;
}
// documentation inherited
public PlaceConfig getPlaceConfig ()
{
return _config;
}
// documentation inherited from interface
public void setId (int sceneId)
{
_model.sceneId = sceneId;
}
// documentation inherited from interface
public void setName (String name)
{
_model.name = name;
}
// documentation inherited from interface
public void setVersion (int version)
{
_model.version = version;
}
// documentation inherited from interface
public SceneModel getSceneModel ()
{
return _model;
}
/**
* Generates a string representation of this instance.
*/
public String toString ()
{
return "[model=" + _model + ", config=" + _config + "]";
}
/** A reference to our scene model. */
protected SceneModel _model;
/** A reference to our place configuration. */
protected PlaceConfig _config;
}
@@ -1,5 +1,5 @@
//
// $Id: SceneMarshaller.java,v 1.2 2002/08/20 19:38:15 mdb Exp $
// $Id: SceneMarshaller.java,v 1.3 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.data;
@@ -10,6 +10,7 @@ import com.threerings.presents.dobj.InvocationResponseEvent;
import com.threerings.whirled.client.SceneService;
import com.threerings.whirled.client.SceneService.SceneMoveListener;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
/**
* Provides the implementation of the {@link SceneService} interface
@@ -17,10 +18,6 @@ import com.threerings.whirled.data.SceneModel;
* on the server. Also provides an implementation of the response listener
* interfaces that marshall the response arguments and deliver them back
* to the requesting client.
*
* <p> Generated from <code>
* $Id: SceneMarshaller.java,v 1.2 2002/08/20 19:38:15 mdb Exp $
* </code>
*/
public class SceneMarshaller extends InvocationMarshaller
implements SceneService
@@ -41,15 +38,27 @@ public class SceneMarshaller extends InvocationMarshaller
new Object[] { new Integer(arg1), arg2 }));
}
/** The method id used to dispatch {@link #moveSucceededPlusUpdate}
/** The method id used to dispatch {@link #moveSucceededWithUpdates}
* responses. */
public static final int MOVE_SUCCEEDED_PLUS_UPDATE = 2;
public static final int MOVE_SUCCEEDED_WITH_UPDATES = 2;
// documentation inherited from interface
public void moveSucceededPlusUpdate (int arg1, PlaceConfig arg2, SceneModel arg3)
public void moveSucceededWithUpdates (int arg1, PlaceConfig arg2, SceneUpdate[] arg3)
{
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, MOVE_SUCCEEDED_PLUS_UPDATE,
callerOid, requestId, MOVE_SUCCEEDED_WITH_UPDATES,
new Object[] { new Integer(arg1), arg2, arg3 }));
}
/** The method id used to dispatch {@link #moveSucceededWithScene}
* responses. */
public static final int MOVE_SUCCEEDED_WITH_SCENE = 3;
// documentation inherited from interface
public void moveSucceededWithScene (int arg1, PlaceConfig arg2, SceneModel arg3)
{
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, MOVE_SUCCEEDED_WITH_SCENE,
new Object[] { new Integer(arg1), arg2, arg3 }));
}
@@ -62,8 +71,13 @@ public class SceneMarshaller extends InvocationMarshaller
((Integer)args[0]).intValue(), (PlaceConfig)args[1]);
return;
case MOVE_SUCCEEDED_PLUS_UPDATE:
((SceneMoveListener)listener).moveSucceededPlusUpdate(
case MOVE_SUCCEEDED_WITH_UPDATES:
((SceneMoveListener)listener).moveSucceededWithUpdates(
((Integer)args[0]).intValue(), (PlaceConfig)args[1], (SceneUpdate[])args[2]);
return;
case MOVE_SUCCEEDED_WITH_SCENE:
((SceneMoveListener)listener).moveSucceededWithScene(
((Integer)args[0]).intValue(), (PlaceConfig)args[1], (SceneModel)args[2]);
return;
@@ -86,5 +100,5 @@ public class SceneMarshaller extends InvocationMarshaller
});
}
// Class file generated on 12:33:06 08/20/02.
// Generated on 14:44:07 02/08/03.
}
@@ -1,18 +1,16 @@
//
// $Id: SceneModel.java,v 1.8 2002/07/23 05:54:52 mdb Exp $
// $Id: SceneModel.java,v 1.9 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.data;
import com.samskivert.util.StringUtil;
import com.samskivert.util.ArrayUtil;
import com.threerings.io.SimpleStreamableObject;
/**
* The scene model is the bare bones representation of the data for a
* scene in the Whirled system. From the scene model, one would create an
* instance of {@link com.threerings.whirled.server.RuntimeScene}, {@link
* com.threerings.whirled.client.DisplayScene} or {@link
* com.threerings.whirled.tools.EditableScene}.
* instance of {@link Scene}.
*
* <p> The scene model is what is loaded from the scene repositories and
* what is transmitted over the wire when communicating scenes from the
@@ -25,7 +23,7 @@ public class SceneModel extends SimpleStreamableObject
public int sceneId;
/** The human readable name of this scene. */
public String sceneName;
public String name;
/** The version number of this scene. Versions are incremented
* whenever modifications are made to a scene so that clients can
@@ -33,18 +31,15 @@ public class SceneModel extends SimpleStreamableObject
* scene. */
public int version;
/** The scene ids of the scenes that neighbor this scene. A neighbor
* is a scene that can be entered from this scene. */
public int[] neighborIds;
/** Auxiliary scene model information. */
public AuxModel[] auxModels = new AuxModel[0];
/**
* Generates a string representation of this scene model.
* Adds the specified auxiliary model to this scene model.
*/
public String toString ()
public void addAuxModel (AuxModel auxModel)
{
StringBuffer buf = new StringBuffer("[");
toString(buf);
return buf.append("]").toString();
auxModels = (AuxModel[])ArrayUtil.append(auxModels, auxModel);
}
// documentation inherited
@@ -52,22 +47,13 @@ public class SceneModel extends SimpleStreamableObject
throws CloneNotSupportedException
{
SceneModel model = (SceneModel)super.clone();
model.neighborIds = (int[])neighborIds.clone();
model.auxModels = new AuxModel[auxModels.length];
for (int ii = 0; ii < auxModels.length; ii++) {
model.auxModels[ii] = (AuxModel)auxModels[ii].clone();
}
return model;
}
/**
* Derived classes override this to tack their <code>toString</code>
* data on to the string buffer.
*/
protected void toString (StringBuffer buf)
{
buf.append("sceneId=").append(sceneId);
buf.append(", name=").append(sceneName);
buf.append(", version=").append(version);
buf.append(", neighborIds=").append(StringUtil.toString(neighborIds));
}
/**
* Creates and returns a blank scene model.
*/
@@ -84,8 +70,7 @@ public class SceneModel extends SimpleStreamableObject
protected static void populateBlankSceneModel (SceneModel model)
{
model.sceneId = -1;
model.sceneName = "<blank>";
model.name = "<blank>";
model.version = 0;
model.neighborIds = new int[0];
}
}
@@ -0,0 +1,114 @@
//
// $Id: SceneUpdate.java,v 1.1 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.data;
import com.threerings.io.Streamable;
import com.threerings.whirled.Log;
/**
* Used to encapsulate updates to scenes in such a manner that updates can
* be stored persistently and sent to clients to update their own local
* copies of scenes.
*/
public abstract class SceneUpdate
implements Streamable, Cloneable
{
/**
* Creates a scene update that will operate on a scene with the
* specified target scene and version number.
*
* @param targetId the id of the scene on which we are to operate.
* @param targetVersion the version of the scene on which we are to
* operate.
*/
public SceneUpdate (int targetId, int targetVersion)
{
_targetId = targetId;
_targetVersion = targetVersion;
}
/**
* Returns the scene id for which this update is appropriate.
*/
public int getSceneId ()
{
return _targetId;
}
/**
* Returns the scene version for which this update is appropriate.
*/
public int getSceneVersion ()
{
return _targetVersion;
}
/**
* Called to ensure that the scene is in the appropriate state prior
* to applying the update.
*
* @exception IllegalStateException thrown if the update cannot be
* applied to the scene because it is not in a valid state
* (appropriate previous updates were not applied, it's the wrong kind
* of scene, etc.).
*/
public void validate (SceneModel model)
throws IllegalStateException
{
if (model.sceneId != _targetId) {
String errmsg = "Wrong target scene, expected id " +
_targetId + " got id " + model.sceneId;
throw new IllegalStateException(errmsg);
}
if (model.version != _targetVersion) {
String errmsg = "Target scene not proper version, expected " +
_targetVersion + " got " + model.version;
throw new IllegalStateException(errmsg);
}
}
/**
* Applies this update to the specified scene model. Derived classes
* will want to override this method and apply updates of their own,
* being sure to call <code>super.applyToScene</code>.
*/
public void apply (SceneModel model)
{
// increment the version; disallowing integer overflow
model.version = Math.max(_targetVersion + 1, model.version);
// sanity check for the amazing two billion updates
if (model.version == _targetVersion) {
Log.warning("Egads! This scene has been updated two billion " +
"times [model=" + model + ", update=" + this + "].");
}
}
/**
* Generates a string representation of this instance.
*/
public String toString ()
{
StringBuffer buf = new StringBuffer("[");
toString(buf);
return buf.append("]").toString();
}
/**
* An extensible mechanism for generating a string representation of
* this instance.
*/
protected void toString (StringBuffer buf)
{
buf.append("sceneId=").append(_targetId);
buf.append(", version=").append(_targetVersion);
}
/** The version number of the scene on which we operate. */
protected int _targetId;
/** The version number of the scene on which we operate. */
protected int _targetVersion;
}
@@ -1,21 +0,0 @@
//
// $Id: DefaultRuntimeSceneFactory.java,v 1.1 2001/11/12 20:56:56 mdb Exp $
package com.threerings.whirled.server;
import com.threerings.whirled.data.DefaultSceneConfig;
import com.threerings.whirled.data.SceneModel;
/**
* The default runtime scene factory creates {@link RuntimeSceneImpl}
* instances with {@link DefaultSceneConfig} instances (which create the
* default scene manager and controller).
*/
public class DefaultRuntimeSceneFactory implements RuntimeSceneFactory
{
// documentation inherited
public RuntimeScene createScene (SceneModel model)
{
return new RuntimeSceneImpl(model, new DefaultSceneConfig());
}
}
@@ -1,56 +0,0 @@
//
// $Id: RuntimeScene.java,v 1.3 2003/02/04 17:25:09 mdb Exp $
package com.threerings.whirled.server;
import com.threerings.crowd.data.PlaceConfig;
/**
* This interface makes available the scene information that is needed by
* the server to manage a scene. At this basic level, not much information
* is available, but extensions to this interface begin to create a more
* comprehensive picture of a scene in a system built from the Whirled
* services.
*
* <p> Additionally, at this basic level, the <code>RuntimeScene</code>
* does not differ greatly (or at all) from the {@link
* com.threerings.whirled.client.DisplayScene} interface, but the
* distinction provides a mechanism for handling the more substantial
* differences that appear in more sophisticated extensions to the base
* scene services.
*/
public interface RuntimeScene
{
/**
* Returns the unique identifier for this scene.
*/
public int getId ();
/**
* Returns the human readable name of this scene.
*/
public String getName ();
/**
* Returns the version number of this scene.
*/
public int getVersion ();
/**
* Updates the version number of this scene and immediately updates
* our associated scene model.
*/
public void setVersion (int version);
/**
* Returns the list of scene ids of this scene's neighbors.
*/
public int[] getNeighborIds ();
/**
* Returns the place config that can be used to determine which place
* controller instance should be used to display this scene as well as
* to obtain runtime configuration information.
*/
public PlaceConfig getPlaceConfig ();
}
@@ -1,29 +0,0 @@
//
// $Id: RuntimeSceneFactory.java,v 1.1 2001/11/12 20:56:56 mdb Exp $
package com.threerings.whirled.server;
import com.threerings.whirled.data.SceneModel;
/**
* When resolving a scene, the scene registry loads scene models from the
* scene repository, but it needs an external entity to convert those
* scene models into the appropriate implementation of {@link
* RuntimeScene}. The runtime scene factory interface provides the
* mechanism by which users of the Whirled system can create the
* appropriate instances.
*/
public interface RuntimeSceneFactory
{
/**
* This is called by the scene registry after it has loaded the scene
* model from the scene repository. The factory implementation is
* required to know what derivation of {@link
* com.threerings.crowd.data.PlaceConfig} should go along with the
* supplied scene model in order to create a {@link RuntimeScene}
* implementation. The expectation is that such information is either
* static or can be obtained from the scene model provided to this
* method.
*/
public RuntimeScene createScene (SceneModel model);
}
@@ -1,66 +0,0 @@
//
// $Id: RuntimeSceneImpl.java,v 1.3 2003/02/04 17:25:09 mdb Exp $
package com.threerings.whirled.server;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.data.SceneModel;
/**
* A basic implementation of the {@link RuntimeScene} interface which is
* used by default if no extended implementation is desired.
*/
public class RuntimeSceneImpl implements RuntimeScene
{
/**
* Creates an instance that will obtain data from the supplied scene
* model and place config.
*/
public RuntimeSceneImpl (SceneModel model, PlaceConfig config)
{
_model = model;
_config = config;
}
// documentation inherited
public int getId ()
{
return _model.sceneId;
}
// documentation inherited
public String getName ()
{
return _model.sceneName;
}
// documentation inherited
public int getVersion ()
{
return _model.version;
}
// documentation inherited from interface
public void setVersion (int version)
{
_model.version = version;
}
// documentation inherited
public int[] getNeighborIds ()
{
return _model.neighborIds;
}
// documentation inherited
public PlaceConfig getPlaceConfig ()
{
return _config;
}
/** A reference to our scene model. */
protected SceneModel _model;
/** A reference to our place configuration. */
protected PlaceConfig _config;
}
@@ -1,5 +1,5 @@
//
// $Id: SceneDispatcher.java,v 1.2 2002/08/20 19:38:15 mdb Exp $
// $Id: SceneDispatcher.java,v 1.3 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.server;
@@ -13,13 +13,10 @@ import com.threerings.whirled.client.SceneService;
import com.threerings.whirled.client.SceneService.SceneMoveListener;
import com.threerings.whirled.data.SceneMarshaller;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
/**
* Dispatches requests to the {@link SceneProvider}.
*
* <p> Generated from <code>
* $Id: SceneDispatcher.java,v 1.2 2002/08/20 19:38:15 mdb Exp $
* </code>
*/
public class SceneDispatcher extends InvocationDispatcher
{
@@ -55,4 +52,6 @@ public class SceneDispatcher extends InvocationDispatcher
super.dispatchRequest(source, methodId, args);
}
}
// Generated on 14:44:07 02/08/03.
}
@@ -1,10 +1,19 @@
//
// $Id: SceneManager.java,v 1.11 2003/02/05 00:23:52 mdb Exp $
// $Id: SceneManager.java,v 1.12 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.server;
import com.samskivert.io.PersistenceException;
import com.threerings.crowd.server.PlaceManager;
import com.threerings.presents.util.Invoker;
import com.threerings.whirled.Log;
import com.threerings.whirled.data.Scene;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.server.WhirledServer;
import com.threerings.whirled.util.UpdateList;
/**
* The scene manager extends the place manager and takes care of basic
@@ -15,37 +24,36 @@ import com.threerings.whirled.data.SceneModel;
public class SceneManager extends PlaceManager
{
/**
* Returns the runtime scene object (not the scene distributed object)
* being managed by this scene manager.
* Returns the scene object (not the scene distributed object) being
* managed by this scene manager.
*/
public RuntimeScene getScene ()
public Scene getScene ()
{
return _scene;
}
/**
* Returns a reference to the scene model from which we created our
* runtime scene object. This model must reflect any modifications
* this manager may have made to it in the course of managing the
* scene as it will be provided to the client as the definitive
* version of the scene. (The scene manager is responsible for writing
* changes made to the scene model back to the scene repository.)
*/
public SceneModel getSceneModel ()
{
return _model;
}
/**
* Called by the scene registry once the scene manager has been
* created (and initialized), but before it is started up.
*/
protected void setSceneData (
RuntimeScene scene, SceneModel model, SceneRegistry screg)
protected void setSceneData (Scene scene, UpdateList updates,
SceneRegistry screg)
{
// make sure the list and our version of the scene are in
// accordance
if (!updates.validate(scene.getVersion())) {
Log.warning("Provided with invalid updates; flushing " +
"[where=" + where() +
", sceneId=" + scene.getId() + "].");
// clear out the update list as it will not allow us to bring
// clients up to date with our current scene version; instead
// they'll have to download the whole thing
updates = new UpdateList();
}
_scene = scene;
_model = model;
_screg = screg;
_updates = updates;
// let derived classes react to the receipt of scene data
gotSceneData();
@@ -85,10 +93,45 @@ public class SceneManager extends PlaceManager
_screg.unmapSceneManager(this);
}
/**
* When a modification is made to a scene, the scene manager should
* update its internal structures, update the {@link Scene} object,
* update the repository (either by storing the updated scene
* wholesale or more efficiently updating only what has changed), and
* then it should create a {@link SceneUpdate} record that can be
* delivered to clients to effect the update to the clients's cached
* copy of the scene model. This update will be stored persistently
* and provided (along with any other accumulated updates) to clients
* that later request to enter the scene with an old version of the
* scene data. Updates are not stored forever, but a sizable number of
* recent updates are stored so that moderately current clients can
* apply incremental patches to their scenes rather than redownloading
* the entire scenes when they change.
*/
protected void recordUpdate (final SceneUpdate update)
{
// add it to our in memory update list
_updates.addUpdate(update);
// and store it in the repository
WhirledServer.invoker.postUnit(new Invoker.Unit() {
public boolean invoke () {
try {
_screg.getSceneRepository().addUpdate(update);
} catch (PersistenceException pe) {
Log.warning("Failed to store scene update " +
"[update=" + update + ", error=" + pe + "].");
}
return false;
}
});
}
// documentation inherited
public String where ()
{
return _scene.getName() + " (" + super.where() + ")";
return _scene.getName() + " (" + super.where() + ":" +
_scene.getId() + ")";
}
// documentation inherited
@@ -98,15 +141,14 @@ public class SceneManager extends PlaceManager
buf.append(", scene=").append(_scene);
}
/** A reference to our runtime scene implementation which provides a
/** A reference to our scene implementation which provides a
* meaningful interpretation of the data in the scene model. */
protected RuntimeScene _scene;
protected Scene _scene;
/** A reference to the scene model which we keep around because we may
* have to send it to clients that need updated versions of the model
* or to update the scene model in the repository if we modify the
* scene for some reason. */
protected SceneModel _model;
/** A list of the updates tracked for this scene. These will be used
* to attempt to bring clients up to date efficiently if they request
* to enter our scene with old scene model data. */
protected UpdateList _updates;
/** A reference to the scene registry so that we can call back to it
* when we're fully initialized. */
@@ -1,5 +1,5 @@
//
// $Id: SceneProvider.java,v 1.14 2002/12/14 01:51:00 mdb Exp $
// $Id: SceneProvider.java,v 1.15 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.server;
@@ -104,9 +104,9 @@ public class SceneProvider
((ScenedBodyObject)source).setSceneId(scmgr.getScene().getId());
// check to see if they need a newer version of the scene data
SceneModel model = scmgr.getSceneModel();
SceneModel model = scmgr.getScene().getSceneModel();
if (sceneVersion < model.version) {
listener.moveSucceededPlusUpdate(ploid, config, model);
listener.moveSucceededWithScene(ploid, config, model);
} else {
listener.moveSucceeded(ploid, config);
}
@@ -1,5 +1,5 @@
//
// $Id: SceneRegistry.java,v 1.17 2002/10/06 00:44:58 mdb Exp $
// $Id: SceneRegistry.java,v 1.18 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.server;
@@ -11,19 +11,23 @@ import com.threerings.presents.util.Invoker;
import com.threerings.presents.server.InvocationManager;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.crowd.server.CrowdServer;
import com.threerings.crowd.server.PlaceManager;
import com.threerings.whirled.Log;
import com.threerings.whirled.data.Scene;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneObject;
import com.threerings.whirled.server.persist.SceneRepository;
import com.threerings.whirled.util.SceneFactory;
import com.threerings.whirled.util.UpdateList;
/**
* The scene registry is responsible for the management of all runtime
* scenes. It handles interaction with the scene repository and ensures
* that scenes are loaded into memory when needed and flushed from memory
* when not needed.
* The scene registry is responsible for the management of all scenes. It
* handles interaction with the scene repository and ensures that scenes
* are loaded into memory when needed and flushed from memory when not
* needed.
*
* <p> The scene repository also takes care of bridging from the blocking,
* synchronous world of the scene repository to the non-blocking
@@ -37,6 +41,18 @@ import com.threerings.whirled.server.persist.SceneRepository;
*/
public class SceneRegistry
{
/**
* Used to create {@link PlaceConfig} instances for scenes.
*/
public static interface ConfigFactory
{
/**
* Creates the place config instance appropriate to the specified
* scene.
*/
PlaceConfig createPlaceConfig (SceneModel model);
}
/** Used to provide scene-related server-side services. */
public SceneProvider sceneprov;
@@ -44,28 +60,18 @@ public class SceneRegistry
* Constructs a scene registry, instructing it to load and store
* scenes using the supplied scene repository.
*/
public SceneRegistry (InvocationManager invmgr, SceneRepository screp)
public SceneRegistry (InvocationManager invmgr, SceneRepository screp,
SceneFactory scfact, ConfigFactory confact)
{
_screp = screp;
// use a default runtime scene factory for now; assume that
// containing systems will call setRuntimeSceneFactory() later
_scfact = new DefaultRuntimeSceneFactory();
_scfact = scfact;
_confact = confact;
// create/register a scene provider with the invocation services
sceneprov = new SceneProvider(CrowdServer.plreg.locprov, this);
invmgr.registerDispatcher(new SceneDispatcher(sceneprov), true);
}
/**
* Instructs the scene registry to use the supplied factory to create
* runtime scene instances from scene models.
*/
public void setRuntimeSceneFactory (RuntimeSceneFactory factory)
{
_scfact = factory;
}
/**
* Fetches the scene manager assosciated with the specified scene.
*
@@ -77,6 +83,15 @@ public class SceneRegistry
return (SceneManager)_scenemgrs.get(sceneId);
}
/**
* Returns a reference to the scene repository in use by this
* registry.
*/
public SceneRepository getSceneRepository ()
{
return _screp;
}
/**
* Because scenes must be loaded from the scene repository and this
* must not be done on the dobjmgr thread, the interface for resolving
@@ -155,6 +170,7 @@ public class SceneRegistry
{
try {
_model = _screp.loadSceneModel(fsceneId);
_updates = _screp.loadUpdates(fsceneId);
} catch (Exception e) {
_cause = e;
}
@@ -165,7 +181,7 @@ public class SceneRegistry
public void handleResult ()
{
if (_model != null) {
processSuccessfulResolution(_model);
processSuccessfulResolution(_model, _updates);
} else if (_cause != null) {
processFailedResolution(fsceneId, _cause);
} else {
@@ -176,6 +192,7 @@ public class SceneRegistry
}
protected SceneModel _model;
protected UpdateList _updates;
protected Exception _cause;
});
}
@@ -184,7 +201,8 @@ public class SceneRegistry
/**
* Called when the scene resolution has completed successfully.
*/
protected void processSuccessfulResolution (SceneModel model)
protected void processSuccessfulResolution (
SceneModel model, UpdateList updates)
{
// now that the scene is loaded, we can create a scene manager for
// it. that will be initialized by the place registry and when
@@ -192,18 +210,14 @@ public class SceneRegistry
// what's up
try {
// first create our runtime scene instance
RuntimeScene scene = _scfact.createScene(model);
// first create our scene instance
Scene scene = _scfact.createScene(
model, _confact.createPlaceConfig(model));
// now create our scene manager
SceneManager scmgr = (SceneManager)
CrowdServer.plreg.createPlace(scene.getPlaceConfig(), null);
// configure the scene manager with references to useful
// stuff; we'll somehow need to convey configuration
// information for the scene to the scene manager, but for now
// let's punt
scmgr.setSceneData(scene, model, this);
scmgr.setSceneData(scene, updates, this);
// when the scene manager completes its startup procedings, it
// will call back to the scene registry and let us know that
@@ -282,9 +296,12 @@ public class SceneRegistry
/** The entity from which we load scene models. */
protected SceneRepository _screp;
/** The entity via which we create runtime scene instances from scene
/** Used to generate place configs for our scenes. */
protected ConfigFactory _confact;
/** The entity via which we create scene instances from scene
* models. */
protected RuntimeSceneFactory _scfact;
protected SceneFactory _scfact;
/** A mapping from scene ids to scene managers. */
protected HashIntMap _scenemgrs = new HashIntMap();
@@ -1,19 +1,20 @@
//
// $Id: WhirledServer.java,v 1.15 2002/10/21 20:56:21 mdb Exp $
// $Id: WhirledServer.java,v 1.16 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.server;
import com.threerings.crowd.server.CrowdServer;
import com.threerings.whirled.Log;
import com.threerings.whirled.server.persist.SceneRepository;
import com.threerings.whirled.server.persist.DummySceneRepository;
import com.threerings.whirled.server.persist.SceneRepository;
import com.threerings.whirled.util.SceneFactory;
/**
* The whirled server extends the {@link CrowdServer} and provides access
* to managers and the like that are needed by the Whirled serviecs.
*/
public class WhirledServer extends CrowdServer
public abstract class WhirledServer extends CrowdServer
{
/** The scene registry. */
public static SceneRegistry screg;
@@ -34,25 +35,39 @@ public class WhirledServer extends CrowdServer
_screp = createSceneRepository();
// create our scene registry
screg = new SceneRegistry(invmgr, _screp);
screg = new SceneRegistry(invmgr, _screp, createSceneFactory(),
createConfigFactory());
Log.info("Whirled server initialized.");
}
/**
* Creates the scene repository that will be used by this server. If a
* derived class wishes to use a particular kind of scene repository
* (which they most likely will), they should override this method and
* instantiate the scene repository of their choosing.
* Creates the scene repository that will be used by this server.
*
* @exception Exception thrown if any error occurs while instantiating
* or initializing the scene repository.
*/
protected SceneRepository createSceneRepository ()
throws Exception
{
return new DummySceneRepository();
}
protected abstract SceneRepository createSceneRepository ()
throws Exception;
/**
* Creates the scene factory that will be used by our scene registry.
*
* @exception Exception thrown if any error occurs while instantiating
* or initializing the scene repository.
*/
protected abstract SceneFactory createSceneFactory ()
throws Exception;
/**
* Creates the place config factory that will be used our scene
* registry.
*
* @exception Exception thrown if any error occurs while instantiating
* or initializing the scene repository.
*/
protected abstract SceneRegistry.ConfigFactory createConfigFactory ()
throws Exception;
/** The scene repository in use by this server. */
protected SceneRepository _screp;
@@ -1,5 +1,5 @@
//
// $Id: DummySceneRepository.java,v 1.7 2001/11/12 20:56:56 mdb Exp $
// $Id: DummySceneRepository.java,v 1.8 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.server.persist;
@@ -7,7 +7,9 @@ import com.samskivert.io.PersistenceException;
import com.threerings.whirled.Log;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.util.NoSuchSceneException;
import com.threerings.whirled.util.UpdateList;
/**
* The dummy scene repository just pretends to load and store scenes, but
@@ -21,18 +23,18 @@ public class DummySceneRepository implements SceneRepository
throws PersistenceException, NoSuchSceneException
{
Log.info("Creating dummy scene [id=" + sceneId + "].");
// create a blank scene model
SceneModel model = new SceneModel();
model.sceneId = sceneId;
model.version = 1;
model.neighborIds = new int[0];
return model;
return SceneModel.blankSceneModel();
}
// documentation inherited
public void updateSceneModel (SceneModel model)
// documentation inherited from interface
public UpdateList loadUpdates (int sceneId)
throws PersistenceException, NoSuchSceneException
{
return new UpdateList();
}
// documentation inherited from interface
public void addUpdate (SceneUpdate update)
throws PersistenceException
{
// nothing doing
@@ -1,12 +1,14 @@
//
// $Id: SceneRepository.java,v 1.5 2001/11/12 20:56:56 mdb Exp $
// $Id: SceneRepository.java,v 1.6 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.server.persist;
import com.samskivert.io.PersistenceException;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.util.NoSuchSceneException;
import com.threerings.whirled.util.UpdateList;
/**
* The scene repository provides the basic interface for loading and
@@ -29,11 +31,23 @@ public interface SceneRepository
throws PersistenceException, NoSuchSceneException;
/**
* Updates the specified scene model in the repository.
* Fetches the set of updates associated with the specified scene.
*
* @exception PersistenceException thrown if an error occurs
* attempting to update the scene data.
* attempting to load the scene updates.
* @exception NoSuchSceneException thrown if no scene exists with the
* specified scene id.
*/
public void updateSceneModel (SceneModel scene)
public UpdateList loadUpdates (int sceneId)
throws PersistenceException, NoSuchSceneException;
/**
* Adds the supplied scene update to the list of updates for its
* associated scene.
*
* @exception PersistenceException thrown if an error occurs
* attempting to store the scene update.
*/
public void addUpdate (SceneUpdate update)
throws PersistenceException;
}
@@ -1,49 +0,0 @@
//
// $Id: DisplaySpotScene.java,v 1.4 2001/12/16 21:22:30 mdb Exp $
package com.threerings.whirled.spot.client;
import java.util.List;
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 the location id of the default entrance to this scene.
*/
public int getDefaultEntranceId ();
/**
* Returns a list of the locations in this scene (including portals
* which will be instances of {@link Portal}).
*/
public List getLocations ();
/**
* Convenience function for obtaining a location's index in the
* location list given its id.
*
* @return the location's index or -1 if a location with the specified
* id is not in this scene's location list.
*/
public int getLocationIndex (int locationId);
/**
* Convenience funtion for looking up a location by id.
*/
public Location getLocation (int locationId);
/**
* Returns a list of the portals in this scene.
*/
public List getPortals ();
}
@@ -1,155 +0,0 @@
//
// $Id: DisplaySpotSceneImpl.java,v 1.5 2001/12/16 21:22:30 mdb Exp $
package com.threerings.whirled.spot.client;
import java.util.ArrayList;
import java.util.List;
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 ArrayList(pcount);
_locations = new ArrayList(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
Portal port = new Portal();
populatePortal(model, port, i, pidx);
_portals.add(port);;
loc = port;
pidx++;
} else {
loc = new Location();
populateLocation(model, loc, i);
}
// everything goes into the locations array
_locations.add(loc);
}
}
/**
* Populates a location instance with the specified index, using
* information from the model.
*
* @param model the scene model.
* @param loc the location instance to populate.
* @param lidx the location index in the model arrays.
*/
protected void populateLocation (
SpotSceneModel model, Location loc, int lidx)
{
loc.locationId = model.locationIds[lidx];
loc.x = model.locationX[lidx];
loc.y = model.locationY[lidx];
loc.orientation = model.locationOrients[lidx];
loc.clusterIndex = model.locationClusters[lidx];
}
/**
* Populates a portal instance with the specified index, using
* information from the model.
*
* @param model the scene model.
* @param port the portal to populate.
* @param lidx the location index in the model arrays.
* @param pidx the portal index in the model arrays.
*/
protected void populatePortal (
SpotSceneModel model, Portal port, int lidx, int pidx)
{
// populate the location fields
populateLocation(model, port, lidx);
// populate the portal-specific fields
port.targetSceneId = model.neighborIds[pidx];
port.targetLocId = model.targetLocIds[pidx];
}
// documentation inherited
public int getDefaultEntranceId ()
{
return _model.defaultEntranceId;
}
// documentation inherited
public List getLocations ()
{
return _locations;
}
// documentation inherited
public int getLocationIndex (int locationId)
{
int lsize = _locations.size();
for (int i = 0; i < lsize; i++) {
Location loc = (Location)_locations.get(i);
if (loc.locationId == locationId) {
return i;
}
}
return -1;
}
// documentation inherited
public Location getLocation (int locationId)
{
int lsize = _locations.size();
for (int i = 0; i < lsize; i++) {
Location loc = (Location)_locations.get(i);
if (loc.locationId == locationId) {
return loc;
}
}
return null;
}
// documentation inherited
public List getPortals ()
{
return _portals;
}
/** The data that makes up our scene. */
protected SpotSceneModel _model;
/** A list of the locations (and portals) in this scene. */
protected ArrayList _locations;
/** A list of just the portals in this scene. */
protected ArrayList _portals;
}
@@ -1,5 +1,5 @@
//
// $Id: SpotSceneDirector.java,v 1.20 2003/01/03 23:07:00 shaper Exp $
// $Id: SpotSceneDirector.java,v 1.21 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.client;
@@ -9,6 +9,8 @@ import com.samskivert.util.StringUtil;
import com.threerings.presents.client.BasicDirector;
import com.threerings.presents.client.Client;
import com.threerings.presents.dobj.AttributeChangeListener;
import com.threerings.presents.dobj.AttributeChangedEvent;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DObjectManager;
@@ -26,16 +28,19 @@ import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.util.WhirledContext;
import com.threerings.whirled.spot.Log;
import com.threerings.whirled.spot.data.ClusteredBodyObject;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SpotCodes;
import com.threerings.whirled.spot.data.SpotScene;
/**
* Extends the standard scene director with facilities to move between
* locations within a scene.
*/
public class SpotSceneDirector extends BasicDirector
implements SpotCodes, Subscriber, SpotService.ChangeLocListener
implements SpotCodes, Subscriber, SpotService.ChangeLocListener,
AttributeChangeListener
{
/**
* This is used to communicate back to the caller of {@link
@@ -46,13 +51,13 @@ public class SpotSceneDirector extends BasicDirector
/**
* Indicates that the requested location change succeeded.
*/
public void locationChangeSucceeded (int locationId);
public void locationChangeSucceeded (Location loc);
/**
* Indicates that the requested location change failed and
* provides a reason code explaining the failure.
*/
public void locationChangeFailed (int locationId, String reason);
public void locationChangeFailed (Location loc, String reason);
}
/**
@@ -113,7 +118,7 @@ public class SpotSceneDirector extends BasicDirector
public boolean traversePortal (int portalId, ResultListener rl)
{
// look up the destination scene and location
DisplaySpotScene scene = (DisplaySpotScene)_scdir.getScene();
SpotScene scene = (SpotScene)_scdir.getScene();
if (scene == null) {
Log.warning("Requested to traverse portal when we have " +
"no scene [portalId=" + portalId + "].");
@@ -121,26 +126,16 @@ public class SpotSceneDirector extends BasicDirector
}
// find the portal they're talking about
int targetSceneId = -1, targetLocId = -1;
Iterator portals = scene.getPortals().iterator();
while (portals.hasNext()) {
Portal portal = (Portal)portals.next();
if (portal.locationId == portalId) {
targetSceneId = portal.targetSceneId;
targetLocId = portal.targetLocId;
}
}
// make sure we found the portal
if (targetSceneId == -1) {
portals = scene.getPortals().iterator();
Portal dest = scene.getPortal(portalId);
if (dest == null) {
Log.warning("Requested to traverse non-existent portal " +
"[portalId=" + portalId +
", portals=" + StringUtil.toString(portals) + "].");
"[portalId=" + portalId + ", portals=" +
StringUtil.toString(scene.getPortals()) + "].");
return false;
}
// prepare to move to this scene (sets up pending data)
if (!_scdir.prepareMoveTo(targetSceneId, rl)) {
if (!_scdir.prepareMoveTo(dest.targetSceneId, rl)) {
return false;
}
@@ -154,53 +149,52 @@ public class SpotSceneDirector extends BasicDirector
}
// issue a traversePortal request
_sservice.traversePortal(
_ctx.getClient(), scene.getId(), portalId, sceneVer, _scdir);
_sservice.traversePortal(_ctx.getClient(), portalId, sceneVer, _scdir);
return true;
}
/**
* Issues a request to change our location within the scene to the
* location identified by the specified id. Most client entities find
* out about location changes via changes to the occupant info data,
* but the initiator of a location change request can be notified of
* its success or failure, primarily so that it can act in
* anticipation of a successful location change (like by starting a
* sprite moving toward the new location), but backtrack if it finds
* out that the location change failed.
* 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.
*
* @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
* can be notified of its success or failure, primarily so that it can
* act in anticipation of a successful location change (like by
* starting a sprite moving toward the new location), but backtrack if
* it finds out that the location change failed.
*/
public void changeLocation (int locationId, ChangeObserver obs)
public void changeLocation (Location loc, int cluster, ChangeObserver obs)
{
// refuse if there's a pending location change or if we're already
// at the specified location
if ((locationId == _locationId) || (_pendingLocId != -1)) {
if (loc.equals(_location) || (_pendingLoc != null)) {
Log.info("Not going to " + loc + "; we're at " + _location +
" and we're headed to " + _pendingLoc + ".");
return;
}
// make sure we're currently in a scene
DisplaySpotScene scene = (DisplaySpotScene)_scdir.getScene();
SpotScene scene = (SpotScene)_scdir.getScene();
if (scene == null) {
Log.warning("Requested to change locations, but we're not " +
"currently in any scene [locId=" + locationId + "].");
"currently in any scene [loc=" + loc + "].");
return;
}
// make sure the specified location is in the current scene
Location loc = scene.getLocation(locationId);
if (loc == null) {
Log.warning("Requested to change to a location that's not " +
"in the current scene [locs=" + StringUtil.toString(
scene.getLocations().iterator()) +
", locId=" + locationId + "].");
return;
}
Log.info("Changing location [loc=" + loc + ", clus=" + cluster + "].");
// make a note that we're changing to this location
_pendingLocId = locationId;
_pendingLoc = (Location)loc.clone();
_changeObserver = obs;
// and send the location change request
_sservice.changeLoc(_ctx.getClient(), scene.getId(), locationId, this);
_sservice.changeLoc(_ctx.getClient(), loc, cluster, this);
}
/**
@@ -225,80 +219,37 @@ public class SpotSceneDirector extends BasicDirector
public boolean requestClusterSpeak (String message, byte mode)
{
// make sure we're currently in a scene
DisplaySpotScene scene = (DisplaySpotScene)_scdir.getScene();
SpotScene scene = (SpotScene)_scdir.getScene();
if (scene == null) {
Log.warning("Requested to speak to cluster, but we're not " +
"currently in any scene [message=" + message + "].");
return false;
}
// make sure we're in a location
Location loc = scene.getLocation(_locationId);
if (loc == null) {
Log.info("Ignoring cluster speak as we're not in a valid " +
"location [locId=" + _locationId + "].");
// make sure we're part of a cluster
if (_self.getClusterOid() <= 0) {
Log.info("Ignoring cluster speak as we're not in a cluster " +
"[cloid=" + _self.getClusterOid() + "].");
return false;
}
// make sure the location has an associated cluster
if (loc.clusterIndex == -1) {
Log.info("Ignoring cluster speak as our location has no " +
"cluster [loc=" + loc + "].");
return false;
}
// we're all clear to go
_sservice.clusterSpeak(_ctx.getClient(), scene.getId(), _locationId,
message, mode);
_sservice.clusterSpeak(_ctx.getClient(), message, mode);
return true;
}
// documentation inherited
protected void fetchServices (Client client)
{
_sservice = (SpotService)client.requireService(SpotService.class);
}
// documentation inherited
public void clientDidLogoff (Client client)
{
super.clientDidLogoff(client);
// clear out our business
_locationId = -1;
_pendingLocId = -1;
_changeObserver = null;
_clobj = null;
_sservice = null;
}
// documentation inherited from interface
public void changeLocSucceeded (int clusterOid)
public void changeLocSucceeded ()
{
ChangeObserver obs = _changeObserver;
_locationId = _pendingLocId;
_location = _pendingLoc;
// clear out our pending location info
_pendingLocId = -1;
_pendingLoc = null;
_changeObserver = null;
// determine if our cluster oid changed (which we only care about
// if we're doing cluster chat)
if (_chatdir != null) {
int oldOid = (_clobj == null) ? -1 : _clobj.getOid();
if (clusterOid != oldOid) {
DObjectManager omgr = _ctx.getDObjectManager();
// remove our old subscription if necessary
clearCluster();
// create a new subscription (we'll wire it up to the chat
// director when the subscription completes)
omgr.subscribeToObject(clusterOid, this);
}
}
// if we had an observer, let them know things went well
if (obs != null) {
obs.locationChangeSucceeded(_locationId);
obs.locationChangeSucceeded(_location);
}
}
@@ -306,15 +257,15 @@ public class SpotSceneDirector extends BasicDirector
public void requestFailed (String reason)
{
ChangeObserver obs = _changeObserver;
int locId = _pendingLocId;
Location loc = _pendingLoc;
// clear out our pending location info
_pendingLocId = -1;
_pendingLoc = null;
_changeObserver = null;
// if we had an observer, let them know things went well
if (obs != null) {
obs.locationChangeFailed(locId, reason);
obs.locationChangeFailed(loc, reason);
}
}
@@ -340,13 +291,73 @@ public class SpotSceneDirector extends BasicDirector
"[oid=" + oid + ", cause=" + cause + "].");
}
// documentation inherited from interface
public void attributeChanged (AttributeChangedEvent event)
{
// if our cluster oid changes from the one we're currently
// subscribed to, give it the boot
if (_clobj != null && _self.getClusterOid() != _clobj.getOid()) {
clearCluster();
}
// if there's a new cluster object, subscribe to it
if (_chatdir != null && _self.getClusterOid() > 0) {
DObjectManager omgr = _ctx.getDObjectManager();
// we'll wire up to the chat director when this completes
omgr.subscribeToObject(_self.getClusterOid(), this);
}
}
// documentation inherited from interface
public void clientDidLogon (Client client)
{
super.clientDidLogon(client);
// listen to the client object
client.getClientObject().addListener(this);
_self = (ClusteredBodyObject)client.getClientObject();
}
// documentation inherited from interface
public void clientObjectDidChange (Client client)
{
super.clientObjectDidChange(client);
// listen to the client object
client.getClientObject().addListener(this);
_self = (ClusteredBodyObject)client.getClientObject();
}
// documentation inherited
public void clientDidLogoff (Client client)
{
super.clientDidLogoff(client);
// clear out our business
_location = null;
_pendingLoc = null;
_changeObserver = null;
_sservice = null;
clearCluster();
// stop listening to the client object
client.getClientObject().removeListener(this);
_self = null;
}
// documentation inherited
protected void fetchServices (Client client)
{
_sservice = (SpotService)client.requireService(SpotService.class);
}
/**
* Clean up after a few things when we depart from a scene.
*/
protected void handleDeparture ()
{
// clear out our last known location id
_locationId = -1;
_location = null;
// unwire and clear out our cluster chat object if we've got one
clearCluster();
@@ -377,15 +388,18 @@ public class SpotSceneDirector extends BasicDirector
/** The scene director with which we are cooperating. */
protected SceneDirector _scdir;
/** A casted reference to our clustered body object. */
protected ClusteredBodyObject _self;
/** A reference to the chat director with which we coordinate. */
protected ChatDirector _chatdir;
/** The location id of the location we currently occupy. */
protected int _locationId = -1;
/** The location we currently occupy. */
protected Location _location;
/** The location id on which we have an outstanding change location
/** The location to which we have an outstanding change location
* request. */
protected int _pendingLocId = -1;
protected Location _pendingLoc;
/** The cluster chat object for the cluster we currently occupy. */
protected DObject _clobj;
@@ -1,5 +1,5 @@
//
// $Id: SpotService.java,v 1.11 2002/08/14 19:07:57 mdb Exp $
// $Id: SpotService.java,v 1.12 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.client;
@@ -7,20 +7,25 @@ import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.whirled.client.SceneService.SceneMoveListener;
import com.threerings.whirled.spot.data.Location;
/**
* Defines the mechanism by which the client can request to move between
* locations within a scene and between scenes (taking exit and entry
* locations into account). These services should not be used directly,
* but instead should be accessed via the {@link SpotSceneDirector}.
* Defines the mechanism by which the client can request to move around
* within a scene and between scenes (taking exit and entry locations into
* account). These services should not be used directly, but instead
* should be accessed via the {@link SpotSceneDirector}.
*/
public interface SpotService extends InvocationService
{
/**
* Requests to traverse the specified portal.
*
* @param portalId the portal to be traversed.
* @param descSceneVer the version of the destination scene data that
* the client has in its local repository.
*/
public void traversePortal (
Client client, int sceneId, int portalId, int sceneVer,
Client client, int portalId, int destSceneVer,
SceneMoveListener listener);
/**
@@ -29,25 +34,32 @@ public interface SpotService extends InvocationService
public static interface ChangeLocListener extends InvocationListener
{
/**
* Called when the change location request succeeded.
*
* @param clusterOid the object id of the cluster object
* associated with the new location.
* Called when the change location request succeeds.
*/
public void changeLocSucceeded (int clusterOid);
public void changeLocSucceeded ();
}
/**
* Requests that this client's body be made to occupy the specified
* Requests that this client's body be made to move to the specified
* 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.
*/
public void changeLoc (Client client, int sceneId, int locationId,
public void changeLoc (Client client, Location loc, int cluster,
ChangeLocListener listener);
/**
* Requests that the supplied message be delivered to listeners in the
* cluster to which the specified location belongs.
*
* @param message the text of the message to be spoken.
* @param mode an associated mode constant that can be used to
* identify different kinds of "speech" (emote, thought bubble, etc.).
*/
public void clusterSpeak (Client client, int sceneId, int locationId,
String message, byte mode);
public void clusterSpeak (Client client, String message, byte mode);
}
@@ -1,14 +1,18 @@
//
// $Id: ClusterObject.dobj,v 1.1 2002/11/04 22:33:39 mdb Exp $
// $Id: ClusterObject.dobj,v 1.2 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.OidList;
/**
* Used to dispatch chat in clusters. Contains no other information at the
* moment.
* Used to dispatch chat in clusters.
*/
public class ClusterObject extends DObject
{
/**
* Tracks the oid of the body objects that occupy this cluster.
*/
public OidList occupants = new OidList();
}
@@ -1,14 +1,41 @@
//
// $Id: ClusterObject.java,v 1.1 2002/11/04 22:33:39 mdb Exp $
// $Id: ClusterObject.java,v 1.2 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.OidList;
/**
* Used to dispatch chat in clusters. Contains no other information at the
* moment.
* Used to dispatch chat in clusters.
*/
public class ClusterObject extends DObject
{
/** The field name of the <code>occupants</code> field. */
public static final String OCCUPANTS = "occupants";
/**
* Tracks the oid of the body objects that occupy this cluster.
*/
public OidList occupants = new OidList();
/**
* Requests that the specified oid be added to the
* <code>occupants</code> oid list. The list will not change until the
* event is actually propagated through the system.
*/
public void addToOccupants (int oid)
{
requestOidAdd(OCCUPANTS, oid);
}
/**
* Requests that the specified oid be removed from the
* <code>occupants</code> oid list. The list will not change until the
* event is actually propagated through the system.
*/
public void removeFromOccupants (int oid)
{
requestOidRemove(OCCUPANTS, oid);
}
}
@@ -0,0 +1,25 @@
//
// $Id: ClusteredBodyObject.java,v 1.1 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import com.threerings.crowd.data.BodyObject;
import com.threerings.whirled.data.ScenedBodyObject;
/**
* Defines some required methods for a {@link BodyObject} that is to
* participate in the Whirled Spot system.
*/
public interface ClusteredBodyObject extends ScenedBodyObject
{
/**
* Returns the oid of the cluster to which this user currently
* belongs.
*/
public int getClusterOid ();
/**
* Sets the oid of the cluster to which this user currently belongs.
*/
public void setClusterOid (int clusterOid);
}
@@ -1,43 +1,75 @@
//
// $Id: Location.java,v 1.5 2001/12/05 09:14:29 mdb Exp $
// $Id: Location.java,v 1.6 2003/02/12 07:23:31 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;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.util.DirectionCodes;
import com.threerings.util.DirectionUtil;
/** This location's x coordinate (interpreted by the display system). */
/**
* Contains information on a scene occupant's position and orientation.
*/
public class Location extends SimpleStreamableObject
implements Cloneable
{
/** The user's x position (interpreted by the display system). */
public int x;
/** This location's y coordinate (interpreted by the display system). */
/** The user's y position (interpreted by the display system). */
public int y;
/** This location's y orientation (interpreted by the display system). */
public int orientation;
/** The user's orientation (defined by {@link DirectionCodes}). */
public byte orient;
/** The cluster to which this location belongs or -1 if it belongs to
* no cluster. */
public int clusterIndex;
/** {@link #toString} helper function. */
public String orientToString ()
{
return DirectionUtil.toShortString(orient);
}
/**
* Location equality is determined by location id.
* A zero-argument constructor used when unserializing instances.
*/
public Location ()
{
}
/**
* Constructs a location with the specified coordinates and
* orientation.
*/
public Location (int x, int y, byte orient)
{
this.x = x;
this.y = y;
this.orient = orient;
if (orient == -1) {
Thread.dumpStack();
}
}
/**
* Creates a clone of this instance.
*/
public Object clone ()
{
try {
return (Location)super.clone();
} catch (CloneNotSupportedException cnse) {
throw new RuntimeException("Location.clone() failed " + cnse);
}
}
/**
* Location equality is determined by coordinates.
*/
public boolean equals (Object other)
{
if (other instanceof Location) {
Location oloc = (Location)other;
return locationId == oloc.locationId;
return (x == oloc.x) && (y == oloc.y);
} else {
return false;
}
@@ -48,29 +80,6 @@ public class Location
*/
public int hashCode ()
{
return 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);
return x ^ y;
}
}
@@ -1,37 +1,110 @@
//
// $Id: Portal.java,v 1.4 2001/12/05 03:38:09 mdb Exp $
// $Id: Portal.java,v 1.5 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.util.DirectionUtil;
/**
* 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.
* Represents an exit to another 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.
*/
public class Portal extends Location
public class Portal extends SimpleStreamableObject
implements Cloneable
{
/** This portal's unique identifier. */
public short portalId;
/** This portal's x coordinate (interpreted by the display system). */
public int x;
/** This portal's y coordinate (interpreted by the display system). */
public int y;
/** This portal's y orientation (interpreted by the display system). */
public byte orient;
/** 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 portal identifier of the portal at which a body will enter
* the target scene when they "use" this portal. */
public int targetLocId;
public short targetPortalId;
// documentation inherited
protected void toString (StringBuffer buf)
/**
* Returns a location instance configured with the location and
* orientation of this portal.
*/
public Location getLocation ()
{
super.toString(buf);
buf.append(", targetScene=").append(targetSceneId);
buf.append(", targetLoc=").append(targetLocId);
return new Location(x, y, orient);
}
/**
* Returns a location instance configured with the location and
* opposite orientation of this portal. This is useful for when a body
* is entering a scene at a portal and we want them to face the
* opposite direction (as they are entering via the portal rather than
* leaving, which is the natural "orientation" of a portal).
*/
public Location getOppLocation ()
{
return new Location(x, y, (byte)DirectionUtil.getOpposite(orient));
}
/**
* Returns true if the portal has a potentially valid target scene and
* portal id (they are not guaranteed to exist, but they are at least
* potentially valid values rather than -1 or 0).
*/
public boolean isValid ()
{
return (targetSceneId > 0) && (targetPortalId > 0);
}
/**
* Creates a clone of this instance.
*/
public Object clone ()
{
try {
return (Portal)super.clone();
} catch (CloneNotSupportedException cnse) {
throw new RuntimeException("Portal.clone() failed " + cnse);
}
}
/**
* Portal equality is determined by portal id.
*/
public boolean equals (Object other)
{
if (other instanceof Portal) {
Portal oport = (Portal)other;
return portalId == oport.portalId;
} else {
return false;
}
}
/** {@link #toString} helper function. */
public String orientToString ()
{
return DirectionUtil.toShortString(orient);
}
/**
* Computes a reasonable hashcode for portal instances.
*/
public int hashCode ()
{
return portalId;
}
}
@@ -0,0 +1,54 @@
//
// $Id: SceneLocation.java,v 1.1 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import com.threerings.presents.dobj.DSet;
/**
* Extends {@link Location} with the data and functionality needed to
* represent a particular user's location in a scene.
*/
public class SceneLocation extends Location
implements DSet.Entry
{
/** The oid of the body that occupies this location. */
public int bodyOid;
/**
* Creates a scene location with the specified information.
*/
public SceneLocation (int x, int y, byte orient, int bodyOid)
{
super(x, y, orient);
this.bodyOid = bodyOid;
}
/**
* Creates a scene location with the specified information.
*/
public SceneLocation (Location loc, int bodyOid)
{
super(loc.x, loc.y, loc.orient);
this.bodyOid = bodyOid;
}
/**
* Creates a blank instance suitable for unserialization.
*/
public SceneLocation ()
{
}
// documentation inherited
public Comparable getKey ()
{
if (_key == null) {
_key = new Integer(bodyOid);
}
return _key;
}
/** Used for {@link #geyKey}. */
protected transient Integer _key;
}
@@ -1,5 +1,5 @@
//
// $Id: SpotMarshaller.java,v 1.2 2002/08/20 19:38:15 mdb Exp $
// $Id: SpotMarshaller.java,v 1.3 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
@@ -10,6 +10,7 @@ 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;
/**
* Provides the implementation of the {@link SpotService} interface
@@ -17,10 +18,6 @@ import com.threerings.whirled.spot.client.SpotService.ChangeLocListener;
* on the server. Also provides an implementation of the response listener
* interfaces that marshall the response arguments and deliver them back
* to the requesting client.
*
* <p> Generated from <code>
* $Id: SpotMarshaller.java,v 1.2 2002/08/20 19:38:15 mdb Exp $
* </code>
*/
public class SpotMarshaller extends InvocationMarshaller
implements SpotService
@@ -34,11 +31,11 @@ public class SpotMarshaller extends InvocationMarshaller
public static final int CHANGE_LOC_SUCCEEDED = 1;
// documentation inherited from interface
public void changeLocSucceeded (int arg1)
public void changeLocSucceeded ()
{
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, CHANGE_LOC_SUCCEEDED,
new Object[] { new Integer(arg1) }));
new Object[] { }));
}
// documentation inherited
@@ -47,7 +44,7 @@ public class SpotMarshaller extends InvocationMarshaller
switch (methodId) {
case CHANGE_LOC_SUCCEEDED:
((ChangeLocListener)listener).changeLocSucceeded(
((Integer)args[0]).intValue());
);
return;
default:
@@ -60,12 +57,12 @@ public class SpotMarshaller extends InvocationMarshaller
public static final int TRAVERSE_PORTAL = 1;
// documentation inherited from interface
public void traversePortal (Client arg1, int arg2, int arg3, int arg4, SceneMoveListener arg5)
public void traversePortal (Client arg1, int arg2, int arg3, SceneMoveListener arg4)
{
SceneMoveMarshaller listener5 = new SceneMoveMarshaller();
listener5.listener = arg5;
SceneMoveMarshaller listener4 = new SceneMoveMarshaller();
listener4.listener = arg4;
sendRequest(arg1, TRAVERSE_PORTAL, new Object[] {
new Integer(arg2), new Integer(arg3), new Integer(arg4), listener5
new Integer(arg2), new Integer(arg3), listener4
});
}
@@ -73,12 +70,12 @@ public class SpotMarshaller extends InvocationMarshaller
public static final int CHANGE_LOC = 2;
// documentation inherited from interface
public void changeLoc (Client arg1, int arg2, int arg3, ChangeLocListener arg4)
public void changeLoc (Client arg1, Location arg2, int arg3, ChangeLocListener arg4)
{
ChangeLocMarshaller listener4 = new ChangeLocMarshaller();
listener4.listener = arg4;
sendRequest(arg1, CHANGE_LOC, new Object[] {
new Integer(arg2), new Integer(arg3), listener4
arg2, new Integer(arg3), listener4
});
}
@@ -86,12 +83,12 @@ public class SpotMarshaller extends InvocationMarshaller
public static final int CLUSTER_SPEAK = 3;
// documentation inherited from interface
public void clusterSpeak (Client arg1, int arg2, int arg3, String arg4, byte arg5)
public void clusterSpeak (Client arg1, String arg2, byte arg3)
{
sendRequest(arg1, CLUSTER_SPEAK, new Object[] {
new Integer(arg2), new Integer(arg3), arg4, new Byte(arg5)
arg2, new Byte(arg3)
});
}
// Class file generated on 12:33:05 08/20/02.
// Generated on 10:09:04 02/05/03.
}
@@ -1,28 +0,0 @@
//
// $Id: SpotOccupantInfo.java,v 1.3 2002/06/20 22:13:20 mdb Exp $
package com.threerings.whirled.spot.data;
import com.samskivert.util.StringUtil.Formatter;
import com.threerings.crowd.data.OccupantInfo;
/**
* The spot services extend the basic occupant info with information on
* which location within the scene a user occupies.
*/
public class SpotOccupantInfo extends OccupantInfo
{
/** The id of the location occupied by this user or -1 if they occupy
* no location. */
public int locationId;
/** Used to log just the user oids and location ids of users in the
* <code>occupantInfo</code> set when debugging. */
public static final Formatter OIDS_AND_LOCS = new Formatter() {
public String toString (Object object) {
SpotOccupantInfo soi = (SpotOccupantInfo)object;
return "[" + soi.getBodyOid() + ", " + soi.locationId + "]";
}
};
}
@@ -0,0 +1,55 @@
//
// $Id: SpotScene.java,v 1.1 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import java.util.Iterator;
/**
* Makes available the spot scene information that the server needs to do
* its business.
*/
public interface SpotScene
{
/**
* Returns a {@link Portal} object for the portal with the specified
* id or null if no portal exists with that id.
*/
public Portal getPortal (int portalId);
/**
* Returns the number of portals in this scene.
*/
public int getPortalCount ();
/**
* Returns an iterator over the portals in this scene.
*/
public Iterator getPortals ();
/**
* Returns the portal that represents 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 portal at which they
* would appear.
*/
public Portal getDefaultEntrance ();
/**
* Adds a portal to this scene, immediately making the requisite
* modifications to the underlying scene model. A portal id will be
* assigned to the portal by this method.
*/
public void addPortal (Portal portal);
/**
* Removes the specified portal from the scene.
*/
public void removePortal (Portal portal);
/**
* Sets the default entrance in this scene, immediately making the
* requisite modifications to the underlying scene model.
*/
public void setDefaultEntrance (Portal portal);
}
@@ -0,0 +1,122 @@
//
// $Id: SpotSceneImpl.java,v 1.1 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import java.util.Iterator;
import com.samskivert.util.HashIntMap;
import com.samskivert.util.ListUtil;
import com.threerings.whirled.spot.Log;
/**
* An implementation of the {@link SpotScene} interface.
*/
public class SpotSceneImpl
implements SpotScene
{
/**
* Creates an instance that will obtain data from the supplied spot
* scene model.
*/
public SpotSceneImpl (SpotSceneModel smodel)
{
_smodel = smodel;
for (int ii = 0, ll = _smodel.portals.length; ii < ll; ii++) {
Portal port = _smodel.portals[ii];
_portals.put(port.portalId, port);
}
}
/**
* Instantiates a blank scene implementation.
*/
public SpotSceneImpl ()
{
_smodel = new SpotSceneModel();
}
// documentation inherited from interface
public Portal getPortal (int portalId)
{
return (Portal)_portals.get(portalId);
}
// documentation inherited from interface
public int getPortalCount ()
{
return _portals.size();
}
// documentation inherited from interface
public Iterator getPortals ()
{
return _portals.values().iterator();
}
// documentation inherited from interface
public Portal getDefaultEntrance ()
{
return getPortal(_smodel.defaultEntranceId);
}
// documentation inherited from interface
public void addPortal (Portal portal)
{
// compute a new portal id for our friend the portal
portal.portalId = 0;
for (short ii = 1; ii < MAX_PORTAL_ID; ii++) {
if (!_portals.containsKey(ii)) {
portal.portalId = ii;
break;
}
}
if (portal.portalId == 0) {
Log.warning("Unable to assign id to new portal " +
"[scene=" + this + "].");
return;
}
// add this beyotch to our model
_smodel.addPortal(portal);
// and slap it into our table
_portals.put(portal.portalId, portal);
}
// documentation inherited from interface
public void removePortal (Portal portal)
{
// remove the portal from our mapping
_portals.remove(portal.portalId);
// remove it from the model
_smodel.removePortal(portal);
}
/**
* Used when we're being parsed from an XML scene model.
*/
public void setDefaultEntranceId (int defaultEntranceId)
{
_smodel.defaultEntranceId = defaultEntranceId;
}
// documentation inherited from interface
public void setDefaultEntrance (Portal portal)
{
_smodel.defaultEntranceId = (portal == null) ? -1 : portal.portalId;
}
/** A casted reference to our scene model. */
protected SpotSceneModel _smodel;
/** A mapping from portal id to portal. */
protected HashIntMap _portals = new HashIntMap();
/** We don't allow more than ~32k portals in a scene. Things would
* slow down *way* before we got there. */
protected static final int MAX_PORTAL_ID = Short.MAX_VALUE;
}
@@ -1,119 +1,79 @@
//
// $Id: SpotSceneModel.java,v 1.8 2002/07/23 05:54:52 mdb Exp $
// $Id: SpotSceneModel.java,v 1.9 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import com.samskivert.util.StringUtil;
import com.samskivert.util.ArrayUtil;
import com.samskivert.util.ListUtil;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.util.DirectionUtil;
import com.threerings.whirled.data.AuxModel;
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 an identifier, unique within the scene and
* unchanging, so that portals can stably reference the target location in
* the scene to which they connect. 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).
* on portals. Portals are referenced by an identifier, unique within the
* scene and unchanging, so that portals can stably reference the target
* portal in the scene to which they connect.
*/
public class SpotSceneModel extends SceneModel
public class SpotSceneModel extends SimpleStreamableObject
implements AuxModel
{
/** The unique (within the scope of this scene) identifier of each
* location in this scene (including portals). */
public int[] locationIds;
/** An array containing all portals in this scene. */
public Portal[] portals = new Portal[0];
/** 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 0
* to indicate that the location is not a member of any cluster
* (including portals, which should always be 0). */
public int[] locationClusters;
/** The location id of the default entrance to this scene. If a body
/** The portal 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;
* portal at which they would appear. */
public int defaultEntranceId = -1;
/** 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;
/**
* Adds a portal to this scene model.
*/
public void addPortal (Portal portal)
{
portals = (Portal[])ArrayUtil.append(portals, portal);
}
/** 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;
/**
* Removes a portal from this model.
*/
public void removePortal (Portal portal)
{
int pidx = ListUtil.indexOfEqual(portals, portal);
if (pidx != -1) {
portals = (Portal[])ArrayUtil.splice(portals, pidx, 1);
}
}
// documentation inherited
public Object clone ()
throws CloneNotSupportedException
{
SpotSceneModel model = (SpotSceneModel)super.clone();
model.locationIds = (int[])locationIds.clone();
model.locationX = (int[])locationX.clone();
model.locationY = (int[])locationY.clone();
model.locationOrients = (int[])locationOrients.clone();
model.locationClusters = (int[])locationClusters.clone();
model.portalIds = (int[])portalIds.clone();
model.targetLocIds = (int[])targetLocIds.clone();
// clone our portals individually
model.portals = new Portal[portals.length];
for (int ii = 0, ll = portals.length; ii < ll; ii++) {
model.portals[ii] = (Portal)portals[ii].clone();
}
return model;
}
/**
* Creates and returns a blank scene model.
* Locates and returns the {@link SpotSceneModel} among the auxiliary
* scene models associated with the supplied scene
* model. <code>null</code> is returned if no spot scene model could
* be found.
*/
public static SpotSceneModel blankSpotSceneModel ()
public static SpotSceneModel getSceneModel (SceneModel model)
{
SpotSceneModel model = new SpotSceneModel();
populateBlankSpotSceneModel(model);
return model;
}
/**
* Populates a blank scene model with blank values.
*/
protected static void populateBlankSpotSceneModel (SpotSceneModel model)
{
// populate our superclass fields
populateBlankSceneModel(model);
// now populate our fields
model.locationIds = new int[0];
model.locationX = new int[0];
model.locationY = new int[0];
model.locationOrients = new int[0];
model.locationClusters = new int[0];
model.defaultEntranceId = -1;
model.portalIds = new int[0];
model.targetLocIds = new int[0];
}
// documentation inherited
protected void toString (StringBuffer buf)
{
super.toString(buf);
buf.append(", locationIds=").append(StringUtil.toString(locationIds));
buf.append(", locationX=").append(StringUtil.toString(locationX ));
buf.append(", locationY=").append(StringUtil.toString(locationY));
buf.append(", locationOrients=").
append(StringUtil.toString(locationOrients));
buf.append(", locationClusters=").
append(StringUtil.toString(locationClusters));
buf.append(", defaultEntranceId=").append(defaultEntranceId);
buf.append(", portalIds=").append(StringUtil.toString(portalIds));
buf.append(", targetLocIds=").append(StringUtil.toString(targetLocIds));
for (int ii = 0; ii < model.auxModels.length; ii++) {
if (model.auxModels[ii] instanceof SpotSceneModel) {
return (SpotSceneModel)model.auxModels[ii];
}
}
return null;
}
}
@@ -0,0 +1,17 @@
//
// $Id: SpotSceneObject.dobj,v 1.1 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import com.threerings.presents.dobj.DSet;
import com.threerings.whirled.data.SceneObject;
/**
* Extends the {@link SceneObject} with information specific to spots.
*/
public class SpotSceneObject extends SceneObject
{
/** A distributed set containing {@link SceneLocation} records for all
* occupants of this scene. */
public DSet occupantLocs = new DSet();
}
@@ -0,0 +1,66 @@
//
// $Id: SpotSceneObject.java,v 1.1 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.data;
import com.threerings.presents.dobj.DSet;
import com.threerings.whirled.data.SceneObject;
/**
* Extends the {@link SceneObject} with information specific to spots.
*/
public class SpotSceneObject extends SceneObject
{
/** The field name of the <code>occupantLocs</code> field. */
public static final String OCCUPANT_LOCS = "occupantLocs";
/** A distributed set containing {@link SceneLocation} records for all
* occupants of this scene. */
public DSet occupantLocs = new DSet();
/**
* Requests that the specified entry be added to the
* <code>occupantLocs</code> set. The set will not change until the event is
* actually propagated through the system.
*/
public void addToOccupantLocs (DSet.Entry elem)
{
requestEntryAdd(OCCUPANT_LOCS, elem);
}
/**
* Requests that the entry matching the supplied key be removed from
* the <code>occupantLocs</code> set. The set will not change until the
* event is actually propagated through the system.
*/
public void removeFromOccupantLocs (Object key)
{
requestEntryRemove(OCCUPANT_LOCS, key);
}
/**
* Requests that the specified entry be updated in the
* <code>occupantLocs</code> set. The set will not change until the event is
* actually propagated through the system.
*/
public void updateOccupantLocs (DSet.Entry elem)
{
requestEntryUpdate(OCCUPANT_LOCS, elem);
}
/**
* Requests that the <code>occupantLocs</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 setOccupantLocs (DSet occupantLocs)
{
this.occupantLocs = occupantLocs;
requestAttributeChange(OCCUPANT_LOCS, occupantLocs);
}
}
@@ -1,78 +0,0 @@
//
// $Id: RuntimeSpotScene.java,v 1.5 2003/02/04 03:12:07 mdb Exp $
package com.threerings.whirled.spot.server;
import com.threerings.whirled.server.RuntimeScene;
import com.threerings.whirled.spot.data.SpotSceneModel;
/**
* 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 number of locations (and portals) in this scene.
*/
public int getLocationCount ();
/**
* Returns the location id of the location at the specified index.
*/
public int getLocationId (int locidx);
/**
* Returns the index of the specified location id.
*/
public int getLocationIndex (int locationId);
/**
* Returns the total number of clusters in this scene.
*/
public int getClusterCount ();
/**
* Returns the cluster index associated with the specified location
* index or -1 if the location at that index is not associated with a
* cluster.
*/
public int getClusterIndex (int locationIdx);
/**
* 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);
/**
* Adds a portal to this runtime scene, immediately making the
* requisite modifications to the underlying scene model.
*
* @return the location id assigned to the newly created portal.
*/
public int addPortal (int locX, int locY, int orient,
int targetSceneId, int targetLocId);
/**
* Returns a reference to the underlying model.
*/
public SpotSceneModel getModel ();
}
@@ -1,158 +0,0 @@
//
// $Id: RuntimeSpotSceneImpl.java,v 1.7 2003/02/06 18:58:30 mdb Exp $
package com.threerings.whirled.spot.server;
import com.samskivert.util.ArrayUtil;
import com.samskivert.util.IntListUtil;
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
implements RuntimeSpotScene
{
/**
* 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 getLocationCount ()
{
return _model.locationIds.length;
}
// documentation inherited
public int getLocationId (int locidx)
{
return _model.locationIds[locidx];
}
// documentation inherited
public int getLocationIndex (int locationId)
{
return IntListUtil.indexOf(_model.locationIds, locationId);
}
// documentation inherited
public int getClusterCount ()
{
return _clusterCount;
}
// documentation inherited
public int getClusterIndex (int locationIdx)
{
return _model.locationClusters[locationIdx];
}
// 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];
}
// make or may not make it into the public interface
public int addLocation (int locX, int locY, int orient, int cluster)
{
// compute the highest location id already used in the scene and
// add one to it for our new location id
int nlocid = Math.max(
IntListUtil.getMaxValue(_model.locationIds), 0) + 1;
// expand the necessary arrays
_model.locationIds = ArrayUtil.append(_model.locationIds, nlocid);
_model.locationX = ArrayUtil.append(_model.locationX, locX);
_model.locationY = ArrayUtil.append(_model.locationY, locY);
_model.locationOrients =
ArrayUtil.append(_model.locationOrients, orient);
_model.locationClusters =
ArrayUtil.append(_model.locationOrients, cluster);
return nlocid;
}
// documentation inherited from interface
public int addPortal (int locX, int locY, int orient,
int targetSceneId, int targetLocId)
{
// add the location information for this portal
int nlocid = addLocation(locX, locY, orient, 0);
// expand the necessary portal arrays
_model.neighborIds =
ArrayUtil.append(_model.neighborIds, targetSceneId);
_model.portalIds = ArrayUtil.append(_model.portalIds, nlocid);
_model.targetLocIds =
ArrayUtil.append(_model.targetLocIds, targetLocId);
return nlocid;
}
// documentation inherited from interface
public SpotSceneModel getModel ()
{
return _model;
}
/**
* 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;
}
@@ -1,5 +1,5 @@
//
// $Id: SpotDispatcher.java,v 1.2 2002/08/20 19:38:15 mdb Exp $
// $Id: SpotDispatcher.java,v 1.3 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.server;
@@ -12,14 +12,11 @@ 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;
/**
* Dispatches requests to the {@link SpotProvider}.
*
* <p> Generated from <code>
* $Id: SpotDispatcher.java,v 1.2 2002/08/20 19:38:15 mdb Exp $
* </code>
*/
public class SpotDispatcher extends InvocationDispatcher
{
@@ -47,21 +44,21 @@ public class SpotDispatcher extends InvocationDispatcher
case SpotMarshaller.TRAVERSE_PORTAL:
((SpotProvider)provider).traversePortal(
source,
((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), ((Integer)args[2]).intValue(), (SceneMoveListener)args[3]
((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), (SceneMoveListener)args[2]
);
return;
case SpotMarshaller.CHANGE_LOC:
((SpotProvider)provider).changeLoc(
source,
((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), (ChangeLocListener)args[2]
(Location)args[0], ((Integer)args[1]).intValue(), (ChangeLocListener)args[2]
);
return;
case SpotMarshaller.CLUSTER_SPEAK:
((SpotProvider)provider).clusterSpeak(
source,
((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), (String)args[2], ((Byte)args[3]).byteValue()
(String)args[0], ((Byte)args[1]).byteValue()
);
return;
@@ -69,4 +66,6 @@ public class SpotDispatcher extends InvocationDispatcher
super.dispatchRequest(source, methodId, args);
}
}
// Generated on 10:09:04 02/05/03.
}
@@ -1,8 +1,10 @@
//
// $Id: SpotProvider.java,v 1.14 2002/12/14 01:51:00 mdb Exp $
// $Id: SpotProvider.java,v 1.15 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.server;
import com.samskivert.util.StringUtil;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.dobj.RootDObjectManager;
import com.threerings.presents.server.InvocationException;
@@ -16,13 +18,16 @@ import com.threerings.crowd.server.PlaceRegistry;
import com.threerings.whirled.client.SceneService.SceneMoveListener;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.ScenedBodyObject;
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.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SpotCodes;
import com.threerings.whirled.spot.data.SpotOccupantInfo;
import com.threerings.whirled.spot.data.SpotScene;
/**
* Provides the server-side implementation of the spot services.
@@ -44,24 +49,18 @@ public class SpotProvider
}
/**
* Processes a request from a client to traverse a portal.
*
* @param source the body object of the client making the request.
* @param sceneId the source scene id.
* @param portalId the portal in the source scene that is being
* traversed.
* @param sceneVer the version of the destination scene data that the
* client has cached.
* @param listener the entity to which we communicate our response.
* Processes a {@link SpotService#traversePortal} request.
*/
public void traversePortal (ClientObject caller, int sceneId, int portalId,
int sceneVer, SceneMoveListener listener)
public void traversePortal (ClientObject caller, int portalId,
int destSceneVer, SceneMoveListener listener)
throws InvocationException
{
int sceneId = getCallerSceneId(caller);
// avoid cluttering up the method declaration with final keywords
final BodyObject fsource = (BodyObject)caller;
final int fportalId = portalId;
final int fsceneVer = sceneVer;
final int fsceneVer = destSceneVer;
final SceneMoveListener flistener = listener;
// obtain the source scene
@@ -75,28 +74,26 @@ public class SpotProvider
}
// obtain the destination scene and location id
RuntimeSpotScene rss = (RuntimeSpotScene)smgr.getScene();
int destSceneId = rss.getTargetSceneId(portalId);
final int destLocId = rss.getTargetLocationId(portalId);
SpotScene rss = (SpotScene)smgr.getScene();
final Portal fdest = rss.getPortal(portalId);
// make sure this portal has valid info
if (destSceneId == -1) {
Log.warning("Traverse portal provided with invalid portal " +
"[user=" + fsource.who() + ", sceneId=" + sceneId +
", portalId=" + portalId +
", destSceneId=" + destSceneId + "].");
if (fdest == null || !fdest.isValid()) {
Log.warning("Traverse portal with invalid portal " +
"[user=" + fsource.who() + ", scene=" + smgr.where() +
", pid=" + portalId + ", portal=" + fdest +
", portals=" + StringUtil.toString(rss.getPortals()) +
"].");
throw new InvocationException(NO_SUCH_PORTAL);
}
// create a callback object that will handle the resolution or
// failed resolution of the scene
// resolve their destination scene
SceneRegistry.ResolutionListener rl =
new SceneRegistry.ResolutionListener() {
public void sceneWasResolved (SceneManager scmgr) {
SpotSceneManager sscmgr = (SpotSceneManager)scmgr;
finishTraversePortalRequest(
fsource, sscmgr, fsceneVer, fportalId, destLocId,
flistener);
fsource, sscmgr, fsceneVer, fdest, flistener);
}
public void sceneFailedToResolve (
@@ -108,10 +105,7 @@ public class SpotProvider
flistener.requestFailed(NO_SUCH_PLACE);
}
};
// make sure the scene they are headed to is actually loaded into
// the server
_screg.resolveScene(destSceneId, rl);
_screg.resolveScene(fdest.targetSceneId, rl);
}
/**
@@ -120,11 +114,10 @@ public class SpotProvider
*/
protected void finishTraversePortalRequest (
BodyObject source, SpotSceneManager scmgr, int sceneVer,
int exitPortalId, int destLocId, SceneMoveListener listener)
Portal dest, SceneMoveListener listener)
{
// let the destination scene manager know that we're coming in
int bodyOid = source.getOid();
scmgr.mapEnteringBody(bodyOid, destLocId);
scmgr.mapEnteringBody(source, dest.targetPortalId);
try {
// move to the place object associated with this scene
@@ -133,17 +126,18 @@ public class SpotProvider
listener.requestFailed(sfe.getMessage());
// and let the destination scene manager know that we're no
// longer coming in
scmgr.clearEnteringBody(bodyOid);
scmgr.clearEnteringBody(source);
}
}
/**
* Processes a request from a client to move to a new location.
* Processes a {@link SpotService#changeLog} request.
*/
public void changeLoc (ClientObject caller, int sceneId, int locationId,
public void changeLoc (ClientObject caller, Location loc, int cluster,
ChangeLocListener listener)
throws InvocationException
{
int sceneId = getCallerSceneId(caller);
BodyObject source = (BodyObject)caller;
// look up the scene manager for the specified scene
@@ -152,23 +146,25 @@ public class SpotProvider
if (smgr == null) {
Log.warning("User requested to change location in " +
"non-existent scene [user=" + source.who() +
", sceneId=" + sceneId +
", locId=" + locationId + "].");
", sceneId=" + sceneId + ", loc=" + loc +"].");
throw new InvocationException(INTERNAL_ERROR);
}
int locOid = smgr.handleChangeLocRequest(source, locationId);
listener.changeLocSucceeded(locOid);
// pass the buck to yon scene manager
smgr.handleChangeLocRequest(source, loc, cluster);
// if that method finished, we're good to go
listener.changeLocSucceeded();
}
/**
* Handles request to generate a speak message in the specified cluster.
*/
public void clusterSpeak (ClientObject caller, int sceneId, int locationId,
String message, byte mode)
public void clusterSpeak (ClientObject caller, String message, byte mode)
throws InvocationException
{
BodyObject source = (BodyObject)caller;
sendClusterChatMessage(sceneId, locationId, source.getOid(),
sendClusterChatMessage(getCallerSceneId(caller), source.getOid(),
source.username, null, message, mode);
}
@@ -181,7 +177,6 @@ public class SpotProvider
* message text) and with the supplied message content.
*
* @param sceneId the scene id in which to deliver the chat message.
* @param locId the location whose cluster will be spoken to.
* @param speakerOid the body object id of the speaker (used to verify
* that they are in the cluster in question).
* @param speaker the username of the user that generated the message
@@ -192,24 +187,39 @@ public class SpotProvider
* @param message the text of the chat message.
*/
public void sendClusterChatMessage (
int sceneId, int locId, int speakerOid, String speaker,
int sceneId, int speakerOid, String speaker,
String bundle, String message, byte mode)
{
// look up the scene manager for the specified scene
SpotSceneManager smgr = (SpotSceneManager)
_screg.getSceneManager(sceneId);
if (smgr == null) {
Log.warning("User requested cluster chat in " +
"non-existent scene [user=" + speaker +
", sceneId=" + sceneId + ", locId=" + locId +
Log.warning("User requested cluster chat in non-existent scene " +
"[user=" + speaker + ", sceneId=" + sceneId +
", message=" + message + "].");
return;
}
// pass this request on to the spot scene manager
smgr.handleClusterSpeakRequest(
speakerOid, speaker, bundle, message, mode);
}
/**
* Obtains the scene id occupied by the supplied caller.
*
* @exception InvocationException thrown if the caller does not
* implement {@link ScenedBodyObject}.
*/
protected static int getCallerSceneId (ClientObject caller)
throws InvocationException
{
if (caller instanceof ScenedBodyObject) {
return ((ScenedBodyObject)caller).getSceneId();
} else {
// pass this request on to the spot scene manager as it will
// need to check that the location exists and that the speaker
// occupies it and so on
smgr.handleClusterSpeakRequest(
speakerOid, speaker, locId, bundle, message, mode);
Log.warning("Can't get scene from non-scened caller " +
caller.who() + ".");
throw new InvocationException(INTERNAL_ERROR);
}
}
@@ -1,10 +1,13 @@
//
// $Id: SpotSceneManager.java,v 1.24 2003/01/31 23:10:46 mdb Exp $
// $Id: SpotSceneManager.java,v 1.25 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.spot.server;
import java.util.Iterator;
import com.samskivert.util.ArrayIntSet;
import com.samskivert.util.HashIntMap;
import com.samskivert.util.IntIntMap;
import com.samskivert.util.IntListUtil;
import com.samskivert.util.StringUtil;
import com.threerings.presents.dobj.DObject;
@@ -20,10 +23,14 @@ import com.threerings.whirled.server.SceneManager;
import com.threerings.whirled.spot.Log;
import com.threerings.whirled.spot.data.ClusterObject;
import com.threerings.whirled.spot.data.ClusteredBodyObject;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SceneLocation;
import com.threerings.whirled.spot.data.SpotCodes;
import com.threerings.whirled.spot.data.SpotOccupantInfo;
import com.threerings.whirled.spot.data.SpotScene;
import com.threerings.whirled.spot.data.SpotSceneModel;
import com.threerings.whirled.spot.util.SpotSceneUtil;
import com.threerings.whirled.spot.data.SpotSceneObject;
/**
* Handles the movement of bodies between locations in the scene and
@@ -41,202 +48,207 @@ public class SpotSceneManager extends SceneManager
SpotSceneManager mgr = (SpotSceneManager)
CrowdServer.plreg.getPlaceManager(body.location);
if (mgr != null) {
RuntimeSpotScene scene = (RuntimeSpotScene)mgr.getScene();
SpotScene scene = (SpotScene)mgr.getScene();
try {
mgr.handleChangeLocRequest(body, scene.getDefaultEntranceId());
Location eloc = scene.getDefaultEntrance().getLocation();
mgr.handleChangeLocRequest(body, eloc, -1);
} catch (InvocationException ie) {
Log.warning("Could not walk user to default portal " +
"[error=" + ie + "].");
Log.warning("Could not move user to default portal " +
"[where=" + mgr.where() + ", who=" + body.who() +
", error=" + ie + "].");
}
}
}
/**
* Prepares a mapping for an entering body, indicating that they will
* be entering at the specified location id. When the time comes to
* prepare that body's occupant info, we will use the supplied
* location id as their starting location.
* Assigns a starting location for an entering body. This will happen
* before the body is made to "occupy" the scene (defined by their
* having an occupant info record). So when they do finally occupy the
* scene, the client will know where to render them.
*/
public void mapEnteringBody (int bodyOid, int locationId)
public void mapEnteringBody (BodyObject body, int portalId)
{
_entering.put(bodyOid, locationId);
_enterers.put(body.getOid(), portalId);
}
/**
* If scene entry fails, this can be called to undo a scene entry
* mapping.
* Called if a body failed to enter our scene after we assigned them
* an entering position.
*/
public void clearEnteringBody (int bodyOid)
public void clearEnteringBody (BodyObject body)
{
_entering.remove(bodyOid);
_enterers.remove(body.getOid());
}
/**
* Returns the locationId of an unoccupied location in this scene
* (portals are not included when selecting). If no locations are
* unoccupied, this method returns -1. This will mark the location as
* pending so that subsequent calls to
* <code>getUnoccupiedLocation()</code> do not return the previously
* returned location as unoccupied, giving the caller a chance to
* actually occupy the location. However, if another user moves to
* that location bewteen the call to this method and the caller's own
* request to move to the location, the caller's move request will
* fail.
*/
public int getUnoccupiedLocation (boolean preferClusters)
// documentation inherited
protected void didStartup ()
{
int locId = SpotSceneUtil.getUnoccupiedLocation(
_sscene.getModel(), _locationOccs, preferClusters);
if (locId != -1) {
// mark the location as pending
// Log.info("Earmarked location [scene=" + where() +
// ", locId=" + locId + "].");
_locationOccs[_sscene.getLocationIndex(locId)] = -1;
}
return locId;
}
// get a casted reference to our place object (we need to do this
// before calling super.didStartup() because that will call
// sceneManagerDidResolve() which may start letting people into
// the scene)
_ssobj = (SpotSceneObject)_plobj;
/**
* Returns true if the location in question is occupied by another
* body (or reserved for someone who's on their way).
*/
public boolean isLocationOccupied (int locId)
{
return (_locationOccs[_sscene.getLocationIndex(locId)] != 0);
super.didStartup();
}
// documentation inherited
protected void gotSceneData ()
{
super.gotSceneData();
// keep a casted reference around to our scene
_sscene = (RuntimeSpotScene)_scene;
// now that we have our scene, we create chat objects for each of
// the clusters in the scene
_clusterObjs = new DObject[_sscene.getClusterCount()];
// create a subscriber that will grab the oids when we hear back
// about object creation
Subscriber sub = new Subscriber() {
public void objectAvailable (DObject object) {
_clusterObjs[_index++] = object;
}
public void requestFailed (int oid, ObjectAccessException cause) {
Log.warning("Failed to create cluster object " +
"[where=" + where() + ", cluster=" + _index +
", oid=" + oid + ", cause=" + cause + "].");
// skip to the next cluster in case others didn't fail
_index++;
}
protected int _index = 0;
};
// now issue the object creation requests
for (int i = 0; i < _clusterObjs.length; i++) {
_omgr.createObject(ClusterObject.class, sub);
}
// create an array in which to track the occupants of each
// location
_locationOccs = new int[_sscene.getLocationCount()];
_isPortal = new boolean[_sscene.getLocationCount()];
SpotSceneModel model = _sscene.getModel();
for (int ii=0; ii < model.locationIds.length; ii++) {
_isPortal[ii] = IntListUtil.contains(model.portalIds,
model.locationIds[ii]);
}
_sscene = (SpotScene)_scene;
}
/**
* When a user is entering a scene, we populate their occupant info
* with the location prepared by the portal traversal code or with the
* default entrance for the scene if no preparation was done.
*/
// documentation inherited
protected void bodyLeft (int bodyOid)
{
super.bodyLeft(bodyOid);
// clear out their location information
_ssobj.removeFromOccupantLocs(new Integer(bodyOid));
// clear any cluster they may occupy
removeFromCluster(bodyOid);
}
// documentation inherited
protected void populateOccupantInfo (OccupantInfo info, BodyObject body)
{
super.populateOccupantInfo(info, body);
// we have a table for tracking the locations of entering bodies
// which is populated by the portal traversal code when a body
// requests to enter our scene. if there's a mapped entrance
// location for this body, use it, otherwise assume they're coming
// in at the default entrance
int entryLocId = _entering.remove(body.getOid());
if (entryLocId == -1) {
entryLocId = _sscene.getDefaultEntranceId();
// we don't actually populate their occupant info, but instead
// assign them their starting location in the scene
int portalId = _enterers.remove(body.getOid());
Portal entry;
if (portalId != -1) {
entry = _sscene.getPortal(portalId);
if (entry == null) {
Log.warning("Body mapped at invalid portal [where=" + where() +
", who=" + body.who() +
", portalId=" + portalId + "].");
entry = _sscene.getDefaultEntrance();
}
} else {
entry = _sscene.getDefaultEntrance();
}
((SpotOccupantInfo)info).locationId = entryLocId;
// Log.info("Positioning entering body [who=" + body.who() +
// ", where=" + entry.getOppLocation() + "].");
// create a scene location for them located on the entrance portal
// but facing the opposite direction
_ssobj.addToOccupantLocs(
new SceneLocation(entry.getOppLocation(), body.getOid()));
}
/**
* Called by the {@link SpotProvider} when we receive a request by a
* user to occupy a particular location.
*
* @return the oid of the chat object associated with the cluster to
* which this location belongs or -1 if the location is not part of a
* cluster.
* @param source the body to be moved.
* @param loc the location to which to move the body.
* @param cluster if zero, a new cluster will be created and assigned
* to the moving user; if -1, the moving 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 moving user will be made to
* 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.
*/
protected int handleChangeLocRequest (BodyObject source, int locationId)
protected void handleChangeLocRequest (
BodyObject source, Location loc, int cluster)
throws InvocationException
{
// make sure no one is already in the requested location
int locidx = _sscene.getLocationIndex(locationId);
if (locidx == -1) {
Log.warning("Ignoring request to move to non-existent location " +
"[where=" + where() + ", user=" + source.who() +
", locId=" + locationId + "].");
throw new InvocationException(LOCATION_OCCUPIED);
} else if (_locationOccs[locidx] > 0) {
Log.info("Ignoring request to move to occupied location " +
"[where=" + where() + ", user=" + source.who() +
", locId=" + locationId +
", occupantOid=" + _locationOccs[locidx] + "].");
throw new InvocationException(LOCATION_OCCUPIED);
}
// make sure they have an occupant info object in the place
int bodyOid = source.getOid();
SpotOccupantInfo soi = (SpotOccupantInfo)getOccupantInfo(bodyOid);
if (soi == null) {
Log.warning("Aiya! Can't update non-existent occupant info " +
"with new location [where=" + where() +
", body=" + source.who() + ":" + source.location +
", newLocId=" + locationId + "].");
// make sure they are in our scene
if (!_ssobj.occupants.contains(source.getOid())) {
Log.warning("Refusing change loc from non-scene occupant " +
"[where=" + where() + ", who=" + source.who() +
", loc=" + loc + "].");
throw new InvocationException(INTERNAL_ERROR);
}
// clear out any location they previously occupied
if (soi.locationId > 0) {
int oldlocidx = _sscene.getLocationIndex(soi.locationId);
if (oldlocidx == -1) {
Log.warning("Changing location for body that was " +
"previously in an invalid location " +
"[where=" + where() + ", info=" + soi + "].");
} else {
_locationOccs[oldlocidx] = 0;
}
// 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
SceneLocation sloc = new SceneLocation(loc, source.getOid());
if (!_ssobj.occupantLocs.contains(sloc)) {
// complain if they don't already have a location configured
Log.warning("Changing loc for occupant without previous loc " +
"[where=" + where() + ", who=" + source.who() +
", nloc=" + loc + "].");
_ssobj.addToOccupantLocs(sloc);
} else {
_ssobj.updateOccupantLocs(sloc);
}
// stick our new friend into that location, if it's not a portal
if (!_isPortal[locidx]) {
_locationOccs[locidx] = bodyOid;
// handle the cluster situation
switch (cluster) {
case 0:
createNewCluster(source);
break;
case -1:
removeFromCluster(source.getOid());
break;
default:
addToCluster(cluster, source);
break;
}
}
// update the location and broadcast to the place
soi.locationId = locationId;
updateOccupantInfo(soi);
/**
* Creates a new cluster with the specified user being added to said
* cluster.
*/
protected void createNewCluster (BodyObject creator)
{
// remove them from any previous cluster
removeFromCluster(creator.getOid());
// figure out the cluster chat oid
int clusterIdx = _sscene.getClusterIndex(locidx);
return (clusterIdx == -1) ? -1 : _clusterObjs[clusterIdx].getOid();
// create a cluster record and map this user to it
ClusterRecord clrec = new ClusterRecord();
if (clrec.addBody(creator)) {
_clusters.put(creator.getOid(), clrec);
}
// if we failed to add the creator, the cluster record will
// quietly off itself when it's done subscribing to its object
}
/**
* Adds the specified user to the cluster occupied by the specified
* other user.
*/
protected void addToCluster (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.addBody(joiner)) {
_clusters.put(joiner.getOid(), clrec);
}
}
/**
* Removes the specified user from any cluster they occupy.
*/
protected void removeFromCluster (int bodyOid)
{
ClusterRecord clrec = (ClusterRecord)_clusters.remove(bodyOid);
if (clrec != null) {
clrec.removeBody(bodyOid);
}
}
/**
@@ -244,99 +256,123 @@ public class SpotSceneManager extends SceneManager
* request.
*/
protected void handleClusterSpeakRequest (
int sourceOid, String source, int locationId,
String bundle, String message, byte mode)
int sourceOid, String source, String bundle, String message, byte mode)
{
int locIdx = _sscene.getLocationIndex(locationId);
// make sure this user occupies the specified location
int locOccId = (locIdx == -1) ? -1 : _locationOccs[locIdx];
if (locOccId != sourceOid) {
Log.warning("User not in specified location for CCREQ " +
ClusterRecord clrec = (ClusterRecord)_clusters.get(sourceOid);
if (clrec == null) {
Log.warning("Non-clustered user requested cluster speak " +
"[where=" + where() + ", chatter=" + source +
" (" + sourceOid + "), locId=" + locationId +
", locIdx=" + locIdx +
", locOccs=" + StringUtil.toString(_locationOccs) +
", message=" + message + "].");
return;
" (" + sourceOid + "), msg=" + message + "].");
} else {
SpeakProvider.sendSpeak(clrec.getClusterObject(),
source, bundle, message, mode);
}
// make sure there's a cluster associated with this location
int clusterIndex = _sscene.getClusterIndex(locIdx);
if (clusterIndex == -1) {
Log.warning("User in clusterless location sent CCREQ " +
"[where=" + where() + ", chatter=" + source +
" (" + sourceOid + "), locId=" + locationId +
", message=" + message + "].");
return;
}
DObject clusterObj = _clusterObjs[clusterIndex];
if (clusterObj == null) {
Log.warning("Have no cluster object for CCREQ " +
"[where=" + where() + ", cidx=" + clusterIndex +
", chatter=" + source + " (" + sourceOid +
"), message=" + message + "].");
return;
}
// all is well, generate a chat notification
SpeakProvider.sendSpeak(clusterObj, source, bundle, message, mode);
}
/**
* @return true if the specified user is in the scene and
* in a valid location (not on a portal).
* Used to manage clusters which are groups of users that can chat to
* one another.
*/
protected boolean inValidLocation (BodyObject body)
protected static class ClusterRecord extends HashIntMap
implements Subscriber
{
int bodyOid = body.getOid();
for (int ii=0; ii < _locationOccs.length; ii++) {
if (_locationOccs[ii] == bodyOid) {
public ClusterRecord ()
{
CrowdServer.omgr.createObject(ClusterObject.class, this);
}
public boolean addBody (BodyObject body)
{
if (body instanceof ClusteredBodyObject) {
if (_clobj != null) {
((ClusteredBodyObject)body).setClusterOid(_clobj.getOid());
}
put(body.getOid(), body);
_clobj.addToOccupants(body.getOid());
return true;
} else {
Log.warning("Refusing to add non-clustered body to cluster " +
"[cloid=" + _clobj.getOid() +
", size=" + size() + ", who=" + body.who() + "].");
return false;
}
}
return false;
}
/**
* When an occupant leaves the room, we want to clear out any location
* they may have occupied.
*/
protected void bodyLeft (int bodyOid)
{
super.bodyLeft(bodyOid);
public void removeBody (int bodyOid)
{
ClusteredBodyObject body = (ClusteredBodyObject)remove(bodyOid);
if (body == null) {
Log.warning("Requested to remove unknown body from cluster " +
"[cloid=" + _clobj.getOid() +
", size=" + size() + ", who=" + bodyOid + "].");
} else {
body.setClusterOid(-1);
_clobj.removeFromOccupants(bodyOid);
}
for (int i = 0; i < _locationOccs.length; i++) {
if (_locationOccs[i] == bodyOid) {
_locationOccs[i] = 0;
break;
// if we've removed our last body; stick a fork in ourselves
if (size() == 0) {
destroy();
}
}
public ClusterObject getClusterObject ()
{
return _clobj;
}
public void objectAvailable (DObject object)
{
// keep this feller around
_clobj = (ClusterObject)object;
// let any mapped users know about our cluster
Iterator iter = values().iterator();
while (iter.hasNext()) {
ClusteredBodyObject body = (ClusteredBodyObject)iter.next();
body.setClusterOid(_clobj.getOid());
}
// if we didn't manage to add our creating user when we first
// started up, there's no point in our sticking around
if (size() == 0) {
destroy();
}
}
public void requestFailed (int oid, ObjectAccessException cause)
{
Log.warning("Aiya! Failed to create cluster object " +
"[cause=" + cause + ", penders=" + size() + "].");
// let any mapped users know that we're hosed
Iterator iter = values().iterator();
while (iter.hasNext()) {
ClusteredBodyObject body = (ClusteredBodyObject)iter.next();
body.setClusterOid(-1);
}
}
protected void destroy ()
{
Log.info("Cluster empty, going away " +
"[cloid=" + _clobj.getOid() + "].");
CrowdServer.omgr.destroyObject(_clobj.getOid());
}
protected ClusterObject _clobj;
}
/**
* We need our own extended occupant info to keep track of what
* location each occupant occupies.
*/
protected Class getOccupantInfoClass ()
{
return SpotOccupantInfo.class;
}
/** A casted reference to our place object. */
protected SpotSceneObject _ssobj;
/** A casted reference to our runtime scene instance. */
protected RuntimeSpotScene _sscene;
/** A casted reference to our scene instance. */
protected SpotScene _sscene;
/** Our cluster chat objects. */
protected DObject[] _clusterObjs;
/** Records with information on all clusters in this scene. */
protected HashIntMap _clusters = new HashIntMap();
/** Oids of the bodies that occupy each of our locations. */
protected int[] _locationOccs;
/** Tracks if each location is a portal. */
protected boolean[] _isPortal;
/** A table of mappings from body oids to entry location ids for
* bodies that are entering our scene. */
protected IntIntMap _entering = new IntIntMap();
/** A mapping of entering bodies to portal ids. */
protected IntIntMap _enterers = new IntIntMap();
}
@@ -1,7 +1,7 @@
//
// $Id: EditablePortal.java,v 1.2 2001/12/05 03:38:09 mdb Exp $
// $Id: EditablePortal.java,v 1.3 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.tools.spot;
package com.threerings.whirled.spot.tools;
import com.threerings.whirled.spot.data.Portal;
@@ -21,13 +21,4 @@ public class EditablePortal extends Portal
/** The human-readable name of the portal to which this portal links
* in its target scene. */
public String targetPortalName;
// documentation inherited
protected void toString (StringBuffer buf)
{
super.toString(buf);
buf.append(", name=").append(name);
buf.append(", targetScene=").append(targetSceneName);
buf.append(", targetPortal=").append(targetPortalName);
}
}
@@ -1,67 +0,0 @@
//
// $Id: EditableSpotScene.java,v 1.5 2001/12/05 09:20:10 mdb Exp $
package com.threerings.whirled.tools.spot;
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);
/**
* Returns the next valid location id for this scene. Newly created
* portals or locations should be assigned a new location id via this
* method.
*/
public int getNextLocationId ();
/**
* 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 (EditablePortal portal);
/**
* Removes a portal from this scene (it should be removed accordingly
* from both the location and portal arrays).
*/
public void removePortal (EditablePortal 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 EditableSpotSceneModel getSpotSceneModel ();
}
@@ -1,257 +0,0 @@
//
// $Id: EditableSpotSceneImpl.java,v 1.11 2003/01/31 23:10:46 mdb Exp $
package com.threerings.whirled.tools.spot;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.tools.EditableSceneModel;
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 EditableSceneImpl
implements EditableSpotScene
{
/**
* Creates an instance that will create and use a blank scene model.
*/
public EditableSpotSceneImpl ()
{
this(EditableSpotSceneModel.blankSpotSceneModel());
}
/**
* Creates an instance that will obtain data from the supplied scene
* model and update it when changes are made.
*/
public EditableSpotSceneImpl (EditableSpotSceneModel model)
{
this(model, new DisplaySpotSceneImpl(model.spotSceneModel, null));
}
/**
* Creates an instance that will obtain data from the supplied scene
* model and update it when changes are made. It will delegate to the
* supplied display spot scene instead of creating its own delegate.
*/
public EditableSpotSceneImpl (
EditableSpotSceneModel model, DisplaySpotSceneImpl delegate)
{
super(model, delegate);
// keep track of these
_model = model.spotSceneModel;
_emodel = model;
_delegate = delegate;
// go through and replace the plain portals with editable portals
// (oh the machinations we have to go through for the lack of
// multiple inheritance)
List portals = _delegate.getPortals();
for (int i = 0; i < portals.size(); i++) {
EditablePortal port = dupePortal((Portal)portals.get(i));;
port.name = _emodel.portalNames[i];
port.targetSceneName = (String)_emodel.neighborNames.get(i);
port.targetPortalName = _emodel.targetPortalNames[i];
portals.set(i, port);
}
// determine the highest location id in use by this scene
Iterator iter = _delegate.getLocations().iterator();
while (iter.hasNext()) {
_nextLocationId = Math.max(_nextLocationId,
((Location)iter.next()).locationId);
}
}
/**
* Constructs an editable portal with the same configuration as the
* supplied regular portal.
*/
protected EditablePortal dupePortal (Portal source)
{
EditablePortal port = new EditablePortal();
port.locationId = source.locationId;
port.x = source.x;
port.y = source.y;
port.orientation = source.orientation;
port.clusterIndex = source.clusterIndex;
port.targetSceneId = source.targetSceneId;
port.targetLocId = source.targetLocId;
return port;
}
// documentation inherited
public int getDefaultEntranceId ()
{
return _delegate.getDefaultEntranceId();
}
// documentation inherited
public List getLocations ()
{
return _delegate.getLocations();
}
// documentation inherited
public int getLocationIndex (int locationId)
{
return _delegate.getLocationIndex(locationId);
}
// documentation inherited
public Location getLocation (int locationId)
{
return _delegate.getLocation(locationId);
}
// documentation inherited
public List getPortals ()
{
return _delegate.getPortals();
}
// documentation inherited
public void setDefaultEntranceId (int defaultEntranceId)
{
_model.defaultEntranceId = defaultEntranceId;
}
// documentation inherited
public int getNextLocationId ()
{
return ++_nextLocationId;
}
// documentation inherited
public void addLocation (Location loc)
{
// add the location to the end of the location list
_delegate.getLocations().add(loc);
// make sure we've got the highest location id in our next
// location id field
_nextLocationId = Math.max(_nextLocationId, loc.locationId);
}
// documentation inherited
public void removeLocation (Location loc)
{
// remove the location from the list
_delegate.getLocations().remove(loc);
}
// documentation inherited
public void addPortal (EditablePortal eport)
{
// add it to the locations lists as well
addLocation(eport);
// now add it to the end of the _portals list
_delegate.getPortals().add(eport);
}
// documentation inherited
public void removePortal (EditablePortal eport)
{
// remove it from the locations list
removeLocation(eport);
// and remove it from the portals list
_delegate.getPortals().remove(eport);
}
// documentation inherited
public EditableSpotSceneModel getSpotSceneModel ()
{
flushToModel();
return _emodel;
}
/**
* 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 ()
{
super.flushToModel();
List locations = _delegate.getLocations();
// flush the locations
int lcount = locations.size();
_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 = (Location)locations.get(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
List portals = _delegate.getPortals();
int pcount = portals.size();
_model.portalIds = new int[pcount];
_model.neighborIds = new int[pcount];
_model.targetLocIds = new int[pcount];
_emodel.neighborNames = new ArrayList();
_emodel.portalNames = new String[pcount];
_emodel.targetPortalNames = new String[pcount];
for (int i = 0; i < pcount; i++) {
EditablePortal port = (EditablePortal)portals.get(i);
_model.portalIds[i] = port.locationId;
_model.neighborIds[i] = port.targetSceneId;
_model.targetLocIds[i] = port.targetLocId;
_emodel.portalNames[i] = port.name;
_emodel.neighborNames.add(port.targetSceneName);
_emodel.targetPortalNames[i] = port.targetPortalName;
}
}
/** Our spot scene model. */
protected SpotSceneModel _model;
/** Our editable spot scene model. */
protected EditableSpotSceneModel _emodel;
/** Our display spot scene delegate. */
protected DisplaySpotSceneImpl _delegate;
/** A location id counter used for assigning ids to new locations. */
protected int _nextLocationId;
}
@@ -1,87 +0,0 @@
//
// $Id: EditableSpotSceneModel.java,v 1.3 2001/12/12 02:47:17 mdb Exp $
package com.threerings.whirled.tools.spot;
import com.samskivert.util.StringUtil;
import com.threerings.whirled.spot.data.SpotSceneModel;
import com.threerings.whirled.tools.EditableSceneModel;
public class EditableSpotSceneModel extends EditableSceneModel
{
/** The spot scene model that we extend with editable info. */
public SpotSceneModel spotSceneModel;
/** The names of the portals in this scene. */
public String[] portalNames;
/** The names of the portals in neighboring scenes to which our
* portals link. */
public String[] targetPortalNames;
// documentation inherited
public Object clone ()
throws CloneNotSupportedException
{
return cloneWithDelegate((SpotSceneModel)spotSceneModel.clone());
}
// documentation inherited
protected Object cloneWithDelegate (SpotSceneModel spotSceneModel)
throws CloneNotSupportedException
{
EditableSpotSceneModel essm = (EditableSpotSceneModel)
super.cloneWithDelegate(spotSceneModel);
essm.spotSceneModel = spotSceneModel;
return essm;
}
/**
* Derived classes override this to tack their <code>toString</code>
* data on to the string buffer.
*/
protected void delegatesToString (StringBuffer buf)
{
buf.append(spotSceneModel);
}
/**
* Derived classes override this to tack their <code>toString</code>
* data on to the string buffer.
*/
protected void toString (StringBuffer buf)
{
super.toString(buf);
buf.append(", portalNames=").
append(StringUtil.toString(portalNames));
buf.append(", targetPortalNames=").
append(StringUtil.toString(targetPortalNames));
}
/**
* Creates and returns a blank scene model.
*/
public static EditableSpotSceneModel blankSpotSceneModel ()
{
EditableSpotSceneModel model = new EditableSpotSceneModel();
model.spotSceneModel = SpotSceneModel.blankSpotSceneModel();
model.sceneModel = model.spotSceneModel;
populateBlankSpotSceneModel(model);
return model;
}
/**
* Populates a blank scene model with blank values.
*/
protected static void populateBlankSpotSceneModel (
EditableSpotSceneModel model)
{
// populate our superclass fields
populateBlankSceneModel(model);
// now populate our fields
model.portalNames = new String[0];
model.targetPortalNames = new String[0];
}
}
@@ -1,59 +0,0 @@
//
// $Id: SpotSceneParser.java,v 1.1 2001/12/05 03:38:09 mdb Exp $
package com.threerings.whirled.tools.spot.xml;
import java.io.IOException;
import java.io.FileInputStream;
import org.xml.sax.SAXException;
import org.apache.commons.digester.Digester;
import com.threerings.whirled.tools.spot.EditableSpotScene;
import com.threerings.whirled.tools.spot.EditableSpotSceneImpl;
/**
* A simple class for parsing an editable spot scene instance.
*/
public class SpotSceneParser
{
/**
* Constructs a scene parser that parses scenes with the specified XML
* path prefix. See the {@link SpotSceneRuleSet#SpotSceneRuleSet}
* documentation for more information.
*/
public SpotSceneParser (String prefix)
{
// create and configure our digester
_digester = new Digester();
SpotSceneRuleSet set = new SpotSceneRuleSet();
set.setPrefix(prefix);
_digester.addRuleSet(set);
_digester.addSetNext(prefix, "setScene",
EditableSpotScene.class.getName());
}
/**
* Parses the XML file at the specified path into an editable scene
* instance.
*/
public EditableSpotScene parseScene (String path)
throws IOException, SAXException
{
_scene = null;
_digester.push(this);
_digester.parse(new FileInputStream(path));
return _scene;
}
/**
* Called by the parser once the scene is parsed.
*/
public void setScene (EditableSpotScene scene)
{
_scene = scene;
}
protected Digester _digester;
protected EditableSpotScene _scene;
}
@@ -1,54 +1,41 @@
//
// $Id: SpotSceneRuleSet.java,v 1.3 2001/12/05 03:40:32 mdb Exp $
// $Id: SpotSceneRuleSet.java,v 1.4 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.tools.spot.xml;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSetBase;
package com.threerings.whirled.spot.tools.xml;
import com.samskivert.xml.SetPropertyFieldsRule;
import com.threerings.tools.xml.NestableRuleSet;
import org.apache.commons.digester.Digester;
import com.threerings.whirled.tools.xml.SceneRuleSet;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.tools.spot.EditablePortal;
import com.threerings.whirled.tools.spot.EditableSpotScene;
import com.threerings.whirled.tools.spot.EditableSpotSceneImpl;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SpotSceneModel;
import com.threerings.whirled.spot.tools.EditablePortal;
/**
* Used to parse an {@link EditableSpotScene} from XML.
* Used to parse a {@link SpotSceneModel} from XML.
*/
public class SpotSceneRuleSet extends SceneRuleSet
public class SpotSceneRuleSet implements NestableRuleSet
{
/**
* Extends the scene rule set with the necessary rules to parse our
* spot scene data.
*/
public void addRuleInstances (Digester digester)
// documentation inherited from interface
public String getOuterElement ()
{
super.addRuleInstances(digester);
return SpotSceneWriter.OUTER_ELEMENT;
}
// create Location instances when we see <location>
String elclass = Location.class.getName();
digester.addObjectCreate(_prefix + "/location", elclass);
digester.addRule(_prefix + "/location",
new SetPropertyFieldsRule(digester));
digester.addSetNext(_prefix + "/location", "addLocation", elclass);
// documentation inherited from interface
public void addRuleInstances (String prefix, Digester digester)
{
digester.addObjectCreate(prefix, SpotSceneModel.class.getName());
// set up rules to parse and set our fields
digester.addRule(prefix, new SetPropertyFieldsRule(digester));
// create EditablePortal instances when we see <portal>
String epclass = EditablePortal.class.getName();
digester.addObjectCreate(_prefix + "/portal", epclass);
digester.addRule(_prefix + "/portal",
digester.addObjectCreate(prefix + "/portal",
EditablePortal.class.getName());
digester.addRule(prefix + "/portal",
new SetPropertyFieldsRule(digester));
digester.addSetNext(_prefix + "/portal", "addPortal", epclass);
}
/**
* This indicates the class (which should implement {@link
* EditableSpotScene}) to be instantiated during the parsing process.
*/
protected Class getSceneClass ()
{
return EditableSpotSceneImpl.class;
digester.addSetNext(prefix + "/portal", "addPortal",
Portal.class.getName());
}
}
@@ -1,70 +1,61 @@
//
// $Id: SpotSceneWriter.java,v 1.6 2001/12/07 05:14:57 mdb Exp $
// $Id: SpotSceneWriter.java,v 1.7 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.tools.spot.xml;
import java.util.Iterator;
package com.threerings.whirled.spot.tools.xml;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import com.megginson.sax.DataWriter;
import com.samskivert.util.StringUtil;
import com.threerings.tools.xml.NestableWriter;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.Log;
import com.threerings.whirled.tools.EditableScene;
import com.threerings.whirled.tools.spot.EditablePortal;
import com.threerings.whirled.tools.spot.EditableSpotScene;
import com.threerings.whirled.tools.xml.SceneWriter;
import com.threerings.whirled.spot.data.SpotSceneModel;
import com.threerings.whirled.spot.tools.EditablePortal;
/**
* Generates an XML representation of an {@link EditableSpotScene}.
* Generates an XML representation of a {@link SpotSceneModel}.
*/
public class SpotSceneWriter extends SceneWriter
public class SpotSceneWriter
implements NestableWriter
{
protected void addSceneAttributes (
EditableScene scene, AttributesImpl attrs)
{
super.addSceneAttributes(scene, attrs);
EditableSpotScene sscene = (EditableSpotScene)scene;
attrs.addAttribute("", "defaultEntranceId", "", "",
Integer.toString(sscene.getDefaultEntranceId()));
}
/** The outer element used to enclose our spot scene definition. */
public static final String OUTER_ELEMENT = "spot";
protected void writeSceneData (EditableScene scene, DataWriter writer)
// documentation inherited from interface
public void write (Object object, DataWriter writer)
throws SAXException
{
// we don't want to write our superclass scene data because it
// writes out neighbors info which we deal with differently, so we
// mean not to call super.writeSceneData()
SpotSceneModel model = (SpotSceneModel)object;
AttributesImpl attrs = new AttributesImpl();
addSceneAttributes(model, attrs);
writer.startElement("", OUTER_ELEMENT, "", attrs);
writeSceneData(model, writer);
writer.endElement(OUTER_ELEMENT);
}
EditableSpotScene sscene = (EditableSpotScene)scene;
// write out the location info
Iterator iter = sscene.getLocations().iterator();
while (iter.hasNext()) {
Location loc = (Location)iter.next();
// skip portals as we'll get those on the next run
if (loc instanceof EditablePortal) {
continue;
}
AttributesImpl attrs = new AttributesImpl();
addSharedAttrs(attrs, loc);
attrs.addAttribute("", "clusterIndex", "", "",
Integer.toString(loc.clusterIndex));
writer.emptyElement("", "location", "", attrs);
protected void addSceneAttributes (SpotSceneModel model,
AttributesImpl attrs)
{
if (model.defaultEntranceId != -1) {
attrs.addAttribute("", "defaultEntranceId", "", "",
Integer.toString(model.defaultEntranceId));
}
}
protected void writeSceneData (SpotSceneModel model, DataWriter writer)
throws SAXException
{
// write out the portal info
iter = sscene.getPortals().iterator();
while (iter.hasNext()) {
EditablePortal port = (EditablePortal)iter.next();
for (int ii = 0; ii < model.portals.length; ii++) {
EditablePortal port = (EditablePortal)model.portals[ii];
AttributesImpl attrs = new AttributesImpl();
addSharedAttrs(attrs, port);
attrs.addAttribute("", "portalId", "", "",
Integer.toString(port.portalId));
attrs.addAttribute("", "x", "", "", Integer.toString(port.x));
attrs.addAttribute("", "y", "", "", Integer.toString(port.y));
attrs.addAttribute("", "orient", "", "",
Integer.toString(port.orient));
maybeAddAttr(attrs, "name", port.name);
maybeAddAttr(attrs, "targetSceneName", port.targetSceneName);
maybeAddAttr(attrs, "targetPortalName", port.targetPortalName);
@@ -83,18 +74,4 @@ public class SpotSceneWriter extends SceneWriter
attrs.addAttribute("", name, "", "", value);
}
}
/**
* Adds the attributes that are shared between location and portal
* elements.
*/
protected void addSharedAttrs (AttributesImpl attrs, Location loc)
{
attrs.addAttribute("", "locationId", "", "",
Integer.toString(loc.locationId));
attrs.addAttribute("", "x", "", "", Integer.toString(loc.x));
attrs.addAttribute("", "y", "", "", Integer.toString(loc.y));
attrs.addAttribute("", "orientation", "", "",
Integer.toString(loc.orientation));
}
}
@@ -1,146 +0,0 @@
//
// $Id: SpotSceneUtil.java,v 1.2 2002/06/25 01:41:59 ray Exp $
package com.threerings.whirled.spot.util;
import java.util.Iterator;
import com.samskivert.util.ArrayIntSet;
import com.samskivert.util.StringUtil;
import com.threerings.util.RandomUtil;
import com.threerings.presents.dobj.DSet;
import com.threerings.whirled.spot.data.SpotOccupantInfo;
import com.threerings.whirled.spot.data.SpotSceneModel;
/**
* Spot scene utility functions shared by client and server.
*/
public class SpotSceneUtil
{
/**
* Returns the locationId of an unoccupied location in the supplied
* scene (portals are not included when selecting). If no locations
* are unoccupied, this method returns -1.
*
* @param preferClusters if true, cluster locations (if any are empty)
* will be preferred.
*/
public static int getUnoccupiedLocation (
SpotSceneModel model, DSet occupantInfo, boolean preferClusters)
{
ArrayIntSet locs = getStartSet(model, preferClusters);
// remove any occupied locations
Iterator iter = occupantInfo.entries();
while (iter.hasNext()) {
SpotOccupantInfo yoi = (SpotOccupantInfo)iter.next();
locs.remove(yoi.locationId);
}
// if there are locations left, pick one at random
int size = locs.size();
if (size > 0) {
return locs.get(RandomUtil.getInt(size));
} else if (preferClusters) {
// retry without the preference
return getUnoccupiedLocation(model, occupantInfo, false);
} else {
return -1; // we didn't find anything.
}
}
/**
* Returns the locationId of an unoccupied location in the supplied
* scene (portals are not included when selecting). If no locations
* are unoccupied, this method returns -1.
*
* @param preferClusters if true, cluster locations (if any are empty)
* will be preferred.
*/
public static int getUnoccupiedLocation (
SpotSceneModel model, int[] occupiedLocs, boolean preferClusters)
{
ArrayIntSet locs = getStartSet(model, preferClusters);
// remove any occupied locations
for (int ii = 0; ii < model.locationIds.length; ii++) {
if (occupiedLocs[ii] != 0) {
locs.remove(model.locationIds[ii]);
}
}
// if there are locations left, pick one at random
int size = locs.size();
if (size > 0) {
return locs.get(RandomUtil.getInt(size));
} else if (preferClusters) {
// retry without the preference
return getUnoccupiedLocation(model, occupiedLocs, false);
} else {
return -1; // we didn't find anything.
}
}
/**
* Return an unoccupied location within the specified cluster.
*/
public static int getUnoccupiedLocation (
SpotSceneModel model, DSet occupantInfo, int clusterId)
{
ArrayIntSet locs = new ArrayIntSet();
// only add locations with a valid cluster Id
for (int ii=0; ii < model.locationIds.length; ii++) {
if (model.locationClusters[ii] == clusterId) {
locs.add(model.locationIds[ii]);
}
}
// remove any occupied locations
Iterator iter = occupantInfo.entries();
while (iter.hasNext()) {
SpotOccupantInfo yoi = (SpotOccupantInfo)iter.next();
locs.remove(yoi.locationId);
}
// if there are locations left, pick one at random
int size = locs.size();
if (size > 0) {
return locs.get(RandomUtil.getInt(size));
} else {
return -1; // we didn't find anything.
}
}
/** Used by {@link #getUnoccupiedLocation}. */
protected static ArrayIntSet getStartSet (
SpotSceneModel model, boolean preferClusters)
{
ArrayIntSet locs = new ArrayIntSet();
if (preferClusters) {
// only add locations with a valid cluster Id
for (int ii=0; ii < model.locationIds.length; ii++) {
if (model.locationClusters[ii] != 0) {
locs.add(model.locationIds[ii]);
}
}
} else {
// start with all the locations in the scene
locs.add(model.locationIds);
// remove the portals
locs.remove(model.portalIds);
}
return locs;
}
}
@@ -1,77 +0,0 @@
//
// $Id: EditableScene.java,v 1.4 2001/12/12 19:06:15 mdb Exp $
package com.threerings.whirled.tools;
import java.util.ArrayList;
import com.threerings.whirled.client.DisplayScene;
import com.threerings.whirled.data.SceneModel;
/**
* The editable 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> Because the editable scene is used in the scene editor, where it is
* displayed, the editable scene interface extends the {@link
* DisplayScene} interface so that the same display mechanisms can be used
* in the client and the editor. This leaves one anomaly, however which is
* that {@link #getPlaceConfig} is out of place in the editor or in
* loading tools. Instead of complicating things with an additional
* interface that factors out that method, we instead recommend that
* editable scene implementations simply return null from that method with
* the expectation that it will never be called.
*/
public interface EditableScene extends DisplayScene
{
/**
* Sets this scene's unique identifier.
*/
public void setId (int sceneId);
/**
* Sets the human readable name of this scene.
*/
public void setName (String name);
/**
* Sets this scene's version number.
*/
public void setVersion (int version);
/**
* Sets the ids of the neighbors of this scene.
*/
public void setNeighborIds (int[] neighborIds);
/**
* Returns the names of the neighbors of this scene.
*/
public ArrayList getNeighborNames ();
/**
* Adds a neighbor to this scene. If the neighbor is already listed
* among the neighbors, it will not be added again.
*/
public void addNeighbor (String neighborName);
/**
* Adds a neighbor to this scene.
*
* @return true if the neighbor was removed, false if they were not in
* the neighbor list.
*/
public boolean removeNeighbor (String neighborName);
/**
* Implementations must provide an editable 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 EditableSceneModel getSceneModel ();
}
@@ -1,144 +0,0 @@
//
// $Id: EditableSceneImpl.java,v 1.7 2003/01/31 23:10:46 mdb Exp $
package com.threerings.whirled.tools;
import java.util.ArrayList;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.client.DisplaySceneImpl;
import com.threerings.whirled.data.SceneModel;
/**
* A basic implementation of the {@link EditableScene} interface.
*/
public class EditableSceneImpl implements EditableScene
{
/**
* Creates an instance that will create and use a blank scene model.
*/
public EditableSceneImpl ()
{
this(EditableSceneModel.blankSceneModel());
}
/**
* Creates an instance that will obtain data from the supplied scene
* model and update it when changes are made.
*/
public EditableSceneImpl (EditableSceneModel model)
{
this(model, new DisplaySceneImpl(model.sceneModel, null));
}
/**
* Creates an instance that will obtain data from the supplied scene
* model and update it when changes are made. It will delegate to the
* supplied display scene instead of creating its own delegate.
*/
public EditableSceneImpl (
EditableSceneModel model, DisplaySceneImpl delegate)
{
_model = model.sceneModel;
_emodel = model;
_delegate = delegate;
}
// documentation inherited
public int getId ()
{
return _delegate.getId();
}
// documentation inherited
public String getName ()
{
return _delegate.getName();
}
// documentation inherited
public int getVersion ()
{
return _delegate.getVersion();
}
// documentation inherited
public int[] getNeighborIds ()
{
return _delegate.getNeighborIds();
}
// documentation inherited
public PlaceConfig getPlaceConfig ()
{
return _delegate.getPlaceConfig();
}
// documentation inherited
public void setId (int sceneId)
{
_model.sceneId = sceneId;
}
// documentation inherited
public void setName (String name)
{
_model.sceneName = name;
}
// documentation inherited
public void setVersion (int version)
{
_model.version = version;
}
// documentation inherited
public void setNeighborIds (int[] neighborIds)
{
_model.neighborIds = neighborIds;
}
// documentation inherited
public ArrayList getNeighborNames ()
{
return _emodel.neighborNames;
}
// documentation inherited
public void addNeighbor (String neighborName)
{
if (!_emodel.neighborNames.contains(neighborName)) {
_emodel.neighborNames.add(neighborName);
}
}
// documentation inherited
public boolean removeNeighbor (String neighborName)
{
return _emodel.neighborNames.remove(neighborName);
}
// documentation inherited
public EditableSceneModel getSceneModel ()
{
flushToModel();
return _emodel;
}
/**
* Derived classes should override this method and flush any editable
* modifications to the scene model when this method is called.
*/
protected void flushToModel ()
{
}
/** A reference to our scene model. */
protected SceneModel _model;
/** A reference to our editable scene model. */
protected EditableSceneModel _emodel;
/** Our display scene delegate. */
protected DisplaySceneImpl _delegate;
}
@@ -1,87 +0,0 @@
//
// $Id: EditableSceneModel.java,v 1.4 2001/12/12 19:06:15 mdb Exp $
package com.threerings.whirled.tools;
import java.util.ArrayList;
import com.samskivert.util.StringUtil;
import com.threerings.whirled.data.SceneModel;
/**
* The editable scene model contains information above and beyond the
* regular scene model that is necessary for editing and loading scenes.
*/
public class EditableSceneModel
{
/** The scene model that we extend. */
public SceneModel sceneModel;
/** The human readable name of this scene's neighbors. */
public ArrayList neighborNames;
/**
* Generates a string representation of this scene model.
*/
public String toString ()
{
StringBuffer buf = new StringBuffer("[");
delegatesToString(buf);
toString(buf);
return buf.append("]").toString();
}
// documentation inherited
public Object clone ()
throws CloneNotSupportedException
{
return cloneWithDelegate((SceneModel)sceneModel.clone());
}
// documentation inherited
protected Object cloneWithDelegate (SceneModel sceneModel)
throws CloneNotSupportedException
{
EditableSceneModel esm = (EditableSceneModel)super.clone();
esm.sceneModel = sceneModel;
return esm;
}
/**
* Derived classes override this to tack their <code>toString</code>
* data on to the string buffer.
*/
protected void delegatesToString (StringBuffer buf)
{
buf.append(sceneModel);
}
/**
* Derived classes override this to tack their <code>toString</code>
* data on to the string buffer.
*/
protected void toString (StringBuffer buf)
{
buf.append(", neighborNames=").
append(StringUtil.toString(neighborNames));
}
/**
* Creates and returns a blank editable scene model.
*/
public static EditableSceneModel blankSceneModel ()
{
EditableSceneModel model = new EditableSceneModel();
model.sceneModel = SceneModel.blankSceneModel();
populateBlankSceneModel(model);
return model;
}
/**
* Populates a blank editable scene model with blank values.
*/
protected static void populateBlankSceneModel (EditableSceneModel model)
{
model.neighborNames = new ArrayList();
}
}
@@ -1,5 +1,5 @@
//
// $Id: SceneParser.java,v 1.1 2001/12/05 03:38:09 mdb Exp $
// $Id: SceneParser.java,v 1.2 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.tools.xml;
@@ -9,8 +9,10 @@ import java.io.FileInputStream;
import org.xml.sax.SAXException;
import org.apache.commons.digester.Digester;
import com.threerings.whirled.tools.EditableScene;
import com.threerings.whirled.tools.EditableSceneImpl;
import com.samskivert.util.StringUtil;
import com.threerings.tools.xml.NestableRuleSet;
import com.threerings.whirled.data.AuxModel;
import com.threerings.whirled.data.SceneModel;
/**
* A simple class for parsing an editable scene instance.
@@ -19,40 +21,75 @@ public class SceneParser
{
/**
* Constructs a scene parser that parses scenes with the specified XML
* path prefix. See the {@link SceneRuleSet#SceneRuleSet}
* documentation for more information.
* path prefix.
*/
public SceneParser (String prefix)
{
// create and configure our digester
_digester = new Digester();
SceneRuleSet set = new SceneRuleSet();
set.setPrefix(prefix);
_digester.addRuleSet(set);
_digester.addSetNext(prefix, "setScene", EditableScene.class.getName());
// create our scene rule set
SceneRuleSet set = createSceneRuleSet();
// configure our top-level path prefix
if (StringUtil.blank(prefix)) {
_prefix = set.getOuterElement();
} else {
_prefix = prefix + "/" + set.getOuterElement();
}
// add the scene rules
set.addRuleInstances(_prefix, _digester);
// add a rule to grab the finished scene model
_digester.addSetNext(_prefix, "setScene", SceneModel.class.getName());
}
/**
* Parses the XML file at the specified path into an editable scene
* Creates the rule set used to parse our scene.
*/
protected SceneRuleSet createSceneRuleSet ()
{
return new SceneRuleSet();
}
/**
* Adds a {@link NestableRuleSet} for parsing auxiliary scene models.
*/
public void registerAuxRuleSet (NestableRuleSet set)
{
// add their outer element to the prefix
String prefix = _prefix + "/" + set.getOuterElement();
// add the rules to generate the aux scene model
set.addRuleInstances(prefix, _digester);
// and add a rule to grab it
_digester.addSetNext(prefix, "addAuxModel", AuxModel.class.getName());
}
/**
* Parses the XML file at the specified path into a scene model
* instance.
*/
public EditableScene parseScene (String path)
public SceneModel parseScene (String path)
throws IOException, SAXException
{
_scene = null;
_model = null;
_digester.push(this);
_digester.parse(new FileInputStream(path));
return _scene;
return _model;
}
/**
* Called by the parser once the scene is parsed.
*/
public void setScene (EditableScene scene)
public void setScene (SceneModel model)
{
_scene = scene;
_model = model;
}
protected String _prefix;
protected Digester _digester;
protected EditableScene _scene;
protected SceneModel _model;
}
@@ -1,63 +1,43 @@
//
// $Id: SceneRuleSet.java,v 1.2 2001/12/05 03:38:09 mdb Exp $
// $Id: SceneRuleSet.java,v 1.3 2003/02/12 07:23:31 mdb Exp $
package com.threerings.whirled.tools.xml;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSetBase;
import com.threerings.whirled.tools.EditableScene;
import com.threerings.whirled.tools.EditableSceneImpl;
import com.samskivert.util.StringUtil;
import com.samskivert.xml.SetPropertyFieldsRule;
import com.threerings.tools.xml.NestableRuleSet;
import com.threerings.whirled.data.SceneModel;
/**
* Used to parse an {@link EditableScene} from XML.
* Used to parse a {@link SceneModel} from XML.
*/
public class SceneRuleSet extends RuleSetBase
public class SceneRuleSet implements NestableRuleSet
{
/**
* Configures this scene rule set to match scenes with the supplied
* prefix. For example, passing <code>scene</code> will match the
* scene in the following XML file:
*
* <pre>
* &lt;scene name="Scene Name" version="3"&gt;
* &lt;neighbor&gt;North Scene&lt;/neighbor&gt;
* &lt;neighbor&gt;West Scene&lt;/neighbor&gt;
* &lt;!-- ... --&gt;
* &lt;/scene&gt;
* </pre>
*/
public void setPrefix (String prefix)
// documentation inherited from interface
public String getOuterElement ()
{
_prefix = prefix;
return SceneWriter.OUTER_ELEMENT;
}
/**
* Adds the necessary rules to the digester to parse our miso scene
* data.
*/
public void addRuleInstances (Digester digester)
// documentation inherited from interface
public void addRuleInstances (String prefix, Digester digester)
{
// this creates the appropriate instance when we encounter our tag
digester.addObjectCreate(_prefix, getSceneClass().getName());
digester.addObjectCreate(prefix, getSceneClass().getName());
// set up rules to parse and set our fields
digester.addSetProperties(_prefix);
digester.addCallMethod(_prefix + "/neighbor", "addNeighbor", 0);
digester.addRule(prefix, new SetPropertyFieldsRule(digester));
}
/**
* This indicates the class (which should implement {@link
* EditableScene}) to be instantiated during the parsing process.
* This indicates the class (which should extend {@link SceneModel})
* to be instantiated during the parsing process.
*/
protected Class getSceneClass ()
{
return EditableSceneImpl.class;
return SceneModel.class;
}
/** The prefix at which me match our scenes. */
protected String _prefix = DEFAULT_SCENE_PREFIX;
/** The default prefix which matches &lt;scene&gt;. */
protected static final String DEFAULT_SCENE_PREFIX = "scene";
}
@@ -1,11 +1,12 @@
//
// $Id: SceneWriter.java,v 1.3 2003/01/30 19:16:50 mdb Exp $
// $Id: SceneWriter.java,v 1.4 2003/02/12 07:23:32 mdb Exp $
package com.threerings.whirled.tools.xml;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import org.xml.sax.SAXException;
@@ -13,78 +14,92 @@ import org.xml.sax.helpers.AttributesImpl;
import com.megginson.sax.DataWriter;
import com.samskivert.util.StringUtil;
import com.threerings.tools.xml.NestableWriter;
import com.threerings.whirled.tools.EditableScene;
import com.threerings.whirled.Log;
import com.threerings.whirled.data.AuxModel;
import com.threerings.whirled.data.SceneModel;
/**
* Generates an XML representation of an {@link EditableScene}.
* Generates an XML representation of an {@link SceneModel}.
*/
public class SceneWriter
{
/** The outer element used to enclose our scene definition. */
public static final String OUTER_ELEMENT = "scene";
/**
* Writes the data for the supplied {@link EditableScene} to the XML
* writer supplied. The writer will already be configured with the
* appropriate indentation level so that this writer can simply output
* its elements and allow the calling code to determine where in the
* greater scene description file the scene data should live.
* Registers a writer for writing auxiliary scene models of the
* supplied class.
*/
public void writeScene (EditableScene scene, DataWriter writer)
throws SAXException
public void registerAuxWriter (Class aclass, NestableWriter writer)
{
AttributesImpl attrs = new AttributesImpl();
addSceneAttributes(scene, attrs);
writer.startElement("", sceneElementName(), "", attrs);
writeSceneData(scene, writer);
writer.endElement(sceneElementName());
_auxers.put(aclass, writer);
}
/**
* Returns the name of the top-level element that we'll use when we
* write out the scene (defaults to <code>scene</code>).
* Writes the supplied scene out to the specified file.
*/
protected String sceneElementName ()
{
return "scene";
}
/**
* Adds attributes to the top-level element before it gets written.
*/
protected void addSceneAttributes (
EditableScene scene, AttributesImpl attrs)
{
attrs.addAttribute("", "name", "", "", scene.getName());
attrs.addAttribute("", "version", "", "",
Integer.toString(scene.getVersion()));
}
/**
* Writes just the scene data which is handy for derived classes which
* may wish to add their own scene data to the scene output.
*/
protected void writeSceneData (EditableScene scene, DataWriter writer)
throws SAXException
{
Iterator iter = scene.getNeighborNames().iterator();
while (iter.hasNext()) {
writer.dataElement("neighbor", (String)iter.next());
}
}
/**
* Writes the supplied scene out to the specified file using the
* supplied scene writer.
*/
public static void writeScene (File out, SceneWriter writer,
EditableScene scene)
public void writeScene (File out, SceneModel model)
throws IOException, SAXException
{
FileWriter fout = new FileWriter(out);
DataWriter dout = new DataWriter(fout);
dout.setIndentStep(2);
dout.startDocument();
writer.writeScene(scene, dout);
writeSceneModel(model, dout);
dout.endDocument();
fout.close();
}
/**
* Writes the data for the supplied {@link SceneModel} to the XML data
* writer supplied. The writer should already be configured with the
* appropriate indentation level so that this writer can simply output
* its elements and allow the calling code to determine where in the
* greater scene description file the scene data should live.
*/
public void writeSceneModel (SceneModel model, DataWriter writer)
throws SAXException
{
AttributesImpl attrs = new AttributesImpl();
addSceneAttributes(model, attrs);
writer.startElement("", OUTER_ELEMENT, "", attrs);
writeSceneData(model, writer);
writer.endElement(OUTER_ELEMENT);
}
/**
* Adds attributes to the top-level element before it gets written.
*/
protected void addSceneAttributes (
SceneModel model, AttributesImpl attrs)
{
attrs.addAttribute("", "name", "", "", model.name);
attrs.addAttribute("", "version", "", "",
Integer.toString(model.version));
}
/**
* Writes just the scene data which is handy for derived classes which
* may wish to add their own scene data to the scene output.
*/
protected void writeSceneData (SceneModel model, DataWriter writer)
throws SAXException
{
// write out our auxiliary scene models
for (int ii = 0; ii < model.auxModels.length; ii++) {
AuxModel amodel = model.auxModels[ii];
NestableWriter awriter = (NestableWriter)
_auxers.get(amodel.getClass());
if (awriter != null) {
awriter.write(amodel, writer);
} else {
Log.warning("No writer registered for auxiliary scene model " +
"[mclass=" + amodel.getClass() + "].");
}
}
}
protected HashMap _auxers = new HashMap();
}
@@ -0,0 +1,21 @@
//
// $Id: SceneFactory.java,v 1.1 2003/02/12 07:23:32 mdb Exp $
package com.threerings.whirled.util;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.data.Scene;
import com.threerings.whirled.data.SceneModel;
/**
* This is used by the Whirled services to obtain a {@link Scene}
* implementation given a scene model and associated data.
*/
public interface SceneFactory
{
/**
* Creates a {@link Scene} implementation given the supplied scene
* model and place config.
*/
public Scene createScene (SceneModel model, PlaceConfig config);
}
@@ -0,0 +1,89 @@
//
// $Id: UpdateList.java,v 1.1 2003/02/12 07:23:32 mdb Exp $
package com.threerings.whirled.util;
import java.util.ArrayList;
import com.threerings.whirled.Log;
import com.threerings.whirled.data.SceneUpdate;
/**
* A list specialized for storing {@link SceneUpdate} objects.
*/
public class UpdateList
{
public UpdateList ()
{
_updates = new ArrayList();
}
/**
* Adds an update to this list. The update must follow appropriately
* the chain of updates established by the updates already in the list
* (meaning it must operate on one version higher than the most recent
* update already in the list).
*/
public void addUpdate (SceneUpdate update)
{
if (_minVersion == -1) {
// this is our first update, so we initialize our min version
_minVersion = update.getSceneVersion();
} else {
int gotVersion = update.getSceneVersion();
int expVersion = _minVersion + _updates.size();
if (gotVersion > expVersion) {
Log.warning("Update continuity broken, flushing list " +
"[got=" + update + ", expect=" + expVersion +
", ucount=" + _updates.size() + "].");
// flush out our old updates and start anew from here
_updates.clear();
_minVersion = expVersion;
} else if (gotVersion < expVersion) {
// we somehow got an update that's older than updates we
// already have? wick wick wack
String errmsg = "Invalid update version " +
"[want=" + expVersion + ", got=" + update + "]";
throw new IllegalArgumentException(errmsg);
}
}
_updates.add(update);
}
/**
* Returns all of the updates that should be applied to a scene with
* the specified version to bring it up to date. <code>null</code> is
* returned if the scene's version is older than the oldest update in
* our list, in which case it cannot be brought up to date by applying
* updates from this list.
*/
public SceneUpdate[] getUpdates (int fromVersion)
{
if (fromVersion < _minVersion) {
return null;
}
int offset = fromVersion - _minVersion;
int ucount = _updates.size() - offset;
SceneUpdate[] updates = new SceneUpdate[ucount];
for (int ii = 0; ii < ucount; ii++) {
updates[ii] = (SceneUpdate)_updates.get(ii+offset);
}
return updates;
}
/**
* Returns true if the supplied actual scene version is in accordance
* with the updates contained in this list.
*/
public boolean validate (int sceneVersion)
{
return ((_minVersion == -1) || // we have no updates
(_minVersion + _updates.size() == sceneVersion));
}
protected ArrayList _updates;
protected int _minVersion = -1;
}
@@ -1,5 +1,5 @@
//
// $Id: ZoneDirector.java,v 1.13 2003/01/18 22:45:16 mdb Exp $
// $Id: ZoneDirector.java,v 1.14 2003/02/12 07:23:32 mdb Exp $
package com.threerings.whirled.zone.client;
@@ -14,6 +14,7 @@ import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.client.SceneDirector;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.util.WhirledContext;
import com.threerings.whirled.zone.Log;
@@ -158,19 +159,38 @@ public class ZoneDirector extends BasicDirector
notifyObservers(summary);
}
/**
* Called in response to a successful {@link ZoneService#moveTo}
* request when our cached scene was out of date and the server
* determined that we needed some updates.
*/
public void moveSucceededWithUpdates (
int placeId, PlaceConfig config, ZoneSummary summary,
SceneUpdate[] updates)
{
// keep track of the summary
_summary = summary;
// pass the rest off to the standard scene transition code
_scdir.moveSucceededWithUpdates(placeId, config, updates);
// and let the zone observers know what's up
notifyObservers(summary);
}
/**
* Called in response to a successful {@link ZoneService#moveTo}
* request when our cached scene was out of date and the server
* determined that we needed an updated copy.
*/
public void moveSucceededPlusUpdate (
public void moveSucceededWithScene (
int placeId, PlaceConfig config, ZoneSummary summary, SceneModel model)
{
// keep track of the summary
_summary = summary;
// pass the rest off to the standard scene transition code
_scdir.moveSucceededPlusUpdate(placeId, config, model);
_scdir.moveSucceededWithScene(placeId, config, model);
// and let the zone observers know what's up
notifyObservers(summary);
@@ -1,5 +1,5 @@
//
// $Id: ZoneService.java,v 1.6 2002/08/14 19:07:58 mdb Exp $
// $Id: ZoneService.java,v 1.7 2003/02/12 07:23:32 mdb Exp $
package com.threerings.whirled.zone.client;
@@ -8,6 +8,7 @@ import com.threerings.presents.client.InvocationService;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.zone.data.ZoneSummary;
@@ -17,12 +18,17 @@ import com.threerings.whirled.zone.data.ZoneSummary;
*/
public interface ZoneService extends InvocationService
{
/** Used to deliver responses to {@link #moveTo} requests. */
public static interface ZoneMoveListener extends InvocationListener
{
public void moveSucceeded (
int placeId, PlaceConfig config, ZoneSummary summary);
public void moveSucceededPlusUpdate (
public void moveSucceededWithUpdates (
int placeId, PlaceConfig config, ZoneSummary summary,
SceneUpdate[] updates);
public void moveSucceededWithScene (
int placeId, PlaceConfig config, ZoneSummary summary,
SceneModel model);
}
@@ -33,11 +39,11 @@ public interface ZoneService extends InvocationService
*
* @param zoneId the zone id to which we want to move.
* @param sceneId the scene id to which we want to move.
* @param sceneVers the version number of the scene object that we
* have in our local repository.
* @param version the version number of the scene object that we have
* in our local repository.
* @param listener the object that will receive the callback when the
* request succeeds or fails.
*/
public void moveTo (Client client, int zoneId, int sceneId,
int sceneVers, ZoneMoveListener listener);
int version, ZoneMoveListener listener);
}
@@ -1,5 +1,5 @@
//
// $Id: ZoneMarshaller.java,v 1.2 2002/08/20 19:38:16 mdb Exp $
// $Id: ZoneMarshaller.java,v 1.3 2003/02/12 07:23:32 mdb Exp $
package com.threerings.whirled.zone.data;
@@ -8,6 +8,7 @@ import com.threerings.presents.client.Client;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.dobj.InvocationResponseEvent;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.zone.client.ZoneService;
import com.threerings.whirled.zone.client.ZoneService.ZoneMoveListener;
import com.threerings.whirled.zone.data.ZoneSummary;
@@ -18,10 +19,6 @@ import com.threerings.whirled.zone.data.ZoneSummary;
* on the server. Also provides an implementation of the response listener
* interfaces that marshall the response arguments and deliver them back
* to the requesting client.
*
* <p> Generated from <code>
* $Id: ZoneMarshaller.java,v 1.2 2002/08/20 19:38:16 mdb Exp $
* </code>
*/
public class ZoneMarshaller extends InvocationMarshaller
implements ZoneService
@@ -42,15 +39,27 @@ public class ZoneMarshaller extends InvocationMarshaller
new Object[] { new Integer(arg1), arg2, arg3 }));
}
/** The method id used to dispatch {@link #moveSucceededPlusUpdate}
/** The method id used to dispatch {@link #moveSucceededWithUpdates}
* responses. */
public static final int MOVE_SUCCEEDED_PLUS_UPDATE = 2;
public static final int MOVE_SUCCEEDED_WITH_UPDATES = 2;
// documentation inherited from interface
public void moveSucceededPlusUpdate (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneModel arg4)
public void moveSucceededWithUpdates (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneUpdate[] arg4)
{
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, MOVE_SUCCEEDED_PLUS_UPDATE,
callerOid, requestId, MOVE_SUCCEEDED_WITH_UPDATES,
new Object[] { new Integer(arg1), arg2, arg3, arg4 }));
}
/** The method id used to dispatch {@link #moveSucceededWithScene}
* responses. */
public static final int MOVE_SUCCEEDED_WITH_SCENE = 3;
// documentation inherited from interface
public void moveSucceededWithScene (int arg1, PlaceConfig arg2, ZoneSummary arg3, SceneModel arg4)
{
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, MOVE_SUCCEEDED_WITH_SCENE,
new Object[] { new Integer(arg1), arg2, arg3, arg4 }));
}
@@ -63,8 +72,13 @@ public class ZoneMarshaller extends InvocationMarshaller
((Integer)args[0]).intValue(), (PlaceConfig)args[1], (ZoneSummary)args[2]);
return;
case MOVE_SUCCEEDED_PLUS_UPDATE:
((ZoneMoveListener)listener).moveSucceededPlusUpdate(
case MOVE_SUCCEEDED_WITH_UPDATES:
((ZoneMoveListener)listener).moveSucceededWithUpdates(
((Integer)args[0]).intValue(), (PlaceConfig)args[1], (ZoneSummary)args[2], (SceneUpdate[])args[3]);
return;
case MOVE_SUCCEEDED_WITH_SCENE:
((ZoneMoveListener)listener).moveSucceededWithScene(
((Integer)args[0]).intValue(), (PlaceConfig)args[1], (ZoneSummary)args[2], (SceneModel)args[3]);
return;
@@ -87,5 +101,5 @@ public class ZoneMarshaller extends InvocationMarshaller
});
}
// Class file generated on 12:33:05 08/20/02.
// Generated on 15:03:19 02/08/03.
}
@@ -1,5 +1,5 @@
//
// $Id: ZoneDispatcher.java,v 1.2 2002/08/20 19:38:16 mdb Exp $
// $Id: ZoneDispatcher.java,v 1.3 2003/02/12 07:23:32 mdb Exp $
package com.threerings.whirled.zone.server;
@@ -10,6 +10,7 @@ import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.server.InvocationDispatcher;
import com.threerings.presents.server.InvocationException;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.zone.client.ZoneService;
import com.threerings.whirled.zone.client.ZoneService.ZoneMoveListener;
import com.threerings.whirled.zone.data.ZoneMarshaller;
@@ -17,10 +18,6 @@ import com.threerings.whirled.zone.data.ZoneSummary;
/**
* Dispatches requests to the {@link ZoneProvider}.
*
* <p> Generated from <code>
* $Id: ZoneDispatcher.java,v 1.2 2002/08/20 19:38:16 mdb Exp $
* </code>
*/
public class ZoneDispatcher extends InvocationDispatcher
{
@@ -56,4 +53,6 @@ public class ZoneDispatcher extends InvocationDispatcher
super.dispatchRequest(source, methodId, args);
}
}
// Generated on 15:03:19 02/08/03.
}
@@ -1,5 +1,5 @@
//
// $Id: ZoneProvider.java,v 1.13 2002/12/03 06:58:57 mdb Exp $
// $Id: ZoneProvider.java,v 1.14 2003/02/12 07:23:32 mdb Exp $
package com.threerings.whirled.zone.server;
@@ -161,10 +161,10 @@ public class ZoneProvider
}
// check to see if they need a newer version of the scene data
SceneModel model = scmgr.getSceneModel();
SceneModel model = scmgr.getScene().getSceneModel();
if (sceneVersion < model.version) {
// then send the moveTo response
listener.moveSucceededPlusUpdate(ploid, config, summary, model);
listener.moveSucceededWithScene(ploid, config, summary, model);
} else {
// then send the moveTo response