mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 19:03:43 +00:00
First step of moving hand written bitstream code to struct based messages (see docs/PacketArchitecture.md). No wire changes. - GameMsg is now only a server-internal event (delivered to handlers registered with RegisterMsg); NetGameMsg is a wire message with Send(sysAddr) (UNASSIGNED broadcasts), SendToClient(sysAddr) (one client, never broadcasts), WritePacket, Serialize, Deserialize and Handle. Mixing them up is now a compile error. NetGameMsgEvent<T> / DeliverLocally carry a wire message to local handlers; loot drops, pickup, the object debugger, GM invisibility and model RequestUse use them. The GM invisibility message keeps its target, so its bytes are unchanged. - Behaviour change: GameMessageHandler logs and drops messages whose Deserialize fails instead of handling them with default fields (the 4 messages already registered: RequestUse, RequestServerObjectInfo, ShootingGalleryFire, PickupItem). - LUBitStream (kept as on main) gets a virtual destructor (Mail deleted derived packets through the base) and WritePacket, also used by ChatPackets::SendRoutedMsg with identical bytes. - BitStreamUtils::WriteOptional/ReadOptional for default-flag fields and WriteLengthPrefixed/ReadLengthPrefixed for length prefixed strings. - Every message ID enumerator (MessageType::*, ServiceType, Mail's wire enums) is pinned with static_asserts, so renumbering or removing one fails to compile. - Tests: dServerMock copies each sent packet (it kept a pointer to the caller's destroyed BitStream); PacketTestUtils.h compares packets bit for bit; helper tests use hand computed golden bytes and equality with the hand written patterns they replace; compile-time checks keep the wire/internal split in place. - docs/PacketArchitecture.md: survey, target architecture, conventions, verification method and migration plan. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
117 lines
3.7 KiB
C++
117 lines
3.7 KiB
C++
#include "GhostComponent.h"
|
|
#include "PlayerManager.h"
|
|
#include "Character.h"
|
|
#include "ControllablePhysicsComponent.h"
|
|
#include "UserManager.h"
|
|
#include "User.h"
|
|
|
|
#include "Amf3.h"
|
|
#include "GameMessages.h"
|
|
|
|
GhostComponent::GhostComponent(Entity* parent, const int32_t componentID) : Component(parent, componentID) {
|
|
m_GhostReferencePoint = NiPoint3Constant::ZERO;
|
|
m_GhostOverridePoint = NiPoint3Constant::ZERO;
|
|
m_GhostOverride = false;
|
|
|
|
RegisterMsg(&GhostComponent::OnToggleGMInvis);
|
|
RegisterMsg(&GhostComponent::OnGetGMInvis);
|
|
RegisterMsg(&GhostComponent::MsgGetObjectReportInfo);
|
|
}
|
|
|
|
GhostComponent::~GhostComponent() {
|
|
for (auto& observedEntity : m_ObservedEntities) {
|
|
if (observedEntity == LWOOBJID_EMPTY) 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(LWOOBJID id) {
|
|
m_ObservedEntities.insert(id);
|
|
}
|
|
|
|
bool GhostComponent::IsObserved(LWOOBJID id) {
|
|
return m_ObservedEntities.contains(id);
|
|
}
|
|
|
|
void GhostComponent::GhostEntity(LWOOBJID id) {
|
|
m_ObservedEntities.erase(id);
|
|
}
|
|
|
|
bool GhostComponent::OnToggleGMInvis(GameMessages::ToggleGMInvisEvent& event) {
|
|
auto& gmInvisMsg = event.msg;
|
|
gmInvisMsg.target = event.target; // the wire message goes out with the target the event was delivered to
|
|
gmInvisMsg.bStateOut = !m_IsGMInvisible;
|
|
m_IsGMInvisible = !m_IsGMInvisible;
|
|
LOG_DEBUG("GM Invisibility toggled to: %s", m_IsGMInvisible ? "true" : "false");
|
|
gmInvisMsg.Send(UNASSIGNED_SYSTEM_ADDRESS);
|
|
auto* thisUser = UserManager::Instance()->GetUser(m_Parent->GetSystemAddress());
|
|
if (!thisUser) {
|
|
LOG("Unable to find user for entity %llu when toggling GM invisibility!", m_Parent->GetObjectID());
|
|
return false;
|
|
}
|
|
|
|
for (const auto& player : PlayerManager::GetAllPlayers()) {
|
|
if (!player || player->GetObjectID() == m_Parent->GetObjectID()) continue;
|
|
auto* toUser = UserManager::Instance()->GetUser(player->GetSystemAddress());
|
|
if (m_IsGMInvisible) {
|
|
if (toUser->GetMaxGMLevel() < thisUser->GetMaxGMLevel()) {
|
|
Game::entityManager->DestructEntity(m_Parent, player->GetSystemAddress());
|
|
}
|
|
} else {
|
|
if (toUser->GetMaxGMLevel() < thisUser->GetMaxGMLevel()) {
|
|
Game::entityManager->ConstructEntity(m_Parent, player->GetSystemAddress());
|
|
auto* controllableComp = m_Parent->GetComponent<ControllablePhysicsComponent>();
|
|
controllableComp->SetDirtyPosition(true);
|
|
}
|
|
}
|
|
}
|
|
Game::entityManager->SerializeEntity(m_Parent);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GhostComponent::OnGetGMInvis(GameMessages::GetGMInvis& gmInvisMsg) {
|
|
LOG_DEBUG("GM Invisibility requested: %s", m_IsGMInvisible ? "true" : "false");
|
|
gmInvisMsg.bGMInvis = m_IsGMInvisible;
|
|
return gmInvisMsg.bGMInvis;
|
|
}
|
|
|
|
bool GhostComponent::MsgGetObjectReportInfo(GameMessages::GetObjectReportInfo& reportMsg) {
|
|
auto& cmptType = reportMsg.info->PushDebug("Ghost");
|
|
cmptType.PushDebug<AMFIntValue>("Component ID") = GetComponentID();
|
|
cmptType.PushDebug<AMFBoolValue>("Is GM Invis") = m_IsGMInvisible;
|
|
|
|
return true;
|
|
}
|