diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index d11a2089..cc86db75 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -140,6 +140,8 @@ Entity::Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser, Enti PlayerManager::AddPlayer(this); } + + RegisterMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, this, &Entity::OnRequestServerObjectInfo); } Entity::~Entity() { @@ -2233,3 +2235,25 @@ bool Entity::HandleMsg(GameMessages::GameMsg& msg) const { void Entity::RegisterMsg(const MessageType::Game msgId, std::function handler) { m_MsgHandlers.emplace(msgId, handler); } + +bool Entity::OnRequestServerObjectInfo(GameMessages::GameMsg& msg) { + auto& request = static_cast(msg); + + AMFArrayValue response; + + response.Insert("visible", true); + response.Insert("objectID", std::to_string(request.targetForReport)); + response.Insert("serverInfo", true); + + auto& data = *response.InsertArray("data"); + + GameMessages::GetObjectReportInfo report; + report.target = request.targetForReport; + report.bVerbose = request.bVerbose; + report.info = &data; + SEND_ENTITY_MSG(report); + + GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, GetSystemAddress()); + + return true; +} diff --git a/dGame/Entity.h b/dGame/Entity.h index 700672c3..1cec8649 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -325,6 +325,12 @@ public: bool HandleMsg(GameMessages::GameMsg& msg) const; + bool OnRequestServerObjectInfo(GameMessages::GameMsg& msg); + + void RegisterMsg(const MessageType::Game msgId, auto* self, const auto handler) { + RegisterMsg(msgId, std::bind(handler, self, std::placeholders::_1)); + } + /** * @brief The observable for player entity position updates. */ diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 718d9024..534c7bbb 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -419,7 +419,7 @@ void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) void EntityManager::SerializeEntity(Entity* entity) { if (!entity) return; - + EntityManager::SerializeEntity(*entity); } @@ -605,9 +605,22 @@ bool EntityManager::IsExcludedFromGhosting(LOT lot) { return std::find(m_GhostingExcludedLOTs.begin(), m_GhostingExcludedLOTs.end(), lot) != m_GhostingExcludedLOTs.end(); } +#ifndef _DEBUG +bool EntityManager::SendMsg(GameMessages::GameMsg& msg, std::source_location location) { + if (msg.target == LWOOBJID_EMPTY) { + LOG("Attempted to send message to empty target"); + } + bool bRet = false; + auto* entity = GetEntity(msg.target); + if (entity) bRet = entity->HandleMsg(msg); + return bRet; +} +#else bool EntityManager::SendMsg(GameMessages::GameMsg& msg) { bool bRet = false; auto* entity = GetEntity(msg.target); if (entity) bRet = entity->HandleMsg(msg); return bRet; } +#endif + diff --git a/dGame/EntityManager.h b/dGame/EntityManager.h index 831de0ca..a61d6077 100644 --- a/dGame/EntityManager.h +++ b/dGame/EntityManager.h @@ -2,6 +2,7 @@ #define ENTITYMANAGER_H #include +#include #include #include #include @@ -80,7 +81,12 @@ public: const uint32_t GetHardcoreUscoreEnemiesMultiplier() { return m_HardcoreUscoreEnemiesMultiplier; }; // Sends a message to be handled by the receiving entity + +#ifndef _DEBUG + bool SendMsg(GameMessages::GameMsg& msg, std::source_location location = std::source_location::current()); +#else bool SendMsg(GameMessages::GameMsg& msg); +#endif private: void SerializeEntities(); diff --git a/dGame/dComponents/CharacterComponent.cpp b/dGame/dComponents/CharacterComponent.cpp index c847b5fb..0ec5f234 100644 --- a/dGame/dComponents/CharacterComponent.cpp +++ b/dGame/dComponents/CharacterComponent.cpp @@ -49,19 +49,13 @@ CharacterComponent::CharacterComponent(Entity* parent, Character* character, con m_LastUpdateTimestamp = std::time(nullptr); m_SystemAddress = systemAddress; - RegisterMsg(MessageType::Game::REQUEST_SERVER_OBJECT_INFO, this, &CharacterComponent::OnRequestServerObjectInfo); + RegisterMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, this, &CharacterComponent::OnGetObjectReportInfo); } -bool CharacterComponent::OnRequestServerObjectInfo(GameMessages::GameMsg& msg) { - auto& request = static_cast(msg); - AMFArrayValue response; +bool CharacterComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) { + auto& request = static_cast(msg); - response.Insert("visible", true); - response.Insert("objectID", std::to_string(request.targetForReport)); - response.Insert("serverInfo", true); - - auto& data = *response.InsertArray("data"); - auto& cmptType = data.PushDebug("Character"); + auto& cmptType = request.info->PushDebug("Character"); cmptType.PushDebug("Component ID") = GeneralUtils::ToUnderlying(ComponentType); cmptType.PushDebug("Character's account ID") = m_Character->GetParentUser()->GetAccountID(); @@ -83,9 +77,6 @@ bool CharacterComponent::OnRequestServerObjectInfo(GameMessages::GameMsg& msg) { cmptType.PushDebug("Current Activity Type") = GeneralUtils::ToUnderlying(m_CurrentActivity); cmptType.PushDebug("Property Clone ID") = m_Character->GetPropertyCloneID(); - GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, m_Parent->GetSystemAddress()); - - LOG("Handled!"); return true; } diff --git a/dGame/dComponents/CharacterComponent.h b/dGame/dComponents/CharacterComponent.h index cb6027b5..4c1c3835 100644 --- a/dGame/dComponents/CharacterComponent.h +++ b/dGame/dComponents/CharacterComponent.h @@ -323,7 +323,7 @@ public: Character* m_Character; private: - bool OnRequestServerObjectInfo(GameMessages::GameMsg& msg); + bool OnGetObjectReportInfo(GameMessages::GameMsg& msg); /** * The map of active venture vision effects diff --git a/dGame/dComponents/FlagComponent.cpp b/dGame/dComponents/FlagComponent.cpp index 1de06d4a..b21c8227 100644 --- a/dGame/dComponents/FlagComponent.cpp +++ b/dGame/dComponents/FlagComponent.cpp @@ -6,17 +6,18 @@ #include "ePlayerFlag.h" #include "MissionComponent.h" +#include "Amf3.h" FlagComponent::FlagComponent(Entity* parent) : Component(parent) { RegisterMsg(MessageType::Game::SET_FLAG, this, &FlagComponent::OnSetFlag); RegisterMsg(MessageType::Game::GET_FLAG, this, &FlagComponent::OnGetFlag); RegisterMsg(MessageType::Game::CLEAR_SESSION_FLAGS, this, &FlagComponent::OnClearSessionFlags); RegisterMsg(MessageType::Game::SET_RETROACTIVE_FLAGS, this, &FlagComponent::OnSetRetroactiveFlags); + RegisterMsg(MessageType::Game::GET_OBJECT_REPORT_INFO, this, &FlagComponent::OnGetObjectReportInfo); } bool FlagComponent::OnSetFlag(GameMessages::GameMsg& msg) { auto& setFlag = static_cast(msg); - LOG("Set %i", setFlag.iFlagId); SetPlayerFlag(setFlag.iFlagId, setFlag.bFlag); // This is always set the first time a player loads into a world from character select @@ -30,8 +31,6 @@ bool FlagComponent::OnSetFlag(GameMessages::GameMsg& msg) { bool FlagComponent::OnGetFlag(GameMessages::GameMsg& msg) { auto& getFlag = static_cast(msg); - LOG("Get %i", getFlag.iFlagId); - getFlag.bFlag = GetPlayerFlag(getFlag.iFlagId); return true; } @@ -181,6 +180,30 @@ bool FlagComponent::OnSetRetroactiveFlags(GameMessages::GameMsg& msg) { return true; } +bool FlagComponent::OnGetObjectReportInfo(GameMessages::GameMsg& msg) { + auto& request = static_cast(msg); + + auto& cmptType = request.info->PushDebug("Player Flag"); + cmptType.PushDebug("Component ID") = GeneralUtils::ToUnderlying(ComponentType); + + auto& allFlags = cmptType.PushDebug("All flags"); + for (const auto& [id, flagChunk] : m_PlayerFlags) { + const auto base = id * 64; + auto flagChunkCopy = flagChunk; + for (int i = 0; i < 64; i++) { + if (static_cast(flagChunkCopy & 1)) { + const int32_t flagId = base + i; + std::stringstream stream; + stream << "Flag: " << flagId; + allFlags.PushDebug(stream.str().c_str()); + } + flagChunkCopy >>= 1; + } + } + + return true; +} + void FlagComponent::ClearSessionFlags(tinyxml2::XMLDocument& doc) { if (!doc.FirstChildElement("obj")) return; auto& obj = *doc.FirstChildElement("obj"); diff --git a/dGame/dComponents/FlagComponent.h b/dGame/dComponents/FlagComponent.h index b2fffc3b..8af32c9f 100644 --- a/dGame/dComponents/FlagComponent.h +++ b/dGame/dComponents/FlagComponent.h @@ -44,6 +44,9 @@ private: * missing in a previous patch. */ bool OnSetRetroactiveFlags(GameMessages::GameMsg& msg); + + bool OnGetObjectReportInfo(GameMessages::GameMsg& msg); + /** * Flags only set for the duration of a session * diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index b870e9e3..e4fc7ba5 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -23,6 +23,7 @@ class Leaderboard; class PropertySelectQueryProperty; class TradeItem; class LDFBaseData; +class AMFArrayValue; enum class eAnimationFlags : uint32_t; @@ -805,6 +806,13 @@ namespace GameMessages { struct SetRetroactiveFlags : public GameMsg { SetRetroactiveFlags() : GameMsg(MessageType::Game::SET_RETROACTIVE_FLAGS) {} }; + + struct GetObjectReportInfo : public GameMsg { + GetObjectReportInfo() : GameMsg(MessageType::Game::GET_OBJECT_REPORT_INFO) {} + + AMFArrayValue* info{}; + bool bVerbose{}; + }; }; #endif // GAMEMESSAGES_H diff --git a/dScripts/EquipmentTriggers/TrialFactionArmorServer.cpp b/dScripts/EquipmentTriggers/TrialFactionArmorServer.cpp index 99168e6d..98824220 100644 --- a/dScripts/EquipmentTriggers/TrialFactionArmorServer.cpp +++ b/dScripts/EquipmentTriggers/TrialFactionArmorServer.cpp @@ -12,6 +12,7 @@ void TrialFactionArmorServer::OnFactionTriggerItemEquipped(Entity* itemOwner, LW if (SEND_ENTITY_MSG(flag) && !flag.bFlag) { GameMessages::SetFlag setFlag{}; + setFlag.target = itemOwner->GetObjectID(); setFlag.iFlagId = ePlayerFlag::EQUPPED_TRIAL_FACTION_GEAR; setFlag.bFlag = true; SEND_ENTITY_MSG(setFlag);