*** empty log message ***

This commit is contained in:
Dave Schuyler 2003-09-09 23:55:24 +00:00
parent 59d17bc208
commit 0ba45e5eda
19 changed files with 1267 additions and 0 deletions

View File

View File

@ -0,0 +1,58 @@
"""AndLoEntityAI.py: contains the AndLoEntity class"""
import PandaObject
import DirectNotifyGlobal
import Entity
class AndLoEntityAI(Entity.Entity, PandaObject.PandaObject):
if __debug__:
notify = DirectNotifyGlobal.directNotify.newCategory(
'AndLoEntityAI')
def __init__(self, air, levelDoId, entId, zoneId=None):
"""entId: """
assert(self.debugPrint(
"AndLoEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
%("the air", levelDoId, entId, zoneId)))
self.input1 = None
self.input2 = None
self.levelDoId = levelDoId
level = air.doId2do[self.levelDoId]
Entity.Entity.__init__(self, level, entId)
self.initializeEntity()
self.setInput_input1_bool(self.input_input1_bool)
self.setInput_input2_bool(self.input_input2_bool)
def setIsInput1(self, isTrue):
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
self.isInput1=isTrue
if self.isInput2:
messenger.send(self.getName(), [isTrue])
def setIsInput2(self, isTrue):
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
self.isInput2=isTrue
if self.isInput1:
messenger.send(self.getName(), [isTrue])
def setInput_input1_bool(self, event):
assert(self.debugPrint("setInput_input1_bool(event=%s)"%(event,)))
if self.input1:
self.ignore(self.input1)
self.input1 = "switch-%s"%(event,)
if self.input1:
self.accept(self.input1, self.setIsInput1)
def setInput_input2_bool(self, event):
assert(self.debugPrint("setInput_input2_bool(event=%s)"%(event,)))
if self.input2:
self.ignore(self.input2)
self.input2 = "switch-%s"%(event,)
if self.input2:
self.accept(self.input2, self.setIsInput2)
def getName(self):
#return "andLoEntity-%s"%(self.entId,)
return "switch-%s"%(self.entId,)

View File

