Browse Source

new search algorithm, replace function intervals, various improvements and speedups

Joe Shochet 19 years ago
parent
commit
405bf80de7
1 changed files with 121 additions and 120 deletions
  1. 121 120
      direct/src/showbase/Finder.py

+ 121 - 120
direct/src/showbase/Finder.py

@@ -1,69 +1,31 @@
-
+import time
 import types
 import types
 import os
 import os
 import new
 import new
-
-def findClassInModule(module, className, visited):
-    # Make sure you have not already visited this module
-    # to prevent recursion
-    if visited.has_key(module):
-        return None
-    # Ok, clear to proceed, add this module to the visited list
-    visited[module] = 1
-    # print ('visiting: ' + `module`)
-
-    # First see if we are in the dict at this level
-    classObj = module.__dict__.get(className)
-    if classObj and ((type(classObj) == types.ClassType) or
-                     (type(classObj) == types.TypeType)):
-        if classObj.__module__ == module.__name__:
-            return [classObj, module.__dict__]
-        else:
-            # print "Must have found a module that imported this class", classObj, module
-            pass
-
-    # Now filter out all the modules and iterate through them
-    moduleList = filter(lambda value: type(value) == types.ModuleType, module.__dict__.values())
-    for moduleObj in moduleList:
-        ret =  findClassInModule(moduleObj, className, visited)
-        # If that recursion found it, return the goodies
-        if ret:
-            return ret
-            
-    # Well, after all that we did not find anything
-    return None
-
-
-# Find a class named className somewhere in this namespace
-def findClass(namespace, className):
-
-    # First see if we are in the namespace
-    classObj = namespace.get(className)
-    # print classObj, type(classObj)
-    if classObj and ((type(classObj) == types.ClassType) or
-                     (type(classObj) == types.TypeType)):
-        return [classObj, namespace]
-    
-    for key in namespace.keys():
-        value = namespace[key]
-        # If we found a class, see if it matches classname
-        # Make sure we do not match "_"
-        if ((key != "_") and ((type(value) == types.ClassType) or
-                              (type(value) == types.TypeType))):
-            if value.__name__ == className:
-                # It does, that was easy!
-                return [value, namespace]
-        # Look in all the modules in this namespace
-        elif (type(value) == types.ModuleType):
-            ret = findClassInModule(value, className, {})
-            # If we found it return the goodies
-            if ret:
-                return ret
-            # Otherwise keep looking
-    # Nope, not in there
+import sys
+
+def findClass(className):
+    """
+    Look in sys.modules dictionary for a module that defines a class
+    with this className.
+    """
+    for moduleName, module in sys.modules.items():
+        # Some modules are None for some reason
+        if module:
+            # print "Searching in ", moduleName
+            classObj = module.__dict__.get(className)
+            # If this modules defines some object called classname and the
+            # object is a class or type definition and that class's module
+            # is the same as the module we are looking in, then we found
+            # the matching class and a good module namespace to redefine
+            # our class in.
+            if (classObj and
+                ((type(classObj) == types.ClassType) or
+                 (type(classObj) == types.TypeType)) and
+                (classObj.__module__ == moduleName)):
+                return [classObj, module.__dict__]
     return None
     return None
 
 
-
 def rebindClass(builtinGlobals, filename):
 def rebindClass(builtinGlobals, filename):
     file = open(filename, 'r')
     file = open(filename, 'r')
     lines = file.readlines()
     lines = file.readlines()
@@ -83,96 +45,135 @@ def rebindClass(builtinGlobals, filename):
                     className = classHeader[:colonLoc]
                     className = classHeader[:colonLoc]
                 else:
                 else:
                     print 'error: className not found'
                     print 'error: className not found'
+                    # Remove that temp file
+                    file.close()
+                    os.remove(filename)
                     return
                     return
             print 'Rebinding class name: ' + className
             print 'Rebinding class name: ' + className
             break
             break
 
 
-    # Store the original real class
-    res = findClass(builtinGlobals, className)
-    if res:
-        realClass, realNameSpace = res
-    else:
-        # print ('Warning: could not find class, defining new class in builtins: ' + className)
-        # Now execute that class def
-        # execfile(filename, builtinGlobals)
-        print ('Warning: Finder could not find class, try importing the file first')
-        # Remove that temp file
+    # Try to find the original class with this class name
+    res = findClass(className)
+
+    if not res:
+        print ('Warning: Finder could not find class')
+        # Remove the temp file we made
         file.close()
         file.close()
         os.remove(filename)
         os.remove(filename)
         return
         return
 
 
-    # Now execute that class def
+    # Store the original real class
+    realClass, realNameSpace = res
+
+    # Now execute that class def in this namespace
     execfile(filename, realNameSpace)
     execfile(filename, realNameSpace)
-    # Remove that temp file
-    file.close()
-    os.remove(filename)
 
 
+    # That execfile should have created a new class obj in that namespace
     tmpClass = realNameSpace[className]
     tmpClass = realNameSpace[className]
 
 
     # Copy the functions that we just redefined into the real class
     # Copy the functions that we just redefined into the real class
     copyFuncs(tmpClass, realClass)
     copyFuncs(tmpClass, realClass)
 
 
-    # Now make sure the original class is in that namespace, not our temp one
+    # Now make sure the original class is in that namespace,
+    # not our temp one from the execfile. This will help us preserve
+    # class variables and other state on the original class.
     realNameSpace[className] = realClass
     realNameSpace[className] = realClass
+    
+    # Remove the temp file we made
+    file.close()
+    os.remove(filename)
 
 
     print ('    Finished rebind')
     print ('    Finished rebind')
 
 
 
 
 def copyFuncs(fromClass, toClass):
 def copyFuncs(fromClass, toClass):
