From 38e60ae40c739705df9a87fc836ee6d97bb0dab3 Mon Sep 17 00:00:00 2001 From: Jared Miller Date: Tue, 10 Feb 2026 13:47:58 -0500 Subject: [PATCH] Fix insert_object to remove from old parent before inserting The old code inserted the object into the new parent first, then tried to remove it from the old parent. This corrupted the sibling chain because the object's sibling pointer was already modified. The Z-spec says "if O already has a parent, it is first removed." Now delegates to remove_object() before inserting. --- src/mudlib/zmachine/zobjectparser.py | 35 +++++++--------------------- 1 file changed, 8 insertions(+), 27 deletions(-) diff --git a/src/mudlib/zmachine/zobjectparser.py b/src/mudlib/zmachine/zobjectparser.py index c0f6ad5..5c265b6 100644 --- a/src/mudlib/zmachine/zobjectparser.py +++ b/src/mudlib/zmachine/zobjectparser.py @@ -330,40 +330,21 @@ class ZObjectParser: self.set_sibling(objectnum, 0) def insert_object(self, parent_object, new_child): - """Prepend object NEW_CHILD to the list of PARENT_OBJECT's children.""" + """Prepend object NEW_CHILD to the list of PARENT_OBJECT's children. - # Remember all the original pointers within the new_child - [p, s, c] = self._get_parent_sibling_child(new_child) + Per the Z-spec: if new_child already has a parent, it is first + removed from that parent's child list, then made the first child + of parent_object.""" - # First insert new_child intto the parent_object + # Remove from old parent first (spec says "first removed") + self.remove_object(new_child) + + # Now insert as first child of parent_object original_child = self.get_child(parent_object) self.set_sibling(new_child, original_child) self.set_parent(new_child, parent_object) self.set_child(parent_object, new_child) - if p == 0: # no need to 'remove' new_child, since it wasn't in a tree - return - - # Hunt down and remove the new_child from its old location - item = self.get_child(p) - if item == 0: - # new_object claimed to have parent p, but p has no children!? - raise ZObjectMalformedTree - elif item == new_child: # done! new_object was head of list - self.set_child(p, s) # note that s might be 0, that's fine. - else: # walk across list of sibling links - prev = item - current = self.get_sibling(item) - while current != 0: - if current == new_child: - self.set_sibling(prev, s) # s might be 0, that's fine. - break - prev = current - current = self.get_sibling(current) - else: - # we reached the end of the list, never got a match - raise ZObjectMalformedTree - def get_shortname(self, objectnum): """Return 'short name' of object number OBJECTNUM as ascii string."""