diff --git a/src/java/com/threerings/whirled/client/DefaultDisplaySceneFactory.java b/src/java/com/threerings/whirled/client/DefaultDisplaySceneFactory.java deleted file mode 100644 index 478754687..000000000 --- a/src/java/com/threerings/whirled/client/DefaultDisplaySceneFactory.java +++ /dev/null @@ -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); - } -} diff --git a/src/java/com/threerings/whirled/client/DisplayScene.java b/src/java/com/threerings/whirled/client/DisplayScene.java deleted file mode 100644 index db46fc0b0..000000000 --- a/src/java/com/threerings/whirled/client/DisplayScene.java +++ /dev/null @@ -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. - * - *

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 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 (); -} diff --git a/src/java/com/threerings/whirled/client/DisplaySceneFactory.java b/src/java/com/threerings/whirled/client/DisplaySceneFactory.java deleted file mode 100644 index 9ee977c3f..000000000 --- a/src/java/com/threerings/whirled/client/DisplaySceneFactory.java +++ /dev/null @@ -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 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 deleted file mode 100644 index df288b7f8..000000000 --- a/src/java/com/threerings/whirled/client/DisplaySceneImpl.java +++ /dev/null @@ -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; -} diff --git a/src/java/com/threerings/whirled/client/SceneDirector.java b/src/java/com/threerings/whirled/client/SceneDirector.java index 9c04ba6a4..182d7ea32 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.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; diff --git a/src/java/com/threerings/whirled/client/SceneService.java b/src/java/com/threerings/whirled/client/SceneService.java index d3095c7ae..a57596cbb 100644 --- a/src/java/com/threerings/whirled/client/SceneService.java +++ b/src/java/com/threerings/whirled/client/SceneService.java @@ -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); } diff --git a/src/java/com/threerings/whirled/client/persist/SceneRepository.java b/src/java/com/threerings/whirled/client/persist/SceneRepository.java index 708879ab0..b8f916561 100644 --- a/src/java/com/threerings/whirled/client/persist/SceneRepository.java +++ b/src/java/com/threerings/whirled/client/persist/SceneRepository.java @@ -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; } diff --git a/src/java/com/threerings/whirled/data/AuxModel.java b/src/java/com/threerings/whirled/data/AuxModel.java new file mode 100644 index 000000000..464454133 --- /dev/null +++ b/src/java/com/threerings/whirled/data/AuxModel.java @@ -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; +} diff --git a/src/java/com/threerings/whirled/data/Scene.java b/src/java/com/threerings/whirled/data/Scene.java new file mode 100644 index 000000000..fb89834df --- /dev/null +++ b/src/java/com/threerings/whirled/data/Scene.java @@ -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 (); +} diff --git a/src/java/com/threerings/whirled/data/SceneImpl.java b/src/java/com/threerings/whirled/data/SceneImpl.java new file mode 100644 index 000000000..22f7b1702 --- /dev/null +++ b/src/java/com/threerings/whirled/data/SceneImpl.java @@ -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; +} diff --git a/src/java/com/threerings/whirled/data/SceneMarshaller.java b/src/java/com/threerings/whirled/data/SceneMarshaller.java index c5b9ec89c..782173ded 100644 --- a/src/java/com/threerings/whirled/data/SceneMarshaller.java +++ b/src/java/com/threerings/whirled/data/SceneMarshaller.java @@ -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. - * - *

