DistributedCartesianGrid.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. from pandac.PandaModules import *
  2. from direct.distributed import DistributedNode
  3. from direct.task import Task
  4. from direct.interval.IntervalGlobal import *
  5. from direct.gui import DirectGuiGlobals
  6. if __debug__:
  7. # For grid drawing
  8. from direct.directtools.DirectGeometry import *
  9. from direct.showbase.PythonUtil import randFloat
  10. import CartesianGridBase
  11. class DistributedCartesianGrid(DistributedNode.DistributedNode,
  12. CartesianGridBase.CartesianGridBase):
  13. notify = directNotify.newCategory("DistributedCartesianGrid")
  14. VisualizeGrid = config.GetBool("visualize-cartesian-grid", 0)
  15. RuleSeparator = ":"
  16. def __init__(self, cr):
  17. DistributedNode.DistributedNode.__init__(self, cr)
  18. # Let the derived classes instantiate the NodePath
  19. self.visAvatar = None
  20. self.visContext = None
  21. # Do we have grid lines visualized?
  22. if __debug__:
  23. self.haveGridLines = 0
  24. def generate(self):
  25. DistributedNode.DistributedNode.generate(self)
  26. def disable(self):
  27. DistributedNode.DistributedNode.disable(self)
  28. self.stopProcessVisibility()
  29. def delete(self):
  30. DistributedNode.DistributedNode.delete(self)
  31. def isGridParent(self):
  32. # If this distributed object is a DistributedGrid return 1. 0 by default
  33. return 1
  34. def setParentingRules(self, style, rule):
  35. assert self.notify.debug("setParentingRules: style: %s, rule: %s" % (style, rule))
  36. rules = rule.split(self.RuleSeparator)
  37. assert(len(rules) == 3)
  38. self.style = style
  39. self.startingZone = int(rules[0])
  40. self.gridSize = int(rules[1])
  41. self.viewingRadius = int(rules[2])
  42. # Store the center of the grid
  43. cx = self.cellWidth * self.gridSize/2.0
  44. self.centerPos = Vec3(cx, cx, 0)
  45. if __debug__:
  46. if self.VisualizeGrid:
  47. self.visualizeGrid()
  48. def getCenterPos(self):
  49. return self.centerPos
  50. def startProcessVisibility(self, avatar):
  51. self.stopProcessVisibility()
  52. self.visAvatar = avatar
  53. self.visZone = None
  54. self.visContext = self.cr.addInterest(self.getDoId(), 0, self.uniqueName("visibility"))
  55. taskMgr.add(self.processVisibility, self.taskName("processVisibility"))
  56. def stopProcessVisibility(self):
  57. taskMgr.remove(self.taskName("processVisibility"))
  58. if self.visContext is not None:
  59. self.cr.removeInterest(self.visContext)
  60. self.visContext = None
  61. self.visAvatar = None
  62. self.visZone = None
  63. def processVisibility(self, task):
  64. pos = self.visAvatar.getPos(self)
  65. # Check to make sure our x and y are positive
  66. dx = self.cellWidth * self.gridSize * .5
  67. x = pos[0] + dx
  68. y = pos[1] + dx
  69. col = x // self.cellWidth
  70. row = y // self.cellWidth
  71. assert self.notify.debug("processVisibility: %s: avatar pos: %s %s" % (self.doId, x,y))
  72. if (row < 0) or (col < 0) or (row > self.gridSize) or (col > self.gridSize):
  73. assert self.notify.debug("processVisibility: %s: not on the grid" % (self.doId))
  74. # If we are viewingRadius away from this entire grid,
  75. # remove interest in any current visZone we may have
  76. if self.visContext:
  77. self.cr.removeInterest(self.visContext)
  78. self.visZone = None
  79. self.visContext = None
  80. return Task.cont
  81. # Compute which zone we are in
  82. zoneId = int(self.startingZone + ((row * self.gridSize) + col))
  83. assert self.notify.debug("processVisibility: %s: row: %s col: %s zoneId: %s" %
  84. (self.doId, row, col, zoneId))
  85. if (zoneId == self.visZone):
  86. assert self.notify.debug("processVisibility: %s: interest did not change" % (self.doId))
  87. return Task.cont
  88. else:
  89. assert self.notify.debug("processVisibility: %s: new interest" % (self.doId))
  90. self.visZone = zoneId
  91. if not self.visContext:
  92. self.visContext = self.cr.addInterest(self.getDoId(), self.visZone,
  93. self.uniqueName("visibility"))
  94. else:
  95. assert self.notify.debug("processVisibility: %s: altering interest to zoneId: %s" %
  96. (self.doId, zoneId))
  97. self.cr.alterInterest(self.visContext, self.getDoId(), self.visZone)
  98. # If the visAvatar is parented to this grid, also do a setLocation
  99. parentId, oldZoneId = self.visAvatar.getLocation()
  100. assert self.notify.debug("processVisibility: %s: parentId: %s oldZoneId: %s" %
  101. (self.doId, parentId, oldZoneId))
  102. if parentId == self.doId:
  103. assert self.notify.debug("processVisibility: %s: changing location" % (self.doId))
  104. self.handleAvatarZoneChange(self.visAvatar, zoneId)
  105. return Task.cont
  106. # Take an avatar (or other object) from somewhere in the world and
  107. # wrtReparent him to the grid.
  108. def addObjectToGrid(self, av):
  109. # Get our pos relative to the island grid
  110. pos = av.getPos(self)
  111. # Figure out what zone in that island grid
  112. zoneId = self.getZoneFromXYZ(pos)
  113. # Do the wrtReparenting to the grid node
  114. self.handleAvatarZoneChange(av, zoneId)
  115. def removeObjectFromGrid(self, av):
  116. # TODO: WHAT LOCATION SHOULD WE SET THIS TO?
  117. av.reparentTo(hidden)
  118. av.b_setLocation(0,0)
  119. def handleAvatarZoneChange(self, av, zoneId):
  120. assert self.notify.debug("handleAvatarZoneChange(%s, %s)" % (av.doId, zoneId))
  121. # This method can be overridden by derived classes that
  122. # want to do some special management when the avatar changes
  123. # zones.
  124. # Make sure this is a valid zone
  125. if not self.isValidZone(zoneId):
  126. self.notify.warning("handleAvatarZoneChange: not a valid zone (%s)" % zoneId)
  127. return
  128. # Set the location on the server
  129. av.b_setLocation(self.doId, zoneId)
  130. return
  131. ##################################################
  132. # Visualization Tools
  133. ##################################################
  134. if __debug__:
  135. def initializeGridLines(self):
  136. # Grid Lines
  137. self.gridColor = VBase4(0.4 + randFloat(0.4),
  138. 0.4 + randFloat(0.4),
  139. 0.4 + randFloat(0.4),
  140. 1)
  141. # A Dark version of the grid color
  142. color = self.gridColor * 0.5
  143. color.setW(1)
  144. self.lines = self.attachNewNode('gridLines')
  145. self.minorLines = LineNodePath(self.lines)
  146. self.minorLines.lineNode.setName('minorLines')
  147. self.minorLines.setColor(color)
  148. self.minorLines.setThickness(1)
  149. self.majorLines = LineNodePath(self.lines)
  150. self.majorLines.lineNode.setName('majorLines')
  151. self.majorLines.setColor(color)
  152. self.majorLines.setThickness(5)
  153. self.centerLines = LineNodePath(self.lines)
  154. self.centerLines.lineNode.setName('centerLines')
  155. self.centerLines.setColor(VBase4(1,0,0,0))
  156. self.centerLines.setThickness(3)
  157. # Load up grid parts to initialize grid object
  158. # Polygon used to mark grid plane
  159. # self.gridBack = loader.loadModel('models/misc/gridBack')
  160. # self.gridBack.reparentTo(self)
  161. # self.gridBack.setColor(0.2,0.2,0.2,0.5)
  162. self.cellLabelParent = None
  163. self.markerParent = None
  164. self.haveGridLines = 1
  165. def updateGrid(self):
  166. # Update grid lines based upon current grid spacing and grid size
  167. # First reset existing grid lines
  168. self.minorLines.reset()
  169. self.majorLines.reset()
  170. self.centerLines.reset()
  171. # Now redraw lines
  172. numLines = self.gridSize
  173. scaledSize = numLines * self.cellWidth / 2.0
  174. center = self.centerLines
  175. minor = self.minorLines
  176. major = self.majorLines
  177. cw = self.cellWidth
  178. dx = cw * self.gridSize * .5
  179. for i in range(numLines+1):
  180. icw = i * cw - dx
  181. if i == numLines/2:
  182. center.moveTo(icw, -scaledSize, 0)
  183. center.drawTo(icw, scaledSize, 0)
  184. center.moveTo(-scaledSize, icw, 0)
  185. center.drawTo(scaledSize, icw, 0)
  186. else:
  187. if (i % 5) == 0:
  188. major.moveTo(icw, -scaledSize, 0)
  189. major.drawTo(icw, scaledSize, 0)
  190. major.moveTo(-scaledSize, icw, 0)
  191. major.drawTo(scaledSize, icw, 0)
  192. else:
  193. minor.moveTo(icw, -scaledSize, 0)
  194. minor.drawTo(icw, scaledSize, 0)
  195. minor.moveTo(-scaledSize, icw, 0)
  196. minor.drawTo(scaledSize, icw, 0)
  197. center.create()
  198. minor.create()
  199. major.create()
  200. # self.gridBack.setScale(scaledSize)
  201. self.labelCells()
  202. def labelCells(self):
  203. if self.cellLabelParent:
  204. self.cellLabelParent.removeNode()
  205. self.cellLabelParent = self.attachNewNode('cellLabels')
  206. cw = self.cellWidth
  207. scale = cw / 10.0
  208. dx = cw * self.gridSize * .5
  209. font = DirectGuiGlobals.getDefaultFont()
  210. color = self.gridColor
  211. for i in range(self.gridSize):
  212. for j in range(self.gridSize):
  213. zoneId = self.startingZone + ((j * self.gridSize) + i)
  214. zoneStr = str(zoneId)
  215. textNode = TextNode(zoneStr)
  216. textNode.setText(zoneStr)
  217. textNode.setFont(font)
  218. textNode.setTextColor(color)
  219. textNode.setAlign(TextNode.ACenter)
  220. genTextNode = textNode.generate()
  221. textNodePath = self.cellLabelParent.attachNewNode(genTextNode)
  222. # Place the text node in the center of the cell
  223. textNodePath.setPosHprScale((i * cw - dx) + (cw * 0.5), # x
  224. (j * cw - dx) + (cw * 0.5), # y
  225. 3.0, # z
  226. # Lay them down flat
  227. 0,-90,0, # hpr
  228. scale, scale, scale)
  229. self.cellLabelParent.flattenLight()
  230. def markCells(self):
  231. if self.markerParent:
  232. self.markerParent.removeNode()
  233. self.markerParent = self.attachNewNode('markers')
  234. self.cellMarkers = []
  235. dx = self.cellWidth * self.gridSize * .5
  236. for i in range(self.gridSize):
  237. for j in range(self.gridSize):
  238. marker = loader.loadModelCopy("models/misc/smiley")
  239. marker.reparentTo(self.markerParent)
  240. marker.setPos(i * self.cellWidth - dx,
  241. j * self.cellWidth - dx,
  242. 1.0)
  243. marker.setScale(5)
  244. self.cellMarkers.append(marker)
  245. def unmarkCells(self):
  246. if self.markerParent:
  247. self.markerParent.removeNode()
  248. self.markerParent = None
  249. def visualizeGrid(self):
  250. if not self.haveGridLines:
  251. self.initializeGridLines()
  252. self.updateGrid()