@ -0,0 +1,56 @@
"""BasicEntities module: contains the BasicEntities class"""
import Entity
import DistributedEntity
import NodePath
# this is an internal class, do not instantiate.
class privNodePathImpl(NodePath.NodePath):
def __init__(self, name):
node = hidden.attachNewNode(name)
NodePath.NodePath.__init__(self, node)
def initializeEntity(self):
self.callSetters(('pos','x','y','z',
'hpr','h','p','r',
'scale','sx','sx','sz'))
if hasattr(self, 'parent'):
self.level.requestReparent(self, self.parent)
def destroy(self):
self.removeNode()
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):
Entity.Entity.__init__(self, level, entId)
privNodePathImpl.__init__(self, str(self))
self.initializeEntity()
def initializeEntity(self):
Entity.Entity.initializeEntity(self)
privNodePathImpl.initializeEntity(self)
def destroy(self):
Entity.Entity.destroy(self)
privNodePathImpl.initializeEntity(self)
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."""
def __init__(self, cr):
DistributedEntity.DistributedEntity.__init__(self, cr)
privNodePathImpl.__init__(self, 'DistributedNodePathEntity')
def initializeEntity(self):
DistributedEntity.DistributedEntity.initializeEntity(self)
privNodePathImpl.initializeEntity(self)
def destroy(self):
DistributedEntity.DistributedEntity.destroy(self)
privNodePathImpl.destroy(self)

View File

@ -0,0 +1,46 @@
import DistributedObject
import Entity
import DirectNotifyGlobal
class DistributedEntity(DistributedObject.DistributedObject, Entity.Entity):
notify = DirectNotifyGlobal.directNotify.newCategory(
'DistributedEntity')
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
def generateInit(self):
DistributedEntity.notify.debug('generateInit')
DistributedObject.DistributedObject.generateInit(self)
# load stuff
def generate(self):
DistributedEntity.notify.debug('generate')
DistributedObject.DistributedObject.generate(self)
def setLevelDoId(self, levelDoId):
DistributedEntity.notify.debug('setLevelDoId: %s' % levelDoId)
self.levelDoId = levelDoId
def setEntId(self, entId):
DistributedEntity.notify.debug('setEntId: %s' % entId)
self.entId = entId
def announceGenerate(self):
DistributedEntity.notify.debug('announceGenerate')
# ask our level obj for our spec data
level = toonbase.tcr.doId2do[self.levelDoId]
Entity.Entity.__init__(self, level, self.entId)
# this sets all of our initial spec parameters on ourselves
self.initializeEntity()
DistributedObject.DistributedObject.announceGenerate(self)
def disable(self):
DistributedEntity.notify.debug('disable')
# stop things
def delete(self):
DistributedEntity.notify.debug('delete')
# unload things

View File

@ -0,0 +1,35 @@
import DistributedObjectAI
import Entity
import DirectNotifyGlobal
class DistributedEntityAI(DistributedObjectAI.DistributedObjectAI,
Entity.Entity):
notify = DirectNotifyGlobal.directNotify.newCategory(
'DistributedEntityAI')
def __init__(self, air, levelDoId, entId):
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
self.levelDoId = levelDoId
level = self.air.doId2do[self.levelDoId]
Entity.Entity.__init__(self, level, entId)
# get our spec data
self.initializeEntity()
def generate(self):
self.notify.debug('generate')
DistributedObjectAI.DistributedObjectAI.generate(self)
def destroy(self):
self.notify.debug('destroy')
Entity.Entity.destroy(self)
self.requestDelete()
def delete(self):
self.notify.debug('delete')
DistributedObjectAI.DistributedObjectAI.delete(self)
def getLevelDoId(self):
return self.levelDoId
def getEntId(self):
return self.entId

View File

@ -0,0 +1,151 @@
""" DistributedInteractiveEntity module: contains the DistributedInteractiveEntity
class, the client side representation of a 'landmark door'."""
from ShowBaseGlobal import *
from ClockDelta import *
import DirectNotifyGlobal
import FSM
import DistributedEntity
class DistributedInteractiveEntity(DistributedEntity.DistributedEntity):
"""
DistributedInteractiveEntity class: The client side representation of any
simple animated prop.
"""
if __debug__:
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedInteractiveEntity')
def __init__(self, cr):
"""constructor for the DistributedInteractiveEntity"""
DistributedEntity.DistributedEntity.__init__(self, cr)
assert(self.debugPrint("__init()"))
self.fsm = FSM.FSM('Distribu, levelDoId, entIdtedInteractiveEntity',
[State.State('off',
self.enterOff,
self.exitOff,
['playing',
'attract']),
State.State('attract',
self.enterAttract,
self.exitAttract,
['playing']),
State.State('playing',
self.enterPlaying,
self.exitPlaying,
['attract'])],
# Initial State
'off',
# Final State
'off',
)
self.fsm.enterInitialState()
# self.generate will be called automatically.
def generate(self):
"""generate(self)
This method is called when the DistributedEntity is reintroduced
to the world, either for the first time or from the cache.
"""
assert(self.debugPrint("generate()"))
DistributedEntity.DistributedEntity.generate(self)
def disable(self):
assert(self.debugPrint("disable()"))
# Go to the off state when the object is put in the cache
self.fsm.request("off")
DistributedEntity.DistributedEntity.disable(self)
# self.delete() will automatically be called.
def delete(self):
assert(self.debugPrint("delete()"))
del self.fsm
DistributedEntity.DistributedEntity.delete(self)
def setAvatarInteract(self, avatarId):
"""
required dc field.
"""
assert(self.debugPrint("setAvatarInteract(%s)"%(avatarId,)))
assert(not self.__dict__.has_key(avatarId))
self.avatarId=avatarId
def setOwnerDoId(self, ownerDoId):
"""
required dc field.
"""
assert(self.debugPrint("setOwnerDoId(%s)"%(ownerDoId,)))
assert(not self.__dict__.has_key("ownerDoId"))
self.ownerDoId=ownerDoId
def setInitialState(self, state, timestamp):
"""
required dc field.
"""
assert(self.debugPrint("setInitialState(%s, %d)" % (state, timestamp)))
assert(not self.__dict__.has_key("initialState"))
self.initialState = state
self.initialStateTimestamp = timestamp
def setState(self, state, timestamp):
assert(self.debugPrint("setState(%s, %d)" % (state, timestamp)))
self.fsm.request(state, [globalClockDelta.localElapsedTime(timestamp)])
#def __getPropNodePath(self):
# assert(self.debugPrint("__getPropNodePath()"))
# if (not self.__dict__.has_key('propNodePath')):
# self.propNodePath=self.cr.playGame.hood.loader.geom.find(
# "**/prop"+self.entID+":*_DNARoot")
# return self.propNodePath
def enterTrigger(self, args=None):
assert(self.debugPrint("enterTrigger(args="+str(args)+")"))
messenger.send("DistributedInteractiveEntity_enterTrigger")
self.sendUpdate("requestInteract")
# the AI server will reply with toonInteract or rejectInteract.
def exitTrigger(self, args=None):
assert(self.debugPrint("exitTrigger(args="+str(args)+")"))
messenger.send("DistributedInteractiveEntity_exitTrigger")
self.sendUpdate("requestExit")
# the AI server will reply with avatarExit.
def rejectInteract(self):
"""Server doesn't let the avatar interact with prop"""
assert(self.debugPrint("rejectInteract()"))
self.cr.playGame.getPlace().setState('walk')
def avatarExit(self, avatarId):
assert(self.debugPrint("avatarExit(avatarId=%s)"%(avatarId,)))
##### off state #####
def enterOff(self):
assert(self.debugPrint("enterOff()"))
def exitOff(self):
assert(self.debugPrint("exitOff()"))
##### attract state #####
def enterAttract(self, ts):
assert(self.debugPrint("enterAttract()"))
def exitAttract(self):
assert(self.debugPrint("exitAttract()"))
##### playing state #####
def enterPlaying(self, ts):
assert(self.debugPrint("enterPlaying()"))
def exitPlaying(self):
assert(self.debugPrint("exitPlaying()"))
if __debug__:
def debugPrint(self, message):
"""for debugging"""
return self.notify.debug(
str(self.__dict__.get('entId', '?'))+' '+message)

