zones are now entities, and lots of other tweaks
This commit is contained in:
parent
ad238789c3
commit
6e1f293140
|
|
@ -4,7 +4,36 @@ import Entity
|
|||
import DistributedEntity
|
||||
import NodePath
|
||||
|
||||
# this is an internal class, do not instantiate.
|
||||
# this is an abstract class, do not instantiate.
|
||||
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()."""
|
||||
def initNodePathAttribs(self, doReparent=1):
|
||||
"""Call this after the entity has been initialized"""
|
||||
self.callSetters('pos','x','y','z',
|
||||
'hpr','h','p','r',
|
||||
'scale','sx','sy','sz')
|
||||
if doReparent and hasattr(self, 'parent'):
|
||||
self.level.requestReparent(self.getNodePath(), self.parent)
|
||||
|
||||
def reparentTo(self, *args): self.getNodePath().reparentTo(*args)
|
||||
|
||||
def setPos(self, *args): self.getNodePath().setPos(*args)
|
||||
def setX(self, *args): self.getNodePath().setX(*args)
|
||||
def setY(self, *args): self.getNodePath().setY(*args)
|
||||
def setZ(self, *args): self.getNodePath().setZ(*args)
|
||||
|
||||
def setHpr(self, *args): self.getNodePath().setHpr(*args)
|
||||
def setH(self, *args): self.getNodePath().setH(*args)
|
||||
def setP(self, *args): self.getNodePath().setP(*args)
|
||||
def setR(self, *args): self.getNodePath().setR(*args)
|
||||
|
||||
def setScale(self, *args): self.getNodePath().setScale(*args)
|
||||
def setSx(self, *args): self.getNodePath().setSx(*args)
|
||||
def setSy(self, *args): self.getNodePath().setSy(*args)
|
||||
def setSz(self, *args): self.getNodePath().setSz(*args)
|
||||
|
||||
class privNodePathImpl(NodePath.NodePath):
|
||||
def __init__(self, name):
|
||||
node = hidden.attachNewNode(name)
|
||||
|
|
@ -15,33 +44,32 @@ class privNodePathImpl(NodePath.NodePath):
|
|||
of its attributes have been set"""
|
||||
self.callSetters('pos','x','y','z',
|
||||
'hpr','h','p','r',
|
||||
'scale','sx','sx','sz')
|
||||
|
||||
if hasattr(self, 'parent'):
|
||||
self.level.requestReparent(self, self.parent)
|
||||
else:
|
||||
self.level.requestReparent(self, 'zone')
|
||||
'scale','sx','sy','sz')
|
||||
self.level.requestReparent(self, self.parent)
|
||||
|
||||
def destroy(self):
|
||||
self.removeNode()
|
||||
|
||||
def getNodePath(self):
|
||||
return self
|
||||
|
||||
class NodePathEntity(Entity.Entity, privNodePathImpl):
|
||||
"""This is an entity that represents a NodePath on the client.
|
||||
It may be instantiated directly or used as a base class for other
|
||||
entity types."""
|
||||
def __init__(self, level, entId):
|
||||
privNodePathImpl.__init__(self, '')
|
||||
Entity.Entity.__init__(self, level, entId)
|
||||
privNodePathImpl.__init__(self, str(self))
|
||||
self.initializeEntity()
|
||||
|
||||
def initializeEntity(self):
|
||||
Entity.Entity.initializeEntity(self)
|
||||
self.setName(str(self))
|
||||
privNodePathImpl.initNodePathAttribs(self)
|
||||
|
||||
def destroy(self):
|
||||
Entity.Entity.destroy(self)
|
||||
privNodePathImpl.destroy(self)
|
||||
|
||||
def getNodePath(self):
|
||||
return self
|
||||
|
||||
class DistributedNodePathEntity(DistributedEntity.DistributedEntity,
|
||||
privNodePathImpl):
|
||||
"""This is a distributed version of NodePathEntity. It should not
|
||||
|
|
@ -50,11 +78,14 @@ class DistributedNodePathEntity(DistributedEntity.DistributedEntity,
|
|||
def __init__(self, cr):
|
||||
DistributedEntity.DistributedEntity.__init__(self, cr)
|
||||
privNodePathImpl.__init__(self, 'DistributedNodePathEntity')
|
||||
|
||||
def initializeEntity(self):
|
||||
DistributedEntity.DistributedEntity.initializeEntity(self)
|
||||
privNodePathImpl.initNodePathAttribs(self)
|
||||
|
||||
def announceGenerate(self):
|
||||
DistributedEntity.DistributedEntity.announceGenerate(self)
|
||||
privNodePathImpl.initNodePathAttribs(self)
|
||||
|
||||
def destroy(self):
|
||||
DistributedEntity.DistributedEntity.destroy(self)
|
||||
privNodePathImpl.destroy(self)
|
||||
|
||||
def getNodePath(self):
|
||||
return self
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@ class DistributedEntity(DistributedObject.DistributedObject, Entity.Entity):
|
|||
# ask our level obj for our spec data
|
||||
level = toonbase.tcr.doId2do[self.levelDoId]
|
||||
Entity.Entity.__init__(self, level, self.entId)
|
||||
# this sets all of our initial spec parameters on ourselves
|
||||
self.initializeEntity()
|
||||
|
||||
DistributedObject.DistributedObject.announceGenerate(self)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,13 +7,10 @@ class DistributedEntityAI(DistributedObjectAI.DistributedObjectAI,
|
|||
notify = DirectNotifyGlobal.directNotify.newCategory(
|
||||
'DistributedEntityAI')
|
||||
|
||||
def __init__(self, air, levelDoId, entId):
|
||||
def __init__(self, air, level, entId):
|
||||
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
||||
self.levelDoId = levelDoId
|
||||
level = self.air.doId2do[self.levelDoId]
|
||||
self.levelDoId = level.doId
|
||||
Entity.Entity.__init__(self, level, entId)
|
||||
# get our spec data
|
||||
self.initializeEntity()
|
||||
|
||||
def generate(self):
|
||||
self.notify.debug('generate')
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ class DistributedInteractiveEntityAI(DistributedEntityAI.DistributedEntityAI):
|
|||
if __debug__:
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedInteractiveEntityAI')
|
||||
|
||||
def __init__(self, air, levelDoId, entId):
|
||||
def __init__(self, air, level, entId):
|
||||
"""entId: a unique identifier for this prop."""
|
||||
DistributedEntityAI.DistributedEntityAI.__init__(self, air,
|
||||
levelDoId, entId)
|
||||
level, entId)
|
||||
assert(self.debugPrint(
|
||||
"DistributedInteractiveEntityAI(air=%s, entId=%s)"
|
||||
%("the air", entId)))
|
||||
"DistributedInteractiveEntityAI(entId=%s)"
|
||||
%(entId)))
|
||||
self.fsm = FSM.FSM('DistributedInteractiveEntityAI',
|
||||
[State.State('off',
|
||||
self.enterOff,
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
|
|||
"""DistributedLevel"""
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevel')
|
||||
|
||||
WantVisibility = config.GetBool('level-visibility', 0)
|
||||
WantVisibility = config.GetBool('level-visibility', 1)
|
||||
HideZones = config.GetBool('level-hidezones', 1)
|
||||
|
||||
def __init__(self, cr):
|
||||
|
|
@ -37,7 +37,9 @@ class DistributedLevel(DistributedObject.DistributedObject,
|
|||
# all our entities at that time.
|
||||
toonbase.tcr.timeManager.synchronize('DistributedLevel.generate')
|
||||
|
||||
# required fields
|
||||
# required fields (these ought to be required fields, but
|
||||
# the AI level obj doesn't know the data values until it has been
|
||||
# generated.)
|
||||
def setZoneIds(self, zoneIds):
|
||||
self.notify.debug('setZoneIds: %s' % zoneIds)
|
||||
self.zoneIds = zoneIds
|
||||
|
|
@ -48,22 +50,73 @@ class DistributedLevel(DistributedObject.DistributedObject,
|
|||
|
||||
def setScenarioIndex(self, scenarioIndex):
|
||||
self.scenarioIndex = scenarioIndex
|
||||
# ugly hack: we treat these DC fields as if they were required,
|
||||
# and use 'levelAnnounceGenerate()' in place of regular old
|
||||
# announceGenerate(). Note that we have to call
|
||||
# levelAnnounceGenerate() in the last 'faux-required' DC update
|
||||
# handler. If you add another field, move this to the last one.
|
||||
self.levelAnnounceGenerate()
|
||||
|
||||
def levelAnnounceGenerate(self):
|
||||
pass
|
||||
|
||||
def initializeLevel(self, spec):
|
||||
"""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')
|
||||
# there should not be any pending reparents left at this point
|
||||
assert len(self.parent2ChildIds) == 0
|
||||
# make sure the zoneNums from the model match the zoneNums from
|
||||
# the zone entities
|
||||
assert sameElements(self.zoneNums, self.zoneNum2entId.keys())
|
||||
|
||||
# load stuff
|
||||
|
||||
# fix up the floor collisions for walkable zones
|
||||
for zoneNum in self.zoneNums:
|
||||
zoneNode = self.zoneNum2node[zoneNum]
|
||||
|
||||
# if this is a walkable zone, fix up the model
|
||||
floorColls = zoneNode.findAllMatches('**/+CollisionNode').asList()
|
||||
if len(floorColls) > 0:
|
||||
# rename the floor collision nodes, and make sure no other
|
||||
# nodes under the ZoneNode have that name
|
||||
floorCollName = '%s' % zoneNum
|
||||
others = zoneNode.findAllMatches(
|
||||
'**/%s' % floorCollName).asList()
|
||||
for other in others:
|
||||
other.setName('%s_renamed' % floorCollName)
|
||||
for floorColl in floorColls:
|
||||
floorColl.setName(floorCollName)
|
||||
|
||||
# listen for zone enter events from floor collisions
|
||||
def handleZoneEnter(collisionEntry,
|
||||
self=self, zoneNum=zoneNum):
|
||||
# eat the collisionEntry
|
||||
self.toonEnterZone(zoneNum)
|
||||
self.accept('enter%s' % floorCollName, handleZoneEnter)
|
||||
|
||||
self.initVisibility()
|
||||
|
||||
def createEntityCreator(self):
|
||||
"""Create the object that will be used to create Entities.
|
||||
Inheritors, override if desired."""
|
||||
return EntityCreator.EntityCreator(level=self)
|
||||
|
||||
def setupEntityCreationHandlers(self):
|
||||
LevelBase.LevelBase.setupEntityCreationHandlers(self)
|
||||
# load up the model ASAP so that we can get zone info out of it
|
||||
self.acceptOnce(self.getEntityTypeCreateEvent('levelMgr'),
|
||||
self.handleLevelMgrCreated)
|
||||
|
||||
def removeEntityCreationHandlers(self):
|
||||
LevelBase.LevelBase.removeEntityCreationHandlers(self)
|
||||
|
||||
def handleLevelMgrCreated(self):
|
||||
# as soon as the levelMgr has been created, load up the model
|
||||
# and extract zone info
|
||||
self.geom = loader.loadModel(self.modelFilename)
|
||||
|
||||
def findNumberedNodes(baseString, model=self.geom, self=self):
|
||||
|
|
@ -87,50 +140,13 @@ class DistributedLevel(DistributedObject.DistributedObject,
|
|||
return num2node
|
||||
|
||||
# find the zones in the model and fix them up
|
||||
self.zoneNum2Node = findNumberedNodes('Zone')
|
||||
self.zoneNum2node = findNumberedNodes('Zone')
|
||||
# add the UberZone to the table
|
||||
self.zoneNum2Node[0] = self.geom
|
||||
self.zoneNum2node[0] = self.geom
|
||||
|
||||
self.zoneNums = self.zoneNum2Node.keys()
|
||||
# take the UberZone out of the list
|
||||
self.zoneNums.remove(0)
|
||||
self.zoneNums = self.zoneNum2node.keys()
|
||||
self.zoneNums.sort()
|
||||
self.notify.debug('zones: %s' % self.zoneNums)
|
||||
assert sameElements(self.zoneNums, self.spec['zones'].keys())
|
||||
|
||||
# fix up the floor collisions for walkable zones
|
||||
for zoneNum in self.zoneNums:
|
||||
zoneNode = self.zoneNum2Node[zoneNum]
|
||||
|
||||
# if this is a walkable zone, fix up the model
|
||||
floorColls = zoneNode.findAllMatches('**/+CollisionNode').asList()
|
||||
if len(floorColls) > 0:
|
||||
# rename the floor collision nodes, and make sure no other
|
||||
# nodes under the ZoneNode have that name
|
||||
floorCollName = '%s' % zoneNum
|
||||
others = zoneNode.findAllMatches(
|
||||
'**/%s' % floorCollName).asList()
|
||||
for other in others:
|
||||
other.setName('%s_renamed' % floorCollName)
|
||||
for floorColl in floorColls:
|
||||
floorColl.setName(floorCollName)
|
||||
|
||||
# listen for zone enter events from floor collisions
|
||||
def handleZoneEnter(collisionEntry,
|
||||
self=self, zoneNum=zoneNum):
|
||||
# eat the collisionEntry
|
||||
self.toonEnterZone(zoneNum)
|
||||
self.accept('enter%s' % floorCollName, handleZoneEnter)
|
||||
|
||||
# listen for camera-ray/floor collision events
|
||||
def handleCameraRayFloorCollision(collEntry, self=self):
|
||||
name = collEntry.getIntoNode().getName()
|
||||
try:
|
||||
zoneNum = int(name)
|
||||
self.camEnterZone(zoneNum)
|
||||
except:
|
||||
self.notify.warning('Invalid floor collision node: %s' % name)
|
||||
self.accept('on-floor', handleCameraRayFloorCollision)
|
||||
|
||||
# hack in another doorway
|
||||
dw = self.geom.attachNewNode('Doorway27')
|
||||
|
|
@ -140,48 +156,16 @@ class DistributedLevel(DistributedObject.DistributedObject,
|
|||
# find the doorway nodes
|
||||
self.doorwayNum2Node = findNumberedNodes('Doorway')
|
||||
|
||||
self.initVisibility()
|
||||
|
||||
# create the rest of the client-side Entities
|
||||
# TODO: only create client-side Entities for the
|
||||
# currently-visible zones?
|
||||
for entType in entTypes:
|
||||
for entId in self.entType2Ids[entType]:
|
||||
self.createEntity(entId)
|
||||
|
||||
# there should not be any pending reparents left at this point
|
||||
assert len(self.parent2ChildIds) == 0
|
||||
|
||||
def makeEntityCreator(self):
|
||||
"""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)
|
||||
|
||||
def disable(self):
|
||||
self.notify.debug('disable')
|
||||
self.destroyLevel()
|
||||
DistributedObject.DistributedObject.disable(self)
|
||||
self.ignoreAll()
|
||||
|
||||
# destroy all of the local entities
|
||||
for entId, entity in self.localEntities.items():
|
||||
entity.destroy()
|
||||
del self.localEntities
|
||||
|
||||
self.destroyLevel()
|
||||
|
||||
def delete(self):
|
||||
self.notify.debug('delete')
|
||||
DistributedObject.DistributedObject.delete(self)
|
||||
|
|
@ -190,67 +174,79 @@ class DistributedLevel(DistributedObject.DistributedObject,
|
|||
# returns node that doors should parent themselves to
|
||||
return self.doorwayNum2Node[doorwayNum]
|
||||
|
||||
def requestReparent(self, entity, parent):
|
||||
if parent is 'zone':
|
||||
entity.reparentTo(self.zoneNum2Node[entity.zone])
|
||||
def getZoneNode(self, zoneNum):
|
||||
return self.zoneNum2node[zoneNum]
|
||||
|
||||
def requestReparent(self, entity, parentId):
|
||||
assert(entity.entId != parentId)
|
||||
if self.entities.has_key(parentId):
|
||||
# parent has already been created
|
||||
entity.reparentTo(self.entities[parentId].getNodePath())
|
||||
else:
|
||||
parentId = parent
|
||||
assert(entity.entId != parentId)
|
||||
# parent hasn't been created yet; schedule the reparent
|
||||
self.notify.debug(
|
||||
'entity %s requesting reparent to %s, not yet created' %
|
||||
(entity, parentId))
|
||||
|
||||
if self.entities.has_key(parentId):
|
||||
# parent has already been created
|
||||
entity.reparentTo(self.entities[parentId])
|
||||
else:
|
||||
# parent hasn't been created yet; schedule the reparent
|
||||
self.notify.debug(
|
||||
'entity %s requesting reparent to %s, not yet created' %
|
||||
(entity, parent))
|
||||
entId = entity.entId
|
||||
entity.reparentTo(hidden)
|
||||
|
||||
entId = entity.entId
|
||||
entity.reparentTo(hidden)
|
||||
# if this parent doesn't already have another child pending,
|
||||
# do some setup
|
||||
if not self.parent2ChildIds.has_key(parentId):
|
||||
self.parent2ChildIds[parentId] = []
|
||||
|
||||
# if this parent doesn't already have another child pending,
|
||||
# do some setup
|
||||
if not self.parent2ChildIds.has_key(parentId):
|
||||
self.parent2ChildIds[parentId] = []
|
||||
# do the reparent once the parent is initialized
|
||||
def doReparent(parentId=parentId, self=self):
|
||||
assert self.parent2ChildIds.has_key(parentId)
|
||||
parent=self.getEntity(parentId)
|
||||
for entId in self.parent2ChildIds[parentId]:
|
||||
entity=self.getEntity(entId)
|
||||
self.notify.debug(
|
||||
'performing pending reparent of %s to %s' %
|
||||
(entity, parent))
|
||||
entity.reparentTo(parent.getNodePath())
|
||||
del self.parent2ChildIds[parentId]
|
||||
|
||||
self.accept(self.getEntityCreateEvent(parentId), doReparent)
|
||||
|
||||
# do the reparent once the parent is initialized
|
||||
def doReparent(parentId=parentId, self=self):
|
||||
assert self.parent2ChildIds.has_key(parentId)
|
||||
parent=self.getEntity(parentId)
|
||||
for entId in self.parent2ChildIds[parentId]:
|
||||
entity=self.getEntity(entId)
|
||||
self.notify.debug(
|
||||
'performing pending reparent of %s to %s' %
|
||||
(entity, parent))
|
||||
entity.reparentTo(parent)
|
||||
del self.parent2ChildIds[parentId]
|
||||
|
||||
self.accept(self.getEntityCreateEvent(parentId), doReparent)
|
||||
|
||||
self.parent2ChildIds[parentId].append(entId)
|
||||
self.parent2ChildIds[parentId].append(entId)
|
||||
|
||||
def showZone(self, zoneNum):
|
||||
self.zoneNum2Node[zoneNum].show()
|
||||
self.zoneNum2node[zoneNum].show()
|
||||
|
||||
def hideZone(self, zoneNum):
|
||||
self.zoneNum2Node[zoneNum].hide()
|
||||
self.zoneNum2node[zoneNum].hide()
|
||||
|
||||
def setTransparency(self, alpha, zone=None):
|
||||
self.geom.setTransparency(1)
|
||||
if zone is None:
|
||||
node = self.geom
|
||||
else:
|
||||
node = self.zoneNum2Node[zone]
|
||||
node = self.zoneNum2node[zone]
|
||||
node.setAlphaScale(alpha)
|
||||
|
||||
def initVisibility(self):
|
||||
# start out with every zone visible, since none of the zones have
|
||||
# been hidden
|
||||
self.curVisibleZoneNums = list2dict(self.zoneNums)
|
||||
# the UberZone is always visible, so it's not included in the
|
||||
# viz lists
|
||||
del self.curVisibleZoneNums[0]
|
||||
# we have not entered any zone yet
|
||||
self.curZoneNum = None
|
||||
|
||||
# listen for camera-ray/floor collision events
|
||||
def handleCameraRayFloorCollision(collEntry, self=self):
|
||||
name = collEntry.getIntoNode().getName()
|
||||
try:
|
||||
zoneNum = int(name)
|
||||
except:
|
||||
self.notify.warning('Invalid floor collision node: %s' % name)
|
||||
else:
|
||||
self.camEnterZone(zoneNum)
|
||||
self.accept('on-floor', handleCameraRayFloorCollision)
|
||||
|
||||
# if no viz, listen to all the zones
|
||||
if not DistributedLevel.WantVisibility:
|
||||
self.setVisibility(self.zoneNums)
|
||||
|
|
@ -270,8 +266,9 @@ class DistributedLevel(DistributedObject.DistributedObject,
|
|||
|
||||
if zoneNum == self.curZoneNum:
|
||||
return
|
||||
|
||||
zoneSpec = self.spec['zones'][zoneNum]
|
||||
|
||||
zoneEntId = self.zoneNum2entId[zoneNum]
|
||||
zoneSpec = self.entId2spec[zoneEntId]
|
||||
# use dicts to efficiently ensure that there are no duplicates
|
||||
visibleZoneNums = list2dict([zoneNum])
|
||||
visibleZoneNums.update(list2dict(zoneSpec['visibility']))
|
||||
|
|
@ -310,10 +307,10 @@ class DistributedLevel(DistributedObject.DistributedObject,
|
|||
# accepts list of visible zone numbers
|
||||
# convert the zone numbers into their actual zoneIds
|
||||
# always include Toontown and factory uberZones
|
||||
factoryUberZone = self.getZoneId(0)
|
||||
factoryUberZone = self.getZoneId(zoneNum=0)
|
||||
visibleZoneIds = [ToontownGlobals.UberZone, factoryUberZone]
|
||||
for vz in vizList:
|
||||
visibleZoneIds.append(self.getZoneId(vz))
|
||||
visibleZoneIds.append(self.getZoneId(zoneNum=vz))
|
||||
assert(uniqueElements(visibleZoneIds))
|
||||
self.notify.debug('new viz list: %s' % visibleZoneIds)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,94 +12,24 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
|
|||
"""DistributedLevelAI"""
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevelAI')
|
||||
|
||||
def __init__(self, air):
|
||||
def __init__(self, air, zoneId):
|
||||
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
|
||||
LevelBase.LevelBase.__init__(self)
|
||||
self.uberZoneId = zoneId
|
||||
|
||||
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, 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
|
||||
self.zoneIds = [self.uberZoneId]
|
||||
for i in range(1,self.numZones):
|
||||
# there is error checking in air.allocateZone
|
||||
self.zoneIds.append(self.air.allocateZone())
|
||||
|
||||
# record the level's start time so that we can sync the clients
|
||||
self.startTime = globalClock.getRealTime()
|
||||
self.startTimestamp = globalClockDelta.localToNetworkTime(
|
||||
self.startTime, bits=32)
|
||||
|
||||
def makeEntityCreator(self):
|
||||
"""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
|
||||
|
||||
def getStartTimestamp(self):
|
||||
return self.startTimestamp
|
||||
|
||||
def getScenarioIndex(self):
|
||||
return self.scenarioIndex
|
||||
|
||||
def generate(self):
|
||||
def generate(self, spec):
|
||||
self.notify.debug('generate')
|
||||
DistributedObjectAI.DistributedObjectAI.generate(self)
|
||||
|
||||
# create the rest of the Entities
|
||||
for entType in self.entTypes:
|
||||
for entId in self.entType2Ids[entType]:
|
||||
self.createEntity(entId)
|
||||
self.initializeLevel(spec)
|
||||
|
||||
self.sendUpdate('setZoneIds', [self.zoneIds])
|
||||
self.sendUpdate('setStartTimestamp', [self.startTimestamp])
|
||||
self.sendUpdate('setScenarioIndex', [self.scenarioIndex])
|
||||
|
||||
def delete(self):
|
||||
self.notify.debug('delete')
|
||||
|
||||
for entId in self.aiEntities.keys():
|
||||
self.aiEntities[entId].destroy()
|
||||
del self.aiEntities
|
||||
|
||||
# we do not allocate the uberZone for now, so don't deallocate it
|
||||
for zoneId in self.zoneIds[1:]:
|
||||
self.air.deallocateZone(zoneId)
|
||||
|
|
@ -108,6 +38,67 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
|
|||
|
||||
DistributedObjectAI.DistributedObjectAI.delete(self)
|
||||
|
||||
def initializeLevel(self, spec):
|
||||
# record the level's start time so that we can sync the clients
|
||||
self.startTime = globalClock.getRealTime()
|
||||
self.startTimestamp = globalClockDelta.localToNetworkTime(
|
||||
self.startTime, bits=32)
|
||||
|
||||
# choose a scenario
|
||||
wc = WeightedChoice.WeightedChoice(spec['scenarios'], 1)
|
||||
scenario = wc.choose()
|
||||
scenarioIndex = spec['scenarios'].index(scenario)
|
||||
|
||||
# this will hold the network zoneIds that we allocate
|
||||
self.zoneIds = [self.uberZoneId]
|
||||
|
||||
LevelBase.LevelBase.initializeLevel(self, self.doId,
|
||||
spec, scenarioIndex)
|
||||
|
||||
def createEntityCreator(self):
|
||||
"""Create the object that will be used to create Entities.
|
||||
Inheritors, override if desired."""
|
||||
return EntityCreatorAI.EntityCreatorAI(self.air, level=self)
|
||||
|
||||
def setupEntityCreationHandlers(self):
|
||||
LevelBase.LevelBase.setupEntityCreationHandlers(self)
|
||||
# listen for the creation of each zone object
|
||||
self.accept(self.getEntityOfTypeCreateEvent('zone'),
|
||||
self.zoneEntCreated)
|
||||
|
||||
def removeEntityCreationHandlers(self):
|
||||
LevelBase.LevelBase.removeEntityCreationHandlers(self)
|
||||
self.ignore(self.getEntityOfTypeCreateEvent('zone'))
|
||||
|
||||
def zoneEntCreated(self, entId):
|
||||
if entId == LevelBase.LevelBase.UberZoneEntId:
|
||||
return
|
||||
# there is error checking in air.allocateZone
|
||||
self.zoneIds.append(self.air.allocateZone())
|
||||
|
||||
def getEntityZoneId(self, entId):
|
||||
"""figure out what network zoneId an entity is in"""
|
||||
# TODO: where should the zone info come from? It could come
|
||||
# from the 'parent' scene-graph info... but what about intangible
|
||||
# distributed objects? I guess if they don't inherit from
|
||||
# NodePathEntity et al, they'll just have an unused 'parent'
|
||||
# attribute hanging around, which isn't the end of the world...
|
||||
|
||||
# this func is called before the entity has been created; look
|
||||
# into the spec data, since we can't get a handle on the object itself
|
||||
spec = self.entId2spec[entId]
|
||||
type = spec['type']
|
||||
if type == 'zone':
|
||||
if not hasattr(self, 'zoneNum2zoneId'):
|
||||
# we haven't even created our zone entities yet;
|
||||
# we have no idea yet which zoneNums map to which
|
||||
# network zoneIds. just return None.
|
||||
return None
|
||||
return self.zoneNum2zoneId[spec['modelZoneNum']]
|
||||
if not spec.has_key('parent'):
|
||||
return None
|
||||
return self.getEntityZoneId(spec['parent'])
|
||||
|
||||
if __debug__:
|
||||
# level editors should call this func to tweak attributes of level
|
||||
# entities
|
||||
|
|
|
|||
|
|
@ -25,14 +25,11 @@ class Entity:
|
|||
if attribs is not None:
|
||||
self.attribs.update(attribs)
|
||||
|
||||
self.level.initializeEntity(self)
|
||||
|
||||
def __str__(self):
|
||||
return 'ent%s(%s)' % (self.entId, self.level.getEntityType(self.entId))
|
||||
|
||||
def initializeEntity(self):
|
||||
"""Call this once on initialization to set this entity's
|
||||
spec data"""
|
||||
self.level.initializeEntity(self)
|
||||
|
||||
def destroy(self):
|
||||
del self.level
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +1,30 @@
|
|||
"""EntityCreator module: contains the EntityCreator class"""
|
||||
|
||||
import EntityCreatorBase
|
||||
import BasicEntities
|
||||
import DirectNotifyGlobal
|
||||
import LevelMgr
|
||||
import ZoneEntity
|
||||
|
||||
# some useful constructor functions
|
||||
# ctor functions must take (level, entId)
|
||||
def nothing(level, entId):
|
||||
def nothing(*args):
|
||||
"""For entities that don't need to be created by the client"""
|
||||
return None
|
||||
|
||||
class EntityCreator:
|
||||
class EntityCreator(EntityCreatorBase.EntityCreatorBase):
|
||||
"""This class is responsible for creating instances of Entities on the
|
||||
client. It can be subclassed to handle more Entity types."""
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('EntityCreator')
|
||||
|
||||
def __init__(self):
|
||||
self.entType2Ctor = {}
|
||||
def __init__(self, level):
|
||||
EntityCreatorBase.EntityCreatorBase.__init__(self, level)
|
||||
self.level = level
|
||||
self.privRegisterTypes({
|
||||
'levelMgr': LevelMgr.LevelMgr,
|
||||
'logicGate': nothing,
|
||||
'nodepath': BasicEntities.NodePathEntity,
|
||||
'zone': ZoneEntity.ZoneEntity,
|
||||
})
|
||||
|
||||
def privRegisterType(self, entType, ctor):
|
||||
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):
|
||||
for entType, ctor in type2ctor.items():
|
||||
self.privRegisterType(entType, ctor)
|
||||
|
||||
def createEntity(self, entType, level, entId):
|
||||
if not self.entType2Ctor.has_key(entType):
|
||||
EntityCreator.notify.warning(
|
||||
'createEntity(entType=%s): entType not found' % entType)
|
||||
return None
|
||||
return self.entType2Ctor[entType](level, entId)
|
||||
def doCreateEntity(self, ctor, entId):
|
||||
return ctor(self.level, entId)
|
||||
|
|
|
|||
|
|
@ -1,59 +1,54 @@
|
|||
"""EntityCreatorAI module: contains the EntityCreatorAI class"""
|
||||
|
||||
import DirectNotifyGlobal
|
||||
import EntityCreatorBase
|
||||
import LogicGateAI
|
||||
import LevelMgrAI
|
||||
import ZoneEntityAI
|
||||
from PythonUtil import Functor
|
||||
|
||||
# some useful constructor functions
|
||||
# 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):
|
||||
# ctor functions for entities must take
|
||||
# (air, level, entId, zoneId)
|
||||
|
||||
# this func creates distributed entities whose constructors take
|
||||
# (air, level doId, entId)
|
||||
# and do not generate themselves
|
||||
def createDistributedEntity(AIclass, air, level, entId, zoneId):
|
||||
"""create a distributed entity and call generate"""
|
||||
ent = AIclass(air, levelDoId, entId)
|
||||
ent = AIclass(air, level, entId)
|
||||
ent.generateWithRequired(zoneId)
|
||||
return ent
|
||||
|
||||
def nothing(air, levelDoId, entId, zoneId):
|
||||
# this func creates local entities whose constructors take
|
||||
# (level, entId)
|
||||
def createLocalEntity(AIclass, air, level, entId, zoneId):
|
||||
"""create a local entity"""
|
||||
ent = AIclass(level, entId)
|
||||
|
||||
# take any number of args to support local and distributed entities
|
||||
def nothing(*args):
|
||||
"""Create entity that doesn't have a server side representation."""
|
||||
return None
|
||||
|
||||
class EntityCreatorAI:
|
||||
class EntityCreatorAI(EntityCreatorBase.EntityCreatorBase):
|
||||
"""This class is responsible for creating instances of Entities on the AI.
|
||||
It can be subclassed to handle more Entity types."""
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('EntityCreatorAI')
|
||||
|
||||
def __init__(self):
|
||||
self.entType2Ctor = {}
|
||||
def __init__(self, air, level):
|
||||
EntityCreatorBase.EntityCreatorBase.__init__(self, level)
|
||||
self.air = air
|
||||
|
||||
# create short aliases for ctor funcs
|
||||
cLE = createLocalEntity
|
||||
|
||||
self.privRegisterTypes({
|
||||
'levelMgr': LevelMgrAI.LevelMgrAI,
|
||||
'logicGate': LogicGateAI.LogicGateAI,
|
||||
'levelMgr': Functor(cLE, LevelMgrAI.LevelMgrAI),
|
||||
'logicGate': Functor(cLE, LogicGateAI.LogicGateAI),
|
||||
'nodepath': nothing,
|
||||
'zone': Functor(cLE, ZoneEntityAI.ZoneEntityAI),
|
||||
})
|
||||
|
||||
def privRegisterType(self, entType, ctor):
|
||||
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, 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, level.doId, entId, zoneId))
|
||||
return None
|
||||
|
||||
if zoneId is None:
|
||||
return self.entType2Ctor[entType](level, entId)
|
||||
else:
|
||||
levelDoId = level.doId
|
||||
return self.entType2Ctor[entType](air, levelDoId, entId, zoneId)
|
||||
def doCreateEntity(self, ctor, entId):
|
||||
zoneId = self.level.getEntityZoneId(entId)
|
||||
self.notify.debug('creating entity %s in zone %s' % (entId, zoneId))
|
||||
return ctor(self.air, self.level, entId, zoneId)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
"""EntityCreatorBase module: contains the EntityCreatorBase class"""
|
||||
|
||||
import DirectNotifyGlobal
|
||||
|
||||
class EntityCreatorBase:
|
||||
"""This class is responsible for creating instances of Entities on the
|
||||
AI and on the client. It must be subclassed to specify what entity
|
||||
types it can create, and to provide the creation implementation."""
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('EntityCreator')
|
||||
|
||||
def __init__(self, level):
|
||||
self.level = level
|
||||
self.entType2Ctor = {}
|
||||
|
||||
def createEntity(self, entId):
|
||||
entType = self.level.getEntityType(entId)
|
||||
|
||||
if not self.entType2Ctor.has_key(entType):
|
||||
self.notify.error('unknown entity type: %s (ent%s)' %
|
||||
(entType, entId))
|
||||
|
||||
# inheritor must define doCreateEntity
|
||||
self.doCreateEntity(self.entType2Ctor[entType], entId)
|
||||
|
||||
def privRegisterType(self, entType, ctor):
|
||||
if self.entType2Ctor.has_key(entType):
|
||||
self.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)
|
||||
|
|
@ -4,15 +4,38 @@ import DirectNotifyGlobal
|
|||
import string
|
||||
from PythonUtil import lineInfo
|
||||
|
||||
"""
|
||||
Any data that can be edited by a level editor must be represented as
|
||||
an attribute of an entity owned by the level, in order to keep the
|
||||
level-editing interface simple and unchanging.
|
||||
|
||||
To support this, we have entities such as 'levelMgr' and 'zoneEntity' that
|
||||
contain crucial level information, much of which is needed when setting
|
||||
up the level object, and is needed before other entity types can be
|
||||
effectively created. (If you try to create a distributed entity, but
|
||||
you don't yet have the information for the zone that it's in, because
|
||||
you haven't created the zone's ZoneEntity, you're hurting.)
|
||||
|
||||
|
||||
"""
|
||||
|
||||
"""
|
||||
ZONE TERMINOLOGY
|
||||
zoneNum / modelZoneNum : the number that a modeler chooses for a zone
|
||||
zoneEntId : the entity ID of the ZoneEntity that represents a zone
|
||||
zoneId : the network ID of the zone
|
||||
"""
|
||||
|
||||
class LevelBase:
|
||||
"""LevelBase: shared client and AI code
|
||||
representation of a game level, keeps track of all of the
|
||||
Level Entities and their interrelations"""
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory('LevelBase')
|
||||
|
||||
def __init__(self, levelId=None):
|
||||
if levelId is not None:
|
||||
self.setLevelId(levelId)
|
||||
UberZoneEntId = 0
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def initializeLevel(self, levelId, spec, scenarioIndex):
|
||||
""" subclass should call this as soon as it has located
|
||||
|
|
@ -24,47 +47,128 @@ class LevelBase:
|
|||
# create a complete set of global and scenario-specific entity specs
|
||||
globalEntities = self.spec['globalEntities']
|
||||
scenarioEntities = self.spec['scenarios'][self.scenarioIndex][0]
|
||||
entId2Spec = {}
|
||||
entId2Spec.update(globalEntities)
|
||||
entId2Spec.update(scenarioEntities)
|
||||
self.entId2Spec = entId2Spec
|
||||
entId2spec = {}
|
||||
entId2spec.update(globalEntities)
|
||||
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)
|
||||
# entity type -> list of entIds
|
||||
self.entType2ids = {}
|
||||
for entId, spec in self.entId2spec.items():
|
||||
entType = spec['type']
|
||||
self.entType2ids.setdefault(entType, [])
|
||||
self.entType2ids[entType].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 = {}
|
||||
assert len(self.entType2ids['levelMgr']) == 1
|
||||
|
||||
# get an entity creator object
|
||||
self.entityCreator = self.makeEntityCreator()
|
||||
self.entityCreator = self.createEntityCreator()
|
||||
# set up handlers for entity creation
|
||||
self.setupEntityCreationHandlers()
|
||||
# create all the entities
|
||||
self.createAllEntities(priorityTypes=['levelMgr','zone'])
|
||||
# tear down the entity creation handlers
|
||||
self.removeEntityCreationHandlers()
|
||||
|
||||
def makeEntityCreator(self):
|
||||
def destroyLevel(self):
|
||||
for entity in self.createdEntities:
|
||||
entity.destroy()
|
||||
del self.createdEntities
|
||||
del self.entities
|
||||
del self.entId2spec
|
||||
del self.spec
|
||||
|
||||
def createEntityCreator(self):
|
||||
self.notify.error(
|
||||
'concrete Level class must override %s' % lineInfo()[2])
|
||||
|
||||
def destroyLevel(self):
|
||||
del self.entities
|
||||
del self.entId2Spec
|
||||
del self.spec
|
||||
def setupEntityCreationHandlers(self):
|
||||
# set up any handlers for entity creation events
|
||||
# override if desired, but be sure to call down
|
||||
self.acceptOnce(
|
||||
self.getEntityTypeCreateEvent('zone'),
|
||||
self.handleAllZonesCreated)
|
||||
|
||||
def removeEntityCreationHandlers(self):
|
||||
pass
|
||||
|
||||
def handleAllZonesCreated(self):
|
||||
"""once all the zone entities have been created, and we've got a
|
||||
list of zoneIds in self.zoneIds, init zone tables"""
|
||||
# create a table mapping the model's zone numbers to the zone
|
||||
# entIds; zone entities are tied to model zone nums in the level spec,
|
||||
# this is just for convenient lookup
|
||||
self.zoneNum2entId = {}
|
||||
for entId in self.entType2ids['zone']:
|
||||
zoneEnt = self.getEntity(entId)
|
||||
self.zoneNum2entId[zoneEnt.modelZoneNum] = entId
|
||||
|
||||
# At this point, we need to have a 'self.zoneIds' table of network
|
||||
# zoneIds, one for each zone including the UberZone. This is where
|
||||
# we decide which zoneNum/Entity gets mapped to which zoneId.
|
||||
# We sort the zoneNums, and then pair the sorted zoneNums up with the
|
||||
# zoneIds in the order that they appear in the self.zoneIds table.
|
||||
modelZoneNums = self.zoneNum2entId.keys()
|
||||
modelZoneNums.sort()
|
||||
# maps of zoneNum and zoneEntId to network zoneId
|
||||
self.zoneNum2zoneId = {}
|
||||
self.zoneEntId2zoneId = {}
|
||||
for i in range(len(modelZoneNums)):
|
||||
modelZoneNum = modelZoneNums[i]
|
||||
zoneEntId = self.zoneNum2entId[modelZoneNum]
|
||||
zoneId = self.zoneIds[i]
|
||||
self.zoneNum2zoneId[modelZoneNum] = zoneId
|
||||
self.zoneEntId2zoneId[zoneEntId] = zoneId
|
||||
|
||||
def createAllEntities(self, priorityTypes=[]):
|
||||
"""creates all entities in the spec. priorityTypes is an
|
||||
optional ordered list of entity types to create first."""
|
||||
# this will be filled in as the entities are created and report in
|
||||
# this includes distributed objects on the client
|
||||
self.entities = {}
|
||||
# this list contains the entities that we have actually created
|
||||
self.createdEntities = []
|
||||
|
||||
# get list of all entity types we need to create
|
||||
entTypes = self.entType2ids.keys()
|
||||
|
||||
# first create the types in the priority list
|
||||
for type in priorityTypes:
|
||||
assert type in entTypes
|
||||
self.createAllEntitiesOfType(type)
|
||||
entTypes.remove(type)
|
||||
|
||||
# create the other entities in any old order
|
||||
for type in entTypes:
|
||||
self.createAllEntitiesOfType(type)
|
||||
|
||||
def createAllEntitiesOfType(self, entType):
|
||||
"""creates all entities of a given type"""
|
||||
assert entType in self.entType2ids
|
||||
for entId in self.entType2ids[entType]:
|
||||
self.createEntity(entId)
|
||||
# send the entity type-create event
|
||||
messenger.send(self.getEntityTypeCreateEvent(entType))
|
||||
|
||||
def createEntity(self, entId):
|
||||
assert not self.entities.has_key(entId)
|
||||
spec = self.entId2spec[entId]
|
||||
self.notify.debug('creating %s %s' % (spec['type'], entId))
|
||||
entity = self.entityCreator.createEntity(entId)
|
||||
if entity is not None:
|
||||
self.createdEntities.append(entity)
|
||||
return entity
|
||||
|
||||
def initializeEntity(self, entity):
|
||||
"""populate an entity with its spec data"""
|
||||
"""populate an entity with its spec data. This is not done
|
||||
in createEntity in order to allow other pieces of code create
|
||||
entities; this is called directly by Entity.
|
||||
"""
|
||||
entId = entity.entId
|
||||
spec = self.entId2Spec[entId]
|
||||
spec = self.entId2spec[entId]
|
||||
# on initialization, set items directly on entity
|
||||
for key,value in spec.items():
|
||||
if key in ('type', 'name', 'comment',):
|
||||
|
|
@ -73,8 +177,21 @@ class LevelBase:
|
|||
|
||||
# entity is initialized, add it to the list of entities
|
||||
self.entities[entity.entId] = entity
|
||||
# send the create event
|
||||
# send the entity-create event
|
||||
messenger.send(self.getEntityCreateEvent(entity.entId))
|
||||
# send the entity-of-type create event
|
||||
messenger.send(self.getEntityOfTypeCreateEvent(spec['type']),
|
||||
[entId])
|
||||
|
||||
def getEntityTypeCreateEvent(self, entType):
|
||||
"""This is the event that is thrown immediately after every
|
||||
entity of a given type has been created"""
|
||||
return 'entityTypeCreate-%s-%s' % (self.levelId, entType)
|
||||
|
||||
def getEntityOfTypeCreateEvent(self, entType):
|
||||
"""This event is thrown immediately after each instance of the
|
||||
given entity type is created; handlers must accept an entId"""
|
||||
return 'entityOfTypeCreate-%s-%s' % (self.levelId, entType)
|
||||
|
||||
def getEntityCreateEvent(self, entId):
|
||||
"""This is the event that is thrown immediately after an entity
|
||||
|
|
@ -85,9 +202,15 @@ class LevelBase:
|
|||
return self.entities[entId]
|
||||
|
||||
def getEntityType(self, entId):
|
||||
return self.entId2Spec[entId]['type']
|
||||
return self.entId2spec[entId]['type']
|
||||
|
||||
def getZoneId(self, index):
|
||||
# get the actual zoneId for this index
|
||||
# TODO: perhaps the zones should be fixed up in the specs
|
||||
return self.zoneIds[index]
|
||||
def getZoneId(self, dummy=None, zoneNum=None, entId=None):
|
||||
"""look up network zoneId by zoneNum or entId"""
|
||||
assert (zoneNum is not None) or (entId is not None)
|
||||
assert not ((zoneNum is not None) and (entId is not None))
|
||||
if zoneNum is not None:
|
||||
assert zoneNum in self.zoneNum2zoneId
|
||||
return self.zoneNum2zoneId[zoneNum]
|
||||
else:
|
||||
assert entId in self.zoneEntId2zoneId
|
||||
return self.zoneEntId2zoneId[entId]
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ class LevelMgr(Entity.Entity):
|
|||
"""This class manages editable client-side level attributes"""
|
||||
def __init__(self, level, entId):
|
||||
Entity.Entity.__init__(self, level, entId)
|
||||
self.initializeEntity()
|
||||
self.callSetters('modelFilename')
|
||||
|
||||
def setModelFilename(self, modelFilename):
|
||||
|
|
|
|||
|
|
@ -6,4 +6,3 @@ class LevelMgrAI(Entity.Entity):
|
|||
"""This class manages editable AI level attributes"""
|
||||
def __init__(self, level, entId):
|
||||
Entity.Entity.__init__(self, level, entId)
|
||||
self.initializeEntity()
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ class LogicGateAI(Entity.Entity, PandaObject.PandaObject):
|
|||
self.input1 = None
|
||||
self.input2 = None
|
||||
Entity.Entity.__init__(self, level, entId)
|
||||
self.initializeEntity()
|
||||
self.setLogicType(self.logicType)
|
||||
self.setInput_input1_bool(self.input_input1_bool)
|
||||
self.setInput_input2_bool(self.input_input2_bool)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
"""ZoneEntity module: contains the ZoneEntity class"""
|
||||
|
||||
import Entity
|
||||
import BasicEntities
|
||||
|
||||
class ZoneEntity(Entity.Entity, BasicEntities.NodePathAttribs):
|
||||
def __init__(self, level, entId):
|
||||
Entity.Entity.__init__(self, level, entId)
|
||||
|
||||
self.nodePath = self.level.getZoneNode(self.modelZoneNum)
|
||||
self.initNodePathAttribs(doReparent=0)
|
||||
|
||||
def getNodePath(self):
|
||||
return self.nodePath
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
"""ZoneEntityAI module: contains the ZoneEntityAI class"""
|
||||
|
||||
import Entity
|
||||
|
||||
class ZoneEntityAI(Entity.Entity):
|
||||
def __init__(self, level, entId):
|
||||
Entity.Entity.__init__(self, level, entId)
|
||||
Loading…
Reference in New Issue