diff --git a/direct/src/distributed/ClientDistClass.py b/direct/src/distributed/ClientDistClass.py index c5de65454b..3383e03ead 100644 --- a/direct/src/distributed/ClientDistClass.py +++ b/direct/src/distributed/ClientDistClass.py @@ -2,20 +2,61 @@ from PandaModules import * import DirectNotifyGlobal +import ClientDistUpdate class ClientDistClass: def __init__(self, dcClass): - self.number = dcClass.get_number() - self.name = dcClass.get_name() - self.atomicFields=[] - self.molecularFields=[] - self.parseAtomicFields(dcClass) - self.parseMolecularFields(dcClass) + self.number = dcClass.getNumber() + self.name = dcClass.getName() + self.allFields = self.parseFields(dcClass) + self.allCDU = self.createAllCDU(self.allFields) + self.number2CDU = self.createNumber2CDUDict(self.allCDU) + self.name2CDU = self.createName2CDUDict(self.allCDU) return None - def parseAtomicFields(dcClass): - for i in range(0,dcClass.get_num_inherited_atomics()): - self.atomicFields.append((dcClass.get_inherited_atomic(i)) + def parseFields(self, dcClass): + fields=[] + for i in range(0,dcClass.getNumInheritedFields()): + fields.append(dcClass.getInheritedField(i)) + return fields + + def createAllCDU(self, allFields): + allCDU = [] + for i in allFields: + allCDU.append(ClientDistUpdate.ClientDistUpdate(i)) + return allCDU + + def createNumber2CDUDict(self, allCDU): + dict={} + for i in allCDU: + dict[i.number] = i + return dict + + def createName2CDUDict(self, allCDU): + dict={} + for i in allCDU: + dict[i.name] = i + return dict + + def updateField(self, do, di): + # Get the update field id + fieldId = di.getArg(ST_uint8) + # look up the CDU + assert(self.number2CDU.has_key(fieldId)) + cdu = self.number2CDU[fieldId] + # Let the cdu finish the job + cdu.updateField(cdc, do, di) + return None + + def sendUpdate(self, do, fieldName, args): + # Look up the cdu + assert(self.name2CDU.has_key(fieldName)) + cdu = self.name2CDU[fieldName] + # Let the cdu finish the job + cdu.sendUpdate(do, args) + + + diff --git a/direct/src/distributed/ClientDistUpdate.py b/direct/src/distributed/ClientDistUpdate.py new file mode 100644 index 0000000000..96f067edcc --- /dev/null +++ b/direct/src/distributed/ClientDistUpdate.py @@ -0,0 +1,65 @@ +"""ClientDistUpdate module: contains the ClientDistUpdate class""" + +import DirectNotifyGlobal + +class ClientDistUpdate: + notify = DirectNotifyGlobal.directNotify.newCategory("ClientDistUpdate") + + def __init__(self, dcField): + self.number = dcField.getNumber() + self.name = dcField.getName() + self.types = self.deriveTypesFromParticle(dcField) + return None + + def deriveTypesFromParticle(self, dcField): + typeList=[] + dcFieldAtomic = dcField.asAtomicField() + dcFieldMolecular = dcField.asMolecularField() + if dcFieldAtomic: + for i in range(0, dcFieldAtomic.getNumElements()): + typeList.append(dcFieldAtomic.getElementType(i)) + elif dcFieldMolecular: + for i in range(0, dcFieldMolecular.getNumAtomics()): + componentField = dcFieldMolecular.getAtomic(i) + for j in range(0, componentField.getNumElements()): + typeList.append(componentField.getElementType(j)) + else: + ClientDistUpdate.notify.error("field is neither atom nor molecule") + return typeList + + def updateField(self, cdc, do, di): + # Look up the class + aClass = eval(cdc.name) + # Look up the function + assert(aClass.__dict__.has_key(self.name)) + func = aClass.__dict__[self.name] + # Get the arguments into a list + args = self.extractArgs(di) + # Apply the function to the object with the arguments + apply(func, [do] + args) + return None + + def extractArgs(self, di): + args = [] + for i in self.types: + args.append(di.getArgs(i)) + return args + + def addArgs(self, datagram, args): + # Add the args to the datagram + numElems = len(args) + assert (numElems == len(self.types)) + for i in range(0, numElems): + datagram.addArg(args[i], self.types[i]) + + def sendUpdate(self, do, args): + datagram = Datagram() + # Add message type + datagram.addUint16(ALL_OBJECT_UPDATE_FIELD) + # Add the DO id + datagram.addUint32(do.doId) + # Add the field id + datagram.addUint8(self.number) + # Add the arguments + self.addArgs(datagram, args) + # send the datagram diff --git a/direct/src/distributed/ClientRepository.py b/direct/src/distributed/ClientRepository.py index abd94a4ee7..da5bc0b70c 100644 --- a/direct/src/distributed/ClientRepository.py +++ b/direct/src/distributed/ClientRepository.py @@ -4,35 +4,37 @@ from PandaModules import * from TaskManagerGlobal import * import Task import DirectNotifyGlobal +import ClientDistClass class ClientRepository: defaultServerPort = 5150 notify = DirectNotifyGlobal.directNotify.newCategory("ClientRepository") - def __init__(self, dcFileName): + def __init__(self, dcFileName, AIClientFlag=0): + self.AIClientFlag=AIClientFlag self.number2cdc={} self.name2cdc={} + self.doId2do={} + self.doId2cdc={} self.parseDcFile(dcFileName) return None - def parseDcFile(dcFileName): - dcFile = DCFile() - dcFile.read(dcFileName) - return self.parseDcClasses(dcFile) + def parseDcFile(self, dcFileName): + self.dcFile = DCFile() + self.dcFile.read(dcFileName) + return self.parseDcClasses(self.dcFile) - def parseDcClasses(dcFile): - numClasses = dcFile.get_num_classes() + def parseDcClasses(self, dcFile): + numClasses = dcFile.getNumClasses() for i in range(0, numClasses): # Create a clientDistClass from the dcClass - clientDistClass = self.parseClass(dcFile.getClass()) + dcClass = dcFile.getClass(i) + clientDistClass = ClientDistClass.ClientDistClass(dcClass) # List the cdc in the number and name dictionaries - self.number2cdc[clientDistClass.getNumber()]=clientDistClass - self.name2cdc[clientDistClass.getName()]=clientDistClass + self.number2cdc[dcClass.getNumber()]=clientDistClass + self.name2cdc[dcClass.getName()]=clientDistClass return None - def parseClass(dcClass): - - def connect(self, serverName="localhost", serverPort=defaultServerPort): self.qcm=QueuedConnectionManager() @@ -64,9 +66,65 @@ class ClientRepository: return availGetVal def handleDatagram(datagram): - print 'Got it!' + di = DatagramIterator(datagram) + msgType = di.getArg(ST_uint16) + + if msgType == ALL_OBJECT_GENERATE_WITH_REQUIRED: + self.handleGenerateWithRequired(di) + elif msgType == ALL_OBJECT_UPDATE_FIELD: + self.handleUpdateField(di) + else: + ClientRepository.notify.warning("We don't handle type: " + + str(msgType)) return None + def handleGenerateWithRequired(di): + # Get the class Id + classId = di.getArg(ST_uint8); + # Get the DO Id + doId = di.getArg(ST_uint32) + # Get the echo context + echoContext = di.getArg(ST_uint32); + # Look up the cdc + cdc = self.number2cdc[classId] + # Create a new distributed object, and put it in the dictionary + distObj = self.generateWithRequiredFields(cdc, doId, di) + return None + + def generateWithRequiredFields(cdc, doId, di): + # Someday, this function will look in a cache of old distributed + # objects to see if this object is in there, and pull it + # out if necessary. For now, we'll just check to see if + # it is in the standard dictionary, and ignore this update + # if it is there. The right thing to do would be to update + # all the required fields, but that will come later, too. + + if self.doId2do.has_key(doId): + ClientRepository.notify.warning("doId: " + + str(doId) + + " was generated again") + distObj = self.doId2do(doId) + else: + distObj = \ + eval(cdc.name).generateWithRequiredFields(doId, di) + # Put the new do in both dictionaries + self.doId2do[doId] = distObj + self.doId2cdc[doId] = cdc + + return distObj + + def handleUpdateField(di): + # Get the DO Id + doId = di.getArg(ST_uint32) + # Find the DO + assert(self.doId2do.has_key(doId)) + do = self.doId2do(doId) + # Find the cdc + assert(self.doId2cdc.has_key(doId)) + cdc = self.doId2cdc[doId] + # Let the cdc finish the job + cdc.updateField(do, di) + def sendLoginMsg(self): datagram = Datagram() # Add message type @@ -80,5 +138,12 @@ class ClientRepository: # Send the message self.cw.send(datagram, self.tcpConn) - + def sendUpdate(self, do, fieldName, args): + # Get the DO id + doId = do.doId + # Get the cdc + assert(self.doId2cdc.has_key(doId)) + cdc = self.doId2cdc[doId] + # Let the cdc finish the job + cdc.sendUpdate(do, fieldName, args) diff --git a/direct/src/extensions/Datagram-extensions.py b/direct/src/extensions/Datagram-extensions.py new file mode 100644 index 0000000000..8580162c24 --- /dev/null +++ b/direct/src/extensions/Datagram-extensions.py @@ -0,0 +1,27 @@ + + def putArg(self, arg, subatomicType): + # Import the type numbers + from DCSubatomicType import * + if subatomicType == STInt8: + self.addInt8(arg) + elif subatomicType == STInt16: + self.addInt16(arg) + elif subatomicType == STInt32: + self.addInt32(arg) + elif subatomicType == STInt64: + self.addInt64(arg) + elif subatomicType == STUint8: + self.addUint8(arg) + elif subatomicType == STUint16: + self.addUint16(arg) + elif subatomicType == STUint32: + self.addUint32(arg) + elif subatomicType == STUint64: + self.addUint64(arg) + elif subatomicType == STFloat64: + self.addFloat64(arg) + elif subatomicType == STString: + self.addString(arg) + else: + raise Exception("Error: No such type as: " + subatomicType) + return None diff --git a/direct/src/extensions/DatagramIterator-extensions.py b/direct/src/extensions/DatagramIterator-extensions.py new file mode 100644 index 0000000000..a91f63232e --- /dev/null +++ b/direct/src/extensions/DatagramIterator-extensions.py @@ -0,0 +1,29 @@ + + def getArg(self, subatomicType): + # Import the type numbers + from DCSubatomicType import * + if subatomicType == STInt8: + retVal = self.getInt8() + elif subatomicType == STInt16: + retVal = self.getInt16() + elif subatomicType == STInt32: + retVal = self.getInt32() + elif subatomicType == STInt64: + retVal = self.getInt64() + elif subatomicType == STUint8: + retVal = self.getUint8() + elif subatomicType == STUint16: + retVal = self.getUint16() + elif subatomicType == STUint32: + retVal = self.getUint32() + elif subatomicType == STUint64: + retVal = self.getUint64() + elif subatomicType == STFloat64: + retVal = self.getFloat64() + elif subatomicType == STString: + retVal = self.getString() + else: + raise Exception("Error: No such type as: " + str(subAtomicType)) + return retVal + +