From: Stefan F. <ste...@we...> - 2012-07-06 03:54:04
|
Below I discuss the per-requisites of the State mechanism. The latter will be covered in a soon-to-follow email. So most likely the only one interested in the bits below will be Erik. Stefan Remark: I changed the term "Move" in Rails1.x to the term "Change" in Rails2.0 to avoid the confusion with an in-game tile move or token move. ChangeStack and ChangeSet are MoveStack and MoveSet in Rails1.x. *** So how do State objects work in Rails internally? Assume a BooleanState variable was created: If the boolean value is changed by e.g. stateVariable.set(true), an object of a Change subclass is created (here a BooleanChange). The change object contains both links to the state and the old and the new variable. The change object then is added to the ChangeStack, which is located inside the StateManager. *** The redesigned ChangeStack: * Changes get collected in ChangeSets, where are two types of ChangeSets: - ActionChangeSet (all Changes associated with an action) - AutoChangeSet (all Changes during automated processing) * ChangeSets can be open=accepting new Changes or closed=raise errors if one tries to add Changes. * The current ChangeSet of the ChangeStack is always open. If the current ChangeSet is closed, a new (Auto)ChangeSet is automatically opened and is the new current ChangeSet of the ChangeStack. Remark: This is different to Rails1.x, for which some State changes could get lost, as there was no open ChangeSet available at the time of processing. * At the start of the game an AutoChangeSet created which is defined the terminal, thus it is not undoable. This collects all changes that precede any player action. * The typical sequence is the following: Player action is processed: ChangeStack.startActionChangeSet(player, action) opens a new ActionChangeSet (and closes the current AutoChangeSet automatically) After processing the action: ChangeStack.closeCurrentChangeSet() closes the current ActionChangeSet (and opens a new AutoChangeSet) Then the games process non-action related changes (e.g. ending the SR, starting a new OR, paying revenue to privates, etc.) all of this gets collected into AutoChangeSet(s). * The major advantage of the separation of changes is that it will allow to link output in the report window and player comments to either a player action or the automated game processing. Currently all output of the game engine is linked to the previous player action, however this is only based on game sequence and not on game logic. * Still undo/redo will always un-execute/re-execute the next player action (including all automated changes). * An internal change is that there are are now two stacks (one for undo, one for redo), this avoids the usage of an index that separates the undo-part from the redo-part if using one stack only. Thus an undo command the top ChangeSet of the undo-stack onto the redo stack and the reverse for redos. The current (open) ChangeSet is stored in a separately as long as it is open, it only gets moved onto the undo stack after its close. Thus all ChangeSets on the undo (and redo) stack are always closed. * Setting up of the ChangeStack: The ChangeStack is automatically setup to full functionality after creating the Root: So Root root = Root.create() will have working ChangeStack inside. If one adds a state now, e.g. BooleanState state = BooleanState.create(root, "example") every change of that state is put on the according ChangeStack. The ChangeStack is unique to the Root item hierarchy, however it is possible to create several roots with each having its own independent ChangeStack. Access to the ChangeStack: From root: root.getStateManager().getChangeStack() From any item: item.getRoot().getStateManager().getChangeStack() * Current state of implementation: The core functionality is working and covered by tests (see ChangeStackTest and ChangeSetTest). |