Browse Source

zoneNum and zoneEntId are the same thing now

Darren Ranalli 22 years ago
parent
commit
7001df5c85

+ 28 - 30
direct/src/level/DistributedLevel.py

@@ -195,11 +195,11 @@ class DistributedLevel(DistributedObject.DistributedObject,
         # make sure the zoneNums from the model match the zoneNums from
         # the zone entities
         modelZoneNums = self.zoneNums
-        entityZoneNums = self.zoneNum2entId.keys()
-        if not sameElements(modelZoneNums, entityZoneNums):
+        specZoneNums = self.zoneNum2zoneId.keys()
+        if not sameElements(modelZoneNums, specZoneNums):
             self.reportModelSpecSyncError(
-                'model zone nums (%s) do not match entity zone nums (%s)' %
-                (modelZoneNums, entityZoneNums))
+                'model zone nums (%s) do not match spec zone nums (%s)' %
+                (modelZoneNums, specZoneNums))
 
         # load stuff
         self.initVisibility()
@@ -236,7 +236,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
             initialZoneEnt = self.getEntity(epEnt.getZoneEntId())
 
         # kickstart the visibility
-        self.enterZone(initialZoneEnt.getZoneNum())
+        self.enterZone(initialZoneEnt.entId)
 
     def createEntityCreator(self):
         """Create the object that will be used to create Entities.
@@ -263,13 +263,14 @@ class DistributedLevel(DistributedObject.DistributedObject,
 
         self.zoneNums = self.zoneNum2node.keys()
         self.zoneNums.sort()
-        DistributedLevel.notify.debug('zones: %s' % self.zoneNums)
+        self.zoneNumDict = list2dict(self.zoneNums)
+        DistributedLevel.notify.debug('zones from model: %s' % self.zoneNums)
 
         # fix up the floor collisions for walkable zones *before*
         # any entities get put under the model
         for zoneNum,zoneNode in self.zoneNum2node.items():
             # don't do this to the uberzone
-            if zoneNum == LevelConstants.UberZoneNum:
+            if zoneNum == LevelConstants.UberZoneEntId:
                 continue
             # if this is a walkable zone, fix up the model
             allColls = zoneNode.findAllMatches('**/+CollisionNode').asList()
@@ -347,9 +348,6 @@ class DistributedLevel(DistributedObject.DistributedObject,
         # make sure the ouch task is stopped
         self.stopOuch()
         
-    def getZoneNode(self, zoneNum):
-        return self.zoneNum2node.get(zoneNum)
-
     def requestReparent(self, entity, parentId):
         if __debug__:
             # some things (like cogs) are not actually entities yet;
@@ -389,8 +387,11 @@ class DistributedLevel(DistributedObject.DistributedObject,
 
             self.parent2pendingChildren[parentId].append(entity)
     
+    def getZoneNode(self, zoneEntId):
+        return self.zoneNum2node.get(zoneEntId)
+
     def showZone(self, zoneNum):
-        zone = self.zoneNum2node[zoneNum]
+        zone = self.getZoneNode(zoneNum)
         zone.unstash()
         zone.clearColor()
 
@@ -402,7 +403,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
         return self.fColorZones
 
     def hideZone(self, zoneNum):
-        zone = self.zoneNum2node[zoneNum]
+        zone = self.getZoneNode(zoneNum)
         if self.fColorZones:
             zone.unstash()
             zone.setColor(1,0,0)
@@ -414,7 +415,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
         if zone is None:
             node = self.geom
         else:
-            node = self.zoneNum2node[zone]
+            node = self.getZoneNode(zoneNum)
         node.setAlphaScale(alpha)
 
     def initVisibility(self):
@@ -423,7 +424,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
         self.curVisibleZoneNums = list2dict(self.zoneNums)
         # the UberZone is always visible, so it's not included in the
         # zones' viz lists
-        del self.curVisibleZoneNums[0]
+        del self.curVisibleZoneNums[LevelConstants.UberZoneEntId]
         # we have not entered any zone yet
         self.curZoneNum = None
 
@@ -452,7 +453,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
         # if no viz, listen to all the zones
         if not DistributedLevel.WantVisibility:
             zoneNums = list(self.zoneNums)
-            zoneNums.remove(LevelConstants.UberZoneNum)
+            zoneNums.remove(LevelConstants.UberZoneEntId)
             self.setVisibility(zoneNums)
 
         # send out any zone changes at the end of the frame, just before
@@ -527,7 +528,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
 
     def lockVisibility(self, zoneNum=None, zoneId=None):
         """call this to lock the visibility to a particular zone
-        pass in either network zoneId or model zoneNum
+        pass in either network zoneId or zoneNum
 
         this was added for battles in the HQ factories; if you engage a suit
         in zone A with your camera in zone B, and you don't call this func,
@@ -563,7 +564,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
         if zoneNum == self.curZoneNum:
             return
 
-        if zoneNum not in self.zoneNum2entId:
+        if zoneNum not in self.zoneNumDict:
             DistributedLevel.notify.error(
                 'no ZoneEntity for this zone (%s)!!' % zoneNum)
 
@@ -580,8 +581,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
         if hasattr(self, 'lockVizZone'):
             zoneNum = self.lockVizZone
             
-        zoneEntId = self.zoneNum2entId[zoneNum]
-        zoneEnt = self.getEntity(zoneEntId)
+        zoneEnt = self.getEntity(zoneNum)
         # use dicts to efficiently ensure that there are no duplicates
         visibleZoneNums = list2dict([zoneNum])
         visibleZoneNums.update(list2dict(zoneEnt.getVisibleZoneNums()))
@@ -600,7 +600,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
                     visibleZoneNums.update(list2dict([self.lastToonZone]))
 
         # we should not have the uberZone in the list at this point
-        assert not 0 in visibleZoneNums
+        assert not LevelConstants.UberZoneEntId in visibleZoneNums
         
         if DistributedLevel.HideZones:
             # figure out which zones are new and which are going invisible
