diff --git a/src/java/com/threerings/parlor/client/ParlorCodes.java b/src/java/com/threerings/parlor/client/ParlorCodes.java index 4c170113c..76c031efb 100644 --- a/src/java/com/threerings/parlor/client/ParlorCodes.java +++ b/src/java/com/threerings/parlor/client/ParlorCodes.java @@ -1,5 +1,5 @@ // -// $Id: ParlorCodes.java,v 1.1 2001/10/01 22:17:34 mdb Exp $ +// $Id: ParlorCodes.java,v 1.2 2001/10/02 02:09:06 mdb Exp $ package com.threerings.parlor.client; @@ -17,6 +17,16 @@ public interface ParlorCodes extends InvocationCodes * notification. */ public static final String INVITE_ID = "Invite"; + /** The response identifier for an accepted invite request. This is + * mapped by the invocation services to a call to {@link + * ParlorDirector#handleInviteReceived}. */ + public static final String INVITE_RECEIVED_RESPONSE = "InviteReceived"; + + /** The response identifier for a rejceted invite request. This is + * mapped by the invocation services to a call to {@link + * ParlorDirector#handleInviteFailed}. */ + public static final String INVITE_FAILED_RESPONSE = "InviteFailed"; + /** The message identifier for an invitation cancellation request or * notification. */ public static final String CANCEL_INVITE_ID = "CancelInvite"; @@ -33,4 +43,9 @@ public interface ParlorCodes extends InvocationCodes /** The response code for a countered invitation. */ public static final int INVITATION_COUNTERED = 2; + + /** An error code explaining that an invitation was rejected because + * the invited user was not online at the time the invitation was + * received. */ + public static final String INVITEE_NOT_ONLINE = "m.invitee_not_online"; } diff --git a/src/java/com/threerings/parlor/client/ParlorDirector.java b/src/java/com/threerings/parlor/client/ParlorDirector.java index 3abc2a5ca..817dc9f2d 100644 --- a/src/java/com/threerings/parlor/client/ParlorDirector.java +++ b/src/java/com/threerings/parlor/client/ParlorDirector.java @@ -1,5 +1,5 @@ // -// $Id: ParlorDirector.java,v 1.4 2001/10/01 22:17:34 mdb Exp $ +// $Id: ParlorDirector.java,v 1.5 2001/10/02 02:09:06 mdb Exp $ package com.threerings.parlor.client; @@ -7,6 +7,8 @@ import java.util.ArrayList; import java.util.Iterator; import com.samskivert.util.HashIntMap; +import com.threerings.cocktail.cher.client.InvocationReceiver; + import com.threerings.parlor.Log; import com.threerings.parlor.data.GameConfig; import com.threerings.parlor.util.ParlorContext; @@ -19,7 +21,7 @@ import com.threerings.parlor.util.ParlorContext; * that started. */ public class ParlorDirector - implements ParlorCodes + implements ParlorCodes, InvocationReceiver { /** * Constructs a parlor director and provides it with the parlor diff --git a/src/java/com/threerings/parlor/client/ParlorService.java b/src/java/com/threerings/parlor/client/ParlorService.java index 406db2f4d..272b89ed4 100644 --- a/src/java/com/threerings/parlor/client/ParlorService.java +++ b/src/java/com/threerings/parlor/client/ParlorService.java @@ -1,10 +1,10 @@ // -// $Id: ParlorService.java,v 1.4 2001/10/01 22:17:34 mdb Exp $ +// $Id: ParlorService.java,v 1.5 2001/10/02 02:09:06 mdb Exp $ package com.threerings.parlor.client; import com.threerings.cocktail.cher.client.Client; -import com.threerings.cocktail.cher.client.InvocationManager; +import com.threerings.cocktail.cher.client.InvocationDirector; import com.threerings.parlor.Log; import com.threerings.parlor.data.GameConfig; @@ -40,11 +40,11 @@ public class ParlorService implements ParlorCodes public static int invite (Client client, String invitee, GameConfig config, Object rsptarget) { - InvocationManager invmgr = client.getInvocationManager(); + InvocationDirector invdir = client.getInvocationDirector(); Object[] args = new Object[] { invitee, config }; Log.info("Sending invite request [to=" + invitee + ", cfg=" + config + "]."); - return invmgr.invoke(MODULE_NAME, INVITE_ID, args, rsptarget); + return invdir.invoke(MODULE_NAME, INVITE_ID, args, rsptarget); } /** @@ -71,14 +71,14 @@ public class ParlorService implements ParlorCodes public static int respond (Client client, int inviteId, int code, Object arg, Object rsptarget) { - InvocationManager invmgr = client.getInvocationManager(); + InvocationDirector invdir = client.getInvocationDirector(); Object[] args = new Object[] { new Integer(inviteId), new Integer(code), null }; // we can't have a null argument so we use the empty string args[2] = (arg == null) ? "" : arg; Log.info("Sending invitation response [inviteId=" + inviteId + ", code=" + code + ", arg=" + arg + "]."); - return invmgr.invoke( + return invdir.invoke( MODULE_NAME, RESPOND_INVITE_ID, args, rsptarget); } @@ -97,10 +97,10 @@ public class ParlorService implements ParlorCodes */ public static int cancel (Client client, int inviteId, Object rsptarget) { - InvocationManager invmgr = client.getInvocationManager(); + InvocationDirector invdir = client.getInvocationDirector(); Object[] args = new Object[] { new Integer(inviteId) }; Log.info("Sending invitation cancellation " + "[inviteId=" + inviteId + "]."); - return invmgr.invoke(MODULE_NAME, CANCEL_INVITE_ID, args, rsptarget); + return invdir.invoke(MODULE_NAME, CANCEL_INVITE_ID, args, rsptarget); } } diff --git a/src/java/com/threerings/parlor/server/ParlorManager.java b/src/java/com/threerings/parlor/server/ParlorManager.java index a52d6baff..68732652d 100644 --- a/src/java/com/threerings/parlor/server/ParlorManager.java +++ b/src/java/com/threerings/parlor/server/ParlorManager.java @@ -1,13 +1,17 @@ // -// $Id: ParlorManager.java,v 1.2 2001/10/01 22:17:34 mdb Exp $ +// $Id: ParlorManager.java,v 1.3 2001/10/02 02:09:06 mdb Exp $ package com.threerings.parlor.server; import com.samskivert.util.Config; +import com.samskivert.util.HashIntMap; import com.threerings.cocktail.cher.server.InvocationManager; +import com.threerings.cocktail.cher.server.ServiceFailedException; + import com.threerings.cocktail.party.data.BodyObject; +import com.threerings.parlor.Log; import com.threerings.parlor.client.ParlorCodes; import com.threerings.parlor.data.GameConfig; @@ -35,6 +39,9 @@ public class ParlorManager // register our invocation provider ParlorProvider pprov = new ParlorProvider(this); invmgr.registerProvider(MODULE_NAME, pprov); + + // keep this around for later + _invmgr = invmgr; } /** @@ -46,13 +53,168 @@ public class ParlorManager * @param invitee the player being invited. * @param config the configuration of the game being proposed. * - * @return the SUCCESS constant if the invitation was - * accepted and delivered, or a string describing the reason for - * failure if it was rejected. + * @return the invitation identifier for the newly created invitation + * record. + * + * @exception ServiceFailedException thrown if the invitation was not + * able to be processed for some reason (like the invited player has + * requested not to be disturbed). The explanation will be provided in + * the message data of the exception. */ - public String invite (BodyObject inviter, BodyObject invitee, - GameConfig config) + public int invite (BodyObject inviter, BodyObject invitee, + GameConfig config) + throws ServiceFailedException { - return SUCCESS; + // here we should check to make sure the invitee hasn't muted the + // inviter, and that the inviter isn't shunned and all that other + // access control type stuff + + // create a new invitation record for this invitation + Invitation invite = new Invitation(inviter, invitee, config); + + // stick it in the pending invites table + _invites.put(invite.inviteId, invite); + + // deliver an invite notification to the invitee + Object[] args = new Object[] { + new Integer(invite.inviteId), inviter.username, config }; + _invmgr.sendNotification( + invitee.getOid(), MODULE_NAME, INVITE_ID, args); + + // and let the caller know the invite id we assigned + return invite.inviteId; } + + /** + * Effects a response to an invitation (accept, refuse or counter), + * made by the specified source user with the specified arguments. + * + * @param source the body object of the user that is issuing this + * response. + * @param inviteId the identifier of the invitation to which we are + * responding. + * @param code the response code (either {@link + * #INVITATION_ACCEPTED}, {@link #INVITATION_REFUSED} or {@link + * #INVITATION_COUNTERED}). + * @param arg the argument that goes along with the response: an + * explanatory message in the case of a refusal (the empty string, not + * null, if no message was provided) or the new game configuration in + * the case of a counter-invitation. + */ + public void respondToInvite (BodyObject source, int inviteId, int code, + Object arg) + { + // look up the invitation + Invitation invite = (Invitation)_invites.get(inviteId); + if (invite == null) { + Log.warning("Requested to respond to non-existent invitation " + + "[source=" + source + ", inviteId=" + inviteId + + ", code=" + code + ", arg=" + arg + "]."); + return; + } + + // make sure this response came from the proper person + if (source != invite.invitee) { + Log.warning("Got response from non-invitee [source=" + source + + ", invite=" + invite + ", code=" + code + + ", arg=" + arg + "]."); + return; + } + + // let the other user know that a response was made to this + // invitation + Object[] args = new Object[] { + new Integer(invite.inviteId), new Integer(code), arg }; + _invmgr.sendNotification( + invite.inviter.getOid(), MODULE_NAME, RESPOND_INVITE_ID, args); + + switch (code) { + case INVITATION_ACCEPTED: + // the invitation was accepted, so we'll need to start up the + // game and get the necessary balls rolling + processAcceptedInvitation(invite); + // and remove the invitation from the pending table + _invites.remove(inviteId); + break; + + case INVITATION_REFUSED: + // remove the invitation record from the pending table as it + // is no longer pending + _invites.remove(inviteId); + break; + + case INVITATION_COUNTERED: + // swap control of the invitation to the invitee + invite.swapControl(); + break; + + default: + Log.warning("Requested to respond to invitation with " + + "unknown response code [source=" + source + + ", invite=" + invite + ", code=" + code + + ", arg=" + arg + "]."); + break; + } + } + + public void cancelInvite (BodyObject source, int inviteId) + { + } + + protected void processAcceptedInvitation (Invitation invite) + { + // start up the game and all that... + } + + /** + * The invitation record is used by the parlor manager to keep track + * of pending invitations. + */ + protected static class Invitation + { + /** The unique identifier for this inviation. */ + public int inviteId = _nextInviteId++; + + /** The person proposing the invitation. */ + public BodyObject inviter; + + /** The person to whom the invitation is proposed. */ + public BodyObject invitee; + + /** The configuration of the game being proposed. */ + public GameConfig config; + + /** + * Constructs a new invitation with the specified participants and + * configuration. + */ + public Invitation (BodyObject inviter, BodyObject invitee, + GameConfig config) + { + this.inviter = inviter; + this.invitee = invitee; + this.config = config; + } + + /** + * Swaps the inviter and invitee which is necessary when the + * invitee responds with a counter-invitation. + */ + public void swapControl () + { + BodyObject tmp = inviter; + inviter = invitee; + invitee = tmp; + } + } + + /** A reference to the invocation manager in operation on this server. */ + protected InvocationManager _invmgr; + + /** The table of pending invitations. */ + protected HashIntMap _invites = new HashIntMap(); + + /** A counter used to generate unique identifiers for invitation + * records. */ + protected static int _nextInviteId = 0; } diff --git a/src/java/com/threerings/parlor/server/ParlorProvider.java b/src/java/com/threerings/parlor/server/ParlorProvider.java index 3063ef001..42c4ef0e7 100644 --- a/src/java/com/threerings/parlor/server/ParlorProvider.java +++ b/src/java/com/threerings/parlor/server/ParlorProvider.java @@ -1,9 +1,10 @@ // -// $Id: ParlorProvider.java,v 1.3 2001/10/01 22:17:34 mdb Exp $ +// $Id: ParlorProvider.java,v 1.4 2001/10/02 02:09:06 mdb Exp $ package com.threerings.parlor.server; import com.threerings.cocktail.cher.server.InvocationProvider; +import com.threerings.cocktail.cher.server.ServiceFailedException; import com.threerings.cocktail.party.data.BodyObject; import com.threerings.cocktail.party.server.PartyServer; @@ -42,21 +43,22 @@ public class ParlorProvider String rsp = null; // ensure that the invitee is online at present - BodyObject target = PartyServer.lookupBody(invitee); - if (target == null) { - rsp = "m.not_online\t" + invitee; + try { + BodyObject target = PartyServer.lookupBody(invitee); + if (target == null) { + throw new ServiceFailedException(INVITEE_NOT_ONLINE); + } - } else { - // if they are, submit the invite request to the parlor - // manager - rsp = _pmgr.invite(source, target, config); - } + // submit the invite request to the parlor manager + int inviteId = _pmgr.invite(source, target, config); + sendResponse(source, invid, INVITE_RECEIVED_RESPONSE, + new Integer(inviteId)); - // now send the response - if (rsp.equals(SUCCESS)) { - sendResponse(source, invid, "InviteReceived"); - } else { - sendResponse(source, invid, "InviteReceived"); + } catch (ServiceFailedException sfe) { + // the exception message is the code indicating the reason + // for the invitation rejection + sendResponse(source, invid, INVITE_FAILED_RESPONSE, + sfe.getMessage()); } } @@ -67,6 +69,8 @@ public class ParlorProvider public void handleRepsondInviteRequest ( BodyObject source, int invid, int inviteId, int code, Object arg) { + // pass this on to the parlor manager + _pmgr.respondToInvite(source, inviteId, code, arg); } /** @@ -76,6 +80,8 @@ public class ParlorProvider public void handleCancelInviteRequest ( BodyObject source, int invid, int inviteId) { + // pass this on to the parlor manager + _pmgr.cancelInvite(source, inviteId); } /** A reference to the parlor manager we're working with. */