Browse Source

added EntrancePoint entity, extended entity NodePath support

Darren Ranalli 22 years ago
parent
commit
5a0a536ef5

+ 83 - 73
direct/src/level/BasicEntities.py

@@ -4,11 +4,12 @@ import Entity
 import DistributedEntity
 import NodePath
 
-# this is an abstract class, do not instantiate.
-class NodePathAttribs:
-    """Derive from this class to give an entity the behavior of a
-    NodePath, without necessarily deriving from NodePath. Derived class
-    must implement getNodePath()."""
+# base class for entities that support NodePath attributes
+# *** Don't derive directly from this class; derive from the appropriate
+# specialized class from the classes defined below.
+class NodePathEntityBase:
+    # we don't call this __init__ because it doesn't have to be called
+    # upon object init
     def initNodePathAttribs(self, doReparent=1):
         """Call this after the entity has been initialized"""
         self.callSetters('pos','x','y','z',
@@ -17,9 +18,64 @@ class NodePathAttribs:
         if doReparent:
             self.callSetters('parentEntId')
 
+        self.getNodePath().setName('%s-%s' %
+                                   (self.__class__.__name__, self.entId))
+
         if __debug__:
+            # for the editor
             self.getNodePath().setTag('entity', '1')
 
+    def setParentEntId(self, parentEntId):
+        self.parentEntId = parentEntId
+        self.level.requestReparent(self, self.parentEntId)
+
+    def destroy(self):
+        if __debug__:
+            # for the editor
+            self.getNodePath().clearTag('entity')
+
+# Entities that already derive from NodePath and Entity should derive
+# from this class
+class NodePathAttribs(NodePathEntityBase):
+    def initNodePathAttribs(self, doReparent=1):
+        NodePathEntityBase.initNodePathAttribs(self, doReparent)
+
+    def destroy(self):
+        NodePathEntityBase.destroy(self)
+
+    def getNodePath(self):
+        return self
+
+# Entities that already derive from Entity, and do not derive from NodePath,
+# but want to be a NodePath, should derive from this.
+class NodePathAndAttribs(NodePathEntityBase, NodePath.NodePath):
+    def __init__(self):
+        node = hidden.attachNewNode('EntityNodePath')
+        NodePath.NodePath.__init__(self, node)
+
+    def initNodePathAttribs(self, doReparent=1):
+        NodePathEntityBase.initNodePathAttribs(self, doReparent)
+
+    def destroy(self):
+        NodePathEntityBase.destroy(self)
+        self.removeNode()
+
+    def getNodePath(self):
+        return self
+        
+# Entities that already derive from Entity, and do not derive from NodePath,
+# but HAVE a NodePath that they want to represent them, should derive from
+# this. They must define getNodePath(), which should return their 'proxy'
+# NodePath instance.
+class NodePathAttribsProxy(NodePathEntityBase):
+    def initNodePathAttribs(self, doReparent=1):
+        """Call this after the entity has been initialized"""
+        NodePathEntityBase.initNodePathAttribs(self, doReparent)
+        assert self.getNodePath() != self
+
+    def destroy(self):
+        NodePathEntityBase.destroy(self)
+
     def setPos(self, *args): self.getNodePath().setPos(*args)
     def setX(self, *args): self.getNodePath().setX(*args)
     def setY(self, *args): self.getNodePath().setY(*args)
@@ -37,85 +93,39 @@ class NodePathAttribs:
     
     def reparentTo(self, *args): self.getNodePath().reparentTo(*args)
 
-    def setParentEntId(self, parentEntId):
-        self.parentEntId = parentEntId
-        self.level.requestReparent(self, self.parentEntId)
-
-# this is an abstract class, do not instantiate.
-class NodePathSelfAttribs:
-    """Derive from this class to give an entity that is already a Nodepath
-    the behavior of a NodePathEntity, with ability to reparent and be
-    picked from the Direct/FactoryEditor interface"""
-    def initNodePathSelfAttribs(self):
-        if __debug__:
-            self.setTag('entity', '1')
-        self.callSetters('parentEntId')
-            
-    def setParentEntId(self, parentEntId):
-        self.parentEntId = parentEntId
-        self.level.requestReparent(self, self.parentEntId)
-
-
-class privNodePathImpl(NodePath.NodePath):
-    def __init__(self, name):
-        node = hidden.attachNewNode(name)
-        NodePath.NodePath.__init__(self, node)
-        if __debug__:
-            self.setTag('entity', '1')
-
-    def initNodePathAttribs(self):
-        """Call this after the entity has been initialized, and all
-        of its attributes have been set"""
-        self.callSetters('pos','x','y','z',
-                         'hpr','h','p','r',
-                         'scale','sx','sy','sz',
-                         'parentEntId')
-        
-    def setParentEntId(self, parentEntId):
-        self.parentEntId = parentEntId
-        self.level.requestReparent(self.getNodePath(), self.parentEntId)
-
-    def destroy(self):
-        if __debug__:
-            self.clearTag('entity')
-        self.removeNode()
-
-    def getNodePath(self):
-        return self
-
-class NodePathEntity(Entity.Entity, privNodePathImpl):
-    """This is an entity that represents a NodePath on the client.
-    It may be instantiated directly or used as a base class for other
-    entity types."""
+# This is an entity that represents a NodePath on the client.
+# It may be instantiated directly or used as a base class for other
+# entity types that 'are' NodePaths.
+class NodePathEntity(Entity.Entity, NodePath.NodePath, NodePathAttribs):
     def __init__(self, level, entId):
-        privNodePathImpl.__init__(self, '')
+        node = hidden.attachNewNode('NodePathEntity')
+        NodePath.NodePath.__init__(self, node)
         Entity.Entity.__init__(self, level, entId)
-        self.setName(str(self))
-        privNodePathImpl.initNodePathAttribs(self)
+        NodePathAttribs.initNodePathAttribs(self)
 
     def destroy(self):
+        NodePathAttribs.destroy(self)
         Entity.Entity.destroy(self)
-        privNodePathImpl.destroy(self)
-
-    def getNodePath(self):
-        return self
+        self.removeNode()
 
+# This is a distributed version of NodePathEntity. It should not
+# be instantiated directly; distributed entities that are also NodePaths
+# may derive from this instead of DistributedEntity.
 class DistributedNodePathEntity(DistributedEntity.DistributedEntity,
-                                privNodePathImpl):
-    """This is a distributed version of NodePathEntity. It should not
-    be instantiated directly; derive your client-side distEntity from
-    this class instead of DistributedEntity."""
+                                NodePath.NodePath, NodePathAttribs):
     def __init__(self, cr):
         DistributedEntity.DistributedEntity.__init__(self, cr)
