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,62 @@
//
// $Id: ParlorCodes.java 3359 2005-02-19 22:38:06Z 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.parlor.data;
import com.threerings.presents.data.InvocationCodes;
/**
* Contains codes used by the parlor invocation services.
*/
public interface ParlorCodes extends InvocationCodes
{
/** The response code for an accepted invitation. */
public static final int INVITATION_ACCEPTED = 0;
/** The response code for a refused invitation. */
public static final int INVITATION_REFUSED = 1;
/** 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";
/** An error code returned when a user requests to join a table that
* doesn't exist. */
public static final String NO_SUCH_TABLE = "m.no_such_table";
/** An error code returned when a user requests to join a table at a
* position that is not valid. */
public static final String INVALID_TABLE_POSITION =
"m.invalid_table_position";
/** An error code returned when a user requests to join a table in a
* position that is already occupied. */
public static final String TABLE_POSITION_OCCUPIED =
"m.table_position_occupied";
/** An error code returned when a user requests to leave a table that
* they were not sitting at in the first place. */
public static final String NOT_AT_TABLE = "m.not_at_table";
}
@@ -0,0 +1,200 @@
//
// $Id: ParlorMarshaller.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.parlor.data;
import com.threerings.parlor.client.ParlorService;
import com.threerings.parlor.data.TableConfig;
import com.threerings.parlor.game.data.GameConfig;
import com.threerings.presents.client.Client;
import com.threerings.presents.client.InvocationService;
import com.threerings.presents.data.InvocationMarshaller;
import com.threerings.presents.dobj.InvocationResponseEvent;
import com.threerings.util.Name;
/**
* Provides the implementation of the {@link ParlorService} interface
* that marshalls the arguments and delivers the request to the provider
* on the server. Also provides an implementation of the response listener
* interfaces that marshall the response arguments and deliver them back
* to the requesting client.
*/
public class ParlorMarshaller extends InvocationMarshaller
implements ParlorService
{
// documentation inherited
public static class InviteMarshaller extends ListenerMarshaller
implements InviteListener
{
/** The method id used to dispatch {@link #inviteReceived}
* responses. */
public static final int INVITE_RECEIVED = 1;
// documentation inherited from interface
public void inviteReceived (int arg1)
{
_invId = null;
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, INVITE_RECEIVED,
new Object[] { Integer.valueOf(arg1) }));
}
// documentation inherited
public void dispatchResponse (int methodId, Object[] args)
{
switch (methodId) {
case INVITE_RECEIVED:
((InviteListener)listener).inviteReceived(
((Integer)args[0]).intValue());
return;
default:
super.dispatchResponse(methodId, args);
return;
}
}
}
// documentation inherited
public static class TableMarshaller extends ListenerMarshaller
implements TableListener
{
/** The method id used to dispatch {@link #tableCreated}
* responses. */
public static final int TABLE_CREATED = 1;
// documentation inherited from interface
public void tableCreated (int arg1)
{
_invId = null;
omgr.postEvent(new InvocationResponseEvent(
callerOid, requestId, TABLE_CREATED,
new Object[] { Integer.valueOf(arg1) }));
}
// documentation inherited
public void dispatchResponse (int methodId, Object[] args)
{
switch (methodId) {
case TABLE_CREATED:
((TableListener)listener).tableCreated(
((Integer)args[0]).intValue());
return;
default:
super.dispatchResponse(methodId, args);
return;
}
}
}
/** The method id used to dispatch {@link #cancel} requests. */
public static final int CANCEL = 1;
// documentation inherited from interface
public void cancel (Client arg1, int arg2, InvocationService.InvocationListener arg3)
{
ListenerMarshaller listener3 = new ListenerMarshaller();
listener3.listener = arg3;
sendRequest(arg1, CANCEL, new Object[] {
Integer.valueOf(arg2), listener3
});
}
/** The method id used to dispatch {@link #createTable} requests. */
public static final int CREATE_TABLE = 2;
// documentation inherited from interface
public void createTable (Client arg1, int arg2, TableConfig arg3, GameConfig arg4, ParlorService.TableListener arg5)
{
ParlorMarshaller.TableMarshaller listener5 = new ParlorMarshaller.TableMarshaller();
listener5.listener = arg5;
sendRequest(arg1, CREATE_TABLE, new Object[] {
Integer.valueOf(arg2), arg3, arg4, listener5
});
}
/** The method id used to dispatch {@link #invite} requests. */
public static final int INVITE = 3;
// documentation inherited from interface
public void invite (Client arg1, Name arg2, GameConfig arg3, ParlorService.InviteListener arg4)
{
ParlorMarshaller.InviteMarshaller listener4 = new ParlorMarshaller.InviteMarshaller();
listener4.listener = arg4;
sendRequest(arg1, INVITE, new Object[] {
arg2, arg3, listener4
});
}
/** The method id used to dispatch {@link #joinTable} requests. */
public static final int JOIN_TABLE = 4;
// documentation inherited from interface
public void joinTable (Client arg1, int arg2, int arg3, int arg4, InvocationService.InvocationListener arg5)
{
ListenerMarshaller listener5 = new ListenerMarshaller();
listener5.listener = arg5;
sendRequest(arg1, JOIN_TABLE, new Object[] {
Integer.valueOf(arg2), Integer.valueOf(arg3), Integer.valueOf(arg4), listener5
});
}
/** The method id used to dispatch {@link #leaveTable} requests. */
public static final int LEAVE_TABLE = 5;
// documentation inherited from interface
public void leaveTable (Client arg1, int arg2, int arg3, InvocationService.InvocationListener arg4)
{
ListenerMarshaller listener4 = new ListenerMarshaller();
listener4.listener = arg4;
sendRequest(arg1, LEAVE_TABLE, new Object[] {
Integer.valueOf(arg2), Integer.valueOf(arg3), listener4
});
}
/** The method id used to dispatch {@link #respond} requests. */
public static final int RESPOND = 6;
// documentation inherited from interface
public void respond (Client arg1, int arg2, int arg3, Object arg4, InvocationService.InvocationListener arg5)
{
ListenerMarshaller listener5 = new ListenerMarshaller();
listener5.listener = arg5;
sendRequest(arg1, RESPOND, new Object[] {
Integer.valueOf(arg2), Integer.valueOf(arg3), arg4, listener5
});
}
/** The method id used to dispatch {@link #startSolitaire} requests. */
public static final int START_SOLITAIRE = 7;
// documentation inherited from interface
public void startSolitaire (Client arg1, GameConfig arg2, InvocationService.ConfirmListener arg3)
{
InvocationMarshaller.ConfirmMarshaller listener3 = new InvocationMarshaller.ConfirmMarshaller();
listener3.listener = arg3;
sendRequest(arg1, START_SOLITAIRE, new Object[] {
arg2, listener3
});
}
}
@@ -0,0 +1,402 @@
//
// $Id: Table.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.parlor.data;
import com.samskivert.util.ArrayIntSet;
import com.samskivert.util.ListUtil;
import com.samskivert.util.StringUtil;
import com.threerings.util.Name;
import com.threerings.presents.dobj.DSet;
import com.threerings.crowd.data.BodyObject;
import com.threerings.parlor.data.ParlorCodes;
import com.threerings.parlor.game.data.GameConfig;
import com.threerings.parlor.game.data.PartyGameConfig;
/**
* This class represents a table that is being used to matchmake a game by
* the Parlor services.
*/
public class Table
implements DSet.Entry, ParlorCodes
{
/** The unique identifier for this table. */
public Integer tableId;
/** The object id of the lobby object with which this table is
* associated. */
public int lobbyOid;
/** The oid of the game that was created from this table or -1 if the
* table is still in matchmaking mode. */
public int gameOid = -1;
/** An array of the usernames of the occupants of this table (some
* slots may not be filled), or null if a party game. */
public Name[] occupants;
/** The body oids of the occupants of this table, or null if a party game.
* (This is not propagated to remote instances.) */
public transient int[] bodyOids;
/** The game config for the game that is being matchmade. */
public GameConfig config;
/** The table configuration object. */
public TableConfig tconfig;
/**
* Creates a new table instance, and assigns it the next monotonically
* increasing table id.
*
* @param lobbyOid the object id of the lobby in which this table is
* to live.
* @param tconfig the table configuration for this table.
* @param config the configuration of the game being matchmade by this
* table.
*/
public Table (int lobbyOid, TableConfig tconfig, GameConfig config)
{
// assign a unique table id
tableId = Integer.valueOf(++_tableIdCounter);
// keep track of our lobby oid
this.lobbyOid = lobbyOid;
// keep a casted reference around
this.tconfig = tconfig;
this.config = config;
// make room for the maximum number of players
if (tconfig.desiredPlayerCount != -1) {
occupants = new Name[tconfig.desiredPlayerCount];
bodyOids = new int[occupants.length];
// fill in information on the AIs
int acount = (config.ais == null) ? 0 : config.ais.length;
for (int ii = 0; ii < acount; ii++) {
// TODO: handle this naming business better
occupants[ii] = new Name("AI " + (ii+1));
}
}
}
/**
* Constructs a blank table instance, suitable for unserialization.
*/
public Table ()
{
}
/**
* A convenience function for accessing the table id as an int.
*/
public int getTableId ()
{
return tableId.intValue();
}
/**
* Returns true if there is no one sitting at this table.
*/
public boolean isEmpty ()
{
for (int i = 0; i < bodyOids.length; i++) {
if (bodyOids[i] != 0) {
return false;
}
}
return true;
}
/**
* Count the number of players currently occupying this table.
*/
public int getOccupiedCount ()
{
int count = 0;
for (int ii = 0; ii < occupants.length; ii++) {
if (occupants[ii] != null) {
count++;
}
}
return count;
}
/**
* Once a table is ready to play (see {@link #mayBeStarted} and {@link
* #shouldBeStarted}), the players array can be fetched using this
* method. It will return an array containing the usernames of all of
* the players in the game, sized properly and with each player in the
* appropriate position.
*/
public Name[] getPlayers ()
{
if (isPartyGame()) {
return occupants;
}
// create and populate the players array
Name[] players = new Name[getOccupiedCount()];
for (int ii = 0, dex = 0; ii < occupants.length; ii++) {
if (occupants[ii] != null) {
players[dex++] = occupants[ii];
}
}
return players;
}
/**
* For a team game, get the team member indices of the compressed
* players array returned by getPlayers().
*/
public int[][] getTeamMemberIndices ()
{
int[][] teams = tconfig.teamMemberIndices;
if (teams == null) {
return null;
}
// compress the team indexes down
ArrayIntSet set = new ArrayIntSet();
int[][] newTeams = new int[teams.length][];
Name[] players = getPlayers();
for (int ii=0; ii < teams.length; ii++) {
set.clear();
for (int jj=0; jj < teams[ii].length; jj++) {
Name occ = occupants[teams[ii][jj]];
if (occ != null) {
set.add(ListUtil.indexOf(players, occ));
}
}
newTeams[ii] = set.toIntArray();
}
return newTeams;
}
/**
* Return true if the game is a party game.
*/
public boolean isPartyGame ()
{
return (PartyGameConfig.NOT_PARTY_GAME != getPartyGameType());
}
/**
* Get the type of party game being played at this table, or
* PartyGameConfig.NOT_PARTY_GAME.
*/
public byte getPartyGameType ()
{
if (config instanceof PartyGameConfig) {
return ((PartyGameConfig) config).getPartyGameType();
} else {
return PartyGameConfig.NOT_PARTY_GAME;
}
}
/**
* Requests to seat the specified user at the specified position in
* this table.
*
* @param position the position in which to seat the user.
* @param occupant the occupant to set.
*
* @return null if the user was successfully seated, a string error
* code explaining the failure if the user was not able to be seated
* at that position.
*/
public String setOccupant (int position, BodyObject occupant)
{
// make sure the requested position is a valid one
if (position >= tconfig.desiredPlayerCount || position < 0) {
return INVALID_TABLE_POSITION;
}
// make sure the requested position is not already occupied
if (occupants[position] != null) {
return TABLE_POSITION_OCCUPIED;
}
// otherwise all is well, stick 'em in
setOccupantPos(position, occupant);
return null;
}
/**
* This method is used for party games, it does no bounds checking
* or verification of the player's ability to join, if you are unsure
* you should call 'setOccupant'.
*/
public void setOccupantPos (int position, BodyObject occupant)
{
occupants[position] = occupant.getVisibleName();
bodyOids[position] = occupant.getOid();
}
/**
* Requests that the specified user be removed from their seat at this
* table.
*
* @return true if the user was seated at the table and has now been
* removed, false if the user was never seated at the table in the
* first place.
*/
public boolean clearOccupant (Name username)
{
for (int i = 0; i < occupants.length; i++) {
if (username.equals(occupants[i])) {
clearOccupantPos(i);
return true;
}
}
return false;
}
/**
* Requests that the user identified by the specified body object id
* be removed from their seat at this table.
*
* @return true if the user was seated at the table and has now been
* removed, false if the user was never seated at the table in the
* first place.
*/
public boolean clearOccupant (int bodyOid)
{
for (int i = 0; i < bodyOids.length; i++) {
if (bodyOid == bodyOids[i]) {
clearOccupantPos(i);
return true;
}
}
return false;
}
/**
* Called to clear an occupant at the specified position.
* Only call this method if you know what you're doing.
*/
public void clearOccupantPos (int position)
{
occupants[position] = null;
bodyOids[position] = 0;
}
/**
* Returns true if this table has a sufficient number of occupants
* that the game can be started.
*/
public boolean mayBeStarted ()
{
if (tconfig.teamMemberIndices == null) {
// for a normal game, just check to see if we're past the minimum
return tconfig.minimumPlayerCount <= getOccupiedCount();
} else {
// for a team game, make sure each team has the minimum players
int[][] teams = tconfig.teamMemberIndices;
for (int ii=0; ii < teams.length; ii++) {
int teamCount = 0;
for (int jj=0; jj < teams[ii].length; jj++) {
if (occupants[teams[ii][jj]] != null) {
teamCount++;
}
}
if (teamCount < tconfig.minimumPlayerCount) {
return false;
}
}
return true;
}
}
/**
* Returns true if sufficient seats are occupied that the game should
* be automatically started.
*/
public boolean shouldBeStarted ()
{
return tconfig.desiredPlayerCount <= getOccupiedCount();
}
/**
* Returns true if this table is in play, false if it is still being
* matchmade.
*/
public boolean inPlay ()
{
return gameOid != -1;
}
// documentation inherited
public Comparable getKey ()
{
return tableId;
}
// documentation inherited
public boolean equals (Object other)
{
return (other instanceof Table) &&
tableId.equals(((Table) other).tableId);
}
// documentation inherited
public int hashCode ()
{
return tableId.intValue();
}
/**
* Generates a string representation of this table instance.
*/
public String toString ()
{
StringBuilder buf = new StringBuilder();
buf.append(StringUtil.shortClassName(this));
buf.append(" [");
toString(buf);
buf.append("]");
return buf.toString();
}
/**
* Helper method for toString, ripe for overrideability.
*/
protected void toString (StringBuilder buf)
{
buf.append("tableId=").append(tableId);
buf.append(", lobbyOid=").append(lobbyOid);
buf.append(", gameOid=").append(gameOid);
buf.append(", occupants=").append(StringUtil.toString(occupants));
buf.append(", config=").append(config);
}
/** A counter for assigning table ids. */
protected static int _tableIdCounter = 0;
}
@@ -0,0 +1,49 @@
//
// $Id: TableConfig.java 3604 2005-06-17 20:25:28Z 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.parlor.data;
import com.threerings.io.SimpleStreamableObject;
/**
* Table configuration parameters for a game that is to be matchmade
* using the table services.
*/
public class TableConfig extends SimpleStreamableObject
{
/** The total number of players that are desired for the table,
* or -1 for a party game. For team games, this should be set to the
* total number of players overall, as teams may be unequal. */
public int desiredPlayerCount;
/** The minimum number of players needed overall (or per-team if a
* team-based game) for the game to start at the creator's discretion. */
public int minimumPlayerCount;
/** If non-null, indicates that this is a team-based game and contains
* the team assignments for each player. For example, a game with
* three players in two teams- players 0 and 2 versus player 1- would
* have { {0, 2}, {1} }; */
public int[][] teamMemberIndices;
/** Whether the table is "private". */
public boolean privateTable;
}
@@ -0,0 +1,56 @@
//
// $Id: TableLobbyObject.java 4145 2006-05-24 01:24:24Z 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.parlor.data;
import com.threerings.presents.dobj.DSet;
/**
* This interface must be implemented by the place object used by a lobby
* that wishes to make use of the table services.
*/
public interface TableLobbyObject
{
/**
* Returns a reference to the distributed set instance that will be
* holding the tables.
*/
public DSet getTables ();
/**
* Adds the supplied table instance to the tables set (using the
* appropriate distributed object mechanisms).
*/
public void addToTables (Table table);
/**
* Updates the value of the specified table instance in the tables
* distributed set (using the appropriate distributed object
* mechanisms).
*/
public void updateTables (Table table);
/**
* Removes the table instance that matches the specified key from the
* tables set (using the appropriate distributed object mechanisms).
*/
public void removeFromTables (Comparable key);
}