From 4d91590a26569f7764a9aa31652fe2918cb8e294 Mon Sep 17 00:00:00 2001 From: Josh Wilson Date: Wed, 26 May 2010 21:38:14 +0000 Subject: [PATCH] adding ability to define specialized behavior for particular transitions --- direct/src/fsm/FSM.py | 53 ++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/direct/src/fsm/FSM.py b/direct/src/fsm/FSM.py index c4968c128b..bcdbfcf987 100644 --- a/direct/src/fsm/FSM.py +++ b/direct/src/fsm/FSM.py @@ -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 fromTo() + 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 and enter + 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()