diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index cc86db75..078110d0 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -97,6 +97,7 @@ #include "CDScriptComponentTable.h" #include "CDSkillBehaviorTable.h" #include "CDZoneTableTable.h" +#include "StringifiedEnum.h" #include @@ -2246,14 +2247,101 @@ bool Entity::OnRequestServerObjectInfo(GameMessages::GameMsg& msg) { response.Insert("serverInfo", true); auto& data = *response.InsertArray("data"); - + + auto& objectDetails = data.PushDebug("Object Details"); + + objectDetails.PushDebug("Name") = ""; + objectDetails.PushDebug("Template ID(LOT)") = GetLOT(); + objectDetails.PushDebug("Object ID") = std::to_string(GetObjectID()); + objectDetails.PushDebug("Type") = ""; + + if (!m_ParentEntity) { + objectDetails.PushDebug("Has a parent object") = false; + } else { + objectDetails.PushDebug("Parent's Object ID") = std::to_string(m_ParentEntity->GetObjectID()); + } + + if (!m_ChildEntities.empty()) { + if (!request.bVerbose) { + objectDetails.PushDebug("Child Objects (shown only in high-detail reports)"); + } else { + auto& childDetails = objectDetails.PushDebug("Child Objects"); + for (const auto* childObj : m_ChildEntities) { + std::stringstream stream; + stream << "Child ID: " << childObj->GetObjectID(); + childDetails.PushDebug(stream.str().c_str()) = std::to_string(childObj->GetObjectID()); + } + } + } + + if (!request.bVerbose) { + objectDetails.PushDebug("Component Information (shown only in high-detail reports)"); + objectDetails.PushDebug("Memory Usage Info (shown only in high-detail reports)"); + objectDetails.PushDebug("Registered Messages (shown only in high-detail reports)"); + } else { + auto& componentInfo = objectDetails.PushDebug("Component Information"); + for (const auto& [componentType, component] : m_Components) { + std::stringstream stream; + const auto componentName = StringifiedEnum::ToString(componentType); + stream << componentName.data() << ", Active"; + + auto& currentCompInfo = componentInfo.PushDebug(stream.str().c_str()); + currentCompInfo.PushDebug("Type ID") = GeneralUtils::ToUnderlying(componentType); + + auto& memUsageInfo = objectDetails.PushDebug("Memory Usage Info"); + memUsageInfo.PushDebug("Static size of this GameObject") = sizeof(Entity); + int staticSizeObject{}; + + objectDetails.PushDebug("Is a human player") = IsPlayer(); + + if (!m_Groups.empty() && request.bVerbose) { + auto& groupInfo = objectDetails.PushDebug("Group Info"); + for (const auto& group : m_Groups) { + groupInfo.PushDebug(group) = ""; + } + } + LWOOBJID upper32Bits = GetObjectID(); + upper32Bits >>= 32; + bool bVar2 = ((upper32Bits & 0xfc000000) == 0x4000000) && ((upper32Bits & 0xffffc000) != 0x4000000); + if (bVar2) { + objectDetails.PushDebug("Object ID Type") = "Spawned"; + } else if ((upper32Bits & 0xf8000000U) == 0) { + if ((upper32Bits & 0xffffc000U) == 0x4000000) { + objectDetails.PushDebug("Object ID Type") = "Local"; + } else if ((upper32Bits & 0xfc000000U) == 0) { + objectDetails.PushDebug("Object ID Type") = "Static"; + } + } else { + objectDetails.PushDebug("Object ID Type") = "Global"; + } + LWOOBJID spawnerId{ LWOOBJID_EMPTY }; + if (m_Spawner) { + objectDetails.PushDebug("Spawner's Object ID") = std::to_string(m_Spawner->m_Info.spawnerID); + } + + objectDetails.PushDebug("Precondition(s)"); + + objectDetails.PushDebug("Components Waiting") = 0; + + if (!request.bVerbose) { + objectDetails.PushDebug("Config Data (shown only in high-detail reports)"); + } else { + auto& configInfo = objectDetails.PushDebug("Config Data"); + for (const auto& setting : GetSettings()) { + configInfo.PushDebug(GeneralUtils::UTF16ToWTF8(setting->GetKey())) = setting->GetValueAsString(); + } + } + } + } + GameMessages::GetObjectReportInfo report; report.target = request.targetForReport; report.bVerbose = request.bVerbose; report.info = &data; SEND_ENTITY_MSG(report); - GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, GetSystemAddress()); + auto* player = Game::entityManager->GetEntity(request.clientId); + if (player) GameMessages::SendUIMessageServerToSingleClient("ToggleObjectDebugger", response, player->GetSystemAddress()); return true; } diff --git a/dGame/EntityManager.cpp b/dGame/EntityManager.cpp index 534c7bbb..e7fa9c33 100644 --- a/dGame/EntityManager.cpp +++ b/dGame/EntityManager.cpp @@ -608,7 +608,7 @@ bool EntityManager::IsExcludedFromGhosting(LOT lot) { #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"); + LOG("Attempted to send message to empty target from funcion %s:%d", location.function_name(), location.line()); } bool bRet = false; auto* entity = GetEntity(msg.target); diff --git a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp index 1cbab3bc..b57a6827 100644 --- a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp +++ b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp @@ -1528,6 +1528,13 @@ namespace DEVGMCommands { if (!closest) return; + GameMessages::RequestServerObjectInfo request{}; + request.target = closest->GetObjectID(); + request.targetForReport = closest->GetObjectID(); + request.bVerbose = true; + request.clientId = entity->GetObjectID(); + SEND_ENTITY_MSG(request); + Game::entityManager->SerializeEntity(closest); auto* table = CDClientManager::GetTable();