# FSM

from direct.fsm.FSM import FSM

A Finite State Machine. This is intended to be the base class of any number of specific machines, which consist of a collection of states and transitions, and rules to switch between states according to arbitrary input data.
The states of an FSM are defined implicitly. Each state is identified by a string, which by convention begins with a capital letter. (Also by convention, strings passed to request that are not state names should begin with a lowercase letter.)
To define specialized behavior when entering or exiting a particular state, define a method named enterState() and/or exitState(), where "State" is the name of the state, e.g.:
def enterRed(self): ... do stuff ...
def exitRed(self): ... cleanup stuff ...
def enterYellow(self): ... do stuff ...
def exitYellow(self): ... cleanup stuff ...
def enterGreen(self): ... do stuff ...
def exitGreen(self): ... cleanup stuff ...
Both functions can access the previous state name as self.oldState, and the new state name we are transitioning to as self.newState. (Of course, in enterRed(), self.newState will always be "Red", and the in exitRed(), self.oldState will always be "Red".)
Both functions are optional. If either function is omitted, the state is still defined, but nothing is done when transitioning into (or out of) the state.
Additionally, you may define a filterState() function for each state. The purpose of this function is to decide what state to transition to next, if any, on receipt of a particular input. The input is always a string and a tuple of optional parameters (which is often empty), and the return value should either be None to do nothing, or the name of the state to transition into. For example:
def filterRed(self, request, args): if request in ['Green']: return (request,) + args return None
def filterYellow(self, request, args): if request in ['Red']: return (request,) + args return None
def filterGreen(self, request, args): if request in ['Yellow']: return (request,) + args return None
As above, the filterState() functions are optional. If any is omitted, the defaultFilter() method is called instead. A standard implementation of defaultFilter() is provided, which may be overridden in a derived class to change the behavior on an unexpected transition.
If self.defaultTransitions is left unassigned, then the standard implementation of defaultFilter() will return None for any lowercase transition name and allow any uppercase transition name (this assumes that an uppercase name is a request to go directly to a particular state by name).
self.state may be queried at any time other than during the handling of the enter() and exit() functions. During these functions, self.state contains the value None (you are not really in any state during the transition). However, during a transition you *can* query the outgoing and incoming states, respectively, via self.oldState and self.newState. At other times, self.state contains the name of the current state.
Initially, the FSM is in state 'Off'. It does not call enterOff() at construction time; it is simply in Off already by convention. If you need to call code in enterOff() to initialize your FSM properly, call it explicitly in the constructor. Similarly, when cleanup() is called or the FSM is destructed, the FSM transitions back to 'Off' by convention. (It does call enterOff() at this point, but does not call exitOff().)
To implement nested hierarchical FSM's, simply create a nested FSM and store it on the class within the appropriate enterState() function, and clean it up within the corresponding exitState() function.
See the code in SampleFSM.py for further examples.

## Inheritance:

FSM: DirectObject
DirectObject:

## Methods of FSM:

__callEnterFunc
__callExitFunc
__del__
__init__
__repr__
__setState
__str__
cleanup
defaultEnter
defaultExit
defaultFilter
demand
filterOff
forceTransition
getCurrentOrNextState
getStateChangeEvent
request
requestNext
requestPrev
setBroadcastStateChanges
setStateArray

## Methods of DirectObject:

__init__
accept
acceptOnce
ignore
ignoreAll
isAccepting
isIgnoring

__callEnterFunc def __callEnterFunc(self, name, *args) Undocumented function.

__callExitFunc def __callExitFunc(self, name) Undocumented function.

__del__ def __del__(self) Undocumented function.

__init__ def __init__(self, name) Undocumented function.

__repr__ def __repr__(self) Undocumented function.

__setState def __setState(self, newState, *args) Undocumented function.

__str__ def __str__(self) Print out something useful about the fsm

cleanup def cleanup(self) Undocumented function.

defaultEnter def defaultEnter(self, *args) This is the default function that is called if there is no enterState() method for a particular state name.

defaultExit def defaultExit(self) This is the default function that is called if there is no exitState() method for a particular state name.

defaultFilter def defaultFilter(self, request, args) This is the function that is called if there is no filterState() method for a particular state name. This default filter function behaves in one of two modes: (1) if self.defaultTransitions is None, allow any request whose name begins with a capital letter, which is assumed to be a direct request to a particular state. This is similar to the old ClassicFSM onUndefTransition=ALLOW, with no explicit state transitions listed. (2) if self.defaultTransitions is not None, allow only those requests explicitly identified in this map. This is similar to the old ClassicFSM onUndefTransition=DISALLOW, with an explicit list of allowed state transitions. Specialized FSM's may wish to redefine this default filter (for instance, to always return the request itself, thus allowing any transition.).

demand def demand(self, request, *args) Requests a state transition, by code that does not expect the request to be denied. If the request is denied, raises a RequestDenied exception. Unlike request(), this method allows a new request to be made while the FSM is currently in transition. In this case, the request is queued up and will be executed when the current transition finishes. Multiple requests will queue up in sequence.

filterOff def filterOff(self, request, args) From the off state, we can always go directly to any other state.

forceTransition def forceTransition(self, request, *args) Changes unconditionally to the indicated state. This bypasses the filterState() function, and just calls exitState() followed by enterState().

getCurrentOrNextState def getCurrentOrNextState(self) Undocumented function.

getStateChangeEvent def getStateChangeEvent(self) Undocumented function.

request def request(self, request, *args) Requests a state transition (or other behavior). The request may be denied by the FSM's filter function. If it is denied, the filter function may either raise an exception (RequestDenied), or it may simply return None, without changing the FSM's state. The request parameter should be a string. The request, along with any additional arguments, is passed to the current filterState() function. If filterState() returns a string, the FSM transitions to that state. The return value is the same as the return value of filterState() (that is, None if the request does not provoke a state transition, otherwise it is a tuple containing the name of the state followed by any optional args.) If the FSM is currently in transition (i.e. in the middle of executing an enterState or exitState function), an AlreadyInTransition exception is raised (but see demand(), which will queue these requests up and apply when the transition is complete).

requestNext def requestNext(self, *args) request the 'next' state in the predefined state array

requestPrev def requestPrev(self, *args) request the 'previous' state in the predefined state array

setBroadcastStateChanges def setBroadcastStateChanges(self, doBroadcast) Undocumented function.

setStateArray def setStateArray(self, stateArray) array of unique states to iterate through

__init__ def __init__(self) Undocumented function.

accept def accept(self, event, method, extraArgs=[]) Undocumented function.

acceptOnce def acceptOnce(self, event, method, extraArgs=[]) Undocumented function.

ignore def ignore(self, event) Undocumented function.

ignoreAll def ignoreAll(self) Undocumented function.

isAccepting def isAccepting(self, event) Undocumented function.

isIgnoring def isIgnoring(self, event) Undocumented function.