Source code for direct.cluster.ClusterMsgs

"""ClusterMsgs module: Message types for Cluster rendering"""

# This module is intended to supply routines and dataformats common to
# both ClusterClient and ClusterServer.

from panda3d.core import *
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
import time

#these are the types of messages that are currently supported.
CLUSTER_NONE                  = 0
CLUSTER_CAM_OFFSET            = 1
CLUSTER_CAM_FRUSTUM           = 2
CLUSTER_CAM_MOVEMENT          = 3
CLUSTER_SWAP_READY            = 4
CLUSTER_SWAP_NOW              = 5
CLUSTER_COMMAND_STRING        = 6
CLUSTER_SELECTED_MOVEMENT     = 7
CLUSTER_TIME_DATA             = 8
CLUSTER_NAMED_OBJECT_MOVEMENT = 9
CLUSTER_NAMED_MOVEMENT_DONE   = 10
CLUSTER_EXIT                  = 100

#Port number for cluster rendering
# DAEMON PORT IS PORT USED FOR STARTUP MESSAGE EXCHANGE
# CAN BE OVERRIDEN WITH cluster-daemon-client-port for client
# and cluster-daemon-server-port for server
CLUSTER_DAEMON_PORT = 8001
# THIS IS THE TCP PORT USED FOR EXCHANGE OF DATA ONCE STARTUP IS COMPLETE
CLUSTER_SERVER_PORT = 1970

# Precede command string with ! to tell server to execute command string
# NOTE: Had to stick with the import __builtin__ scheme, at startup,
# __builtins__ is a module, not a dictionary, like it is inside of a module
# Note, this startup string obviates the need to set any cluster related
# config variables in the client Configrc files
SERVER_STARTUP_STRING = (
    '!bash ppython -c ' +
    '"import __builtin__; ' +
    '__builtin__.clusterMode = \'server\';' +
    '__builtin__.clusterServerPort = %s;' +
    '__builtin__.clusterSyncFlag = %d;' +
    '__builtin__.clusterDaemonClient = \'%s\';' +
    '__builtin__.clusterDaemonPort = %d;'
    'from direct.directbase.DirectStart import *; run()"')

