Browse Source

abstract entity types can have typenames, exposed inheritance and output-type information through entityTypeReg

Darren Ranalli 22 years ago
parent
commit
14efabc778

+ 3 - 2
direct/src/level/AttribDesc.py

@@ -24,8 +24,9 @@ class AttribDesc:
     def __str__(self):
     def __str__(self):
         return self.name
         return self.name
     def __repr__(self):
     def __repr__(self):
-        return "AttribDesc(%s, %s, %s)" % (
+        return "AttribDesc(%s, %s, %s, %s)" % (
             repr(self.name),
             repr(self.name),
             repr(self.default),
             repr(self.default),
-            repr(self.datatype)
+            repr(self.datatype),
+            repr(self.params),
             )
             )

+ 112 - 0
direct/src/level/EntityTypeDesc.py

@@ -0,0 +1,112 @@
+"""EntityTypeDesc module: contains the EntityTypeDesc class"""
+
+import DirectNotifyGlobal
+import AttribDesc
+from PythonUtil import mostDerivedLast
+
+class EntityTypeDesc:
+    """This class is meta-data that describes an Entity type."""
+    notify = DirectNotifyGlobal.directNotify.newCategory('EntityTypeDesc')
+
+    output = None
+
+    def __init__(self):
+        self.__class__.privCompileAttribDescs(self.__class__)
+
+        self.attribNames = []
+        self.attribDescDict = {}
+
+        # ordered list of attrib descriptors
+        attribDescs = self.__class__._attribDescs
+
+        # create ordered list of attrib names, dict of attrib name to attribDesc
+        for desc in attribDescs:
+            attribName = desc.getName()
+            self.attribNames.append(attribName)
+            self.attribDescDict[attribName] = desc
+
+    def isConcrete(self):
+        return not self.__class__.__dict__.has_key('abstract')
+
+    def getOutputType(self):
+        return self.output
+
+    def getAttribNames(self):
+        """ returns ordered list of attribute names for this entity type """
+        return self.attribNames
+
+    def getAttribDescDict(self):
+        """ returns dict of attribName -> attribDescriptor """
+        return self.attribDescDict
+
+    def privCompileAttribDescs(entTypeClass):
+        """this compiles an ordered list of attribDescs for the Entity class
+        passed in. The attribute descriptors describe the properties of each
+        of the Entity type's attributes"""
+        # has someone already compiled the info?
+        if entTypeClass.__dict__.has_key('_attribDescs'):
+            return
+
+        c = entTypeClass
+        EntityTypeDesc.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__:
+            EntityTypeDesc.privCompileAttribDescs(base)
+
+        # aggregate the attribute descriptors from our direct base classes
+        delAttribs = c.__dict__.get('delAttribs', [])
+        baseADs = []
+
+        bases = list(c.__bases__)
+        # make sure base-class attribs show up before derived-class attribs
+        mostDerivedLast(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():
+                        EntityTypeDesc.notify.warning(
+                            '%s inherits attrib %s from multiple bases' %
+                            (c.__name__, desc.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
+                        assert ad not in baseADs
+                        break
+                    
+                attribDescs.append(desc)
+
+        c._attribDescs = baseADs + attribDescs
+    privCompileAttribDescs = staticmethod(privCompileAttribDescs)
+
+    def __str__(self):
+        return str(self.__class__)
+    def __repr__(self):
+        # this is used to produce a hash value
+        return (str(self.__class__.__dict__.get('type',None))+
+                str(self.output)+
+                str(self.attribDescDict))

+ 64 - 106
direct/src/level/EntityTypeRegistry.py

@@ -3,124 +3,82 @@
 import DirectNotifyGlobal
 import DirectNotifyGlobal
 import types
 import types
 import AttribDesc
 import AttribDesc
-import EntityTypes
+import EntityTypeDesc
 from PythonUtil import mostDerivedLast
 from PythonUtil import mostDerivedLast
 
 
 class EntityTypeRegistry:
 class EntityTypeRegistry:
     notify = DirectNotifyGlobal.directNotify.newCategory('EntityTypeRegistry')
     notify = DirectNotifyGlobal.directNotify.newCategory('EntityTypeRegistry')
 
 
-    def __init__(self, entityTypeModule=EntityTypes):
-        """pass in a module that contains EntityType classes"""
-        # get a list of the entity type classes in the type module
+    def __init__(self, entityTypeModule):
+        """pass in a module that contains EntityTypeDesc classes"""
+        # get a list of the EntityTypeDesc classes in the type module
         classes = []
         classes = []
         for key, value in entityTypeModule.__dict__.items():
         for key, value in entityTypeModule.__dict__.items():
             if type(value) is types.ClassType:
             if type(value) is types.ClassType:
-                if issubclass(value, EntityTypes.Entity):
+                if issubclass(value, EntityTypeDesc.EntityTypeDesc):
                     classes.append(value)
                     classes.append(value)
 
 
-        # put derived classes after their bases
-        mostDerivedLast(classes)
+        self.entTypeName2typeDesc = {}
 
 
-        # scrub through the class heirarchy and compile complete
-        # attribute descriptor lists for each concrete Entity type class
-        typeName2class = {}
+        # create an instance of each EntityType class with a typename
+        # make sure that derived classes come after bases
+        mostDerivedLast(classes)
         for c in classes:
         for c in classes:
-            # if this is a concrete Entity type, add it to the dict
             if c.__dict__.has_key('type'):
             if c.__dict__.has_key('type'):
-                if typeName2class.has_key(c.type):
-                    EntityTypeRegistry.notify.debug(
-                        "replacing %s with %s for type '%s'" %
-                        (typeName2class[c.type], c, c.type))
-                typeName2class[c.type] = c
-
-            self.privCompileAttribDescs(c)
-
-        # maps entity typename to ordered list of attrib names
-        self.typeName2attribNames = {}
-        # maps entity typename to dict of attrib name -> attrib descriptor
-        self.typeName2attribDescDict = {}
-        
-        for typeName, c in typeName2class.items():
-            self.typeName2attribNames[typeName] = []
-            self.typeName2attribDescDict[typeName] = {}
-
-            # ordered list of attrib descriptors
-            attribDescs = c._attribDescs
-
-            for desc in attribDescs:
-                attribName = desc.getName()
-                self.typeName2attribNames[typeName].append(attribName)
-                self.typeName2attribDescDict[typeName][attribName] = desc
-
-    def getAttribNames(self, entityTypeName):
-        """ returns ordered list of attribute names for entity type """
-        assert entityTypeName in self.typeName2attribNames
-        return self.typeName2attribNames[entityTypeName]
-
-    def getAttribDescDict(self, entityTypeName):
-        """ returns dict of attribName -> attribDescriptor """
-        assert entityTypeName in self.typeName2attribDescDict
-        return self.typeName2attribDescDict[entityTypeName]
+                if self.entTypeName2typeDesc.has_key(c.type):
+                    # a more-derived class is replacing a less-derived class
+                    # to implement a particular entity type
+                    EntityTypeRegistry.notify.info(
+                        "replacing %s with %s for entity type '%s'" %
+                        (self.entTypeName2typeDesc[c.type].__class__,
+                         c, c.type))
+                self.entTypeName2typeDesc[c.type] = c()
+
+        # create mapping of entity output types to list of concrete entity
+        # typenames with that output type
+        self.output2typeNames = {}
+        for typename, typeDesc in self.entTypeName2typeDesc.items():
+            if typeDesc.isConcrete():
+                if hasattr(typeDesc, 'output'):
+                    outputType = typeDesc.output
+                    self.output2typeNames.setdefault(outputType, [])
+                    self.output2typeNames[outputType].append(typename)
+
+        # create mapping of entity typename (abstract or concrete) to list
+        # of entity typenames are concrete and are of that type or derive
+        # from that type
+        self.typeName2derivedTypeNames = {}
+        for typename, typeDesc in self.entTypeName2typeDesc.items():
+            typenames = []
+            for tn, td in self.entTypeName2typeDesc.items():
+                if td.isConcrete():
+                    if issubclass(td.__class__, typeDesc.__class__):
+                        typenames.append(tn)
+            self.typeName2derivedTypeNames[typename] = typenames
+
+    def getTypeDesc(self, entTypeName):
+        """returns EntityTypeDesc instance for concrete Entity type"""
+        assert entTypeName in self.entTypeName2typeDesc,\
+               "unknown entity type '%s'" % entTypeName
+        # the table has descriptors for abstract entity types, but I don't
+        # think there's any need for anyone outside this class to access them
+        assert self.entTypeName2typeDesc[entTypeName].isConcrete(),\
+               "entity type '%s' is abstract" % entTypeName
+        return self.entTypeName2typeDesc[entTypeName]
+
+    def getTypeNamesFromOutputType(self, outputType):
+        """return Entity typenames for Entity types with particular output"""
+        return self.output2typeNames.get(outputType, [])
+
+    def getDerivedTypeNames(self, entTypeName):
+        """return Entity typenames that are of or derive from an entity type,
+        which may be concrete or abstract"""
+        assert entTypeName in self.typeName2derivedTypeNames,\
+               "unknown entity type '%s'" % entTypeName
+        return self.typeName2derivedTypeNames[entTypeName]
 
 
     def __hash__(self):
     def __hash__(self):
-        return hash(str(self))
-    def __str__(self):
-        return str(self.typeName2attribNames)+str(self.typeName2attribDescDict)
-
-    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
+        return hash(repr(self))
+    def __repr__(self):
+        # this is used to produce a hash value
+        return str(self.entTypeName2typeDesc)

+ 33 - 28
direct/src/level/EntityTypes.py

@@ -1,28 +1,17 @@
 """EntityTypes module: contains classes that describe Entity types"""
 """EntityTypes module: contains classes that describe Entity types"""
 
 
+from EntityTypeDesc import EntityTypeDesc
 from SpecImports import *
 from SpecImports import *
 
 
-class Entity:
+class Entity(EntityTypeDesc):
+    abstract = 1
+    type = 'entity'
     attribs = (
     attribs = (
         ('type', None),
         ('type', None),
         ('name', 'unnamed'),
         ('name', 'unnamed'),
         ('comment', ''),
         ('comment', ''),
         )
         )
 
 
-class ActiveCell(Entity):
-    type = 'activeCell'
-    attribs = (
-        ('row', 0, 'int'),
-        ('col', 0, 'int'),
-        ('gridId', None, 'entId', {'type':'grid'})
-        )
-
-class DirectionalCell(ActiveCell):
-    type = 'directionalCell'
-    attribs = (
-        ('dir', [0,0], 'choice', {'choiceSet':['l','r','up','dn']}),
-        )
-    
 class LevelMgr(Entity):
 class LevelMgr(Entity):
     type = 'levelMgr'
     type = 'levelMgr'
     attribs = (
     attribs = (
@@ -60,7 +49,7 @@ class Nodepath(Entity):
         ('hpr', Vec3(0,0,0), 'hpr'),
         ('hpr', Vec3(0,0,0), 'hpr'),
         )
         )
 
 
-class Zone(Entity, Nodepath):
+class Zone(Nodepath):
     type = 'zone'
     type = 'zone'
     delAttribs = (
     delAttribs = (
         'parent',
         'parent',
@@ -86,6 +75,7 @@ class CutScene(Entity):
         )
         )
 
 
 class BarrelBase(Nodepath):
 class BarrelBase(Nodepath):
+    abstract = 1
     delAttribs = (
     delAttribs = (
         'hpr',
         'hpr',
         )
         )
@@ -103,7 +93,8 @@ class GagBarrel(BarrelBase):
         ('gagTrack', 0, 'choice', {'choiceSet':range(7)}),
         ('gagTrack', 0, 'choice', {'choiceSet':range(7)}),
         )
         )
 
 
-class Switch(Entity, Nodepath):
+class Switch(Nodepath):
+    abstract = 1
     output = 'bool'
     output = 'bool'
     attribs = (
     attribs = (
         ('scale', Vec3(1), 'scale'),
         ('scale', Vec3(1), 'scale'),
@@ -131,17 +122,6 @@ class ConveyorBelt(Nodepath):
         ('floorName', 'platformcollision'),
         ('floorName', 'platformcollision'),
         )        
         )        
         
         
-class Crate(Nodepath):
-    type = 'crate'
-    delAttribs = (
-        'hpr',
-        )
-    attribs = (
-        ('scale', Vec3(1), 'scale'),
-        ('gridId', None, 'entId', {'type':'grid'}),
-        ('pushable', 1, 'bool'),
-        )
-
 class Door(Entity):
 class Door(Entity):
     type = 'door'
     type = 'door'
     output = 'bool'
     output = 'bool'
@@ -177,6 +157,31 @@ class Grid(Nodepath):
         ('numRow', 3, 'int'),
         ('numRow', 3, 'int'),
         )
         )
 
 
