diff --git a/docs/whirled/design.txt b/docs/whirled/design.txt index f540a9459..8a60cc970 100644 --- a/docs/whirled/design.txt +++ b/docs/whirled/design.txt @@ -30,10 +30,6 @@ scene database, from which they can then continue to mirror updates as needed. * Notes -Scene provider needs to do the right thing when a client requests an out -of date scene. Presently it doesn't handle sending the client the updated -scene data. - Scene manager registers a timer when it becomes empty and flushes itself from memory after timeout period. diff --git a/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java b/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java index d29660b04..c6a218c5d 100644 --- a/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java +++ b/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java @@ -1,5 +1,5 @@ // -// $Id: DisplayMisoSceneImpl.java,v 1.42 2001/10/25 16:36:42 shaper Exp $ +// $Id: DisplayMisoSceneImpl.java,v 1.43 2001/11/12 20:56:55 mdb Exp $ package com.threerings.miso.scene; @@ -11,7 +11,6 @@ import java.util.List; import com.samskivert.util.StringUtil; import com.threerings.media.tile.*; -import com.threerings.whirled.data.Scene; import com.threerings.miso.Log; import com.threerings.miso.scene.util.ClusterUtil; diff --git a/src/java/com/threerings/miso/tools/xml/XMLSceneGroupParser.java b/src/java/com/threerings/miso/tools/xml/XMLSceneGroupParser.java index 900a15075..0c7ef995c 100644 --- a/src/java/com/threerings/miso/tools/xml/XMLSceneGroupParser.java +++ b/src/java/com/threerings/miso/tools/xml/XMLSceneGroupParser.java @@ -1,5 +1,5 @@ // -// $Id: XMLSceneGroupParser.java,v 1.7 2001/10/17 22:21:22 shaper Exp $ +// $Id: XMLSceneGroupParser.java,v 1.8 2001/11/12 20:56:55 mdb Exp $ package com.threerings.miso.scene.xml; @@ -15,8 +15,6 @@ import com.threerings.miso.Log; import com.threerings.miso.scene.*; import com.threerings.miso.scene.util.MisoSceneUtil; -import com.threerings.whirled.data.Scene; - /** * Parses an XML scene group description file, loads the referenced * scenes into the runtime scene repository, and creates bindings diff --git a/src/java/com/threerings/whirled/client/DisplayScene.java b/src/java/com/threerings/whirled/client/DisplayScene.java new file mode 100644 index 000000000..dd2cdb890 --- /dev/null +++ b/src/java/com/threerings/whirled/client/DisplayScene.java @@ -0,0 +1,45 @@ +// +// $Id: DisplayScene.java,v 1.1 2001/11/12 20:56:55 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. + * + *

