Yet more Parlor progress. Added GameController which manages the flow of

the game on the client side and have started to wire up the DObject stuff.
Whee!


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@366 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2001-10-01 06:19:15 +00:00
parent 23ccfde6c8
commit 1e7b01ad85
6 changed files with 354 additions and 45 deletions
@@ -1,5 +1,5 @@
//
// $Id: GameConfig.java,v 1.1 2001/10/01 02:56:35 mdb Exp $
// $Id: GameConfig.java,v 1.2 2001/10/01 06:19:15 mdb Exp $
package com.threerings.parlor.data;
@@ -12,33 +12,87 @@ import com.threerings.cocktail.cher.io.Streamable;
/**
* 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 the client provides a game config
* object to the game manager at game creation time which is used to set
* the game's configuration options.
* 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.
*
* <p> 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
* #getControllerClass} 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.
*
* <p> A game that has specific configuration needs would extend this
* class (or an appropriate subclass) adding it's configuration
* information, and also overriding {@link #writeTo} and {@link #readFrom}
* to provide code to effect the necessary serialization and
* unserialization of the added fields.
*
* <p> The implementation of the client-side of the game can either use
* the code provided for obtaining configuration parameters from the user,
* or provide its own specialized configuration interface. It need only
* produce a game config object when the configuration process is complete
* and provide that to the server along with the game creation request.
* information and overriding {@link #writeTo} and {@link #readFrom} to
* provide code to serialize and unserialize the additional fields.
*/
public class GameConfig implements Streamable
public abstract class GameConfig implements Streamable
{
/** Indicates whether or not this game is rated. */
public boolean rated = false;
/**
* Returns the class that should be used to create a controller for
* this game. The controller class must derive from {@link
* com.threerings.parlor.client.GameController}.
*/
public abstract Class getControllerClass ();
/**
* Returns the name of the class that should be used to create a
* manager for this game. The manager class must derive from {@link
* com.threerings.parlor.server.GameManager}. <em>Note:</em> this
* method differs from {@link #getControllerClass} because we want to
* avoid compile time linkage of the game config object (which is used
* on the client) to server code. This allows a code optimizer (DashO
* Pro, for example) to remove the server code from the client,
* knowing that it is never used.
*/
public abstract String getManagerClassName ();
// documentation inherited
public void writeTo (DataOutputStream out)
throws IOException
{
out.writeBoolean(rated);
}
// documentation inherited
public void readFrom (DataInputStream in)
throws IOException
{
rated = in.readBoolean();
}
/**
* Generates a string representation of this object by calling the
* overridable {@link #toString(StringBuffer)} which builds up the
* string in a manner friendly to derived classes.
*/
public String toString ()
{
StringBuffer buf = new StringBuffer();
buf.append("[");
toString(buf);
buf.append("]");
return buf.toString();
}
/**
* An extensible mechanism for generating a string representation of
* this object. Derived classes should override this method, calling
* super and then appending their own data to the supplied string
* buffer. The regular {@link #toString} function will call this
* derived function to generate its string.
*/
protected void toString (StringBuffer buf)
{
buf.append("type=").append(getClass().getName());
buf.append("rated=").append(rated);
}
}
@@ -0,0 +1,141 @@
//
// $Id: GameController.java,v 1.1 2001/10/01 06:19:15 mdb Exp $
package com.threerings.parlor.client;
import java.awt.event.ActionEvent;
import com.samskivert.swing.Controller;
import com.threerings.cocktail.cher.dobj.*;
import com.threerings.parlor.Log;
import com.threerings.parlor.data.GameConfig;
import com.threerings.parlor.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.
*/
public class GameController extends Controller implements Subscriber
{
/**
* 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 <code>super.init</code> in such cases.
*
* @param gameOid the object id of the game object for the game we are
* intended to control.
* @param config the configuration of the game we are intended to
* control.
*/
public void init (ParlorContext ctx, int gameOid, GameConfig config)
{
// keep a reference to our context
_ctx = ctx;
// subscribe to the game object
_ctx.getDObjectManager().subscribeToObject(gameOid, this);
// keep the config around for later
_config = config;
}
/**
* Handles basic game controller action events. Derived classes should
* be sure to call <code>super.handleAction</code> for events they
* don't specifically handle.
*/
public boolean handleAction (ActionEvent action)
{
return false;
}
// documentation inherited
public void objectAvailable (DObject object)
{
// keep a reference around to the game object
_gobj = (GameObject)object;
}
// documentation inherited
public void requestFailed (int oid, ObjectAccessException cause)
{
Log.warning("Unable to subscribe to game object!? [oid=" + oid +
", cause=" + cause + "].");
}
// documentation inherited
public boolean handleEvent (DEvent event, DObject target)
{
if (event instanceof AttributeChangedEvent) {
AttributeChangedEvent ace = (AttributeChangedEvent)event;
// deal with game state changes
if (ace.getName().equals(GameObject.STATE)) {
switch (ace.getIntValue()) {
case GameObject.IN_PLAY:
gameDidStart();
break;
case GameObject.GAME_OVER:
gameDidEnd();
break;
case GameObject.CANCELLED:
gameWasCancelled();
break;
default:
Log.warning("Game transitioned to unknown state " +
"[gobj=" + _gobj +
", state=" + ace.getIntValue() + "].");
break;
}
}
}
return true;
}
/**
* Called when the game transitions to the <code>IN_PLAY</code>
* state. This happens when all of the players have arrived and the
* server starts the game.
*/
protected void gameDidStart ()
{
}
/**
* Called when the game transitions to the <code>GAME_OVER</code>
* state. This happens when the game reaches some end condition by
* normal means (is not cancelled or aborted).
*/
protected void gameDidEnd ()
{
}
/**
* Called when the game was cancelled for some reason.
*/
protected void gameWasCancelled ()
{
}
/** A reference to the active parlor context. */
protected ParlorContext _ctx;
/** Our game configuration information. */
protected GameConfig _config;
/** A reference to the game object for the game that we're
* controlling. */
protected GameObject _gobj;
}
@@ -1,5 +1,5 @@
//
// $Id: GameObject.dobj,v 1.1 2001/10/01 02:56:35 mdb Exp $
// $Id: GameObject.dobj,v 1.2 2001/10/01 06:19:15 mdb Exp $
package com.threerings.parlor.data;
@@ -17,6 +17,43 @@ import com.threerings.cocktail.party.data.PlaceObject;
*/
public class GameObject extends PlaceObject
{
/** The field name of the <code>state</code> field. */
public static final String STATE = "state";
/** The field name of the <code>isRated</code> field. */
public static final String IS_RATED = "isRated";
/** A game state constant indicating that the game has not yet started
* and is still awaiting the arrival of all of the players. */
public static final int AWAITING_PLAYERS = 0;
/** A game state constant indicating that the game is in play. */
public static final int IN_PLAY = 1;
/** A game state constant indicating that the game ended normally. */
public static final int GAME_OVER = 2;
/** A game state constant indicating that the game was cancelled. */
public static final int CANCELLED = 3;
/** The game state, one of {@link #AWAITING_PLAYERS}, {@link #IN_PLAY},
* {@link #GAME_OVER}, or {@link #CANCELLED}. */
public int state;
/** Indicates whether or not this game is rated. */
public boolean isRated;
/** Requests that the <code>state</code> field be set to the specified
* value. */
public void setState (int state)
{
requestAttributeChange(STATE, new Integer(state));
}
/** Requests that the <code>isRated</code> field be set to the
* specified value. */
public void setIsRated (boolean isRated)
{
requestAttributeChange(IS_RATED, new Boolean(isRated));
}
}