Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Move Player ghosting functionality to GhostComponent #1413

Merged
merged 10 commits into from
Jan 14, 2024
6 changes: 3 additions & 3 deletions dGame/Entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2125,9 +2125,9 @@ void Entity::ProcessPositionUpdate(PositionUpdate& update) {
controllablePhysicsComponent->SetAngularVelocity(update.angularVelocity);
controllablePhysicsComponent->SetDirtyAngularVelocity(update.angularVelocity != NiPoint3::ZERO);

auto* player = static_cast<Player*>(this);
player->SetGhostReferencePoint(update.position);
Game::entityManager->QueueGhostUpdate(player->GetObjectID());
auto* ghostComponent = GetComponent<GhostComponent>();
if (ghostComponent) ghostComponent->SetGhostReferencePoint(update.position);
Game::entityManager->QueueGhostUpdate(GetObjectID());

if (updateChar) Game::entityManager->SerializeEntity(this);
}
34 changes: 21 additions & 13 deletions dGame/EntityManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<LWOMAPID> EntityManager::m_GhostingExcludedZones = {
Expand Down Expand Up @@ -189,7 +190,8 @@ void EntityManager::SerializeEntities() {

if (entity->GetIsGhostingCandidate()) {
for (auto* player : PlayerManager::GetAllPlayers()) {
if (player->IsObserved(toSerialize)) {
auto* ghostComponent = player->GetComponent<GhostComponent>();
if (ghostComponent && ghostComponent->IsObserved(toSerialize)) {
Game::server->Send(&stream, player->GetSystemAddress(), false);
}
}
Expand Down Expand Up @@ -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<GhostComponent>();
if (ghostComponent) ghostComponent->AddLimboConstruction(entity->GetObjectID());
}
}
}
Expand Down Expand Up @@ -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<GhostComponent>();
if (ghostComponent) ghostComponent->RemoveLimboConstruction(entity->GetObjectID());
}
}
}
Expand Down Expand Up @@ -484,13 +488,14 @@ void EntityManager::UpdateGhosting(Player* player) {
}

auto* missionComponent = player->GetComponent<MissionComponent>();
auto* ghostComponent = player->GetComponent<GhostComponent>();

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;
Expand All @@ -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);

Expand All @@ -511,7 +516,7 @@ void EntityManager::UpdateGhosting(Player* player) {
}

if (observed && distance > ghostingDistanceMax && !isOverride) {
player->GhostEntity(id);
ghostComponent->GhostEntity(id);

DestructEntity(entity, player->GetSystemAddress());

Expand All @@ -528,7 +533,7 @@ void EntityManager::UpdateGhosting(Player* player) {
}
}

player->ObserveEntity(id);
ghostComponent->ObserveEntity(id);

ConstructEntity(entity, player->GetSystemAddress());

Expand All @@ -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<GhostComponent>();
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());

Expand Down
81 changes: 1 addition & 80 deletions dGame/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}
Expand All @@ -145,6 +68,4 @@ Player::~Player() {
}
}
}

PlayerManager::RemovePlayer(this);
}
36 changes: 0 additions & 36 deletions dGame/Player.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,6 @@ class Player final : public Entity

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<LWOOBJID, Loot::Info>& GetDroppedLoot() { return m_DroppedLoot; };

uint64_t GetDroppedCoins() const { return m_DroppedCoins; };
Expand All @@ -42,8 +34,6 @@ class Player final : public Entity
* Setters
*/

void SetGhostOverride(bool value) { m_GhostOverride = value; };

void SetDroppedCoins(const uint64_t value) { m_DroppedCoins = value; };

void SetSystemAddress(const SystemAddress& value) override;
Expand All @@ -52,26 +42,10 @@ class Player final : public Entity

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;
Expand All @@ -82,16 +56,6 @@ class Player final : public Entity

User* m_ParentUser;

NiPoint3 m_GhostReferencePoint;

NiPoint3 m_GhostOverridePoint;

bool m_GhostOverride;

std::vector<int32_t> m_ObservedEntities;

std::vector<LWOOBJID> m_LimboConstructions;

std::map<LWOOBJID, Loot::Info> m_DroppedLoot;

uint64_t m_DroppedCoins;
Expand Down
7 changes: 5 additions & 2 deletions dGame/PlayerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion dGame/PlayerManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
57 changes: 55 additions & 2 deletions dGame/dComponents/GhostComponent.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
Loading
Loading