View File

@ -0,0 +1,144 @@
""" DistributedInteractiveEntityAI module: contains the DistributedInteractiveEntityAI
class, the server side representation of a simple, animated, interactive
prop."""
from AIBaseGlobal import *
from ClockDelta import *
import DirectNotifyGlobal
import FSM
import DistributedEntityAI
import State
class DistributedInteractiveEntityAI(DistributedEntityAI.DistributedEntityAI):
"""
DistributedInteractiveEntityAI class: The server side representation of
an animated prop. This is the object that remembers what the
prop is doing. The child of this object, the DistributedAnimatedProp
object, is the client side version and updates the display that
client's display based on the state of the prop.
"""
if __debug__:
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedInteractiveEntityAI')
def __init__(self, air, levelDoId, entId):
"""entId: a unique identifier for this prop."""
DistributedEntityAI.DistributedEntityAI.__init__(self, air,
levelDoId, entId)
assert(self.debugPrint(
"DistributedInteractiveEntityAI(air=%s, entId=%s)"
%("the air", entId)))
self.fsm = FSM.FSM('DistributedInteractiveEntityAI',
[State.State('off',
self.enterOff,
self.exitOff,
['playing']),
# Attract is an idle mode. It is named attract
# because the prop is not interacting with an
# avatar, and is therefore trying to attract an
# avatar.
State.State('attract',
self.enterAttract,
self.exitAttract,
['playing']),
# Playing is for when an avatar is interacting
# with the prop.
State.State('playing',
self.enterPlaying,
self.exitPlaying,
['attract'])],
# Initial State
'off',
# Final State
'off',
)
self.fsm.enterInitialState()
self.avatarId=0
def delete(self):
del self.fsm
DistributedEntityAI.DistributedEntityAI.delete(self)
def getAvatarInteract(self):
assert(self.debugPrint("getAvatarInteract() returning: %s"%(self.avatarId,)))
return self.avatarId
def getInitialState(self):
assert(self.debugPrint("getInitialState()"))
return [self.fsm.getCurrentState().getName(),
globalClockDelta.getRealNetworkTime()]
def getOwnerDoId(self):
assert(self.debugPrint("getOwnerDoId() returning: %s"%(self.ownerDoId,)))
return self.ownerDoId
def requestInteract(self):
assert(self.debugPrint("requestInteract()"))
avatarId = self.air.msgSender
assert(self.notify.debug(" avatarId:%s"%(avatarId,)))
stateName = self.fsm.getCurrentState().getName()
if stateName != 'playing':
self.sendUpdate("setAvatarInteract", [avatarId])
self.avatarId=avatarId
self.fsm.request('playing')
else:
self.sendUpdateToAvatarId(avatarId, "rejectInteract", [])
def requestExit(self):
assert(self.debugPrint("requestExit()"))
avatarId = self.air.msgSender
assert(self.notify.debug(" avatarId:%s"%(avatarId,)))
if avatarId==self.avatarId:
stateName = self.fsm.getCurrentState().getName()
if stateName == 'playing':
self.sendUpdate("avatarExit", [avatarId])
self.fsm.request('attract')
else:
assert(self.notify.debug(" requestExit: invalid avatarId"))
def getState(self):
assert(self.debugPrint("getState()"))
return [self.fsm.getCurrentState().getName(),
globalClockDelta.getRealNetworkTime()]
def d_setState(self, state):
assert(self.debugPrint("d_setState(state=%s)"%(state,)))
self.sendUpdate('setState', [state, globalClockDelta.getRealNetworkTime()])
##### off state #####
def enterOff(self):
assert(self.debugPrint("enterOff()"))
#self.d_setState('off')
def exitOff(self):
assert(self.debugPrint("exitOff()"))
##### attract state #####
def enterAttract(self):
assert(self.debugPrint("enterAttract()"))
self.d_setState('attract')
def exitAttract(self):
assert(self.debugPrint("exitAttract()"))
##### open state #####
def enterPlaying(self):
assert(self.debugPrint("enterPlaying()"))
self.d_setState('playing')
def exitPlaying(self):
assert(self.debugPrint("exitPlaying()"))
if __debug__:
def debugPrint(self, message):
"""for debugging"""
return self.notify.debug(
str(self.__dict__.get('entId', '?'))+' '+message)

View File