+class Crate(Nodepath):
+    type = 'crate'
+    delAttribs = (
+        'hpr',
+        )
+    attribs = (
+        ('scale', Vec3(1), 'scale'),
+        ('gridId', None, 'entId', {'type':'grid'}),
+        ('pushable', 1, 'bool'),
+        )
+
+class ActiveCell(Entity):
+    type = 'activeCell'
+    attribs = (
+        ('row', 0, 'int'),
+        ('col', 0, 'int'),
+        ('gridId', None, 'entId', {'type':'grid'})
+        )
+
+class DirectionalCell(ActiveCell):
+    type = 'directionalCell'
+    attribs = (
+        ('dir', [0,0], 'choice', {'choiceSet':['l','r','up','dn']}),
+        )
+
 class Lift(Nodepath):
 class Lift(Nodepath):
     type = 'lift'
     type = 'lift'
     attribs = (
     attribs = (

+ 5 - 3
direct/src/level/LevelSpec.py

@@ -116,7 +116,8 @@ class LevelSpec:
             # create a new entity spec entry w/ default values
             # create a new entity spec entry w/ default values
             globalEnts[entId] = {}
             globalEnts[entId] = {}
             spec = globalEnts[entId]
             spec = globalEnts[entId]
-            attribDescs = self.entTypeReg.getAttribDescDict(entType)
+            attribDescs = self.entTypeReg.getTypeDesc(entType
+                                                      ).getAttribDescDict()
             for name, desc in attribDescs.items():
             for name, desc in attribDescs.items():
                 spec[name] = desc.getDefaultValue()
                 spec[name] = desc.getDefaultValue()
             spec['type'] = entType
             spec['type'] = entType
@@ -323,8 +324,9 @@ class LevelSpec:
 
 
                     assert spec.has_key('type')
                     assert spec.has_key('type')
                     entType = spec['type']
                     entType = spec['type']
-                    attribNames = self.entTypeReg.getAttribNames(entType)
-                    attribDescs = self.entTypeReg.getAttribDescDict(entType)
+                    typeDesc = self.entTypeReg.getTypeDesc(entType)
+                    attribNames = typeDesc.getAttribNames()
+                    attribDescs = typeDesc.getAttribDescDict()
 
 
                     # are there any unknown attribs in the spec?
                     # are there any unknown attribs in the spec?
                     for attrib in spec.keys():
                     for attrib in spec.keys():