From b24661710b327f5ba29e54dd21233da2fa075832 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Thu, 1 Oct 2026 16:05:04 -0500 Subject: [PATCH] refactor(component): controllable physics places its object itself Where an object starts (where the level put it) moves into ControllablePhysicsComponent::LoadConfigData, and where a character comes into the world (its save, then its respawn point, the target scene or the zone's spawn when it came from elsewhere) into LoadFromSaveData, out of Entity::Initialize. Same placement. Co-Authored-By: Claude Opus 5.5 --- dGame/Entity.cpp | 35 +-------------- .../Physics/ControllablePhysicsComponent.cpp | 43 +++++++++++++++++++ .../Physics/ControllablePhysicsComponent.h | 4 ++ 3 files changed, 49 insertions(+), 33 deletions(-) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index ad6987c21..2a7983e6e 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -341,40 +341,9 @@ void Entity::Initialize() { case eReplicaComponentType::CONTROLLABLE_PHYSICS: { const auto controllablePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS); if (controllablePhysicsComponentID > 0) { + // The component places it: where the level put an object, where a character's save and the zone put it auto* controllablePhysics = AddComponent(controllablePhysicsComponentID); - - if (m_Character) { - controllablePhysics->LoadFromSaveData(m_Character->GetXMLDoc()); - - const auto mapID = Game::server->GetZoneID(); - const auto& targetSceneName = m_Character->GetTargetScene(); - - //If we came from another zone, put us in the starting loc - // Exception for Moon Base as you tend to spawn on the roof. - // second exception if we have a specified targetScene since that would only be possible in a test map - if (m_Character->GetZoneID() != Game::server->GetZoneID() || mapID == 1603 || !targetSceneName.empty()) { - NiPoint3 pos; - NiQuaternion rot = QuatUtils::IDENTITY; - - auto* targetScene = Game::entityManager->GetSpawnPointEntity(targetSceneName); - if (m_Character->HasBeenToWorld(mapID) && targetSceneName.empty()) { - pos = m_Character->GetRespawnPoint(mapID); - rot = Game::zoneManager->GetZone()->GetSpawnRot(); - } else if (targetScene != nullptr) { - pos = targetScene->GetPosition(); - rot = targetScene->GetRotation(); - } else { - pos = Game::zoneManager->GetZone()->GetSpawnPos(); - rot = Game::zoneManager->GetZone()->GetSpawnRot(); - } - - controllablePhysics->SetPosition(pos); - controllablePhysics->SetRotation(rot); - } - } else { - controllablePhysics->SetPosition(m_DefaultPosition); - controllablePhysics->SetRotation(m_DefaultRotation); - } + if (m_Character) controllablePhysics->LoadFromSaveData(m_Character->GetXMLDoc()); } break; } diff --git a/dGame/dComponents/Physics/ControllablePhysicsComponent.cpp b/dGame/dComponents/Physics/ControllablePhysicsComponent.cpp index 11fd10f99..a3b8010e6 100644 --- a/dGame/dComponents/Physics/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/Physics/ControllablePhysicsComponent.cpp @@ -13,6 +13,8 @@ #include "EntityManager.h" #include "Character.h" #include "dZoneManager.h" +#include "dServer.h" +#include "Zone.h" #include "LevelProgressionComponent.h" #include "eStateChangeType.h" #include "StringifiedEnum.h" @@ -55,6 +57,12 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity, const void ControllablePhysicsComponent::LoadConfigData() { PhysicsComponent::LoadConfigData(); + // An object that isn't a character starts where the level put it (a character's place comes with its save) + if (!m_Parent->GetCharacter()) { + SetPosition(m_Parent->GetDefaultPosition()); + SetRotation(m_Parent->GetDefaultRotation()); + } + if (m_Parent->GetLOT() != 1) // Other physics entities we care about will be added by BaseCombatAI return; @@ -171,7 +179,42 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bo } } +// A character's save, then where it comes into this world void ControllablePhysicsComponent::LoadFromSaveData(const tinyxml2::XMLDocument& doc) { + ReadSaveData(doc); + PlaceCharacter(); +} + +// If it came from another zone it starts at its respawn point, the target scene or the zone's spawn (Moon Base always: +// the saved place tends to be on the roof; a target scene too: only possible in a test map) +void ControllablePhysicsComponent::PlaceCharacter() { + auto* const character = m_Parent->GetCharacter(); + if (!character) return; + + const auto mapID = Game::server->GetZoneID(); + const auto& targetSceneName = character->GetTargetScene(); + if (character->GetZoneID() == Game::server->GetZoneID() && mapID != 1603 && targetSceneName.empty()) return; + + NiPoint3 pos; + NiQuaternion rot = QuatUtils::IDENTITY; + + auto* targetScene = Game::entityManager->GetSpawnPointEntity(targetSceneName); + if (character->HasBeenToWorld(mapID) && targetSceneName.empty()) { + pos = character->GetRespawnPoint(mapID); + rot = Game::zoneManager->GetZone()->GetSpawnRot(); + } else if (targetScene != nullptr) { + pos = targetScene->GetPosition(); + rot = targetScene->GetRotation(); + } else { + pos = Game::zoneManager->GetZone()->GetSpawnPos(); + rot = Game::zoneManager->GetZone()->GetSpawnRot(); + } + + SetPosition(pos); + SetRotation(rot); +} + +void ControllablePhysicsComponent::ReadSaveData(const tinyxml2::XMLDocument& doc) { auto* character = doc.FirstChildElement("obj")->FirstChildElement("char"); if (!character) { LOG("Failed to find char tag!"); diff --git a/dGame/dComponents/Physics/ControllablePhysicsComponent.h b/dGame/dComponents/Physics/ControllablePhysicsComponent.h index ada804b59..cd9c1a6a9 100644 --- a/dGame/dComponents/Physics/ControllablePhysicsComponent.h +++ b/dGame/dComponents/Physics/ControllablePhysicsComponent.h @@ -285,6 +285,10 @@ public: const bool GetImmuneToStunUseItem() { return m_ImmuneToStunUseItemCount > 0;}; private: + // The save's physics state (LoadFromSaveData), then where the character comes into the world + void ReadSaveData(const tinyxml2::XMLDocument& doc); + void PlaceCharacter(); + bool OnGetObjectReportInfo(GameMessages::GetObjectReportInfo& reportInfo); /**