ClusterMsgs.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. """ClusterMsgs module: Message types for Cluster rendering"""
  2. # This module is intended to supply routines and dataformats common to
  3. # both ClusterClient and ClusterServer.
  4. from panda3d.core import *
  5. from direct.distributed.PyDatagram import PyDatagram
  6. from direct.distributed.PyDatagramIterator import PyDatagramIterator
  7. import time
  8. #these are the types of messages that are currently supported.
  9. CLUSTER_NONE = 0
  10. CLUSTER_CAM_OFFSET = 1
  11. CLUSTER_CAM_FRUSTUM = 2
  12. CLUSTER_CAM_MOVEMENT = 3
  13. CLUSTER_SWAP_READY = 4
  14. CLUSTER_SWAP_NOW = 5
  15. CLUSTER_COMMAND_STRING = 6
  16. CLUSTER_SELECTED_MOVEMENT = 7
  17. CLUSTER_TIME_DATA = 8
  18. CLUSTER_NAMED_OBJECT_MOVEMENT = 9
  19. CLUSTER_NAMED_MOVEMENT_DONE = 10
  20. CLUSTER_EXIT = 100
  21. #Port number for cluster rendering
  22. # DAEMON PORT IS PORT USED FOR STARTUP MESSAGE EXCHANGE
  23. # CAN BE OVERRIDEN WITH cluster-daemon-client-port for client
  24. # and cluster-daemon-server-port for server
  25. CLUSTER_DAEMON_PORT = 8001
  26. # THIS IS THE TCP PORT USED FOR EXCHANGE OF DATA ONCE STARTUP IS COMPLETE
  27. CLUSTER_SERVER_PORT = 1970
  28. # Precede command string with ! to tell server to execute command string
  29. # NOTE: Had to stick with the import __builtin__ scheme, at startup,
  30. # __builtins__ is a module, not a dictionary, like it is inside of a module
  31. # Note, this startup string obviates the need to set any cluster related
  32. # config variables in the client Configrc files
  33. SERVER_STARTUP_STRING = (
  34. '!bash ppython -c ' +
  35. '"import __builtin__; ' +
  36. '__builtin__.clusterMode = \'server\';' +
  37. '__builtin__.clusterServerPort = %s;' +
  38. '__builtin__.clusterSyncFlag = %d;' +
  39. '__builtin__.clusterDaemonClient = \'%s\';' +
  40. '__builtin__.clusterDaemonPort = %d;'
  41. 'from direct.directbase.DirectStart import *; run()"')
  42. class ClusterMsgHandler:
  43. """ClusterMsgHandler: wrapper for PC clusters/multi-piping networking"""
  44. def __init__(self, packetStart, notify):
  45. # packetStart can be used to distinguish which ClusterMsgHandler
  46. # sends a given packet.
  47. self.packetNumber = packetStart
  48. self.notify = notify
  49. def nonBlockingRead(self, qcr):
  50. """
  51. Return a datagram iterator and type if data is available on the
  52. queued connection reader
  53. """
  54. if qcr.dataAvailable():
  55. datagram = NetDatagram()
  56. if qcr.getData(datagram):
  57. (dgi, type) = self.readHeader(datagram)
  58. else:
  59. dgi = None
  60. type = CLUSTER_NONE
  61. self.notify.warning("getData returned false")
  62. else:
  63. datagram = None
  64. dgi = None
  65. type = CLUSTER_NONE
  66. # Note, return datagram to keep a handle on the data
  67. return (datagram, dgi, type)
  68. def blockingRead(self, qcr):
  69. """
  70. Block until data is available on the queued connection reader.
  71. Returns a datagram iterator and type
  72. """
  73. while not qcr.dataAvailable():
  74. # The following may not be necessary.
  75. # I just wanted some
  76. # time given to the operating system while
  77. # busy waiting.
  78. time.sleep(0.002)
  79. # Data is available, create a datagram iterator
  80. datagram = NetDatagram()
  81. if qcr.getData(datagram):
  82. (dgi, type) = self.readHeader(datagram)
  83. else:
  84. (dgi, type) = (None, CLUSTER_NONE)
  85. self.notify.warning("getData returned false")
  86. # Note, return datagram to keep a handle on the data
  87. return (datagram, dgi, type)
  88. def readHeader(self, datagram):
  89. dgi = PyDatagramIterator(datagram)
  90. number = dgi.getUint32()
  91. type = dgi.getUint8()
  92. self.notify.debug("Packet %d type %d received" % (number, type))
  93. return (dgi, type)
  94. def makeCamOffsetDatagram(self, xyz, hpr):
  95. datagram = PyDatagram()
  96. datagram.addUint32(self.packetNumber)
  97. self.packetNumber = self.packetNumber + 1
  98. datagram.addUint8(CLUSTER_CAM_OFFSET)
  99. datagram.addFloat32(xyz[0])
  100. datagram.addFloat32(xyz[1])
  101. datagram.addFloat32(xyz[2])
  102. datagram.addFloat32(hpr[0])
  103. datagram.addFloat32(hpr[1])
  104. datagram.addFloat32(hpr[2])
  105. return datagram
  106. def parseCamOffsetDatagram(self, dgi):
  107. x=dgi.getFloat32()
  108. y=dgi.getFloat32()
  109. z=dgi.getFloat32()
  110. h=dgi.getFloat32()
  111. p=dgi.getFloat32()
  112. r=dgi.getFloat32()
  113. self.notify.debug('new offset=%f %f %f %f %f %f' % (x, y, z, h, p, r))
  114. return (x, y, z, h, p, r)
  115. def makeCamFrustumDatagram(self, focalLength, filmSize, filmOffset):
  116. datagram = PyDatagram()
  117. datagram.addUint32(self.packetNumber)
  118. self.packetNumber = self.packetNumber + 1
  119. datagram.addUint8(CLUSTER_CAM_FRUSTUM)
  120. datagram.addFloat32(focalLength)
  121. datagram.addFloat32(filmSize[0])
  122. datagram.addFloat32(filmSize[1])
  123. datagram.addFloat32(filmOffset[0])
  124. datagram.addFloat32(filmOffset[1])
  125. return datagram
  126. def parseCamFrustumDatagram(self, dgi):
  127. focalLength = dgi.getFloat32()
  128. filmSize = (dgi.getFloat32(), dgi.getFloat32())
  129. filmOffset = (dgi.getFloat32(), dgi.getFloat32())
  130. self.notify.debug('fl, fs, fo=%f, (%f, %f), (%f, %f)' %
  131. (focalLength, filmSize[0], filmSize[1],
  132. filmOffset[0], filmOffset[1]))
  133. return (focalLength, filmSize, filmOffset)
  134. def makeCamMovementDatagram(self, xyz, hpr):
  135. datagram = PyDatagram()
  136. datagram.addUint32(self.packetNumber)
  137. self.packetNumber = self.packetNumber + 1
  138. datagram.addUint8(CLUSTER_CAM_MOVEMENT)
  139. datagram.addFloat32(xyz[0])
  140. datagram.addFloat32(xyz[1])
  141. datagram.addFloat32(xyz[2])
  142. datagram.addFloat32(hpr[0])
  143. datagram.addFloat32(hpr[1])
  144. datagram.addFloat32(hpr[2])
  145. return datagram
  146. def makeNamedMovementDone(self):
  147. datagram = PyDatagram()
  148. datagram.addUint32(self.packetNumber)
  149. self.packetNumber = self.packetNumber + 1
  150. datagram.addUint8(CLUSTER_NAMED_MOVEMENT_DONE)
  151. return datagram
  152. def makeNamedObjectMovementDatagram(self, xyz, hpr, scale, color, hidden, name):
  153. datagram = PyDatagram()
  154. datagram.addUint32(self.packetNumber)
  155. self.packetNumber = self.packetNumber + 1
  156. datagram.addUint8(CLUSTER_NAMED_OBJECT_MOVEMENT)
  157. datagram.addString(name)
  158. datagram.addFloat32(xyz[0])
  159. datagram.addFloat32(xyz[1])
  160. datagram.addFloat32(xyz[2])
  161. datagram.addFloat32(hpr[0])
  162. datagram.addFloat32(hpr[1])
  163. datagram.addFloat32(hpr[2])
  164. datagram.addFloat32(scale[0])
  165. datagram.addFloat32(scale[1])
  166. datagram.addFloat32(scale[2])
  167. datagram.addFloat32(color[0])
  168. datagram.addFloat32(color[1])
  169. datagram.addFloat32(color[2])
  170. datagram.addFloat32(color[3])
  171. datagram.addBool(hidden)
  172. return datagram
  173. def parseCamMovementDatagram(self, dgi):
  174. x=dgi.getFloat32()
  175. y=dgi.getFloat32()
  176. z=dgi.getFloat32()
  177. h=dgi.getFloat32()
  178. p=dgi.getFloat32()
  179. r=dgi.getFloat32()
  180. self.notify.debug((' new position=%f %f %f %f %f %f' %
  181. (x, y, z, h, p, r)))
  182. return (x, y, z, h, p, r)
  183. def parseNamedMovementDatagram(self, dgi):
  184. name = dgi.getString()
  185. x=dgi.getFloat32()
  186. y=dgi.getFloat32()
  187. z=dgi.getFloat32()
  188. h=dgi.getFloat32()
  189. p=dgi.getFloat32()
  190. r=dgi.getFloat32()
  191. sx = dgi.getFloat32()
  192. sy = dgi.getFloat32()
  193. sz = dgi.getFloat32()
  194. red = dgi.getFloat32()
  195. g = dgi.getFloat32()
  196. b = dgi.getFloat32()
  197. a = dgi.getFloat32()
  198. hidden = dgi.getBool()
  199. return (name,x, y, z, h, p, r, sx, sy, sz, red, g, b, a, hidden)
  200. def makeSelectedMovementDatagram(self, xyz, hpr, scale):
  201. datagram = PyDatagram()
  202. datagram.addUint32(self.packetNumber)
  203. self.packetNumber = self.packetNumber + 1
  204. datagram.addUint8(CLUSTER_SELECTED_MOVEMENT)
  205. datagram.addFloat32(xyz[0])
  206. datagram.addFloat32(xyz[1])
  207. datagram.addFloat32(xyz[2])
  208. datagram.addFloat32(hpr[0])
  209. datagram.addFloat32(hpr[1])
  210. datagram.addFloat32(hpr[2])
  211. datagram.addFloat32(scale[0])
  212. datagram.addFloat32(scale[1])
  213. datagram.addFloat32(scale[2])
  214. #datagram.addBool(hidden)
  215. return datagram
  216. def parseSelectedMovementDatagram(self, dgi):
  217. x=dgi.getFloat32()
  218. y=dgi.getFloat32()
  219. z=dgi.getFloat32()
  220. h=dgi.getFloat32()
  221. p=dgi.getFloat32()
  222. r=dgi.getFloat32()
  223. sx=dgi.getFloat32()
  224. sy=dgi.getFloat32()
  225. sz=dgi.getFloat32()
  226. self.notify.debug(' new position=%f %f %f %f %f %f %f %f %f' %
  227. (x, y, z, h, p, r, sx, sy, sz))
  228. return (x, y, z, h, p, r, sx, sy, sz)
  229. def makeCommandStringDatagram(self, commandString):
  230. datagram = PyDatagram()
  231. datagram.addUint32(self.packetNumber)
  232. self.packetNumber = self.packetNumber + 1
  233. datagram.addUint8(CLUSTER_COMMAND_STRING)
  234. datagram.addString(commandString)
  235. return datagram
  236. def parseCommandStringDatagram(self, dgi):
  237. command = dgi.getString()
  238. return command
  239. def makeSwapNowDatagram(self):
  240. datagram = PyDatagram()
  241. datagram.addUint32(self.packetNumber)
  242. self.packetNumber = self.packetNumber + 1
  243. datagram.addUint8(CLUSTER_SWAP_NOW)
  244. return datagram
  245. def makeSwapReadyDatagram(self):
  246. datagram = PyDatagram()
  247. datagram.addUint32(self.packetNumber)
  248. self.packetNumber = self.packetNumber + 1
  249. datagram.addUint8(CLUSTER_SWAP_READY)
  250. return datagram
  251. def makeExitDatagram(self):
  252. datagram = PyDatagram()
  253. datagram.addUint32(self.packetNumber)
  254. self.packetNumber = self.packetNumber + 1
  255. datagram.addUint8(CLUSTER_EXIT)
  256. return datagram
  257. def makeTimeDataDatagram(self, frameCount, frameTime, dt):
  258. datagram = PyDatagram()
  259. datagram.addUint32(self.packetNumber)
  260. self.packetNumber = self.packetNumber + 1
  261. datagram.addUint8(CLUSTER_TIME_DATA)
  262. datagram.addUint32(frameCount)
  263. datagram.addFloat32(frameTime)
  264. datagram.addFloat32(dt)
  265. return datagram
  266. def parseTimeDataDatagram(self, dgi):
  267. frameCount=dgi.getUint32()
  268. frameTime=dgi.getFloat32()
  269. dt=dgi.getFloat32()
  270. self.notify.debug('time data=%f %f' % (frameTime, dt))
  271. return (frameCount, frameTime, dt)