added levelMgr, changed AI entity creation, reorganized level initialization
This commit is contained in:
parent
82295ee76d
commit
80d1520092
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 = {}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue