Poodletooth-iLand/panda/direct/distributed/OldClientRepository.py
Master Jumblespeed d882959bfa switch to remote
2015-05-18 22:11:33 -04:00

208 lines
7.5 KiB
Python
Executable file

"""OldClientRepository module: contains the OldClientRepository class"""
from ClientRepositoryBase import *
class OldClientRepository(ClientRepositoryBase):
"""
This is the open-source ClientRepository as provided by CMU. It
communicates with the ServerRepository in this same directory.
If you are looking for the VR Studio's implementation of the
client repository, look to OTPClientRepository (elsewhere).
"""
notify = DirectNotifyGlobal.directNotify.newCategory("ClientRepository")
def __init__(self, dcFileNames = None):
ClientRepositoryBase.__init__(self, dcFileNames = dcFileNames)
# The DOID allocator. The CMU LAN server may choose to
# send us a block of DOIDs. If it chooses to do so, then we
# may create objects, using those DOIDs.
self.DOIDbase = 0
self.DOIDnext = 0
self.DOIDlast = 0
def handleSetDOIDrange(self, di):
self.DOIDbase = di.getUint32()
self.DOIDlast = self.DOIDbase + di.getUint32()
self.DOIDnext = self.DOIDbase
def handleRequestGenerates(self, di):
# When new clients join the zone of an object, they need to hear
# about it, so we send out all of our information about objects in
# that particular zone.
assert self.DOIDnext < self.DOIDlast
zone = di.getUint32()
for obj in self.doId2do.values():
if obj.zone == zone:
id = obj.doId
if (self.isLocalId(id)):
self.send(obj.dclass.clientFormatGenerate(obj, id, zone, []))
def createWithRequired(self, className, zoneId = 0, optionalFields=None):
if self.DOIDnext >= self.DOIDlast:
self.notify.error(
"Cannot allocate a distributed object ID: all IDs used up.")
return None
id = self.DOIDnext
self.DOIDnext = self.DOIDnext + 1
dclass = self.dclassesByName[className]
classDef = dclass.getClassDef()
if classDef == None:
self.notify.error("Could not create an undefined %s object." % (
dclass.getName()))
obj = classDef(self)
obj.dclass = dclass
obj.zone = zoneId
obj.doId = id
self.doId2do[id] = obj
obj.generateInit()
obj._retrieveCachedData()
obj.generate()
obj.announceGenerate()
datagram = dclass.clientFormatGenerate(obj, id, zoneId, optionalFields)
self.send(datagram)
return obj
def sendDisableMsg(self, doId):
datagram = PyDatagram()
datagram.addUint16(CLIENT_OBJECT_DISABLE)
datagram.addUint32(doId)
self.send(datagram)
def sendDeleteMsg(self, doId):
datagram = PyDatagram()
datagram.addUint16(CLIENT_OBJECT_DELETE)
datagram.addUint32(doId)
self.send(datagram)
def sendRemoveZoneMsg(self, zoneId, visibleZoneList=None):
datagram = PyDatagram()
datagram.addUint16(CLIENT_REMOVE_ZONE)
datagram.addUint32(zoneId)
# if we have an explicit list of visible zones, add them
if visibleZoneList is not None:
vzl = list(visibleZoneList)
vzl.sort()
assert PythonUtil.uniqueElements(vzl)
for zone in vzl:
datagram.addUint32(zone)
# send the message
self.send(datagram)
def sendUpdateZone(self, obj, zoneId):
id = obj.doId
assert self.isLocalId(id)
self.sendDeleteMsg(id, 1)
obj.zone = zoneId
self.send(obj.dclass.clientFormatGenerate(obj, id, zoneId, []))
def sendSetZoneMsg(self, zoneId, visibleZoneList=None):
datagram = PyDatagram()
# Add message type
datagram.addUint16(CLIENT_SET_ZONE_CMU)
# Add zone id
datagram.addUint32(zoneId)
# if we have an explicit list of visible zones, add them
if visibleZoneList is not None:
vzl = list(visibleZoneList)
vzl.sort()
assert PythonUtil.uniqueElements(vzl)
for zone in vzl:
datagram.addUint32(zone)
# send the message
self.send(datagram)
def isLocalId(self, id):
return ((id >= self.DOIDbase) and (id < self.DOIDlast))
def haveCreateAuthority(self):
return (self.DOIDlast > self.DOIDnext)
def handleDatagram(self, di):
if self.notify.getDebug():
print "ClientRepository received datagram:"
di.getDatagram().dumpHex(ostream)
msgType = self.getMsgType()
# These are the sort of messages we may expect from the public
# Panda server.
if msgType == CLIENT_SET_DOID_RANGE:
self.handleSetDOIDrange(di)
elif msgType == CLIENT_CREATE_OBJECT_REQUIRED_RESP:
self.handleGenerateWithRequired(di)
elif msgType == CLIENT_CREATE_OBJECT_REQUIRED_OTHER_RESP:
self.handleGenerateWithRequiredOther(di)
elif msgType == CLIENT_OBJECT_UPDATE_FIELD_RESP:
self.handleUpdateField(di)
elif msgType == CLIENT_OBJECT_DELETE_RESP:
self.handleDelete(di)
elif msgType == CLIENT_OBJECT_DISABLE_RESP:
self.handleDisable(di)
elif msgType == CLIENT_REQUEST_GENERATES:
self.handleRequestGenerates(di)
else:
self.handleMessageType(msgType, di)
# If we're processing a lot of datagrams within one frame, we
# may forget to send heartbeats. Keep them coming!
self.considerHeartbeat()
def handleGenerateWithRequired(self, di):
# Get the class Id
classId = di.getUint16()
# Get the DO Id
doId = di.getUint32()
# Look up the dclass
dclass = self.dclassesByNumber[classId]
dclass.startGenerate()
# Create a new distributed object, and put it in the dictionary
distObj = self.generateWithRequiredFields(dclass, doId, di)
dclass.stopGenerate()
def generateWithRequiredFields(self, dclass, doId, di):
if doId in self.doId2do:
# ...it is in our dictionary.
# Just update it.
distObj = self.doId2do[doId]
assert distObj.dclass == dclass
distObj.generate()
distObj.updateRequiredFields(dclass, di)
# updateRequiredFields calls announceGenerate
elif self.cache.contains(doId):
# ...it is in the cache.
# Pull it out of the cache:
distObj = self.cache.retrieve(doId)
assert distObj.dclass == dclass
# put it in the dictionary:
self.doId2do[doId] = distObj
# and update it.
distObj.generate()
distObj.updateRequiredFields(dclass, di)
# updateRequiredFields calls announceGenerate
else:
# ...it is not in the dictionary or the cache.
# Construct a new one
classDef = dclass.getClassDef()
if classDef == None:
self.notify.error("Could not create an undefined %s object." % (
dclass.getName()))
distObj = classDef(self)
distObj.dclass = dclass
# Assign it an Id
distObj.doId = doId
# Put the new do in the dictionary
self.doId2do[doId] = distObj
# Update the required fields
distObj.generateInit() # Only called when constructed
distObj.generate()
distObj.updateRequiredFields(dclass, di)
# updateRequiredFields calls announceGenerate
return distObj