Additionally, at this basic level, the DisplayScene + * 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 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 (); +} diff --git a/src/java/com/threerings/whirled/client/DisplaySceneFactory.java b/src/java/com/threerings/whirled/client/DisplaySceneFactory.java new file mode 100644 index 000000000..9ee977c3f --- /dev/null +++ b/src/java/com/threerings/whirled/client/DisplaySceneFactory.java @@ -0,0 +1,24 @@ +// +// $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 moveTo request. + */ + public DisplayScene createScene (SceneModel model, PlaceConfig config); +} diff --git a/src/java/com/threerings/whirled/client/DisplaySceneImpl.java b/src/java/com/threerings/whirled/client/DisplaySceneImpl.java new file mode 100644 index 000000000..448a10759 --- /dev/null +++ b/src/java/com/threerings/whirled/client/DisplaySceneImpl.java @@ -0,0 +1,54 @@ +// +// $Id: DisplaySceneImpl.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; + +/** + * 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 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; +} diff --git a/src/java/com/threerings/whirled/client/SceneCodes.java b/src/java/com/threerings/whirled/client/SceneCodes.java index 477b9f376..85a6153fa 100644 --- a/src/java/com/threerings/whirled/client/SceneCodes.java +++ b/src/java/com/threerings/whirled/client/SceneCodes.java @@ -1,5 +1,5 @@ // -// $Id: SceneCodes.java,v 1.2 2001/10/11 04:07:54 mdb Exp $ +// $Id: SceneCodes.java,v 1.3 2001/11/12 20:56:55 mdb Exp $ package com.threerings.whirled.client; @@ -12,4 +12,11 @@ public interface SceneCodes extends LocationCodes { /** The module name for the scene services. */ public static final String MODULE_NAME = "whirled!scene"; + + /** The response identifier for a successful moveTo request that + * includes an updated scene model. This is mapped by the invocation + * services to a call to {@link + * SceneDirector#handleMoveSucceededPlusUpdate}. */ + public static final String MOVE_SUCCEEDED_PLUS_UPDATE_RESPONSE = + "MoveSucceededPlusUpdate"; } diff --git a/src/java/com/threerings/whirled/client/SceneController.java b/src/java/com/threerings/whirled/client/SceneController.java new file mode 100644 index 000000000..9756a3fc1 --- /dev/null +++ b/src/java/com/threerings/whirled/client/SceneController.java @@ -0,0 +1,18 @@ +// +// $Id: SceneController.java,v 1.1 2001/11/12 20:56:55 mdb Exp $ + +package com.threerings.whirled.client; + +import com.threerings.crowd.client.PlaceController; + +/** + * The base scene controller class. It is expected that users of the + * Whirled services will extend this controller class when creating + * specialized controllers for their scenes. Presently there are no basic + * scene services provided by this controller, but its existence affords + * the addition of such services should they become necessary in the + * future. + */ +public abstract class SceneController extends PlaceController +{ +} diff --git a/src/java/com/threerings/whirled/client/SceneDirector.java b/src/java/com/threerings/whirled/client/SceneDirector.java index 3d491b3e2..15e52d35c 100644 --- a/src/java/com/threerings/whirled/client/SceneDirector.java +++ b/src/java/com/threerings/whirled/client/SceneDirector.java @@ -1,5 +1,5 @@ // -// $Id: SceneDirector.java,v 1.6 2001/10/11 04:07:54 mdb Exp $ +// $Id: SceneDirector.java,v 1.7 2001/11/12 20:56:55 mdb Exp $ package com.threerings.whirled.client; @@ -16,43 +16,50 @@ import com.threerings.crowd.data.PlaceObject; import com.threerings.whirled.Log; import com.threerings.whirled.client.persist.SceneRepository; +import com.threerings.whirled.data.SceneModel; import com.threerings.whirled.util.NoSuchSceneException; -import com.threerings.whirled.data.Scene; import com.threerings.whirled.util.WhirledContext; /** * The scene director is the client's interface to all things scene * related. It interfaces with the scene repository to ensure that scene * objects are available when the client enters a particular scene. It - * handles moving from scene to scene (it extends and replaces the - * location director in order to do this). + * handles moving from scene to scene (it extends and replaces the {@link + * LocationDirector} in order to do this). * *

