From bbea3902db7b3749ffb11958cd47cd6cc3780bac Mon Sep 17 00:00:00 2001 From: David Rose Date: Wed, 26 May 2004 19:17:27 +0000 Subject: [PATCH] allow extra args to enter function, don't pass oldState, newState but store them instead --- direct/src/fsm/FSM.py | 49 ++++++++++++++---------- direct/src/fsm/SampleFSM.py | 74 ++++++++++++++++++------------------- 2 files changed, 66 insertions(+), 57 deletions(-) diff --git a/direct/src/fsm/FSM.py b/direct/src/fsm/FSM.py index 5d76747d18..3614748954 100644 --- a/direct/src/fsm/FSM.py +++ b/direct/src/fsm/FSM.py @@ -22,22 +22,22 @@ class FSM(DirectObject.DirectObject): particular state, define a method named enterState() and/or exitState(), where "State" is the name of the state, e.g.: - def enterRed(self, oldState, newState): + def enterRed(self): ... do stuff ... - def exitRed(self, oldState, newState): + def exitRed(self): ... cleanup stuff ... - def enterYellow(self, oldState, newState): + def enterYellow(self): ... do stuff ... - def exitYellow(self, oldState, newState): + def exitYellow(self): ... cleanup stuff ... - def enterGreen(self, oldState, newState): + def enterGreen(self): ... do stuff ... - def exitGreen(self, oldState, newState): + def exitGreen(self): ... cleanup stuff ... Both functions are supplied the previous state name and the new @@ -134,7 +134,7 @@ class FSM(DirectObject.DirectObject): bypasses the filterState() function, and just calls exitState() followed by enterState().""" - assert(isinstance(newState, types.StringType)) + assert(isinstance(newState, types.StringTypes)) self.__setState(newState) @@ -147,13 +147,14 @@ class FSM(DirectObject.DirectObject): The return value is the same as the return value of filterState() (that is, None if the request does not provoke a - state transition, or the name of the new state otherwise.) + 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), the request is denied and None is returned.""" - assert(isinstance(request, types.StringType)) + assert(isinstance(request, types.StringTypes)) self.notify.debug("%s.request(%s, %s" % (self.name, request, str(args)[1:])) if not self.state: @@ -167,8 +168,13 @@ class FSM(DirectObject.DirectObject): func = self.defaultFilter result = func(request, args) if result: - assert(isinstance(result, types.StringType)) - self.__setState(result) + if isinstance(result, types.StringTypes): + # If the return value is a string, it's just the name + # of the state. Wrap it in a tuple for consistency. + result = (result,) + + # Otherwise, assume it's a (name, *args) tuple + self.__setState(*result) return result @@ -182,14 +188,14 @@ class FSM(DirectObject.DirectObject): if request == 'Off': # We can always go to the "Off" state. - return request + return (request,) + args if self.defaultTransitions is None: # If self.defaultTransitions is None, it means to accept # all requests whose name begins with a capital letter. # These are direct requests to a particular state. if request[0] in string.uppercase: - return request + return (request,) + args else: # If self.defaultTransitions is not None, it is a map of @@ -200,7 +206,7 @@ class FSM(DirectObject.DirectObject): if request in self.defaultTransitions.get(self.state, []): # This transition is listed in the defaultTransitions map; # accept it. - return request + return (request,) + args # If self.defaultTransitions is not None, it is an error # to request a direct state transition (capital letter @@ -222,26 +228,29 @@ class FSM(DirectObject.DirectObject): return self.defaultFilter(request, args) - def __setState(self, newState): + def __setState(self, newState, *args): # Internal function to change unconditionally to the indicated # state. assert(self.state) - oldState = self.state + self.oldState = self.state + self.newState = newState self.state = None - self.__callTransitionFunc("exit" + oldState, oldState, newState) - self.__callTransitionFunc("enter" + newState, oldState, newState) + self.__callTransitionFunc("exit" + self.oldState) + self.__callTransitionFunc("enter" + self.newState, *args) self.state = newState + del self.oldState + del self.newState - def __callTransitionFunc(self, name, oldState, newState): + def __callTransitionFunc(self, name, *args): # Calls the appropriate enter or exit function when # transitioning between states, if it exists. assert(self.state == None) func = getattr(self, name, None) if func: - func(oldState, newState) + func(*args) def __repr__(self): return self.__str__() diff --git a/direct/src/fsm/SampleFSM.py b/direct/src/fsm/SampleFSM.py index a8c0538012..000df0d774 100644 --- a/direct/src/fsm/SampleFSM.py +++ b/direct/src/fsm/SampleFSM.py @@ -15,29 +15,29 @@ class ClassicStyle(FSM.FSM): 'Green' : ['Yellow'], } - def enterRed(self, oldState, newState): - print "enterRed(self, '%s', '%s')" % (oldState, newState) + def enterRed(self): + print "enterRed(self, '%s', '%s')" % (self.oldState, self.newState) - def exitRed(self, oldState, newState): - print "exitRed(self, '%s', '%s')" % (oldState, newState) + def exitRed(self): + print "exitRed(self, '%s', '%s')" % (self.oldState, self.newState) - def enterYellow(self, oldState, newState): - print "enterYellow(self, '%s', '%s')" % (oldState, newState) + def enterYellow(self): + print "enterYellow(self, '%s', '%s')" % (self.oldState, self.newState) - def exitYellow(self, oldState, newState): - print "exitYellow(self, '%s', '%s')" % (oldState, newState) + def exitYellow(self): + print "exitYellow(self, '%s', '%s')" % (self.oldState, self.newState) - def enterGreen(self, oldState, newState): - print "enterGreen(self, '%s', '%s')" % (oldState, newState) + def enterGreen(self): + print "enterGreen(self, '%s', '%s')" % (self.oldState, self.newState) - def exitGreen(self, oldState, newState): - print "exitGreen(self, '%s', '%s')" % (oldState, newState) + def exitGreen(self): + print "exitGreen(self, '%s', '%s')" % (self.oldState, self.newState) class NewStyle(FSM.FSM): - def enterRed(self, oldState, newState): - print "enterRed(self, '%s', '%s')" % (oldState, newState) + def enterRed(self): + print "enterRed(self, '%s', '%s')" % (self.oldState, self.newState) def filterRed(self, request, args): print "filterRed(self, '%s', %s)" % (request, args) @@ -45,11 +45,11 @@ class NewStyle(FSM.FSM): return 'Green' return self.defaultFilter(request, args) - def exitRed(self, oldState, newState): - print "exitRed(self, '%s', '%s')" % (oldState, newState) + def exitRed(self): + print "exitRed(self, '%s', '%s')" % (self.oldState, self.newState) - def enterYellow(self, oldState, newState): - print "enterYellow(self, '%s', '%s')" % (oldState, newState) + def enterYellow(self): + print "enterYellow(self, '%s', '%s')" % (self.oldState, self.newState) def filterYellow(self, request, args): print "filterYellow(self, '%s', %s)" % (request, args) @@ -57,11 +57,11 @@ class NewStyle(FSM.FSM): return 'Red' return self.defaultFilter(request, args) - def exitYellow(self, oldState, newState): - print "exitYellow(self, '%s', '%s')" % (oldState, newState) + def exitYellow(self): + print "exitYellow(self, '%s', '%s')" % (self.oldState, self.newState) - def enterGreen(self, oldState, newState): - print "enterGreen(self, '%s', '%s')" % (oldState, newState) + def enterGreen(self): + print "enterGreen(self, '%s', '%s')" % (self.oldState, self.newState) def filterGreen(self, request, args): print "filterGreen(self, '%s', %s)" % (request, args) @@ -69,8 +69,8 @@ class NewStyle(FSM.FSM): return 'Yellow' return self.defaultFilter(request, args) - def exitGreen(self, oldState, newState): - print "exitGreen(self, '%s', '%s')" % (oldState, newState) + def exitGreen(self): + print "exitGreen(self, '%s', '%s')" % (self.oldState, self.newState) class ToonEyes(FSM.FSM): @@ -91,7 +91,7 @@ class ToonEyes(FSM.FSM): # Unexpected command requests are quietly ignored. return None - def enterOpen(self, oldState, newState): + def enterOpen(self): print "swap in eyes open model" def filterOpen(self, request, args): @@ -105,7 +105,7 @@ class ToonEyes(FSM.FSM): self.request('unblink') return Task.done - def enterClosed(self, oldState, newState): + def enterClosed(self): print "swap in eyes closed model" def filterClosed(self, request, args): @@ -113,10 +113,10 @@ class ToonEyes(FSM.FSM): return 'Open' return self.defaultFilter(request, args) - def enterSurprised(self, oldState, newState): + def enterSurprised(self): print "swap in eyes surprised model" - def enterOff(self, oldState, newState): + def enterOff(self): taskMgr.remove(self.__unblinkName) @@ -127,7 +127,7 @@ class ToonEyes(FSM.FSM): ## >>> foo = SampleFSM.ClassicStyle('foo') ## >>> foo.request('Red') ## enterRed(self, 'Off', 'Red') -## 'Red' +## ('Red',) ## >>> foo.request('Yellow') ## Traceback (most recent call last): ## File "", line 1, in ? @@ -141,7 +141,7 @@ class ToonEyes(FSM.FSM): ## >>> foo.request('Green') ## exitRed(self, 'Red', 'Green') ## enterGreen(self, 'Red', 'Green') -## 'Green' +## ('Green',) ## >>> #### @@ -151,27 +151,27 @@ class ToonEyes(FSM.FSM): ## >>> foo = SampleFSM.NewStyle('foo') ## >>> foo.request('Red') ## enterRed(self, 'Off', 'Red') -## 'Red' +## ('Red',) ## >>> foo.request('advance') ## filterRed(self, 'advance', ()) ## exitRed(self, 'Red', 'Green') ## enterGreen(self, 'Red', 'Green') -## 'Green' +## ('Green',) ## >>> foo.request('advance') ## filterGreen(self, 'advance', ()) ## exitGreen(self, 'Green', 'Yellow') ## enterYellow(self, 'Green', 'Yellow') -## 'Yellow' +## ('Yellow',) ## >>> foo.request('advance') ## filterYellow(self, 'advance', ()) ## exitYellow(self, 'Yellow', 'Red') ## enterRed(self, 'Yellow', 'Red') -## 'Red' +## ('Red',) ## >>> foo.request('advance') ## filterRed(self, 'advance', ()) ## exitRed(self, 'Red', 'Green') ## enterGreen(self, 'Red', 'Green') -## 'Green' +## ('Green',) ## >>> #### @@ -183,11 +183,11 @@ class ToonEyes(FSM.FSM): ## swap in eyes open model ## >>> eyes.request('blink') ## swap in eyes closed model -## 'Closed' +## ('Closed',) ## >>> run() ## swap in eyes open model ## >>> eyes.request('Surprised') ## swap in eyes surprised model -## 'Surprised' +## ('Surprised',) ## >>> eyes.request('blink') ## >>>