adding ability to define specialized behavior for particular transitions

This commit is contained in:
Josh Wilson 2010-05-26 21:38:14 +00:00
parent 60e2152767
commit 4d91590a26

View File

@ -121,6 +121,14 @@ class FSM(DirectObject):
function, and clean it up within the corresponding exitState() function, and clean it up within the corresponding exitState()
function. function.
There is a way to define specialized transition behavior between
two particular states. This is done by defining a from<X>To<Y>()
function, where X is the old state and Y is the new state. If this
is defined, it will be run in place of the exit<X> and enter<Y>
functions, so if you want that behavior, you'll have to call them
specifically. Otherwise, you can completely replace that transition's
behavior.
See the code in SampleFSM.py for further examples. See the code in SampleFSM.py for further examples.
""" """
@ -180,6 +188,19 @@ class FSM(DirectObject):
# functions will already have been called. # functions will already have been called.
return 'FSM-%s-%s-stateChange' % (self._serialNum, self.name) return 'FSM-%s-%s-stateChange' % (self._serialNum, self.name)
def getCurrentFilter(self):
if not self.state:
error = "requested %s while FSM is in transition from %s to %s." % (request, self.oldState, self.newState)
raise AlreadyInTransition, error
filter = getattr(self, "filter" + self.state, None)
if not filter:
# If there's no matching filterState() function, call
# defaultFilter() instead.
filter = self.defaultFilter
return filter
def getCurrentOrNextState(self): def getCurrentOrNextState(self):
# Returns the current state if we are in a state now, or the # Returns the current state if we are in a state now, or the
# state we are transitioning into if we are currently within # state we are transitioning into if we are currently within
@ -289,16 +310,8 @@ class FSM(DirectObject):
self.notify.debug("%s.request(%s, %s" % ( self.notify.debug("%s.request(%s, %s" % (
self.name, request, str(args)[1:])) self.name, request, str(args)[1:]))
if not self.state: filter = self.getCurrentFilter()
error = "requested %s while FSM is in transition from %s to %s." % (request, self.oldState, self.newState) result = filter(request, args)
raise AlreadyInTransition, error
func = getattr(self, "filter" + self.state, None)
if not func:
# If there's no matching filterState() function, call
# defaultFilter() instead.
func = self.defaultFilter
result = func(request, args)
if result: if result:
if isinstance(result, types.StringTypes): if isinstance(result, types.StringTypes):
# If the return value is a string, it's just the name # If the return value is a string, it's just the name
@ -439,8 +452,11 @@ class FSM(DirectObject):
self.state = None self.state = None
try: try:
self.__callExitFunc(self.oldState) if not self.__callFromToFunc(self.oldState, self.newState, *args):
self.__callEnterFunc(self.newState, *args) self.__callExitFunc(self.oldState)
self.__callEnterFunc(self.newState, *args)
pass
pass
except: except:
# If we got an exception during the enter or exit methods, # If we got an exception during the enter or exit methods,
# go directly to state "InternalError" and raise up the # go directly to state "InternalError" and raise up the
@ -476,6 +492,17 @@ class FSM(DirectObject):
func = self.defaultEnter func = self.defaultEnter
func(*args) func(*args)
def __callFromToFunc(self, oldState, newState, *args):
# Calls the appropriate fromTo function when transitioning into
# a new state, if it exists.
assert self.state == None and self.oldState == oldState and self.newState == newState
func = getattr(self, "from%sTo%s" % (oldState,newState), None)
if func:
func(*args)
return True
return False
def __callExitFunc(self, name): def __callExitFunc(self, name):
# Calls the appropriate exit function when leaving a # Calls the appropriate exit function when leaving a
# state, if it exists. # state, if it exists.
@ -501,7 +528,7 @@ class FSM(DirectObject):
if self.state: if self.state:
str = ('%s FSM:%s in state "%s"' % (className, self.name, self.state)) str = ('%s FSM:%s in state "%s"' % (className, self.name, self.state))
else: else:
str = ('%s FSM:%s not in any state' % (className, self.name)) str = ('%s FSM:%s in transition from \'%s\' to \'%s\'' % (className, self.name, self.oldState, self.newState))
return str return str
finally: finally:
self.fsmLock.release() self.fsmLock.release()