From b64887d146df3a8aad807706df4670e2e45d88f1 Mon Sep 17 00:00:00 2001 From: Darren Ranalli Date: Fri, 18 Jul 2003 20:22:24 +0000 Subject: [PATCH] added parentMgr for more flexible distributed reparentTo's --- direct/src/distributed/ClientRepository.py | 5 + direct/src/distributed/DistributedNode.py | 10 +- .../src/distributed/DistributedSmoothNode.py | 12 +++ direct/src/distributed/ParentMgr.py | 100 ++++++++++++++++++ 4 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 direct/src/distributed/ParentMgr.py diff --git a/direct/src/distributed/ClientRepository.py b/direct/src/distributed/ClientRepository.py index 0e51e3c89d..2d555e03bc 100644 --- a/direct/src/distributed/ClientRepository.py +++ b/direct/src/distributed/ClientRepository.py @@ -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 diff --git a/direct/src/distributed/DistributedNode.py b/direct/src/distributed/DistributedNode.py index 3bdc27078f..d37a1b99a5 100644 --- a/direct/src/distributed/DistributedNode.py +++ b/direct/src/distributed/DistributedNode.py @@ -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 ####### diff --git a/direct/src/distributed/DistributedSmoothNode.py b/direct/src/distributed/DistributedSmoothNode.py index 317daa7d38..3bfc2d300e 100644 --- a/direct/src/distributed/DistributedSmoothNode.py +++ b/direct/src/distributed/DistributedSmoothNode.py @@ -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 ### diff --git a/direct/src/distributed/ParentMgr.py b/direct/src/distributed/ParentMgr.py new file mode 100644 index 0000000000..df5150a613 --- /dev/null +++ b/direct/src/distributed/ParentMgr.py @@ -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]