@ -0,0 +1,254 @@
"""DistributedLevel.py: contains the DistributedLevel class"""
from ClockDelta import *
from PythonUtil import Functor, sameElements, list2dict, uniqueElements
import ToontownGlobals
import DistributedObject
import LevelBase
import DirectNotifyGlobal
import EntityCreator
class DistributedLevel(DistributedObject.DistributedObject,
LevelBase.LevelBase):
"""DistributedLevel"""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevel')
WantVisibility = config.GetBool('level-visibility', 0)
HideZones = config.GetBool('level-hidezones', 1)
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
LevelBase.LevelBase.__init__(self)
def generate(self):
self.notify.debug('generate')
DistributedObject.DistributedObject.generate(self)
self.setLevelId(self.doId)
# this dict stores entity reparents if the parent hasn't been
# created yet
self.pendingEntId2ParentId = {}
# Most (if not all) of the timed entities of levels
# run on looping intervals that are started once based on
# the level's start time.
# This sync request is *NOT* guaranteed to finish by the time
# the entities get created.
# We should listen for any and all time-sync events and re-sync
# all our entities at that time.
toonbase.tcr.timeManager.synchronize('DistributedLevel.generate')
# required fields
def setZoneIds(self, zoneIds):
self.notify.debug('setZoneIds: %s' % zoneIds)
self.zoneIds = zoneIds
def setStartTimestamp(self, timestamp):
self.notify.debug('setStartTimestamp: %s' % timestamp)
self.startTime = globalClockDelta.networkToLocalTime(timestamp,bits=32)
def setScenarioIndex(self, scenarioIndex):
self.scenarioIndex = scenarioIndex
def initializeLevel(self, spec):
""" subclass should call this as soon as it's located its spec data """
LevelBase.LevelBase.initializeLevel(self, spec, self.scenarioIndex)
# load stuff
self.geom = loader.loadModel(self.spec['modelFilename'])
def findNumberedNodes(baseString, model=self.geom, self=self):
# finds nodes whose name follows the pattern 'baseString#'
# where there are no characters after #
# returns dictionary that maps # to node
potentialNodes = model.findAllMatches(
'**/%s*' % baseString).asList()
num2node = {}
for potentialNode in potentialNodes:
name = potentialNode.getName()
self.notify.debug('potential match for %s: %s' %
(baseString, name))
try:
num = int(name[len(baseString):])
except:
continue
num2node[num] = potentialNode
return num2node
# find the zones in the model and fix them up
self.zoneNum2Node = findNumberedNodes('Zone')
# add the UberZone
self.zoneNum2Node[0] = self.geom
# fix up the floor collisions for walkable zones
for zoneNum, zoneNode in self.zoneNum2Node.items():
# if this is a walkable zone, fix up the model
floorColl = zoneNode.find('**/*FloorCollision*')
if not floorColl.isEmpty():
# rename the floor collision node, and make sure no other
# nodes under the ZoneNode have that name
floorCollName = 'Zone%sFloor' % zoneNum
others = zoneNode.findAllMatches(
'**/%s' % floorCollName).asList()
for other in others:
other.setName('%s_renamed' % floorCollName)
floorColl.setName(floorCollName)
# listen for zone enter events from floor collisions
def handleZoneEnter(collisionEntry,
self=self, zoneNum=zoneNum):
# eat the collisionEntry
self.enterZone(zoneNum)
self.accept('enter%s' % floorCollName, handleZoneEnter)
self.zoneNums = self.zoneNum2Node.keys()
self.zoneNums.sort()
self.notify.debug('zones: %s' % self.zoneNums)
assert sameElements(self.zoneNums, self.spec['zones'].keys() + [0])
# find the doorway nodes
self.doorwayNum2Node = findNumberedNodes('Doorway')
self.initVisibility()
# create client-side Entities
# TODO: only create client-side Entities for the
# currently-visible zones?
self.localEntities = {}
for entId, spec in self.entId2Spec.iteritems():
entity = EntityCreator.createEntity(spec['type'], self, entId)
if entity is not None:
self.localEntities[entId] = entity
# there should not be any pending reparents left
assert len(self.pendingEntId2ParentId) == 0
def announceGenerate(self):
self.notify.debug('announceGenerate')
DistributedObject.DistributedObject.announceGenerate(self)
def disable(self):
self.notify.debug('disable')
DistributedObject.DistributedObject.disable(self)
self.ignoreAll()
# destroy all of the local entities
for entId, entity in self.localEntities.items():
entity.destroy()
del self.localEntities
self.destroyLevel()
def delete(self):
self.notify.debug('delete')
DistributedObject.DistributedObject.delete(self)
def getDoorwayNode(self, doorwayNum):
# returns node that doors should parent themselves to
return self.doorwayNum2Node[doorwayNum]
def requestReparent(self, entity, parent):
if parent is 'zone':
entity.reparentTo(self.zoneNum2Node[entity.zone])
else:
parentId = parent
assert(entity.entId != parentId)
if self.entities.has_key(parentId):
# parent has already been created
entity.reparentTo(self.entities[parentId])
else:
# parent hasn't been created yet; schedule the reparent
self.notify.debug(
'entity %s requesting reparent to %s, not yet created' %
(entity, parent))
entId = entity.entId
self.pendingEntId2ParentId[entId] = parentId
entity.reparentTo(hidden)
# do the reparent once the parent is initialized
def doReparent(entId=entId, parentId=parentId, self=self):
entity=self.getEntity(entId)
parent=self.getEntity(parentId)
self.notify.debug(
'performing pending reparent of %s to %s' %
(entity, parent))
entity.reparentTo(parent)
del self.pendingEntId2ParentId[entId]
self.accept(self.getEntityCreateEvent(parentId), doReparent)
def showZone(self, zoneNum):
self.zoneNum2Node[zoneNum].show()
def hideZone(self, zoneNum):
self.zoneNum2Node[zoneNum].hide()
def setTransparency(self, alpha, zone=None):
self.geom.setTransparency(1)
if zone is None:
node = self.geom
else:
node = self.zoneNum2Node[zone]
node.setAlphaScale(alpha)
def initVisibility(self):
# start out with every zone visible, since none of the zones have
# been hidden
self.curVisibleZoneNums = list2dict(self.zoneNums)
# we have not entered any zone yet
self.curZoneNum = None
# TODO: make this data-driven
firstZone = 16
self.enterZone(firstZone)
def enterZone(self, zoneNum):
if not DistributedLevel.WantVisibility:
return
if zoneNum == self.curZoneNum:
return
print "enterZone %s" % zoneNum
zoneSpec = self.spec['zones'][zoneNum]
# use dicts to efficiently ensure that there are no duplicates
visibleZoneNums = list2dict([zoneNum])
visibleZoneNums.update(list2dict(zoneSpec['visibility']))
if DistributedLevel.HideZones:
# figure out which zones are new and which are going invisible
# use dicts because it's faster to use dict.has_key(x)
# than 'x in list'
addedZoneNums = []
removedZoneNums = []
allVZ = dict(visibleZoneNums)
allVZ.update(self.curVisibleZoneNums)
for vz,None in allVZ.items():
new = vz in visibleZoneNums
old = vz in self.curVisibleZoneNums
if new and old:
continue
if new:
addedZoneNums.append(vz)
else:
removedZoneNums.append(vz)
# show the new, hide the old
self.notify.debug('showing zones %s' % addedZoneNums)
for az in addedZoneNums:
self.showZone(az)
self.notify.debug('hiding zones %s' % removedZoneNums)
for rz in removedZoneNums:
self.hideZone(rz)
# convert the zone numbers into their actual zoneIds
# always include Toontown and factory uberZones
visibleZoneIds = [ToontownGlobals.UberZone, self.getZoneId(0)]
for vz in visibleZoneNums.keys():
visibleZoneIds.append(self.getZoneId(vz))
assert(uniqueElements(visibleZoneIds))
self.notify.debug('new viz list: %s' % visibleZoneIds)
toonbase.tcr.sendSetZoneMsg(self.getZoneId(zoneNum), visibleZoneIds)
self.curZoneNum = zoneNum
self.curVisibleZoneNums = visibleZoneNums

