Message types. Skeleton of AstronClientRepository.py.
This commit is contained in:
parent
a959c2ba2f
commit
e4a83aaa6e
|
|
@ -0,0 +1,192 @@
|
|||
"""AstronClientRepository module: contains the AstronClientRepository class"""
|
||||
|
||||
from ClientRepositoryBase import ClientRepositoryBase
|
||||
from MsgTypesAstron import *
|
||||
|
||||
class AstronClientRepository(ClientRepositoryBase):
|
||||
"""
|
||||
The Astron implementation of a clients repository for
|
||||
communication with an Astron ClientAgent.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
ClientRepositoryBase.__init__(self, *args, **kwargs)
|
||||
base.finalExitCallbacks.append(self.shutdown)
|
||||
# FIXME: Partial code from ClientRepository.py may be required here.
|
||||
|
||||
#
|
||||
# Message Handling
|
||||
#
|
||||
|
||||
def handleDatagram(self, di):
|
||||
|
||||
msgType = self.getMsgType()
|
||||
|
||||
# These are the messages to a client that Astron specifies.
|
||||
|
||||
if msgType == CLIENT_HELLO_RESP:
|
||||
messenger.send("CLIENT_HELLO_RESP", [])
|
||||
elif msgType == CLIENT_EJECT:
|
||||
error_code = di.get_uint16()
|
||||
reason = di.get_string()
|
||||
messenger.send("CLIENT_EJECT", [error_code, reason])
|
||||
elif msgType == CLIENT_ENTER_OBJECT_REQUIRED:
|
||||
self.handleEnterObjectRequired(di)
|
||||
elif msgType == CLIENT_ENTER_OBJECT_REQUIRED_OWNER:
|
||||
self.handleEnterObjectRequiredOwner(di)
|
||||
# FIXME: These are supposedly handled in cConnectionRepository
|
||||
#elif msgType == CLIENT_OBJECT_SET_FIELD:
|
||||
# self.handleObjectSetField(di)
|
||||
#elif msgType == CLIENT_OBJECT_SET_FIELDS:
|
||||
# self.handleObjectSetFields(di)
|
||||
elif msgType == CLIENT_OBJECT_LEAVING:
|
||||
self.handleObjectLeaving(di)
|
||||
elif msgType == CLIENT_OBJECT_LOCATION:
|
||||
self.handleObjectLocation(di)
|
||||
elif msgType == CLIENT_ADD_INTEREST:
|
||||
self.handleAddInterest(di)
|
||||
elif msgType == CLIENT_ADD_INTEREST_MULTIPLE:
|
||||
self.handleAddInterestMultiple(di)
|
||||
elif msgType == CLIENT_REMOVE_INTEREST:
|
||||
self.handleRemoveInterest(di)
|
||||
else:
|
||||
self.handleMessageType(msgType, di)
|
||||
|
||||
self.considerHeartbeat()
|
||||
|
||||
def handleEnterObjectRequired(di)
|
||||
do_id = di.getArg(STUint32)
|
||||
parent_id = di.getArg(STUint32)
|
||||
zone_id = di.getArg(STUint32)
|
||||
dclass_id = di.getArg(STUint16)
|
||||
dclass = self.dclassesByNumber[dclass_id]
|
||||
self.generateWithRequiredFields(dclass, do_id, di, parent_id, zone_id)
|
||||
|
||||
def handleEnterObjectRequiredOwner(di)
|
||||
avatar_doId = di.getArg(STUint32)
|
||||
parentId = di.getArg(STUint32)
|
||||
zoneId = di.getArg(STUint32)
|
||||
dclass_id = di.getArg(STUint16)
|
||||
dclass = self.dclassesByNumber[dclass_id]
|
||||
self.generateWithRequiredFieldsOwner(dclass, avatar_doId, di)
|
||||
|
||||
def generateWithRequiredFieldsOwner(self, dclass, doId, di):
|
||||
if doId in self.doId2ownerView:
|
||||
# ...it is in our dictionary.
|
||||
# Just update it.
|
||||
self.notify.error('duplicate owner generate for %s (%s)' % (
|
||||
doId, dclass.getName()))
|
||||
distObj = self.doId2ownerView[doId]
|
||||
assert distObj.dclass == dclass
|
||||
distObj.generate()
|
||||
distObj.updateRequiredFields(dclass, di)
|
||||
# updateRequiredFields calls announceGenerate
|
||||
elif self.cacheOwner.contains(doId):
|
||||
# ...it is in the cache.
|
||||
# Pull it out of the cache:
|
||||
distObj = self.cacheOwner.retrieve(doId)
|
||||
assert distObj.dclass == dclass
|
||||
# put it in the dictionary:
|
||||
self.doId2ownerView[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.getOwnerClassDef()
|
||||
if classDef == None:
|
||||
self.notify.error("Could not create an undefined %s object. Have you created an owner view?" % (dclass.getName()))
|
||||
distObj = classDef(self)
|
||||
distObj.dclass = dclass
|
||||
# Assign it an Id
|
||||
distObj.doId = doId
|
||||
# Put the new do in the dictionary
|
||||
self.doId2ownerView[doId] = distObj
|
||||
# Update the required fields
|
||||
distObj.generateInit() # Only called when constructed
|
||||
distObj.generate()
|
||||
distObj.updateRequiredFields(dclass, di)
|
||||
# updateRequiredFields calls announceGenerate
|
||||
return distObj
|
||||
|
||||
def handleObjectSetField(di):
|
||||
do_id = di.getArg(STUint32)
|
||||
field_id = di.getArg(STUint16)
|
||||
# FIXME: Is this really the best way?
|
||||
do = self.doId2do[do_id]
|
||||
# FIXME: Figure out field types and unpack them, or use
|
||||
# some code that auto-unpacks them.
|
||||
field_name = self.get_dc_file().get_field_by_index(field_id).get_name()
|
||||
# FIXME: You actually need to figure out the fields types and unpack them!
|
||||
self.sendUpdate(field_name, [fieldArguments])
|
||||
|
||||
def handleObjectSetFields(di):
|
||||
# FIXME: Implement this!
|
||||
pass
|
||||
|
||||
def handleObjectLeaving(di):
|
||||
# FIXME: Implement this!
|
||||
pass
|
||||
|
||||
def handleObjectLocation(di):
|
||||
# FIXME: Implement this!
|
||||
pass
|
||||
|
||||
def handleAddInterest(di):
|
||||
# FIXME: Implement this!
|
||||
pass
|
||||
|
||||
def handleAddInterestMultiple(di):
|
||||
# FIXME: Implement this!
|
||||
pass
|
||||
|
||||
def handleRemoveInterest(di):
|
||||
# FIXME: Implement this!
|
||||
pass
|
||||
|
||||
#
|
||||
# Sending messages
|
||||
#
|
||||
|
||||
# FIXME: The version string should default to a .prc variable.
|
||||
def sendHello(self, version_string):
|
||||
dg = PyDatagram()
|
||||
dg.add_uint16(MsgTypes.CLIENT_HELLO)
|
||||
dg.add_uint32(self.get_dc_file().get_hash())
|
||||
dg.add_string(version_string)
|
||||
self.send(dg)
|
||||
|
||||
def sendHeartbeat(self):
|
||||
datagram = PyDatagram()
|
||||
datagram.addUint16(CLIENT_HEARTBEAT)
|
||||
self.send(datagram)
|
||||
|
||||
def sendAddInterest(self, context, interest_id, parent_id, zone_id):
|
||||
dg = PyDatagram()
|
||||
dg.add_uint16(MsgTypes.CLIENT_ADD_INTEREST)
|
||||
dg.add_uint32(context)
|
||||
dg.add_uint16(interest_id)
|
||||
dg.add_uint32(parent_id)
|
||||
dg.add_uint32(zone_id)
|
||||
self.send(dg)
|
||||
|
||||
def sendAddInterestMultiple(self, context, interest_id, parent_id, zone_ids):
|
||||
dg = PyDatagram()
|
||||
dg.add_uint16(MsgTypes.CLIENT_ADD_INTEREST_MULTIPLE)
|
||||
dg.add_uint32(context)
|
||||
dg.add_uint16(interest_id)
|
||||
dg.add_uint32(parent_id)
|
||||
dg.add_uint16(len(zone_ids))
|
||||
for zone_id in zone_ids:
|
||||
dg.add_uint32(zone_id)
|
||||
self.send(dg)
|
||||
|
||||
def sendRemoveInterest(self, context, interest_id):
|
||||
dg = PyDatagram()
|
||||
dg.add_uint16(MsgTypes.CLIENT_REMOVE_INTEREST)
|
||||
dg.add_uint32(context)
|
||||
dg.add_uint16(interest_id)
|
||||
self.send(dg)
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
"""MsgTypesAstron module: contains distributed object message types"""
|
||||
|
||||
from direct.showbase.PythonUtil import invertDictLossless
|
||||
|
||||
MsgName2Id = {
|
||||
'CLIENT_HELLO': 1,
|
||||
'CLIENT_HELLO_RESP': 2,
|
||||
'CLIENT_DISCONNECT': 3,
|
||||
'CLIENT_EJECT': 4,
|
||||
'CLIENT_HEARTBEAT': 5,
|
||||
'CLIENT_ENTER_OBJECT_REQUIRED': 142,
|
||||
'CLIENT_ENTER_OBJECT_REQUIRED_OTHER': 143,
|
||||
'CLIENT_ENTER_OBJECT_REQUIRED_OWNER': 172,
|
||||
'CLIENT_ENTER_OBJECT_REQUIRED_OTHER_OWNER': 173,
|
||||
'CLIENT_OBJECT_SET_FIELD': 120,
|
||||
'CLIENT_OBJECT_SET_FIELDS': 121,
|
||||
'CLIENT_OBJECT_LEAVING': 132,
|
||||
'CLIENT_OBJECT_LOCATION': 140,
|
||||
'CLIENT_ADD_INTEREST': 200,
|
||||
'CLIENT_ADD_INTEREST_MULTIPLE': 201,
|
||||
'CLIENT_REMOVE_INTEREST': 203,
|
||||
'CLIENT_DONE_INTEREST_RESP': 204,
|
||||
}
|
||||
|
||||
# create id->name table for debugging
|
||||
MsgId2Names = invertDictLossless(MsgName2Id)
|
||||
|
||||
# put msg names in module scope, assigned to msg value
|
||||
for name, value in MsgName2Id.items():
|
||||
exec '%s = %s' % (name, value)
|
||||
del name, value
|
||||
|
||||
Loading…
Reference in New Issue