Generated from - * $Id: SceneMarshaller.java,v 1.2 2002/08/20 19:38:15 mdb Exp $ - * */ 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. } diff --git a/src/java/com/threerings/whirled/data/SceneModel.java b/src/java/com/threerings/whirled/data/SceneModel.java index 41add44cc..f07b360af 100644 --- a/src/java/com/threerings/whirled/data/SceneModel.java +++ b/src/java/com/threerings/whirled/data/SceneModel.java @@ -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}. * *

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 toString - * 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 = ""; + model.name = ""; model.version = 0; - model.neighborIds = new int[0]; } } diff --git a/src/java/com/threerings/whirled/data/SceneUpdate.java b/src/java/com/threerings/whirled/data/SceneUpdate.java new file mode 100644 index 000000000..05633ac5f --- /dev/null +++ b/src/java/com/threerings/whirled/data/SceneUpdate.java @@ -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 super.applyToScene. + */ + 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; +} diff --git a/src/java/com/threerings/whirled/server/DefaultRuntimeSceneFactory.java b/src/java/com/threerings/whirled/server/DefaultRuntimeSceneFactory.java deleted file mode 100644 index f13f733ba..000000000 --- a/src/java/com/threerings/whirled/server/DefaultRuntimeSceneFactory.java +++ /dev/null @@ -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()); - } -} diff --git a/src/java/com/threerings/whirled/server/RuntimeScene.java b/src/java/com/threerings/whirled/server/RuntimeScene.java deleted file mode 100644 index 8dc3aa1d8..000000000 --- a/src/java/com/threerings/whirled/server/RuntimeScene.java +++ /dev/null @@ -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. - * - *

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 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 (); -} diff --git a/src/java/com/threerings/whirled/server/RuntimeSceneFactory.java b/src/java/com/threerings/whirled/server/RuntimeSceneFactory.java deleted file mode 100644 index f32ff592d..000000000 --- a/src/java/com/threerings/whirled/server/RuntimeSceneFactory.java +++ /dev/null @@ -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); -} diff --git a/src/java/com/threerings/whirled/server/RuntimeSceneImpl.java b/src/java/com/threerings/whirled/server/RuntimeSceneImpl.java deleted file mode 100644 index d0e78f8e2..000000000 --- a/src/java/com/threerings/whirled/server/RuntimeSceneImpl.java +++ /dev/null @@ -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; -} diff --git a/src/java/com/threerings/whirled/server/SceneDispatcher.java b/src/java/com/threerings/whirled/server/SceneDispatcher.java index e4339d2a1..b511ed681 100644 --- a/src/java/com/threerings/whirled/server/SceneDispatcher.java +++ b/src/java/com/threerings/whirled/server/SceneDispatcher.java @@ -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}. - * - *

