added parentMgr for more flexible distributed reparentTo's

This commit is contained in:
Darren Ranalli 2003-07-18 20:22:24 +00:00
parent 9d18ee6aff
commit b64887d146
4 changed files with 120 additions and 7 deletions

View File

@ -8,6 +8,7 @@ import ClientDistClass
import CRCache
import ConnectionRepository
import PythonUtil
import ParentMgr
import time
class ClientRepository(ConnectionRepository.ConnectionRepository):
@ -27,6 +28,10 @@ class ClientRepository(ConnectionRepository.ConnectionRepository):
self.bootedIndex = None
self.bootedText = None
# create a parentMgr to handle distributed reparents
# this used to be 'token2nodePath'
self.parentMgr = ParentMgr.ParentMgr()
def setServerDelta(self, delta):
"""
Indicates the approximate difference in seconds between the

View File

@ -48,15 +48,14 @@ class DistributedNode(DistributedObject.DistributedObject, NodePath):
def b_setParent(self, parentToken):
self.setParent(parentToken)
# it's important to call the local setParent first.
self.d_setParent(parentToken)
return None
def d_setParent(self, parentToken):
self.sendUpdate("setParent", [parentToken])
return None
def setParent(self, parentToken):
return self.do_setParent(parentToken)
self.do_setParent(parentToken)
def do_setParent(self, parentToken):
"""do_setParent(self, int parentToken)
@ -66,10 +65,7 @@ class DistributedNode(DistributedObject.DistributedObject, NodePath):
desired.
"""
if not self.isDisabled():
assert(self.cr.token2nodePath.has_key(parentToken))
parent = self.cr.token2nodePath[parentToken]
self.wrtReparentTo(parent)
return None
self.cr.parentMgr.requestReparent(self, parentToken)
###### set pos and hpr functions #######

View File

@ -319,6 +319,18 @@ class DistributedSmoothNode(DistributedNode.DistributedNode):
else:
NodePath.wrtReparentTo(self, parent)
def d_setParent(self, parentToken):
# We override this DistributedNode method to force a full position
# update immediately after the distributed setParent is sent.
# See ParentMgr.py for an explanation.
DistributedNode.DistributedNode.d_setParent(self, parentToken)
self.forceToTruePosition()
xyz = self.getPos()
hpr = self.getHpr()
x=xyz[0]; y=xyz[1]; z=xyz[2]
h=hpr[0]; p=hpr[1]; r=hpr[2]
self.d_setSmPosHpr(x,y,z,h,p,r)
### Monitor clock sync ###

View File

@ -0,0 +1,100 @@
"""ParentMgr module: contains the ParentMgr class"""
from ShowBaseGlobal import *
from ToontownGlobals import *
import DirectNotifyGlobal
class ParentMgr:
"""ParentMgr holds a table of nodes that avatars may be parented to
in a distributed manner. All clients within a particular zone maintain
identical tables of these nodes, and the nodes are referenced by 'tokens'
which the clients can pass to each other to communicate distributed
reparenting information.
The functionality of ParentMgr used to be implemented with a simple
token->node dictionary. As distributed 'parent' objects were manifested,
they would add themselves to the dictionary. Problems occured when
distributed avatars were manifested before the objects to which they
were parented to.
Since the order of object manifestation depends on the order of the
classes in the DC file, we could maintain an ordering of DC definitions
that ensures that the necessary objects are manifested before avatars.
However, it's easy enough to keep a list of pending reparents and thus
support the general case without requiring any strict ordering in the DC.
"""
notify = DirectNotifyGlobal.directNotify.newCategory('ParentMgr')
def __init__(self):
self.token2nodepath = {}
# these are nodepaths that have requested to be parented to
# a node that has not yet been registered
self.pendingChildren = {}
def destroy(self):
del self.token2nodepath
del self.pendingChildren
def requestReparent(self, child, parentToken):
if parentToken in self.token2nodepath.keys():
# this parent has registered
self.notify.debug('performing wrtReparent of %s to %s' %
(child, parentToken))
child.wrtReparentTo(self.token2nodepath[parentToken])
else:
self.notify.warning(
"child %s requested reparent to '%s', not in list" %
(child, parentToken))
if not self.pendingChildren.has_key(parentToken):
self.pendingChildren[parentToken] = []
self.pendingChildren[parentToken].append(child)
def registerParent(self, token, parent):
if token in self.token2nodepath.keys():
self.notify.error(
'token %s already in the table, referencing %s' %
(token, self.token2nodepath[token]))
self.notify.debug('registering %s as %s' % (parent, token))
self.token2nodepath[token] = parent
# if we have any pending children, add them
if token in self.pendingChildren.keys():
children = self.pendingChildren[token]
for child in children:
# NOTE: We do a plain-old reparentTo here (non-wrt)
# under the assumption that the node has been
# positioned as if it is already under the new parent.
#
# The only case that I can think of where the parent
# node would not have been registered at the time of
# the reparent request is when we're entering a new
# zone and manifesting remote toons along with
# other distributed objects, and a remote toon is
# requesting to be parented to geometry owned by a
# distributed object that has not yet been manifested.
#
# It is therefore important for that remote toon to
# have his position set as a required field, relative
# to the parent node, after the reparent request.
# If the node has already been registered, the toon will
# be in the correct position. Otherwise, the toon will
# have the correct position but the wrong parent node,
# until this code runs and corrects the toon's parent
# node. Since we don't start rendering until all objects
# in a new zone have been generated, all of that action
# will happen in a single frame, and the net result will
# be that the toon will be in the right place when
# rendering starts.
self.notify.debug('performing reparent of %s to %s' %
(child, token))
child.reparentTo(self.token2nodepath[token])
del self.pendingChildren[token]
def unregisterParent(self, token):
if token not in self.token2nodepath.keys():
self.notify.warning('unknown token %s' % token)
return
self.notify.debug("unregistering parent '%s'" % (token))
del self.token2nodepath[token]