Browse Source

added EntityTypes

Darren Ranalli 22 years ago
parent
commit
d2747bd99a

+ 15 - 0
direct/src/level/AttribDesc.py

@@ -0,0 +1,15 @@
+"""AttribDesc.py module: contains the AttribDesc class"""
+
+class AttribDesc:
+    """
+    Entity attribute descriptor
+    name == name of attribute
+    """
+    def __init__(self, name):
+        self.name = name
+    def getName(self):
+        return self.name
+    def __str__(self):
+        return self.name
+    def __repr__(self):
+        return "AttribDesc('%s')" % self.name

+ 0 - 6
direct/src/level/BasicEntities.py

@@ -9,9 +9,6 @@ class NodePathAttribs:
     """Derive from this class to give an entity the behavior of a
     """Derive from this class to give an entity the behavior of a
     NodePath, without necessarily deriving from NodePath. Derived class
     NodePath, without necessarily deriving from NodePath. Derived class
     must implement getNodePath()."""
     must implement getNodePath()."""
-    __attribs__ = (
-        'parent', 'pos', 'hpr',
-        )
     def initNodePathAttribs(self, doReparent=1):
     def initNodePathAttribs(self, doReparent=1):
         """Call this after the entity has been initialized"""
         """Call this after the entity has been initialized"""
         self.callSetters('pos','x','y','z',
         self.callSetters('pos','x','y','z',
@@ -38,9 +35,6 @@ class NodePathAttribs:
     def setSz(self, *args): self.getNodePath().setSz(*args)
     def setSz(self, *args): self.getNodePath().setSz(*args)
     
     
 class privNodePathImpl(NodePath.NodePath):
 class privNodePathImpl(NodePath.NodePath):
-    __attribs__ = (
-        'parent', 'pos', 'hpr',
-        )
     def __init__(self, name):
     def __init__(self, name):
         node = hidden.attachNewNode(name)
         node = hidden.attachNewNode(name)
         NodePath.NodePath.__init__(self, node)
         NodePath.NodePath.__init__(self, node)

+ 0 - 117
direct/src/level/Entity.py

@@ -10,12 +10,6 @@ class Entity(DirectObject):
     and can be edited with the LevelEditor."""
     and can be edited with the LevelEditor."""
     notify = DirectNotifyGlobal.directNotify.newCategory('Entity')
     notify = DirectNotifyGlobal.directNotify.newCategory('Entity')
 
 
-    __attribs__ = (
-        'type',
-        'name',
-        'comment',
-        )
-
     def __init__(self, level=None, entId=None):
     def __init__(self, level=None, entId=None):
         self.initializeEntity(level, entId)
         self.initializeEntity(level, entId)
 
 
@@ -71,117 +65,6 @@ class Entity(DirectObject):
         self.__dict__[attrib] = value
         self.__dict__[attrib] = value
 
 
     if __debug__:
     if __debug__:
-        def getAttribDescriptors(entClass):
-            """pass in an Entity class"""
-            # lazy compilation
-            if not entClass.__dict__.has_key('_attribDescs'):
-                entClass.compileAttribDescs(entClass)
-            return entClass.__dict__['_attribDescs']
-        getAttribDescriptors = staticmethod(getAttribDescriptors)
-
-        def compileAttribDescs(entClass):
-            Entity.notify.debug('compiling attrib descriptors for %s' %
-                                entClass.__name__)
-            # create a complete list of attribute descriptors, pulling in
-            # the attribs from the entire class heirarchy
-            def getClassList(obj):
-                """returns list, ordered from most-derived to base classes,
-                depth-first. Multiple inheritance base classes that do not
-                derive from Entity are listed before those that do.
-                """
-                assert (type(obj) == types.ClassType)
-                classList = [obj]
-
-                # no need to go below Entity
-                if obj == Entity:
-                    return classList
-
-                # explore the base classes
-                entityBases = []
-                nonEntityBases = []
-                for base in obj.__bases__:
-                    l = getClassList(base)
-                    if Entity in l:
-                        entityBases.extend(l)
-                    else:
-                        nonEntityBases.extend(l)
-                # put bases that derive from Entity last
-                classList = classList + nonEntityBases + entityBases
-                return classList
-
-            def getUniqueClassList(obj):
-                classList = getClassList(obj)
-                # remove duplicates, leaving the last instance
-                uniqueList = []
-                for i in range(len(classList)):
-                    if classList[i] not in classList[(i+1):]:
-                        uniqueList.append(classList[i])
-                return uniqueList
-
-            classList = getUniqueClassList(entClass)
-
-            # work backwards, through the class list, from Entity to the
-            # most-derived class, aggregating attribute descriptors.
-            allAttribs = []
-
-            def isDistObjAI(obj):
-                # util func: is this class a DistributedObjectAI?
-                lineage = getClassLineage(obj)
-                for item in lineage:
-                    if type(item) == types.ClassType:
-                        if item.__name__ == 'DistributedObjectAI':
-                            return 1
-                return 0
-
-            while len(classList):
-                cl = classList.pop()
-                Entity.notify.debug('looking for attribs on %s' % cl.__name__)
-
-                def getClassAttr(cl, name):
-                    """grab an attribute, such as __attribs__, off of a class"""
-                    if cl.__dict__.has_key(name):
-                        return cl.__dict__[name]
-                    elif isDistObjAI(cl):
-                        # It's a distributed AI class.
-                        # Check the client-side class
-                        globals = {}
-                        locals = {}
-                        ccn = cl.__name__[:-2] # clientClassName
-                        Entity.notify.debug('importing client class %s' % ccn)
-                        try:
-                            exec 'import %s' % ccn in globals, locals
-                        except:
-                            print 'could not import %s' % ccn
-                            return None
-                        exec 'attr = %s.%s.__dict__.get("%s")' % (
-                            ccn, ccn, name) in globals, locals
-                        return locals['attr']
-                    else:
-                        return None
-
-                # delete some attribs?
-                delAttribs = getClassAttr(cl, '__delAttribs__')
-                if delAttribs is not None:
-                    assert type(delAttribs) in (types.TupleType, types.ListType)
-                    Entity.notify.debug('delAttribs: %s' % list(delAttribs))
-                    for attrib in delAttribs:
-                        if attrib in allAttribs:
-                            allAttribs.remove(attrib)
-
-                attribs = getClassAttr(cl, '__attribs__')
-                if attribs is not None:
-                    assert type(attribs) in (types.TupleType, types.ListType)
-                    Entity.notify.debug('attribs: %s' % list(attribs))
-                    for attrib in attribs:
-                        if attrib not in allAttribs:
-                            allAttribs.append(attrib)
-
-            # we now have an ordered list of all of the attribute descriptors
-            # for this class. Cache it on the class object
-            Entity.notify.debug('all attribs: %s' % allAttribs)
-            entClass.__dict__['_attribDescs'] = allAttribs
-        compileAttribDescs = staticmethod(compileAttribDescs)
-
         # support for level editing
         # support for level editing
         def handleAttribChange(self, attrib, value):
         def handleAttribChange(self, attrib, value):
             # call callback function if it exists
             # call callback function if it exists

+ 99 - 0
direct/src/level/EntityTypeRegistry.py

@@ -0,0 +1,99 @@
+"""EntityTypeRegistry module: contains the EntityTypeRegistry class"""
+
+import DirectNotifyGlobal
+import types
+import AttribDesc
+import EntityTypes
+from PythonUtil import mostDerivedLast
+
+class EntityTypeRegistry:
+    notify = DirectNotifyGlobal.directNotify.newCategory('EntityTypeRegistry')
+
+    def __init__(self, entityTypeModule=EntityTypes):
+        """pass in a module that contains EntityType classes"""
+        # maps entity typename to type class
+        self.name2typeClass = {}
+        
+        # get a list of the entity type classes in the type module
+        classes = []
+        for key, value in entityTypeModule.__dict__.items():
+            if type(value) is types.ClassType:
+                if issubclass(value, EntityTypes.Entity):
+                    classes.append(value)
+
+        # put derived classes after their bases
+        mostDerivedLast(classes)
+
+        # scrub through the class heirarchy and compile complete
+        # attribute descriptor lists for each concrete Entity type class
+        for c in classes:
+            # if this is a concrete Entity type, add it to the dict
+            if c.__dict__.has_key('name'):
+                if self.name2typeClass.has_key(c.name):
+                    EntityTypeRegistry.notify.debug(
+                        "replacing %s with %s for type '%s'" %
+                        (self.name2typeClass[c.name], c, c.name))
+                self.name2typeClass[c.name] = c
+
+            self.privCompileAttribDescs(c)
+
+    def getAttributeDescriptors(self, entityTypeName):
+        return self.name2typeClass[entityTypeName]._attribDescs
+
+    def privCompileAttribDescs(self, entTypeClass):
+        # has someone already compiled the info?
+        if entTypeClass.__dict__.has_key('_attribDescs'):
+            return
+
+        c = entTypeClass
+        EntityTypeRegistry.notify.debug('compiling attrib descriptors for %s' %
+                                        c.__name__)
+
+        # make sure all of our base classes have their complete list of
+        # attribDescs
+        for base in c.__bases__:
+            self.privCompileAttribDescs(base)
+
+        # aggregate the attribute descriptors from our direct base classes
+        delAttribs = c.__dict__.get('delAttribs', [])
+        baseADs = []
+
+        bases = list(c.__bases__)
+        # make sure that Entity comes first
+        if EntityTypes.Entity in bases:
+            bases.remove(EntityTypes.Entity)
+            bases = [EntityTypes.Entity] + bases
+
+        for base in bases:
+            for desc in base._attribDescs:
+                # are we blocking this attribute?
+                if desc.getName() in delAttribs:
+                    continue
+                    
+                # make sure we haven't already picked up this attribute
+                # from an earlier base class
+                for d in baseADs:
+                    if desc.getName() == d.getName():
+                        break
+                else:
+                    baseADs.append(desc)
+
+        # now that we have all of the descriptors from our base classes,
+        # add the descriptors from this class
+        attribDescs = []
+        if c.__dict__.has_key('attribs'):
+            for attrib in c.attribs:
+                desc = AttribDesc.AttribDesc(attrib)
+                
+                # if we picked up an attribute with the same name from a base
+                # class, this overrides it
+                for ad in baseADs:
+                    if ad.getName() == desc.getName():
+                        baseADs.remove(ad)
+                        # there ought to be no more than one desc with
+                        # this name from the base classes
+                        break
+                    
+                attribDescs.append(desc)
+
+        c._attribDescs = baseADs + attribDescs

+ 208 - 0
direct/src/level/EntityTypes.py

@@ -0,0 +1,208 @@
+"""EntityTypes module: contains classes that describe Entity types"""
+
+class Entity:
+    attribs = (
+        'type',
+        'name',
+        'comment',
+        )
+
+class LevelMgr(Entity):
+    name = 'levelMgr'
+    attribs = (
+        'cogLevel',
+        'cogTrack',
+        'modelFilename',
+        )
+
+class LogicGate(Entity):
+    name = 'logicGate'
+    attribs = (
+        'input_input1_bool',
+        'input_input2_bool',
+        'isInput1',
+        'isInput2',
+        'logicType',
+        'output',
+        )
+
+class NodepathImpl:
+    attribs = (
+        'parent',
+        'pos',
+        'hpr',
+        )
+
+# Note: this covers Nodepath and DistributedNodepath
+class Nodepath(Entity, NodepathImpl):
+    name = 'nodepath'
+
+class NodepathAttribs:
+    attribs = (
+        'parent',
+        'pos',
+        'hpr',
+        )
+
+class Zone(Entity, NodepathAttribs):
+    name = 'zone'
+    delAttribs = (
+        'parent',
+        'pos',
+        'hpr',
+        )
+    attribs = (
+        'description',
+        'modelZoneNum',
+        )
+
+class BarrelBase(Nodepath):
+    delAttribs = (
+        'hpr',
+        )
+    attribs = (
+        'h',
+        )
+
+class BeanBarrel(BarrelBase):
+    name = 'beanBarrel'
+
+class GagBarrel(BarrelBase):
+    name = 'gagBarrel'
+    attribs = (
+        'gagLevel',
+        'gagTrack',
+        )
+
+class Switch(Entity, NodepathImpl):
+    attribs = (
+        'scale',
+        'color',
+        'model',
+        'input_isOn_bool',
+        'isOn',
+        'output',
+        'secondsOn',
+        )
+
+class Button(Switch):
+    name = 'button'
+
+class Trigger(Switch):
+    name = 'trigger'
+
+class Crate(Nodepath):
+    name = 'crate'
+    delAttribs = (
+        'hpr',
+        )
+    attribs = (
+        'scale',
+        'gridId',
+        'pushable',
+        )
+
+class Door(Entity):
+    name = 'door'
+    attribs = (
+        'parent',
+        'pos',
+        'hpr',
+        'scale',
+        'color',
+        'model',
+        'doorwayNum',
+        'input_Lock0_bool',
+        'input_Lock1_bool',
+        'input_Lock2_bool',
+        'input_Lock3_bool',
+        'input_isOpen_bool',
+        'isLock0Unlocked',
+        'isLock1Unlocked',
+        'isLock2Unlocked',
+        'isLock3Unlocked',
+        'isOpen',
+        'output',
+        'secondsOpen',
+        )
+
+class Grid(Nodepath):
+    name = 'grid'
+    delAttribs = (
+        'hpr',
+        )
+    attribs = (
+        'cellSize',
+        'numCol',
+        'numRow',
+        )
+
+class Lift(Nodepath):
+    name = 'lift'
+    attribs = (
+        'duration',
+        'startPos',
+        'endPos',
+        'modelPath',
+        'floorName',
+        'modelScale',
+        )
+
+class Platform(Nodepath):
+    name = 'platform'
+    delAttribs = (
+        'pos',
+        )
+    attribs = (
+        'startPos',
+        'endPos',
+        'speed',
+        'waitDur',
+        'phaseShift',
+        )
+
+class SinkingPlatform(Nodepath):
+    name = 'sinkingPlatform'
+    delAttribs = (
+        'pos',
+        )
+    attribs = (
+        'endPos',
+        'phaseShift',
+        'startPos',
+        'verticalRange',
+        'sinkRate',
+        'riseRate',
+        'speed',
+        'waitDur',
+        )
+
+class Stomper(Nodepath):
+    name = 'stomper'
+    attribs = (
+        'headScale',
+        'motion',
+        'period',
+        'phaseShift',
+        'range',
+        'shaftScale',
+        'soundLen',
+        'soundOn',
+        'style',
+        'zOffset',
+        )
+
+class StomperPair(Nodepath):
+    name = 'stomperPair'
+    attribs = (
+        'headScale',
+        'motion',
+        'period',
+        'phaseShift',
+        'range',
+        'shaftScale',
+        'soundLen',
+        'soundOn',
+        'stomperIds',
+        'style',
+        )

+ 0 - 6
direct/src/level/LevelMgr.py

@@ -6,12 +6,6 @@ import LevelMgrBase
 class LevelMgr(LevelMgrBase.LevelMgrBase):
 class LevelMgr(LevelMgrBase.LevelMgrBase):
     """This class manages editable client-side level attributes"""
     """This class manages editable client-side level attributes"""
 
 
-    __attribs__ = (
-        'cogLevel',
-        'cogTrack',
-        'modelFilename',
-        )
-    
     def __init__(self, level, entId):
     def __init__(self, level, entId):
         LevelMgrBase.LevelMgrBase.__init__(self, level, entId)
         LevelMgrBase.LevelMgrBase.__init__(self, level, entId)
         
         

+ 0 - 4
direct/src/level/LogicGateAI.py

@@ -69,10 +69,6 @@ class LogicGateAI(Entity.Entity, PandaObject.PandaObject):
     if __debug__:
     if __debug__:
         notify = DirectNotifyGlobal.directNotify.newCategory(
         notify = DirectNotifyGlobal.directNotify.newCategory(
                 'LogicGateAI')
                 'LogicGateAI')
-    __attribs__ = (
-        'input_input1_bool', 'input_input2_bool',
-        'isInput1', 'isInput2', 'logicType', 'output',
-        )
     logicTests={
     logicTests={
         "and": andTest,
         "and": andTest,
         "or": orTest,
         "or": orTest,

+ 0 - 7
direct/src/level/ZoneEntity.py

@@ -4,13 +4,6 @@ import ZoneEntityBase
 import BasicEntities
 import BasicEntities
 
 
 class ZoneEntity(ZoneEntityBase.ZoneEntityBase, BasicEntities.NodePathAttribs):
 class ZoneEntity(ZoneEntityBase.ZoneEntityBase, BasicEntities.NodePathAttribs):
-    __delAttribs__ = (
-        'parent', 'pos', 'hpr',
-        )
-    __attribs__ = (
-        'description', 'modelZoneNum',
-        )
-    
     def __init__(self, level, entId):
     def __init__(self, level, entId):
         ZoneEntityBase.ZoneEntityBase.__init__(self, level, entId)
         ZoneEntityBase.ZoneEntityBase.__init__(self, level, entId)
 
 

+ 10 - 0
direct/src/showbase/PythonUtil.py

@@ -757,3 +757,13 @@ class PureVirtual:
         pure-virtual methods. """
         pure-virtual methods. """
         raise 'error: derived class must implement %s' % callerInfo()[2]
         raise 'error: derived class must implement %s' % callerInfo()[2]
 
 
+def mostDerivedLast(classList):
+    """pass in list of classes. sorts list in-place, with derived classes
+    appearing after their bases"""
+    def compare(a,b):
+        if a is b:
+            return 0
+        if issubclass(a,b):
+            return 1
+        return -1
+    classList.sort(compare)