2
0
Эх сурвалжийг харах

allow extra args to enter function, don't pass oldState, newState but store them instead

David Rose 21 жил өмнө
parent
commit
bbea3902db

+ 29 - 20
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__()

+ 37 - 37
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 "<stdin>", 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')
 ## >>>