diff --git a/code/components/citizen-server-impl/src/state/ServerGameState_Scripting.cpp b/code/components/citizen-server-impl/src/state/ServerGameState_Scripting.cpp index 619d155541..64b5fa580d 100644 --- a/code/components/citizen-server-impl/src/state/ServerGameState_Scripting.cpp +++ b/code/components/citizen-server-impl/src/state/ServerGameState_Scripting.cpp @@ -17,6 +17,78 @@ namespace fx void DisownEntityScript(const fx::sync::SyncEntityPtr& entity); } +namespace +{ + bool IsAttachedToRootEntity(const fx::sync::SyncEntityPtr& entity, + const fx::sync::SyncEntityPtr& rootEntity, + const fwRefContainer& gameState, + std::unordered_set& visitedEntities, + std::unordered_set& rootConnectedEntities) + { + if (rootConnectedEntities.find(entity->handle) != rootConnectedEntities.end()) + { + return true; + } + + if (visitedEntities.find(entity->handle) != visitedEntities.end()) + { + return false; + } + + visitedEntities.insert(entity->handle); + + if (entity->syncTree) + { + const fx::sync::CBaseAttachNodeData* attachment = entity->syncTree->GetAttachment(); + + if (attachment && attachment->attached && attachment->attachedTo) + { + const auto parentEntity = gameState->GetEntity(0, attachment->attachedTo); + + if (parentEntity) + { + if (parentEntity == rootEntity || IsAttachedToRootEntity(parentEntity, rootEntity, gameState, visitedEntities, rootConnectedEntities)) + { + if (entity->type == fx::sync::NetObjEntityType::Player) + { + if (const auto client = entity->GetClient()) + { + auto [lock, clientData] = gameState->ExternalGetClientData(client); + gameState->ClearClientFromWorldGrid(client); + clientData->routingBucket = parentEntity->routingBucket; + } + } + + entity->routingBucket = parentEntity->routingBucket; + + rootConnectedEntities.insert(entity->handle); + + return true; + } + } + } + } + + return false; + } + + void SetRoutingBucketForAttachedEntities(const fx::sync::SyncEntityPtr& rootEntity) + { + const auto resourceManager = fx::ResourceManager::GetCurrent(); + const auto instance = resourceManager->GetComponent()->Get(); + const auto gameState = instance->GetComponent(); + + std::unordered_set visitedEntities; + std::unordered_set rootConnectedEntities; + + std::shared_lock lock(gameState->m_entityListMutex); + for (auto& entity : gameState->m_entityList) + { + IsAttachedToRootEntity(entity, rootEntity, gameState, visitedEntities, rootConnectedEntities); + } + } +} + static void Init() { auto makeEntityFunction = [](auto fn, uintptr_t defaultValue = 0) @@ -1550,6 +1622,7 @@ static void Init() if (playerEntity) { playerEntity->routingBucket = bucket; + SetRoutingBucketForAttachedEntities(playerEntity); } } } @@ -1571,6 +1644,7 @@ static void Init() if (bucket >= 0) { entity->routingBucket = bucket; + SetRoutingBucketForAttachedEntities(entity); } }