View File

@ -0,0 +1,80 @@
"""DistributedLevelAI.py: contains the DistributedLevelAI class"""
from ClockDelta import *
import DistributedObjectAI
import LevelBase
import DirectNotifyGlobal
import EntityCreatorAI
import WeightedChoice
class DistributedLevelAI(DistributedObjectAI.DistributedObjectAI,
LevelBase.LevelBase):
"""DistributedLevelAI"""
notify = DirectNotifyGlobal.directNotify.newCategory('DistributedLevelAI')
def __init__(self, air):
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
LevelBase.LevelBase.__init__(self)
def initializeLevel(self, spec, uberZoneId):
self.uberZoneId = uberZoneId
# choose a scenario
wc = WeightedChoice.WeightedChoice(spec['scenarios'], 1)
scenario = wc.choose()
scenarioIndex = spec['scenarios'].index(scenario)
LevelBase.LevelBase.initializeLevel(self, spec, scenarioIndex)
# allocate the rest of the zones; add one for the uber-zone
self.numZones = len(self.spec['zones']) + 1
self.zoneIds = [self.uberZoneId]
for i in range(1,self.numZones):
# there is error checking in air.allocateZone
self.zoneIds.append(self.air.allocateZone())
# record the level's start time so that we can sync the clients
self.startTime = globalClock.getRealTime()
self.startTimestamp = globalClockDelta.localToNetworkTime(
self.startTime, bits=32)
# required-field getters
def getZoneIds(self):
return self.zoneIds
def getStartTimestamp(self):
return self.startTimestamp
def getScenarioIndex(self):
return self.scenarioIndex
def generate(self):
self.notify.debug('generate')
DistributedObjectAI.DistributedObjectAI.generate(self)
self.setLevelId(self.doId)
# create the Entities
self.aiEntities = {}
for entId, spec in self.entId2Spec.iteritems():
self.notify.debug('creating %s %s' % (spec['type'], entId))
entity = EntityCreatorAI.createEntity(
spec['type'], self.air, self.doId, entId,
self.getZoneId(spec['zone']))
if entity is not None:
self.aiEntities[entId] = entity
def delete(self):
self.notify.debug('delete')
for entId in self.aiEntities.keys():
self.aiEntities[entId].destroy()
del self.aiEntities
# we do not allocate the uberZone for now, so don't deallocate it
for zoneId in self.zoneIds[1:]:
self.air.deallocateZone(zoneId)
self.destroyLevel()
DistributedObjectAI.DistributedObjectAI.delete(self)

