Phase one of the scene refactoring (which will set the stage for all

manner of happiness and joy).


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@615 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-11-12 20:56:56 +00:00
parent b1748332f5
commit d35f2894c1
27 changed files with 743 additions and 227 deletions
-4
View File
@@ -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.
@@ -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;
@@ -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
@@ -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.
*
* <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 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 ();
}
@@ -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 <code>moveTo</code> request.
*/
public DisplayScene createScene (SceneModel model, PlaceConfig config);
}
@@ -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;
}
@@ -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";
}
@@ -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
{
}
@@ -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).
*
* <p> 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 <code>moveTo</code> 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
* <code>moveTo</code> 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
@@ -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;
}
@@ -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.
*
* <p> 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";
}
}
@@ -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;
}
@@ -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);
}
@@ -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 ();
}
@@ -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}.
*
* <p> 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();
}
}
}
@@ -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());
}
}
@@ -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.
*
* <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 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 ();
}
@@ -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);
}
@@ -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;
}
@@ -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;
}
@@ -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,
@@ -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();
}
@@ -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);
@@ -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
@@ -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;
}
@@ -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.
*
* <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 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 ();
}
@@ -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;
}
}