From c83ec8228c4d67323b5bac87725bcbcefe576874 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sun, 14 Jan 2024 11:10:13 -0800 Subject: [PATCH] chore: Move Player ghosting functionality to GhostComponent (#1413) * Moving and organizing Player code - Move code to CharacterComponent - Remove extraneous interfaces - Simplify some code greatly - Change some types to return and take in const ref (only structs larger than 8 bytes benefit from this change.) - Update code to use CharacterComponent for sending to zone instead of Player*. * Moving and organizing Player code - Move code to CharacterComponent - Remove extraneous interfaces - Simplify some code greatly - Change some types to return and take in const ref (only structs larger than 8 bytes benefit from this change.) - Update code to use CharacterComponent for sending to zone instead of Player*. - Remove static storage container (static containers can be destroyed before exit/terminate handler executes) * remove player cast * Remove extra includes * Add a player manager Used for the static Player functions. Further removes stuff from the Player class/file. * chore: Move ghosting functionality to component Tested that ghosting still works and players are still firing off the OnPlayerLeave and relevant handlers. * move to unordered_set --- dGame/Entity.cpp | 6 +- dGame/EntityManager.cpp | 34 +++++---- dGame/Player.cpp | 81 +--------------------- dGame/Player.h | 36 ---------- dGame/PlayerManager.cpp | 7 +- dGame/PlayerManager.h | 2 +- dGame/dComponents/GhostComponent.cpp | 57 ++++++++++++++- dGame/dComponents/GhostComponent.h | 41 +++++++++++ dGame/dGameMessages/GameMessageHandler.cpp | 11 +-- dGame/dGameMessages/GameMessages.cpp | 7 +- 10 files changed, 138 insertions(+), 144 deletions(-) diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 46350803..23f0b6b6 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -2135,9 +2135,9 @@ void Entity::ProcessPositionUpdate(PositionUpdate& update) { controllablePhysicsComponent->SetAngularVelocity(update.angularVelocity); controllablePhysicsComponent->SetDirtyAngularVelocity(update.angularVelocity != NiPoint3::ZERO); - auto* player = static_cast(this); - player->SetGhostReferencePoint(update.position); - Game::entityManager->QueueGhostUpdate(player->GetObjectID()); + auto* ghostComponent = GetComponent(); + if (ghostComponent) ghostComponent->SetGhostReferencePoint(update.position); + Game::entityManager->QueueGhostUpdate(GetObjectID()); if (updateChar) Game::entityManager->SerializeEntity(this); } diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 29aa54bb..10655d25 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -24,6 +24,7 @@ #include "eReplicaComponentType.h" #include "eReplicaPacketType.h" #include "PlayerManager.h" +#include "GhostComponent.h" // Configure which zones have ghosting disabled, mostly small worlds. std::vector EntityManager::m_GhostingExcludedZones = { @@ -189,7 +190,8 @@ void EntityManager::SerializeEntities() { if (entity->GetIsGhostingCandidate()) { for (auto* player : PlayerManager::GetAllPlayers()) { - if (player->IsObserved(toSerialize)) { + auto* ghostComponent = player->GetComponent(); + if (ghostComponent && ghostComponent->IsObserved(toSerialize)) { Game::server->Send(&stream, player->GetSystemAddress(), false); } } @@ -381,7 +383,8 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr if (player->GetPlayerReadyForUpdates()) { Game::server->Send(&stream, player->GetSystemAddress(), false); } else { - player->AddLimboConstruction(entity->GetObjectID()); + auto* ghostComponent = player->GetComponent(); + if (ghostComponent) ghostComponent->AddLimboConstruction(entity->GetObjectID()); } } } @@ -421,7 +424,8 @@ void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) for (auto* player : PlayerManager::GetAllPlayers()) { if (!player->GetPlayerReadyForUpdates()) { - player->RemoveLimboConstruction(entity->GetObjectID()); + auto* ghostComponent = player->GetComponent(); + if (ghostComponent) ghostComponent->RemoveLimboConstruction(entity->GetObjectID()); } } } @@ -484,13 +488,14 @@ void EntityManager::UpdateGhosting(Player* player) { } auto* missionComponent = player->GetComponent(); + auto* ghostComponent = player->GetComponent(); - if (missionComponent == nullptr) { + if (missionComponent == nullptr || !ghostComponent) { return; } - const auto& referencePoint = player->GetGhostReferencePoint(); - const auto isOverride = player->GetGhostOverride(); + const auto& referencePoint = ghostComponent->GetGhostReferencePoint(); + const auto isOverride = ghostComponent->GetGhostOverride(); for (auto* entity : m_EntitiesToGhost) { const auto isAudioEmitter = entity->GetLOT() == 6368; @@ -499,7 +504,7 @@ void EntityManager::UpdateGhosting(Player* player) { const int32_t id = entity->GetObjectID(); - const auto observed = player->IsObserved(id); + const auto observed = ghostComponent->IsObserved(id); const auto distance = NiPoint3::DistanceSquared(referencePoint, entityPoint); @@ -511,7 +516,7 @@ void EntityManager::UpdateGhosting(Player* player) { } if (observed && distance > ghostingDistanceMax && !isOverride) { - player->GhostEntity(id); + ghostComponent->GhostEntity(id); DestructEntity(entity, player->GetSystemAddress()); @@ -528,7 +533,7 @@ void EntityManager::UpdateGhosting(Player* player) { } } - player->ObserveEntity(id); + ghostComponent->ObserveEntity(id); ConstructEntity(entity, player->GetSystemAddress()); @@ -550,22 +555,25 @@ void EntityManager::CheckGhosting(Entity* entity) { const auto isAudioEmitter = entity->GetLOT() == 6368; for (auto* player : PlayerManager::GetAllPlayers()) { - const auto& entityPoint = player->GetGhostReferencePoint(); + auto* ghostComponent = player->GetComponent(); + if (!ghostComponent) continue; + + const auto& entityPoint = ghostComponent->GetGhostReferencePoint(); const int32_t id = entity->GetObjectID(); - const auto observed = player->IsObserved(id); + const auto observed = ghostComponent->IsObserved(id); const auto distance = NiPoint3::DistanceSquared(referencePoint, entityPoint); if (observed && distance > ghostingDistanceMax) { - player->GhostEntity(id); + ghostComponent->GhostEntity(id); DestructEntity(entity, player->GetSystemAddress()); entity->SetObservers(entity->GetObservers() - 1); } else if (!observed && ghostingDistanceMin > distance) { - player->ObserveEntity(id); + ghostComponent->ObserveEntity(id); ConstructEntity(entity, player->GetSystemAddress()); diff --git a/dGame/Player.cpp b/dGame/Player.cpp index 96ba1ecd..8f414b43 100644 --- a/dGame/Player.cpp +++ b/dGame/Player.cpp @@ -14,14 +14,6 @@ #include "eReplicaComponentType.h" #include "PlayerManager.h" -void Player::SetGhostReferencePoint(const NiPoint3& value) { - m_GhostReferencePoint = value; -} - -void Player::SetGhostOverridePoint(const NiPoint3& value) { - m_GhostOverridePoint = value; -} - void Player::SetRespawnPos(const NiPoint3& position) { if (!m_Character) return; @@ -47,85 +39,16 @@ Player::Player(const LWOOBJID& objectID, const EntityInfo info, User* user, Enti m_SystemAddress = m_ParentUser->GetSystemAddress(); m_DroppedCoins = 0; - m_GhostReferencePoint = NiPoint3::ZERO; - m_GhostOverridePoint = NiPoint3::ZERO; - m_GhostOverride = false; - - int32_t initialObservedEntitiesCapacity = 256; - m_ObservedEntities.resize(initialObservedEntitiesCapacity); - m_Character->SetEntity(this); PlayerManager::AddPlayer(this); } -void Player::AddLimboConstruction(LWOOBJID objectId) { - const auto iter = std::find(m_LimboConstructions.begin(), m_LimboConstructions.end(), objectId); - if (iter == m_LimboConstructions.end()) { - m_LimboConstructions.push_back(objectId); - } -} - -void Player::RemoveLimboConstruction(LWOOBJID objectId) { - const auto iter = std::find(m_LimboConstructions.begin(), m_LimboConstructions.end(), objectId); - if (iter != m_LimboConstructions.end()) { - m_LimboConstructions.erase(iter); - } -} - -void Player::ConstructLimboEntities() { - for (const auto& objectId : m_LimboConstructions) { - auto* entity = Game::entityManager->GetEntity(objectId); - if (!entity) continue; - - Game::entityManager->ConstructEntity(entity, m_SystemAddress); - } - - m_LimboConstructions.clear(); -} - -void Player::ObserveEntity(int32_t id) { - for (auto& observedEntity : m_ObservedEntities) { - if (observedEntity == 0 || observedEntity == id) { - observedEntity = id; - - return; - } - } - - m_ObservedEntities.reserve(m_ObservedEntities.size() + 1); - - m_ObservedEntities.push_back(id); -} - -bool Player::IsObserved(int32_t id) { - return std::find(m_ObservedEntities.begin(), m_ObservedEntities.end(), id) != m_ObservedEntities.end(); -} - -void Player::GhostEntity(int32_t id) { - for (auto& observedEntity : m_ObservedEntities) { - if (observedEntity == id) { - observedEntity = 0; - } - } -} - Player::~Player() { LOG("Deleted player"); - - for (auto& observedEntity : m_ObservedEntities) { - if (observedEntity == 0) continue; - - auto* entity = Game::entityManager->GetGhostCandidate(observedEntity); - if (!entity) continue; - - entity->SetObservers(entity->GetObservers() - 1); - } - - m_LimboConstructions.clear(); // Make sure the player exists first. Remove afterwards to prevent the OnPlayerExist functions from not being able to find the player. - if (!PlayerManager::GetPlayer(GetObjectID())) { + if (!PlayerManager::RemovePlayer(this)) { LOG("Unable to find player to remove from manager."); return; } @@ -145,6 +68,4 @@ Player::~Player() { } } } - - PlayerManager::RemovePlayer(this); } diff --git a/dGame/Player.h b/dGame/Player.h index a168c70b..dd8efd9c 100644 --- a/dGame/Player.h +++ b/dGame/Player.h @@ -26,14 +26,6 @@ public: const NiQuaternion& GetRespawnRotation() const override { return m_respawnRot; }; - const NiPoint3& GetGhostReferencePoint() const { return m_GhostOverride ? m_GhostOverridePoint : m_GhostReferencePoint; }; - - const NiPoint3& GetOriginGhostReferencePoint() const { return m_GhostReferencePoint; }; - - const NiPoint3& GetGhostOverridePoint() const { return m_GhostOverridePoint; }; - - bool GetGhostOverride() const { return m_GhostOverride; }; - std::map& GetDroppedLoot() { return m_DroppedLoot; }; uint64_t GetDroppedCoins() const { return m_DroppedCoins; }; @@ -42,8 +34,6 @@ public: * Setters */ - void SetGhostOverride(bool value) { m_GhostOverride = value; }; - void SetDroppedCoins(const uint64_t value) { m_DroppedCoins = value; }; void SetSystemAddress(const SystemAddress& value) override; @@ -52,26 +42,10 @@ public: void SetRespawnRot(const NiQuaternion& rotation) override; - void SetGhostReferencePoint(const NiPoint3& value); - - void SetGhostOverridePoint(const NiPoint3& value); - /** * Ghosting */ - void AddLimboConstruction(LWOOBJID objectId); - - void RemoveLimboConstruction(LWOOBJID objectId); - - void ConstructLimboEntities(); - - void ObserveEntity(const int32_t id); - - bool IsObserved(const int32_t id); - - void GhostEntity(const int32_t id); - ~Player() override; private: SystemAddress m_SystemAddress; @@ -82,16 +56,6 @@ private: User* m_ParentUser; - NiPoint3 m_GhostReferencePoint; - - NiPoint3 m_GhostOverridePoint; - - bool m_GhostOverride; - - std::vector m_ObservedEntities; - - std::vector m_LimboConstructions; - std::map m_DroppedLoot; uint64_t m_DroppedCoins; diff --git a/dGame/PlayerManager.cpp b/dGame/PlayerManager.cpp index 7094abf7..e3017f05 100644 --- a/dGame/PlayerManager.cpp +++ b/dGame/PlayerManager.cpp @@ -22,12 +22,15 @@ void PlayerManager::AddPlayer(Player* player) { } } -void PlayerManager::RemovePlayer(Player* player) { +bool PlayerManager::RemovePlayer(Player* player) { const auto iter = std::find(m_Players.begin(), m_Players.end(), player); - if (iter != m_Players.end()) { + const bool toReturn = iter != m_Players.end(); + if (toReturn) { m_Players.erase(iter); } + + return toReturn; } Player* PlayerManager::GetPlayer(const SystemAddress& sysAddr) { diff --git a/dGame/PlayerManager.h b/dGame/PlayerManager.h index 7b88ebfd..bb54f83b 100644 --- a/dGame/PlayerManager.h +++ b/dGame/PlayerManager.h @@ -11,7 +11,7 @@ struct SystemAddress; namespace PlayerManager { void AddPlayer(Player* player); - void RemovePlayer(Player* player); + bool RemovePlayer(Player* player); Player* GetPlayer(const SystemAddress& sysAddr); diff --git a/dGame/dComponents/GhostComponent.cpp b/dGame/dComponents/GhostComponent.cpp index 56bb1670..2978c912 100644 --- a/dGame/dComponents/GhostComponent.cpp +++ b/dGame/dComponents/GhostComponent.cpp @@ -1,4 +1,57 @@ #include "GhostComponent.h" -// TODO Move ghosting related code from Player to here -GhostComponent::GhostComponent(Entity* parent) : Component(parent) {} +GhostComponent::GhostComponent(Entity* parent) : Component(parent) { + m_GhostReferencePoint = NiPoint3::ZERO; + m_GhostOverridePoint = NiPoint3::ZERO; + m_GhostOverride = false; +} + +GhostComponent::~GhostComponent() { + for (auto& observedEntity : m_ObservedEntities) { + if (observedEntity == 0) continue; + + auto* entity = Game::entityManager->GetGhostCandidate(observedEntity); + if (!entity) continue; + + entity->SetObservers(entity->GetObservers() - 1); + } +} + +void GhostComponent::SetGhostReferencePoint(const NiPoint3& value) { + m_GhostReferencePoint = value; +} + +void GhostComponent::SetGhostOverridePoint(const NiPoint3& value) { + m_GhostOverridePoint = value; +} + +void GhostComponent::AddLimboConstruction(LWOOBJID objectId) { + m_LimboConstructions.insert(objectId); +} + +void GhostComponent::RemoveLimboConstruction(LWOOBJID objectId) { + m_LimboConstructions.erase(objectId); +} + +void GhostComponent::ConstructLimboEntities() { + for (const auto& objectId : m_LimboConstructions) { + auto* entity = Game::entityManager->GetEntity(objectId); + if (!entity) continue; + + Game::entityManager->ConstructEntity(entity, m_Parent->GetSystemAddress()); + } + + m_LimboConstructions.clear(); +} + +void GhostComponent::ObserveEntity(int32_t id) { + m_ObservedEntities.insert(id); +} + +bool GhostComponent::IsObserved(int32_t id) { + return m_ObservedEntities.contains(id); +} + +void GhostComponent::GhostEntity(int32_t id) { + m_ObservedEntities.erase(id); +} diff --git a/dGame/dComponents/GhostComponent.h b/dGame/dComponents/GhostComponent.h index d99ffcd9..5ae308a4 100644 --- a/dGame/dComponents/GhostComponent.h +++ b/dGame/dComponents/GhostComponent.h @@ -3,11 +3,52 @@ #include "Component.h" #include "eReplicaComponentType.h" +#include + +class NiPoint3; class GhostComponent : public Component { public: static inline const eReplicaComponentType ComponentType = eReplicaComponentType::GHOST; GhostComponent(Entity* parent); + ~GhostComponent() override; + + void SetGhostOverride(bool value) { m_GhostOverride = value; }; + + const NiPoint3& GetGhostReferencePoint() const { return m_GhostOverride ? m_GhostOverridePoint : m_GhostReferencePoint; }; + + const NiPoint3& GetOriginGhostReferencePoint() const { return m_GhostReferencePoint; }; + + const NiPoint3& GetGhostOverridePoint() const { return m_GhostOverridePoint; }; + + bool GetGhostOverride() const { return m_GhostOverride; }; + + void SetGhostReferencePoint(const NiPoint3& value); + + void SetGhostOverridePoint(const NiPoint3& value); + + void AddLimboConstruction(const LWOOBJID objectId); + + void RemoveLimboConstruction(const LWOOBJID objectId); + + void ConstructLimboEntities(); + + void ObserveEntity(const int32_t id); + + bool IsObserved(const int32_t id); + + void GhostEntity(const int32_t id); + +private: + NiPoint3 m_GhostReferencePoint; + + NiPoint3 m_GhostOverridePoint; + + std::unordered_set m_ObservedEntities; + + std::unordered_set m_LimboConstructions; + + bool m_GhostOverride; }; #endif //!__GHOSTCOMPONENT__H__ diff --git a/dGame/dGameMessages/GameMessageHandler.cpp b/dGame/dGameMessages/GameMessageHandler.cpp index c997bdd1..fa11c086 100644 --- a/dGame/dGameMessages/GameMessageHandler.cpp +++ b/dGame/dGameMessages/GameMessageHandler.cpp @@ -37,6 +37,7 @@ #include "eGameMessageType.h" #include "ePlayerFlag.h" #include "dConfig.h" +#include "GhostComponent.h" #include "StringifiedEnum.h" void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const SystemAddress& sysAddr, LWOOBJID objectID, eGameMessageType messageID) { @@ -108,9 +109,9 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System GameMessages::SendRestoreToPostLoadStats(entity, sysAddr); entity->SetPlayerReadyForUpdates(); - auto* player = dynamic_cast(entity); - if (player != nullptr) { - player->ConstructLimboEntities(); + auto* ghostComponent = entity->GetComponent(); + if (ghostComponent != nullptr) { + ghostComponent->ConstructLimboEntities(); } InventoryComponent* inv = entity->GetComponent(); @@ -137,14 +138,14 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System Entity* zoneControl = Game::entityManager->GetZoneControlEntity(); for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { - script->OnPlayerLoaded(zoneControl, player); + script->OnPlayerLoaded(zoneControl, entity); } std::vector scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPT); for (Entity* scriptEntity : scriptedActs) { if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { - script->OnPlayerLoaded(scriptEntity, player); + script->OnPlayerLoaded(scriptEntity, entity); } } } diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index c1c92116..595444e9 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -78,6 +78,7 @@ #include "RailActivatorComponent.h" #include "LevelProgressionComponent.h" #include "DonationVendorComponent.h" +#include "GhostComponent.h" // Message includes: #include "dZoneManager.h" @@ -4605,7 +4606,8 @@ void GameMessages::HandleToggleGhostReferenceOverride(RakNet::BitStream* inStrea auto* player = PlayerManager::GetPlayer(sysAddr); if (player != nullptr) { - player->SetGhostOverride(bOverride); + auto* ghostComponent = entity->GetComponent(); + if (ghostComponent) ghostComponent->SetGhostOverride(bOverride); Game::entityManager->UpdateGhosting(player); } @@ -4620,7 +4622,8 @@ void GameMessages::HandleSetGhostReferencePosition(RakNet::BitStream* inStream, auto* player = PlayerManager::GetPlayer(sysAddr); if (player != nullptr) { - player->SetGhostOverridePoint(position); + auto* ghostComponent = entity->GetComponent(); + if (ghostComponent) ghostComponent->SetGhostOverridePoint(position); Game::entityManager->UpdateGhosting(player); }