0fc8813314
scene. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@2834 542714f4-19e9-0310-aa3c-eee0fc999fb1
308 lines
12 KiB
Java
308 lines
12 KiB
Java
//
|
|
// $Id: SpotProvider.java,v 1.21 2003/10/25 00:10:35 mdb Exp $
|
|
|
|
package com.threerings.whirled.spot.server;
|
|
|
|
import com.samskivert.util.StringUtil;
|
|
|
|
import com.threerings.presents.data.ClientObject;
|
|
import com.threerings.presents.dobj.RootDObjectManager;
|
|
import com.threerings.presents.server.InvocationException;
|
|
import com.threerings.presents.server.InvocationManager;
|
|
import com.threerings.presents.server.InvocationProvider;
|
|
|
|
import com.threerings.crowd.chat.server.CommunicationAuthorizer;
|
|
import com.threerings.crowd.data.BodyObject;
|
|
import com.threerings.crowd.data.PlaceConfig;
|
|
import com.threerings.crowd.data.PlaceObject;
|
|
import com.threerings.crowd.server.PlaceRegistry;
|
|
|
|
import com.threerings.whirled.client.SceneService.SceneMoveListener;
|
|
import com.threerings.whirled.data.SceneModel;
|
|
import com.threerings.whirled.data.ScenedBodyObject;
|
|
import com.threerings.whirled.server.SceneManager;
|
|
import com.threerings.whirled.server.SceneRegistry;
|
|
|
|
import com.threerings.whirled.spot.Log;
|
|
import com.threerings.whirled.spot.client.SpotService;
|
|
import com.threerings.whirled.spot.data.Location;
|
|
import com.threerings.whirled.spot.data.Portal;
|
|
import com.threerings.whirled.spot.data.SpotCodes;
|
|
import com.threerings.whirled.spot.data.SpotScene;
|
|
|
|
/**
|
|
* Provides the server-side implementation of the spot services.
|
|
*/
|
|
public class SpotProvider
|
|
implements SpotCodes, InvocationProvider
|
|
{
|
|
/**
|
|
* Creates a spot provider that can be registered with the invocation
|
|
* manager to handle spot services.
|
|
*/
|
|
public SpotProvider (RootDObjectManager omgr, PlaceRegistry plreg,
|
|
SceneRegistry screg)
|
|
{
|
|
// we'll need these later
|
|
_plreg = plreg;
|
|
_screg = screg;
|
|
_omgr = omgr;
|
|
}
|
|
|
|
/**
|
|
* Set the authorizer we will use to see if the user is allowed to
|
|
* perform various chatting actions.
|
|
*/
|
|
public static void setCommunicationAuthorizer (
|
|
CommunicationAuthorizer comAuth)
|
|
{
|
|
_comAuth = comAuth;
|
|
}
|
|
|
|
/**
|
|
* Processes a {@link SpotService#traversePortal} request.
|
|
*/
|
|
public void traversePortal (ClientObject caller, int portalId,
|
|
int destSceneVer, SceneMoveListener listener)
|
|
throws InvocationException
|
|
{
|
|
int sceneId = getCallerSceneId(caller);
|
|
|
|
// avoid cluttering up the method declaration with final keywords
|
|
final BodyObject fsource = (BodyObject)caller;
|
|
final int fportalId = portalId;
|
|
final int fsceneVer = destSceneVer;
|
|
final SceneMoveListener flistener = listener;
|
|
|
|
// obtain the source scene
|
|
final SpotSceneManager srcmgr = (SpotSceneManager)
|
|
_screg.getSceneManager(sceneId);
|
|
if (srcmgr == null) {
|
|
Log.warning("Traverse portal missing source scene " +
|
|
"[user=" + fsource.who() + ", sceneId=" + sceneId +
|
|
", portalId=" + portalId + "].");
|
|
throw new InvocationException(INTERNAL_ERROR);
|
|
}
|
|
|
|
// obtain the destination scene and location id
|
|
SpotScene rss = (SpotScene)srcmgr.getScene();
|
|
final Portal fdest = rss.getPortal(portalId);
|
|
|
|
// give the source scene manager a chance to do access control
|
|
String errmsg = srcmgr.mayTraversePortal(fsource, fdest);
|
|
if (errmsg != null) {
|
|
throw new InvocationException(errmsg);
|
|
}
|
|
|
|
// make sure this portal has valid info
|
|
if (fdest == null || !fdest.isValid()) {
|
|
Log.warning("Traverse portal with invalid portal " +
|
|
"[user=" + fsource.who() + ", scene=" + srcmgr.where() +
|
|
", pid=" + portalId + ", portal=" + fdest +
|
|
", portals=" + StringUtil.toString(rss.getPortals()) +
|
|
"].");
|
|
throw new InvocationException(NO_SUCH_PORTAL);
|
|
}
|
|
|
|
// resolve their destination scene
|
|
SceneRegistry.ResolutionListener 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 (!fsource.isActive()) {
|
|
Log.info("Abandoning portal traversal, client gone " +
|
|
"[who=" + fsource.who() +
|
|
", dest=" + scmgr.where() + "].");
|
|
return;
|
|
}
|
|
|
|
// let the source manager know that this guy is
|
|
// departing via the specified portal
|
|
srcmgr.willTraversePortal(fsource, fdest);
|
|
|
|
SpotSceneManager sscmgr = (SpotSceneManager)scmgr;
|
|
finishTraversePortalRequest(
|
|
fsource, sscmgr, fsceneVer, fdest, flistener);
|
|
}
|
|
|
|
public void sceneFailedToResolve (
|
|
int rsceneId, Exception reason) {
|
|
Log.warning("Unable to resolve target scene " +
|
|
"[sceneId=" + rsceneId +
|
|
", reason=" + reason + "].");
|
|
// pretend like the scene doesn't exist to the client
|
|
flistener.requestFailed(NO_SUCH_PLACE);
|
|
}
|
|
};
|
|
_screg.resolveScene(fdest.targetSceneId, rl);
|
|
}
|
|
|
|
/**
|
|
* This is called after the scene to which we are moving is guaranteed
|
|
* to have been loaded into the server.
|
|
*/
|
|
protected void finishTraversePortalRequest (
|
|
BodyObject source, SpotSceneManager destmgr, int sceneVer,
|
|
Portal dest, SceneMoveListener listener)
|
|
{
|
|
// let the destination scene manager know that we're coming in
|
|
destmgr.mapEnteringBody(source, dest.targetPortalId);
|
|
|
|
try {
|
|
// move to the place object associated with this scene
|
|
_screg.sceneprov.effectSceneMove(
|
|
source, destmgr, sceneVer, listener);
|
|
} catch (InvocationException sfe) {
|
|
listener.requestFailed(sfe.getMessage());
|
|
// and let the destination scene manager know that we're no
|
|
// longer coming in
|
|
destmgr.clearEnteringBody(source);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Processes a {@link SpotService#changeLocation} request.
|
|
*/
|
|
public void changeLocation (ClientObject caller, int sceneId, Location loc,
|
|
SpotService.ConfirmListener listener)
|
|
throws InvocationException
|
|
{
|
|
BodyObject source = (BodyObject)caller;
|
|
int cSceneId = getCallerSceneId(caller);
|
|
if (cSceneId != sceneId) {
|
|
Log.warning("Rejecting changeLocation for invalid scene " +
|
|
"[user=" + source.who() + ", insid=" + cSceneId +
|
|
", wantsid=" + sceneId + ", loc=" + loc + "].");
|
|
throw new InvocationException(INVALID_LOCATION);
|
|
}
|
|
|
|
// look up the scene manager for the specified scene
|
|
SpotSceneManager smgr = (SpotSceneManager)
|
|
_screg.getSceneManager(sceneId);
|
|
if (smgr == null) {
|
|
Log.warning("User requested to change location from " +
|
|
"non-existent scene [user=" + source.who() +
|
|
", sceneId=" + sceneId + ", loc=" + loc +"].");
|
|
throw new InvocationException(INTERNAL_ERROR);
|
|
}
|
|
|
|
// pass the buck to yon scene manager
|
|
smgr.handleChangeLoc(source, loc);
|
|
|
|
// if that method finished, we're good to go
|
|
listener.requestProcessed();
|
|
}
|
|
|
|
/**
|
|
* Processes a {@link SpotService#joinCluster} request.
|
|
*/
|
|
public void joinCluster (ClientObject caller, int friendOid,
|
|
SpotService.ConfirmListener listener)
|
|
throws InvocationException
|
|
{
|
|
int sceneId = getCallerSceneId(caller);
|
|
BodyObject source = (BodyObject)caller;
|
|
|
|
// look up the scene manager for the specified scene
|
|
SpotSceneManager smgr = (SpotSceneManager)
|
|
_screg.getSceneManager(sceneId);
|
|
if (smgr == null) {
|
|
Log.warning("User requested to join cluster from " +
|
|
"non-existent scene [user=" + source.who() +
|
|
", sceneId=" + sceneId + ", foid=" + friendOid +"].");
|
|
throw new InvocationException(INTERNAL_ERROR);
|
|
}
|
|
|
|
// pass the buck to yon scene manager
|
|
smgr.handleJoinCluster(source, friendOid);
|
|
|
|
// if that method finished, we're good to go
|
|
listener.requestProcessed();
|
|
}
|
|
|
|
/**
|
|
* Handles request to generate a speak message in the specified cluster.
|
|
*/
|
|
public void clusterSpeak (ClientObject caller, String message, byte mode)
|
|
throws InvocationException
|
|
{
|
|
// make sure the caller is authorized to perform this action
|
|
if ((_comAuth != null) && (!_comAuth.authorized(caller))) {
|
|
return;
|
|
}
|
|
|
|
BodyObject source = (BodyObject)caller;
|
|
sendClusterChatMessage(getCallerSceneId(caller), source.getOid(),
|
|
source.username, null, message, mode);
|
|
}
|
|
|
|
/**
|
|
* Sends a cluster chat notification to the specified location in the
|
|
* specified place object originating with the specified speaker (the
|
|
* speaker can be a server entity that wishes to fake a "speak"
|
|
* message, in which case the bundle argument should be non-null and
|
|
* should contain the id of the bundle to be used to translate the
|
|
* message text) and with the supplied message content.
|
|
*
|
|
* @param sceneId the scene id in which to deliver the chat message.
|
|
* @param speakerOid the body object id of the speaker (used to verify
|
|
* that they are in the cluster in question).
|
|
* @param speaker the username of the user that generated the message
|
|
* (or some special speaker name for server messages).
|
|
* @param bundle the bundle identifier that will be used by the client
|
|
* to translate the message text (or null if the message originated
|
|
* from a real live human who wrote it in their native tongue).
|
|
* @param message the text of the chat message.
|
|
*/
|
|
public void sendClusterChatMessage (
|
|
int sceneId, int speakerOid, String speaker,
|
|
String bundle, String message, byte mode)
|
|
{
|
|
// look up the scene manager for the specified scene
|
|
SpotSceneManager smgr = (SpotSceneManager)
|
|
_screg.getSceneManager(sceneId);
|
|
if (smgr == null) {
|
|
Log.warning("User requested cluster chat in non-existent scene " +
|
|
"[user=" + speaker + ", sceneId=" + sceneId +
|
|
", 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 {
|
|
Log.warning("Can't get scene from non-scened caller " +
|
|
caller.who() + ".");
|
|
throw new InvocationException(INTERNAL_ERROR);
|
|
}
|
|
}
|
|
|
|
/** The place registry with which we interoperate. */
|
|
protected PlaceRegistry _plreg;
|
|
|
|
/** The scene registry with which we interoperate. */
|
|
protected SceneRegistry _screg;
|
|
|
|
/** The object manager we use to do dobject stuff. */
|
|
protected RootDObjectManager _omgr;
|
|
|
|
/** The entity that will authorize our speaker. */
|
|
protected static CommunicationAuthorizer _comAuth;
|
|
}
|