Initial work on entity introspection

This commit is contained in:
Luke Street 2021-05-25 22:49:24 -04:00
parent bae1d7d59f
commit 0841bd4ab2
11 changed files with 99 additions and 25 deletions

View File

@ -204,7 +204,7 @@ elseif(UNIX)
set(PLAT_LIBS rt) set(PLAT_LIBS rt)
endif() endif()
add_executable(metaforce CMain.cpp ${PLAT_SRCS} ImGuiConsole.hpp ImGuiConsole.cpp) add_executable(metaforce CMain.cpp ${PLAT_SRCS} ImGuiConsole.hpp ImGuiConsole.cpp ImGuiEntitySupport.hpp ImGuiEntitySupport.cpp)
target_link_libraries(metaforce PUBLIC RuntimeCommon ${PLAT_LIBS}) target_link_libraries(metaforce PUBLIC RuntimeCommon ${PLAT_LIBS})
if(COMMAND add_sanitizers) if(COMMAND add_sanitizers)

View File

@ -27,7 +27,7 @@ static std::wstring_convert<deletable_facet<std::codecvt<char16_t, char, std::mb
std::string readUtf8String(CStringTable* tbl, int idx) { return conv16.to_bytes(tbl->GetString(idx)); } std::string readUtf8String(CStringTable* tbl, int idx) { return conv16.to_bytes(tbl->GetString(idx)); }
static const std::vector<std::pair<std::string, CAssetId>> listWorlds() { static const std::vector<std::pair<std::string, CAssetId>> ListWorlds() {
std::vector<std::pair<std::string, CAssetId>> worlds; std::vector<std::pair<std::string, CAssetId>> worlds;
for (const auto& pak : g_ResFactory->GetResLoader()->GetPaks()) { for (const auto& pak : g_ResFactory->GetResLoader()->GetPaks()) {
if (!pak->IsWorldPak()) { if (!pak->IsWorldPak()) {
@ -54,7 +54,7 @@ static const std::vector<std::pair<std::string, CAssetId>> listWorlds() {
return worlds; return worlds;
} }
static const std::vector<std::pair<std::string, TAreaId>> listAreas(CAssetId worldId) { static const std::vector<std::pair<std::string, TAreaId>> ListAreas(CAssetId worldId) {
std::vector<std::pair<std::string, TAreaId>> areas; std::vector<std::pair<std::string, TAreaId>> areas;
const auto& world = dummyWorlds[worldId]; const auto& world = dummyWorlds[worldId];
for (int i = 0; i < world->IGetAreaCount(); ++i) { for (int i = 0; i < world->IGetAreaCount(); ++i) {
@ -74,7 +74,7 @@ static const std::vector<std::pair<std::string, TAreaId>> listAreas(CAssetId wor
return areas; return areas;
} }
static void warp(const CAssetId worldId, TAreaId aId) { static void Warp(const CAssetId worldId, TAreaId aId) {
g_GameState->SetCurrentWorldId(worldId); g_GameState->SetCurrentWorldId(worldId);
g_GameState->GetWorldTransitionManager()->DisableTransition(); g_GameState->GetWorldTransitionManager()->DisableTransition();
if (aId >= g_GameState->CurrentWorldState().GetLayerState()->GetAreaCount()) { if (aId >= g_GameState->CurrentWorldState().GetLayerState()->GetAreaCount()) {
@ -82,8 +82,12 @@ static void warp(const CAssetId worldId, TAreaId aId) {
} }
g_GameState->CurrentWorldState().SetAreaId(aId); g_GameState->CurrentWorldState().SetAreaId(aId);
g_Main->SetFlowState(EFlowState::None); g_Main->SetFlowState(EFlowState::None);
g_StateManager->SetWarping(true); if (g_StateManager != nullptr) {
g_StateManager->SetShouldQuitGame(true); g_StateManager->SetWarping(true);
g_StateManager->SetShouldQuitGame(true);
} else {
// TODO warp from menu?
}
} }
static void ShowMenuGame() { static void ShowMenuGame() {
@ -92,12 +96,13 @@ static void ShowMenuGame() {
if (ImGui::MenuItem("Paused", nullptr, &paused)) { if (ImGui::MenuItem("Paused", nullptr, &paused)) {
g_Main->SetPaused(paused); g_Main->SetPaused(paused);
} }
if (ImGui::BeginMenu("Warp", g_ResFactory != nullptr && g_ResFactory->GetResLoader() != nullptr)) { if (ImGui::BeginMenu("Warp", g_StateManager != nullptr && g_ResFactory != nullptr &&
for (const auto& world : listWorlds()) { g_ResFactory->GetResLoader() != nullptr)) {
for (const auto& world : ListWorlds()) {
if (ImGui::BeginMenu(world.first.c_str())) { if (ImGui::BeginMenu(world.first.c_str())) {
for (const auto& area : listAreas(world.second)) { for (const auto& area : ListAreas(world.second)) {
if (ImGui::MenuItem(area.first.c_str())) { if (ImGui::MenuItem(area.first.c_str())) {
warp(world.second, area.second); Warp(world.second, area.second);
} }
} }
ImGui::EndMenu(); ImGui::EndMenu();
@ -112,13 +117,14 @@ static void ShowMenuGame() {
static void ShowInspectWindow(bool* isOpen) { static void ShowInspectWindow(bool* isOpen) {
if (ImGui::Begin("Inspect", isOpen)) { if (ImGui::Begin("Inspect", isOpen)) {
if (ImGui::BeginTable("Entities", 3, if (ImGui::BeginTable("Entities", 4,
ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_RowBg |
ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ScrollY)) { ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ScrollY)) {
ImGui::TableSetupColumn("ID", ImGui::TableSetupColumn("ID",
ImGuiTableColumnFlags_PreferSortAscending | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_PreferSortAscending | ImGuiTableColumnFlags_DefaultSort |
ImGuiTableColumnFlags_WidthFixed, ImGuiTableColumnFlags_WidthFixed,
0, 'id'); 0, 'id');
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 0, 'type');
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0, 'name'); ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0, 'name');
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupScrollFreeze(0, 1); ImGui::TableSetupScrollFreeze(0, 1);
@ -143,6 +149,11 @@ static void ShowInspectWindow(bool* isOpen) {
int compare = a->GetName().compare(b->GetName()); int compare = a->GetName().compare(b->GetName());
return specs.SortDirection == ImGuiSortDirection_Ascending ? compare < 0 : compare > 0; return specs.SortDirection == ImGuiSortDirection_Ascending ? compare < 0 : compare > 0;
}); });
} else if (specs.ColumnUserID == 'type') {
std::sort(items.begin(), items.end(), [&](CEntity* a, CEntity* b) {
int compare = a->ImGuiType().compare(b->ImGuiType());
return specs.SortDirection == ImGuiSortDirection_Ascending ? compare < 0 : compare > 0;
});
} }
} }
} }
@ -153,6 +164,9 @@ static void ShowInspectWindow(bool* isOpen) {
if (ImGui::TableNextColumn()) { if (ImGui::TableNextColumn()) {
ImGui::Text("%x", uid.Value()); ImGui::Text("%x", uid.Value());
} }
if (ImGui::TableNextColumn()) {
ImGui::Text("%s", item->ImGuiType().data());
}
if (ImGui::TableNextColumn()) { if (ImGui::TableNextColumn()) {
ImGui::Text("%s", item->GetName().data()); ImGui::Text("%s", item->GetName().data());
} }
@ -177,12 +191,7 @@ static bool showEntityInfoWindow(TUniqueId uid) {
} }
auto name = fmt::format(FMT_STRING("{}##{:x}"), !ent->GetName().empty() ? ent->GetName() : "Entity", uid.Value()); auto name = fmt::format(FMT_STRING("{}##{:x}"), !ent->GetName().empty() ? ent->GetName() : "Entity", uid.Value());
if (ImGui::Begin(name.c_str(), &open, ImGuiWindowFlags_AlwaysAutoResize)) { if (ImGui::Begin(name.c_str(), &open, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("ID: %x", uid.Value()); ent->ImGuiInspect();
ImGui::Text("Name: %s", ent->GetName().data());
if (const TCastToPtr<CActor> act = ent) {
const zeus::CVector3f& pos = act->GetTranslation();
ImGui::Text("Position: %f, %f, %f", pos.x(), pos.y(), pos.z());
}
} }
ImGui::End(); ImGui::End();
return open; return open;
@ -191,6 +200,7 @@ static bool showEntityInfoWindow(TUniqueId uid) {
static void ShowAppMainMenuBar() { static void ShowAppMainMenuBar() {
static bool showInspectWindow = false; static bool showInspectWindow = false;
static bool showDemoWindow = false; static bool showDemoWindow = false;
bool canInspect = g_StateManager != nullptr && g_StateManager->GetObjectList();
if (ImGui::BeginMainMenuBar()) { if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("Game")) { if (ImGui::BeginMenu("Game")) {
ShowMenuGame(); ShowMenuGame();
@ -198,18 +208,17 @@ static void ShowAppMainMenuBar() {
} }
ImGui::Spacing(); ImGui::Spacing();
if (ImGui::BeginMenu("Tools")) { if (ImGui::BeginMenu("Tools")) {
ImGui::MenuItem("Inspect", nullptr, &showInspectWindow, ImGui::MenuItem("Inspect", nullptr, &showInspectWindow, canInspect);
g_StateManager != nullptr && g_StateManager->GetObjectList());
ImGui::Separator(); ImGui::Separator();
ImGui::MenuItem("Demo", nullptr, &showDemoWindow); ImGui::MenuItem("Demo", nullptr, &showDemoWindow);
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::EndMainMenuBar(); ImGui::EndMainMenuBar();
} }
if (showInspectWindow) { if (canInspect) {
ShowInspectWindow(&showInspectWindow); if (showInspectWindow) {
} ShowInspectWindow(&showInspectWindow);
{ }
auto iter = inspectingEntities.begin(); auto iter = inspectingEntities.begin();
while (iter != inspectingEntities.end()) { while (iter != inspectingEntities.end()) {
if (!showEntityInfoWindow(*iter)) { if (!showEntityInfoWindow(*iter)) {
@ -218,6 +227,8 @@ static void ShowAppMainMenuBar() {
iter++; iter++;
} }
} }
} else {
inspectingEntities.clear();
} }
if (showDemoWindow) { if (showDemoWindow) {
ImGui::ShowDemoWindow(&showDemoWindow); ImGui::ShowDemoWindow(&showDemoWindow);
@ -230,4 +241,4 @@ ImGuiConsole::~ImGuiConsole() {
dummyWorlds.clear(); dummyWorlds.clear();
stringTables.clear(); stringTables.clear();
} }
} // namespace metaforce } // namespace metaforce

View File

@ -0,0 +1,36 @@
#include "Runtime/World/CEntity.hpp"
#include "Runtime/World/CActor.hpp"
#include "Runtime/World/CAi.hpp"
#include "Runtime/World/CPatterned.hpp"
#include "Runtime/World/CPlayer.hpp"
#include "imgui.h"
#define IMGUI_ENTITY_INSPECT(CLS, PARENT, NAME, BLOCK) \
std::string_view CLS::ImGuiType() { return #NAME; } \
void CLS::ImGuiInspect() { \
PARENT::ImGuiInspect(); \
if (ImGui::CollapsingHeader(#NAME)) \
BLOCK \
}
namespace metaforce {
std::string_view CEntity::ImGuiType() { return "Entity"; }
void CEntity::ImGuiInspect() {
if (ImGui::CollapsingHeader("Entity", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::Text("ID: %x", x8_uid.Value());
ImGui::Text("Name: %s", x10_name.c_str());
}
}
IMGUI_ENTITY_INSPECT(CActor, CEntity, Actor, {
const zeus::CVector3f& pos = GetTranslation();
ImGui::Text("Position: %f, %f, %f", pos.x(), pos.y(), pos.z());
})
IMGUI_ENTITY_INSPECT(CPhysicsActor, CActor, Physics Actor, {})
IMGUI_ENTITY_INSPECT(CAi, CPhysicsActor, AI, {})
IMGUI_ENTITY_INSPECT(CPatterned, CAi, Patterned, {})
IMGUI_ENTITY_INSPECT(CPlayer, CPhysicsActor, Player, {})
} // namespace metaforce

View File

@ -0,0 +1 @@
#pragma once

View File

@ -195,5 +195,7 @@ public:
void MoveScannableObjectInfoToActor(CActor*, CStateManager&); void MoveScannableObjectInfoToActor(CActor*, CStateManager&);
const zeus::CAABox& GetRenderBounds() const { return x9c_renderBounds; } const zeus::CAABox& GetRenderBounds() const { return x9c_renderBounds; }
void SetNotInSortedLists(bool notIn) { xe4_27_notInSortedLists = notIn; } void SetNotInSortedLists(bool notIn) { xe4_27_notInSortedLists = notIn; }
IMGUI_ENTITY_PROTOTYPES
}; };
} // namespace metaforce } // namespace metaforce

View File

@ -185,6 +185,8 @@ public:
virtual bool FixedRandom(CStateManager&, float) { return false; } virtual bool FixedRandom(CStateManager&, float) { return false; }
virtual bool IsDizzy(CStateManager&, float) { return false; } virtual bool IsDizzy(CStateManager&, float) { return false; }
virtual bool ShouldCallForBackup(CStateManager&, float) { return false; } virtual bool ShouldCallForBackup(CStateManager&, float) { return false; }
IMGUI_ENTITY_PROTOTYPES
}; };
} // namespace metaforce } // namespace metaforce

View File

@ -7,6 +7,18 @@
#include "Runtime/World/CEntityInfo.hpp" #include "Runtime/World/CEntityInfo.hpp"
#include "Runtime/World/ScriptObjectSupport.hpp" #include "Runtime/World/ScriptObjectSupport.hpp"
#ifndef ENABLE_IMGUI
#define ENABLE_IMGUI 1
#endif
#if ENABLE_IMGUI
#define IMGUI_ENTITY_PROTOTYPES \
std::string_view ImGuiType() override; \
void ImGuiInspect() override;
#else
#define IMGUI_ENTITY_PROTOTYPES
#endif
namespace metaforce { namespace metaforce {
class CStateManager; class CStateManager;
class IVisitor; class IVisitor;
@ -36,6 +48,10 @@ public:
virtual void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr); virtual void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr);
virtual void SetActive(bool active) { x30_24_active = active; } virtual void SetActive(bool active) { x30_24_active = active; }
// Debugging utilities
virtual std::string_view ImGuiType();
virtual void ImGuiInspect();
bool GetActive() const { return x30_24_active; } bool GetActive() const { return x30_24_active; }
void ToggleActive() { x30_24_active ^= 1; } void ToggleActive() { x30_24_active ^= 1; }

View File

@ -419,5 +419,7 @@ public:
static void Initialize(); static void Initialize();
// endregion // endregion
IMGUI_ENTITY_PROTOTYPES
}; };
} // namespace metaforce } // namespace metaforce

View File

@ -208,5 +208,7 @@ public:
void UseCollisionImpulses(); void UseCollisionImpulses();
static constexpr float GravityConstant() { return 9.81f * 2.5f; } /* 9.81 m/s ^ 2 is normal acceleration under earth gravity, Tallon 4 is 2.5 times that */ static constexpr float GravityConstant() { return 9.81f * 2.5f; } /* 9.81 m/s ^ 2 is normal acceleration under earth gravity, Tallon 4 is 2.5 times that */
IMGUI_ENTITY_PROTOTYPES
}; };
} // namespace metaforce } // namespace metaforce

View File

@ -1272,7 +1272,7 @@ static CAssetId UpdatePersistentScanPercent(u32 prevLogScans, u32 logScans, u32
if (scanPercentProgStep > prevScanPercentProgStep) { if (scanPercentProgStep > prevScanPercentProgStep) {
const char* const messageResBase = UnlockMessageResBases[zeus::clamp(0, scanPercentProgStep - 1, 1)]; const char* const messageResBase = UnlockMessageResBases[zeus::clamp(0, scanPercentProgStep - 1, 1)];
const auto message = std::string(messageResBase).append(1, firstTime ? '1' : '2'); const auto message = std::string(messageResBase).append(1, firstTime ? '1' : '2');
const auto* const id = g_ResFactory->GetResourceIdByName(message); const auto* const id = g_ResFactory->GetResourceIdByName(message);
if (id != nullptr) { if (id != nullptr) {
return id->id; return id->id;

View File

@ -622,5 +622,7 @@ public:
bool IsInWaterMovement() const { return x9c4_31_inWaterMovement; } bool IsInWaterMovement() const { return x9c4_31_inWaterMovement; }
void SetNoDamageLoopSfx(bool val) { x9c7_24_noDamageLoopSfx = val; } void SetNoDamageLoopSfx(bool val) { x9c7_24_noDamageLoopSfx = val; }
void SetAccelerationChangeTimer(float time) { x2d4_accelerationChangeTimer = time; } void SetAccelerationChangeTimer(float time) { x2d4_accelerationChangeTimer = time; }
IMGUI_ENTITY_PROTOTYPES
}; };
} // namespace metaforce } // namespace metaforce