added EntrancePoint entity, extended entity NodePath support

This commit is contained in:
Darren Ranalli 2003-11-05 01:46:49 +00:00
parent b76ae7cb96
commit 5a0a536ef5
11 changed files with 211 additions and 78 deletions

View File

@ -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)
# 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):
node = hidden.attachNewNode('NodePathEntity')
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)
Entity.Entity.__init__(self, level, entId)
NodePathAttribs.initNodePathAttribs(self)
def destroy(self):
if __debug__:
self.clearTag('entity')
NodePathAttribs.destroy(self)
Entity.Entity.destroy(self)
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."""
def __init__(self, level, entId):
privNodePathImpl.__init__(self, '')
Entity.Entity.__init__(self, level, entId)
self.setName(str(self))
privNodePathImpl.initNodePathAttribs(self)
def destroy(self):
Entity.Entity.destroy(self)
privNodePathImpl.destroy(self)
def getNodePath(self):
return self
# 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)

View File

@ -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."""

View File

@ -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__:

View File

@ -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):

View File

@ -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,

View File

@ -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,

View File

@ -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'

View File

@ -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()

View File

@ -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)

View File

@ -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 = {}

View File

@ -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