added EntityTypes

This commit is contained in:
Darren Ranalli 2003-10-03 01:34:52 +00:00
parent f8d1734379
commit d2747bd99a
9 changed files with 332 additions and 140 deletions

15
direct/src/level/AttribDesc.py Executable file
View File

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

View File

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

View File

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

View File

@ -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
direct/src/level/EntityTypes.py Executable file
View File

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

View File

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

View File

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

View File

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

View File

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