added support for static grid objects in setLocation of DistributedNode
This commit is contained in:
parent
9c9a444209
commit
877a2aa548
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
# Utility functions that are useful to both AI and client CartesianGrid code
|
||||
|
||||
class CartesianGridBase:
|
||||
def isValidZone(self, zoneId):
|
||||
if ((zoneId < self.startingZone) or
|
||||
(zoneId > self.startingZone + self.gridSize * self.gridSize - 1)):
|
||||
return 0
|
||||
return 1
|
||||
|
||||
def getZoneFromXYZ(self, pos):
|
||||
# NOTE: pos should be relative to our own grid origin
|
||||
# Convert a 3d position to a zone
|
||||
dx = self.cellWidth * self.gridSize * .5
|
||||
x = pos[0] + dx
|
||||
y = pos[1] + dx
|
||||
col = x // self.cellWidth
|
||||
row = y // self.cellWidth
|
||||
# Compute which zone we are in
|
||||
zoneId = int(self.startingZone + ((row * self.gridSize) + col))
|
||||
|
||||
return zoneId
|
||||
|
||||
def getGridSizeFromSphereRadius(self, sphereRadius, cellWidth, gridRadius):
|
||||
# NOTE: This ensures that the grid is at least a "gridRadius" number of cells
|
||||
# larger than the trigger sphere that loads the grid. This gives us some
|
||||
# room to start setting interest to the grid before we expect to see any objects
|
||||
# on it.
|
||||
return 2 * (sphereRadius // cellWidth)
|
||||
|
||||
def getZoneCellOrigin(self, zoneId):
|
||||
dx = self.cellWidth * self.gridSize * .5
|
||||
zone = zoneId - self.startingZone
|
||||
row = zone // self.gridSize
|
||||
col = zone % self.gridSize
|
||||
x = col * self.cellWidth - dx
|
||||
y = row * self.cellWidth - dx
|
||||
|
||||
return (x,y,0)
|
||||
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
|
||||
from pandac.PandaModules import *
|
||||
|
||||
from direct.distributed import DistributedNode
|
||||
from direct.task import Task
|
||||
from direct.interval.IntervalGlobal import *
|
||||
from direct.gui import DirectGuiGlobals
|
||||
|
||||
if __debug__:
|
||||
# For grid drawing
|
||||
from direct.directtools.DirectGeometry import *
|
||||
from direct.showbase.PythonUtil import randFloat
|
||||
|
||||
import CartesianGridBase
|
||||
|
||||
|
||||
class DistributedCartesianGrid(DistributedNode.DistributedNode,
|
||||
CartesianGridBase.CartesianGridBase):
|
||||
|
||||
notify = directNotify.newCategory("DistributedCartesianGrid")
|
||||
|
||||
VisualizeGrid = config.GetBool("visualize-cartesian-grid", 0)
|
||||
|
||||
RuleSeparator = ":"
|
||||
|
||||
def __init__(self, cr):
|
||||
DistributedNode.DistributedNode.__init__(self, cr)
|
||||
# Let the derived classes instantiate the NodePath
|
||||
self.visAvatar = None
|
||||
self.visContext = None
|
||||
# Do we have grid lines visualized?
|
||||
if __debug__:
|
||||
self.haveGridLines = 0
|
||||
|
||||
def generate(self):
|
||||
DistributedNode.DistributedNode.generate(self)
|
||||
|
||||
def disable(self):
|
||||
DistributedNode.DistributedNode.disable(self)
|
||||
self.stopProcessVisibility()
|
||||
|
||||
def delete(self):
|
||||
DistributedNode.DistributedNode.delete(self)
|
||||
|
||||
def isGridParent(self):
|
||||
# If this distributed object is a DistributedGrid return 1. 0 by default
|
||||
return 1
|
||||
|
||||
def setParentingRules(self, style, rule):
|
||||
assert self.notify.debug("setParentingRules: style: %s, rule: %s" % (style, rule))
|
||||
rules = rule.split(self.RuleSeparator)
|
||||
assert(len(rules) == 3)
|
||||
self.startingZone = int(rules[0])
|
||||
self.gridSize = int(rules[1])
|
||||
self.viewingRadius = int(rules[2])
|
||||
|
||||
# Store the center of the grid
|
||||
cx = self.cellWidth * self.gridSize/2.0
|
||||
self.centerPos = Vec3(cx, cx, 0)
|
||||
|
||||
if __debug__:
|
||||
if self.VisualizeGrid:
|
||||
self.visualizeGrid()
|
||||
|
||||
def getCenterPos(self):
|
||||
return self.centerPos
|
||||
|
||||
def startProcessVisibility(self, avatar):
|
||||
self.stopProcessVisibility()
|
||||
self.visAvatar = avatar
|
||||
self.visZone = None
|
||||
self.visContext = self.cr.addInterest(self.getDoId(), 0, self.uniqueName("visibility"))
|
||||
taskMgr.add(self.processVisibility, self.taskName("processVisibility"))
|
||||
|
||||
def stopProcessVisibility(self):
|
||||
taskMgr.remove(self.taskName("processVisibility"))
|
||||
if self.visContext is not None:
|
||||
self.cr.removeInterest(self.visContext)
|
||||
self.visContext = None
|
||||
self.visAvatar = None
|
||||
self.visZone = None
|
||||
|
||||
def processVisibility(self, task):
|
||||
pos = self.visAvatar.getPos(self)
|
||||
# Check to make sure our x and y are positive
|
||||
dx = self.cellWidth * self.gridSize * .5
|
||||
x = pos[0] + dx
|
||||
y = pos[1] + dx
|
||||
col = x // self.cellWidth
|
||||
row = y // self.cellWidth
|
||||
assert self.notify.debug("processVisibility: %s: avatar pos: %s %s" % (self.doId, x,y))
|
||||
if (row < 0) or (col < 0) or (row > self.gridSize) or (col > self.gridSize):
|
||||
assert self.notify.debug("processVisibility: %s: not on the grid" % (self.doId))
|
||||
# If we are viewingRadius away from this entire grid,
|
||||
# remove interest in any current visZone we may have
|
||||
if self.visContext:
|
||||
self.cr.removeInterest(self.visContext)
|
||||
self.visZone = None
|
||||
self.visContext = None
|
||||
return Task.cont
|
||||
# Compute which zone we are in
|
||||
zoneId = int(self.startingZone + ((row * self.gridSize) + col))
|
||||
assert self.notify.debug("processVisibility: %s: row: %s col: %s zoneId: %s" %
|
||||
(self.doId, row, col, zoneId))
|
||||
if (zoneId == self.visZone):
|
||||
assert self.notify.debug("processVisibility: %s: interest did not change" % (self.doId))
|
||||
return Task.cont
|
||||
else:
|
||||
assert self.notify.debug("processVisibility: %s: new interest" % (self.doId))
|
||||
self.visZone = zoneId
|
||||
if not self.visContext:
|
||||
self.visContext = self.cr.addInterest(self.getDoId(), self.visZone,
|
||||
self.uniqueName("visibility"))
|
||||
else:
|
||||
assert self.notify.debug("processVisibility: %s: altering interest to zoneId: %s" %
|
||||
(self.doId, zoneId))
|
||||
self.cr.alterInterest(self.visContext, self.getDoId(), self.visZone)
|
||||
# If the visAvatar is parented to this grid, also do a setLocation
|
||||
parentId, oldZoneId = self.visAvatar.getLocation()
|
||||
assert self.notify.debug("processVisibility: %s: parentId: %s oldZoneId: %s" %
|
||||
(self.doId, parentId, oldZoneId))
|
||||
if parentId == self.doId:
|
||||
assert self.notify.debug("processVisibility: %s: changing location" % (self.doId))
|
||||
self.handleAvatarZoneChange(self.visAvatar, zoneId)
|
||||
return Task.cont
|
||||
|
||||
def handleAvatarZoneChange(self, av, zoneId):
|
||||
assert self.notify.debug("handleAvatarZoneChange(%s, %s)" % (av.doId, zoneId))
|
||||
# This method can be overridden by derived classes that
|
||||
# want to do some special management when the avatar changes
|
||||
# zones.
|
||||
# Make sure this is a valid zone
|
||||
if not self.isValidZone(zoneId):
|
||||
self.notify.warning("handleAvatarZoneChange: not a valid zone (%s)" % zoneId)
|
||||
return
|
||||
|
||||
# Set the location on the server
|
||||
av.b_setLocation(self.doId, zoneId)
|
||||
return
|
||||
|
||||
|
||||
##################################################
|
||||
# Visualization Tools
|
||||
##################################################
|
||||
|
||||
if __debug__:
|
||||
|
||||
def initializeGridLines(self):
|
||||
# Grid Lines
|
||||
self.gridColor = VBase4(0.4 + randFloat(0.4),
|
||||
0.4 + randFloat(0.4),
|
||||
0.4 + randFloat(0.4),
|
||||
1)
|
||||
# A Dark version of the grid color
|
||||
color = self.gridColor * 0.5
|
||||
color.setW(1)
|
||||
|
||||
self.lines = self.attachNewNode('gridLines')
|
||||
self.minorLines = LineNodePath(self.lines)
|
||||
self.minorLines.lineNode.setName('minorLines')
|
||||
self.minorLines.setColor(color)
|
||||
self.minorLines.setThickness(1)
|
||||
|
||||
self.majorLines = LineNodePath(self.lines)
|
||||
self.majorLines.lineNode.setName('majorLines')
|
||||
self.majorLines.setColor(color)
|
||||
self.majorLines.setThickness(5)
|
||||
|
||||
self.centerLines = LineNodePath(self.lines)
|
||||
self.centerLines.lineNode.setName('centerLines')
|
||||
self.centerLines.setColor(VBase4(1,0,0,0))
|
||||
self.centerLines.setThickness(3)
|
||||
|
||||
# Load up grid parts to initialize grid object
|
||||
# Polygon used to mark grid plane
|
||||
# self.gridBack = loader.loadModel('models/misc/gridBack')
|
||||
# self.gridBack.reparentTo(self)
|
||||
# self.gridBack.setColor(0.2,0.2,0.2,0.5)
|
||||
|
||||
self.cellLabelParent = None
|
||||
self.markerParent = None
|
||||
self.haveGridLines = 1
|
||||
|
||||
def updateGrid(self):
|
||||
# Update grid lines based upon current grid spacing and grid size
|
||||
# First reset existing grid lines
|
||||
self.minorLines.reset()
|
||||
self.majorLines.reset()
|
||||
self.centerLines.reset()
|
||||
# Now redraw lines
|
||||
numLines = self.gridSize
|
||||
scaledSize = numLines * self.cellWidth / 2.0
|
||||
center = self.centerLines
|
||||
minor = self.minorLines
|
||||
major = self.majorLines
|
||||
cw = self.cellWidth
|
||||
dx = cw * self.gridSize * .5
|
||||
for i in range(numLines+1):
|
||||
icw = i * cw - dx
|
||||
if i == numLines/2:
|
||||
center.moveTo(icw, -scaledSize, 0)
|
||||
center.drawTo(icw, scaledSize, 0)
|
||||
center.moveTo(-scaledSize, icw, 0)
|
||||
center.drawTo(scaledSize, icw, 0)
|
||||
else:
|
||||
if (i % 5) == 0:
|
||||
major.moveTo(icw, -scaledSize, 0)
|
||||
major.drawTo(icw, scaledSize, 0)
|
||||
major.moveTo(-scaledSize, icw, 0)
|
||||
major.drawTo(scaledSize, icw, 0)
|
||||
else:
|
||||
minor.moveTo(icw, -scaledSize, 0)
|
||||
minor.drawTo(icw, scaledSize, 0)
|
||||
minor.moveTo(-scaledSize, icw, 0)
|
||||
minor.drawTo(scaledSize, icw, 0)
|
||||
center.create()
|
||||
minor.create()
|
||||
major.create()
|
||||
# self.gridBack.setScale(scaledSize)
|
||||
self.labelCells()
|
||||
|
||||
def labelCells(self):
|
||||
if self.cellLabelParent:
|
||||
self.cellLabelParent.removeNode()
|
||||
self.cellLabelParent = self.attachNewNode('cellLabels')
|
||||
cw = self.cellWidth
|
||||
scale = cw / 10.0
|
||||
dx = cw * self.gridSize * .5
|
||||
font = DirectGuiGlobals.getDefaultFont()
|
||||
color = self.gridColor
|
||||
for i in range(self.gridSize):
|
||||
for j in range(self.gridSize):
|
||||
zoneId = self.startingZone + ((j * self.gridSize) + i)
|
||||
zoneStr = str(zoneId)
|
||||
textNode = TextNode(zoneStr)
|
||||
textNode.setText(zoneStr)
|
||||
textNode.setFont(font)
|
||||
textNode.setTextColor(color)
|
||||
textNode.setAlign(TextNode.ACenter)
|
||||
genTextNode = textNode.generate()
|
||||
textNodePath = self.cellLabelParent.attachNewNode(genTextNode)
|
||||
# Place the text node in the center of the cell
|
||||
textNodePath.setPosHprScale((i * cw - dx) + (cw * 0.5), # x
|
||||
(j * cw - dx) + (cw * 0.5), # y
|
||||
3.0, # z
|
||||
# Lay them down flat
|
||||
0,-90,0, # hpr
|
||||
scale, scale, scale)
|
||||
self.cellLabelParent.flattenLight()
|
||||
|
||||
def markCells(self):
|
||||
if self.markerParent:
|
||||
self.markerParent.removeNode()
|
||||
self.markerParent = self.attachNewNode('markers')
|
||||
self.cellMarkers = []
|
||||
dx = self.cellWidth * self.gridSize * .5
|
||||
for i in range(self.gridSize):
|
||||
for j in range(self.gridSize):
|
||||
marker = loader.loadModelCopy("models/misc/smiley")
|
||||
marker.reparentTo(self.markerParent)
|
||||
marker.setPos(i * self.cellWidth - dx,
|
||||
j * self.cellWidth - dx,
|
||||
1.0)
|
||||
marker.setScale(5)
|
||||
self.cellMarkers.append(marker)
|
||||
|
||||
def unmarkCells(self):
|
||||
if self.markerParent:
|
||||
self.markerParent.removeNode()
|
||||
self.markerParent = None
|
||||
|
||||
def visualizeGrid(self):
|
||||
if not self.haveGridLines:
|
||||
self.initializeGridLines()
|
||||
self.updateGrid()
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
|
||||
from pandac.PandaModules import *
|
||||
|
||||
from direct.task import Task
|
||||
import DistributedNodeAI
|
||||
import CartesianGridBase
|
||||
|
||||
class DistributedCartesianGridAI(DistributedNodeAI.DistributedNodeAI,
|
||||
CartesianGridBase.CartesianGridBase):
|
||||
|
||||
notify = directNotify.newCategory("DistributedCartesianGridAI")
|
||||
|
||||
RuleSeparator = ":"
|
||||
|
||||
def __init__(self, air, startingZone, gridSize, gridRadius):
|
||||
DistributedNodeAI.DistributedNodeAI.__init__(self, air)
|
||||
self.style = "Cartesian"
|
||||
self.startingZone = startingZone
|
||||
self.gridSize = gridSize
|
||||
self.gridRadius = gridRadius
|
||||
|
||||
# Keep track of all AI objects added to the grid
|
||||
self.gridObjects = {}
|
||||
self.updateTaskStarted = 0
|
||||
|
||||
def delete(self):
|
||||
DistributedNodeAI.DistributedNodeAI.delete(self)
|
||||
self.stopUpdateGridTask()
|
||||
|
||||
def isGridParent(self):
|
||||
# If this distributed object is a DistributedGrid return 1. 0 by default
|
||||
return 1
|
||||
|
||||
def getParentingRules(self):
|
||||
print "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
|
||||
def addObjectToGrid(self, av):
|
||||
print "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)
|
||||
|
||||
if not self.updateTaskStarted:
|
||||
self.startUpdateGridTask()
|
||||
|
||||
def removeObjectFromGrid(self, av):
|
||||
# TODO: WHAT LOCATION SHOULD WE SET THIS TO?
|
||||
#av.wrtReparentTo(self.parentNP)
|
||||
av.setLocation(simbase.air.districtId, PiratesGlobals.TestZone)
|
||||
|
||||
# Remove grid parent for this av
|
||||
avId = av.doId
|
||||
if self.gridObjects.has_key(avId):
|
||||
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
|
||||
|
||||
def startUpdateGridTask(self):
|
||||
self.stopUpdateGridTask()
|
||||
self.updateTaskStarted = 1
|
||||
taskMgr.add(self.updateGridTask, self.taskName("updateGridTask"))
|
||||
|
||||
def stopUpdateGridTask(self):
|
||||
taskMgr.remove(self.taskName("updateGridTask"))
|
||||
self.updateTaskStarted = 0
|
||||
|
||||
def updateGridTask(self, task):
|
||||
# Run through all grid objects and update their parents if needed
|
||||
for avId in self.gridObjects:
|
||||
av = self.gridObjects[avId]
|
||||
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
|
||||
task.delayTime = 1.0
|
||||
return Task.again
|
||||
|
||||
def handleAvatarZoneChange(self, av):
|
||||
# Calculate zone id
|
||||
# Get position of av relative to this grid
|
||||
pos = av.getPos(self)
|
||||
zoneId = self.getZoneFromXYZ(pos)
|
||||
|
||||
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)
|
||||
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
"""DistributedNode module: contains the DistributedNode class"""
|
||||
|
||||
from direct.showbase.ShowBaseGlobal import *
|
||||
from pandac.PandaModules import NodePath
|
||||
import DistributedObject
|
||||
from direct.showbase.ShowBaseGlobal import *
|
||||
from direct.task import Task
|
||||
import GridParent
|
||||
import DistributedObject
|
||||
import types
|
||||
|
||||
class DistributedNode(DistributedObject.DistributedObject, NodePath):
|
||||
|
|
@ -17,6 +18,9 @@ class DistributedNode(DistributedObject.DistributedObject, NodePath):
|
|||
self.gotStringParentToken = 0
|
||||
DistributedObject.DistributedObject.__init__(self, cr)
|
||||
|
||||
# initialize gridParent
|
||||
self.gridParent = None
|
||||
|
||||
def disable(self):
|
||||
if self.activeState != DistributedObject.ESDisabled:
|
||||
self.reparentTo(hidden)
|
||||
|
|
@ -29,12 +33,34 @@ class DistributedNode(DistributedObject.DistributedObject, NodePath):
|
|||
self.DistributedNode_deleted = 1
|
||||
if not self.isEmpty():
|
||||
self.removeNode()
|
||||
if self.gridParent:
|
||||
self.gridParent.delete()
|
||||
DistributedObject.DistributedObject.delete(self)
|
||||
|
||||
def generate(self):
|
||||
DistributedObject.DistributedObject.generate(self)
|
||||
self.gotStringParentToken = 0
|
||||
|
||||
def setLocation(self, parentId, zoneId):
|
||||
# Redefine DistributedObject setLocation, so that when
|
||||
# location is set to the ocean grid, we can update our parenting
|
||||
# under gridParent
|
||||
DistributedObject.DistributedObject.setLocation(self, parentId, zoneId)
|
||||
parentObj = self.cr.doId2do.get(parentId)
|
||||
if parentObj:
|
||||
if parentObj.isGridParent():
|
||||
if not self.gridParent:
|
||||
self.gridParent = GridParent.GridParent(self)
|
||||
self.gridParent.setGridParent(parentObj, zoneId)
|
||||
else:
|
||||
if self.gridParent:
|
||||
self.gridParent.delete()
|
||||
self.gridParent = None
|
||||
# NOTE: at this point the avatar has been detached from the scene
|
||||
# graph. Someone else needs to reparent him to something in the scene graph
|
||||
# TODO: handle DistributedNode parenting
|
||||
|
||||
|
||||
def __cmp__(self, other):
|
||||
# DistributedNode inherits from NodePath, which inherits a
|
||||
# definition of __cmp__ from FFIExternalObject that uses the
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from otp.ai.AIBaseGlobal import *
|
||||
from pandac.PandaModules import NodePath
|
||||
from direct.distributed import DistributedObjectAI
|
||||
import DistributedObjectAI
|
||||
import GridParent
|
||||
|
||||
class DistributedNodeAI(DistributedObjectAI.DistributedObjectAI, NodePath):
|
||||
def __init__(self, air, name=None):
|
||||
|
|
@ -13,12 +14,35 @@ class DistributedNodeAI(DistributedObjectAI.DistributedObjectAI, NodePath):
|
|||
if name is None:
|
||||
name = self.__class__.__name__
|
||||
NodePath.__init__(self, name)
|
||||
self.gridParent = None
|
||||
|
||||
def delete(self):
|
||||
if not self.isEmpty():
|
||||
self.removeNode()
|
||||
if self.gridParent:
|
||||
self.gridParent.delete()
|
||||
DistributedObjectAI.DistributedObjectAI.delete(self)
|
||||
|
||||
def setLocation(self, parentId, zoneId):
|
||||
# Redefine DistributedObject setLocation, so that when
|
||||
# location is set to the ocean grid, we can update our parenting
|
||||
# under gridParent
|
||||
DistributedObjectAI.DistributedObjectAI.setLocation(self, parentId, zoneId)
|
||||
parentObj = self.air.doId2do.get(parentId)
|
||||
if parentObj:
|
||||
if parentObj.isGridParent():
|
||||
if not self.gridParent:
|
||||
self.gridParent = GridParent.GridParent(self)
|
||||
self.gridParent.setGridParent(parentObj, zoneId)
|
||||
else:
|
||||
if self.gridParent:
|
||||
self.gridParent.delete()
|
||||
self.gridParent = None
|
||||
# NOTE: at this point the avatar has been detached from the scene
|
||||
# graph. Someone else needs to reparent him to something in the scene graph
|
||||
# TODO: handle DistributedNode parenting
|
||||
|
||||
|
||||
### setParent ###
|
||||
|
||||
def b_setParent(self, parentToken):
|
||||
|
|
|
|||
|
|
@ -367,3 +367,7 @@ class DistributedObject(PandaObject):
|
|||
def updateZone(self, zoneId):
|
||||
self.cr.sendUpdateZone(self, zoneId)
|
||||
|
||||
def isGridParent(self):
|
||||
# If this distributed object is a DistributedGrid return 1. 0 by default
|
||||
return 0
|
||||
|
||||
|
|
|
|||
|
|
@ -316,7 +316,6 @@ class DistributedObjectAI(DirectObject.DirectObject):
|
|||
assert doId is None or doId == self.__preallocDoId
|
||||
doId=self.__preallocDoId
|
||||
self.__preallocDoId = 0
|
||||
|
||||
self.air.sendGenerateOtpObject(
|
||||
self, parentId, zoneId, optionalFields, doId=doId)
|
||||
assert not hasattr(self, 'parentId')
|
||||
|
|
@ -475,4 +474,7 @@ class DistributedObjectAI(DirectObject.DirectObject):
|
|||
else:
|
||||
self.notify.warning("Unexpected completion from barrier %s" % (context))
|
||||
|
||||
def isGridParent(self):
|
||||
# If this distributed object is a DistributedGrid return 1. 0 by default
|
||||
return 0
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
from pandac.PandaModules import *
|
||||
|
||||
#
|
||||
# GridParent.py
|
||||
# Any object that can be parented to the ocean grid
|
||||
# (or any grid whose size is too large to represent in 16 bits),
|
||||
# should derive from GridParent. Can be used on client and AI code.
|
||||
|
||||
# GridParent will put a node inbetween the object and the grid so
|
||||
# that the object is broadcasting its position relative to the gridCell
|
||||
# it lies in.
|
||||
|
||||
class GridParent:
|
||||
|
||||
def __init__(self, av):
|
||||
# The object on the grid will need to broadcast his position relative to
|
||||
# his current grid cell in order to use 16 bit
|
||||
# telemetry. To do this, we will have a node attached to the
|
||||
# grid cell origin, and the object will wrtReparent himself to it when
|
||||
# crossing into that grid cell. We don't need to create a node for each
|
||||
# cell origin. We just need two nodes: one that we are currently parented
|
||||
# to, and the other that we will wrtReparentTo. Just before wrtReparenting
|
||||
# to the new node, set it's position to the new grid cell origin.
|
||||
self.av = av
|
||||
self.grid = None
|
||||
self.cellOrigin = NodePath("cellOrigin")
|
||||
|
||||
def delete(self):
|
||||
if self.av.getParent() == self.cellOrigin:
|
||||
self.av.detachNode()
|
||||
del self.av
|
||||
# Remove the gridNodes
|
||||
self.cellOrigin.removeNode()
|
||||
|
||||
def setGridParent(self, grid, zoneId):
|
||||
# If the avatar has a parent, preserve his absolute position. Otherwise
|
||||
# if he has no parent, assume this is the first time he's been parented
|
||||
# to anything, and don't wrtReparent, just do a regular reparent.
|
||||
firstParent = 0
|
||||
if self.av.getParent().isEmpty():
|
||||
firstParent = 1
|
||||
|
||||
if not firstParent:
|
||||
# Stick the avatar under hidden while we move the cellOrigin into
|
||||
# position so we do not lose the avatars absolute position.
|
||||
self.av.wrtReparentTo(hidden)
|
||||
|
||||
if grid != self.grid:
|
||||
# Setup the grid for the first time
|
||||
# set/change the grid that we are working on.
|
||||
self.grid = grid
|
||||
# Reparent the gridNodes under this grid
|
||||
self.cellOrigin.reparentTo(grid)
|
||||
self.cellOrigin.setPosHpr(0,0,0,0,0,0)
|
||||
|
||||
# Get grid cell origin
|
||||
cellPos = self.grid.getZoneCellOrigin(zoneId)
|
||||
|
||||
# Set the gridNode's position
|
||||
self.cellOrigin.setPos(*cellPos)
|
||||
|
||||
# Reparent our avatar to this node
|
||||
if not firstParent:
|
||||
self.av.wrtReparentTo(self.cellOrigin)
|
||||
else:
|
||||
self.av.reparentTo(self.cellOrigin)
|
||||
|
||||
#print "gridParent: reparent to %s" % self.av
|
||||
#print "gridParent: pos = %s,%s" % (self.av.getPos(), self.av.getParent().getPos())
|
||||
|
||||
|
||||
Loading…
Reference in New Issue