+    replaceFuncList = []
+    newFuncList = []
+    
     # Copy the functions from fromClass into toClass dictionary
     # Copy the functions from fromClass into toClass dictionary
-    for key in fromClass.__dict__.keys():
-        value = fromClass.__dict__[key]
-        if (type(value) == types.FunctionType):
-            newFunc = value
+    for funcName, newFunc in fromClass.__dict__.items():
+        # Filter out for functions
+        if (type(newFunc) == types.FunctionType):
             # See if we already have a function with this name
             # See if we already have a function with this name
-            if toClass.__dict__.has_key(key):
-                # Look in the messenger and taskMgr to see if this
-                # old function pointer is stored there,
-                # and update it to the new function pointer
-                oldFunc = toClass.__dict__[key]
-                replaceMessengerFunc(oldFunc, newFunc)
-                replaceTaskMgrFunc(oldFunc, newFunc)
-                replaceStateFunc(oldFunc, newFunc)
-                replaceTcrFunc(oldFunc, newFunc)
-            # You cannot assign directly to the dict with new style classes
-            # toClass.__dict__[key] = newFunc
-            # Instead we will use setattr
-            setattr(toClass, key, newFunc)
-
-def replaceMessengerFunc(oldFunc, newFunc):
+            oldFunc = toClass.__dict__.get(funcName)
+            if oldFunc:
+                replaceFuncList.append((oldFunc, funcName, newFunc))
+            else:
+                newFuncList.append((funcName, newFunc))
+
+    # Look in the messenger, taskMgr, and other globals that store func
+    # pointers to see if this old function pointer is stored there, and
+    # update it to the new function pointer.
+    replaceMessengerFunc(replaceFuncList)
+    replaceTaskMgrFunc(replaceFuncList)
+    replaceStateFunc(replaceFuncList)
+    replaceCRFunc(replaceFuncList)
+    replaceAIRFunc(replaceFuncList)
+    replaceIvalFunc(replaceFuncList)
+
+    # Now that we've the globals funcs, actually swap the pointers in
+    # the new class to the new functions
+    for oldFunc, funcName, newFunc in replaceFuncList:
+        # print "replacing old func: ", oldFunc, funcName, newFunc
+        setattr(toClass, funcName, newFunc)
+    # Add the brand new functions too
+    for funcName, newFunc in newFuncList:
+        # print "adding new func: ", oldFunc, funcName, newFunc
+        setattr(toClass, funcName, newFunc)
+
+def replaceMessengerFunc(replaceFuncList):
     try:
     try:
         messenger
         messenger
     except:
     except:
         return
         return
-    res = messenger.replaceMethod(oldFunc, newFunc)
-    if res:
-        print 'replaced %d messenger functions: %s' % (res, newFunc.__name__)
+    for oldFunc, funcName, newFunc in replaceFuncList:    
+        res = messenger.replaceMethod(oldFunc, newFunc)
+        if res:
+            print ('replaced %s messenger function(s): %s' % (res, funcName))
 
 
-def replaceTaskMgrFunc(oldFunc, newFunc):
+def replaceTaskMgrFunc(replaceFuncList):
     try:
     try:
         taskMgr
         taskMgr
     except:
     except:
         return
         return
-    res = taskMgr.replaceMethod(oldFunc, newFunc)
-    if res:
-        print ('replaced taskMgr function: ' + newFunc.__name__)
-
-def replaceStateFunc(oldFunc, newFunc):
-    from direct.fsm 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__)
-
-def replaceTcrFunc(oldFunc, newFunc):
+    for oldFunc, funcName, newFunc in replaceFuncList:    
+        if taskMgr.replaceMethod(oldFunc, newFunc):
+            print ('replaced taskMgr function: %s' % funcName)
+
+def replaceStateFunc(replaceFuncList):
+    if not sys.modules.get('direct.fsm.State'):
+        return
+    from direct.fsm.State import State
+    for oldFunc, funcName, newFunc in replaceFuncList:
+        res = State.replaceMethod(oldFunc, newFunc)
+        if res:
+            print ('replaced %s FSM transition function(s): %s' % (res, funcName))
+
+def replaceCRFunc(replaceFuncList):
+    try:
+        base.cr
+    except:
+        return
+    for oldFunc, funcName, newFunc in replaceFuncList:        
+        if base.cr.replaceMethod(oldFunc, newFunc):
+            print ('replaced DistributedObject function: %s' % funcName)
+
+def replaceAIRFunc(replaceFuncList):
     try:
     try:
-        res = base.cr.replaceMethod(oldFunc, newFunc)
+        simbase.air
     except:
     except:
-        try:
-            res = simbase.air.replaceMethod(oldFunc, newFunc)
-        except:
-            res = None
-    if res:
-        print ('replaced DistributedObject function: ' + newFunc.__name__)
+        return
+    for oldFunc, funcName, newFunc in replaceFuncList:        
+        if simbase.air.replaceMethod(oldFunc, newFunc):
+            print ('replaced DistributedObject function: %s' % funcName)
+
+def replaceIvalFunc(replaceFuncList):
+    # Make sure we have imported IntervalManager and thus created
+    # a global ivalMgr.
+    if not sys.modules.get('direct.interval.IntervalManager'):
+        return
+    from direct.interval.FunctionInterval import FunctionInterval
+    for oldFunc, funcName, newFunc in replaceFuncList:    
+        res = FunctionInterval.replaceMethod(oldFunc, newFunc)
+        if res:
+            print ('replaced %s interval function(s): %s' % (res, funcName))