added LevelSpec data wrapper

This commit is contained in:
Darren Ranalli 2003-09-26 01:58:46 +00:00
parent 5951f37a02
commit 5c113af66a
4 changed files with 234 additions and 40 deletions

View File

@ -64,11 +64,11 @@ class DistributedLevel(DistributedObject.DistributedObject,
def levelAnnounceGenerate(self):
pass
def initializeLevel(self, spec):
"""subclass should call this as soon as it's located its spec data.
def initializeLevel(self, levelSpec):
"""subclass should call this as soon as it's located its level spec.
Must be called after obj has been generated."""
Level.Level.initializeLevel(self, self.doId,
spec, self.scenarioIndex)
levelSpec, self.scenarioIndex)
# all of the entities have been created now.
# there should not be any pending reparents left at this point
@ -287,7 +287,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
return
zoneEntId = self.zoneNum2entId[zoneNum]
zoneSpec = self.entId2spec[zoneEntId]
zoneSpec = self.levelSpec.getEntitySpec(zoneEntId)
# use dicts to efficiently ensure that there are no duplicates
visibleZoneNums = list2dict([zoneNum])
visibleZoneNums.update(list2dict(zoneSpec['visibility']))
@ -352,12 +352,12 @@ class DistributedLevel(DistributedObject.DistributedObject,
if __debug__:
# if someone has edited the level, we'll get the full up-to-date
# spec in this message
def setSpecOverride(self, specStr):
if self.spec is not None:
def setLevelSpecOverride(self, specStr):
if self.levelSpec is not None:
return
try:
self.spec = eval(specStr)
self.levelSpec = eval(specStr)
except Exception, e:
print ('Exception in %s(%s):\n\t%s' %
(lineInfo()[2], specStr, e))

View File

@ -17,11 +17,11 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
Level.Level.__init__(self)
self.uberZoneId = zoneId
def generate(self, spec):
def generate(self, levelSpec):
self.notify.debug('generate')
DistributedObjectAI.DistributedObjectAI.generate(self)
self.initializeLevel(spec)
self.initializeLevel(levelSpec)
self.sendUpdate('setZoneIds', [self.zoneIds])
self.sendUpdate('setStartTimestamp', [self.startTimestamp])
@ -32,19 +32,21 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
self.destroyLevel()
DistributedObjectAI.DistributedObjectAI.delete(self)
def initializeLevel(self, spec):
def initializeLevel(self, levelSpec):
# 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)
# make list of lists: [(weight, scenarioIndex), ...]
lol = zip(levelSpec.getScenarioWeights(),
range(levelSpec.getNumScenarios()))
wc = WeightedChoice.WeightedChoice(lol)
scenarioIndex = wc.choose()[1]
Level.Level.initializeLevel(self, self.doId,
spec, scenarioIndex)
levelSpec, scenarioIndex)
def createEntityCreator(self):
"""Create the object that will be used to create Entities.
@ -56,7 +58,7 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
# this func is called before the entity has been created; look
# into the spec data, since we can't yet get a handle on the
# object itself at this point
spec = self.entId2spec[entId]
spec = self.levelSpec.getEntitySpec(entId)
type = spec['type']
if type == 'zone':
if not hasattr(self, 'zoneNum2zoneId'):
@ -85,11 +87,11 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
# send a copy of the entire spec for any new users that
# might come in
##self.sendUpdate('setSpecOverride', [repr(self.spec)])
##self.sendUpdate('setSpecOverride', [repr(self.levelSpec)])
def getCurrentSpec(self):
def getCurrentLevelSpec(self):
"""returns the complete, current spec, including any edits"""
return self.spec
return self.levelSpec
"""
def getSpecOverride(self):

View File

@ -34,31 +34,22 @@ class Level:
UberZoneEntId = 0
def __init__(self):
self.spec = None
self.levelSpec = None
def initializeLevel(self, levelId, spec, scenarioIndex):
def initializeLevel(self, levelId, levelSpec, scenarioIndex):
""" subclass should call this as soon as it has located
its spec data """
self.levelId = levelId
self.spec = spec
self.levelSpec = levelSpec
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
self.levelSpec.setScenario(self.scenarioIndex)
# 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)
self.entType2ids = self.levelSpec.getEntType2ids(
self.levelSpec.getAllEntIds())
# there should be one and only one levelMgr
assert len(self.entType2ids['levelMgr']) == 1
@ -83,10 +74,8 @@ class Level:
del self.createdEntities
if hasattr(self, 'entities'):
del self.entities
if hasattr(self, 'entId2spec'):
del self.entId2spec
if hasattr(self, 'spec'):
del self.spec
if hasattr(self, 'levelSpec'):
del self.levelSpec
def createEntityCreator(self):
self.notify.error(
@ -131,7 +120,7 @@ class Level:
def createEntity(self, entId):
assert not self.entities.has_key(entId)
spec = self.entId2spec[entId]
spec = self.levelSpec.getEntitySpec(entId)
self.notify.debug('creating %s %s' % (spec['type'], entId))
entity = self.entityCreator.createEntity(entId)
# NOTE: the entity is not considered to really be created until
@ -156,7 +145,7 @@ class Level:
entities; this is called directly by Entity.
"""
entId = entity.entId
spec = self.entId2spec[entId]
spec = self.levelSpec.getEntitySpec(entId)
# on initialization, set items directly on entity
for key,value in spec.items():
if key in ('type', 'name', 'comment',):
@ -170,7 +159,7 @@ class Level:
return self.entities.get(entId)
def getEntityType(self, entId):
return self.entId2spec[entId]['type']
return self.levelSpec.getEntityType(entId)
def getZoneId(self, dummy=None, zoneNum=None, entId=None):
"""look up network zoneId by zoneNum or entId"""

203
direct/src/level/LevelSpec.py Executable file
View File

@ -0,0 +1,203 @@
"""LevelSpec module: contains the LevelSpec class"""
from PythonUtil import list2dict
import string
class LevelSpec:
"""contains spec data for a level, is responsible for handing the data
out upon request, as well as recording changes made during editing, and
saving out modified spec data"""
def __init__(self, specDict, scenario=0):
self.specDict = specDict
# this maps an entId to the dict that holds its spec;
# entities are either in the global dict or a scenario dict
# update the map of entId to spec dict
self.entId2specDict = {}
self.entId2specDict.update(
list2dict(self.getGlobalEntIds(),
value=self.privGetGlobalEntityDict()))
for i in range(self.getNumScenarios()):
self.entId2specDict.update(
list2dict(self.getScenarioEntIds(i),
value=self.privGetScenarioEntityDict(i)))
self.setScenario(scenario)
def getNumScenarios(self):
return len(self.specDict['scenarios'])
def getScenarioWeights(self):
weights = []
for entry in self.specDict['scenarios']:
weights.append(entry[1])
return weights
def setScenario(self, scenario):
assert scenario in range(0, self.getNumScenarios())
self.scenario = scenario
def getScenario(self):
return self.scenario
def getGlobalEntIds(self):
return self.privGetGlobalEntityDict().keys()
def getScenarioEntIds(self, scenario=None):
if scenario is None:
scenario = self.scenario
return self.privGetScenarioEntityDict(scenario).keys()
def getAllEntIds(self):
return self.getGlobalEntIds() + self.getScenarioEntIds()
def getEntitySpec(self, entId):
assert entId in self.entId2specDict
specDict = self.entId2specDict[entId]
return specDict[entId]
def getEntityType(self, entId):
return self.getEntitySpec(entId)['type']
def getEntType2ids(self, entIds):
"""given list of entIds, return dict of entType 2 entIds"""
entType2ids = {}
for entId in entIds:
type = self.getEntityType(entId)
entType2ids.setdefault(type, [])
entType2ids[type].append(entId)
return entType2ids
# private support functions to abstract dict structure
def privGetGlobalEntityDict(self):
return self.specDict['globalEntities']
def privGetScenarioEntityDict(self, scenario):
return self.specDict['scenarios'][scenario][0]
if __debug__:
def setAttribChange(self, entId, attrib, value):
pass
def getSpecImportsModuleName(self):
# name of module that should be imported by spec py file
return 'SpecImports'
def getPrettyString(self):
"""Returns a string that contains the spec data, nicely formatted.
This should be used when writing the spec out to file."""
import pprint
tabWidth = 4
tab = ' ' * tabWidth
# structure names
globalEntitiesName = 'GlobalEntities'
scenarioEntitiesName = 'Scenario%s'
scenarioWeightName = 'Scenarios'
topLevelName = 'levelSpec'
def getPrettyEntityDictStr(name, dict, tabs=0):
def t(n):
return (tabs+n)*tab
def sortList(lst, firstElements=[]):
"""sort list; elements in firstElements will be put
first, in the order that they appear in firstElements;
rest of elements will follow, sorted"""
elements = list(lst)
# put elements in order
result = []
for el in firstElements:
if el in elements:
result.append(el)
elements.remove(el)
elements.sort()
result.extend(elements)
return result
firstTypes = ('levelMgr', 'zone',)
firstAttribs = ('type', 'name', 'comment', 'parent',
'pos', 'x', 'y', 'z',
'hpr', 'h', 'p', 'r',
'scale', 'sx', 'sy', 'sz',
'color',
'model',
)
str = t(0)+'%s = {\n' % name
# get list of types
entIds = dict.keys()
entType2ids = self.getEntType2ids(entIds)
# put types in order
types = sortList(entType2ids.keys(), firstTypes)
for type in types:
str += t(1)+'# %s\n' % string.upper(type)
entIds = entType2ids[type]
entIds.sort()
for entId in entIds:
str += t(1)+'%s: {\n' % entId
spec = dict[entId]
attribs = sortList(spec.keys(), firstAttribs)
for attrib in attribs:
str += t(2)+"'%s': %s,\n" % (attrib,
repr(spec[attrib]))
str += t(2)+'},\n'
str += t(1)+'}\n'
return str
def getPrettyScenarioWeightTableStr(tabs=0, self=self):
def t(n):
return (tabs+n)*tab
str = t(0)+'%s = [\n' % scenarioWeightName
for i in range(self.getNumScenarios()):
str += t(1)+'[%s, %s],\n' % (scenarioEntitiesName % i,
self.getScenarioWeights()[i])
str += t(1)+']\n'
return str
def getPrettyTopLevelDictStr(tabs=0):
def t(n):
return (tabs+n)*tab
str = t(0)+'%s = {\n' % topLevelName
str += t(1)+"'globalEntities': %s,\n" % globalEntitiesName
str += t(1)+"'scenarios': %s,\n" % scenarioWeightName
str += t(1)+'}\n'
return str
str = 'from %s import *\n' % self.getSpecImportsModuleName()
str += '\n'
# add the global entities
str += getPrettyEntityDictStr('GlobalEntities',
self.privGetGlobalEntityDict())
str += '\n'
# add the scenario entities
numScenarios = self.getNumScenarios()
for i in range(numScenarios):
str += getPrettyEntityDictStr('Scenario%s' % i,
self.privGetScenarioEntityDict(i))
str += '\n'
# add the scenario weight table
str += getPrettyScenarioWeightTableStr()
str += '\n'
# add the top-level table
str += getPrettyTopLevelDictStr()
self.testPrettyString(prettyString=str)
return str
def testPrettyString(self, prettyString=None):
# execute the pretty output in our local scope
if prettyString is None:
prettyString=self.getPrettyString()
exec(prettyString)
assert levelSpec == self.specDict, (
'LevelSpec pretty string does not match spec data.\n'
'pretty=%s\n'
'specData=%s' %
(levelSpec, self.specDict)
)
def __repr__(self):
return 'LevelSpec(%s, scenario=%s)' % (repr(self.specDict),
self.scenario)