open_toontown_panda3d/direct/src/fsm/State.py

251 lines
7.6 KiB
Python

"""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):
"""State class: """
def __init__(self, name, enterFunc=None, exitFunc=None, transitions=[],
inspectorPos = []):
"""__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)
self.setTransitions(transitions)
self.setInspectorPos(inspectorPos)
self.__FSMList = None
# setters and getters
def getName(self):
"""getName(self)"""
return(self.__name)
def setName(self, stateName):
"""setName(self, string)"""
self.__name = stateName
def getEnterFunc(self):
"""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):
self.redefineFunc(self.__enterFunc, stateEnterFunc, EnterFuncRedefineMap)
self.__enterFunc = stateEnterFunc
def getExitFunc(self):
"""getExitFunc(self)"""
return(self.__exitFunc)
def setExitFunc(self, stateExitFunc):
"""setExitFunc(self, func)"""
self.redefineFunc(self.__exitFunc, stateExitFunc, ExitFuncRedefineMap)
self.__exitFunc = stateExitFunc
def getTransitions(self):
"""getTransitions(self)"""
return(self.__transitions)
def setTransitions(self, stateTransitions):
"""setTransitions(self, string[])"""
self.__transitions = stateTransitions
def addTransition(self, transition):
"""addTransitions(self, string)"""
self.__transitions.append(transition)
def getInspectorPos(self):
"""getInspectorPos(self)"""
return(self.__inspectorPos)
def setInspectorPos(self, inspectorPos):
"""setInspectorPos(self, [x, y])"""
self.__inspectorPos = inspectorPos
# support for HFSMs
def getChildren(self):
"""getChildren(self)
Return the list of child FSMs"""
return(self.__FSMList)
def setChildren(self, FSMList):
"""setChildren(self, FSM[])
Set the children to given list of FSMs"""
self.__FSMList = FSMList
def addChild(self, FSM):
"""addChild(self, FSM)
Add the given FSM to list of child FSMs"""
if (self.__FSMList == None):
self.__FSMList = [FSM]
else:
self.__FSMList.append(FSM)
def removeChild(self, FSM):
"""addChild(self, FSM)
Add the given FSM to list of child FSMs"""
if FSM in self.__FSMList:
self.__FSMList.remove(FSM)
def hasChildren(self):
"""hasChildren(self)
Return true if state has child FSMs"""
return(self.__FSMList != None)
def __enterChildren(self, argList):
"""__enterChildren(self, argList)
Enter all child FSMs"""
if self.hasChildren():
for fsm in self.__FSMList:
# Check to see if the child fsm is already in a state
# if it is, politely request the initial state
if fsm.getCurrentState():
fsm.request((fsm.getInitialState()).getName())
# If it has no current state, I assume this means it
# has never entered the initial state, so enter it
# explicitly
else:
fsm.enterInitialState()
def __exitChildren(self, argList):
"""__exitChildren(self, argList)
Exit all child FSMs"""
if self.hasChildren():
for fsm in self.__FSMList:
fsm.request((fsm.getFinalState()).getName())
# basic State functionality
def enter(self, argList=[]):
"""enter(self)
Call the enter function for this state"""
# enter child FSMs first. It is assumed these have a start
# state that is safe to enter
self.__enterChildren(argList)
if (self.__enterFunc != None):
apply(self.__enterFunc, argList)
def exit(self, argList=[]):
"""exit(self)
Call the exit function for this state"""
# first exit child FSMs
self.__exitChildren(argList)
# call exit function if it exists
if (self.__exitFunc != None):
apply(self.__exitFunc, argList)
def __str__(self):
"""__str__(self)"""
return "State: name = %s, enter = %s, exit = %s, trans = %s, children = %s" %\
(self.__name, self.__enterFunc, self.__exitFunc, self.__transitions, self.__FSMList)