from panda3d.core import *
from panda3d.direct import *
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.task import Task
from direct.task.TaskManagerGlobal import taskMgr
from .DistributedNodeAI import DistributedNodeAI
from .CartesianGridBase import CartesianGridBase
[docs]class DistributedCartesianGridAI(DistributedNodeAI, CartesianGridBase):
notify = directNotify.newCategory("DistributedCartesianGridAI")
RuleSeparator = ":"
[docs] def __init__(self, air, startingZone, gridSize, gridRadius, cellWidth,
style="Cartesian"):
DistributedNodeAI.__init__(self, air)
self.style = style
self.startingZone = startingZone
self.gridSize = gridSize
self.gridRadius = gridRadius
self.cellWidth = cellWidth
# Keep track of all AI objects added to the grid
self.gridObjects = {}
self.updateTaskStarted = 0
[docs] def delete(self):
DistributedNodeAI.delete(self)
self.stopUpdateGridTask()
[docs] def isGridParent(self):
# If this distributed object is a DistributedGrid return 1.
# 0 by default
return 1
[docs] def getCellWidth(self):
return self.cellWidth
[docs] def getParentingRules(self):
self.notify.debug("calling getter")
rule = ("%i%s%i%s%i" % (self.startingZone, self.RuleSeparator,
self.gridSize, self.RuleSeparator,
self.gridRadius))
return [self.style, rule]
# Reparent and setLocation on av to DistributedOceanGrid
[docs] def addObjectToGrid(self, av, useZoneId=-1, startAutoUpdate=True):
self.notify.debug("setting parent to grid %s" % self)
avId = av.doId
# Create a grid parent
#gridParent = self.attachNewNode("gridParent-%s" % avId)
#self.gridParents[avId] = gridParent
self.gridObjects[avId] = av
# Put the avatar on the grid
self.handleAvatarZoneChange(av, useZoneId)
if startAutoUpdate and not self.updateTaskStarted:
self.startUpdateGridTask()
[docs] def removeObjectFromGrid(self, av):
# TODO: WHAT LOCATION SHOULD WE SET THIS TO?
#av.wrtReparentTo(self.parentNP)
#av.setLocation(self.air.districtId, 1000)
# Remove grid parent for this av
avId = av.doId
if avId in self.gridObjects:
del self.gridObjects[avId]
# Stop task if there are no more av's being managed
if len(self.gridObjects) == 0:
self.stopUpdateGridTask()
#####################################################################
# updateGridTask
# This task is similar to the processVisibility task for the local client.
# A couple differences:
# - we are not doing setInterest on the AI (that is a local client
# specific call).
# - we assume that the moving objects on the grid are parented to a
# gridParent, and are broadcasting their position relative to that
# gridParent. This makes the task's math easy. Just check to see
# when our position goes out of the current grid cell. When it does,
# call handleAvatarZoneChange
[docs] def startUpdateGridTask(self):
self.stopUpdateGridTask()
self.updateTaskStarted = 1
taskMgr.add(self.updateGridTask, self.taskName("updateGridTask"))
[docs] def stopUpdateGridTask(self):
taskMgr.remove(self.taskName("updateGridTask"))
self.updateTaskStarted = 0
[docs] def updateGridTask(self, task=None):
# Run through all grid objects and update their parents if needed
missingObjs = []
for avId in list(self.gridObjects.keys()):
av = self.gridObjects[avId]
# handle a missing object after it is already gone?
if av.isEmpty():
task.setDelay(1.0)
del self.gridObjects[avId]
continue
pos = av.getPos()
if (pos[0] < 0 or pos[1] < 0) or \
(pos[0] > self.cellWidth or pos[1] > self.cellWidth):
# we are out of the bounds of this current cell
self.handleAvatarZoneChange(av)
# Do this every second, not every frame
if task:
task.setDelay(1.0)
return Task.again
[docs] def handleAvatarZoneChange(self, av, useZoneId=-1):
# Calculate zone id
# Get position of av relative to this grid
if useZoneId == -1:
pos = av.getPos(self)
zoneId = self.getZoneFromXYZ(pos)
else:
# zone already calculated, position of object might not
# give the correct zone
pos = None
zoneId = useZoneId
if not self.isValidZone(zoneId):
self.notify.warning(
"%s handleAvatarZoneChange %s: not a valid zone (%s) for pos %s" %(self.doId, av.doId, zoneId, pos))
return
# Set the location on the server.
# setLocation will update the gridParent
av.b_setLocation(self.doId, zoneId)
[docs] def handleSetLocation(self, av, parentId, zoneId):
pass
#if av.parentId != parentId:
# parent changed, need to look up instance tree
# to see if avatar's named area location information
# changed
#av.requestRegionUpdateTask(regionegionUid)