Generated from - * $Id: SceneDispatcher.java,v 1.2 2002/08/20 19:38:15 mdb Exp $ - * */ 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. } diff --git a/src/java/com/threerings/whirled/server/SceneManager.java b/src/java/com/threerings/whirled/server/SceneManager.java index bfaaf08cb..6036edf3c 100644 --- a/src/java/com/threerings/whirled/server/SceneManager.java +++ b/src/java/com/threerings/whirled/server/SceneManager.java @@ -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. */ diff --git a/src/java/com/threerings/whirled/server/SceneProvider.java b/src/java/com/threerings/whirled/server/SceneProvider.java index 4caac7d2a..cba2a557b 100644 --- a/src/java/com/threerings/whirled/server/SceneProvider.java +++ b/src/java/com/threerings/whirled/server/SceneProvider.java @@ -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); } diff --git a/src/java/com/threerings/whirled/server/SceneRegistry.java b/src/java/com/threerings/whirled/server/SceneRegistry.java index 3791d27c1..d57ece6c3 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.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. * *

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(); diff --git a/src/java/com/threerings/whirled/server/WhirledServer.java b/src/java/com/threerings/whirled/server/WhirledServer.java index 77d9bff6e..dae03a074 100644 --- a/src/java/com/threerings/whirled/server/WhirledServer.java +++ b/src/java/com/threerings/whirled/server/WhirledServer.java @@ -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; diff --git a/src/java/com/threerings/whirled/server/persist/DummySceneRepository.java b/src/java/com/threerings/whirled/server/persist/DummySceneRepository.java index da2f26378..ed004b2af 100644 --- a/src/java/com/threerings/whirled/server/persist/DummySceneRepository.java +++ b/src/java/com/threerings/whirled/server/persist/DummySceneRepository.java @@ -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 diff --git a/src/java/com/threerings/whirled/server/persist/SceneRepository.java b/src/java/com/threerings/whirled/server/persist/SceneRepository.java index c206ee515..ee2920ee4 100644 --- a/src/java/com/threerings/whirled/server/persist/SceneRepository.java +++ b/src/java/com/threerings/whirled/server/persist/SceneRepository.java @@ -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; } diff --git a/src/java/com/threerings/whirled/spot/client/DisplaySpotScene.java b/src/java/com/threerings/whirled/spot/client/DisplaySpotScene.java deleted file mode 100644 index 03aae15de..000000000 --- a/src/java/com/threerings/whirled/spot/client/DisplaySpotScene.java +++ /dev/null @@ -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 (); -} diff --git a/src/java/com/threerings/whirled/spot/client/DisplaySpotSceneImpl.java b/src/java/com/threerings/whirled/spot/client/DisplaySpotSceneImpl.java deleted file mode 100644 index 992c333b6..000000000 --- a/src/java/com/threerings/whirled/spot/client/DisplaySpotSceneImpl.java +++ /dev/null @@ -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; -} diff --git a/src/java/com/threerings/whirled/spot/client/SpotSceneDirector.java b/src/java/com/threerings/whirled/spot/client/SpotSceneDirector.java index e24c07eea..811a738b9 100644 --- a/src/java/com/threerings/whirled/spot/client/SpotSceneDirector.java +++ b/src/java/com/threerings/whirled/spot/client/SpotSceneDirector.java @@ -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 cluster + * 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; diff --git a/src/java/com/threerings/whirled/spot/client/SpotService.java b/src/java/com/threerings/whirled/spot/client/SpotService.java index 7337d3ce8..17ba1698e 100644 --- a/src/java/com/threerings/whirled/spot/client/SpotService.java +++ b/src/java/com/threerings/whirled/spot/client/SpotService.java @@ -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); } diff --git a/src/java/com/threerings/whirled/spot/data/ClusterObject.dobj b/src/java/com/threerings/whirled/spot/data/ClusterObject.dobj index d694be76d..cec127ea8 100644 --- a/src/java/com/threerings/whirled/spot/data/ClusterObject.dobj +++ b/src/java/com/threerings/whirled/spot/data/ClusterObject.dobj @@ -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(); } diff --git a/src/java/com/threerings/whirled/spot/data/ClusterObject.java b/src/java/com/threerings/whirled/spot/data/ClusterObject.java index 48a3ddf9c..74ed84bbe 100644 --- a/src/java/com/threerings/whirled/spot/data/ClusterObject.java +++ b/src/java/com/threerings/whirled/spot/data/ClusterObject.java @@ -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 occupants 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 + * occupants 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 + * occupants oid list. The list will not change until the + * event is actually propagated through the system. + */ + public void removeFromOccupants (int oid) + { + requestOidRemove(OCCUPANTS, oid); + } } diff --git a/src/java/com/threerings/whirled/spot/data/ClusteredBodyObject.java b/src/java/com/threerings/whirled/spot/data/ClusteredBodyObject.java new file mode 100644 index 000000000..b9f6ee778 --- /dev/null +++ b/src/java/com/threerings/whirled/spot/data/ClusteredBodyObject.java @@ -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); +} diff --git a/src/java/com/threerings/whirled/spot/data/Location.java b/src/java/com/threerings/whirled/spot/data/Location.java index 730eb982f..558f7a152 100644 --- a/src/java/com/threerings/whirled/spot/data/Location.java +++ b/src/java/com/threerings/whirled/spot/data/Location.java @@ -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; } } diff --git a/src/java/com/threerings/whirled/spot/data/Portal.java b/src/java/com/threerings/whirled/spot/data/Portal.java index 178b29442..bd30cdb00 100644 --- a/src/java/com/threerings/whirled/spot/data/Portal.java +++ b/src/java/com/threerings/whirled/spot/data/Portal.java @@ -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. - * - *

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; } } diff --git a/src/java/com/threerings/whirled/spot/data/SceneLocation.java b/src/java/com/threerings/whirled/spot/data/SceneLocation.java new file mode 100644 index 000000000..959410cf0 --- /dev/null +++ b/src/java/com/threerings/whirled/spot/data/SceneLocation.java @@ -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; +} diff --git a/src/java/com/threerings/whirled/spot/data/SpotMarshaller.java b/src/java/com/threerings/whirled/spot/data/SpotMarshaller.java index 6f7987c1c..0027cc61e 100644 --- a/src/java/com/threerings/whirled/spot/data/SpotMarshaller.java +++ b/src/java/com/threerings/whirled/spot/data/SpotMarshaller.java @@ -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. - * - *