74
direct/src/level/Entity.py Executable file
View File

@ -0,0 +1,74 @@
"""Entity.py: contains the Entity class"""
import string
class Entity:
"""Entity is the base class for all objects that exist in a Level
and can be edited with the LevelEditor."""
# these are values that can be changed in the level editor
# TODO: pick a good name for these values;
# parameters, tweakables, attributes, attribs, traits,
Tweakables = (
# Name, PythonType, CallSetterOnInitialization
('name', str, 0),
('comment', str, 0),
)
def __init__(self, level, entId, tweakables=None):
self.level = level
self.entId = entId
self.tweakables = Entity.Tweakables
# add any additional tweakable values
if tweakables is not None:
self.tweakables.update(tweakables)
# TODO: funcs to populate the entity with its spec data, and system
# to call back when data changes
def initializeEntity(self):
"""Call this once on initialization to set this entity's
spec data"""
self.level.initializeEntity(self)
def destroy(self):
del self.level
def privGetSetter(self, attrib):
setFuncName = 'set%s%s' % (string.upper(attrib[0]), attrib[1:])
if hasattr(self, setFuncName):
return getattr(self, setFuncName)
return None
def callSetters(self, attribList):
"""call this with a list of attribs, and any that exist on the
entity and have setters will be passed to their setter"""
for attrib in attribList:
if hasattr(self, attrib):
setter = self.privGetSetter(attrib)
if setter is not None:
setter(getattr(self, attrib))
def paramChanged(self):
"""This is called when a parameter is tweaked and no setter
is called; i.e. the value is set directly on the object.
Some Entities might want to completely reset every time anything
is tweaked; this is the place to do it; override this func in your
derived class
"""
pass
def getTweakables(self):
return self.tweakables
def privTweak(self, name, value):
self.__dict__[name] = value
def __str__(self):
return 'ent%s(%s)' % (self.entId, self.level.getEntityType(self.entId))
if __debug__:
def debugPrint(self, message):
"""for debugging"""
return self.notify.debug(
str(self.__dict__.get('entId', '?'))+' '+message)

View File

@ -0,0 +1,35 @@
"""EntityCreator.py: contains methods for creation of Entities"""
from PythonUtil import Functor
import PlatformEntity
import BasicEntities
def nothing(level, entId):
"""For entities that don't need to be created by the client"""
return None
# Client-side entity ctors:
EntityType2Ctor = {
# Map entity type name to constructor function that takes
# (level, entId)
'beanBarrel': nothing,
'door': nothing,
'gagBarrel': nothing,
'lift': nothing,
'nodepath': BasicEntities.NodePathEntity,
#'platform': PlatformEntity.PlatformEntity,
'stomper': nothing,
'switch': nothing,
'andLogicObject': nothing,
'orLogicObject': nothing,
'xorLogicObject': nothing, #XorLoEntity.XorLoEntity,
}
# TODO: what other args will be required?
def createEntity(entType, level, entId):
if not EntityType2Ctor.has_key(entType):
print "createEntity(entType=%s, entId=%s) not found"%(
entType, entId)
return None
return EntityType2Ctor[entType](level, entId)

View File

@ -0,0 +1,49 @@
"""EntityCreatorAI.py: contains methods for creation of Entities"""
from PythonUtil import Functor
import DistributedBeanBarrelAI
import DistributedLiftAI
import DistributedDoorEntityAI
import DistributedGagBarrelAI
#import DistributedStomperPairAI
import DistributedSwitchAI
import DistributedStomperAI
import AndLoEntityAI
import OrLoEntityAI
#import XorLoEntity
def cDE(AIclass, air, levelDoId, entId, zoneId):
"""create a distributed entity"""
ent = AIclass(air, levelDoId, entId)
ent.generateWithRequired(zoneId)
return ent
def nothing(air, levelDoId, entId, zoneId):
"""Create entity that doesn't have a server side representation."""
return None
# Server (AI) side factory functions:
EntityType2Ctor = {
# Map entity type name to constructor function that takes
# (air, level doId, entId, zoneId)
'beanBarrel': Functor(cDE, DistributedBeanBarrelAI.DistributedBeanBarrelAI),
'door': DistributedDoorEntityAI.DistributedDoorEntityAI,
'gagBarrel': Functor(cDE, DistributedGagBarrelAI.DistributedGagBarrelAI),
'lift': Functor(cDE, DistributedLiftAI.DistributedLiftAI),
'nodepath': nothing,
'platform': nothing,
'stomper': Functor(cDE, DistributedStomperAI.DistributedStomperAI),
'switch': DistributedSwitchAI.DistributedSwitchAI,
'andLogicObject': AndLoEntityAI.AndLoEntityAI,
'orLogicObject': OrLoEntityAI.OrLoEntityAI,
'xorLogicObject': nothing, #XorLoEntity.XorLoEntity,
}
def createEntity(entType, air, levelDoId, entId, zoneId):
if not EntityType2Ctor.has_key(entType):
print "createEntity(entType=%s, air=%s, levelDoId=%s, entId=%s, zoneId=%s) not found"%(
entType, "the air", levelDoId, entId, zoneId)
return None
return EntityType2Ctor[entType](air, levelDoId, entId, zoneId)

