mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
added EntityTypes
This commit is contained in:
parent
f8d1734379
commit
d2747bd99a
15
direct/src/level/AttribDesc.py
Executable file
15
direct/src/level/AttribDesc.py
Executable 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
|
@ -9,9 +9,6 @@ class NodePathAttribs:
|
||||
"""Derive from this class to give an entity the behavior of a
|
||||
NodePath, without necessarily deriving from NodePath. Derived class
|
||||
must implement getNodePath()."""
|
||||
__attribs__ = (
|
||||
'parent', 'pos', 'hpr',
|
||||
)
|
||||
def initNodePathAttribs(self, doReparent=1):
|
||||
"""Call this after the entity has been initialized"""
|
||||
self.callSetters('pos','x','y','z',
|
||||
@ -38,9 +35,6 @@ class NodePathAttribs:
|
||||
def setSz(self, *args): self.getNodePath().setSz(*args)
|
||||
|
||||
class privNodePathImpl(NodePath.NodePath):
|
||||
__attribs__ = (
|
||||
'parent', 'pos', 'hpr',
|
||||
)
|
||||
def __init__(self, name):
|
||||
node = hidden.attachNewNode(name)
|
||||
NodePath.NodePath.__init__(self, node)
|
||||
|
@ -10,12 +10,6 @@ class Entity(DirectObject):
|
||||
and can be edited with the LevelEditor."""
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('Entity')
|
||||
|
||||
__attribs__ = (
|
||||
'type',
|
||||
'name',
|
||||
'comment',
|
||||
)
|
||||
|
||||
def __init__(self, level=None, entId=None):
|
||||
self.initializeEntity(level, entId)
|
||||
|
||||
@ -71,117 +65,6 @@ class Entity(DirectObject):
|
||||
self.__dict__[attrib] = value
|
||||
|
||||
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
|
||||
def handleAttribChange(self, attrib, value):
|
||||
# call callback function if it exists
|
||||
|
99
direct/src/level/EntityTypeRegistry.py
Executable file
99
direct/src/level/EntityTypeRegistry.py
Executable 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
208
direct/src/level/EntityTypes.py
Executable 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',
|
||||
)
|
@ -6,12 +6,6 @@ import LevelMgrBase
|
||||
class LevelMgr(LevelMgrBase.LevelMgrBase):
|
||||
"""This class manages editable client-side level attributes"""
|
||||
|
||||
__attribs__ = (
|
||||
'cogLevel',
|
||||
'cogTrack',
|
||||
'modelFilename',
|
||||
)
|
||||
|
||||
def __init__(self, level, entId):
|
||||
LevelMgrBase.LevelMgrBase.__init__(self, level, entId)
|
||||
|
||||
|
@ -69,10 +69,6 @@ class LogicGateAI(Entity.Entity, PandaObject.PandaObject):
|
||||
if __debug__:
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||||
'LogicGateAI')
|
||||
__attribs__ = (
|
||||
'input_input1_bool', 'input_input2_bool',
|
||||
'isInput1', 'isInput2', 'logicType', 'output',
|
||||
)
|
||||
logicTests={
|
||||
"and": andTest,
|
||||
"or": orTest,
|
||||
|
@ -4,13 +4,6 @@ import ZoneEntityBase
|
||||
import BasicEntities
|
||||
|
||||
class ZoneEntity(ZoneEntityBase.ZoneEntityBase, BasicEntities.NodePathAttribs):
|
||||
__delAttribs__ = (
|
||||
'parent', 'pos', 'hpr',
|
||||
)
|
||||
__attribs__ = (
|
||||
'description', 'modelZoneNum',
|
||||
)
|
||||
|
||||
def __init__(self, level, entId):
|
||||
ZoneEntityBase.ZoneEntityBase.__init__(self, level, entId)
|
||||
|
||||
|
@ -757,3 +757,13 @@ class PureVirtual:
|
||||
pure-virtual methods. """
|
||||
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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user