Generated from - * $Id: SpotMarshaller.java,v 1.2 2002/08/20 19:38:15 mdb Exp $ - * */ 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. } diff --git a/src/java/com/threerings/whirled/spot/data/SpotOccupantInfo.java b/src/java/com/threerings/whirled/spot/data/SpotOccupantInfo.java deleted file mode 100644 index 880dce39b..000000000 --- a/src/java/com/threerings/whirled/spot/data/SpotOccupantInfo.java +++ /dev/null @@ -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 - * occupantInfo 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 + "]"; - } - }; -} diff --git a/src/java/com/threerings/whirled/spot/data/SpotScene.java b/src/java/com/threerings/whirled/spot/data/SpotScene.java new file mode 100644 index 000000000..c3faeb63d --- /dev/null +++ b/src/java/com/threerings/whirled/spot/data/SpotScene.java @@ -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); +} diff --git a/src/java/com/threerings/whirled/spot/data/SpotSceneImpl.java b/src/java/com/threerings/whirled/spot/data/SpotSceneImpl.java new file mode 100644 index 000000000..c0983d162 --- /dev/null +++ b/src/java/com/threerings/whirled/spot/data/SpotSceneImpl.java @@ -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; +} diff --git a/src/java/com/threerings/whirled/spot/data/SpotSceneModel.java b/src/java/com/threerings/whirled/spot/data/SpotSceneModel.java index 122dfebbc..1679b7d20 100644 --- a/src/java/com/threerings/whirled/spot/data/SpotSceneModel.java +++ b/src/java/com/threerings/whirled/spot/data/SpotSceneModel.java @@ -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. null 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; } } diff --git a/src/java/com/threerings/whirled/spot/data/SpotSceneObject.dobj b/src/java/com/threerings/whirled/spot/data/SpotSceneObject.dobj new file mode 100644 index 000000000..637d2fbc6 --- /dev/null +++ b/src/java/com/threerings/whirled/spot/data/SpotSceneObject.dobj @@ -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(); +} diff --git a/src/java/com/threerings/whirled/spot/data/SpotSceneObject.java b/src/java/com/threerings/whirled/spot/data/SpotSceneObject.java new file mode 100644 index 000000000..81a5f4e9e --- /dev/null +++ b/src/java/com/threerings/whirled/spot/data/SpotSceneObject.java @@ -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 occupantLocs 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 + * occupantLocs 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 occupantLocs 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 + * occupantLocs 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 occupantLocs 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); + } +} diff --git a/src/java/com/threerings/whirled/spot/server/RuntimeSpotScene.java b/src/java/com/threerings/whirled/spot/server/RuntimeSpotScene.java deleted file mode 100644 index 1ffc4ebe2..000000000 --- a/src/java/com/threerings/whirled/spot/server/RuntimeSpotScene.java +++ /dev/null @@ -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 (); -} diff --git a/src/java/com/threerings/whirled/spot/server/RuntimeSpotSceneImpl.java b/src/java/com/threerings/whirled/spot/server/RuntimeSpotSceneImpl.java deleted file mode 100644 index d18940624..000000000 --- a/src/java/com/threerings/whirled/spot/server/RuntimeSpotSceneImpl.java +++ /dev/null @@ -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; -} diff --git a/src/java/com/threerings/whirled/spot/server/SpotDispatcher.java b/src/java/com/threerings/whirled/spot/server/SpotDispatcher.java index 5a9bb7e88..135975cf5 100644 --- a/src/java/com/threerings/whirled/spot/server/SpotDispatcher.java +++ b/src/java/com/threerings/whirled/spot/server/SpotDispatcher.java @@ -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}. - * - *