-        privNodePathImpl.__init__(self, 'DistributedNodePathEntity')
+        node = hidden.attachNewNode('DistributedNodePathEntity')
+        NodePath.NodePath.__init__(self, node)
 
     def announceGenerate(self):
         DistributedEntity.DistributedEntity.announceGenerate(self)
-        privNodePathImpl.initNodePathAttribs(self)
+        NodePathAttribs.initNodePathAttribs(self)
         
-    def destroy(self):
-        DistributedEntity.DistributedEntity.destroy(self)
-        privNodePathImpl.destroy(self)
+    def disable(self):
+        NodePathAttribs.destroy(self)
+        DistributedEntity.DistributedEntity.disable(self)
 
-    def getNodePath(self):
-        return self
+    def delete(self):
+        self.removeNode()
+        DistributedEntity.DistributedEntity.delete(self)

+ 23 - 0
direct/src/level/DistributedLevel.py

@@ -81,6 +81,16 @@ class DistributedLevel(DistributedObject.DistributedObject,
         # zone the entire time we're in here
         self.levelZone = zoneId
 
+    def setPlayerIds(self, avIdList):
+        self.avIdList = avIdList
+        assert toonbase.localToon.doId in self.avIdList
+
+    def setEntranceId(self, entranceId):
+        self.entranceId = entranceId
+
+    def getEntranceId(self):
+        return self.entranceId
+
     # "required" fields (these ought to be required fields, but
     # the AI level obj doesn't know the data values until it has been
     # generated.)
@@ -168,6 +178,19 @@ class DistributedLevel(DistributedObject.DistributedObject,
         # load stuff
         self.initVisibility()
 
+        self.placeLocalToon()
+
+    def placeLocalToon(self):
+        # the entrancePoint entities register themselves with us
+        if self.entranceId not in self.entranceId2entity:
+            self.notify.warning('unknown entranceId %s' % self.entranceId)
+            toonbase.localToon.setPos(0,0,0)
+        else:
+            epEnt = self.entranceId2entity[self.entranceId]
+            epEnt.placeToon(toonbase.localToon,
+                            self.avIdList.index(toonbase.localToon.doId),
+                            len(self.avIdList))
+
     def createEntityCreator(self):
         """Create the object that will be used to create Entities.
         Inheritors, override if desired."""

+ 17 - 2
direct/src/level/DistributedLevelAI.py

@@ -13,11 +13,20 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
     """DistributedLevelAI"""
     notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevelAI')
 
-    def __init__(self, air, zoneId):
+    def __init__(self, air, zoneId, entranceId, avIds):
         DistributedObjectAI.DistributedObjectAI.__init__(self, air)
         Level.Level.__init__(self)
-        # this is one of the required fields
+        # these are required fields
         self.zoneId = zoneId
+        self.entranceId = entranceId
+
+        assert len(avIds) > 0 and len(avIds) <= 4
+        assert 0 not in avIds
+        assert None not in avIds
+        self.avIdList = avIds
+        self.numPlayers = len(self.avIdList)
+        self.notify.debug("expecting avatars: %s" % str(self.avIdList))
+
         if __debug__:
             self.modified = 0
 
@@ -37,6 +46,12 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
         same zone with the level"""
         return self.zoneId
 
+    def getPlayerIds(self):
+        return self.avIdList
+
+    def getEntranceId(self):
+        return self.entranceId
+
     def delete(self):
         self.notify.debug('delete')
         if __debug__:

+ 4 - 0
direct/src/level/Entity.py

@@ -38,6 +38,10 @@ class Entity(DirectObject):
         del self.level
         del self.entId
         
+    def getZoneEntId(self):
+        """returns entId of zone that contains this entity"""
+        return self.level.getEntityZoneEntId(self.entId)
+
     def privGetSetter(self, attrib):
         setFuncName = 'set%s%s' % (string.upper(attrib[0]), attrib[1:])
         if hasattr(self, setFuncName):

+ 4 - 1
direct/src/level/EntityCreator.py

@@ -5,6 +5,7 @@ import EntityCreatorBase
 import BasicEntities
 import DirectNotifyGlobal
 import EditMgr
+import EntrancePoint
 import LevelMgr
 import ZoneEntity
 import ModelEntity
@@ -14,7 +15,8 @@ import PathEntity
 # ctor functions must take (level, entId)
 # and they must return the entity that was created, or 'nothing'
 def nothing(*args):
-    """For entities that don't need to be created by the client"""
+    """For entities that don't need to be created by the client or don't
+    exist on the client at all"""
     return 'nothing'
 
 class EntityCreator(EntityCreatorBase.EntityCreatorBase):
@@ -29,6 +31,7 @@ class EntityCreator(EntityCreatorBase.EntityCreatorBase):
         self.privRegisterTypes({
             'cutScene': CutScene.CutScene,
             'editMgr': EditMgr.EditMgr,
+            'entrancePoint': EntrancePoint.EntrancePoint,
             'levelMgr': LevelMgr.LevelMgr,
             'logicGate': nothing,
             'model' : ModelEntity.ModelEntity,

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

@@ -46,6 +46,7 @@ class EntityCreatorAI(EntityCreatorBase.EntityCreatorBase):
         self.privRegisterTypes({
             'cutScene': nothing,
             'editMgr': Functor(cLE, EditMgrAI.EditMgrAI),
+            'entrancePoint': nothing,
             'levelMgr': Functor(cLE, LevelMgrAI.LevelMgrAI),
             'logicGate': Functor(cLE, LogicGateAI.LogicGateAI),
             'model' : nothing,

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

@@ -53,6 +53,12 @@ class Zone(Nodepath):
         ('visibility', [], 'visZoneList'),
         )
 
+class EntrancePoint(Nodepath):
+    type = 'entrancePoint'
+    attribs = (
+        ('entranceId', -1, 'int'),
+        )
+
 class LogicGate(Entity):
     type = 'logicGate'
     output = 'bool'

+ 31 - 0
direct/src/level/EntrancePoint.py

@@ -0,0 +1,31 @@
+from ToontownGlobals import *
+import DirectNotifyGlobal
+import BasicEntities
+import NodePath
+
+class EntrancePoint(BasicEntities.NodePathEntity):
+    def __init__(self, level, entId):
+        BasicEntities.NodePathEntity.__init__(self, level, entId)
+        self.initEntrancePoint()
+
+    def destroy(self):
+        self.destroyEntrancePoint()
+        BasicEntities.NodePathEntity.destroy(self)
+
+    def placeToon(self, toon, toonIndex, numToons):
+        toon.setPosHpr(self, 0,0,0, 0,0,0)
+
+    def initEntrancePoint(self):
+        if self.entranceId >= 0:
+            self.level.entranceId2entity[self.entranceId] = self
+
+    def destroyEntrancePoint(self):
+        if self.entranceId >= 0:
+            if self.level.entranceId2entity.has_key(self.entranceId):
+                del self.level.entranceId2entity[self.entranceId]
+
+    if __debug__:
+        def attribChanged(self, *args):
+            BasicEntities.NodePathEntity.attribChanged(self, *args)
+            self.destroyEntrancePoint()
+            self.initEntrancePoint()

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

@@ -53,6 +53,9 @@ class Level:
         self.entType2ids = self.levelSpec.getEntType2ids(
             self.levelSpec.getAllEntIds())
 
+        # entranceId to entrance entity
+        self.entranceId2entity = {}
+
         # this list contains the entIds of entities that we have actually
         # created, in order of creation
         self.createdEntIds = []
@@ -198,6 +201,19 @@ class Level:
     def getEntityType(self, entId):
         return self.levelSpec.getEntityType(entId)
 
+    def getEntityZoneEntId(self, entId):
+        """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"""
+        zoneEntId = self.getEntityZoneEntId(entId)
+        return self.zoneEntId2zoneId[entId]
+
     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)

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

@@ -103,6 +103,26 @@ class LevelSpec:
     def getEntityType(self, entId):
         return self.getEntitySpec(entId)['type']
 
+    def getEntityZoneEntId(self, entId):
+        """ return the entId of the zone that entity is in; if entity
+        is a zone, returns its entId """
+        spec = self.getEntitySpec(entId)
+        type = spec['type']
+        # 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.getEntityZoneId(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 = {}

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

@@ -8,7 +8,11 @@ class ZoneEntity(ZoneEntityBase.ZoneEntityBase, BasicEntities.NodePathAttribs):
         ZoneEntityBase.ZoneEntityBase.__init__(self, level, entId)
 
         self.nodePath = self.level.getZoneNode(self.modelZoneNum)
-        self.initNodePathAttribs(doReparent=0)
+        BasicEntities.NodePathAttribs.initNodePathAttribs(self, doReparent=0)
+
+    def destroy(self):
+        BasicEntities.NodePathAttribs.destroy(self)
+        ZoneEntityBase.ZoneEntityBase.destroy(self)
 
     def getNodePath(self):
         return self.nodePath