Delegation! Since it's clear that extracting services into delegation

classes is only going to become more common, I've gone and created a
comprehensive facility for creating and using delegates in the place
controller and manager as well as the game controller and manager. With
the pattern nicely set, it is also easy to extend to controller/managers
further up the hierarchy that might need to delegate special methods of
their own. Whee!


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@994 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2002-02-13 03:21:28 +00:00
parent 8399c9a9cf
commit a85a6f1394
13 changed files with 531 additions and 106 deletions
@@ -1,5 +1,5 @@
//
// $Id: GameController.java,v 1.8 2001/10/12 00:03:03 mdb Exp $
// $Id: GameController.java,v 1.9 2002/02/13 03:21:28 mdb Exp $
package com.threerings.parlor.game;
@@ -8,7 +8,9 @@ import java.awt.event.ActionEvent;
import com.samskivert.swing.Controller;
import com.threerings.presents.dobj.*;
import com.threerings.crowd.client.PlaceController;
import com.threerings.crowd.client.PlaceControllerDelegate;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.util.CrowdContext;
@@ -26,8 +28,7 @@ import com.threerings.parlor.util.ParlorContext;
* subscription to the game object and dispatch of commands and
* distributed object events.
*/
public abstract class GameController
extends PlaceController
public abstract class GameController extends PlaceController
implements AttributeChangeListener, GameCodes
{
/**
@@ -127,6 +128,12 @@ public abstract class GameController
*/
protected void gameDidStart ()
{
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceControllerDelegate delegate) {
((GameControllerDelegate)delegate).gameDidStart();
}
});
}
/**
@@ -136,6 +143,12 @@ public abstract class GameController
*/
protected void gameDidEnd ()
{
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceControllerDelegate delegate) {
((GameControllerDelegate)delegate).gameDidEnd();
}
});
}
/**
@@ -143,6 +156,12 @@ public abstract class GameController
*/
protected void gameWasCancelled ()
{
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceControllerDelegate delegate) {
((GameControllerDelegate)delegate).gameWasCancelled();
}
});
}
/** A reference to the active parlor context. */
@@ -0,0 +1,47 @@
//
// $Id: GameControllerDelegate.java,v 1.1 2002/02/13 03:21:28 mdb Exp $
package com.threerings.parlor.game;
import com.threerings.crowd.client.PlaceControllerDelegate;
/**
* Extends the {@link PlaceControllerDelegate} mechanism with game
* controller specific methods.
*/
public class GameControllerDelegate extends PlaceControllerDelegate
{
/**
* Provides the delegate with a reference to the game controller for
* which it is delegating.
*/
public GameControllerDelegate (GameController ctrl)
{
super(ctrl);
}
/**
* 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.
*/
public 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).
*/
public void gameDidEnd ()
{
}
/**
* Called when the game was cancelled for some reason.
*/
public void gameWasCancelled ()
{
}
}
@@ -1,5 +1,5 @@
//
// $Id: GameManager.java,v 1.18 2002/02/12 06:57:29 mdb Exp $
// $Id: GameManager.java,v 1.19 2002/02/13 03:21:28 mdb Exp $
package com.threerings.parlor.game;
@@ -9,9 +9,11 @@ import com.threerings.presents.dobj.MessageEvent;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.server.PlaceManager;
import com.threerings.crowd.server.CrowdServer;
import com.threerings.crowd.server.CrowdServer;
import com.threerings.crowd.server.PlaceManagerDelegate;
import com.threerings.parlor.Log;
import com.threerings.parlor.client.ParlorCodes;
@@ -25,8 +27,7 @@ import com.threerings.parlor.client.ParlorCodes;
* implicitly played in a location, the players of the game implicitly
* bodies in that location.
*/
public class GameManager
extends PlaceManager
public class GameManager extends PlaceManager
implements ParlorCodes, GameCodes, AttributeChangeListener
{
// documentation inherited
@@ -158,6 +159,12 @@ public class GameManager
*/
protected void gameWillStart ()
{
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceManagerDelegate delegate) {
((GameManagerDelegate)delegate).gameWillStart();
}
});
}
/**
@@ -168,6 +175,12 @@ public class GameManager
*/
protected void gameDidStart ()
{
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceManagerDelegate delegate) {
((GameManagerDelegate)delegate).gameDidStart();
}
});
}
/**
@@ -195,6 +208,13 @@ public class GameManager
*/
protected void gameDidEnd ()
{
// let our delegates do their business
applyToDelegates(new DelegateOp() {
public void apply (PlaceManagerDelegate delegate) {
((GameManagerDelegate)delegate).gameDidEnd();
}
});
// calculate ratings and all that...
}
@@ -0,0 +1,43 @@
//
// $Id: GameManagerDelegate.java,v 1.1 2002/02/13 03:21:28 mdb Exp $
package com.threerings.parlor.game;
import com.threerings.crowd.server.PlaceManagerDelegate;
/**
* Extends the {@link PlaceManagerDelegate} mechanism with game manager
* specific methods.
*/
public class GameManagerDelegate extends PlaceManagerDelegate
{
/**
* Provides the delegate with a reference to the game manager for
* which it is delegating.
*/
public GameManagerDelegate (GameManager gmgr)
{
super(gmgr);
}
/**
* Called by the game manager when the game is about to start.
*/
public void gameWillStart ()
{
}
/**
* Called by the game manager after the game was started.
*/
public void gameDidStart ()
{
}
/**
* Called by the game manager after the game ended.
*/
public void gameDidEnd ()
{
}
}
@@ -1,5 +1,5 @@
//
// $Id: GameObject.dobj,v 1.7 2002/02/08 23:55:25 mdb Exp $
// $Id: GameObject.dobj,v 1.8 2002/02/13 03:21:28 mdb Exp $
package com.threerings.parlor.game;
@@ -23,13 +23,13 @@ public class GameObject extends PlaceObject
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;
public static final int IN_PLAY = AWAITING_PLAYERS+1;
/** A game state constant indicating that the game ended normally. */
public static final int GAME_OVER = 2;
public static final int GAME_OVER = IN_PLAY+2;
/** A game state constant indicating that the game was cancelled. */
public static final int CANCELLED = 3;
public static final int CANCELLED = GAME_OVER+3;
/** The game state, one of {@link #AWAITING_PLAYERS}, {@link #IN_PLAY},
* {@link #GAME_OVER}, or {@link #CANCELLED}. */
@@ -1,5 +1,5 @@
//
// $Id: GameObject.java,v 1.1 2002/02/08 23:55:25 mdb Exp $
// $Id: GameObject.java,v 1.2 2002/02/13 03:21:28 mdb Exp $
package com.threerings.parlor.game;
@@ -32,13 +32,13 @@ public class GameObject extends PlaceObject
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;
public static final int IN_PLAY = AWAITING_PLAYERS+1;
/** A game state constant indicating that the game ended normally. */
public static final int GAME_OVER = 2;
public static final int GAME_OVER = IN_PLAY+2;
/** A game state constant indicating that the game was cancelled. */
public static final int CANCELLED = 3;
public static final int CANCELLED = GAME_OVER+3;
/** The game state, one of {@link #AWAITING_PLAYERS}, {@link #IN_PLAY},
* {@link #GAME_OVER}, or {@link #CANCELLED}. */
@@ -1,13 +1,15 @@
//
// $Id: TurnGameController.java,v 1.3 2002/02/12 06:57:30 mdb Exp $
// $Id: TurnGameController.java,v 1.4 2002/02/13 03:21:28 mdb Exp $
package com.threerings.parlor.turn;
import com.threerings.parlor.game.GameController;
/**
* Games that wish to make use of the turn game services should have their
* controller implement this interface and create an instance of {@link
* TurnGameControllerDelegate}, calling out to it at the appropriate
* times.
* TurnGameControllerDelegate} which should be passed to {@link
* GameController#addDelegate}.
*/
public interface TurnGameController
{
@@ -1,5 +1,5 @@
//
// $Id: TurnGameControllerDelegate.java,v 1.1 2002/02/12 06:57:30 mdb Exp $
// $Id: TurnGameControllerDelegate.java,v 1.2 2002/02/13 03:21:28 mdb Exp $
package com.threerings.parlor.turn;
@@ -7,9 +7,12 @@ import com.threerings.presents.dobj.AttributeChangedEvent;
import com.threerings.presents.dobj.AttributeChangeListener;
import com.threerings.crowd.data.BodyObject;
import com.threerings.crowd.data.PlaceConfig;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.util.CrowdContext;
import com.threerings.parlor.game.GameController;
import com.threerings.parlor.game.GameControllerDelegate;
import com.threerings.parlor.game.GameObject;
/**
@@ -20,7 +23,7 @@ import com.threerings.parlor.game.GameObject;
* implement the {@link TurnGameController} interface so that it can be
* notified when turn-based game events take place.
*/
public class TurnGameControllerDelegate
public class TurnGameControllerDelegate extends GameControllerDelegate
implements AttributeChangeListener
{
/**
@@ -30,15 +33,10 @@ public class TurnGameControllerDelegate
*/
public TurnGameControllerDelegate (TurnGameController tgctrl)
{
_tgctrl = tgctrl;
}
super((GameController)tgctrl);
/**
* This must be called from {@link GameController#init}.
*/
public void init (CrowdContext ctx)
{
_ctx = ctx;
// keep this around for later
_tgctrl = tgctrl;
}
/**
@@ -52,27 +50,29 @@ public class TurnGameControllerDelegate
_turnGame.getTurnHolder().equals(self.username));
}
/**
* This must be called from {@link GameController#willEnterPlace}.
*/
public void willEnterPlace (GameObject gobj)
// documentation inherited
public void init (CrowdContext ctx, PlaceConfig config)
{
_ctx = ctx;
}
// documentation inherited
public void willEnterPlace (PlaceObject plobj)
{
// get a casted reference to the object
_gameObj = gobj;
_turnGame = (TurnGameObject)gobj;
_gameObj = (GameObject)plobj;
_turnGame = (TurnGameObject)plobj;
_thfield = _turnGame.getTurnHolderFieldName();
// and add ourselves as a listener
gobj.addListener(this);
plobj.addListener(this);
}
/**
* This must be called from {@link GameController#didLeavePlace}.
*/
public void didLeavePlace (GameObject gobj)
// documentation inherited
public void didLeavePlace (PlaceObject plobj)
{
// remove our listenership
gobj.removeListener(this);
plobj.removeListener(this);
// clean up
_turnGame = null;
@@ -87,12 +87,12 @@ public class TurnGameControllerDelegate
}
}
/** A reference to our client context. */
protected CrowdContext _ctx;
/** The turn game controller for whom we are delegating. */
protected TurnGameController _tgctrl;
/** A reference to our client context. */
protected CrowdContext _ctx;
/** A reference to our game object. */
protected GameObject _gameObj;
@@ -1,31 +1,24 @@
//
// $Id: TurnGameManagerDelegate.java,v 1.3 2002/02/12 07:17:33 mdb Exp $
// $Id: TurnGameManagerDelegate.java,v 1.4 2002/02/13 03:21:28 mdb Exp $
package com.threerings.parlor.turn;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.parlor.Log;
import com.threerings.parlor.game.GameManager;
import com.threerings.parlor.game.GameManagerDelegate;
import com.threerings.parlor.util.MathUtil;
/**
* Performs the server-side turn-based game processing for a turn based
* game. Games which wish to make use of the turn services must call the
* following methods on the delegate at the appropriate times:
*
* <pre>
* init()
* gameDidStart()
* startTurn()
* endTurn()
* </pre>
*
* They must also implement the {@link TurnGameManager} interface. If the
* game requires specialized behavior from its delegate, it can extend the
* delegate and override the many methods that have been provided for just
* such a purpose (e.g. {@link #setFirstTurnHolder}, {@link
* #setNextTurnHolder}).
* game. Game managers which wish to make use of the turn services must
* implement {@link TurnGameManager} either create an instance of this
* class, or an instance of a derivation which customizes the behavior,
* either of which would be passed to {@link GameManager#addDelegate} to
* be activated.
*/
public class TurnGameManagerDelegate
public class TurnGameManagerDelegate extends GameManagerDelegate
{
/**
* Constructs a delegate that will manage the turn game state and call
@@ -34,36 +27,10 @@ public class TurnGameManagerDelegate
*/
public TurnGameManagerDelegate (TurnGameManager tgmgr)
{
super((GameManager)tgmgr);
_tgmgr = tgmgr;
}
/**
* This should be called from {@link GameManager#didStartup} to
* initialize the delegate.
*/
public void init (TurnGameObject turnGame)
{
_turnGame = turnGame;
}
/**
* This should be called from {@link GameManager#gameDidStart} to let
* the turn delegate perform start of game processing.
*/
public void gameDidStart ()
{
// grab the players array
_players = _tgmgr.getPlayers();
// figure out who will be first
setFirstTurnHolder();
// and start the first turn if we should apparently do so
if (_turnIdx != -1) {
startTurn();
}
}
/**
* Returns the index of the current turn holder as configured in the
* game object.
@@ -82,17 +49,6 @@ public class TurnGameManagerDelegate
return -1;
}
/**
* This is called to determine whichi player will take the first
* turn. The default implementation chooses a player at random.
*/
protected void setFirstTurnHolder ()
{
// TODO: sort out a better random number generator and make it
// available via the parlor services
_turnIdx = MathUtil.random(_players.length);
}
/**
* Called to start the next turn. It calls {@link
* TurnGameManager#turnWillStart} to allow our owning manager to
@@ -149,6 +105,41 @@ public class TurnGameManagerDelegate
}
}
// documentation inherited
public void didStartup (PlaceObject plobj)
{
_turnGame = (TurnGameObject)plobj;
}
/**
* This should be called from {@link GameManager#gameDidStart} to let
* the turn delegate perform start of game processing.
*/
public void gameDidStart ()
{
// grab the players array
_players = _tgmgr.getPlayers();
// figure out who will be first
setFirstTurnHolder();
// and start the first turn if we should apparently do so
if (_turnIdx != -1) {
startTurn();
}
}
/**
* This is called to determine whichi player will take the first
* turn. The default implementation chooses a player at random.
*/
protected void setFirstTurnHolder ()
{
// TODO: sort out a better random number generator and make it
// available via the parlor services
_turnIdx = MathUtil.random(_players.length);
}
/**
* This is called to determine which player will next hold the turn.
* The default implementation simply rotates through the players in