[docs]class ClusterMsgHandler: """ClusterMsgHandler: wrapper for PC clusters/multi-piping networking"""
[docs] def __init__(self, packetStart, notify): # packetStart can be used to distinguish which ClusterMsgHandler # sends a given packet. self.packetNumber = packetStart self.notify = notify
[docs] def nonBlockingRead(self, qcr): """ Return a datagram iterator and type if data is available on the queued connection reader """ if qcr.dataAvailable(): datagram = NetDatagram() if qcr.getData(datagram): (dgi, type) = self.readHeader(datagram) else: dgi = None type = CLUSTER_NONE self.notify.warning("getData returned false") else: datagram = None dgi = None type = CLUSTER_NONE # Note, return datagram to keep a handle on the data return (datagram, dgi, type)
[docs] def blockingRead(self, qcr): """ Block until data is available on the queued connection reader. Returns a datagram iterator and type """ while not qcr.dataAvailable(): # The following may not be necessary. # I just wanted some # time given to the operating system while # busy waiting. time.sleep(0.002) # Data is available, create a datagram iterator datagram = NetDatagram() if qcr.getData(datagram): (dgi, type) = self.readHeader(datagram) else: (dgi, type) = (None, CLUSTER_NONE) self.notify.warning("getData returned false") # Note, return datagram to keep a handle on the data return (datagram, dgi, type)
[docs] def readHeader(self, datagram): dgi = PyDatagramIterator(datagram) number = dgi.getUint32() type = dgi.getUint8() self.notify.debug("Packet %d type %d received" % (number, type)) return (dgi, type)
[docs] def makeCamOffsetDatagram(self, xyz, hpr): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_CAM_OFFSET) datagram.addFloat32(xyz[0]) datagram.addFloat32(xyz[1]) datagram.addFloat32(xyz[2]) datagram.addFloat32(hpr[0]) datagram.addFloat32(hpr[1]) datagram.addFloat32(hpr[2]) return datagram
[docs] def parseCamOffsetDatagram(self, dgi): x=dgi.getFloat32() y=dgi.getFloat32() z=dgi.getFloat32() h=dgi.getFloat32() p=dgi.getFloat32() r=dgi.getFloat32() self.notify.debug('new offset=%f %f %f %f %f %f' % (x, y, z, h, p, r)) return (x, y, z, h, p, r)
[docs] def makeCamFrustumDatagram(self, focalLength, filmSize, filmOffset): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_CAM_FRUSTUM) datagram.addFloat32(focalLength) datagram.addFloat32(filmSize[0]) datagram.addFloat32(filmSize[1]) datagram.addFloat32(filmOffset[0]) datagram.addFloat32(filmOffset[1]) return datagram
[docs] def parseCamFrustumDatagram(self, dgi): focalLength = dgi.getFloat32() filmSize = (dgi.getFloat32(), dgi.getFloat32()) filmOffset = (dgi.getFloat32(), dgi.getFloat32()) self.notify.debug('fl, fs, fo=%f, (%f, %f), (%f, %f)' % (focalLength, filmSize[0], filmSize[1], filmOffset[0], filmOffset[1])) return (focalLength, filmSize, filmOffset)
[docs] def makeCamMovementDatagram(self, xyz, hpr): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_CAM_MOVEMENT) datagram.addFloat32(xyz[0]) datagram.addFloat32(xyz[1]) datagram.addFloat32(xyz[2]) datagram.addFloat32(hpr[0]) datagram.addFloat32(hpr[1]) datagram.addFloat32(hpr[2]) return datagram
[docs] def makeNamedMovementDone(self): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_NAMED_MOVEMENT_DONE) return datagram
[docs] def makeNamedObjectMovementDatagram(self, xyz, hpr, scale, color, hidden, name): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_NAMED_OBJECT_MOVEMENT) datagram.addString(name) datagram.addFloat32(xyz[0]) datagram.addFloat32(xyz[1]) datagram.addFloat32(xyz[2]) datagram.addFloat32(hpr[0]) datagram.addFloat32(hpr[1]) datagram.addFloat32(hpr[2]) datagram.addFloat32(scale[0]) datagram.addFloat32(scale[1]) datagram.addFloat32(scale[2]) datagram.addFloat32(color[0]) datagram.addFloat32(color[1]) datagram.addFloat32(color[2]) datagram.addFloat32(color[3]) datagram.addBool(hidden) return datagram
[docs] def parseCamMovementDatagram(self, dgi): x=dgi.getFloat32() y=dgi.getFloat32() z=dgi.getFloat32() h=dgi.getFloat32() p=dgi.getFloat32() r=dgi.getFloat32() self.notify.debug((' new position=%f %f %f %f %f %f' % (x, y, z, h, p, r))) return (x, y, z, h, p, r)
[docs] def parseNamedMovementDatagram(self, dgi): name = dgi.getString() x=dgi.getFloat32() y=dgi.getFloat32() z=dgi.getFloat32() h=dgi.getFloat32() p=dgi.getFloat32() r=dgi.getFloat32() sx = dgi.getFloat32() sy = dgi.getFloat32() sz = dgi.getFloat32() red = dgi.getFloat32() g = dgi.getFloat32() b = dgi.getFloat32() a = dgi.getFloat32() hidden = dgi.getBool() return (name,x, y, z, h, p, r, sx, sy, sz, red, g, b, a, hidden)
[docs] def makeSelectedMovementDatagram(self, xyz, hpr, scale): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_SELECTED_MOVEMENT) datagram.addFloat32(xyz[0]) datagram.addFloat32(xyz[1]) datagram.addFloat32(xyz[2]) datagram.addFloat32(hpr[0]) datagram.addFloat32(hpr[1]) datagram.addFloat32(hpr[2]) datagram.addFloat32(scale[0]) datagram.addFloat32(scale[1]) datagram.addFloat32(scale[2]) #datagram.addBool(hidden) return datagram
[docs] def parseSelectedMovementDatagram(self, dgi): x=dgi.getFloat32() y=dgi.getFloat32() z=dgi.getFloat32() h=dgi.getFloat32() p=dgi.getFloat32() r=dgi.getFloat32() sx=dgi.getFloat32() sy=dgi.getFloat32() sz=dgi.getFloat32() self.notify.debug(' new position=%f %f %f %f %f %f %f %f %f' % (x, y, z, h, p, r, sx, sy, sz)) return (x, y, z, h, p, r, sx, sy, sz)
[docs] def makeCommandStringDatagram(self, commandString): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_COMMAND_STRING) datagram.addString(commandString) return datagram
[docs] def parseCommandStringDatagram(self, dgi): command = dgi.getString() return command
[docs] def makeSwapNowDatagram(self): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_SWAP_NOW) return datagram
[docs] def makeSwapReadyDatagram(self): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_SWAP_READY) return datagram
[docs] def makeExitDatagram(self): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_EXIT) return datagram
[docs] def makeTimeDataDatagram(self, frameCount, frameTime, dt): datagram = PyDatagram() datagram.addUint32(self.packetNumber) self.packetNumber = self.packetNumber + 1 datagram.addUint8(CLUSTER_TIME_DATA) datagram.addUint32(frameCount) datagram.addFloat32(frameTime) datagram.addFloat32(dt) return datagram
[docs] def parseTimeDataDatagram(self, dgi): frameCount=dgi.getUint32() frameTime=dgi.getFloat32() dt=dgi.getFloat32() self.notify.debug('time data=%f %f' % (frameTime, dt)) return (frameCount, frameTime, dt)