From c268773ab403e3415b6c438e900180176ec249fb Mon Sep 17 00:00:00 2001 From: Darren Ranalli Date: Sat, 8 Nov 2003 23:19:29 +0000 Subject: [PATCH] added VisibilityExtender --- direct/src/level/DistributedLevel.py | 10 ++--- direct/src/level/DistributedLevelAI.py | 21 --------- direct/src/level/EntityCreator.py | 2 + direct/src/level/EntityCreatorAI.py | 1 + direct/src/level/EntityTypes.py | 11 +++-- direct/src/level/Level.py | 17 +++++++- direct/src/level/LevelSpec.py | 6 +-- direct/src/level/VisibilityExtender.py | 59 ++++++++++++++++++++++++++ direct/src/level/ZoneEntity.py | 33 ++++++++++++-- 9 files changed, 122 insertions(+), 38 deletions(-) create mode 100755 direct/src/level/VisibilityExtender.py diff --git a/direct/src/level/DistributedLevel.py b/direct/src/level/DistributedLevel.py index a954816829..28da290c71 100755 --- a/direct/src/level/DistributedLevel.py +++ b/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 diff --git a/direct/src/level/DistributedLevelAI.py b/direct/src/level/DistributedLevelAI.py index 751bb8448b..d48475af73 100755 --- a/direct/src/level/DistributedLevelAI.py +++ b/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 diff --git a/direct/src/level/EntityCreator.py b/direct/src/level/EntityCreator.py index a35902611d..7175136413 100755 --- a/direct/src/level/EntityCreator.py +++ b/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, }) diff --git a/direct/src/level/EntityCreatorAI.py b/direct/src/level/EntityCreatorAI.py index af53a374ff..c7eeb81848 100755 --- a/direct/src/level/EntityCreatorAI.py +++ b/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), }) diff --git a/direct/src/level/EntityTypes.py b/direct/src/level/EntityTypes.py index b4549cd3d1..199bfe4670 100755 --- a/direct/src/level/EntityTypes.py +++ b/direct/src/level/EntityTypes.py @@ -10,6 +10,7 @@ class Entity(EntityTypeDesc): ('type', None), ('name', '', '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'), + ) diff --git a/direct/src/level/Level.py b/direct/src/level/Level.py index cb0d13f798..d4efc43c2d 100755 --- a/direct/src/level/Level.py +++ b/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""" diff --git a/direct/src/level/LevelSpec.py b/direct/src/level/LevelSpec.py index e74db10c66..f379aae5b2 100755 --- a/direct/src/level/LevelSpec.py +++ b/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 diff --git a/direct/src/level/VisibilityExtender.py b/direct/src/level/VisibilityExtender.py new file mode 100755 index 0000000000..65ff63fc57 --- /dev/null +++ b/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() diff --git a/direct/src/level/ZoneEntity.py b/direct/src/level/ZoneEntity.py index 7b2eaa3595..845a8393cb 100755 --- a/direct/src/level/ZoneEntity.py +++ b/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()