91
direct/src/level/LevelBase.py Executable file
View File

@ -0,0 +1,91 @@
"""LevelBase.py: contains the LevelBase class"""
import DirectNotifyGlobal
import string
class LevelBase:
"""LevelBase: shared client and AI code
representation of a game level, keeps track of all of the
Level Entities and their interrelations"""
notify = DirectNotifyGlobal.directNotify.newCategory('LevelBase')
def __init__(self, levelId=None):
if levelId is not None:
self.setLevelId(levelId)
def setLevelId(self, levelId):
self.levelId = levelId
def initializeLevel(self, spec, scenarioIndex):
""" subclass should call this as soon as it has located
its spec data """
self.spec = spec
self.scenarioIndex = scenarioIndex
# create a complete set of global and scenario-specific entity specs
globalEntities = self.spec['globalEntities']
scenarioEntities = self.spec['scenarios'][self.scenarioIndex][0]
entId2Spec = {}
entId2Spec.update(globalEntities)
entId2Spec.update(scenarioEntities)
self.entId2Spec = entId2Spec
# this will be filled in as the entities are created and report in
self.entities = {}
def destroyLevel(self):
del self.entities
del self.entId2Spec
del self.spec
def initializeEntity(self, entity):
"""populate an entity with its spec data"""
entId = entity.entId
spec = self.entId2Spec[entId]
# on initialization, set items directly on entity
for key,value in spec.items():
if key in ('type', 'name', 'comment',):
continue
if hasattr(entity, key):
self.notify.warning('entity %s (%s) already has member %s' %
(entId, spec['type'], key))
entity.__dict__[key] = value
# entity is initialized, add it to the list of entities
self.entities[entity.entId] = entity
# send the create event
messenger.send(self.getEntityCreateEvent(entity.entId))
"""
# set items directly on entity, or call callback functions...
for key,value in spec.items():
# filter out some entries; we might want to restructure the
# spec data into different categories of properties instead
# of filtering them here
if key in ('type', 'name', 'comment', 'zone',):
continue
setFuncName = 'set%s%s' % (string.upper(key[0]), key[1:])
if hasattr(entity, setFuncName):
# call the setter
func = getattr(entity, setFuncName)
func(value)
else:
# set the param directly on the object
entity.__dict__[key] = value
"""
def getEntityCreateEvent(self, entId):
"""This is the event that is thrown immediately after an entity
is initialized"""
return 'entityCreate-%s-%s' % (self.levelId, entId)
def getEntity(self, entId):
return self.entities[entId]
def getEntityType(self, entId):
return self.entId2Spec[entId]['type']
def getZoneId(self, index):
# get the actual zoneId for this index
# TODO: perhaps the zones should be fixed up in the specs
return self.zoneIds[index]

View File

@ -0,0 +1,56 @@
"""NandLoEntityAI.py: contains the NandLoEntity class"""
import PandaObject
import DirectNotifyGlobal
import Entity
class NandLoEntityAI(Entity.Entity, PandaObject.PandaObject):
if __debug__:
notify = DirectNotifyGlobal.directNotify.newCategory(
'NandLoEntityAI')
def __init__(self, air, levelDoId, entId, zoneId=None):
"""entId: """
assert(self.debugPrint(
"NandLoEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
%("the air", levelDoId, entId, zoneId)))
self.input1 = None
self.input2 = None
self.levelDoId = levelDoId
level = air.doId2do[self.levelDoId]
Entity.Entity.__init__(self, level, entId)
self.initializeEntity()
self.setInput_input1_bool(self.input_input1_bool)
self.setInput_input2_bool(self.input_input2_bool)
def setIsInput1(self, isTrue):
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
self.isInput1=isTrue
messenger.send(self.getName(), [not (isTrue or self.isInput2)])
def setIsInput2(self, isTrue):
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
self.isInput2=isTrue
messenger.send(self.getName(), [not (isTrue or self.isInput1)])
def setInput_input1_bool(self, event):
assert(self.debugPrint("setInput_input1_bool(event=%s)"%(event,)))
if self.input1:
self.ignore(self.input1)
self.input1 = "switch-%s"%(event,)
if self.input1:
self.accept(self.input1, self.setIsInput1)
def setInput_input2_bool(self, event):
assert(self.debugPrint("setInput_input2_bool(event=%s)"%(event,)))
if self.input2:
self.ignore(self.input2)
self.input2 = "switch-%s"%(event,)
if self.input2:
self.accept(self.input2, self.setIsInput2)
def getName(self):
#return "NandLoEntity-%s"%(self.entId,)
return "switch-%s"%(self.entId,)

