added levelMgr, changed AI entity creation, reorganized level initialization

This commit is contained in:
Darren Ranalli 2003-09-15 21:03:19 +00:00
parent 82295ee76d
commit 80d1520092
8 changed files with 127 additions and 57 deletions

View File

@ -11,9 +11,9 @@ class privNodePathImpl(NodePath.NodePath):
NodePath.NodePath.__init__(self, node)
def initializeEntity(self):
self.callSetters(('pos','x','y','z',
'hpr','h','p','r',
'scale','sx','sx','sz'))
self.callSetters('pos','x','y','z',
'hpr','h','p','r',
'scale','sx','sx','sz')
if hasattr(self, 'parent'):
self.level.requestReparent(self, self.parent)

View File

@ -24,8 +24,6 @@ class DistributedLevel(DistributedObject.DistributedObject,
self.notify.debug('generate')
DistributedObject.DistributedObject.generate(self)
self.setLevelId(self.doId)
# this dict stores entity reparents if the parent hasn't been
# created yet
self.parent2ChildIds = {}
@ -52,10 +50,21 @@ class DistributedLevel(DistributedObject.DistributedObject,
self.scenarioIndex = scenarioIndex
def initializeLevel(self, spec):
""" subclass should call this as soon as it's located its spec data """
LevelBase.LevelBase.initializeLevel(self, spec, self.scenarioIndex)
"""subclass should call this as soon as it's located its spec data.
Must be called after obj has been generated."""
LevelBase.LevelBase.initializeLevel(self, self.doId,
spec, self.scenarioIndex)
self.localEntities = {}
# get list of entity types we need to create
entTypes = self.entType2Ids.keys()
# create the levelMgr
self.levelMgr = self.createEntity(self.entType2Ids['levelMgr'][0])
entTypes.remove('levelMgr')
# load stuff
self.geom = loader.loadModel(self.spec['modelFilename'])
self.geom = loader.loadModel(self.modelFilename)
def findNumberedNodes(baseString, model=self.geom, self=self):
# finds nodes whose name follows the pattern 'baseString#'
@ -133,22 +142,30 @@ class DistributedLevel(DistributedObject.DistributedObject,
self.initVisibility()
# create client-side Entities
# create the rest of the client-side Entities
# TODO: only create client-side Entities for the
# currently-visible zones?
self.localEntities = {}
for entId, spec in self.entId2Spec.iteritems():
entity = self.entityCreator.createEntity(spec['type'], self, entId)
if entity is not None:
self.localEntities[entId] = entity
for entType in entTypes:
for entId in self.entType2Ids[entType]:
self.createEntity(entId)
# there should not be any pending reparents left
# there should not be any pending reparents left at this point
assert len(self.parent2ChildIds) == 0
def makeEntityCreator(self):
"""inheritors, override if desired"""
"""Create the object that will be used to create Entities.
Inheritors, override if desired."""
return EntityCreator.EntityCreator()
def createEntity(self, entId):
assert not self.localEntities.has_key(entId)
spec = self.entId2Spec[entId]
self.notify.debug('creating %s %s' % (spec['type'], entId))
entity = self.entityCreator.createEntity(spec['type'], self, entId)
if entity is not None:
self.localEntities[entId] = entity
return entity
def announceGenerate(self):
self.notify.debug('announceGenerate')
DistributedObject.DistributedObject.announceGenerate(self)

View File

@ -19,12 +19,25 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
def initializeLevel(self, spec, uberZoneId):
self.uberZoneId = uberZoneId
# We need a unique level ID to init the level system, and we need
# the level system to get the data for our required fields.
# Pre-allocate a doId.
self.preAllocateDoId()
# choose a scenario
wc = WeightedChoice.WeightedChoice(spec['scenarios'], 1)
scenario = wc.choose()
scenarioIndex = spec['scenarios'].index(scenario)
LevelBase.LevelBase.initializeLevel(self, spec, scenarioIndex)
LevelBase.LevelBase.initializeLevel(self, self.doId,
spec, scenarioIndex)
self.aiEntities = {}
# get list of entity types we need to create
self.entTypes = self.entType2Ids.keys()
# create the levelMgr
self.levelMgr = self.createEntity(self.entType2Ids['levelMgr'][0])
self.entTypes.remove('levelMgr')
# allocate the rest of the zones; add one for the uber-zone
self.numZones = len(self.spec['zones']) + 1
@ -39,9 +52,28 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
self.startTime, bits=32)
def makeEntityCreator(self):
"""inheritors, override if desired"""
"""Create the object that will be used to create Entities.
Inheritors, override if desired."""
return EntityCreatorAI.EntityCreatorAI()
def createEntity(self, entId):
assert not self.aiEntities.has_key(entId)
spec = self.entId2Spec[entId]
self.notify.debug('creating %s %s' % (spec['type'], entId))
zone = spec.get('zone')
# we might attempt to create non-distributed entities before
# we've been generated
if zone is not None:
zone = self.getZoneId(zone)
entity = self.entityCreator.createEntity(
spec['type'], self, entId, self.air, zone)
else:
entity = self.entityCreator.createEntity(
spec['type'], self, entId)
if entity is not None:
self.aiEntities[entId] = entity
return entity
# required-field getters
def getZoneIds(self):
return self.zoneIds
@ -56,17 +88,10 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
self.notify.debug('generate')
DistributedObjectAI.DistributedObjectAI.generate(self)
self.setLevelId(self.doId)
# create the Entities
self.aiEntities = {}
for entId, spec in self.entId2Spec.iteritems():
self.notify.debug('creating %s %s' % (spec['type'], entId))
entity = self.entityCreator.createEntity(
spec['type'], self.air, self.doId, entId,
self.getZoneId(spec['zone']))
if entity is not None:
self.aiEntities[entId] = entity
# create the rest of the Entities
for entType in self.entTypes:
for entId in self.entType2Ids[entType]:
self.createEntity(entId)
def delete(self):
self.notify.debug('delete')

View File

@ -7,25 +7,21 @@ class Entity:
and can be edited with the LevelEditor."""
# these are values that can be changed in the level editor
# TODO: pick a good name for these values;
# parameters, tweakables, attributes, attribs, traits,
Tweakables = (
Attribs = (
# Name, PythonType, CallSetterOnInitialization
('name', str, 0),
('comment', str, 0),
)
def __init__(self, level, entId, tweakables=None):
def __init__(self, level, entId, attribs=None):
self.level = level
self.entId = entId
self.tweakables = Entity.Tweakables
self.attribs = Entity.Attribs
# add any additional tweakable values
if tweakables is not None:
self.tweakables.update(tweakables)
if attribs is not None:
self.attribs.update(attribs)
# TODO: funcs to populate the entity with its spec data, and system
# to call back when data changes
def initializeEntity(self):
"""Call this once on initialization to set this entity's
spec data"""
@ -40,16 +36,16 @@ class Entity:
return getattr(self, setFuncName)
return None
def callSetters(self, attribList):
def callSetters(self, *attribs):
"""call this with a list of attribs, and any that exist on the
entity and have setters will be passed to their setter"""
for attrib in attribList:
for attrib in attribs:
if hasattr(self, attrib):
setter = self.privGetSetter(attrib)
if setter is not None:
setter(getattr(self, attrib))
def paramChanged(self):
def attribChanged(self):
"""This is called when a parameter is tweaked and no setter
is called; i.e. the value is set directly on the object.
Some Entities might want to completely reset every time anything
@ -58,8 +54,8 @@ class Entity:
"""
pass
def getTweakables(self):
return self.tweakables
def getAttribInfo(self):
return self.attribs
def privTweak(self, name, value):
self.__dict__[name] = value

View File

@ -2,6 +2,7 @@
import BasicEntities
import DirectNotifyGlobal
import LevelMgr
# some useful constructor functions
# ctor functions must take (level, entId)
@ -17,12 +18,16 @@ class EntityCreator:
def __init__(self):
self.entType2Ctor = {}
self.privRegisterTypes({
'levelMgr': LevelMgr.LevelMgr,
'logicGate': nothing,
'nodepath': BasicEntities.NodePathEntity,
})
def privRegisterType(self, entType, ctor):
assert(not self.entType2Ctor.has_key(entType))
if self.entType2Ctor.has_key(entType):
EntityCreator.notify.warning(
'replacing %s ctor %s with %s' %
(entType, self.entType2Ctor[entType], ctor))
self.entType2Ctor[entType] = ctor
def privRegisterTypes(self, type2ctor):

View File

@ -2,9 +2,13 @@
import DirectNotifyGlobal
import LogicGateAI
import LevelMgrAI
# some useful constructor functions
# ctor functions must take (air, level doId, entId, zoneId)
# ctor functions for distributed entities must take
# (air, level doId, entId, zoneId)
# ctor functions for non-distributed entities must take
# (level, entId)
def createDistributedEntity(AIclass, air, levelDoId, entId, zoneId):
"""create a distributed entity and call generate"""
ent = AIclass(air, levelDoId, entId)
@ -23,23 +27,33 @@ class EntityCreatorAI:
def __init__(self):
self.entType2Ctor = {}
self.privRegisterTypes({
'levelMgr': LevelMgrAI.LevelMgrAI,
'logicGate': LogicGateAI.LogicGateAI,
'nodepath': nothing,
})
def privRegisterType(self, entType, ctor):
assert(not self.entType2Ctor.has_key(entType))
if self.entType2Ctor.has_key(entType):
EntityCreatorAI.notify.warning(
'replacing %s ctor %s with %s' %
(entType, self.entType2Ctor[entType], ctor))
self.entType2Ctor[entType] = ctor
def privRegisterTypes(self, type2ctor):
for entType, ctor in type2ctor.items():
self.privRegisterType(entType, ctor)
def createEntity(self, entType, air, levelDoId, entId, zoneId):
def createEntity(self, entType, level, entId, air=None, zoneId=None):
"""zoneId=None indicates a non-distributed entity"""
if not self.entType2Ctor.has_key(entType):
EntityCreatorAI.notify.warning(
'createEntity(entType=%s, levelDoId=%s, '
'entId=%s, zoneId=%s) not found' %
(entType, levelDoId, entId, zoneId))
return None
return self.entType2Ctor[entType](air, levelDoId, entId, zoneId)
if zoneId is None:
return self.entType2Ctor[entType](level, entId)
else:
levelDoId = level.doId
return self.entType2Ctor[entType](air, levelDoId, entId, zoneId)

View File

@ -14,12 +14,10 @@ class LevelBase:
if levelId is not None:
self.setLevelId(levelId)
def setLevelId(self, levelId):
self.levelId = levelId
def initializeLevel(self, spec, scenarioIndex):
def initializeLevel(self, levelId, spec, scenarioIndex):
""" subclass should call this as soon as it has located
its spec data """
self.levelId = levelId
self.spec = spec
self.scenarioIndex = scenarioIndex
@ -31,6 +29,23 @@ class LevelBase:
entId2Spec.update(scenarioEntities)
self.entId2Spec = entId2Spec
# create some handy tables
self.entType2Ids = {}
self.entZone2Ids = {}
self.nonZoneEntIds = []
for entId, spec in self.entId2Spec.items():
entType = spec['type']
self.entType2Ids.setdefault(entType, [])
self.entType2Ids[entType].append(entId)
entZone = spec.get('zone')
# note that entities with no Zone will be filed under 'None'
self.entZone2Ids.setdefault(entZone, [])
self.entZone2Ids[entZone].append(entId)
# there should be one and only one levelMgr
assert len(self.entType2Ids['levelMgr']) == 1
# this will be filled in as the entities are created and report in
self.entities = {}

View File

@ -78,15 +78,13 @@ class LogicGateAI(Entity.Entity, PandaObject.PandaObject):
"xnor": xnorTest,
}
def __init__(self, air, levelDoId, entId, zoneId=None):
def __init__(self, level, entId):
"""entId: """
assert(self.debugPrint(
"LogicGateAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
%("the air", levelDoId, entId, zoneId)))
"LogicGateAI(entId=%s)"
%(entId)))
self.input1 = None
self.input2 = None
self.levelDoId = levelDoId
level = air.doId2do[self.levelDoId]
Entity.Entity.__init__(self, level, entId)
self.initializeEntity()
self.setLogicType(self.logicType)