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 DistributedEntity
 import NodePath
 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):
     def initNodePathAttribs(self, doReparent=1):
         """Call this after the entity has been initialized"""
         """Call this after the entity has been initialized"""
         self.callSetters('pos','x','y','z',
         self.callSetters('pos','x','y','z',
@@ -17,9 +18,64 @@ class NodePathAttribs:
         if doReparent:
         if doReparent:
             self.callSetters('parentEntId')
             self.callSetters('parentEntId')
 
 
+        self.getNodePath().setName('%s-%s' %
+                                   (self.__class__.__name__, self.entId))
+
         if __debug__:
         if __debug__:
+            # for the editor
             self.getNodePath().setTag('entity', '1')
             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 setPos(self, *args): self.getNodePath().setPos(*args)
     def setX(self, *args): self.getNodePath().setX(*args)
     def setX(self, *args): self.getNodePath().setX(*args)
     def setY(self, *args): self.getNodePath().setY(*args)
     def setY(self, *args): self.getNodePath().setY(*args)
@@ -37,85 +93,39 @@ class NodePathAttribs:
     
     
     def reparentTo(self, *args): self.getNodePath().reparentTo(*args)
     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):
     def __init__(self, level, entId):
-        privNodePathImpl.__init__(self, '')
+        node = hidden.attachNewNode('NodePathEntity')
+        NodePath.NodePath.__init__(self, node)
         Entity.Entity.__init__(self, level, entId)
         Entity.Entity.__init__(self, level, entId)
-        self.setName(str(self))
-        privNodePathImpl.initNodePathAttribs(self)
+        NodePathAttribs.initNodePathAttribs(self)
 
 
     def destroy(self):
     def destroy(self):
+        NodePathAttribs.destroy(self)
         Entity.Entity.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,
 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):
     def __init__(self, cr):
         DistributedEntity.DistributedEntity.__init__(self, cr)
         DistributedEntity.DistributedEntity.__init__(self, cr)
-        privNodePathImpl.__init__(self, 'DistributedNodePathEntity')
+        node = hidden.attachNewNode('DistributedNodePathEntity')
+        NodePath.NodePath.__init__(self, node)
 
 
     def announceGenerate(self):
     def announceGenerate(self):
         DistributedEntity.DistributedEntity.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
         # zone the entire time we're in here
         self.levelZone = zoneId
         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
     # "required" fields (these ought to be required fields, but
     # the AI level obj doesn't know the data values until it has been
     # the AI level obj doesn't know the data values until it has been
     # generated.)
     # generated.)
@@ -168,6 +178,19 @@ class DistributedLevel(DistributedObject.DistributedObject,
         # load stuff
         # load stuff
         self.initVisibility()
         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):
     def createEntityCreator(self):
         """Create the object that will be used to create Entities.
         """Create the object that will be used to create Entities.
         Inheritors, override if desired."""
         Inheritors, override if desired."""

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

@@ -13,11 +13,20 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
     """DistributedLevelAI"""
     """DistributedLevelAI"""
     notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevelAI')
     notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevelAI')
 
 
-    def __init__(self, air, zoneId):
+    def __init__(self, air, zoneId, entranceId, avIds):
         DistributedObjectAI.DistributedObjectAI.__init__(self, air)
         DistributedObjectAI.DistributedObjectAI.__init__(self, air)
         Level.Level.__init__(self)
         Level.Level.__init__(self)
-        # this is one of the required fields
+        # these are required fields
         self.zoneId = zoneId
         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__:
         if __debug__:
             self.modified = 0
             self.modified = 0
 
 
@@ -37,6 +46,12 @@ class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
         same zone with the level"""
         same zone with the level"""
         return self.zoneId
         return self.zoneId
 
 
+    def getPlayerIds(self):
+        return self.avIdList
+
+    def getEntranceId(self):
+        return self.entranceId
+
     def delete(self):
     def delete(self):
         self.notify.debug('delete')
         self.notify.debug('delete')
         if __debug__:
         if __debug__:

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

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

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