@@ -640,14 +640,14 @@ class DistributedLevel(DistributedObject.DistributedObject,
         # if we're showing all zones, get all the DOs
         if self.fColorZones and DistributedLevel.ColorZonesAllDOs:
             vizList = list(self.zoneNums)
-            vizList.remove(LevelConstants.UberZoneNum)
+            vizList.remove(LevelConstants.UberZoneEntId)
         # convert the zone numbers into their actual zoneIds
         # always include Toontown and factory uberZones
-        uberZone = self.getZoneId(zoneNum=LevelConstants.UberZoneNum)
+        uberZone = self.getZoneId(LevelConstants.UberZoneEntId)
         # the level itself is in the 'level zone'
         visibleZoneIds = [ToontownGlobals.UberZone, self.levelZone, uberZone]
         for vz in vizList:
-            visibleZoneIds.append(self.getZoneId(zoneNum=vz))
+            visibleZoneIds.append(self.getZoneId(vz))
         assert(uniqueElements(visibleZoneIds))
         DistributedLevel.notify.info('new viz list: %s' % visibleZoneIds)
 
@@ -659,7 +659,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
         self.curVisibleZoneNums = list2dict(self.zoneNums)
         # the UberZone is always visible, so it's not included in the
         # zones' viz lists
-        del self.curVisibleZoneNums[0]
+        del self.curVisibleZoneNums[LevelConstants.UberZoneEntId]
         # Make sure every zone is visible
         for vz,dummy in self.curVisibleZoneNums.items():
             self.showZone(vz)
@@ -688,12 +688,10 @@ class DistributedLevel(DistributedObject.DistributedObject,
             self.levelSpec.setAttribChange(entId, attribName, value, username)
 
     def spawnTitleText(self):
-        def getDescription(zoneId, self=self):
-            entId = self.zoneNum2entId.get(zoneId)
-            if entId:
-                ent = self.entities.get(entId)
-                if ent and hasattr(ent, 'description'):
-                    return ent.description
+        def getDescription(zoneNum, self=self):
+            ent = self.entities.get(zoneNum)
+            if ent and hasattr(ent, 'description'):
+                return ent.description
             return None
 
         description = getDescription(self.lastCamZone)

+ 0 - 1
direct/src/level/EntityTypes.py

@@ -63,7 +63,6 @@ class Zone(Nodepath):
         )
     attribs = (
         ('parentEntId', 0, 'const'),
-        ('modelZoneNum', -1, 'const'),
         ('description', '', 'string'),
         ('visibility', [], 'visZoneList'),
         )

+ 10 - 20
direct/src/level/Level.py

@@ -22,9 +22,9 @@ 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
+zoneNum / zoneEntId: the number that a modeler chooses for a zone, and also
+                     the entity ID of the ZoneEntity that represents a zone
+zoneId : the network ID of a zone
 """
 
 class Level:
@@ -221,10 +221,6 @@ class Level:
         """return entId of zone that contains the entity"""
         return self.levelSpec.getEntityZoneEntId(entId)
 
-    def getEntityZoneNum(self, entId):
-        """return the model zoneNum of zone that contains the entity"""
-        return self.levelSpec.getEntityZoneNum(entId)
-
     def getEntityZoneId(self, entId):
         """return network zoneId of zone that contains the entity"""
         # this is called during entity creation on the AI; we have to
@@ -233,7 +229,7 @@ class Level:
         # entities have been instantiated.
         zoneEntId = self.getEntityZoneEntId(entId)
         # fundamental entities (levelMgr) are responsible for creating
-        # tables like 'zoneEntId2zoneId'; if those tables haven't been
+        # tables like 'zoneNum2zoneId'; if those tables haven't been
         # created yet, just return None
         if not hasattr(self, 'zoneNum2zoneId'):
             return None
@@ -241,18 +237,12 @@ class Level:
         # been created yet. this could be a problem if zone entities
         # are ever distributed. it also means that no distributed entities
         # should be created before the zone entities.
-        return self.zoneEntId2zoneId.get(zoneEntId)
-
-    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]
+        return self.zoneNum2zoneId.get(zoneEntId)
+
+    def getZoneId(self, zoneEntId):
+        """look up network zoneId by zone entId"""
+        assert zoneEntId in self.zoneNum2zoneId
+        return self.zoneNum2zoneId[zoneEntId]
 
     def getZoneNumFromId(self, zoneId):
         """returns the model zoneNum that corresponds to a network zoneId"""

+ 8 - 6
direct/src/level/LevelConstants.py

@@ -1,10 +1,12 @@
 """LevelConstants module: contains Level-related constants"""
 
-UberZoneEntId = 0
-UberZoneNum = 0
-
-LevelMgrEntId = 10
+# Zone Num from model is also the Zone Entity's entId
+MinZoneNum = 0
+MaxZoneNum = 999
 
-EditMgrEntId = 20
+# zoneNum 0 is reserved for UberZone
+UberZoneEntId = 0
 
-ZoneEntIdStart = 100
+# system-allocated entities start at 1000
+LevelMgrEntId = 1000
+EditMgrEntId  = 1001

+ 24 - 33
direct/src/level/LevelMgr.py

@@ -12,14 +12,13 @@ class LevelMgr(LevelMgrBase.LevelMgrBase):
         # load the model
         self.geom = loader.loadModel(self.modelFilename)
 
-        # modelZoneNum -> zone entId
-        self.level.zoneNum2entId = {}
-        # modelZoneNum -> network zoneId
+        # this will hold the zoneNums/entIds for our own bookkeeping
+        self.zoneNums = []
+
+        # zoneNum -> network zoneId
         self.level.zoneNum2zoneId = {}
-        # network zoneId -> modelZoneNum
+        # network zoneId -> zoneNum
         self.level.zoneId2zoneNum = {}
-        # zone entId -> network zoneId
-        self.level.zoneEntId2zoneId = {}
 
         # listen for every zone creation
         self.accept(self.level.getEntityOfTypeCreateEvent('zone'),
@@ -27,10 +26,8 @@ class LevelMgr(LevelMgrBase.LevelMgrBase):
 
     def destroy(self):
         del self.level.zoneIds
-        del self.level.zoneEntId2zoneId
         del self.level.zoneId2zoneNum
         del self.level.zoneNum2zoneId
-        del self.level.zoneNum2entId
         self.geom.removeNode()
         del self.geom
         LevelMgrBase.LevelMgrBase.destroy(self)
@@ -39,10 +36,11 @@ class LevelMgr(LevelMgrBase.LevelMgrBase):
         zoneEnt = self.level.getEntity(entId)
 
         # register the zone's info in the tables
-        # right off the bat, we have the zone's modelZoneNum and entId
-        self.level.zoneNum2entId[zoneEnt.modelZoneNum] = entId
 
-        # we can assume that we have a complete list of zoneIds in
+        assert (zoneEnt.entId not in self.zoneNums)
+        self.zoneNums.append(zoneEnt.entId)
+        
+        # we can assume that we have a complete list of network zoneIds in
         # self.level.zoneIds. As each zone entity is created, set up
         # as if we have all of the zone entities. This allows dynamic
         # zone entity creation and deletion during editing.
@@ -57,33 +55,26 @@ class LevelMgr(LevelMgrBase.LevelMgrBase):
     def handleZoneDestroy(self, entId):
         zoneEnt = self.level.getEntity(entId)
         # unregister the zone from the maps
-        del self.level.zoneNum2entId[zoneEnt.modelZoneNum]
         del self.level.zoneId2zoneNum[
-            self.level.zoneNum2zoneId[zoneEnt.modelZoneNum]]
-        del self.level.zoneNum2zoneId[zoneEnt.modelZoneNum]
-        del self.level.zoneEntId2zoneId[entId]
+            self.level.zoneNum2zoneId[zoneEnt.entId]]
+        del self.level.zoneNum2zoneId[zoneEnt.entId]
+        self.zoneNums.remove(zoneEnt.entId)
         # reassign the zoneIds (we may not need to do this, if all of the
         # other entities already have their correct zoneId...?)
         self.privAssignZoneIds()
 
     def privAssignZoneIds(self):
-        """assign zoneIds from self.level.zoneIds, according to the zones
-        that are registered so far in self.level.zoneNum2entId"""
-        # sort the model zoneNums
-        modelZoneNums = self.level.zoneNum2entId.keys()
-        modelZoneNums.sort()
+        """assign network zoneIds from self.level.zoneIds, according to
+        the zones that are registered so far"""
+        # sort the zoneNums
+        self.zoneNums.sort()
 
         # dole out the zoneIds, in increasing order of zoneNum
-        for i in range(len(modelZoneNums)):
-            zoneNum = modelZoneNums[i]
-            entId = self.level.zoneNum2entId[zoneNum]
-            zoneEnt = self.level.getEntity(entId)
-            zoneEnt.setZoneId(self.level.zoneIds[i])
-
-        # the zoneIds have shifted. update the tables
-        for entId in self.level.zoneNum2entId.values():
-            zoneEnt = self.level.getEntity(entId)
-            zoneId = zoneEnt.getZoneId()
-            self.level.zoneNum2zoneId[zoneEnt.modelZoneNum] = zoneId
-            self.level.zoneId2zoneNum[zoneId] = zoneEnt.modelZoneNum
-            self.level.zoneEntId2zoneId[entId] = zoneId
+        for i in range(len(self.zoneNums)):
+            zoneNum = self.zoneNums[i]
+            zoneEnt = self.level.getEntity(zoneNum)
+            zoneId = self.level.zoneIds[i]
+            zoneEnt.setZoneId(zoneId)
+            # the zoneIds have shifted. update the tables
+            self.level.zoneNum2zoneId[zoneNum] = zoneId
+            self.level.zoneId2zoneNum[zoneId] = zoneNum

+ 12 - 21
direct/src/level/LevelMgrAI.py

@@ -8,13 +8,9 @@ class LevelMgrAI(LevelMgrBase.LevelMgrBase):
     def __init__(self, level, entId):
         LevelMgrBase.LevelMgrBase.__init__(self, level, entId)
 
-        # modelZoneNum -> zone entId
-        self.level.zoneNum2entId = {}
-        # modelZoneNum -> network zoneId
+        # zoneNum -> network zoneId
         self.level.zoneNum2zoneId = {}
-        # zone entId -> network zoneId
-        self.level.zoneEntId2zoneId = {}
-        # list of network zoneIDs, sorted by modelZoneNum
+        # list of network zoneIDs, sorted by zoneNum
         self.level.zoneIds = []
 
         # listen for every zone creation
@@ -23,18 +19,14 @@ class LevelMgrAI(LevelMgrBase.LevelMgrBase):
 
     def destroy(self):
         del self.level.zoneIds
-        del self.level.zoneEntId2zoneId
         del self.level.zoneNum2zoneId
-        del self.level.zoneNum2entId
         LevelMgrBase.LevelMgrBase.destroy(self)
 
     def handleZoneCreated(self, entId):
         zoneEnt = self.level.getEntity(entId)
 
         # register the zone's info in the tables
-        self.level.zoneNum2entId[zoneEnt.modelZoneNum] = entId
-        self.level.zoneNum2zoneId[zoneEnt.modelZoneNum] = zoneEnt.getZoneId()
-        self.level.zoneEntId2zoneId[entId] = zoneEnt.getZoneId()
+        self.level.zoneNum2zoneId[zoneEnt.entId] = zoneEnt.getZoneId()
 
         # TODO: we should delay this until all zone entities have been
         # created on level init
@@ -46,23 +38,22 @@ class LevelMgrAI(LevelMgrBase.LevelMgrBase):
 
     def handleZoneDestroy(self, entId):
         zoneEnt = self.level.getEntity(entId)
-        # unregister the zone from the maps
-        del self.level.zoneNum2entId[zoneEnt.modelZoneNum]
-        del self.level.zoneNum2zoneId[zoneEnt.modelZoneNum]
-        del self.level.zoneEntId2zoneId[entId]
+        # unregister the zone from the tables
+        del self.level.zoneNum2zoneId[zoneEnt.entId]
         # recreate the sorted network zoneId list
         self.privCreateSortedZoneIdList()
 
     def privCreateSortedZoneIdList(self):
-        # sort the model zoneNums
-        modelZoneNums = self.level.zoneNum2entId.keys()
-        modelZoneNums.sort()
+        # sort the zoneNums
+        zoneNums = self.level.zoneNum2zoneId.keys()
+        zoneNums.sort()
 
         # create a list of network zoneIds, ordered by their corresponding
         # sorted model zoneNum values
         self.level.zoneIds = []
-        for zoneNum in modelZoneNums:
+        for zoneNum in zoneNums:
             self.level.zoneIds.append(self.level.zoneNum2zoneId[zoneNum])
 
-        # TODO: if we just added or removed a zone entity AFTER the level
-        # was initialized, we need to re-send the zoneId list
+        # TODO: if we ever allow dynamic insertion and removal of zone
+        # entities, and we just added or removed a zone entity AFTER the level
+        # was initialized, we would need to re-send the zoneId list

+ 5 - 20
direct/src/level/LevelSpec.py

@@ -63,8 +63,6 @@ class LevelSpec:
                 # UberZone
                 entId = LevelConstants.UberZoneEntId
                 self.insertEntity(entId, 'zone')
-                self.doSetAttrib(entId, 'modelZoneNum',
-                                 LevelConstants.UberZoneNum)
                 self.doSetAttrib(entId, 'name', 'UberZone')
                 # LevelMgr
                 entId = LevelConstants.LevelMgrEntId
@@ -121,12 +119,6 @@ class LevelSpec:
         # keep looking up the heirarchy for a zone entity
         return self.getEntityZoneEntId(spec['parentEntId'])
 
-    def getEntityZoneNum(self, entId):
-        """ return the model zoneNum of zone that contains the entity """
-        zoneEntId = self.getEntityZoneEntId(entId)
-        spec = self.getEntitySpec(zoneEntId)
-        return spec['modelZoneNum']
-
     def getEntType2ids(self, entIds):
         """given list of entIds, return dict of entType 2 entIds"""
         entType2ids = {}
@@ -144,7 +136,7 @@ class LevelSpec:
         return self.specDict['scenarios'][scenario][0]
 
     def printZones(self):
-        """currently prints list of modelZoneNum->zone name"""
+        """currently prints list of zoneNum->zone name"""
         # this could be more efficient
         allIds = self.getAllEntIds()
         type2id = self.getEntType2ids(allIds)
@@ -152,17 +144,10 @@ class LevelSpec:
         # omit the UberZone
         if 0 in zoneIds:
             zoneIds.remove(0)
-        # need to sort the zones by modelZoneNum
-        zoneNum2zoneId = {}
-        for id in zoneIds:
-            spec = self.getEntitySpec(id)
-            zoneNum2zoneId[spec['modelZoneNum']] = id
-        modelZoneNums = zoneNum2zoneId.keys()
-        modelZoneNums.sort()
-        for zoneNum in modelZoneNums:
-            id = zoneNum2zoneId[zoneNum]
-            spec = self.getEntitySpec(id)
-            print 'zone %s : %s' % (spec['modelZoneNum'], spec['name'])
+        zoneIds.sort()
+        for zoneNum in zoneIds:
+            spec = self.getEntitySpec(zoneNum)
+            print 'zone %s : %s' % (zoneNum, spec['name'])
 
     if __dev__:
         def setLevel(self, level):

+ 14 - 1
direct/src/level/LevelUtil.py

@@ -1,6 +1,7 @@
 """LevelUtil module: contains Level utility funcs"""
 
 import string
+import LevelConstants
 
 def getZoneNum2Node(levelModel):
     """ given model, returns dict of ZoneNumber -> ZoneNode """
@@ -24,15 +25,27 @@ def getZoneNum2Node(levelModel):
             if numDigits == 0:
                 continue
             num = int(name[:numDigits])
+            # is this a valid zoneNum?
+            if num == LevelConstants.UberZoneEntId:
+                print ('warning: cannot use UberZone zoneNum (%s). '
+                       'ignoring %s' % (LevelConstants.UberZoneEntId,
+                                        potentialNode))
+                continue
+            if (num < LevelConstants.MinZoneNum) or (
+                num > LevelConstants.MaxZoneNum):
+                print 'warning: zone %s is out of range. ignoring %s' % (
+                    num, potentialNode)
+                continue
             # do we already have a ZoneNode for this zone num?
             if num in num2node:
                 print 'warning: zone %s already assigned to %s. ignoring %s' % (
                     num, num2node[num], potentialNode)
+                continue
             num2node[num] = potentialNode
 
         return num2node
 
     zoneNum2node = findNumberedNodes('zone', levelModel)
     # add the UberZone to the table
-    zoneNum2node[0] = levelModel
+    zoneNum2node[LevelConstants.UberZoneEntId] = levelModel
     return zoneNum2node

+ 14 - 35
direct/src/level/SpecUtil.py

@@ -74,8 +74,8 @@ def privUpdateSpec(spec, modelPath, entTypeModule, newZonesGloballyVisible=0):
     assert model is not None
     TexturePool.clearFakeTextureImage()
     # get the model's zone info
-    modelZoneNum2node = LevelUtil.getZoneNum2Node(model)
-    modelZoneNums = modelZoneNum2node.keys()
+    zoneNum2node = LevelUtil.getZoneNum2Node(model)
+    zoneNums = zoneNum2node.keys()
 
     # what zone entities do we have specs for?
     type2ids = spec.getEntType2ids(spec.getAllEntIds())
@@ -86,50 +86,29 @@ def privUpdateSpec(spec, modelPath, entTypeModule, newZonesGloballyVisible=0):
         spec.removeEntity(entId)
         zoneEntIds.remove(entId)
 
-    def insertZoneEntity(entId, modelZoneNum, spec=spec, zoneEntIds=zoneEntIds):
-        spec.insertEntity(entId, 'zone', LevelConstants.UberZoneEntId)
-        spec.doSetAttrib(entId, 'name', 'zone%s' % modelZoneNum)
-        spec.doSetAttrib(entId, 'modelZoneNum', modelZoneNum)
-        zoneEntIds.append(entId)
-
-    # create dict of zoneNum -> entId
-    zoneNum2entId = {}
-    for entId in list(zoneEntIds):
-        zoneNum = spec.getEntitySpec(entId)['modelZoneNum']
-        if zoneNum in zoneNum2entId:
-            print ('multiple zone entities reference zoneNum %s; removing '
-                   'entity %s' % (zoneNum, entId))
-            removeZoneEntity(entId)
-            continue
-        zoneNum2entId[zoneNum] = entId
+    def insertZoneEntity(zoneNum, spec=spec, zoneEntIds=zoneEntIds):
+        spec.insertEntity(zoneNum, 'zone', LevelConstants.UberZoneEntId)
+        spec.doSetAttrib(zoneNum, 'name', 'zone%s' % zoneNum)
+        zoneEntIds.append(zoneNum)
 
     # prune zone entities that reference zones that no longer exist
     removedZoneNums = []
     for entId in list(zoneEntIds):
-        zoneNum = spec.getEntitySpec(entId)['modelZoneNum']
-        if zoneNum not in modelZoneNums:
-            print 'zone %s no longer exists; removing entity %s' % (
-                zoneNum, entId)
+        if entId not in zoneNums:
+            print 'zone %s no longer exists; removing' % entId
             removeZoneEntity(entId)
-            del zoneNum2entId[zoneNum]
-            removedZoneNums.append(zoneNum)
+            removedZoneNums.append(entId)
             
     # add new zone entities for new zones
     newZoneNums = []
-    for zoneNum in modelZoneNums:
-        if zoneNum not in zoneNum2entId:
+    for zoneNum in zoneNums:
+        if zoneNum not in zoneEntIds:
             newZoneNums.append(zoneNum)
 
-            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)
-            insertZoneEntity(entId, zoneNum)
+            print 'adding new zone entity %s' % zoneNum
+            insertZoneEntity(zoneNum)
             # by default, new zone can't see any other zones
-            spec.doSetAttrib(entId, 'visibility', [])
+            spec.doSetAttrib(zoneNum, 'visibility', [])
 
     if newZonesGloballyVisible:
         for entId in zoneEntIds:

+ 3 - 3
direct/src/level/ZoneEntity.py

@@ -7,12 +7,12 @@ class ZoneEntity(ZoneEntityBase.ZoneEntityBase, BasicEntities.NodePathAttribs):
     def __init__(self, level, entId):
         ZoneEntityBase.ZoneEntityBase.__init__(self, level, entId)
 
-        self.nodePath = self.level.getZoneNode(self.modelZoneNum)
+        self.nodePath = self.level.getZoneNode(self.entId)
         if __dev__:
             if self.nodePath is None:
                 self.level.reportModelSpecSyncError(
-                    'unknown modelZoneNum %s; zone was removed from model?' %
-                    self.modelZoneNum)
+                    'unknown zoneNum %s; zone was removed from model?' %
+                    self.entId)
         BasicEntities.NodePathAttribs.initNodePathAttribs(self, doReparent=0)
 
         # dict of zoneNum to 'visible' reference count

+ 2 - 2
direct/src/level/ZoneEntityBase.py

@@ -24,5 +24,5 @@ class ZoneEntityBase(Entity.Entity):
         return self.zoneId
 
     def getZoneNum(self):
-        """zoneNum from model"""
-        return self.modelZoneNum
+        """zoneNum from model / entityId"""
+        return self.entId