Generated from - * $Id: SpotDispatcher.java,v 1.2 2002/08/20 19:38:15 mdb Exp $ - * */ 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. } diff --git a/src/java/com/threerings/whirled/spot/server/SpotProvider.java b/src/java/com/threerings/whirled/spot/server/SpotProvider.java index 1856a7e3f..024e3b30c 100644 --- a/src/java/com/threerings/whirled/spot/server/SpotProvider.java +++ b/src/java/com/threerings/whirled/spot/server/SpotProvider.java @@ -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); } } diff --git a/src/java/com/threerings/whirled/spot/server/SpotSceneManager.java b/src/java/com/threerings/whirled/spot/server/SpotSceneManager.java index 5ee8a3b9b..d81f8a60a 100644 --- a/src/java/com/threerings/whirled/spot/server/SpotSceneManager.java +++ b/src/java/com/threerings/whirled/spot/server/SpotSceneManager.java @@ -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 - * getUnoccupiedLocation() 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(); } diff --git a/src/java/com/threerings/whirled/spot/tools/EditablePortal.java b/src/java/com/threerings/whirled/spot/tools/EditablePortal.java index 4c78371af..d5d0bd722 100644 --- a/src/java/com/threerings/whirled/spot/tools/EditablePortal.java +++ b/src/java/com/threerings/whirled/spot/tools/EditablePortal.java @@ -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); - } } diff --git a/src/java/com/threerings/whirled/spot/tools/EditableSpotScene.java b/src/java/com/threerings/whirled/spot/tools/EditableSpotScene.java deleted file mode 100644 index 2a0301bd3..000000000 --- a/src/java/com/threerings/whirled/spot/tools/EditableSpotScene.java +++ /dev/null @@ -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 (); -} diff --git a/src/java/com/threerings/whirled/spot/tools/EditableSpotSceneImpl.java b/src/java/com/threerings/whirled/spot/tools/EditableSpotSceneImpl.java deleted file mode 100644 index 8c89b6a6c..000000000 --- a/src/java/com/threerings/whirled/spot/tools/EditableSpotSceneImpl.java +++ /dev/null @@ -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. - * - *

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; -} diff --git a/src/java/com/threerings/whirled/spot/tools/EditableSpotSceneModel.java b/src/java/com/threerings/whirled/spot/tools/EditableSpotSceneModel.java deleted file mode 100644 index d520e219a..000000000 --- a/src/java/com/threerings/whirled/spot/tools/EditableSpotSceneModel.java +++ /dev/null @@ -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 toString - * data on to the string buffer. - */ - protected void delegatesToString (StringBuffer buf) - { - buf.append(spotSceneModel); - } - - /** - * Derived classes override this to tack their toString - * 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]; - } -} diff --git a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneParser.java b/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneParser.java deleted file mode 100644 index c560e7df7..000000000 --- a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneParser.java +++ /dev/null @@ -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; -} diff --git a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneRuleSet.java b/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneRuleSet.java index e1a3ab7fb..f3477ca7c 100644 --- a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneRuleSet.java +++ b/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneRuleSet.java @@ -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 - 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 - 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()); } } diff --git a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneWriter.java b/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneWriter.java index eb122a862..0be472e33 100644 --- a/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneWriter.java +++ b/src/java/com/threerings/whirled/spot/tools/xml/SpotSceneWriter.java @@ -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)); - } } diff --git a/src/java/com/threerings/whirled/spot/util/SpotSceneUtil.java b/src/java/com/threerings/whirled/spot/util/SpotSceneUtil.java deleted file mode 100644 index 9ca9abfd9..000000000 --- a/src/java/com/threerings/whirled/spot/util/SpotSceneUtil.java +++ /dev/null @@ -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; - } -} diff --git a/src/java/com/threerings/whirled/tools/EditableScene.java b/src/java/com/threerings/whirled/tools/EditableScene.java deleted file mode 100644 index 9e91795c6..000000000 --- a/src/java/com/threerings/whirled/tools/EditableScene.java +++ /dev/null @@ -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. - * - *

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 (); -} diff --git a/src/java/com/threerings/whirled/tools/EditableSceneImpl.java b/src/java/com/threerings/whirled/tools/EditableSceneImpl.java deleted file mode 100644 index e5137b6ed..000000000 --- a/src/java/com/threerings/whirled/tools/EditableSceneImpl.java +++ /dev/null @@ -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; -} diff --git a/src/java/com/threerings/whirled/tools/EditableSceneModel.java b/src/java/com/threerings/whirled/tools/EditableSceneModel.java deleted file mode 100644 index 0bb385daa..000000000 --- a/src/java/com/threerings/whirled/tools/EditableSceneModel.java +++ /dev/null @@ -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 toString - * data on to the string buffer. - */ - protected void delegatesToString (StringBuffer buf) - { - buf.append(sceneModel); - } - - /** - * Derived classes override this to tack their toString - * 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(); - } -} diff --git a/src/java/com/threerings/whirled/tools/xml/SceneParser.java b/src/java/com/threerings/whirled/tools/xml/SceneParser.java index 35445ba07..2c5df0505 100644 --- a/src/java/com/threerings/whirled/tools/xml/SceneParser.java +++ b/src/java/com/threerings/whirled/tools/xml/SceneParser.java @@ -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; } diff --git a/src/java/com/threerings/whirled/tools/xml/SceneRuleSet.java b/src/java/com/threerings/whirled/tools/xml/SceneRuleSet.java index 2cf5164fa..6ee2ed930 100644 --- a/src/java/com/threerings/whirled/tools/xml/SceneRuleSet.java +++ b/src/java/com/threerings/whirled/tools/xml/SceneRuleSet.java @@ -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 scene will match the - * scene in the following XML file: - * - *

-     * <scene name="Scene Name" version="3">
-     *   <neighbor>North Scene</neighbor>
-     *   <neighbor>West Scene</neighbor>
-     *   <!-- ... -->
-     * </scene>
-     * 
- */ - 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 <scene>. */ - protected static final String DEFAULT_SCENE_PREFIX = "scene"; } diff --git a/src/java/com/threerings/whirled/tools/xml/SceneWriter.java b/src/java/com/threerings/whirled/tools/xml/SceneWriter.java index 09149505e..ffbfb9109 100644 --- a/src/java/com/threerings/whirled/tools/xml/SceneWriter.java +++ b/src/java/com/threerings/whirled/tools/xml/SceneWriter.java @@ -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 scene). + * 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(); } diff --git a/src/java/com/threerings/whirled/util/SceneFactory.java b/src/java/com/threerings/whirled/util/SceneFactory.java new file mode 100644 index 000000000..4a98e426f --- /dev/null +++ b/src/java/com/threerings/whirled/util/SceneFactory.java @@ -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); +} diff --git a/src/java/com/threerings/whirled/util/UpdateList.java b/src/java/com/threerings/whirled/util/UpdateList.java new file mode 100644 index 000000000..74198cf7b --- /dev/null +++ b/src/java/com/threerings/whirled/util/UpdateList.java @@ -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. null 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; +} diff --git a/src/java/com/threerings/whirled/zone/client/ZoneDirector.java b/src/java/com/threerings/whirled/zone/client/ZoneDirector.java index 850f61aab..0d0598bc5 100644 --- a/src/java/com/threerings/whirled/zone/client/ZoneDirector.java +++ b/src/java/com/threerings/whirled/zone/client/ZoneDirector.java @@ -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); diff --git a/src/java/com/threerings/whirled/zone/client/ZoneService.java b/src/java/com/threerings/whirled/zone/client/ZoneService.java index 613f9a41f..63f529363 100644 --- a/src/java/com/threerings/whirled/zone/client/ZoneService.java +++ b/src/java/com/threerings/whirled/zone/client/ZoneService.java @@ -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); } diff --git a/src/java/com/threerings/whirled/zone/data/ZoneMarshaller.java b/src/java/com/threerings/whirled/zone/data/ZoneMarshaller.java index 83bd03feb..6b09a41b5 100644 --- a/src/java/com/threerings/whirled/zone/data/ZoneMarshaller.java +++ b/src/java/com/threerings/whirled/zone/data/ZoneMarshaller.java @@ -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. - * - *

Generated from - * $Id: ZoneMarshaller.java,v 1.2 2002/08/20 19:38:16 mdb Exp $ - * */ 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. } diff --git a/src/java/com/threerings/whirled/zone/server/ZoneDispatcher.java b/src/java/com/threerings/whirled/zone/server/ZoneDispatcher.java index 863eb0f4b..50b77bbcf 100644 --- a/src/java/com/threerings/whirled/zone/server/ZoneDispatcher.java +++ b/src/java/com/threerings/whirled/zone/server/ZoneDispatcher.java @@ -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}. - * - *

Generated from - * $Id: ZoneDispatcher.java,v 1.2 2002/08/20 19:38:16 mdb Exp $ - * */ 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. } diff --git a/src/java/com/threerings/whirled/zone/server/ZoneProvider.java b/src/java/com/threerings/whirled/zone/server/ZoneProvider.java index ccc09c742..f8490ce1d 100644 --- a/src/java/com/threerings/whirled/zone/server/ZoneProvider.java +++ b/src/java/com/threerings/whirled/zone/server/ZoneProvider.java @@ -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