As I remarked yesterday, player action selection and processing
has now been centralised by passing these through two "Manager" classes,
oen at the UI/client side and one at the back-end/server side.
These activities have also been highly unified by implementing all action
selection
options and executed actions by means of PossibleAction subclass objects.
I think it is a good idea to write down the whole process cycle,
which is what I will try to do below.
Should we ever write a Rails Developer Handbook, this could be one
if its chapters.
For a start, we can take any point in the cycle, so let's choose one.
1. The player who has the turn selects the next action to take
by pressing a button, selecting a menu item, and/or filling in some
value in a UI entry field or a dialog. On program level, this boils down
to picking one entry from an ArrayList<PossibleAction>, and (where
needed) setting all required attributes to further specify that action
(for instance, when laying a tile: the hex location, tile id, and tile
orientation).
The acting player is also added. This work is all done in the classes
that constitute the UI for the current type of round.
2. The selected and completed PossibleAction object is passed to
GameUIManager.processOnServer().
3. GameUIManager.processOnServer() passes this action to
GameManager.process().
See 7 for further actions taken when the latter method has returned
its result.
4. GameManager.process() does some common checks first:
- does the action player really have the turn?
- does the passed object really occur in the previous PossibleAction list?
Then the action is passed to the process() method of the current Round
subclass (StockRound, OperatingRound,etc.), unless it is a (forced) Undo
or a Redo, which are executed here immediately.
See 6 for further actions taken when the round-specific process() method
has returned its result.
5. The current round's process() method does the remaining processing.
This includes:
- complete validation (if invalid, it puts a message in the display buffer
and returns false; but if this occurs, it is a program error -
or someone is trying to crack the game!),
- execution, including all side effects, up to and including round changes.
To start a new round, GameManager.nextRound() is called.
6. GameManager.process() then calls the current (possibly changed!) round's
setPossibleActions() method. This method refills the PossibleAction list.
All possible actions are represented by a specific object.
This includes Undo/ForcedUndo/Redo, but these common actions are added
by GameManager.process() itself.
Finally the result (true=success, false=error) is returned.
7. GameUIManager.processOnServer() continues:
- A report of the player's action is added to the Report Window.
- updateUI() is called to check if the round has changed.
If so, the old round's window is finished and the new round's window
intialised.
8. Also in updateUI(), the updateStatus() method of the (now) current window
is called.
This method prepares the screen for the next player action
by enabling the right menu options and buttons, etc.
This UI updating is based upon the current PossibleActions list
(to which the UI currently has direct access).
9. Back in processOnServer():
- The Undo/Redo menu items are en/disabled as appropriate,
- The current window's processImmediateAction() method is called.
This method executes any forced actions, that must be executed immediately
by a modal dialog (i.e. without waiting for a player action).
The only currently existing example is the par price setting for B&O
(see previous post).
10. Finally, the current round's window displays any error or other
messages (I'll probably move this action to processOnServer() as well).
11. The player gets the turn to select the next action.
The main point of this cycle is that it applies to all types of round,
so several round-specific idiosyncrasies have been removed.
A new interface ActionPerformer is implemented by all UI window classes
to define all methods these windows must implement (including
those that GameUIManager.processOnServer may call).
Erik Vos
|