Behold Vilya, Ring of Air and repository for our game and virtual worldly

extensions to the distributed environment provided by Narya.


git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@1 c613c5cb-e716-0410-b11b-feb51c14d237
This commit is contained in:
Michael Bayne
2006-06-23 17:58:11 +00:00
commit a4df87e52f
317 changed files with 45818 additions and 0 deletions
@@ -0,0 +1,73 @@
//
// $Id: SceneDispatcher.java 4145 2006-05-24 01:24:24Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2006 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.server;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.presents.client.Client;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.server.InvocationDispatcher;
import com.threerings.presents.server.InvocationException;
import com.threerings.whirled.client.SceneService;
import com.threerings.whirled.data.SceneMarshaller;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
/**
* Dispatches requests to the {@link SceneProvider}.
*/
public class SceneDispatcher extends InvocationDispatcher
{
/**
* Creates a dispatcher that may be registered to dispatch invocation
* service requests for the specified provider.
*/
public SceneDispatcher (SceneProvider provider)
{
this.provider = provider;
}
// documentation inherited
public InvocationMarshaller createMarshaller ()
{
return new SceneMarshaller();
}
// documentation inherited
public void dispatchRequest (
ClientObject source, int methodId, Object[] args)
throws InvocationException
{
switch (methodId) {
case SceneMarshaller.MOVE_TO:
((SceneProvider)provider).moveTo(
source,
((Integer)args[0]).intValue(), ((Integer)args[1]).intValue(), (SceneService.SceneMoveListener)args[2]
);
return;
default:
super.dispatchRequest(source, methodId, args);
return;
}
}
}
@@ -0,0 +1,194 @@
//
// $Id: SceneManager.java 4191 2006-06-13 22:42:20Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.server;
import com.samskivert.io.PersistenceException;
import com.samskivert.util.Invoker;
import com.threerings.crowd.server.PlaceManager;
import com.threerings.presents.server.PresentsServer;
import com.threerings.whirled.Log;
import com.threerings.whirled.data.Scene;
import com.threerings.whirled.data.SceneCodes;
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
* scene services. Presently that is little more than registering the
* scene manager with the scene registry so that the manager can be looked
* up by scene id in addition to place object id.
*/
public class SceneManager extends PlaceManager
{
/**
* Returns the scene object (not the scene distributed object) being
* managed by this scene manager.
*/
public Scene getScene ()
{
return _scene;
}
/**
* Returns {@link UpdateList#getUpdates} for this scene's updates.
*/
public SceneUpdate[] getUpdates (int fromVersion)
{
return _updates.getUpdates(fromVersion);
}
/**
* Called by the scene registry once the scene manager has been
* created (and initialized), but before it is started up.
*/
protected void setSceneData (Scene scene, UpdateList updates,
SceneRegistry screg)
{
_scene = scene;
_screg = screg;
_updates = updates;
// 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();
}
// let derived classes react to the receipt of scene data
gotSceneData();
}
/**
* A method that can be overridden by derived classes to perform
* initialization processing after we receive our scene information
* but before we're started up (and hence registered as an active
* place).
*/
protected void gotSceneData ()
{
}
/**
* We're fully ready to go, so now we register ourselves with the
* scene registry which will make us available to the clients and
* system at large.
*/
protected void didStartup ()
{
super.didStartup();
// Wait until us and all of our subclasses have completely finished
// running didStartup prior to registering the scene as being ready.
PresentsServer.omgr.postRunnable(new Runnable() {
public void run () {
_screg.sceneManagerDidStart(SceneManager.this);
}
});
}
/**
* Called when we have shutdown.
*/
protected void didShutdown ()
{
super.didShutdown();
// unregister ourselves with the scene registry
_screg.unmapSceneManager(this);
}
/**
* When a modification is made to a scene, the scene manager should
* create a SceneUpdate instance and pass it to this method which will
* update the in-memory scene, and apply and record the update in the
* scene repository.
*
* <p> 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 entire scenes
* when they change.
*/
protected void recordUpdate (final SceneUpdate update)
{
// instruct our in-memory copy of the scene to apply the update
_scene.updateReceived(update);
// add it to our in memory update list
_updates.addUpdate(update);
// and apply and store it in the repository
WhirledServer.invoker.postUnit(new Invoker.Unit() {
public boolean invoke () {
try {
_screg.getSceneRepository().applyAndRecordUpdate(
_scene.getSceneModel(), update);
} catch (PersistenceException pe) {
Log.warning("Failed to apply scene update " + update + ".");
Log.logStackTrace(pe);
}
return false;
}
});
// broadcast the update to all occupants of the scene
_plobj.postMessage(SceneCodes.SCENE_UPDATE, new Object[] { update });
}
// documentation inherited
public String where ()
{
return _scene.getName() + " (" + super.where() + ":" +
_scene.getId() + ")";
}
// documentation inherited
protected void toString (StringBuilder buf)
{
super.toString(buf);
buf.append(", scene=").append(_scene);
}
/** A reference to our scene implementation which provides a
* meaningful interpretation of the data in the scene model. */
protected Scene _scene;
/** A list of the updates tracked for this scene. These will be used
* to attempt to bring clients up to date efficiently if they request
* to enter our scene with old scene model data. */
protected UpdateList _updates;
/** A reference to the scene registry so that we can call back to it
* when we're fully initialized. */
protected SceneRegistry _screg;
}
@@ -0,0 +1,184 @@
//
// $Id: SceneProvider.java 3832 2006-02-04 03:49:53Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.server;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.server.InvocationException;
import com.threerings.presents.server.InvocationProvider;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.crowd.server.LocationProvider;
import com.threerings.whirled.Log;
import com.threerings.whirled.client.SceneService.SceneMoveListener;
import com.threerings.whirled.data.SceneCodes;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.data.ScenedBodyObject;
/**
* The scene provider handles the server side of the scene related
* invocation services (e.g. moving from scene to scene).
*/
public class SceneProvider
implements InvocationProvider, SceneCodes
{
/**
* Constructs a scene provider that will interact with the supplied
* scene registry.
*/
public SceneProvider (LocationProvider locprov, SceneRegistry screg)
{
_locprov = locprov;
_screg = screg;
}
/**
* Processes a request from a client to move to a new scene.
*/
public void moveTo (ClientObject caller, int sceneId,
final int sceneVer, final SceneMoveListener listener)
{
final BodyObject source = (BodyObject)caller;
// create a callback object that will handle the resolution or
// failed resolution of the scene
SceneRegistry.ResolutionListener rl = null;
rl = new SceneRegistry.ResolutionListener() {
public void sceneWasResolved (SceneManager scmgr) {
// make sure our caller is still around; under heavy load,
// clients might end their session while the scene is
// resolving
if (!source.isActive()) {
Log.info("Abandoning scene move, client gone " +
"[who=" + source.who() +
", dest=" + scmgr.where() + "].");
InvocationMarshaller.setNoResponse(listener);
return;
}
finishMoveToRequest(source, scmgr, sceneVer, listener);
}
public void sceneFailedToResolve (int rsceneId, Exception reason) {
Log.warning("Unable to resolve scene [sceneid=" + rsceneId +
", reason=" + reason + "].");
// pretend like the scene doesn't exist to the client
listener.requestFailed(NO_SUCH_PLACE);
}
};
// make sure the scene they are headed to is actually loaded into
// the server
_screg.resolveScene(sceneId, rl);
}
/**
* This is called after the scene to which we are moving is guaranteed
* to have been loaded into the server.
*/
protected void finishMoveToRequest (
BodyObject source, SceneManager scmgr, int sceneVersion,
SceneMoveListener listener)
{
try {
effectSceneMove(source, scmgr, sceneVersion, listener);
} catch (InvocationException sfe) {
listener.requestFailed(sfe.getMessage());
} catch (RuntimeException re) {
Log.logStackTrace(re);
listener.requestFailed(INTERNAL_ERROR);
}
}
/**
* Moves the supplied body into the supplied (already resolved) scene
* and informs the supplied listener if the move is successful.
*
* @exception InvocationException thrown if a failure occurs
* attempting to move the user into the place associated with the
* scene.
*/
public void effectSceneMove (BodyObject source, SceneManager scmgr,
int sceneVersion, SceneMoveListener listener)
throws InvocationException
{
// move to the place object associated with this scene
int ploid = scmgr.getPlaceObject().getOid();
PlaceConfig config = _locprov.moveTo(source, ploid);
// now that we've finally moved, we can update the user object
// with the new scene id
((ScenedBodyObject)source).setSceneId(scmgr.getScene().getId());
// check to see if they need a newer version of the scene data
SceneModel model = scmgr.getScene().getSceneModel();
if (sceneVersion < model.version) {
// try getting updates
SceneUpdate[] updates = scmgr.getUpdates(sceneVersion);
if (updates != null) {
listener.moveSucceededWithUpdates(ploid, config, updates);
} else {
listener.moveSucceededWithScene(ploid, config, model);
}
} else {
listener.moveSucceeded(ploid, config);
}
}
/**
* Ejects the specified body from their current scene and sends them a
* request to move to the specified new scene. This is the
* scene-equivalent to {@link LocationProvider#moveBody}.
*/
public void moveBody (BodyObject source, int sceneId)
{
// first remove them from their old place
_locprov.leaveOccupiedPlace(source);
// then send a forced move notification
SceneSender.forcedMove(source, sceneId);
}
/**
* Ejects the specified body from their current scene and zone. This
* is the zone equivalent to {@link
* LocationProvider#leaveOccupiedPlace}.
*/
public void leaveOccupiedScene (ScenedBodyObject source)
{
// remove them from their occupied place
_locprov.leaveOccupiedPlace((BodyObject)source);
// and clear out their scene information
source.setSceneId(-1);
}
/** The location provider we use to handle low-level location stuff. */
protected LocationProvider _locprov;
/** The scene registry with which we interact. */
protected SceneRegistry _screg;
}
@@ -0,0 +1,354 @@
//
// $Id: SceneRegistry.java 3679 2005-08-11 22:30:40Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.server;
import java.util.ArrayList;
import com.samskivert.util.HashIntMap;
import com.samskivert.util.Invoker;
import com.threerings.presents.server.InvocationManager;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.crowd.server.CrowdServer;
import com.threerings.whirled.Log;
import com.threerings.whirled.data.Scene;
import com.threerings.whirled.data.SceneModel;
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 scenes. It
* handles interaction with the scene repository and ensures that scenes
* are loaded into memory when needed and flushed from memory when not
* needed.
*
* <p> The scene repository also takes care of bridging from the blocking,
* synchronous world of the scene repository to the non-blocking
* asynchronous world of the distributed object event queue. Thus its
* interfaces for accessing scenes are structured so as to not block the
* dobjmgr thread while waiting for scenes to be read from or written to
* the repository.
*
* <p><em>Note:</em> All access to the scene registry should take place
* from the dobjmgr thread.
*/
public class SceneRegistry
{
/**
* Used to create {@link PlaceConfig} instances for scenes.
*/
public static interface ConfigFactory
{
/**
* Creates the place config instance appropriate to the specified
* scene.
*/
PlaceConfig createPlaceConfig (SceneModel model);
}
/** Used to provide scene-related server-side services. */
public SceneProvider sceneprov;
/**
* Constructs a scene registry, instructing it to load and store
* scenes using the supplied scene repository.
*/
public SceneRegistry (InvocationManager invmgr, SceneRepository screp,
SceneFactory scfact, ConfigFactory confact)
{
_screp = screp;
_scfact = scfact;
_confact = confact;
// create/register a scene provider with the invocation services
sceneprov = new SceneProvider(CrowdServer.plreg.locprov, this);
invmgr.registerDispatcher(new SceneDispatcher(sceneprov), true);
}
/**
* Fetches the scene manager assosciated with the specified scene.
*
* @return the scene manager for the specified scene or null if no
* scene manager is loaded for that scene.
*/
public SceneManager getSceneManager (int sceneId)
{
return (SceneManager)_scenemgrs.get(sceneId);
}
/**
* Returns a reference to the scene repository in use by this
* registry.
*/
public SceneRepository getSceneRepository ()
{
return _screp;
}
/**
* Returns {@link SceneManager#where} for the specified scene or
* <code>null:sceneId</code> if no scene manager exists for that
* scene.
*/
public String where (int sceneId)
{
SceneManager scmgr = getSceneManager(sceneId);
return (scmgr == null) ? ("null:" + sceneId) : scmgr.where();
}
/**
* Because scenes must be loaded from the scene repository and this
* must not be done on the dobjmgr thread, the interface for resolving
* scenes requires that the entity that wishes for a scene to be
* resolved implement this callback interface so that it can be
* notified when a scene has been loaded and initialized.
*/
public static interface ResolutionListener
{
/**
* Called when the scene has been successfully resolved. The scene
* manager instance provided can be used to obtain a reference to
* the scene, or the scene distributed object.
*/
public void sceneWasResolved (SceneManager scmgr);
/**
* Called if some failure occurred in the scene resolution
* process.
*/
public void sceneFailedToResolve (int sceneId, Exception reason);
}
/**
* Requests that the specified scene be resolved, which means loaded
* into the server and initialized if the scene is not currently
* active. The supplied callback instance will be notified, on the
* dobjmgr thread, when the scene has been resolved. If the scene is
* already active, it will be notified immediately (before the call to
* {@link #resolveScene} returns).
*
* @param sceneId the id of the scene to resolve.
* @param target a reference to a callback instance that will be
* notified when the scene has been resolved (which may be immediately
* if the scene is already active).
*/
public void resolveScene (int sceneId, ResolutionListener target)
{
SceneManager mgr = (SceneManager)_scenemgrs.get(sceneId);
if (mgr != null) {
// if the scene is already resolved, we're ready to roll
target.sceneWasResolved(mgr);
return;
}
if (Log.debug()) {
Log.debug("Resolving scene [id=" + sceneId + "].");
}
// otherwise we've got to resolve the scene and call them back
// later; we can manipulate the penders table with impunity here
// because we only do so on the dobjmgr thread
ArrayList penders = (ArrayList)_penders.get(sceneId);
// if we're already in the process of resolving this scene, just
// add these guys to the list to be notified when it finally is
// resolved
if (penders != null) {
penders.add(target);
} else {
// otherwise we've got to initiate the resolution process.
// first we create the penders list
_penders.put(sceneId, penders = new ArrayList());
penders.add(target);
// i don't like cluttering up method declarations with final
// keywords...
final int fsceneId = sceneId;
if (Log.debug()) {
Log.debug("Invoking scene lookup [id=" + sceneId + "].");
}
// then we queue up an execution unit that'll load the scene
// and initialize it and all that
WhirledServer.invoker.postUnit(new Invoker.Unit() {
// this is run on the invoker thread
public boolean invoke ()
{
try {
_model = _screp.loadSceneModel(fsceneId);
_updates = _screp.loadUpdates(fsceneId);
} catch (Exception e) {
_cause = e;
}
return true;
}
// this is run on the dobjmgr thread
public void handleResult ()
{
if (_model != null) {
processSuccessfulResolution(_model, _updates);
} else if (_cause != null) {
processFailedResolution(fsceneId, _cause);
} else {
Log.warning("Scene loading unit finished with " +
"neither a scene nor a reason for " +
"failure!?");
}
}
public String toString ()
{
return "SceneRegistry.SceneLoader " +
(_model == null ? "" : _model.name) +
"(" + fsceneId + ")";
}
protected SceneModel _model;
protected UpdateList _updates;
protected Exception _cause;
});
}
}
/**
* Called when the scene resolution has completed successfully.
*/
protected void processSuccessfulResolution (
SceneModel model, UpdateList updates)
{
// now that the scene is loaded, we can create a scene manager for
// it. that will be initialized by the place registry and when
// that is finally complete, then we can let our penders know
// what's up
try {
// first create our scene instance
Scene scene = _scfact.createScene(
model, _confact.createPlaceConfig(model));
// now create our scene manager
SceneManager scmgr = (SceneManager)
CrowdServer.plreg.createPlace(scene.getPlaceConfig(), null);
scmgr.setSceneData(scene, updates, this);
// when the scene manager completes its startup procedings, it
// will call back to the scene registry and let us know that
// we can turn the penders loose
} catch (Exception e) {
// so close, but no cigar
processFailedResolution(model.sceneId, e);
}
}
/**
* Called if resolving the scene fails for some reason.
*/
protected void processFailedResolution (int sceneId, Exception cause)
{
Log.info("Failed to resolve scene [sceneId=" + sceneId +
", cause=" + cause + "].");
Log.logStackTrace(cause);
// alas things didn't work out, notify our penders
ArrayList penders = (ArrayList)_penders.remove(sceneId);
if (penders != null) {
for (int i = 0; i < penders.size(); i++) {
ResolutionListener rl = (ResolutionListener)penders.get(i);
try {
rl.sceneFailedToResolve(sceneId, cause);
} catch (Exception e) {
Log.warning("Resolution listener choked.");
Log.logStackTrace(e);
}
}
}
}
/**
* Called by the scene manager once it has started up (meaning that it
* has its place object and is ready to roll).
*/
protected void sceneManagerDidStart (SceneManager scmgr)
{
// register this scene manager in our table
int sceneId = scmgr.getScene().getId();
_scenemgrs.put(sceneId, scmgr);
if (Log.debug()) {
Log.debug("Registering scene manager [scid=" + sceneId +
", scmgr=" + scmgr + "].");
}
// now notify any penders
ArrayList penders = (ArrayList)_penders.remove(sceneId);
if (penders != null) {
for (int i = 0; i < penders.size(); i++) {
ResolutionListener rl = (ResolutionListener)penders.get(i);
try {
rl.sceneWasResolved(scmgr);
} catch (Exception e) {
Log.warning("Resolution listener choked.");
Log.logStackTrace(e);
}
}
}
}
/**
* Called by the scene manager when it is shut down.
*/
protected void unmapSceneManager (SceneManager scmgr)
{
if (_scenemgrs.remove(scmgr.getScene().getId()) == null) {
Log.warning("Requested to unmap unmapped scene manager " +
"[scmgr=" + scmgr + "].");
return;
}
if (Log.debug()) {
Log.debug("Unmapped scene manager " + scmgr + ".");
}
}
/** The entity from which we load scene models. */
protected SceneRepository _screp;
/** Used to generate place configs for our scenes. */
protected ConfigFactory _confact;
/** The entity via which we create scene instances from scene
* models. */
protected SceneFactory _scfact;
/** A mapping from scene ids to scene managers. */
protected HashIntMap _scenemgrs = new HashIntMap();
/** The table of pending resolution listeners. */
protected HashIntMap _penders = new HashIntMap();
}
@@ -0,0 +1,47 @@
//
// $Id: SceneSender.java 4145 2006-05-24 01:24:24Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2006 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.server;
import com.threerings.presents.data.ClientObject;
import com.threerings.presents.server.InvocationSender;
import com.threerings.whirled.client.SceneDecoder;
import com.threerings.whirled.client.SceneReceiver;
/**
* Used to issue notifications to a {@link SceneReceiver} instance on a
* client.
*/
public class SceneSender extends InvocationSender
{
/**
* Issues a notification that will result in a call to {@link
* SceneReceiver#forcedMove} on a client.
*/
public static void forcedMove (
ClientObject target, int arg1)
{
sendNotification(
target, SceneDecoder.RECEIVER_CODE, SceneDecoder.FORCED_MOVE,
new Object[] { Integer.valueOf(arg1) });
}
}
@@ -0,0 +1,40 @@
//
// $Id: WhirledClient.java 4191 2006-06-13 22:42:20Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.server;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.server.CrowdClient;
import com.threerings.whirled.data.ScenedBodyObject;
/**
* The client object used by client management on the Whirled server.
*/
public class WhirledClient extends CrowdClient
{
// documentation inherited from interface
protected void clearLocation (BodyObject bobj)
{
WhirledServer.screg.sceneprov.leaveOccupiedScene(
(ScenedBodyObject)bobj);
}
}
@@ -0,0 +1,91 @@
//
// $Id: WhirledServer.java 4191 2006-06-13 22:42:20Z ray $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.server;
import com.threerings.crowd.server.CrowdServer;
import com.threerings.whirled.Log;
import com.threerings.whirled.server.persist.SceneRepository;
import com.threerings.whirled.util.SceneFactory;
/**
* The whirled server extends the {@link CrowdServer} and provides access
* to managers and the like that are needed by the Whirled serviecs.
*/
public abstract class WhirledServer extends CrowdServer
{
/** The scene registry. */
public static SceneRegistry screg;
/**
* Initializes all of the server services and prepares for operation.
*/
public void init ()
throws Exception
{
// do the base server initialization
super.init();
// configure the client to use our whirled client
clmgr.setClientClass(WhirledClient.class);
// create the scene repository
_screp = createSceneRepository();
// create our scene registry
screg = new SceneRegistry(invmgr, _screp, createSceneFactory(),
createConfigFactory());
Log.info("Whirled server initialized.");
}
/**
* Creates the scene repository that will be used by this server.
*
* @exception Exception thrown if any error occurs while instantiating
* or initializing the scene repository.
*/
protected abstract SceneRepository createSceneRepository ()
throws Exception;
/**
* Creates the scene factory that will be used by our scene registry.
*
* @exception Exception thrown if any error occurs while instantiating
* or initializing the scene repository.
*/
protected abstract SceneFactory createSceneFactory ()
throws Exception;
/**
* Creates the place config factory that will be used our scene
* registry.
*
* @exception Exception thrown if any error occurs while instantiating
* or initializing the scene repository.
*/
protected abstract SceneRegistry.ConfigFactory createConfigFactory ()
throws Exception;
/** The scene repository in use by this server. */
protected SceneRepository _screp;
}
@@ -0,0 +1,60 @@
//
// $Id: DummySceneRepository.java 3438 2005-03-29 23:18:59Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.server.persist;
import com.samskivert.io.PersistenceException;
import com.threerings.whirled.Log;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.util.NoSuchSceneException;
import com.threerings.whirled.util.UpdateList;
/**
* The dummy scene repository just pretends to load and store scenes, but
* in fact it just creates new blank scenes when requested to load a scene
* and does nothing when requested to save one.
*/
public class DummySceneRepository implements SceneRepository
{
// documentation inherited
public SceneModel loadSceneModel (int sceneId)
throws PersistenceException, NoSuchSceneException
{
Log.info("Creating dummy scene [id=" + sceneId + "].");
return SceneModel.blankSceneModel();
}
// documentation inherited from interface
public UpdateList loadUpdates (int sceneId)
throws PersistenceException, NoSuchSceneException
{
return new UpdateList();
}
// documentation inherited from interface
public void applyAndRecordUpdate (SceneModel model, SceneUpdate update)
throws PersistenceException
{
// nothing doing
}
}
@@ -0,0 +1,73 @@
//
// $Id: SceneRepository.java 3438 2005-03-29 23:18:59Z mdb $
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.server.persist;
import com.samskivert.io.PersistenceException;
import com.threerings.whirled.data.SceneModel;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.util.NoSuchSceneException;
import com.threerings.whirled.util.UpdateList;
/**
* The scene repository provides the basic interface for loading and
* updating scene data. It is used by the scene registry and though more
* scene related persistence services may be needed in a full-fledged
* application, the scene repository only encapsulates those needed by the
* scene registry and other services provided by the Whirled framework.
*/
public interface SceneRepository
{
/**
* Fetches the model for the scene with the specified scene id.
*
* @exception PersistenceException thrown if an error occurs
* attempting to load the scene data.
* @exception NoSuchSceneException thrown if no scene exists with the
* specified scene id.
*/
public SceneModel loadSceneModel (int sceneId)
throws PersistenceException, NoSuchSceneException;
/**
* Fetches the set of updates associated with the specified scene.
*
* @exception PersistenceException thrown if an error occurs
* attempting to load the scene updates.
* @exception NoSuchSceneException thrown if no scene exists with the
* specified scene id.
*/
public UpdateList loadUpdates (int sceneId)
throws PersistenceException, NoSuchSceneException;
/**
* Applise the supplied scene update to persistent representation of
* its associated scene, then stores the update persistently for
* future invocations of the server to load. <em>Note:</em> the scene
* update will have already been applied to the supplied scene model.
*
* @exception PersistenceException thrown if an error occurs
* attempting to apply the scene update.
*/
public void applyAndRecordUpdate (SceneModel model, SceneUpdate update)
throws PersistenceException;
}