GameController derivation that we use to bootstrap on
+ * the client. */
+ public var controller :String;
+
+ /** The class name of the GameManager derivation that we use to manage the game on
+ * the server. */
+ public var manager :String;
+
+ /** The MD5 digest of the game media file. */
+ public var digest :String;
+
+ /** The configuration of the match-making mechanism. */
+ public var match :MatchConfig;
+
+ /** Parameters used to configure the game itself. */
+ public var params :TypedArray;
+
+ public function GameDefinition ()
+ {
+ }
+
+ /**
+ * Provides the path to this game's media (a jar file or an SWF).
+ *
+ * @param gameId the unique id of the game provided when this game definition was registered
+ * with the system, or -1 if we're running in test mode.
+ */
+ public function getMediaPath (gameId :int) :String
+ {
+ throw new Error("abstract");
+ }
+
+ /**
+ * Returns true if a single player can play this game (possibly against AI opponents), or if
+ * opponents are needed.
+ */
+ public function isSinglePlayerPlayable () :Boolean
+ {
+ throw new Error("Not implemented");
+ }
+
+ /** Generates a string representation of this instance. */
+ public function toString () :String
+ {
+ return "[ident=" + ident + ", ctrl=" + controller + ", mgr=" + manager +
+ ", match=" + match + ", params=" + params + ", digest=" + digest + "]";
+ }
+
+ // from interface Streamable
+ public function readObject (ins :ObjectInputStream) :void
+ {
+ ident = (ins.readField(String) as String);
+ controller = (ins.readField(String) as String);
+ manager = (ins.readField(String) as String);
+ digest = (ins.readField(String) as String);
+ match = (ins.readObject() as MatchConfig);
+ params = (ins.readObject() as TypedArray);
+ }
+
+ // from interface Streamable
+ public function writeObject (out :ObjectOutputStream) :void
+ {
+ out.writeField(ident);
+ out.writeField(controller);
+ out.writeField(manager);
+ out.writeField(digest);
+ out.writeObject(match);
+ out.writeObject(params);
+ }
+}
+}
diff --git a/src/as/com/threerings/ezgame/data/MatchConfig.as b/src/as/com/threerings/ezgame/data/MatchConfig.as
new file mode 100644
index 00000000..e688a9d5
--- /dev/null
+++ b/src/as/com/threerings/ezgame/data/MatchConfig.as
@@ -0,0 +1,50 @@
+//
+// $Id$
+//
+// Vilya library - tools for developing networked games
+// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
+// http://www.threerings.net/code/vilya/
+//
+// 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.ezgame.data {
+
+import com.threerings.io.SimpleStreamableObject;
+
+import com.threerings.parlor.game.data.GameConfig;
+
+/**
+ * Used to configure the match-making interface for a game. Particular match-making mechanisms
+ * extend this class and specify their own special configuration parameters.
+ */
+public /*abstract*/ class MatchConfig extends SimpleStreamableObject
+{
+ public function MatchConfig ()
+ {
+ }
+
+ /** Returns the matchmaking type to use for this game, e.g. {@link GameConfig.SEATED_GAME}. */
+ public function getMatchType () :int
+ {
+ throw new Error("Abstract");
+ }
+
+ /** Returns the minimum number of players needed to play this game. */
+ public function getMinimumPlayers () :int
+ {
+ throw new Error("Abstract");
+ }
+}
+}
diff --git a/src/as/com/threerings/ezgame/data/Parameter.as b/src/as/com/threerings/ezgame/data/Parameter.as
new file mode 100644
index 00000000..5a333318
--- /dev/null
+++ b/src/as/com/threerings/ezgame/data/Parameter.as
@@ -0,0 +1,81 @@
+//
+// $Id$
+//
+// Vilya library - tools for developing networked games
+// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
+// http://www.threerings.net/code/vilya/
+//
+// 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.ezgame.data {
+
+import com.threerings.io.ObjectInputStream;
+import com.threerings.io.ObjectOutputStream;
+import com.threerings.io.Streamable;
+
+/**
+ * Defines a configuration parameter for a game. Various derived classes exist that define
+ * particular types of configuration parameters including choices, toggles, ranges, etc.
+ */
+public /*abstract*/ class Parameter
+ implements Streamable
+{
+ /** A string identifier that names this parameter. */
+ public var ident :String;
+
+ /** A human readable name for this configuration parameter. */
+ public var name :String;
+
+ /** A human readable tooltip to display when the mouse is hovered over this configuration
+ * parameter. */
+ public var tip :String;
+
+ public function Parameter ()
+ {
+ }
+
+ public function toString () :String
+ {
+ return ident;
+ }
+
+ public function getDefaultValue () :Object
+ {
+ throw new Error("Abstract");
+ }
+
+ /** Returns the translation key for this parameter's label. */
+ public function getLabel () :String
+ {
+ return "m." + ident;
+ }
+
+ // from interface Streamable
+ public function readObject (ins :ObjectInputStream) :void
+ {
+ ident = (ins.readField(String) as String);
+ name = (ins.readField(String) as String);
+ tip = (ins.readField(String) as String);
+ }
+
+ // from interface Streamable
+ public function writeObject (out :ObjectOutputStream) :void
+ {
+ out.writeField(ident);
+ out.writeField(name);
+ out.writeField(tip);
+ }
+}
+}
diff --git a/src/as/com/threerings/ezgame/data/PropertySetEvent.as b/src/as/com/threerings/ezgame/data/PropertySetEvent.as
index a7a3ec3a..87b1334f 100644
--- a/src/as/com/threerings/ezgame/data/PropertySetEvent.as
+++ b/src/as/com/threerings/ezgame/data/PropertySetEvent.as
@@ -53,8 +53,7 @@ public class PropertySetEvent extends NamedEvent
override public function applyToObject (target :DObject) :Boolean
{
// since we're in actionscript, we're always on the client
- _oldValue =
- EZGameObject(target).applyPropertySet(_name, _data, _index);
+ _oldValue = EZGameObject(target).applyPropertySet(_name, _data, _index);
return true;
}
@@ -63,7 +62,7 @@ public class PropertySetEvent extends NamedEvent
*/
public function getValue () :Object
{
- return _data;
+ return EZObjectMarshaller.decode(_data);
}
/**
@@ -87,7 +86,7 @@ public class PropertySetEvent extends NamedEvent
{
super.readObject(ins);
_index = ins.readInt();
- _data = EZObjectMarshaller.decode(ins.readObject());
+ _data = (ins.readObject() as Object);
}
// from interface Streamable
diff --git a/src/as/com/threerings/ezgame/data/RangeParameter.as b/src/as/com/threerings/ezgame/data/RangeParameter.as
new file mode 100644
index 00000000..22130cd8
--- /dev/null
+++ b/src/as/com/threerings/ezgame/data/RangeParameter.as
@@ -0,0 +1,69 @@
+//
+// $Id$
+//
+// Vilya library - tools for developing networked games
+// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
+// http://www.threerings.net/code/vilya/
+//
+// 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.ezgame.data {
+
+import com.threerings.io.ObjectInputStream;
+import com.threerings.io.ObjectOutputStream;
+
+/**
+ * Models a parameter that can contain an integer value in a specified range.
+ */
+public class RangeParameter extends Parameter
+{
+ /** The minimum value of this parameter. */
+ public var minimum :int;
+
+ /** The maximum value of this parameter. */
+ public var maximum :int;
+
+ /** The starting value for this parameter. */
+ public var start :int;
+
+ public function RangeParameter ()
+ {
+ }
+
+ // documentation inherited
+ override public function getDefaultValue () :Object
+ {
+ return start;
+ }
+
+ // from interface Streamable
+ override public function readObject (ins :ObjectInputStream) :void
+ {
+ super.readObject(ins);
+ minimum = ins.readInt();
+ maximum = ins.readInt();
+ start = ins.readInt();
+ }
+
+ // from interface Streamable
+ override public function writeObject (out :ObjectOutputStream) :void
+ {
+ super.writeObject(out);
+ out.writeInt(minimum);
+ out.writeInt(maximum);
+ out.writeInt(start);
+ }
+}
+}
diff --git a/src/as/com/threerings/ezgame/data/TableMatchConfig.as b/src/as/com/threerings/ezgame/data/TableMatchConfig.as
new file mode 100644
index 00000000..1ef84236
--- /dev/null
+++ b/src/as/com/threerings/ezgame/data/TableMatchConfig.as
@@ -0,0 +1,82 @@
+//
+// $Id$
+//
+// Vilya library - tools for developing networked games
+// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
+// http://www.threerings.net/code/vilya/
+//
+// 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.ezgame.data {
+
+import com.threerings.io.ObjectInputStream;
+import com.threerings.io.ObjectOutputStream;
+
+import com.threerings.parlor.game.data.GameConfig;
+
+/**
+ * Extends {@link MatchConfig} with information about match-making in the table style.
+ */
+public class TableMatchConfig extends MatchConfig
+{
+ /** The minimum number of seats at this table. */
+ public var minSeats :int;
+
+ /** The starting setting for the number of seats at this table. */
+ public var startSeats :int;
+
+ /** The maximum number of seats at this table. */
+ public var maxSeats :int;
+
+ /** This is set to true if this is a party game. */
+ public var isPartyGame :Boolean;
+
+ public function TableMatchConfig ()
+ {
+ }
+
+ // from MatchConfig
+ override public function getMatchType () :int
+ {
+ return isPartyGame ? GameConfig.PARTY : GameConfig.SEATED_GAME;
+ }
+
+ // from MatchConfig
+ override public function getMinimumPlayers () :int
+ {
+ return minSeats;
+ }
+
+ // from interface Streamable
+ override public function readObject (ins :ObjectInputStream) :void
+ {
+ super.readObject(ins);
+ minSeats = ins.readInt();
+ startSeats = ins.readInt();
+ maxSeats = ins.readInt();
+ isPartyGame = ins.readBoolean();
+ }
+
+ // from interface Streamable
+ override public function writeObject (out :ObjectOutputStream) :void
+ {
+ super.writeObject(out);
+ out.writeInt(minSeats);
+ out.writeInt(startSeats);
+ out.writeInt(maxSeats);
+ out.writeBoolean(isPartyGame);
+ }
+}
+}
diff --git a/src/as/com/threerings/ezgame/data/ToggleParameter.as b/src/as/com/threerings/ezgame/data/ToggleParameter.as
new file mode 100644
index 00000000..03007da1
--- /dev/null
+++ b/src/as/com/threerings/ezgame/data/ToggleParameter.as
@@ -0,0 +1,59 @@
+//
+// $Id$
+//
+// Vilya library - tools for developing networked games
+// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
+// http://www.threerings.net/code/vilya/
+//
+// 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.ezgame.data {
+
+import com.threerings.io.ObjectInputStream;
+import com.threerings.io.ObjectOutputStream;
+
+/**
+ * Models a parameter that allows the toggling of a single value.
+ */
+public class ToggleParameter extends Parameter
+{
+ /** The starting state for this parameter. */
+ public var start :Boolean;
+
+ public function ToggleParameter ()
+ {
+ }
+
+ // documentation inherited
+ override public function getDefaultValue () :Object
+ {
+ return start;
+ }
+
+ // from interface Streamable
+ override public function readObject (ins :ObjectInputStream) :void
+ {
+ super.readObject(ins);
+ start = ins.readBoolean();
+ }
+
+ // from interface Streamable
+ override public function writeObject (out :ObjectOutputStream) :void
+ {
+ super.writeObject(out);
+ out.writeBoolean(start);
+ }
+}
+}
diff --git a/src/as/com/threerings/ezgame/data/UserCookie.as b/src/as/com/threerings/ezgame/data/UserCookie.as
index 9d5def20..18a2e6f2 100644
--- a/src/as/com/threerings/ezgame/data/UserCookie.as
+++ b/src/as/com/threerings/ezgame/data/UserCookie.as
@@ -28,16 +28,23 @@ import com.threerings.io.ObjectOutputStream;
import com.threerings.presents.dobj.DSet_Entry;
-import com.threerings.ezgame.util.EZObjectMarshaller;
-
+/**
+ * Represents a user's game-specific cookie data.
+ */
public class UserCookie
implements DSet_Entry
{
/** The id of the player that has this cookie. */
public var playerId :int;
- /** The decoded cookie value. */
- public var cookie :Object;
+ /** The cookie value. */
+ public var cookie :ByteArray;
+
+ public function UserCookie (playerId :int = 0, cookie :ByteArray = null)
+ {
+ this.playerId = playerId;
+ this.cookie = cookie;
+ }
// from DSet_Entry
public function getKey () :Object
@@ -49,14 +56,14 @@ public class UserCookie
public function readObject (ins :ObjectInputStream) :void
{
playerId = ins.readInt();
- var ba :ByteArray = (ins.readField(ByteArray) as ByteArray);
- cookie = EZObjectMarshaller.decode(ba);
+ cookie = (ins.readField(ByteArray) as ByteArray);
}
// from superinterface Streamable
public function writeObject (out :ObjectOutputStream) :void
{
- throw new Error();
+ out.writeInt(playerId);
+ out.writeField(cookie);
}
}
}
diff --git a/src/as/com/threerings/parlor/data/Table.as b/src/as/com/threerings/parlor/data/Table.as
index d4a7e91b..eb62a51c 100644
--- a/src/as/com/threerings/parlor/data/Table.as
+++ b/src/as/com/threerings/parlor/data/Table.as
@@ -40,8 +40,7 @@ import com.threerings.parlor.data.ParlorCodes;
import com.threerings.parlor.game.data.GameConfig;
/**
- * This class represents a table that is being used to matchmake a game by
- * the Parlor services.
+ * This class represents a table that is being used to matchmake a game by the Parlor services.
*/
public class Table
implements DSet_Entry, Hashable
@@ -49,28 +48,25 @@ public class Table
/** The unique identifier for this table. */
public var tableId :int;
- /** The object id of the lobby object with which this table is
- * associated. */
+ /** The object id of the lobby object with which this table is associated. */
public var lobbyOid :int;
- /** The oid of the game that was created from this table or -1 if the
- * table is still in matchmaking mode. */
+ /** The oid of the game that was created from this table or -1 if the table is still in
+ * matchmaking mode. */
public var gameOid :int = -1;
- /** An array of the usernames of the occupants of this table (some
- * slots may not be filled), or null if a party game. */
+ /** An array of the usernames of the occupants of this table (some slots may not be filled), or
+ * null if a party game. */
public var occupants :TypedArray;
- /** The body oids of the occupants of this table, or null if a party game.
- * (This is not propagated to remote instances.) */
- public /*transient*/ var bodyOids :TypedArray;
+ /** The body oids of the occupants of this table, or null if a party game. (This is not
+ * propagated to remote instances.) */
+ public var bodyOids :TypedArray;
- /** For a running game, the total number of players. For FFA party games,
- * this is everyone. */
+ /** For a running game, the total number of players. For FFA party games, this is everyone. */
public var playerCount :int;
- /** For a running game, the total number of watchers. For FFA party games,
- * this is always 0. */
+ /** For a running game, the total number of watchers. For FFA party games, this is always 0. */
public var watcherCount :int;
/** The game config for the game that is being matchmade. */
@@ -84,6 +80,25 @@ public class Table
{
}
+ /**
+ * 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 function getPlayers () :Array
+ {
+ // create and populate the players array
+ var players :Array = new Array();
+ for (var ii :int = 0; ii < occupants.length; ii++) {
+ if (occupants[ii] != null) {
+ players.push(occupants[ii]);
+ }
+ }
+
+ return players;
+ }
+
/**
* Count the number of players currently occupying this table.
*/
@@ -101,28 +116,8 @@ public class Table
}
/**
- * 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 function getPlayers () :Array
- {
- // create and populate the players array
- var players :Array = new Array();
- for (var ii :int = 0; ii < occupants.length; ii++) {
- if (occupants[ii] != null) {
- players.push(occupants[ii]);
- }
- }
-
- return players;
- }
-
- /**
- * For a team game, get the team member indices of the compressed
- * players array returned by getPlayers().
+ * For a team game, get the team member indices of the compressed players array returned by
+ * getPlayers().
*/
public function getTeamMemberIndices () :TypedArray /* of Array of int */
{
@@ -150,98 +145,13 @@ public class Table
return newTeams;
}
-// /**
-// * 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 function setOccupant (position :int, occupant :BodyObject) :String
-// {
-// // make sure the requested position is a valid one
-// if (position >= tconfig.desiredPlayerCount || position < 0) {
-// return ParlorCodes.INVALID_TABLE_POSITION;
-// }
-//
-// // make sure the requested position is not already occupied
-// if (occupants[position] != null) {
-// return ParlorCodes.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 function setOccupantPos (position :int, occupant :BodyObject) :void
-// {
-// 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 function clearOccupant (username :Name) :Boolean
-// {
-// var dex :int = ArrayUtil.indexOf(occupants, username);
-// if (dex != -1) {
-// clearOccupantPos(dex);
-// 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 function clearOccupantByOid (bodyOid :int) :Boolean
-// {
-// var dex :int = ArrayUtil.indexOf(bodyOids, bodyOid);
-// if (dex != -1) {
-// clearOccupantPos(dex);
-// 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 function clearOccupantPos (position :int) :void
-// {
-// occupants[position] = null;
-// bodyOids[position] = 0;
-// }
-
/**
- * Returns true if this table has a sufficient number of occupants
- * that the game can be started.
+ * Returns true if this table has a sufficient number of occupants that the game can be
+ * started.
*/
public function mayBeStarted () :Boolean
{
- switch (config.getGameType()) {
+ switch (config.getMatchType()) {
case GameConfig.SEATED_CONTINUOUS:
case GameConfig.PARTY:
return true;
@@ -270,25 +180,23 @@ public class Table
}
}
-// /**
-// * Returns true if sufficient seats are occupied that the game should
-// * be automatically started.
-// */
-// public function shouldBeStarted () :Boolean
-// {
-// switch (config.getGameType()) {
-// case GameConfig.SEATED_CONTINUOUS:
-// case GameConfig.PARTY:
-// return true;
-//
-// default:
-// return (tconfig.desiredPlayerCount <= getOccupiedCount());
-// }
-// }
+ /**
+ * Returns true if sufficient seats are occupied that the game should be automatically started.
+ */
+ public function shouldBeStarted () :Boolean
+ {
+ switch (config.getMatchType()) {
+ case GameConfig.SEATED_CONTINUOUS:
+ case GameConfig.PARTY:
+ return true;
+
+ default:
+ return (tconfig.desiredPlayerCount <= getOccupiedCount());
+ }
+ }
/**
- * Returns true if this table is in play, false if it is still being
- * matchmade.
+ * Returns true if this table is in play, false if it is still being matchmade.
*/
public function inPlay () :Boolean
{
@@ -304,8 +212,7 @@ public class Table
// from Hashable
public function equals (other :Object) :Boolean
{
- return (other is Table) &&
- (tableId == (other as Table).tableId);
+ return (other is Table) && (tableId == (other as Table).tableId);
}
/**
@@ -327,19 +234,6 @@ public class Table
return tableId;
}
-// /**
-// * Returns true if there is no one sitting at this table.
-// */
-// public function isEmpty () :Boolean
-// {
-// for (var ii :int = 0; ii < bodyOids.length; ii++) {
-// if ((bodyOids[ii] as int) !== 0) {
-// return false;
-// }
-// }
-// return true;
-// }
-
// from Streamable
public function readObject (ins :ObjectInputStream) :void
{
@@ -356,13 +250,14 @@ public class Table
// from Streamable
public function writeObject (out :ObjectOutputStream) :void
{
- throw new Error();
-// out.writeInt(tableId);
-// out.writeInt(lobbyOid);
-// out.writeInt(gameOid);
-// out.writeObject(occupants);
-// out.writeObject(config);
-// out.writeObject(tconfig);
+ out.writeInt(tableId);
+ out.writeInt(lobbyOid);
+ out.writeInt(gameOid);
+ out.writeObject(occupants);
+ out.writeShort(playerCount);
+ out.writeShort(watcherCount);
+ out.writeObject(config);
+ out.writeObject(tconfig);
}
/**
@@ -373,7 +268,7 @@ public class Table
buf.append("tableId=").append(tableId);
buf.append(", lobbyOid=").append(lobbyOid);
buf.append(", gameOid=").append(gameOid);
- buf.append(", occupants=").append(occupants.join());
+ buf.append(", occupants=").append(occupants == null ? "Clients that use the game configurator will want to instantiate one - * based on the class returned from the {@link GameConfig} and then - * initialize it with a call to {@link #init}. + *
Clients that use the game configurator will want to instantiate one based on the class + * returned from the {@link GameConfig} and then initialize it with a call to {@link #init}. */ public /*abstract*/ class FlexGameConfigurator extends GameConfigurator { @@ -54,14 +52,12 @@ public /*abstract*/ class FlexGameConfigurator extends GameConfigurator } /** - * Add a control to the interface. This should be the standard way - * that configurator controls are added, but note also that external - * entities may add their own controls that are related to the game, - * but do not directly alter the game config, so that all the controls - * are added in a uniform manner and are well aligned. + * Add a control to the interface. This should be the standard way that configurator controls + * are added, but note also that external entities may add their own controls that are related + * to the game, but do not directly alter the game config, so that all the controls are added + * in a uniform manner and are well aligned. */ - public function addControl ( - label :UIComponent, control :UIComponent) :void + public function addControl (label :UIComponent, control :UIComponent) :void { var item :HBox = new HBox(); item.width = 225; diff --git a/src/as/com/threerings/parlor/game/client/GameConfigurator.as b/src/as/com/threerings/parlor/game/client/GameConfigurator.as index 70edb9a2..7426c2fd 100644 --- a/src/as/com/threerings/parlor/game/client/GameConfigurator.as +++ b/src/as/com/threerings/parlor/game/client/GameConfigurator.as @@ -25,20 +25,18 @@ import com.threerings.parlor.game.data.GameConfig; import com.threerings.parlor.util.ParlorContext; /** - * Provides the base from which interfaces can be built to configure games - * prior to starting them. Derived classes would extend the base - * configurator adding interface elements and wiring them up properly to - * allow the user to configure an instance of their game. + * Provides the base from which interfaces can be built to configure games prior to starting + * them. Derived classes would extend the base configurator adding interface elements and wiring + * them up properly to allow the user to configure an instance of their game. * - *
Clients that use the game configurator will want to instantiate one - * based on the class returned from the {@link GameConfig} and then - * initialize it with a call to {@link #init}. + *
Clients that use the game configurator will want to instantiate one based on the class + * returned from the {@link GameConfig} and then initialize it with a call to {@link #init}. */ public /*abstract*/ class GameConfigurator { /** - * Initializes this game configurator, creates its user interface - * elements and prepares it for display. + * Initializes this game configurator, creates its user interface elements and prepares it for + * display. */ public function init (ctx :ParlorContext) :void { @@ -57,8 +55,8 @@ public /*abstract*/ class GameConfigurator } /** - * Provides this configurator with its configuration. It should set up - * all of its user interface elements to reflect the configuration. + * Provides this configurator with its configuration. It should set up all of its user + * interface elements to reflect the configuration. */ public function setGameConfig (config :GameConfig) :void { @@ -68,8 +66,8 @@ public /*abstract*/ class GameConfigurator } /** - * Derived classes will likely want to override this method and - * configure their user interface elements accordingly. + * Derived classes will likely want to override this method and configure their user interface + * elements accordingly. */ protected function gotGameConfig () :void { @@ -86,10 +84,9 @@ public /*abstract*/ class GameConfigurator } /** - * Derived classes will want to override this method, flushing values - * from the user interface to the game config object so that it is - * properly configured prior to being returned to the {@link - * #getGameConfig} caller. + * Derived classes will want to override this method, flushing values from the user interface + * to the game config object so that it is properly configured prior to being returned to the + * {@link #getGameConfig} caller. */ protected function flushGameConfig () :void { diff --git a/src/as/com/threerings/parlor/game/client/GameController.as b/src/as/com/threerings/parlor/game/client/GameController.as index 335e5c3b..26f43187 100644 --- a/src/as/com/threerings/parlor/game/client/GameController.as +++ b/src/as/com/threerings/parlor/game/client/GameController.as @@ -294,9 +294,9 @@ public /*abstract*/ class GameController extends PlaceController /** * Convenience method to determine the type of game. */ - protected function getGameType () :int + protected function getMatchType () :int { - return _gconfig.getGameType(); + return _gconfig.getMatchType(); } /** A reference to the active parlor context. */ diff --git a/src/as/com/threerings/parlor/game/data/GameConfig.as b/src/as/com/threerings/parlor/game/data/GameConfig.as index fa116cee..f96314b0 100644 --- a/src/as/com/threerings/parlor/game/data/GameConfig.as +++ b/src/as/com/threerings/parlor/game/data/GameConfig.as @@ -37,48 +37,43 @@ import com.threerings.parlor.client.TableConfigurator; import com.threerings.parlor.game.client.GameConfigurator; /** - * The game config class encapsulates the configuration information for a - * particular type of game. The hierarchy of game config objects mimics the - * hierarchy of game managers and controllers. Both the game manager and game - * controller are provided with the game config object when the game is - * created. + * The game config class encapsulates the configuration information for a particular type of + * game. The hierarchy of game config objects mimics the hierarchy of game managers and + * controllers. Both the game manager and game controller are provided with the game config object + * when the game is created. * - *
The game config object is also the mechanism used to instantiate the - * appropriate game manager and controller. Every game must have an associated - * game config derived class that overrides {@link #createController} and - * {@link #getManagerClassName}, returning the appropriate game controller and - * manager class for that game. Thus the entire chain of events that causes a - * particular game to be created is the construction of the appropriate game - * config instance which is provided to the server as part of an invitation or - * via some other matchmaking mechanism. + *
The game config object is also the mechanism used to instantiate the appropriate game
+ * manager and controller. Every game must have an associated game config derived class that
+ * overrides {@link #createController} and {@link #getManagerClassName}, returning the appropriate
+ * game controller and manager class for that game. Thus the entire chain of events that causes a
+ * particular game to be created is the construction of the appropriate game config instance which
+ * is provided to the server as part of an invitation or via some other matchmaking mechanism.
*/
public /*abstract*/ class GameConfig extends PlaceConfig
implements Cloneable, Hashable
{
- /** Game type constant: a game that is started with a list of players,
- * and those are the only players that may play. */
+ /** Game type constant: a game that is started with a list of players, and those are the only
+ * players that may play. */
public static const SEATED_GAME :int = 0;
- /** Game type constant: a game that starts immediately, but only has
- * a certain number of player slots. Users enter the game room, and
- * then choose where to sit. */
+ /** Game type constant: a game that starts immediately, but only has a certain number of player
+ * slots. Users enter the game room, and then choose where to sit. */
public static const SEATED_CONTINUOUS :int = 1;
- /** Game type constant: a game that starts immediately, and every
- * user that enters is a player. */
+ /** Game type constant: a game that starts immediately, and every user that enters is a
+ * player. */
public static const PARTY :int = 2;
- /** The usernames of the players involved in this game, or an empty
- * array if such information is not needed by this particular game. */
+ /** The usernames of the players involved in this game, or an empty array if such information
+ * is not needed by this particular game. */
public var players :TypedArray = TypedArray.create(Name);
/** Indicates whether or not this game is rated. */
public var rated :Boolean = true;
- /** Configurations for AIs to be used in this game. Slots with real
- * players should be null and slots with AIs should contain
- * configuration for those AIs. A null array indicates no use of AIs
- * at all. */
+ /** Configurations for AIs to be used in this game. Slots with real players should be null and
+ * slots with AIs should contain configuration for those AIs. A null array indicates no use of
+ * AIs at all. */
public var ais :TypedArray = TypedArray.create(GameAI);
public function GameConfig ()
@@ -87,27 +82,31 @@ public /*abstract*/ class GameConfig extends PlaceConfig
}
/**
- * Get the type of game.
+ * Returns a numeric identifier for this game class. This may be used to track persisent
+ * information on a per-game basis.
*/
- public function getGameType () :int
+ public function getGameId () :int
{
- return SEATED_GAME;
+ throw new Error("abstract");
}
- /**
- * Returns the message bundle identifier for the bundle that should be
- * used to translate the translatable strings used to describe the
- * game config parameters.
- */
- public /*abstract*/ function getBundleName () :String
+ public function getGameIdent () :String
{
throw new Error("abstract");
}
/**
- * Creates a configurator that can be used to create a user interface
- * for configuring this instance prior to starting the game. If no
- * configuration is necessary, this method should return null.
+ * Get the type of game.
+ */
+ public function getMatchType () :int
+ {
+ return SEATED_GAME;
+ }
+
+ /**
+ * Creates a configurator that can be used to create a user interface for configuring this
+ * instance prior to starting the game. If no configuration is necessary, this method should
+ * return null.
*/
public /*abstract*/ function createConfigurator () :GameConfigurator
{
@@ -115,8 +114,8 @@ public /*abstract*/ class GameConfig extends PlaceConfig
}
/**
- * Creates a table configurator for initializing 'table' properties
- * of the game. The default implementation returns null.
+ * Creates a table configurator for initializing 'table' properties of the game. The default
+ * implementation returns null.
*/
public function createTableConfigurator () :TableConfigurator
{
@@ -124,34 +123,13 @@ public /*abstract*/ class GameConfig extends PlaceConfig
}
/**
- * Returns a translatable label describing this game.
- */
- public function getGameName () :String
- {
- // the whole getRatingTypeId(), getGameName(), getBundleName()
- // business should be cleaned up. we should have getGameIdent()
- // and everything should have a default implementation using that
- return "m." + getBundleName();
- }
-
- /**
- * Returns the game rating type, if the system uses such things.
- */
- public function getRatingTypeId () :int
- {
- return -1;
- }
-
- /**
- * Computes a hashcode for this game config object that supports our
- * {@link #equals} implementation. Objects that are equal should have
- * the same hashcode.
+ * Computes a hashcode for this game config object that supports our {@link #equals}
+ * implementation. Objects that are equal should have the same hashcode.
*/
public function hashCode () :int
{
// look ma, it's so sophisticated!
- return StringUtil.hashCode(ClassUtil.getClassName(this)) +
- (rated ? 1 : 0);
+ return StringUtil.hashCode(ClassUtil.getClassName(this)) + (rated ? 1 : 0);
}
// from Cloneable
@@ -161,30 +139,27 @@ public /*abstract*/ class GameConfig extends PlaceConfig
copy.players = this.players;
copy.rated = this.rated;
copy.ais = this.ais;
-
return copy;
}
/**
- * Returns true if this game config object is equal to the supplied
- * object (meaning it is also a game config object and its
- * configuration settings are the same as ours).
+ * Returns true if this game config object is equal to the supplied object (meaning it is also
+ * a game config object and its configuration settings are the same as ours).
*/
public function equals (other :Object) :Boolean
{
// make sure they're of the same class
if (ClassUtil.isSameClass(other, this)) {
var that :GameConfig = GameConfig(other);
- return this.rated == that.rated;
-
+ return this.getGameId() == that.getGameId() && this.rated == that.rated;
} else {
return false;
}
}
/**
- * Returns an Array of strings that describe the configuration of this
- * game. Default implementation returns an empty array.
+ * Returns an Array of strings that describe the configuration of this game. Default
+ * implementation returns an empty array.
*/
public function getDescription () :Array
{
diff --git a/src/java/com/threerings/ezgame/Log.java b/src/java/com/threerings/ezgame/Log.java
new file mode 100644
index 00000000..87c819ff
--- /dev/null
+++ b/src/java/com/threerings/ezgame/Log.java
@@ -0,0 +1,58 @@
+//
+// $Id$
+//
+// Vilya library - tools for developing networked games
+// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
+// http://www.threerings.net/code/vilya/
+//
+// 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.ezgame;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Contains a reference to the log object used by this package.
+ */
+public class Log
+{
+ /** We dispatch our log messages through this logger. */
+ public static Logger log = Logger.getLogger("com.threerings.ezgame");
+
+ /** Convenience function. */
+ public static void debug (String message)
+ {
+ log.fine(message);
+ }
+
+ /** Convenience function. */
+ public static void info (String message)
+ {
+ log.info(message);
+ }
+
+ /** Convenience function. */
+ public static void warning (String message)
+ {
+ log.warning(message);
+ }
+
+ /** Convenience function. */
+ public static void logStackTrace (Throwable t)
+ {
+ log.log(Level.WARNING, t.getMessage(), t);
+ }
+}
diff --git a/src/java/com/threerings/ezgame/client/EZGameConfigurator.java b/src/java/com/threerings/ezgame/client/EZGameConfigurator.java
new file mode 100644
index 00000000..963888a9
--- /dev/null
+++ b/src/java/com/threerings/ezgame/client/EZGameConfigurator.java
@@ -0,0 +1,309 @@
+//
+// $Id$
+//
+// Vilya library - tools for developing networked games
+// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
+// http://www.threerings.net/code/vilya/
+//
+// 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.ezgame.client;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+
+import java.util.logging.Level;
+
+import org.apache.commons.io.IOUtils;
+
+import com.samskivert.swing.HGroupLayout;
+import com.samskivert.swing.SimpleSlider;
+
+import com.threerings.util.MessageBundle;
+import com.threerings.util.MessageManager;
+
+import com.threerings.parlor.game.client.SwingGameConfigurator;
+import com.threerings.parlor.game.data.GameAI;
+
+import com.threerings.ezgame.data.AIParameter;
+import com.threerings.ezgame.data.ChoiceParameter;
+import com.threerings.ezgame.data.EZGameConfig;
+import com.threerings.ezgame.data.FileParameter;
+import com.threerings.ezgame.data.GameDefinition;
+import com.threerings.ezgame.data.Parameter;
+import com.threerings.ezgame.data.RangeParameter;
+import com.threerings.ezgame.data.ToggleParameter;
+import com.threerings.ezgame.util.EZGameContext;
+
+import static com.threerings.ezgame.Log.log;
+
+/**
+ * Handles the configuration of an EZ game. This works in conjunction with the {@link EZGameConfig}
+ * to provide a generic mechanism for defining and obtaining game configuration settings.
+ */
+public class EZGameConfigurator extends SwingGameConfigurator
+{
+ // documentation inherited
+ protected void gotGameConfig ()
+ {
+ super.gotGameConfig();
+
+ EZGameContext ctx = (EZGameContext)_ctx;
+ EZGameConfig config = (EZGameConfig)_config;
+ GameDefinition gamedef = config.getGameDefinition();
+
+ // create our parameter editors
+ if (_editors == null) {
+ MessageBundle msgs = ctx.getMessageManager().getBundle(config.getGameIdent());
+ _editors = new ParamEditor[gamedef.params.length];
+ for (int ii = 0; ii < _editors.length; ii++) {
+ _editors[ii] = createEditor(ctx, msgs, gamedef.params[ii]);
+ addControl(new JLabel(msgs.get(gamedef.params[ii].getLabel())),
+ (JComponent) _editors[ii]);
+ }
+ }
+
+ // now read our parameters
+ for (int ii = 0; ii < gamedef.params.length; ii++) {
+ _editors[ii].readParameter(gamedef.params[ii], config);
+ }
+ }
+
+ // documentation inherited
+ protected void flushGameConfig ()
+ {
+ super.flushGameConfig();
+
+ EZGameConfig config = (EZGameConfig)_config;
+ GameDefinition gamedef = config.getGameDefinition();
+ for (int ii = 0; ii < gamedef.params.length; ii++) {
+ _editors[ii].writeParameter(gamedef.params[ii], config);
+ }
+ }
+
+ protected ParamEditor createEditor (EZGameContext ctx, MessageBundle msgs, Parameter param)
+ {
+ if (param instanceof AIParameter) {
+ return new AIEditor((AIParameter)param);
+ } else if (param instanceof RangeParameter) {
+ return new RangeEditor((RangeParameter)param);
+ } else if (param instanceof ToggleParameter) {
+ return new ToggleEditor((ToggleParameter)param);
+ } else if (param instanceof ChoiceParameter) {
+ return new ChoiceEditor(msgs, (ChoiceParameter)param);
+ } else if (param instanceof FileParameter) {
+ return new FileEditor(ctx, (FileParameter)param);
+ } else {
+ log.warning("Unknown parameter type! " + param + ".");
+ return null;
+ }
+ }
+
+ /** Provides a uniform interface to our UI components. */
+ protected static interface ParamEditor
+ {
+ public void readParameter (Parameter param, EZGameConfig config);
+ public void writeParameter (Parameter param, EZGameConfig config);
+ }
+
+ protected class RangeEditor extends SimpleSlider implements ParamEditor
+ {
+ public RangeEditor (RangeParameter param)
+ {
+ super(null, param.minimum, param.maximum, param.start);
+ }
+
+ public void readParameter (Parameter param, EZGameConfig config)
+ {
+ setValue((Integer)config.params.get(param.ident));
+ }
+
+ public void writeParameter (Parameter param, EZGameConfig config)
+ {
+ config.params.put(param.ident, getValue());
+ }
+ }
+
+ protected class ToggleEditor extends JPanel implements ParamEditor
+ {
+ public ToggleEditor (ToggleParameter param)
+ {
+ setLayout(new HGroupLayout(HGroupLayout.NONE, HGroupLayout.LEFT));
+ add(_box = new JCheckBox(null, null, param.start));
+ }
+
+ public void readParameter (Parameter param, EZGameConfig config)
+ {
+ _box.setSelected((Boolean)config.params.get(param.ident));
+ }
+
+ public void writeParameter (Parameter param, EZGameConfig config)
+ {
+ config.params.put(param.ident, _box.isSelected());
+ }
+
+ protected JCheckBox _box;
+ }
+
+ protected class ChoiceEditor extends JPanel implements ParamEditor
+ {
+ public ChoiceEditor (MessageBundle msgs, ChoiceParameter param)
+ {
+ setLayout(new HGroupLayout(HGroupLayout.NONE, HGroupLayout.LEFT));
+ Choice[] choices = new Choice[param.choices.length];
+ Choice selection = null;
+ for (int ii = 0; ii < choices.length; ii++) {
+ String choice = param.choices[ii];
+ choices[ii] = new Choice();
+ choices[ii].choice = choice;
+ choices[ii].label = msgs.get(param.getChoiceLabel(ii));
+ if (choice.equals(param.start)) {
+ selection = choices[ii];
+ }
+ }
+ add(_combo = new JComboBox(choices));
+ if (selection != null) {
+ _combo.setSelectedItem(selection);
+ }
+ }
+
+ public void readParameter (Parameter param, EZGameConfig config)
+ {
+ Choice selected = new Choice();
+ selected.choice = (String)config.params.get(param.ident);
+ _combo.setSelectedItem(selected);
+ }
+
+ public void writeParameter (Parameter param, EZGameConfig config)
+ {
+ config.params.put(param.ident, ((Choice)_combo.getSelectedItem()).choice);
+ }
+
+ protected JComboBox _combo;
+ }
+
+ protected static class Choice
+ {
+ public String choice;
+ public String label;
+
+ public String toString () {
+ return label;
+ }
+
+ public boolean equals (Object other) {
+ return (other instanceof Choice) && choice.equals(((Choice) other).choice);
+ }
+ }
+
+ protected class FileEditor extends JPanel
+ implements ParamEditor, ActionListener
+ {
+ public FileEditor (EZGameContext ctx, FileParameter param)
+ {
+ _ctx = ctx;
+ _param = param;
+ setLayout(new HGroupLayout(HGroupLayout.NONE, HGroupLayout.LEFT));
+ String label = ctx.getMessageManager().getBundle(
+ MessageManager.GLOBAL_BUNDLE).get("m.file_unset");
+ add(_show = new JButton(label));
+ _show.addActionListener(this);
+ }
+
+ public void readParameter (Parameter param, EZGameConfig config)
+ {
+ // nothing doing
+ }
+
+ public void writeParameter (Parameter param, EZGameConfig config)
+ {
+ if (_data != null) {
+ config.params.put(param.ident, _data);
+ }
+ }
+
+ public void actionPerformed (ActionEvent event)
+ {
+ if (event.getSource() == _show) {
+ if (_chooser == null) {
+ _chooser = new JFileChooser();
+ }
+
+ int rv = _chooser.showOpenDialog(this);
+ if (rv == JFileChooser.APPROVE_OPTION) {
+ File file = _chooser.getSelectedFile();
+
+ try {
+ if (_param.binary) {
+ _data = IOUtils.toByteArray(new FileInputStream(file));
+ } else {
+ _data = IOUtils.toString(new FileReader(file));
+ }
+ _show.setText(file.getName());
+
+ } catch (IOException ioe) {
+ String msg = MessageBundle.tcompose(
+ "m.file_read_failure", ioe.getMessage());
+ _ctx.getChatDirector().displayFeedback(null, msg);
+ log.warning("Failed to read '" + file + "': " + ioe.getMessage());
+ }
+ }
+ }
+ }
+
+ protected EZGameContext _ctx;
+ protected FileParameter _param;
+ protected JButton _show;
+ protected JFileChooser _chooser;
+ protected Object _data;
+ }
+
+ protected class AIEditor extends SimpleSlider implements ParamEditor
+ {
+ public AIEditor (AIParameter param)
+ {
+ super(null, 0, param.maximum, 0);
+ }
+
+ public void readParameter (Parameter param, EZGameConfig config)
+ {
+ setValue((config.ais == null) ? 0 : config.ais.length);
+ }
+
+ public void writeParameter (Parameter param, EZGameConfig config)
+ {
+ config.ais = new GameAI[getValue()];
+ for (int ii = 0; ii < config.ais.length; ii++) {
+ // TODO: allow specification of difficulty and personality
+ config.ais[ii] = new GameAI(0, 0);
+ }
+ }
+ }
+
+ protected ParamEditor[] _editors;
+}
diff --git a/src/java/com/threerings/ezgame/client/EZGamePanel.java b/src/java/com/threerings/ezgame/client/EZGamePanel.java
index 4644faef..3b8a252f 100644
--- a/src/java/com/threerings/ezgame/client/EZGamePanel.java
+++ b/src/java/com/threerings/ezgame/client/EZGamePanel.java
@@ -38,7 +38,6 @@ import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.util.CrowdContext;
-import com.threerings.ezgame.data.EZGameConfig;
import com.threerings.ezgame.data.EZGameObject;
import com.threerings.ezgame.Game;
@@ -56,16 +55,17 @@ public class EZGamePanel extends JPanel
// add a listener so that we hear about all new children
addContainerListener(this);
- EZGameConfig cfg = (EZGameConfig) ctrl.getPlaceConfig();
- try {
- _gameView = (Component) Class.forName(cfg.gameMedia).newInstance();
- add(_gameView);
- } catch (RuntimeException re) {
- throw re;
+// TODO: sort out if and how EZ games will create their views
+// EZGameConfig cfg = (EZGameConfig) ctrl.getPlaceConfig();
+// try {
+// _gameView = (Component) Class.forName(cfg.gameMedia).newInstance();
+// add(_gameView);
+// } catch (RuntimeException re) {
+// throw re;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+// } catch (Exception e) {
+// throw new RuntimeException(e);
+// }
// TODO: Add a standard chat display?
//addChild(new ChatDisplayBox(ctx));
diff --git a/src/java/com/threerings/ezgame/data/AIParameter.java b/src/java/com/threerings/ezgame/data/AIParameter.java
new file mode 100644
index 00000000..bb6a1286
--- /dev/null
+++ b/src/java/com/threerings/ezgame/data/AIParameter.java
@@ -0,0 +1,49 @@
+//
+// $Id$
+//
+// Vilya library - tools for developing networked games
+// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
+// http://www.threerings.net/code/vilya/
+//
+// 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.ezgame.data;
+
+import com.threerings.util.ActionScript;
+
+/**
+ * Models a parameter that is used to configure AIs.
+ */
+@ActionScript(omit=true)
+public class AIParameter extends Parameter
+{
+ /** Indicates the maximum number of AIs in the game. */
+ public int maximum;
+
+ // TODO: allow specification of difficulty range
+ // TODO: allow specification of personality types
+
+ @Override // documentation inherited
+ public String getLabel ()
+ {
+ return "m.ai_" + ident;
+ }
+
+ @Override // documentation inherited
+ public Object getDefaultValue ()
+ {
+ return 0;
+ }
+}
diff --git a/src/java/com/threerings/ezgame/data/ChoiceParameter.java b/src/java/com/threerings/ezgame/data/ChoiceParameter.java
new file mode 100644
index 00000000..4a8aeddc
--- /dev/null
+++ b/src/java/com/threerings/ezgame/data/ChoiceParameter.java
@@ -0,0 +1,57 @@
+//
+// $Id$
+//
+// Vilya library - tools for developing networked games
+// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
+// http://www.threerings.net/code/vilya/
+//
+// 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.ezgame.data;
+
+import com.threerings.util.ActionScript;
+
+/**
+ * Models a parameter that allows the selection of one of a list of choices (specified as strings).
+ */
+public class ChoiceParameter extends Parameter
+{
+ /** The set of choices available for this parameter. */
+ public String[] choices;
+
+ /** The starting selection. */
+ public String start;
+
+ /**
+ * Returns the translation key for the specified choice.
+ */
+ @ActionScript(omit=true)
+ public String getChoiceLabel (int index)
+ {
+ return "m.choice_" + choices[index];
+ }
+
+ @Override @ActionScript(omit=true) // documentation inherited
+ public String getLabel ()
+ {
+ return "m.choice_" + ident;
+ }
+
+ @Override // documentation inherited
+ public Object getDefaultValue ()
+ {
+ return start;
+ }
+}
diff --git a/src/java/com/threerings/ezgame/data/EZGameConfig.java b/src/java/com/threerings/ezgame/data/EZGameConfig.java
index bb40e48b..cdcdbb65 100644
--- a/src/java/com/threerings/ezgame/data/EZGameConfig.java
+++ b/src/java/com/threerings/ezgame/data/EZGameConfig.java
@@ -21,90 +21,80 @@
package com.threerings.ezgame.data;
-import com.threerings.util.MessageBundle;
-
-import com.threerings.crowd.client.PlaceController;
+import com.threerings.util.StreamableHashMap;
import com.threerings.parlor.game.client.GameConfigurator;
import com.threerings.parlor.game.data.GameConfig;
-import com.threerings.ezgame.client.EZGameController;
+import com.threerings.ezgame.client.EZGameConfigurator;
/**
* A game config for a simple multiplayer game.
*/
public class EZGameConfig extends GameConfig
{
- /** The name of the game. */
- public String name;
+ /** Our configuration parameters. These will be seeded with the defaults from the game
+ * definition and then configured by the player in the lobby. */
+ public StreamableHashMap Clients that use the game configurator will want to instantiate one
- * based on the class returned from the {@link GameConfig} and then
- * initialize it with a call to {@link #init}.
+ * Clients that use the game configurator will want to instantiate one based on the class
+ * returned from the {@link GameConfig} and then initialize it with a call to {@link #init}.
*/
public abstract class GameConfigurator
{
/**
- * Initializes this game configurator, creates its user interface
- * elements and prepares it for display.
+ * Initializes this game configurator, creates its user interface elements and prepares it for
+ * display.
*/
public void init (ParlorContext ctx)
{
@@ -57,8 +55,8 @@ public abstract class GameConfigurator
}
/**
- * Provides this configurator with its configuration. It should set up
- * all of its user interface elements to reflect the configuration.
+ * Provides this configurator with its configuration. It should set up all of its user
+ * interface elements to reflect the configuration.
*/
public void setGameConfig (GameConfig config)
{
@@ -68,8 +66,8 @@ public abstract class GameConfigurator
}
/**
- * Derived classes will likely want to override this method and
- * configure their user interface elements accordingly.
+ * Derived classes will likely want to override this method and configure their user interface
+ * elements accordingly.
*/
protected void gotGameConfig ()
{
@@ -86,10 +84,9 @@ public abstract class GameConfigurator
}
/**
- * Derived classes will want to override this method, flushing values
- * from the user interface to the game config object so that it is
- * properly configured prior to being returned to the {@link
- * #getGameConfig} caller.
+ * Derived classes will want to override this method, flushing values from the user interface
+ * to the game config object so that it is properly configured prior to being returned to the
+ * {@link #getGameConfig} caller.
*/
protected void flushGameConfig ()
{
diff --git a/src/java/com/threerings/parlor/game/client/GameController.java b/src/java/com/threerings/parlor/game/client/GameController.java
index 2d68a1e6..d17c7f22 100644
--- a/src/java/com/threerings/parlor/game/client/GameController.java
+++ b/src/java/com/threerings/parlor/game/client/GameController.java
@@ -40,24 +40,21 @@ import com.threerings.parlor.game.data.GameObject;
import com.threerings.parlor.util.ParlorContext;
/**
- * The game controller manages the flow and control of a game on the
- * client side. This class serves as the root of a hierarchy of controller
- * classes that aim to provide functionality shared between various
- * similar games. The base controller provides functionality for starting
- * and ending the game and for calculating ratings adjustements when a
- * game ends normally. It also handles the basic house keeping like
- * subscription to the game object and dispatch of commands and
- * distributed object events.
+ * The game controller manages the flow and control of a game on the client side. This class serves
+ * as the root of a hierarchy of controller classes that aim to provide functionality shared
+ * between various similar games. The base controller provides functionality for starting and
+ * ending the game and for calculating ratings adjustements when a game ends normally. It also
+ * handles the basic house keeping like subscription to the game object and dispatch of commands
+ * and distributed object events.
*/
public abstract class GameController extends PlaceController
implements AttributeChangeListener
{
/**
- * Initializes this game controller with the game configuration that
- * was established during the match making process. Derived classes
- * may want to override this method to initialize themselves with
- * game-specific configuration parameters but they should be sure to
- * call The game config object is also the mechanism used to instantiate the
- * appropriate game manager and controller. Every game must have an associated
- * game config derived class that overrides {@link #createController} and
- * {@link #getManagerClassName}, returning the appropriate game controller and
- * manager class for that game. Thus the entire chain of events that causes a
- * particular game to be created is the construction of the appropriate game
- * config instance which is provided to the server as part of an invitation or
- * via some other matchmaking mechanism.
+ * The game config object is also the mechanism used to instantiate the appropriate game
+ * manager and controller. Every game must have an associated game config derived class that
+ * overrides {@link #createController} and {@link #getManagerClassName}, returning the appropriate
+ * game controller and manager class for that game. Thus the entire chain of events that causes a
+ * particular game to be created is the construction of the appropriate game config instance which
+ * is provided to the server as part of an invitation or via some other matchmaking mechanism.
*/
public abstract class GameConfig extends PlaceConfig implements Cloneable
{
- /** Game type constant: a game that is started with a list of players,
- * and those are the only players that may play. */
- public static final byte SEATED_GAME = 0;
+ /** Matchmaking type constant: a game that is started with a list of players, and those are the
+ * only players that may play. */
+ public static final int SEATED_GAME = 0;
- /** Game type constant: a game that starts immediately, but only has
- * a certain number of player slots. Users enter the game room, and
- * then choose where to sit. */
- public static final byte SEATED_CONTINUOUS = 1;
+ /** Matchmaking type constant: a game that starts immediately, but only has a certain number of
+ * player slots. Users enter the game room, and then choose where to sit. */
+ public static final int SEATED_CONTINUOUS = 1;
- /** Game type constant: a game that starts immediately, and every
- * user that enters is a player. */
- public static final byte PARTY = 2;
+ /** Matchmaking type constant: a game that starts immediately, and every user that enters is a
+ * player. */
+ public static final int PARTY = 2;
- /** The usernames of the players involved in this game, or an empty
- * array if such information is not needed by this particular game. */
+ /** Maps the matchmaking type codes into strings used in our XML configuration. */
+ public static final String[] TYPE_STRINGS = { "table", "entersit", "party" };
+
+ /** The usernames of the players involved in this game, or an empty array if such information
+ * is not needed by this particular game. */
public Name[] players = new Name[0];
/** Indicates whether or not this game is rated. */
public boolean rated = true;
- /** Configurations for AIs to be used in this game. Slots with real
- * players should be null and slots with AIs should contain
- * configuration for those AIs. A null array indicates no use of AIs
- * at all. */
+ /** Configurations for AIs to be used in this game. Slots with real players should be null and
+ * slots with AIs should contain configuration for those AIs. A null array indicates no use of
+ * AIs at all. */
public GameAI[] ais = new GameAI[0];
/**
- * Get the type of game.
+ * Returns a numeric identifier for this game class. This may be used to track persisent
+ * information on a per-game basis.
*/
- public byte getGameType ()
+ public abstract int getGameId ();
+
+ /**
+ * Returns a string identifier for this game class (e.g. "spades"). This may be used to
+ * identify a message bundle for which to obtain translations for this game configuration and
+ * to look up the name of the game in said bundle.
+ */
+ public abstract String getGameIdent ();
+
+ /**
+ * Returns the matchmaking type of this game: {@link #SEATED_GAME}, etc.
+ */
+ public int getMatchType ()
{
return SEATED_GAME;
}
/**
- * Returns the message bundle identifier for the bundle that should be
- * used to translate the translatable strings used to describe the
- * game config parameters.
+ * Creates a configurator that can be used to create a user interface for configuring this
+ * instance prior to starting the game. If no configuration is necessary, this method should
+ * return null.
*/
- public abstract String getBundleName ();
+ public GameConfigurator createConfigurator ()
+ {
+ return null;
+ }
/**
- * Creates a configurator that can be used to create a user interface
- * for configuring this instance prior to starting the game. If no
- * configuration is necessary, this method should return null.
- */
- public abstract GameConfigurator createConfigurator ();
-
- /**
- * Creates a table configurator for initializing 'table' properties
- * of the game. The default implementation returns null.
+ * Creates a table configurator for initializing 'table' properties of the game. The default
+ * implementation returns null.
*/
public TableConfigurator createTableConfigurator ()
{
@@ -106,27 +113,8 @@ public abstract class GameConfig extends PlaceConfig implements Cloneable
}
/**
- * Returns a translatable label describing this game.
- */
- public String getGameName ()
- {
- // the whole getRatingTypeId(), getGameName(), getBundleName()
- // business should be cleaned up. we should have getGameIdent()
- // and everything should have a default implementation using that
- return "m." + getBundleName();
- }
-
- /**
- * Returns the game rating type, if the system uses such things.
- */
- public byte getRatingTypeId ()
- {
- return (byte)-1;
- }
-
- /**
- * Returns a List of strings that describe the configuration of this
- * game. Default implementation returns an empty list.
+ * Returns a List of strings that describe the configuration of this game. Default
+ * implementation returns an empty list.
*/
public List The game manager extends the place manager because games are
- * implicitly played in a location, the players of the game implicitly
- * bodies in that location.
+ * The game manager extends the place manager because games are implicitly played in a
+ * location, the players of the game implicitly bodies in that location.
*/
public class GameManager extends PlaceManager
implements ParlorCodes, GameCodes
{
/**
- * Returns the configuration object for the game being managed by this
- * manager.
+ * Returns the configuration object for the game being managed by this manager.
*/
public GameConfig getGameConfig ()
{
@@ -81,19 +78,19 @@ public class GameManager extends PlaceManager
/**
* A convenience method for getting the game type.
*/
- public byte getGameType ()
+ public int getMatchType ()
{
- return _gameconfig.getGameType();
+ return _gameconfig.getMatchType();
}
/**
- * Adds the given player to the game at the first available player
- * index. This should only be called before the game is started, and
- * is most likely to be used to add players to party games.
+ * Adds the given player to the game at the first available player index. This should only be
+ * called before the game is started, and is most likely to be used to add players to party
+ * games.
*
* @param player the username of the player to add to this game.
- * @return the player index at which the player was added, or
- * GameController derivation that we use to bootstrap on
+ * the client. */
+ public String controller;
+
+ /** The class name of the GameManager derivation that we use to manage the game on
+ * the server. */
+ public String manager;
+
+ /** The MD5 digest of the game media file. */
+ public String digest;
+
+ /** The configuration of the match-making mechanism. */
+ public MatchConfig match;
+
+ /** Parameters used to configure the game itself. */
+ public Parameter[] params;
+
+ /**
+ * Provides the path to this game's media (a jar file or an SWF).
+ *
+ * @param gameId the unique id of the game provided when this game definition was registered
+ * with the system, or -1 if we're running in test mode.
+ */
+ public abstract String getMediaPath (int gameId);
+
+ /**
+ * Returns true if a single player can play this game (possibly against AI opponents), or if
+ * opponents are needed.
+ */
+ public boolean isSinglePlayerPlayable ()
+ {
+ // maybe it's just single player no problem
+ int minPlayers = 2;
+ if (match != null) {
+ minPlayers = match.getMinimumPlayers();
+ if (minPlayers <= 1) {
+ return true;
+ }
+ }
+
+ // or maybe it has AIs
+ int aiCount = 0;
+ for (Parameter param : params) {
+ if (param instanceof AIParameter) {
+ aiCount = ((AIParameter)param).maximum;
+ }
+ }
+ return (minPlayers - aiCount) <= 1;
+ }
+
+ /** Called when parsing a game definition from XML. */
+ @ActionScript(omit=true)
+ public void setParams (ArrayListsuper.init in such cases.
+ * Initializes this game controller with the game configuration that was established during the
+ * match making process. Derived classes may want to override this method to initialize
+ * themselves with game-specific configuration parameters but they should be sure to call
+ * super.init in such cases.
*
* @param ctx the client context.
* @param config the configuration of the game we are intended to
@@ -65,9 +62,8 @@ public abstract class GameController extends PlaceController
*/
public void init (CrowdContext ctx, PlaceConfig config)
{
- // cast our references before we call super.init() so that when
- // super.init() calls createPlaceView(), we have our casted
- // references already in place
+ // cast our references before we call super.init() so that when super.init() calls
+ // createPlaceView(), we have our casted references already in place
_ctx = (ParlorContext)ctx;
_config = (GameConfig)config;
@@ -75,9 +71,8 @@ public abstract class GameController extends PlaceController
}
/**
- * Adds this controller as a listener to the game object (thus derived
- * classes need not do so) and lets the game manager know that we are
- * now ready to go.
+ * Adds this controller as a listener to the game object (thus derived classes need not do so)
+ * and lets the game manager know that we are now ready to go.
*/
public void willEnterPlace (PlaceObject plobj)
{
@@ -86,27 +81,24 @@ public abstract class GameController extends PlaceController
// obtain a casted reference
_gobj = (GameObject)plobj;
- // if this place object is not our current location we'll need to
- // add it as an auxiliary chat source
+ // if this place object is not our current location we'll need to add it as an auxiliary
+ // chat source
BodyObject bobj = (BodyObject)_ctx.getClient().getClientObject();
if (bobj.location != plobj.getOid()) {
- _ctx.getChatDirector().addAuxiliarySource(
- _gobj, GameCodes.GAME_CHAT_TYPE);
+ _ctx.getChatDirector().addAuxiliarySource(_gobj, GameCodes.GAME_CHAT_TYPE);
}
// and add ourselves as a listener
_gobj.addListener(this);
- // we don't want to claim to be finished until any derived classes
- // that overrode this method have executed, so we'll queue up a
- // runnable here that will let the game manager know that we're
- // ready on the next pass through the distributed event loop
+ // we don't want to claim to be finished until any derived classes that overrode this
+ // method have executed, so we'll queue up a runnable here that will let the game manager
+ // know that we're ready on the next pass through the distributed event loop
Log.info("Entering game " + _gobj.which() + ".");
if (_gobj.getPlayerIndex(bobj.getVisibleName()) != -1) {
_ctx.getClient().getRunQueue().postRunnable(new Runnable() {
public void run () {
- // finally let the game manager know that we're ready
- // to roll
+ // finally let the game manager know that we're ready to roll
playerReady();
}
});
@@ -114,8 +106,7 @@ public abstract class GameController extends PlaceController
}
/**
- * Removes our listener registration from the game object and cleans
- * house.
+ * Removes our listener registration from the game object and cleans house.
*/
public void didLeavePlace (PlaceObject plobj)
{
@@ -131,9 +122,9 @@ public abstract class GameController extends PlaceController
/**
* Convenience method to determine the type of game.
*/
- public byte getGameType ()
+ public int getMatchType ()
{
- return _config.getGameType();
+ return _config.getMatchType();
}
/**
@@ -141,15 +132,13 @@ public abstract class GameController extends PlaceController
*/
public boolean isGameOver ()
{
- boolean gameOver = (_gobj == null) ||
- (_gobj.state != GameObject.IN_PLAY);
+ boolean gameOver = (_gobj == null) || (_gobj.state != GameObject.IN_PLAY);
return (_gameOver || gameOver);
}
/**
- * Sets the client game over override. This is used in situations
- * where we determine that the game is over before the server has
- * informed us of such.
+ * Sets the client game over override. This is used in situations where we determine that the
+ * game is over before the server has informed us of such.
*/
public void setGameOver (boolean gameOver)
{
@@ -157,13 +146,11 @@ public abstract class GameController extends PlaceController
}
/**
- * Calls {@link #gameWillReset}, ends the current game (locally, it
- * does not tell the server to end the game), and waits to receive a
- * reset notification (which is simply an event setting the game state
- * to IN_PLAY even though it's already set to
- * IN_PLAY) from the server which will start up a new
- * game. Derived classes should override {@link #gameWillReset} to
- * perform any game-specific animations.
+ * Calls {@link #gameWillReset}, ends the current game (locally, it does not tell the server to
+ * end the game), and waits to receive a reset notification (which is simply an event setting
+ * the game state to IN_PLAY even though it's already set to IN_PLAY)
+ * from the server which will start up a new game. Derived classes should override {@link
+ * #gameWillReset} to perform any game-specific animations.
*/
public void resetGame ()
{
@@ -183,9 +170,8 @@ public abstract class GameController extends PlaceController
}
/**
- * Handles basic game controller action events. Derived classes should
- * be sure to call super.handleAction for events they
- * don't specifically handle.
+ * Handles basic game controller action events. Derived classes should be sure to call
+ * super.handleAction for events they don't specifically handle.
*/
public boolean handleAction (ActionEvent action)
{
@@ -197,8 +183,7 @@ public abstract class GameController extends PlaceController
*/
public void systemMessage (String bundle, String msg)
{
- _ctx.getChatDirector().displayInfo(
- bundle, msg, GameCodes.GAME_CHAT_TYPE);
+ _ctx.getChatDirector().displayInfo(bundle, msg, GameCodes.GAME_CHAT_TYPE);
}
// documentation inherited
@@ -208,16 +193,16 @@ public abstract class GameController extends PlaceController
if (event.getName().equals(GameObject.STATE)) {
int newState = event.getIntValue();
if (!stateDidChange(newState)) {
- Log.warning("Game transitioned to unknown state " +
- "[gobj=" + _gobj + ", state=" + newState + "].");
+ Log.warning("Game transitioned to unknown state [gobj=" + _gobj +
+ ", state=" + newState + "].");
}
}
}
/**
- * Derived classes can override this method if they add additional game
- * states and should handle transitions to those states, returning true to
- * indicate they were handled and calling super for the normal game states.
+ * Derived classes can override this method if they add additional game states and should
+ * handle transitions to those states, returning true to indicate they were handled and calling
+ * super for the normal game states.
*/
protected boolean stateDidChange (int state)
{
@@ -236,8 +221,8 @@ public abstract class GameController extends PlaceController
}
/**
- * Called after we've entered the game and everything has initialized
- * to notify the server that we, as a player, are ready to play.
+ * Called after we've entered the game and everything has initialized to notify the server that
+ * we, as a player, are ready to play.
*/
protected void playerReady ()
{
@@ -246,9 +231,8 @@ public abstract class GameController extends PlaceController
}
/**
- * Called when the game transitions to the IN_PLAY
- * state. This happens when all of the players have arrived and the
- * server starts the game.
+ * Called when the game transitions to the IN_PLAY state. This happens when all of
+ * the players have arrived and the server starts the game.
*/
protected void gameDidStart ()
{
@@ -269,9 +253,8 @@ public abstract class GameController extends PlaceController
}
/**
- * Called when the game transitions to the GAME_OVER
- * state. This happens when the game reaches some end condition by
- * normal means (is not cancelled or aborted).
+ * Called when the game transitions to the GAME_OVER state. This happens when the
+ * game reaches some end condition by normal means (is not cancelled or aborted).
*/
protected void gameDidEnd ()
{
@@ -297,9 +280,8 @@ public abstract class GameController extends PlaceController
}
/**
- * Called to give derived classes a chance to display animations, send
- * a final packet, or do any other business they care to do when the
- * game is about to reset.
+ * Called to give derived classes a chance to display animations, send a final packet, or do
+ * any other business they care to do when the game is about to reset.
*/
protected void gameWillReset ()
{
@@ -317,12 +299,10 @@ public abstract class GameController extends PlaceController
/** Our game configuration information. */
protected GameConfig _config;
- /** A reference to the game object for the game that we're
- * controlling. */
+ /** A reference to the game object for the game that we're controlling. */
protected GameObject _gobj;
- /** A local flag overriding the game over state for situations where
- * the client knows the game is over before the server has
- * transitioned the game object accordingly. */
+ /** A local flag overriding the game over state for situations where the client knows the game
+ * is over before the server has transitioned the game object accordingly. */
protected boolean _gameOver;
}
diff --git a/src/java/com/threerings/parlor/game/data/GameConfig.java b/src/java/com/threerings/parlor/game/data/GameConfig.java
index 0b4c24b2..a8085041 100644
--- a/src/java/com/threerings/parlor/game/data/GameConfig.java
+++ b/src/java/com/threerings/parlor/game/data/GameConfig.java
@@ -31,74 +31,81 @@ import com.threerings.parlor.client.TableConfigurator;
import com.threerings.parlor.game.client.GameConfigurator;
/**
- * The game config class encapsulates the configuration information for a
- * particular type of game. The hierarchy of game config objects mimics the
- * hierarchy of game managers and controllers. Both the game manager and game
- * controller are provided with the game config object when the game is
+ * The game config class encapsulates the configuration information for a particular type of game.
+ * The hierarchy of game config objects mimics the hierarchy of game managers and controllers. Both
+ * the game manager and game controller are provided with the game config object when the game is
* created.
*
- * -1 if the player could not be added to the game.
+ * @return the player index at which the player was added, or -1 if the player
+ * could not be added to the game.
*/
public int addPlayer (Name player)
{
@@ -108,10 +105,9 @@ public class GameManager extends PlaceManager
// sanity-check the player index
if (pidx == -1) {
- Log.warning("Couldn't find free player index for player " +
- "[game=" + where() + ", player=" + player +
- ", players=" + StringUtil.toString(_gameobj.players) +
- "].");
+ Log.warning("Couldn't find free player index for player [game=" + where() +
+ ", player=" + player +
+ ", players=" + StringUtil.toString(_gameobj.players) + "].");
return -1;
}
@@ -120,9 +116,8 @@ public class GameManager extends PlaceManager
}
/**
- * Adds the given player to the game at the specified player index.
- * This should only be called before the game is started, and is most
- * likely to be used to add players to party games.
+ * Adds the given player to the game at the specified player index. This should only be called
+ * before the game is started, and is most likely to be used to add players to party games.
*
* @param player the username of the player to add to this game.
* @param pidx the player index at which the player is to be added.
@@ -132,34 +127,31 @@ public class GameManager extends PlaceManager
{
// make sure the specified player index is valid
if (pidx < 0 || pidx >= getPlayerSlots()) {
- Log.warning("Attempt to add player at an invalid index " +
- "[game=" + where() + ", player=" + player +
- ", pidx=" + pidx + "].");
+ Log.warning("Attempt to add player at an invalid index [game=" + where() +
+ ", player=" + player + ", pidx=" + pidx + "].");
return false;
}
// make sure the player index is available
if (_gameobj.players[pidx] != null) {
- Log.warning("Attempt to add player at occupied index " +
- "[game=" + where() + ", player=" + player +
- ", pidx=" + pidx + "].");
+ Log.warning("Attempt to add player at occupied index [game=" + where() +
+ ", player=" + player + ", pidx=" + pidx + "].");
return false;
}
- // make sure the player isn't already somehow a part of the game
- // to avoid any potential badness that might ensue if we added
- // them more than once
+ // make sure the player isn't already somehow a part of the game to avoid any potential
+ // badness that might ensue if we added them more than once
if (_gameobj.getPlayerIndex(player) != -1) {
- Log.warning("Attempt to add player to game that they're already " +
- "playing [game=" + where() + ", player=" + player + "].");
+ Log.warning("Attempt to add player to game that they're already playing " +
+ "[game=" + where() + ", player=" + player + "].");
return false;
}
// get the player's body object
BodyObject bobj = CrowdServer.lookupBody(player);
if (bobj == null) {
- Log.warning("Unable to get body object while adding player " +
- "[game=" + where() + ", player=" + player + "].");
+ Log.warning("Unable to get body object while adding player [game=" + where() +
+ ", player=" + player + "].");
return false;
}
@@ -179,9 +171,9 @@ public class GameManager extends PlaceManager
}
/**
- * Removes the given player from the game. This is most likely to be
- * used to allow players involved in a party game to leave the game
- * early-on if they realize they'd rather not play for some reason.
+ * Removes the given player from the game. This is most likely to be used to allow players
+ * involved in a party game to leave the game early-on if they realize they'd rather not play
+ * for some reason.
*
* @param player the username of the player to remove from this game.
* @return true if the player was successfully removed, false if not.
@@ -193,10 +185,9 @@ public class GameManager extends PlaceManager
// sanity-check the player index
if (pidx == -1) {
- Log.warning("Attempt to remove non-player from players list " +
- "[game=" + where() + ", player=" + player +
- ", players=" + StringUtil.toString(_gameobj.players) +
- "].");
+ Log.warning("Attempt to remove non-player from players list [game=" + where() +
+ ", player=" + player +
+ ", players=" + StringUtil.toString(_gameobj.players) + "].");
return false;
}
@@ -221,9 +212,8 @@ public class GameManager extends PlaceManager
}
/**
- * Replaces the player at the specified index and calls {@link
- * #playerWasReplaced} to let derived classes and delegates know
- * what's going on.
+ * Replaces the player at the specified index and calls {@link #playerWasReplaced} to let
+ * derived classes and delegates know what's going on.
*/
public void replacePlayer (final int pidx, final Name player)
{
@@ -236,15 +226,14 @@ public class GameManager extends PlaceManager
// notify our delegates
applyToDelegates(new DelegateOp() {
public void apply (PlaceManagerDelegate delegate) {
- ((GameManagerDelegate)delegate).playerWasReplaced(
- pidx, oplayer, player);
+ ((GameManagerDelegate)delegate).playerWasReplaced(pidx, oplayer, player);
}
});
}
/**
- * Returns the user object for the player with the specified index or
- * null if the player at that index is not online.
+ * Returns the user object for the player with the specified index or null if the player at
+ * that index is not online.
*/
public BodyObject getPlayer (int playerIdx)
{
@@ -259,9 +248,8 @@ public class GameManager extends PlaceManager
}
/**
- * Sets the specified player as an AI with the specified
- * configuration. It is assumed that this will be set soon after the
- * player names for all AIs present in the game. (It should be done
+ * Sets the specified player as an AI with the specified configuration. It is assumed that this
+ * will be set soon after the player names for all AIs present in the game. (It should be done
* before human players start trickling into the game.)
*
* @param pidx the player index of the AI.
@@ -288,8 +276,8 @@ public class GameManager extends PlaceManager
}
/**
- * Returns the name of the player with the specified index or null if
- * no player exists at that index.
+ * Returns the name of the player with the specified index or null if no player exists at that
+ * index.
*/
public Name getPlayerName (int index)
{
@@ -297,8 +285,8 @@ public class GameManager extends PlaceManager
}
/**
- * Returns the player index of the given user in the game, or
- * -1 if the player is not involved in the game.
+ * Returns the player index of the given user in the game, or -1 if the player is
+ * not involved in the game.
*/
public int getPlayerIndex (Name username)
{
@@ -306,14 +294,12 @@ public class GameManager extends PlaceManager
}
/**
- * Get the player index of the specified oid, or -1 if the oid is
- * not a player or is a player that is not presently in the game.
+ * Get the player index of the specified oid, or -1 if the oid is not a player or is a player
+ * that is not presently in the game.
*/
public int getPresentPlayerIndex (int bodyOid)
{
- return (_playerOids == null)
- ? -1
- : IntListUtil.indexOf(_playerOids, bodyOid);
+ return (_playerOids == null) ? -1 : IntListUtil.indexOf(_playerOids, bodyOid);
}
/**
@@ -349,13 +335,11 @@ public class GameManager extends PlaceManager
}
/**
- * Returns whether the player at the specified player index is actively
- * playing the game
+ * Returns whether the player at the specified player index is actively playing the game
*/
public boolean isActivePlayer (int pidx)
{
- return _gameobj.isActivePlayer(pidx) &&
- (getPlayerOid(pidx) > 0 || isAI(pidx));
+ return _gameobj.isActivePlayer(pidx) && (getPlayerOid(pidx) > 0 || isAI(pidx));
}
/**
@@ -377,14 +361,12 @@ public class GameManager extends PlaceManager
/**
* Sends a system message to the players in the game room.
*
- * @param waitForStart if true, the message will not be sent until the
- * game has started.
+ * @param waitForStart if true, the message will not be sent until the game has started.
*/
public void systemMessage (
String msgbundle, String msg, boolean waitForStart)
{
- if (waitForStart &&
- ((_gameobj == null) || (_gameobj.state == GameObject.PRE_GAME))) {
+ if (waitForStart && ((_gameobj == null) || (_gameobj.state == GameObject.PRE_GAME))) {
// queue up the message.
if (_startmsgs == null) {
_startmsgs = new ArrayListsuper.playerWasAdded().
*
* @param player the username of the player added to the game.
@@ -689,22 +652,19 @@ public class GameManager extends PlaceManager
}
/**
- * Called when a player was removed from the game. Derived classes
- * may override this method to perform any game-specific actions they
- * desire, but should be sure to call
+ * Called when a player was removed from the game. Derived classes may override this method to
+ * perform any game-specific actions they desire, but should be sure to call
* super.playerWasRemoved().
*
* @param player the username of the player removed from the game.
- * @param pidx the player index of the player before they were removed
- * from the game.
+ * @param pidx the player index of the player before they were removed from the game.
*/
protected void playerWasRemoved (Name player, int pidx)
{
}
/**
- * Called when a player has been replaced via a call to {@link
- * #replacePlayer}.
+ * Called when a player has been replaced via a call to {@link #replacePlayer}.
*/
protected void playerWasReplaced (int pidx, Name oldPlayer, Name newPlayer)
{
@@ -717,14 +677,12 @@ public class GameManager extends PlaceManager
{
BodyObject user = getPlayer(pidx);
if (user == null) {
- // body object can be null for ai players
- return;
+ return; // body object can be null for ai players
}
DObject place = CrowdServer.omgr.getObject(user.location);
if (place != null) {
- place.postMessage(PLAYER_KNOCKED_OUT,
- new Object[] { new int[] { user.getOid() } });
+ place.postMessage(PLAYER_KNOCKED_OUT, new Object[] { new int[] { user.getOid() } });
}
}
@@ -770,8 +728,8 @@ public class GameManager extends PlaceManager
// set up an initial player status array
_gameobj.setPlayerStatus(new int[getPlayerSlots()]);
- // save off the number of players so that we needn't repeatedly
- // iterate through the player name array server-side unnecessarily
+ // save off the number of players so that we needn't repeatedly iterate through the player
+ // name array server-side unnecessarily
_playerCount = _gameobj.getPlayerCount();
// instantiate a player oid array which we'll fill in later
@@ -780,8 +738,8 @@ public class GameManager extends PlaceManager
// give delegates a chance to do their thing
super.didStartup();
- // let the players of this game know that we're ready to roll (if
- // we have a specific set of players)
+ // let the players of this game know that we're ready to roll (if we have a specific set of
+ // players)
for (int ii = 0; ii < getPlayerSlots(); ii++) {
// skip non-existent players and AIs
if (!_gameobj.isOccupiedPlayer(ii) || isAI(ii)) {
@@ -790,8 +748,7 @@ public class GameManager extends PlaceManager
BodyObject bobj = CrowdServer.lookupBody(_gameobj.players[ii]);
if (bobj == null) {
- Log.warning("Unable to deliver game ready to non-existent " +
- "player [game=" + where() +
+ Log.warning("Unable to deliver game ready to non-existent player [game=" + where() +
", player=" + _gameobj.players[ii] + "].");
continue;
}
@@ -841,22 +798,21 @@ public class GameManager extends PlaceManager
endPlayerGame(pidx);
}
- // then complete the bodyLeft() processing which may result in a call
- // to placeBecameEmpty() which will shut the game down
+ // then complete the bodyLeft() processing which may result in a call to placeBecameEmpty()
+ // which will shut the game down
super.bodyLeft(bodyOid);
}
/**
- * When a game room becomes empty, we cancel the game if it's still in
- * progress and close down the game room.
+ * When a game room becomes empty, we cancel the game if it's still in progress and close down
+ * the game room.
*/
protected void placeBecameEmpty ()
{
// Log.info("Game room empty. Going away. [game=" + where() + "].");
// if we're in play then move to game over
- if (_gameobj.state != GameObject.PRE_GAME &&
- _gameobj.state != GameObject.GAME_OVER &&
+ if (_gameobj.state != GameObject.PRE_GAME && _gameobj.state != GameObject.GAME_OVER &&
_gameobj.state != GameObject.CANCELLED) {
_gameobj.setState(GameObject.GAME_OVER);
// and shutdown directly
@@ -870,23 +826,21 @@ public class GameManager extends PlaceManager
}
/**
- * Called when all players have arrived in the game room. By default,
- * this starts up the game, but a manager may wish to override this
- * and start the game according to different criterion.
+ * Called when all players have arrived in the game room. By default, this starts up the game,
+ * but a manager may wish to override this and start the game according to different criterion.
*/
protected void playersAllHere ()
{
// if we're a seated game and we haven't already started, start.
- if ((getGameType() == GameConfig.SEATED_GAME) && (_gameobj.state == GameObject.PRE_GAME)) {
+ if ((getMatchType() == GameConfig.SEATED_GAME) && (_gameobj.state == GameObject.PRE_GAME)) {
startGame();
}
}
/**
- * Called after the no-show delay has expired following the delivery
- * of notifications to all players that the game is ready.
- * Note: this is not called for party games. Those games have
- * a human who decides when to start the game.
+ * Called after the no-show delay has expired following the delivery of notifications to all
+ * players that the game is ready. Note: this is not called for party games. Those
+ * games have a human who decides when to start the game.
*/
protected void checkForNoShows ()
{
@@ -914,14 +868,13 @@ public class GameManager extends PlaceManager
}
/**
- * This is called when some, but not all, players failed to show up
- * for a game. The default implementation simply cancels the game.
+ * This is called when some, but not all, players failed to show up for a game. The default
+ * implementation simply cancels the game.
*/
protected void handlePartialNoShow ()
{
- // mark the no-show players; this will cause allPlayersReady() to
- // think that everyone has arrived, but still allow us to tell who
- // has not shown up in gameDidStart()
+ // mark the no-show players; this will cause allPlayersReady() to think that everyone has
+ // arrived, but still allow us to tell who has not shown up in gameDidStart()
int humansHere = 0;
for (int ii = 0; ii < _playerOids.length; ii++) {
if (_playerOids[ii] == 0) {
@@ -938,9 +891,8 @@ public class GameManager extends PlaceManager
cancelGame();
} else {
- // go ahead and report that everyone is ready (which will start the
- // game); gameDidStart() will take care of giving the boot to
- // anyone who isn't around
+ // go ahead and report that everyone is ready (which will start the game);
+ // gameDidStart() will take care of giving the boot to anyone who isn't around
Log.info("Forcing start of partial no-show game [game=" + where() +
", poids=" + StringUtil.toString(_playerOids) + "].");
playersAllHere();
@@ -948,8 +900,8 @@ public class GameManager extends PlaceManager
}
/**
- * @return true if we should start the game even without any humans.
- * Default implementation always returns false.
+ * @return true if we should start the game even without any humans. Default implementation
+ * always returns false.
*/
protected boolean startWithoutHumans ()
{
@@ -957,11 +909,9 @@ public class GameManager extends PlaceManager
}
/**
- * Called when the game is about to start, but before the game start
- * notification has been delivered to the players. Derived classes
- * should override this if they need to perform some pre-start
- * activities, but should be sure to call
- * super.gameWillStart().
+ * Called when the game is about to start, but before the game start notification has been
+ * delivered to the players. Derived classes should override this if they need to perform some
+ * pre-start activities, but should be sure to call super.gameWillStart().
*/
protected void gameWillStart ()
{
@@ -977,8 +927,8 @@ public class GameManager extends PlaceManager
}
/**
- * Called when the game state changes. This happens after the attribute
- * change event has propagated.
+ * Called when the game state changes. This happens after the attribute change event has
+ * propagated.
*
* @param state the new game state.
* @param oldState the previous game state.
@@ -991,8 +941,8 @@ public class GameManager extends PlaceManager
break;
case GameObject.GAME_OVER:
- // we do some jiggery pokery to allow derived game objects to have
- // different notions of what it means to be in play
+ // we do some jiggery pokery to allow derived game objects to have different notions of
+ // what it means to be in play
_gameobj.state = oldState;
boolean wasInPlay = _gameobj.isInPlay();
_gameobj.state = state;
@@ -1016,11 +966,10 @@ public class GameManager extends PlaceManager
}
/**
- * Called after the game start notification was dispatched. Derived
- * classes can override this to put whatever wheels they might need
- * into motion now that the game is started (if anything other than
- * transitioning the game to {@link GameObject#IN_PLAY} is necessary),
- * but should be sure to call super.gameDidStart().
+ * Called after the game start notification was dispatched. Derived classes can override this
+ * to put whatever wheels they might need into motion now that the game is started (if anything
+ * other than transitioning the game to {@link GameObject#IN_PLAY} is necessary), but should be
+ * sure to call super.gameDidStart().
*/
protected void gameDidStart ()
{
@@ -1034,8 +983,7 @@ public class GameManager extends PlaceManager
// inform the players of any pending messages.
if (_startmsgs != null) {
for (Tuplesuper.gameWillEnd().
+ * Called when the game is about to end, but before the game end notification has been
+ * delivered to the players. Derived classes should override this if they need to perform some
+ * pre-end activities, but should be sure to call super.gameWillEnd().
*/
protected void gameWillEnd ()
{
@@ -1152,9 +1092,8 @@ public class GameManager extends PlaceManager
}
/**
- * Called after the game has transitioned to the {@link
- * GameObject#GAME_OVER} state. Derived classes should override this
- * to perform any post-game activities, but should be sure to call
+ * Called after the game has transitioned to the {@link GameObject#GAME_OVER} state. Derived
+ * classes should override this to perform any post-game activities, but should be sure to call
* super.gameDidEnd().
*/
protected void gameDidEnd ()
@@ -1181,15 +1120,13 @@ public class GameManager extends PlaceManager
}
/**
- * Called to let the manager know that the game was cancelled (and may be
- * about to be shutdown if there's no one in the room). In the base
- * framework a game will only be canceled if no one shows up, so {@link
- * #gameWillStart}, etc. will never have been called and thus {@link
- * #gameWillEnd}, etc. will not be called. However, if a game chooses to
- * cancel itself for whatever reason, no effort will be made to call {@link
- * #endGame} and the game ending call backs so that game can override this
- * method to do anything it needs. Note that {@link #didShutdown} will be
- * called in every case and that's generally the best place to free
+ * Called to let the manager know that the game was cancelled (and may be about to be shutdown
+ * if there's no one in the room). In the base framework a game will only be canceled if no one
+ * shows up, so {@link #gameWillStart}, etc. will never have been called and thus {@link
+ * #gameWillEnd}, etc. will not be called. However, if a game chooses to cancel itself for
+ * whatever reason, no effort will be made to call {@link #endGame} and the game ending call
+ * backs so that game can override this method to do anything it needs. Note that {@link
+ * #didShutdown} will be called in every case and that's generally the best place to free
* resources so this method may not be needed.
*/
protected void gameWasCancelled ()
@@ -1198,8 +1135,7 @@ public class GameManager extends PlaceManager
}
/**
- * Report winner and loser oids to each room that any of the
- * winners/losers is in.
+ * Report winner and loser oids to each room that any of the winners/losers is in.
*/
protected void reportWinnersAndLosers ()
{
@@ -1218,8 +1154,7 @@ public class GameManager extends PlaceManager
}
}
- Object[] args =
- new Object[] { winners.toIntArray(), losers.toIntArray() };
+ Object[] args = new Object[] { winners.toIntArray(), losers.toIntArray() };
// now send a message event to each room
for (int ii=0, nn = places.size(); ii < nn; ii++) {
@@ -1231,10 +1166,9 @@ public class GameManager extends PlaceManager
}
/**
- * Called when the game is about to reset, but before the board has
- * been re-initialized or any other clearing out of game data has
- * taken place. Derived classes should override this if they need to
- * perform some pre-reset activities.
+ * Called when the game is about to reset, but before the board has been re-initialized or any
+ * other clearing out of game data has taken place. Derived classes should override this if
+ * they need to perform some pre-reset activities.
*/
protected void gameWillReset ()
{
@@ -1250,8 +1184,8 @@ public class GameManager extends PlaceManager
}
/**
- * Gives game managers an opportunity to perform periodic processing
- * that is not driven by events generated by the player.
+ * Gives game managers an opportunity to perform periodic processing that is not driven by
+ * events generated by the player.
*/
protected void tick (long tickStamp)
{
@@ -1259,8 +1193,7 @@ public class GameManager extends PlaceManager
}
/**
- * Called periodically to call {@link #tick} on all registered game
- * managers.
+ * Called periodically to call {@link #tick} on all registered game managers.
*/
protected static void tickAllGames ()
{
@@ -1271,8 +1204,7 @@ public class GameManager extends PlaceManager
try {
gmgr.tick(now);
} catch (Exception e) {
- Log.warning(
- "Game manager choked during tick [gmgr=" + gmgr + "].");
+ Log.warning("Game manager choked during tick [gmgr=" + gmgr + "].");
Log.logStackTrace(e);
}
}
@@ -1298,12 +1230,11 @@ public class GameManager extends PlaceManager
}
/** Listens for game state changes. */
- protected AttributeChangeListener _stateListener =
- new AttributeChangeListener() {
+ protected AttributeChangeListener _stateListener = new AttributeChangeListener() {
public void attributeChanged (AttributeChangedEvent event) {
if (event.getName().equals(GameObject.STATE)) {
stateDidChange(_committedState = event.getIntValue(),
- ((Integer)event.getOldValue()).intValue());
+ ((Integer)event.getOldValue()).intValue());
}
}
};
@@ -1320,19 +1251,17 @@ public class GameManager extends PlaceManager
/** The oids of our player and AI body objects. */
protected int[] _playerOids;
- /** If AIs are present, contains their configuration, or null at human
- * player indexes. */
+ /** If AIs are present, contains their configuration, or null at human player indexes. */
protected GameAI[] _AIs;
- /** If non-null, contains bundles and messages that should be sent as
- * system messages once the game has started. */
+ /** If non-null, contains bundles and messages that should be sent as system messages once the
+ * game has started. */
protected ArrayList