diff --git a/direct/src/fsm/FSM.py b/direct/src/fsm/FSM.py index 4d6ccb9aed..0b68145c3a 100644 --- a/direct/src/fsm/FSM.py +++ b/direct/src/fsm/FSM.py @@ -7,7 +7,6 @@ class FSM(DirectObject): # create FSM DirectNotify category notify = directNotify.newCategory("FSM") - #notify.setDebug(1) # special methods diff --git a/direct/src/fsm/State.py b/direct/src/fsm/State.py index a0f1062b77..3c31612904 100644 --- a/direct/src/fsm/State.py +++ b/direct/src/fsm/State.py @@ -2,6 +2,69 @@ """State module: contains State class""" from DirectObject import * +import types + +# This gets set by a dconfig variable in ShowBase.py +# We cannot put a dconfig in here because FSM is not +# dependent on Panda +FsmRedefine = 0 + +# Map function pointers back into states so the Finder +# can find a function and swap a newly redefined function +# back into the original state +# The map is keyed off function pointers which map to +# a list of states that have that function pointer defined +# as their enter function (or exit function as the case may be) +EnterFuncRedefineMap = {} +ExitFuncRedefineMap = {} + + +def redefineEnterFunc(oldMethod, newFunction): + import new + if not FsmRedefine: + return + for method in EnterFuncRedefineMap.keys(): + if (type(method) == types.MethodType): + function = method.im_func + else: + function = method + #print ('function: ' + `function` + '\n' + + # 'method: ' + `method` + '\n' + + # 'oldMethod: ' + `oldMethod` + '\n' + + # 'newFunction: ' + `newFunction` + '\n') + if (function == oldMethod): + newMethod = new.instancemethod(newFunction, + method.im_self, + method.im_class) + stateList = EnterFuncRedefineMap[method] + for state in stateList: + state.setEnterFunc(newMethod) + return 1 + return 0 + + +def redefineExitFunc(oldMethod, newFunction): + import new + if not FsmRedefine: + return + for method in ExitFuncRedefineMap.keys(): + if (type(method) == types.MethodType): + function = method.im_func + else: + function = method + #print ('function: ' + `function` + '\n' + + # 'method: ' + `method` + '\n' + + # 'oldMethod: ' + `oldMethod` + '\n' + + # 'newFunction: ' + `newFunction` + '\n') + if (function == oldMethod): + newMethod = new.instancemethod(newFunction, + method.im_self, + method.im_class) + stateList = ExitFuncRedefineMap[method] + for state in stateList: + state.setExitFunc(newMethod) + return 1 + return 0 class State(DirectObject): @@ -13,6 +76,9 @@ class State(DirectObject): """__init__(self, string, func, func, string[], inspectorPos = []) State constructor: takes name, enter func, exit func, and a list of states it can transition to.""" + self.__enterFunc = None + self.__exitFunc = None + self.setName(name) self.setEnterFunc(enterFunc) self.setExitFunc(exitFunc) @@ -35,8 +101,25 @@ class State(DirectObject): """getEnterFunc(self)""" return(self.__enterFunc) + def redefineFunc(self, oldMethod, newMethod, map): + if not FsmRedefine: + return + if map.has_key(oldMethod): + # Get the list of states for the old function + stateList = map[oldMethod] + # Remove this state from that list of states + stateList.remove(self) + # If the stateList is now empty, remove this entry altogether + if not stateList: + del(map[oldMethod]) + # Now add the new function, creating a starter state list + # if there is not one already + stateList = map.get(newMethod, []) + stateList.append(self) + map[newMethod] = stateList + def setEnterFunc(self, stateEnterFunc): - """setEnterFunc(self, func)""" + self.redefineFunc(self.__enterFunc, stateEnterFunc, EnterFuncRedefineMap) self.__enterFunc = stateEnterFunc def getExitFunc(self): @@ -45,6 +128,7 @@ class State(DirectObject): def setExitFunc(self, stateExitFunc): """setExitFunc(self, func)""" + self.redefineFunc(self.__exitFunc, stateExitFunc, ExitFuncRedefineMap) self.__exitFunc = stateExitFunc def getTransitions(self): diff --git a/direct/src/showbase/Finder.py b/direct/src/showbase/Finder.py index 53fb1c7f19..db6e928562 100644 --- a/direct/src/showbase/Finder.py +++ b/direct/src/showbase/Finder.py @@ -132,6 +132,7 @@ def copyFuncs(fromClass, toClass): oldFunc = toClass.__dict__[key] replaceMessengerFunc(oldFunc, newFunc) replaceTaskMgrFunc(oldFunc, newFunc) + replaceStateFunc(oldFunc, newFunc) toClass.__dict__[key] = newFunc def replaceMessengerFunc(oldFunc, newFunc): @@ -143,3 +144,13 @@ def replaceTaskMgrFunc(oldFunc, newFunc): res = taskMgr.replaceMethod(oldFunc, newFunc) if res: print ('replaced taskMgr function: ' + newFunc.__name__) + +def replaceStateFunc(oldFunc, newFunc): + import State + res = State.redefineEnterFunc(oldFunc, newFunc) + if res: + print ('replaced state enter function: ' + newFunc.__name__) + res = State.redefineExitFunc(oldFunc, newFunc) + if res: + print ('replaced state exit function: ' + newFunc.__name__) + diff --git a/direct/src/showbase/ShowBase.py b/direct/src/showbase/ShowBase.py index 405b751489..599a29df56 100644 --- a/direct/src/showbase/ShowBase.py +++ b/direct/src/showbase/ShowBase.py @@ -19,6 +19,7 @@ import Transitions import Loader import time import FSM +import State globalClock = ClockObject.ClockObject.getGlobalClock() @@ -38,9 +39,13 @@ class ShowBase: self.wantStats = self.config.GetBool('want-stats', 0) taskMgr.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0) + fsmDebug = self.config.GetBool('fsm-debug', 0) FSM.FSM.notify.setDebug(fsmDebug) + fsmRedefine = self.config.GetBool('fsm-redefine', 0) + State.FsmRedefine = fsmRedefine + self.initialState = NodeAttributes() # Set a default "off color" (i.e. use poly color) for color transitions self.initialState.setAttribute(ColorTransition.getClassType(),