Add AstronDatabaseInterface, which can generate objects into an Astron DB.

This commit is contained in:
Sam Edwards 2013-10-15 04:10:40 -06:00
parent 1ca02ae9e1
commit f74dc9b35d
2 changed files with 86 additions and 1 deletions

View File

@ -0,0 +1,79 @@
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)

View File

@ -4,6 +4,7 @@ from direct.directnotify import DirectNotifyGlobal
from ConnectionRepository import ConnectionRepository
from PyDatagram import PyDatagram
from PyDatagramIterator import PyDatagramIterator
from AstronDatabaseInterface import AstronDatabaseInterface
class AstronInternalRepository(ConnectionRepository):
"""
@ -40,6 +41,10 @@ class AstronInternalRepository(ConnectionRepository):
self.channelAllocator = UniqueIdAllocator(baseChannel, baseChannel+maxChannels-1)
self._registeredChannels = set()
self.contextAllocator = UniqueIdAllocator(0, 100)
self.dbInterface = AstronDatabaseInterface(self)
self.ourChannel = self.allocateChannel()
self.eventLogId = self.config.GetString('eventlog-id', 'AIR:%d' % self.ourChannel)
@ -137,7 +142,8 @@ class AstronInternalRepository(ConnectionRepository):
self.handleObjEntry(di)
elif msgType == STATESERVER_OBJECT_LEAVING_AI_INTEREST:
self.handleObjExit(di)
elif msgType in (DBSERVER_OBJECT_CREATE_RESP,):
self.dbInterface.handleDatagram(msgType, di)
def handleObjEntry(self, di):
parentId = di.getUint32()