@@ -5,6 +5,7 @@ import EntityCreatorBase
 import BasicEntities
 import BasicEntities
 import DirectNotifyGlobal
 import DirectNotifyGlobal
 import EditMgr
 import EditMgr
+import EntrancePoint
 import LevelMgr
 import LevelMgr
 import ZoneEntity
 import ZoneEntity
 import ModelEntity
 import ModelEntity
@@ -14,7 +15,8 @@ import PathEntity
 # ctor functions must take (level, entId)
 # ctor functions must take (level, entId)
 # and they must return the entity that was created, or 'nothing'
 # and they must return the entity that was created, or 'nothing'
 def nothing(*args):
 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'
     return 'nothing'
 
 
 class EntityCreator(EntityCreatorBase.EntityCreatorBase):
 class EntityCreator(EntityCreatorBase.EntityCreatorBase):
@@ -29,6 +31,7 @@ class EntityCreator(EntityCreatorBase.EntityCreatorBase):
         self.privRegisterTypes({
         self.privRegisterTypes({
             'cutScene': CutScene.CutScene,
             'cutScene': CutScene.CutScene,
             'editMgr': EditMgr.EditMgr,
             'editMgr': EditMgr.EditMgr,
+            'entrancePoint': EntrancePoint.EntrancePoint,
             'levelMgr': LevelMgr.LevelMgr,
             'levelMgr': LevelMgr.LevelMgr,
             'logicGate': nothing,
             'logicGate': nothing,
             'model' : ModelEntity.ModelEntity,
             'model' : ModelEntity.ModelEntity,

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

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

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

@@ -53,6 +53,12 @@ class Zone(Nodepath):
         ('visibility', [], 'visZoneList'),
         ('visibility', [], 'visZoneList'),
         )
         )
 
 
+class EntrancePoint(Nodepath):
+    type = 'entrancePoint'
+    attribs = (
+        ('entranceId', -1, 'int'),
+        )
+
 class LogicGate(Entity):
 class LogicGate(Entity):
     type = 'logicGate'
     type = 'logicGate'
     output = 'bool'
     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.entType2ids = self.levelSpec.getEntType2ids(
             self.levelSpec.getAllEntIds())
             self.levelSpec.getAllEntIds())
 
 
+        # entranceId to entrance entity
+        self.entranceId2entity = {}
+
         # this list contains the entIds of entities that we have actually
         # this list contains the entIds of entities that we have actually
         # created, in order of creation
         # created, in order of creation
         self.createdEntIds = []
         self.createdEntIds = []
@@ -198,6 +201,19 @@ class Level:
     def getEntityType(self, entId):
     def getEntityType(self, entId):
         return self.levelSpec.getEntityType(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):
     def getZoneId(self, dummy=None, zoneNum=None, entId=None):
         """look up network zoneId by zoneNum or entId"""
         """look up network zoneId by zoneNum or entId"""
         assert (zoneNum is not None) or (entId is not None)
         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):
     def getEntityType(self, entId):
         return self.getEntitySpec(entId)['type']
         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):
     def getEntType2ids(self, entIds):
         """given list of entIds, return dict of entType 2 entIds"""
         """given list of entIds, return dict of entType 2 entIds"""
         entType2ids = {}
         entType2ids = {}

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

@@ -8,7 +8,11 @@ class ZoneEntity(ZoneEntityBase.ZoneEntityBase, BasicEntities.NodePathAttribs):
         ZoneEntityBase.ZoneEntityBase.__init__(self, level, entId)
         ZoneEntityBase.ZoneEntityBase.__init__(self, level, entId)
 
 
         self.nodePath = self.level.getZoneNode(self.modelZoneNum)
         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):
     def getNodePath(self):
         return self.nodePath
         return self.nodePath