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

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


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