Note that when the scene director is in use instead of the location * director, scene ids instead of place oids will be supplied to {@link - * com.threerings.crowd.client.LocationObserver#locationMayChange} - * and {@link - * com.threerings.crowd.client.LocationObserver#locationChangeFailed}. + * LocationObserver#locationMayChange} and {@link + * LocationObserver#locationChangeFailed}. */ public class SceneDirector extends LocationDirector implements SceneCodes { /** * Creates a new scene director with the specified context. + * + * @param ctx the active client context. + * @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. */ - public SceneDirector (WhirledContext ctx, SceneRepository screp) + public SceneDirector (WhirledContext ctx, SceneRepository screp, + DisplaySceneFactory dsfact) { super(ctx); // we'll need these for later _ctx = ctx; _screp = screp; + _dsfact = dsfact; } /** - * Returns the scene object associated with the scene we currently - * occupy or null if we currently occupy no scene. + * Returns the dispaly scene object associated with the scene we + * currently occupy or null if we currently occupy no scene. */ - public Scene getScene () + public DisplayScene getScene () { return _scene; } @@ -86,10 +93,10 @@ public class SceneDirector // load up the pending scene so that we can communicate it's most // recent version to the server int sceneVers = 0; - _pendingScene = loadScene(sceneId); + _pendingModel = loadSceneModel(sceneId); // if we were unable to load it, assume a previous version of zero - if (_pendingScene != null) { - sceneVers = _pendingScene.getVersion(); + if (_pendingModel != null) { + sceneVers = _pendingModel.version; } // make a note of our pending scene id @@ -113,22 +120,54 @@ public class SceneDirector // parallelize and go ahead and load up the new scene now rather // than wait until subscription to our place object succeeds - // release the old scene - releaseScene(_scene); - - // update our scene id tracking fields + // keep track of our previous scene info _previousSceneId = _sceneId; + + // clear out the old info + clearScene(); + + // make the pending scene the active scene _sceneId = _pendingSceneId; _pendingSceneId = -1; - // and load the new scene - _scene = loadScene(_sceneId); + // load the new scene model + _model = loadSceneModel(_sceneId); // complain if we didn't find a scene - if (_scene == null) { + if (_model == null) { Log.warning("Aiya! Unable to load scene [sid=" + _sceneId + ", plid=" + placeId + "]."); } + + // and finally create a display scene instance with the model and + // the place config + _scene = _dsfact.createScene(_model, config); + } + + /** + * Called in response to a successful moveTo request when + * our cached scene was out of date and the server determined that we + * needed an updated copy. + */ + public void handleMoveSucceededPlusUpdate ( + int invid, int placeId, PlaceConfig config, SceneModel model) + { + // update the model in the repository + try { + _screp.updateSceneModel(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.logStackTrace(ioe); + } + + // update our scene cache + _scache.put(model.sceneId, model); + + // and pass through to the normal move succeeded handler + handleMoveSucceeded(invid, placeId, config); } /** @@ -144,13 +183,17 @@ public class SceneDirector notifyFailure(sceneId, reason); } + /** + * Called when something breaks down in the process of performing a + * moveTo request. + */ protected void recoverFailedMove (int placeId) { - // clear out our now bogus scene tracking info + // we'll need this momentarily int sceneId = _sceneId; - _sceneId = -1; - releaseScene(_scene); - _scene = null; + + // clear out our now bogus scene tracking info + clearScene(); // if we were previously somewhere (and that somewhere isn't where // we just tried to go), try going back to that happy place @@ -159,20 +202,37 @@ public class SceneDirector } } + /** + * Clears out our current scene information and releases the scene + * model for the loaded scene back to the cache. + */ + protected void clearScene () + { + // clear out our scene id info + _sceneId = -1; + + // release the old scene model + releaseSceneModel(_model); + + // clear out our references + _model = null; + _scene = null; + } + /** * Loads a scene from the repository. If the scene is cached, it will * be returned from the cache instead. */ - protected Scene loadScene (int sceneId) + protected SceneModel loadSceneModel (int sceneId) { - // first look in the cache - Scene scene = (Scene)_scache.get(sceneId); + // first look in the model cache + SceneModel model = (SceneModel)_scache.get(sceneId); // load from the repository if it's not cached - if (scene == null) { + if (model == null) { try { - scene = _screp.loadScene(sceneId); - _scache.put(sceneId, scene); + model = _screp.loadSceneModel(sceneId); + _scache.put(sceneId, model); } catch (NoSuchSceneException nsse) { // nothing special here, just fall through and return null @@ -184,34 +244,46 @@ public class SceneDirector } } - return scene; + return model; } /** - * Unloads a scene that was previously loaded via {@link #loadScene}. - * The scene will probably continue to live in the cache for a while - * in case we quickly return to it. + * Unloads a scene model that was previously loaded via {@link + * #loadSceneModel}. The model will probably continue to live in the + * cache for a while in case we quickly return to it. */ - protected void releaseScene (Scene scene) + protected void releaseSceneModel (SceneModel model) { // we're cool if we're called with null - if (scene == null) { + if (model == null) { return; } } + /** Access to general client services. */ protected WhirledContext _ctx; + + /** 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; + + /** A cache of scene model information. */ protected HashIntMap _scache = new HashIntMap(); - /** The scene object of the scene we currently occupy. */ - protected Scene _scene; + /** The display scene object for the scene we currently occupy. */ + protected DisplayScene _scene; + + /** The scene model for the scene we currently occupy. */ + protected SceneModel _model; /** The id of the scene we currently occupy. */ protected int _sceneId = -1; - /** Our most recent copy of the scene we're about to enter. */ - protected Scene _pendingScene; + /** Our most recent copy of the scene model for the scene we're about + * to enter. */ + protected SceneModel _pendingModel; /** * The id of the scene for which we have an outstanding moveTo diff --git a/src/java/com/threerings/whirled/client/persist/SceneRepository.java b/src/java/com/threerings/whirled/client/persist/SceneRepository.java index 5a27f0773..708879ab0 100644 --- a/src/java/com/threerings/whirled/client/persist/SceneRepository.java +++ b/src/java/com/threerings/whirled/client/persist/SceneRepository.java @@ -1,42 +1,43 @@ // -// $Id: SceneRepository.java,v 1.2 2001/08/14 06:51:07 mdb Exp $ +// $Id: SceneRepository.java,v 1.3 2001/11/12 20:56:55 mdb Exp $ package com.threerings.whirled.client.persist; import java.io.IOException; -import com.threerings.whirled.data.Scene; +import com.threerings.whirled.data.SceneModel; import com.threerings.whirled.util.NoSuchSceneException; /** * The scene repository provides access to a persistent repository of - * scene information. The scenes in the repository can be updated with - * individual scenes fetched from the server as well as with new scene + * 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. * - * @see com.threerings.whirled.data.Scene + * @see SceneModel */ public interface SceneRepository { /** - * Fetches the scene with the specified scene id. + * Fetches the mode for the scene with the specified scene id. * * @exception IOException thrown if an error occurs attempting to load - * a scene. + * the scene data. * @exception NoSuchSceneException thrown if no scene exists with the * specified scene id. */ - public Scene loadScene (int sceneId) + public SceneModel loadSceneModel (int sceneId) throws IOException, NoSuchSceneException; /** - * Updates the specified scene in the repository with the information - * provided in the scene object. + * 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. * * @exception IOException thrown if an error occurs attempting to - * update the scene. + * update the scene data. */ - public void updateScene (Scene scene) + public void updateSceneModel (SceneModel model) throws IOException; } diff --git a/src/java/com/threerings/whirled/data/DefaultSceneConfig.java b/src/java/com/threerings/whirled/data/DefaultSceneConfig.java new file mode 100644 index 000000000..1f2a0f49f --- /dev/null +++ b/src/java/com/threerings/whirled/data/DefaultSceneConfig.java @@ -0,0 +1,32 @@ +// +// $Id: DefaultSceneConfig.java,v 1.1 2001/11/12 20:56:55 mdb Exp $ + +package com.threerings.whirled.data; + +import com.threerings.crowd.data.PlaceConfig; +import com.threerings.whirled.client.SceneController; + +/** + * The default scene config simply causes the default scene manager and + * controller to be created. A user of the Whirled services would most + * likely extend the default scene config. + * + *

Note that this place config won't even work on the client side + * because it instantiates a {@link SceneController} which is an abstract + * class. It is used only for testing the server side and as a placeholder + * in case standard scene configuration information is one day needed. + */ +public class DefaultSceneConfig extends PlaceConfig +{ + // documentation inherited + public Class getControllerClass () + { + return SceneController.class; + } + + // documentation inherited + public String getManagerClassName () + { + return "com.threerings.whirled.server.SceneManager"; + } +} diff --git a/src/java/com/threerings/whirled/data/DummyScene.java b/src/java/com/threerings/whirled/data/DummyScene.java deleted file mode 100644 index 23f272726..000000000 --- a/src/java/com/threerings/whirled/data/DummyScene.java +++ /dev/null @@ -1,41 +0,0 @@ -// -// $Id: DummyScene.java,v 1.7 2001/11/08 02:59:17 mdb Exp $ - -package com.threerings.whirled.data; - -import com.threerings.crowd.data.PlaceConfig; - -public class DummyScene implements Scene -{ - public DummyScene (int sceneId) - { - _sceneId = sceneId; - } - - public int getId () - { - return _sceneId; - } - - public int getVersion () - { - return 1; - } - - public String getName () - { - return "scene"; - } - - public int[] getNeighborIds () - { - return null; - } - - public PlaceConfig getPlaceConfig () - { - return null; - } - - protected int _sceneId; -} diff --git a/src/java/com/threerings/whirled/data/EditableScene.java b/src/java/com/threerings/whirled/data/EditableScene.java deleted file mode 100644 index 685ad2a7e..000000000 --- a/src/java/com/threerings/whirled/data/EditableScene.java +++ /dev/null @@ -1,22 +0,0 @@ -// -// $Id: EditableScene.java,v 1.3 2001/10/05 23:59:36 mdb Exp $ - -package com.threerings.whirled.data; - -/** - * The editable scene interface. This separate interface allows the - * ability to modify the scenes to be restricted only to code that needs - * such an ability. - */ -public interface EditableScene extends Scene -{ - /** - * Updates the scene's unique identifier. - */ - public void setId (int sceneId); - - /** - * Updates the scene's version. - */ - public void setVersion (int version); -} diff --git a/src/java/com/threerings/whirled/data/Scene.java b/src/java/com/threerings/whirled/data/Scene.java deleted file mode 100644 index 187197fec..000000000 --- a/src/java/com/threerings/whirled/data/Scene.java +++ /dev/null @@ -1,45 +0,0 @@ -// -// $Id: Scene.java,v 1.6 2001/10/11 04:07:54 mdb Exp $ - -package com.threerings.whirled.data; - -import com.threerings.crowd.data.PlaceConfig; - -/** - * The base scene interface. This encapsulates the minimum information - * needed about a scene in the Whirled system. - */ -public interface Scene -{ - /** - * Returns the scene's unique identifier. - */ - public int getId (); - - /** - * Returns the scene's version. The version should be updated every - * time the scene is modified and stored back to the repository. This - * allows a client to determine whether or not they need an updated - * version of the scene for their local cache. - */ - public int getVersion (); - - /** - * Returns the scene ids of all scenes that neighbor this scene. A - * neighboring scene is one to which the user can traverse from this - * scene and vice versa. - */ - public int[] getNeighborIds (); - - /** - * A scene is associated with a place on the server. Because the - * scenes are loaded on demand, the scene implementation must be able - * to provide a place config instance for each scene. This will allow - * the server to figure out what manager class to instantiate to - * manage the scene and all the client to figure out what controller - * class to instantiate to controll the scene. Additionally, it may - * contain runtime configuration information needed by the application - * using the Whirled services. - */ - public PlaceConfig getPlaceConfig (); -} diff --git a/src/java/com/threerings/whirled/data/SceneModel.java b/src/java/com/threerings/whirled/data/SceneModel.java new file mode 100644 index 000000000..248225a03 --- /dev/null +++ b/src/java/com/threerings/whirled/data/SceneModel.java @@ -0,0 +1,63 @@ +// +// $Id: SceneModel.java,v 1.1 2001/11/12 20:56:55 mdb Exp $ + +package com.threerings.whirled.data; + +import java.io.IOException; +import java.io.DataInputStream; +import java.io.DataOutputStream; + +import com.threerings.presents.io.Streamable; + +/** + * 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}. + * + *

