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.
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.
"""
@ -180,6 +188,19 @@ class FSM(DirectObject):
# functions will already have been called.
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):
# Returns the current state if we are in a state now, or the
# 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.name, request, str(args)[1:]))
if not self.state:
error = "requested %s while FSM is in transition from %s to %s." % (request, self.oldState, self.newState)
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)
filter = self.getCurrentFilter()
result = filter(request, args)
if result:
if isinstance(result, types.StringTypes):
# If the return value is a string, it's just the name
@ -439,8 +452,11 @@ class FSM(DirectObject):
self.state = None
try:
self.__callExitFunc(self.oldState)
self.__callEnterFunc(self.newState, *args)
if not self.__callFromToFunc(self.oldState, self.newState, *args):
self.__callExitFunc(self.oldState)
self.__callEnterFunc(self.newState, *args)
pass
pass
except:
# If we got an exception during the enter or exit methods,
# go directly to state "InternalError" and raise up the
@ -476,6 +492,17 @@ class FSM(DirectObject):
func = self.defaultEnter
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):
# Calls the appropriate exit function when leaving a
# state, if it exists.
@ -501,7 +528,7 @@ class FSM(DirectObject):
if self.state:
str = ('%s FSM:%s in state "%s"' % (className, self.name, self.state))
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
finally:
self.fsmLock.release()