19
direct/src/level/OrLoEntity.py Executable file
View File

@ -0,0 +1,19 @@
"""OrLoEntity.py: contains the OrLoEntity class"""
class OrLoEntity(Entity.Entity):
if __debug__:
notify = DirectNotifyGlobal.directNotify.newCategory(
'OrLoEntity')
def __init__(self, air, levelDoId, entId, zoneId=None):
"""entId: """
assert(self.debugPrint(
"DistributedDoorEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
%("the air", levelDoId, entId, zoneId)))
self.doLaterTask=None
self.isOpenInput = None
DistributedInteractiveEntityAI.DistributedInteractiveEntityAI.__init__(
self, air, levelDoId, entId)
self.fsm.setName('DistributedDoorEntity')
if zoneId is not None:
self.generateWithRequired(zoneId)

View File

@ -0,0 +1,60 @@
"""OrLoEntityAI.py: contains the OrLoEntity class"""
import PandaObject
import DirectNotifyGlobal
import Entity
class OrLoEntityAI(Entity.Entity, PandaObject.PandaObject):
if __debug__:
notify = DirectNotifyGlobal.directNotify.newCategory(
'OrLoEntityAI')
def __init__(self, air, levelDoId, entId, zoneId=None):
"""entId: """
assert(self.debugPrint(
"OrLoEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
%("the air", levelDoId, entId, zoneId)))
self.input1 = None
self.input2 = None
self.levelDoId = levelDoId
level = air.doId2do[self.levelDoId]
Entity.Entity.__init__(self, level, entId)
self.initializeEntity()
self.setInput_input1_bool(self.input_input1_bool)
self.setInput_input2_bool(self.input_input2_bool)
def setIsInput1(self, isTrue):
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
self.isInput1=isTrue
if not self.isInput2:
# ...we already sent the messege when input2 was set.
messenger.send(self.getName(), [isTrue])
def setIsInput2(self, isTrue):
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
self.isInput2=isTrue
if not self.isInput1:
# ...we already sent the messege when input1 was set.
messenger.send(self.getName(), [isTrue])
def setInput_input1_bool(self, event):
assert(self.debugPrint("setInput_input1_bool(event=%s)"%(event,)))
if self.input1:
self.ignore(self.input1)
self.input1 = "switch-%s"%(event,)
if self.input1:
self.accept(self.input1, self.setIsInput1)
def setInput_input2_bool(self, event):
assert(self.debugPrint("setInput_input2_bool(event=%s)"%(event,)))
if self.input2:
self.ignore(self.input2)
self.input2 = "switch-%s"%(event,)
if self.input2:
self.accept(self.input2, self.setIsInput2)
def getName(self):
#return "orLoEntity-%s"%(self.entId,)
return "switch-%s"%(self.entId,)

View File

@ -0,0 +1,3 @@
// For now, since we are not installing Python files, this file can
// remain empty.

View File

View File

@ -0,0 +1,56 @@
"""XorLoEntityAI.py: contains the XorLoEntity class"""
import PandaObject
import DirectNotifyGlobal
import Entity
class XorLoEntityAI(Entity.Entity, PandaObject.PandaObject):
if __debug__:
notify = DirectNotifyGlobal.directNotify.newCategory(
'XorLoEntityAI')
def __init__(self, air, levelDoId, entId, zoneId=None):
"""entId: """
assert(self.debugPrint(
"XorLoEntityAI(air=%s, levelDoId=%s, entId=%s, zoneId=%s)"
%("the air", levelDoId, entId, zoneId)))
self.input1 = None
self.input2 = None
self.levelDoId = levelDoId
level = air.doId2do[self.levelDoId]
Entity.Entity.__init__(self, level, entId)
self.initializeEntity()
self.setInput_input1_bool(self.input_input1_bool)
self.setInput_input2_bool(self.input_input2_bool)
def setIsInput1(self, isTrue):
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
self.isInput1=isTrue
messenger.send(self.getName(), [(not (isTrue and self.isInput2)) and (isTrue or self.isInput2)])
def setIsInput2(self, isTrue):
assert(self.debugPrint("setIsInput1(isTrue=%s)"%(isTrue,)))
self.isInput2=isTrue
messenger.send(self.getName(), [(not (isTrue and self.isInput2)) and (isTrue or self.isInput2)])
def setInput_input1_bool(self, event):
assert(self.debugPrint("setInput_input1_bool(event=%s)"%(event,)))
if self.input1:
self.ignore(self.input1)
self.input1 = "switch-%s"%(event,)
if self.input1:
self.accept(self.input1, self.setIsInput1)
def setInput_input2_bool(self, event):
assert(self.debugPrint("setInput_input2_bool(event=%s)"%(event,)))
if self.input2:
self.ignore(self.input2)
self.input2 = "switch-%s"%(event,)
if self.input2:
self.accept(self.input2, self.setIsInput2)
def getName(self):
#return "xorLoEntity-%s"%(self.entId,)
return "switch-%s"%(self.entId,)