LevelBase->Level, more robust entity creation handler system

This commit is contained in:
Darren Ranalli 2003-09-22 23:31:57 +00:00
parent 1ec650644e
commit e954395d38
1 changed files with 0 additions and 230 deletions

View File

@ -1,230 +0,0 @@
"""LevelBase.py: contains the LevelBase class"""
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 constant (there are at least three
places where the entire editing interface must be duplicated).
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')
UberZoneEntId = 0
def __init__(self):
self.spec = None
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
# 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
# create some handy tables
# 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
# get an entity creator object
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 destroyLevel(self):
if hasattr(self, 'createdEntities'):
# destroy the entities in reverse order
while len(self.createdEntities) > 0:
entity = self.createdEntities.pop()
self.notify.debug('destroying %s entity %s' %
(self.getEntityType(entity.entId),
entity.entId))
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 setupEntityCreationHandlers(self):
# set up any handlers for entity creation events
# override if desired, but be sure to call down
# NOTE: we currently don't support a single object listening
# multiple times to a single event; therefore, anything that
# is listened for here cannot be listened for in a subclass
# as well; one will stomp the other. Therefore, until we figure
# out a better way to handle it, override any handlers defined
# in LevelBase and call down, instead of installing your own
# handler.
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. 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]
# on initialization, set items directly on entity
for key,value in spec.items():
if key in ('type', 'name', 'comment',):
continue
entity.setAttribInit(key, value)
# entity is initialized, add it to the list of entities
self.entities[entity.entId] = entity
# 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
is initialized"""
return 'entityCreate-%s-%s' % (self.levelId, entId)
def getEntity(self, entId):
return self.entities[entId]
def getEntityType(self, entId):
return self.entId2spec[entId]['type']
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]