Kaynağa Gözat

added VisibilityExtender

Darren Ranalli 22 yıl önce
ebeveyn
işleme
c268773ab4

+ 5 - 5
direct/src/level/DistributedLevel.py

@@ -330,7 +330,7 @@ class DistributedLevel(DistributedObject.DistributedObject,
     
     def showZone(self, zoneNum):
         zone = self.zoneNum2node[zoneNum]
-        zone.show()
+        zone.unstash()
         zone.clearColor()
 
     def setColorZones(self, fColorZones):
@@ -339,10 +339,10 @@ class DistributedLevel(DistributedObject.DistributedObject,
     def hideZone(self, zoneNum):
         zone = self.zoneNum2node[zoneNum]
         if self.fColorZones:
-            zone.show()
+            zone.unstash()
             zone.setColor(1,0,0)
         else:
-            zone.hide()
+            zone.stash()
 
     def setTransparency(self, alpha, zone=None):
         self.geom.setTransparency(1)
@@ -418,10 +418,10 @@ class DistributedLevel(DistributedObject.DistributedObject,
             zoneNum = self.curZoneNum
             
         zoneEntId = self.zoneNum2entId[zoneNum]
-        zoneSpec = self.levelSpec.getEntitySpec(zoneEntId)
+        zoneEnt = self.getEntity(zoneEntId)
         # use dicts to efficiently ensure that there are no duplicates
         visibleZoneNums = list2dict([zoneNum])
-        visibleZoneNums.update(list2dict(zoneSpec['visibility']))
+        visibleZoneNums.update(list2dict(zoneEnt.getVisibleZoneNums()))
 
         # we should not have the uberZone in the list at this point
         assert not 0 in visibleZoneNums

+ 0 - 21
direct/src/level/DistributedLevelAI.py

@@ -83,27 +83,6 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
         Inheritors, override if desired."""
         return EntityCreatorAI.EntityCreatorAI(level=self)
 
-    def getEntityZoneId(self, entId):
-        """figure out what network zoneId an entity is in"""
-        # 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.levelSpec.getEntitySpec(entId)
-        type = spec['type']
-        if type == 'zone':
-            if not hasattr(self, 'zoneNum2zoneId'):
-                # we haven't even started creating our zone entities yet;
-                # we have no idea yet which zoneNums map to which
-                # network zoneIds. just return None.
-                return None
-            # If the entity *is* the zone, it will not yet be in the
-            # table; but since zone entities are currently not distributed,
-            # it's fine to return None.
-            return self.zoneNum2zoneId.get(spec['modelZoneNum'])
-        if not spec.has_key('parentEntId'):
-            return None
-        return self.getEntityZoneId(spec['parentEntId'])
-
     if __debug__:
         # level editors should call this func to tweak attributes of level
         # entities

+ 2 - 0
direct/src/level/EntityCreator.py

@@ -10,6 +10,7 @@ import LevelMgr
 import ZoneEntity
 import ModelEntity
 import PathEntity
+import VisibilityExtender
 
 # some useful constructor functions
 # ctor functions must take (level, entId)
@@ -37,6 +38,7 @@ class EntityCreator(EntityCreatorBase.EntityCreatorBase):
             'model' : ModelEntity.ModelEntity,
             'nodepath': BasicEntities.NodePathEntity,
             'path' : PathEntity.PathEntity,
+            'visibilityExtender': VisibilityExtender.VisibilityExtender,
             'zone': ZoneEntity.ZoneEntity,
             })
 

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

@@ -52,6 +52,7 @@ class EntityCreatorAI(EntityCreatorBase.EntityCreatorBase):
             'model' : nothing,
             'nodepath': nothing,
             'path': nothing,
+            'visibilityExtender': nothing,
             'zone': Functor(cLE, ZoneEntityAI.ZoneEntityAI),
             })
 

+ 8 - 3
direct/src/level/EntityTypes.py

@@ -10,6 +10,7 @@ class Entity(EntityTypeDesc):
         ('type', None),
         ('name', '<unnamed>', 'string'),
         ('comment', '', 'string'),
+        ('parentEntId', 0, 'entId', {'type':'nodepath'}),
         )
 
 class LevelMgr(Entity):
@@ -39,7 +40,6 @@ class EditMgr(Entity):
 class Nodepath(Entity):
     type = 'nodepath'
     attribs = (
-        ('parentEntId', 0, 'entId', {'type':'nodepath'}),
         ('pos', Point3(0,0,0), 'pos'),
         ('hpr', Vec3(0,0,0), 'hpr'),
         )
@@ -48,7 +48,6 @@ class Zone(Nodepath):
     type = 'zone'
     permanent = 1
     delAttribs = (
-        'parentEntId',
         'pos',
         'hpr',
         )
@@ -101,4 +100,10 @@ class Path(Nodepath):
         ('scale', 1, 'pos'),
         ('pathIndex', 0, 'int'),
         )
-    
+
+class VisibilityExtender(Entity):
+    type = 'visibilityExtender'
+    attribs = (
+        ('event', None, 'entId', {'output':'bool'}),
+        ('newZones', [], 'visZoneList'),
+        )

+ 16 - 1
direct/src/level/Level.py

@@ -195,6 +195,8 @@ class Level:
             entity.setAttribInit(key, value)
 
         # entity is initialized, add it to the list of entities
+        # if this assert fails, check distributed entities to make sure
+        # they're calling down to Entity.destroy
         assert not entId in self.entities
         self.entities[entId] = entity
 
@@ -214,8 +216,21 @@ class Level:
 
     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
+        # handle this carefully, since the information required to
+        # produce a zoneId is not available until the level's zone
+        # entities have been instantiated.
         zoneEntId = self.getEntityZoneEntId(entId)
-        return self.zoneEntId2zoneId[entId]
+        # fundamental entities (levelMgr) are responsible for creating
+        # tables like 'zoneEntId2zoneId'; if those tables haven't been
+        # created yet, just return None
+        if not hasattr(self, 'zoneNum2zoneId'):
+            return None
+        # this might return None if all of our zone entities haven't
+        # 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"""

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

@@ -111,9 +111,6 @@ class LevelSpec:
         # if it's a zone, this is our entity
         if type == 'zone':
             return entId
-        # if we have no parentEntId, assume we're in the UberZone
-        if not spec.has_key('parentEntId'):
-            return LevelConstants.UberZoneEntId
         # keep looking up the heirarchy for a zone entity
         return self.getEntityZoneEntId(spec['parentEntId'])
 
@@ -188,8 +185,7 @@ class LevelSpec:
             for name, desc in attribDescs.items():
                 spec[name] = desc.getDefaultValue()
             spec['type'] = entType
-            if 'parentEntId' in spec:
-                spec['parentEntId'] = parentEntId
+            spec['parentEntId'] = parentEntId
 
             if self.hasLevel():
                 # notify the level

+ 59 - 0
direct/src/level/VisibilityExtender.py

@@ -0,0 +1,59 @@
+"""VisibilityExtender module: contains the VisibilityExtender class"""
+
+import Entity
+
+class VisibilityExtender(Entity.Entity):
+    def __init__(self, level, entId):
+        Entity.Entity.__init__(self, level, entId)
+        self.initVisExt()
+
+    def initVisExt(self):
+        self.extended = 0
+        self.zoneEntId = self.getZoneEntId()
+        self.eventName = 'switch-%s' % self.event
+        self.accept(self.eventName, self.handleEvent)
+
+    def destroyVisExt(self):
+        self.ignore(self.eventName)
+        if self.extended:
+            self.retract()
+
+    def handleEvent(self, doExtend):
+        if doExtend:
+            if not self.extended:
+                self.extend()
+        else:
+            if self.extended:
+                self.retract()
+
+    def extend(self):
+        """extend the visibility list"""
+        assert not self.extended
+        zoneEnt = self.level.getEntity(self.getZoneEntId())
+        zoneEnt.incrementRefCounts(self.newZones)
+        self.extended = 1
+        self.level.handleVisChange()
+        
+    def retract(self):
+        """un-extend the visibility list"""
+        assert self.extended
+        zoneEnt = self.level.getEntity(self.getZoneEntId())
+        zoneEnt.decrementRefCounts(self.newZones)
+        self.extended = 0
+        self.level.handleVisChange()
+
+    def destroy(self):
+        self.destroyVisExt()
+        Entity.Entity.destroy(self)
+
+    if __debug__:
+        def setNewZones(self, newZones):
+            # we need to call destroyVisExt before accepting the new
+            # zone set
+            self.destroyVisExt()
+            self.newZones = newZones
+            self.initVisExt()
+            
+        def attribChanged(self, *args):
+            self.destroyVisExt()
+            self.initVisExt()

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

@@ -10,13 +10,40 @@ class ZoneEntity(ZoneEntityBase.ZoneEntityBase, BasicEntities.NodePathAttribs):
         self.nodePath = self.level.getZoneNode(self.modelZoneNum)
         BasicEntities.NodePathAttribs.initNodePathAttribs(self, doReparent=0)
 
+        # dict of zoneNum to 'visible' reference count
+        self.visibleZoneNums = {}
+
+        # inc ref counts for the zones that are always visible from this zone
+        self.incrementRefCounts(self.visibility)
+
     def destroy(self):
+        # no need to dec our reference counts
         BasicEntities.NodePathAttribs.destroy(self)
         ZoneEntityBase.ZoneEntityBase.destroy(self)
 
     def getNodePath(self):
         return self.nodePath
 
-    def setVisibility(self, visibility):
-        self.visibility = visibility
-        self.level.handleVisChange()
+    def getVisibleZoneNums(self):
+        return self.visibleZoneNums.keys()
+
+    # call these with lists of zoneNums to increment or decrement their
+    # 'visible' reference counts
+    # zone is visible as long as its ref count is nonzero
+    def incrementRefCounts(self, zoneNumList):
+        for zoneNum in zoneNumList:
+            self.visibleZoneNums.setdefault(zoneNum, 0)
+            self.visibleZoneNums[zoneNum] += 1
+    def decrementRefCounts(self, zoneNumList):
+        for zoneNum in zoneNumList:
+            self.visibleZoneNums[zoneNum] -= 1
+            if self.visibleZoneNums[zoneNum] == 0:
+                del self.visibleZoneNums[zoneNum]
+
+    if __debug__:
+        def setVisibility(self, visibility):
+            self.decrementRefCounts(self.visibility)
+            self.visibility = visibility
+            self.incrementRefCounts(self.visibility)
+
+            self.level.handleVisChange()