open_toontown_panda3d/direct/src/distributed/AstronDatabaseInterface.py

80 lines
2.8 KiB
Python

from pandac.PandaModules import *
from MsgTypes import *
from direct.directnotify import DirectNotifyGlobal
from ConnectionRepository import ConnectionRepository
from PyDatagram import PyDatagram
from PyDatagramIterator import PyDatagramIterator
class AstronDatabaseInterface:
"""
This class is part of Panda3D's new MMO networking framework.
It interfaces with Astron database(s) to manage objects directly, rather than
via DB-StateServers.
Do not create this class directly; instead, use AstronInternalRepository's
dbInterface attribute.
"""
notify = DirectNotifyGlobal.directNotify.newCategory("AstronDatabaseInterface")
def __init__(self, air):
self.air = air
self._callbacks = {}
def createObject(self, databaseId, dclass, fields={}, callback=None):
"""
Create an object in the specified database.
databaseId specifies the control channel of the target database.
dclass specifies the class of the object to be created.
fields is a dict with any fields that should be stored in the object on creation.
callback will be called with callback(doId) if specified. On failure, doId is 0.
"""
# Save the callback:
ctx = self.air.contextAllocator.allocate()
self._callbacks[ctx] = callback
# Pack up/count valid fields.
fieldPacker = DCPacker()
fieldCount = 0
for k,v in fields.items():
field = dclass.getFieldByName(k)
if not field:
self.notify.warning('Creation request for %s object contains '
'invalid field named %s' % (dclass.getName(), k))
continue
fieldPacker.rawPackUint16(field.getNumber())
fieldPacker.beginPack(field)
field.packArgs(fieldPacker, v)
fieldPacker.endPack()
fieldCount += 1
# Now generate and send the datagram:
dg = PyDatagram()
dg.addServerHeader(databaseId, self.air.ourChannel, DBSERVER_OBJECT_CREATE)
dg.addUint32(ctx)
dg.addUint16(dclass.getNumber())
dg.addUint16(fieldCount)
dg.appendData(fieldPacker.getString())
self.air.send(dg)
def handleCreateObjectResp(self, di):
ctx = di.getUint32()
doId = di.getUint32()
if ctx not in self._callbacks:
self.notify.warning('Received unexpected DBSERVER_OBJECT_CREATE_RESP'
' (ctx %d, doId %d)' % (ctx, doId))
return
self._callbacks[ctx](doId)
del self._callbacks[ctx]
self.air.contextAllocator.free(ctx)
def handleDatagram(self, msgType, di):
if msgType == DBSERVER_OBJECT_CREATE_RESP:
self.handleCreateObjectResp(di)