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

This commit is contained in:
Darren Ranalli 2003-10-17 22:40:23 +00:00
parent 61008f86b7
commit 14efabc778
5 changed files with 212 additions and 134 deletions

View File

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

View File

@ -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))

View File

@ -3,124 +3,82 @@
import DirectNotifyGlobal
import types
import AttribDesc
import EntityTypes
import EntityTypeDesc
from PythonUtil import mostDerivedLast
class 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 = []
for key, value in entityTypeModule.__dict__.items():
if type(value) is types.ClassType:
if issubclass(value, EntityTypes.Entity):
if issubclass(value, EntityTypeDesc.EntityTypeDesc):
classes.append(value)
# put derived classes after their bases
self.entTypeName2typeDesc = {}
# create an instance of each EntityType class with a typename
# make sure that derived classes come after bases
mostDerivedLast(classes)
# scrub through the class heirarchy and compile complete
# attribute descriptor lists for each concrete Entity type class
typeName2class = {}
for c in classes:
# if this is a concrete Entity type, add it to the dict
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
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()
self.privCompileAttribDescs(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)
# 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] = {}
# 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
# ordered list of attrib descriptors
attribDescs = c._attribDescs
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]
for desc in attribDescs:
attribName = desc.getName()
self.typeName2attribNames[typeName].append(attribName)
self.typeName2attribDescDict[typeName][attribName] = desc
def getTypeNamesFromOutputType(self, outputType):
"""return Entity typenames for Entity types with particular output"""
return self.output2typeNames.get(outputType, [])
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]
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):
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)

View File

@ -1,28 +1,17 @@
"""EntityTypes module: contains classes that describe Entity types"""
from EntityTypeDesc import EntityTypeDesc
from SpecImports import *
class Entity:
class Entity(EntityTypeDesc):
abstract = 1
type = 'entity'
attribs = (
('type', None),
('name', 'unnamed'),
('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):
type = 'levelMgr'
attribs = (
@ -60,7 +49,7 @@ class Nodepath(Entity):
('hpr', Vec3(0,0,0), 'hpr'),
)
class Zone(Entity, Nodepath):
class Zone(Nodepath):
type = 'zone'
delAttribs = (
'parent',
@ -86,6 +75,7 @@ class CutScene(Entity):
)
class BarrelBase(Nodepath):
abstract = 1
delAttribs = (
'hpr',
)
@ -103,7 +93,8 @@ class GagBarrel(BarrelBase):
('gagTrack', 0, 'choice', {'choiceSet':range(7)}),
)
class Switch(Entity, Nodepath):
class Switch(Nodepath):
abstract = 1
output = 'bool'
attribs = (
('scale', Vec3(1), 'scale'),
@ -131,17 +122,6 @@ class ConveyorBelt(Nodepath):
('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):
type = 'door'
output = 'bool'
@ -177,6 +157,31 @@ class Grid(Nodepath):
('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):
type = 'lift'
attribs = (

View File

@ -116,7 +116,8 @@ class LevelSpec:
# create a new entity spec entry w/ default values
globalEnts[entId] = {}
spec = globalEnts[entId]
attribDescs = self.entTypeReg.getAttribDescDict(entType)
attribDescs = self.entTypeReg.getTypeDesc(entType
).getAttribDescDict()
for name, desc in attribDescs.items():
spec[name] = desc.getDefaultValue()
spec['type'] = entType
@ -323,8 +324,9 @@ class LevelSpec:
assert spec.has_key('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?
for attrib in spec.keys():