DistributedCartesianGridAI.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. from panda3d.core import *
  2. from panda3d.direct import *
  3. from direct.directnotify.DirectNotifyGlobal import directNotify
  4. from direct.task import Task
  5. from .DistributedNodeAI import DistributedNodeAI
  6. from .CartesianGridBase import CartesianGridBase
  7. class DistributedCartesianGridAI(DistributedNodeAI, CartesianGridBase):
  8. notify = directNotify.newCategory("DistributedCartesianGridAI")
  9. RuleSeparator = ":"
  10. def __init__(self, air, startingZone, gridSize, gridRadius, cellWidth,
  11. style="Cartesian"):
  12. DistributedNodeAI.__init__(self, air)
  13. self.style = style
  14. self.startingZone = startingZone
  15. self.gridSize = gridSize
  16. self.gridRadius = gridRadius
  17. self.cellWidth = cellWidth
  18. # Keep track of all AI objects added to the grid
  19. self.gridObjects = {}
  20. self.updateTaskStarted = 0
  21. def delete(self):
  22. DistributedNodeAI.delete(self)
  23. self.stopUpdateGridTask()
  24. def isGridParent(self):
  25. # If this distributed object is a DistributedGrid return 1.
  26. # 0 by default
  27. return 1
  28. def getCellWidth(self):
  29. return self.cellWidth
  30. def getParentingRules(self):
  31. self.notify.debug("calling getter")
  32. rule = ("%i%s%i%s%i" % (self.startingZone, self.RuleSeparator,
  33. self.gridSize, self.RuleSeparator,
  34. self.gridRadius))
  35. return [self.style, rule]
  36. # Reparent and setLocation on av to DistributedOceanGrid
  37. def addObjectToGrid(self, av, useZoneId=-1, startAutoUpdate=True):
  38. self.notify.debug("setting parent to grid %s" % self)
  39. avId = av.doId
  40. # Create a grid parent
  41. #gridParent = self.attachNewNode("gridParent-%s" % avId)
  42. #self.gridParents[avId] = gridParent
  43. self.gridObjects[avId] = av
  44. # Put the avatar on the grid
  45. self.handleAvatarZoneChange(av, useZoneId)
  46. if (not self.updateTaskStarted) and startAutoUpdate:
  47. self.startUpdateGridTask()
  48. def removeObjectFromGrid(self, av):
  49. # TODO: WHAT LOCATION SHOULD WE SET THIS TO?
  50. #av.wrtReparentTo(self.parentNP)
  51. #av.setLocation(self.air.districtId, 1000)
  52. # Remove grid parent for this av
  53. avId = av.doId
  54. if avId in self.gridObjects:
  55. del self.gridObjects[avId]
  56. # Stop task if there are no more av's being managed
  57. if len(self.gridObjects) == 0:
  58. self.stopUpdateGridTask()
  59. #####################################################################
  60. # updateGridTask
  61. # This task is similar to the processVisibility task for the local client.
  62. # A couple differences:
  63. # - we are not doing setInterest on the AI (that is a local client
  64. # specific call).
  65. # - we assume that the moving objects on the grid are parented to a
  66. # gridParent, and are broadcasting their position relative to that
  67. # gridParent. This makes the task's math easy. Just check to see
  68. # when our position goes out of the current grid cell. When it does,
  69. # call handleAvatarZoneChange
  70. def startUpdateGridTask(self):
  71. self.stopUpdateGridTask()
  72. self.updateTaskStarted = 1
  73. taskMgr.add(self.updateGridTask, self.taskName("updateGridTask"))
  74. def stopUpdateGridTask(self):
  75. taskMgr.remove(self.taskName("updateGridTask"))
  76. self.updateTaskStarted = 0
  77. def updateGridTask(self, task=None):
  78. # Run through all grid objects and update their parents if needed
  79. missingObjs = []
  80. for avId in list(self.gridObjects.keys()):
  81. av = self.gridObjects[avId]
  82. # handle a missing object after it is already gone?
  83. if (av.isEmpty()):
  84. task.setDelay(1.0)
  85. del self.gridObjects[avId]
  86. continue
  87. pos = av.getPos()
  88. if ((pos[0] < 0 or pos[1] < 0) or
  89. (pos[0] > self.cellWidth or pos[1] > self.cellWidth)):
  90. # we are out of the bounds of this current cell
  91. self.handleAvatarZoneChange(av)
  92. # Do this every second, not every frame
  93. if (task):
  94. task.setDelay(1.0)
  95. return Task.again
  96. def handleAvatarZoneChange(self, av, useZoneId=-1):
  97. # Calculate zone id
  98. # Get position of av relative to this grid
  99. if (useZoneId == -1):
  100. pos = av.getPos(self)
  101. zoneId = self.getZoneFromXYZ(pos)
  102. else:
  103. # zone already calculated, position of object might not
  104. # give the correct zone
  105. pos = None
  106. zoneId = useZoneId
  107. if not self.isValidZone(zoneId):
  108. self.notify.warning(
  109. "%s handleAvatarZoneChange %s: not a valid zone (%s) for pos %s" %(self.doId, av.doId, zoneId, pos))
  110. return
  111. # Set the location on the server.
  112. # setLocation will update the gridParent
  113. av.b_setLocation(self.doId, zoneId)
  114. def handleSetLocation(self, av, parentId, zoneId):
  115. pass
  116. #if (av.parentId != parentId):
  117. # parent changed, need to look up instance tree
  118. # to see if avatar's named area location information
  119. # changed
  120. #av.requestRegionUpdateTask(regionegionUid)