From 3236d9f08ae6236ebe5e482002fed7ec6048fe8b Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Fri, 2 Oct 2026 08:55:04 -0500 Subject: [PATCH] fix(entity): children once each in id order, and the count matches the ids sent The client keeps an object's children as a set of ids (LWOGameObject::childObjects). Every multi-child list in the live captures (57) was in ascending id order. A child added twice is now kept once. The child count also counted entries the loop then skipped. Co-Authored-By: Claude Opus 5.5 --- dGame/Entity.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 211b7f08c..73b5f309e 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -747,7 +747,7 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream& outBitStream, eReplicaPacke } outBitStream.Write(!m_ChildEntities.empty()); if (!m_ChildEntities.empty()) { - outBitStream.Write(m_ChildEntities.size()); + outBitStream.Write(std::ranges::count_if(m_ChildEntities, [](const Entity* child) { return child != nullptr; })); for (const auto* const child : m_ChildEntities) { if (child) outBitStream.Write(child->GetObjectID()); } @@ -1261,9 +1261,14 @@ void Entity::RegisterCoinDrop(uint64_t count) const { characterComponent->SetDroppedCoins(characterComponent->GetDroppedCoins() + count); } +// The client keeps an object's children as a set of ids (LWOGameObject::childObjects): once each, in id order void Entity::AddChild(Entity* child) { + if (!child) return; + const auto id = child->GetObjectID(); + const auto it = std::ranges::lower_bound(m_ChildEntities, id, {}, [](const Entity* entity) { return entity ? entity->GetObjectID() : LWOOBJID_EMPTY; }); + if (it != m_ChildEntities.end() && *it && (*it)->GetObjectID() == id) return; m_IsParentChildDirty = true; - m_ChildEntities.push_back(child); + m_ChildEntities.insert(it, child); } void Entity::RemoveChild(Entity* child) {