From be086b33d77f2d10a8312e961583c866c47152d9 Mon Sep 17 00:00:00 2001 From: Darren Ranalli Date: Sat, 25 Oct 2003 01:10:17 +0000 Subject: [PATCH] added SpecUtil funcs for creating and adapting specs to new level models --- direct/src/level/DistributedLevel.py | 49 ++++++++++---------- direct/src/level/LevelConstants.py | 2 + direct/src/level/LevelSpec.py | 14 +++--- direct/src/level/SpecUtil.py | 67 ++++++++++++++++++++++++++-- 4 files changed, 98 insertions(+), 34 deletions(-) diff --git a/direct/src/level/DistributedLevel.py b/direct/src/level/DistributedLevel.py index 65cc4ea645..aedf17c993 100755 --- a/direct/src/level/DistributedLevel.py +++ b/direct/src/level/DistributedLevel.py @@ -10,6 +10,7 @@ import DirectNotifyGlobal import EntityCreator import OnscreenText import Task +import LevelUtil class DistributedLevel(DistributedObject.DistributedObject, Level.Level): @@ -181,34 +182,13 @@ class DistributedLevel(DistributedObject.DistributedObject, def __handleLevelMgrCreated(self): # as soon as the levelMgr has been created, load up the model - # and extract zone info + # and extract zone info. We need to do this before any entities + # get parented to the level! levelMgr = self.getEntity(LevelConstants.LevelMgrEntId) self.geom = levelMgr.geom - def findNumberedNodes(baseString, model=self.geom, self=self): - # finds nodes whose name follows the pattern 'baseString#' - # where there are no characters after # - # returns dictionary that maps # to node - potentialNodes = model.findAllMatches( - '**/%s*' % baseString).asList() - num2node = {} - for potentialNode in potentialNodes: - name = potentialNode.getName() - DistributedLevel.notify.debug('potential match for %s: %s' % - (baseString, name)) - try: - num = int(name[len(baseString):]) - except: - continue - - num2node[num] = potentialNode - - return num2node - # find the zones in the model and fix them up - self.zoneNum2node = findNumberedNodes('Zone') - # add the UberZone to the table - self.zoneNum2node[0] = self.geom + self.zoneNum2node = LevelUtil.getZoneNum2Node(self.geom) self.zoneNums = self.zoneNum2node.keys() self.zoneNums.sort() @@ -250,6 +230,27 @@ class DistributedLevel(DistributedObject.DistributedObject, dw.setH(0) # find the doorway nodes + # this is going to go away soon. + def findNumberedNodes(baseString, model=self.geom, self=self): + # finds nodes whose name follows the pattern 'baseString#' + # where there are no characters after # + # returns dictionary that maps # to node + potentialNodes = model.findAllMatches( + '**/%s*' % baseString).asList() + num2node = {} + for potentialNode in potentialNodes: + name = potentialNode.getName() + DistributedLevel.notify.debug('potential match for %s: %s' % + (baseString, name)) + try: + num = int(name[len(baseString):]) + except: + continue + + num2node[num] = potentialNode + + return num2node + self.doorwayNum2Node = findNumberedNodes('Doorway') def announceGenerate(self): diff --git a/direct/src/level/LevelConstants.py b/direct/src/level/LevelConstants.py index 304faa3d93..8665fed0fe 100755 --- a/direct/src/level/LevelConstants.py +++ b/direct/src/level/LevelConstants.py @@ -6,3 +6,5 @@ UberZoneNum = 0 LevelMgrEntId = 10 EditMgrEntId = 20 + +ZoneEntIdStart = 100 diff --git a/direct/src/level/LevelSpec.py b/direct/src/level/LevelSpec.py index d8850fa678..23a2681012 100755 --- a/direct/src/level/LevelSpec.py +++ b/direct/src/level/LevelSpec.py @@ -16,22 +16,24 @@ class LevelSpec: def __init__(self, spec=None, scenario=0): """spec must be passed in as a python module or a dictionary""" + newSpec = 0 if type(spec) is types.ModuleType: self.specDict = spec.levelSpec - else: + if __debug__: + self.setFilename(spec.__file__) + elif type(spec) is types.DictType: # we need this for repr/eval-ing LevelSpecs - assert type(spec) is types.DictType self.specDict = spec - - if __debug__: - newSpec = 0 - if self.specDict == None: + elif spec is None: + if __debug__: newSpec = 1 self.specDict = { 'globalEntities': {}, 'scenarios': [[{}, 1]], } + assert hasattr(self, '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 diff --git a/direct/src/level/SpecUtil.py b/direct/src/level/SpecUtil.py index ad0db9be11..e486458d74 100755 --- a/direct/src/level/SpecUtil.py +++ b/direct/src/level/SpecUtil.py @@ -2,13 +2,14 @@ import LevelSpec import LevelConstants +import LevelUtil +from PythonUtil import list2dict def makeNewSpec(filename, modelPath): """call this to create a new level spec for the level model at 'modelPath'. Spec will be saved as 'filename'""" spec = LevelSpec.LevelSpec() - spec.doSetAttrib(LevelConstants.LevelMgrEntId, - 'modelFilename', modelPath) + privUpdateSpec(spec, modelPath) spec.saveToDisk(filename, makeBackup=0) def updateSpec(specModule, modelPath=None): @@ -16,10 +17,68 @@ def updateSpec(specModule, modelPath=None): model. If the level model has a new path, pass it in as 'modelPath'. specModule must be a Python module""" spec = LevelSpec.LevelSpec(specModule) + privUpdateSpec(spec, modelPath) + spec.saveToDisk() + +def privUpdateSpec(spec, modelPath=None): + """internal: take a spec and update it to match its level model""" if modelPath is None: modelPath = spec.getEntitySpec( LevelConstants.LevelMgrEntId)['modelFilename'] + else: + spec.doSetAttrib(LevelConstants.LevelMgrEntId, + 'modelFilename', modelPath) - # ... + # load the model + model = loader.loadModel(modelPath) + # get the model's zone info + modelZoneNum2node = LevelUtil.getZoneNum2Node(model) + modelZoneNums = modelZoneNum2node.keys() - spec.saveToDisk() + # what zone entities do we have specs for? + type2ids = spec.getEntType2ids(spec.getAllEntIds()) + type2ids.setdefault('zone', []) + zoneEntIds = type2ids['zone'] + zoneEntId2spec = list2dict(zoneEntIds) + for entId in zoneEntIds: + zoneEntId2spec[entId] = spec.getEntitySpec(entId) + + def removeZoneEntity(entId, spec=spec, zoneEntIds=zoneEntIds, + zoneEntId2spec=zoneEntId2spec): + spec.removeEntity(entId) + zoneEntIds.remove(entId) + del zoneEntId2spec[entId] + + # create dict of zoneNum -> entId + zoneNum2entId = {} + for entId in list(zoneEntIds): + zoneNum = zoneEntId2spec[entId]['modelZoneNum'] + if zoneNum in zoneNum2entId: + print ('multiple zone entities reference zoneNum %s; removing ' + 'entity %s' % (zoneNum, entId)) + removeZoneEntity(entId) + continue + zoneNum2entId[zoneNum] = entId + + # prune zone entities that reference zones that no longer exist + for entId in list(zoneEntIds): + zoneNum = zoneEntId2spec[entId]['modelZoneNum'] + if zoneNum not in modelZoneNums: + print 'zone %s no longer exists; removing entity %s' % ( + zoneNum, entId) + removeZoneEntity(entId) + del zoneNum2entId[zoneNum] + + # add new zone entities for new zones + for zoneNum in modelZoneNums: + if zoneNum not in zoneNum2entId: + entIdDict = list2dict(spec.getAllEntIds()) + entId = LevelConstants.ZoneEntIdStart + # we could do better than linear + while entId in entIdDict: + entId += 1 + + print 'adding entity %s for new zone %s' % (entId, zoneNum) + spec.insertEntity(entId, 'zone', LevelConstants.UberZoneEntId) + spec.doSetAttrib(entId, 'name', 'zone%s' % zoneNum) + spec.doSetAttrib(entId, 'modelZoneNum', zoneNum)