The scene model is what is loaded from the scene repositories and + * what is transmitted over the wire when communicating scenes from the + * server to the client. + */ +public class SceneModel implements Streamable +{ + /** This scene's unique identifier. */ + public int sceneId; + + /** The version number of this scene. Versions are incremented + * whenever modifications are made to a scene so that clients can + * determine whether or not they have the latest version of a + * 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; + + // documentation inherited + public void writeTo (DataOutputStream out) + throws IOException + { + out.writeInt(sceneId); + out.writeInt(version); + int nlength = neighborIds.length; + out.writeInt(nlength); + for (int i = 0; i < nlength; i++) { + out.writeInt(neighborIds[i]); + } + } + + // documentation inherited + public void readFrom (DataInputStream in) + throws IOException + { + sceneId = in.readInt(); + version = in.readInt(); + int nlength = in.readInt(); + neighborIds = new int[nlength]; + for (int i = 0; i < nlength; i++) { + neighborIds[i] = in.readInt(); + } + } +} diff --git a/src/java/com/threerings/whirled/server/DefaultRuntimeSceneFactory.java b/src/java/com/threerings/whirled/server/DefaultRuntimeSceneFactory.java new file mode 100644 index 000000000..f13f733ba --- /dev/null +++ b/src/java/com/threerings/whirled/server/DefaultRuntimeSceneFactory.java @@ -0,0 +1,21 @@ +// +// $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()); + } +} diff --git a/src/java/com/threerings/whirled/server/RuntimeScene.java b/src/java/com/threerings/whirled/server/RuntimeScene.java new file mode 100644 index 000000000..7ad010ec1 --- /dev/null +++ b/src/java/com/threerings/whirled/server/RuntimeScene.java @@ -0,0 +1,45 @@ +// +// $Id: RuntimeScene.java,v 1.1 2001/11/12 20:56:56 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. + * + *

Additionally, at this basic level, the RuntimeScene + * 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 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 (); +} diff --git a/src/java/com/threerings/whirled/server/RuntimeSceneFactory.java b/src/java/com/threerings/whirled/server/RuntimeSceneFactory.java new file mode 100644 index 000000000..f32ff592d --- /dev/null +++ b/src/java/com/threerings/whirled/server/RuntimeSceneFactory.java @@ -0,0 +1,29 @@ +// +// $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); +} diff --git a/src/java/com/threerings/whirled/server/RuntimeSceneImpl.java b/src/java/com/threerings/whirled/server/RuntimeSceneImpl.java new file mode 100644 index 000000000..8dde2db34 --- /dev/null +++ b/src/java/com/threerings/whirled/server/RuntimeSceneImpl.java @@ -0,0 +1,54 @@ +// +// $Id: RuntimeSceneImpl.java,v 1.1 2001/11/12 20:56:56 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 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; +} diff --git a/src/java/com/threerings/whirled/server/SceneManager.java b/src/java/com/threerings/whirled/server/SceneManager.java index 87514e4d4..38e07e2e1 100644 --- a/src/java/com/threerings/whirled/server/SceneManager.java +++ b/src/java/com/threerings/whirled/server/SceneManager.java @@ -1,32 +1,50 @@ // -// $Id: SceneManager.java,v 1.7 2001/10/24 00:58:12 mdb Exp $ +// $Id: SceneManager.java,v 1.8 2001/11/12 20:56:56 mdb Exp $ package com.threerings.whirled.server; -import com.threerings.crowd.chat.ChatMessageHandler; -import com.threerings.crowd.chat.ChatService; import com.threerings.crowd.server.PlaceManager; +import com.threerings.whirled.data.SceneModel; -import com.threerings.whirled.data.Scene; - +/** + * The scene manager extends the place manager and takes care of basic + * scene services. Presently that is little more than registering the + * scene manager with the scene registry so that the manager can be looked + * up by scene id in addition to place object id. + */ public class SceneManager extends PlaceManager { /** - * Returns the scene object (not the scene distributed object) - * associated with this scene. + * Returns the runtime scene object (not the scene distributed object) + * being managed by this scene manager. */ - public Scene getScene () + public RuntimeScene 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 postInit (Scene scene, SceneRegistry screg) + protected void postInit ( + RuntimeScene scene, SceneModel model, SceneRegistry screg) { _scene = scene; + _model = model; _screg = screg; } @@ -41,11 +59,6 @@ public class SceneManager extends PlaceManager // let the scene registry know that we're up and running _screg.sceneManagerDidStart(this); - - // register a chat message handler because we want to support - // chatting - MessageHandler handler = new ChatMessageHandler(); - registerMessageHandler(ChatService.SPEAK_REQUEST, handler); } /** @@ -66,6 +79,17 @@ public class SceneManager extends PlaceManager buf.append(", scene=").append(_scene); } - protected Scene _scene; + /** A reference to our runtime scene implementation which provides a + * meaningful interpretation of the data in the scene model. */ + protected RuntimeScene _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 reference to the scene registry so that we can call back to it + * when we're fully initialized. */ protected SceneRegistry _screg; } diff --git a/src/java/com/threerings/whirled/server/SceneProvider.java b/src/java/com/threerings/whirled/server/SceneProvider.java index d08c17eeb..f47c97b28 100644 --- a/src/java/com/threerings/whirled/server/SceneProvider.java +++ b/src/java/com/threerings/whirled/server/SceneProvider.java @@ -1,16 +1,19 @@ // -// $Id: SceneProvider.java,v 1.4 2001/10/11 04:07:54 mdb Exp $ +// $Id: SceneProvider.java,v 1.5 2001/11/12 20:56:56 mdb Exp $ package com.threerings.whirled.server; import com.threerings.presents.server.InvocationProvider; import com.threerings.presents.server.ServiceFailedException; -import com.threerings.crowd.data.*; +import com.threerings.crowd.data.BodyObject; +import com.threerings.crowd.data.PlaceConfig; +import com.threerings.crowd.data.PlaceObject; import com.threerings.crowd.server.LocationProvider; import com.threerings.whirled.Log; import com.threerings.whirled.client.SceneCodes; +import com.threerings.whirled.data.SceneModel; /** * The scene provider handles the server side of the scene related @@ -72,10 +75,17 @@ public class SceneProvider PlaceConfig config = LocationProvider.moveTo(source, ploid); // check to see if they need a newer version of the scene data + SceneModel model = scmgr.getSceneModel(); + if (sceneVersion < model.version) { + // then send the moveTo response + sendResponse(source, invid, MOVE_SUCCEEDED_PLUS_UPDATE_RESPONSE, + new Integer(ploid), config, model); - // then send the moveTo response - sendResponse(source, invid, MOVE_SUCCEEDED_RESPONSE, - new Integer(ploid), config); + } else { + // then send the moveTo response + sendResponse(source, invid, MOVE_SUCCEEDED_RESPONSE, + new Integer(ploid), config); + } } catch (ServiceFailedException sfe) { sendResponse(source, invid, MOVE_FAILED_RESPONSE, diff --git a/src/java/com/threerings/whirled/server/SceneRegistry.java b/src/java/com/threerings/whirled/server/SceneRegistry.java index b654e0143..b14eca51b 100644 --- a/src/java/com/threerings/whirled/server/SceneRegistry.java +++ b/src/java/com/threerings/whirled/server/SceneRegistry.java @@ -1,5 +1,5 @@ // -// $Id: SceneRegistry.java,v 1.9 2001/11/09 21:47:09 mdb Exp $ +// $Id: SceneRegistry.java,v 1.10 2001/11/12 20:56:56 mdb Exp $ package com.threerings.whirled.server; @@ -13,7 +13,7 @@ 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; @@ -43,9 +43,18 @@ public class SceneRegistry { _screp = screp; - // we'll use this to do database stuff - _invoker = new Invoker(); - _invoker.start(); + // use a default runtime scene factory for now; assume that + // containing systems will call setRuntimeSceneFactory() later + _scfact = new DefaultRuntimeSceneFactory(); + } + + /** + * Instructs the scene registry to use the supplied factory to create + * runtime scene instances from scene models. + */ + public void setRuntimeSceneFactory (RuntimeSceneFactory factory) + { + _scfact = factory; } /** @@ -120,24 +129,23 @@ public class SceneRegistry } else { // otherwise we've got to initiate the resolution process. // first we create the penders list - penders = new ArrayList(); - _penders.put(sceneId, penders); + _penders.put(sceneId, penders = new ArrayList()); penders.add(target); // i don't like cluttering up method declarations with final // keywords... final int fsceneId = sceneId; - Log.info("Invoking scene repository [id=" + sceneId + "]."); + Log.info("Invoking scene lookup [id=" + sceneId + "]."); // then we queue up an execution unit that'll load the scene // and initialize it and all that - _invoker.postUnit(new Invoker.Unit() { + WhirledServer.invoker.postUnit(new Invoker.Unit() { // this is run on the invoker thread public boolean invoke () { try { - _scene = _screp.loadScene(fsceneId); + _model = _screp.loadSceneModel(fsceneId); } catch (Exception e) { _cause = e; } @@ -147,8 +155,8 @@ public class SceneRegistry // this is run on the dobjmgr thread public void handleResult () { - if (_scene != null) { - processSuccessfulResolution(_scene); + if (_model != null) { + processSuccessfulResolution(_model); } else if (_cause != null) { processFailedResolution(fsceneId, _cause); } else { @@ -158,7 +166,7 @@ public class SceneRegistry } } - protected Scene _scene; + protected SceneModel _model; protected Exception _cause; }); } @@ -167,7 +175,7 @@ public class SceneRegistry /** * Called when the scene resolution has completed successfully. */ - protected void processSuccessfulResolution (Scene scene) + protected void processSuccessfulResolution (SceneModel model) { // now that the scene is loaded, we can create a scene manager for // it. that will be initialized by the place registry and when @@ -175,6 +183,10 @@ public class SceneRegistry // what's up try { + // first create our runtime scene instance + RuntimeScene scene = _scfact.createScene(model); + + // now create our scene manager SceneManager scmgr = (SceneManager) CrowdServer.plreg.createPlace(scene.getPlaceConfig(), null); @@ -182,7 +194,7 @@ public class SceneRegistry // stuff; we'll somehow need to convey configuration // information for the scene to the scene manager, but for now // let's punt - scmgr.postInit(scene, this); + scmgr.postInit(scene, model, this); // when the scene manager completes its startup procedings, it // will call back to the scene registry and let us know that @@ -190,7 +202,7 @@ public class SceneRegistry } catch (InstantiationException ie) { // so close, but no cigar - processFailedResolution(scene.getId(), ie); + processFailedResolution(model.sceneId, ie); } } @@ -255,9 +267,16 @@ public class SceneRegistry } } + /** The entity from which we load scene models. */ protected SceneRepository _screp; - protected Invoker _invoker; - + + /** The entity via which we create runtime scene instances from scene + * models. */ + protected RuntimeSceneFactory _scfact; + + /** A mapping from scene ids to scene managers. */ protected HashIntMap _scenemgrs = new HashIntMap(); + + /** The table of pending resolution listeners. */ protected HashIntMap _penders = new HashIntMap(); } diff --git a/src/java/com/threerings/whirled/server/WhirledServer.java b/src/java/com/threerings/whirled/server/WhirledServer.java index c9f9ffab5..f2c82c3f8 100644 --- a/src/java/com/threerings/whirled/server/WhirledServer.java +++ b/src/java/com/threerings/whirled/server/WhirledServer.java @@ -1,5 +1,5 @@ // -// $Id: WhirledServer.java,v 1.8 2001/11/08 02:59:17 mdb Exp $ +// $Id: WhirledServer.java,v 1.9 2001/11/12 20:56:56 mdb Exp $ package com.threerings.whirled.server; @@ -7,6 +7,7 @@ import com.samskivert.jdbc.ConnectionProvider; import com.samskivert.jdbc.StaticConnectionProvider; import com.samskivert.util.Config; +import com.threerings.presents.util.Invoker; import com.threerings.crowd.server.CrowdServer; import com.threerings.whirled.Log; @@ -28,6 +29,9 @@ public class WhirledServer extends CrowdServer /** The scene registry. */ public static SceneRegistry screg; + /** A thread on which we can do things like repository lookups. */ + public static Invoker invoker; + /** * Initializes all of the server services and prepares for operation. */ @@ -40,6 +44,10 @@ public class WhirledServer extends CrowdServer // bind the whirled server config into the namespace config.bindProperties(CONFIG_KEY, CONFIG_PATH, true); + // create and start up our invoker + invoker = new Invoker(); + invoker.start(); + // create our connection provider conprov = createConnectionProvider(config); diff --git a/src/java/com/threerings/whirled/server/persist/DummySceneRepository.java b/src/java/com/threerings/whirled/server/persist/DummySceneRepository.java index b8cd21195..da2f26378 100644 --- a/src/java/com/threerings/whirled/server/persist/DummySceneRepository.java +++ b/src/java/com/threerings/whirled/server/persist/DummySceneRepository.java @@ -1,13 +1,12 @@ // -// $Id: DummySceneRepository.java,v 1.6 2001/11/08 02:59:17 mdb Exp $ +// $Id: DummySceneRepository.java,v 1.7 2001/11/12 20:56:56 mdb Exp $ package com.threerings.whirled.server.persist; import com.samskivert.io.PersistenceException; import com.threerings.whirled.Log; -import com.threerings.whirled.data.DummyScene; -import com.threerings.whirled.data.Scene; +import com.threerings.whirled.data.SceneModel; import com.threerings.whirled.util.NoSuchSceneException; /** @@ -18,15 +17,22 @@ import com.threerings.whirled.util.NoSuchSceneException; public class DummySceneRepository implements SceneRepository { // documentation inherited - public Scene loadScene (int sceneId) + public SceneModel loadSceneModel (int sceneId) throws PersistenceException, NoSuchSceneException { Log.info("Creating dummy scene [id=" + sceneId + "]."); - return new DummyScene(sceneId); + + // create a blank scene model + SceneModel model = new SceneModel(); + model.sceneId = sceneId; + model.version = 1; + model.neighborIds = new int[0]; + + return model; } // documentation inherited - public void updateScene (Scene scene) + public void updateSceneModel (SceneModel model) throws PersistenceException { // nothing doing diff --git a/src/java/com/threerings/whirled/server/persist/SceneRepository.java b/src/java/com/threerings/whirled/server/persist/SceneRepository.java index 75f63086e..c206ee515 100644 --- a/src/java/com/threerings/whirled/server/persist/SceneRepository.java +++ b/src/java/com/threerings/whirled/server/persist/SceneRepository.java @@ -1,40 +1,39 @@ // -// $Id: SceneRepository.java,v 1.4 2001/09/28 22:15:57 mdb Exp $ +// $Id: SceneRepository.java,v 1.5 2001/11/12 20:56:56 mdb Exp $ package com.threerings.whirled.server.persist; import com.samskivert.io.PersistenceException; -import com.threerings.whirled.data.Scene; +import com.threerings.whirled.data.SceneModel; import com.threerings.whirled.util.NoSuchSceneException; /** * The scene repository provides the basic interface for loading and - * updating scenes. It is used by the scene registry and though more scene - * related persistence services may be needed in a full-fledged + * updating scene data. It is used by the scene registry and though more + * scene related persistence services may be needed in a full-fledged * application, the scene repository only encapsulates those needed by the * scene registry and other services provided by the Whirled framework. */ public interface SceneRepository { /** - * Fetches the scene with the specified scene id. + * Fetches the model for the scene with the specified scene id. * * @exception PersistenceException thrown if an error occurs - * attempting to load a scene. + * attempting to load the scene data. * @exception NoSuchSceneException thrown if no scene exists with the * specified scene id. */ - public Scene loadScene (int sceneId) + public SceneModel loadSceneModel (int sceneId) throws PersistenceException, NoSuchSceneException; /** - * Updates the specified scene in the repository with the information - * provided in the scene object. + * Updates the specified scene model in the repository. * * @exception PersistenceException thrown if an error occurs - * attempting to update the scene. + * attempting to update the scene data. */ - public void updateScene (Scene scene) + public void updateSceneModel (SceneModel scene) throws PersistenceException; } diff --git a/src/java/com/threerings/whirled/tools/EditableScene.java b/src/java/com/threerings/whirled/tools/EditableScene.java new file mode 100644 index 000000000..5da295e7a --- /dev/null +++ b/src/java/com/threerings/whirled/tools/EditableScene.java @@ -0,0 +1,51 @@ +// +// $Id: EditableScene.java,v 1.1 2001/11/12 20:56:56 mdb Exp $ + +package com.threerings.whirled.tools; + +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. + * + *

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 this scene's version number. + */ + public void setVersion (int version); + + /** + * Sets the ids of the neighbors of this scene. + */ + public void setNeighborIds (int[] neighborIds); + + /** + * 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 SceneModel getSceneModel (); +} diff --git a/src/java/com/threerings/whirled/tools/EditableSceneImpl.java b/src/java/com/threerings/whirled/tools/EditableSceneImpl.java new file mode 100644 index 000000000..2e94994bc --- /dev/null +++ b/src/java/com/threerings/whirled/tools/EditableSceneImpl.java @@ -0,0 +1,49 @@ +// +// $Id: EditableSceneImpl.java,v 1.1 2001/11/12 20:56:56 mdb Exp $ + +package com.threerings.whirled.tools; + +import com.threerings.crowd.data.PlaceConfig; +import com.threerings.whirled.client.DisplaySceneImpl; +import com.threerings.whirled.data.SceneModel; + +/** + * A basic implementation of the {@link EditableScene} interface. + */ +public class EditableSceneImpl + extends DisplaySceneImpl + implements EditableScene +{ + /** + * Creates an instance that will obtain data from the supplied scene + * model and update it when changes are made. + */ + public EditableSceneImpl (SceneModel model) + { + super(model, null); + } + + // documentation inherited + public void setId (int sceneId) + { + _model.sceneId = sceneId; + } + + // documentation inherited + public void setVersion (int version) + { + _model.version = version; + } + + // documentation inherited + public void setNeighborIds (int[] neighborIds) + { + _model.neighborIds = neighborIds; + } + + // documentation inherited + public SceneModel getSceneModel () + { + return _model; + } +}