mirror of https://github.com/AxioDL/metaforce.git
Initial work on entity introspection
This commit is contained in:
parent
bae1d7d59f
commit
0841bd4ab2
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
if (g_StateManager != nullptr) {
|
||||||
g_StateManager->SetWarping(true);
|
g_StateManager->SetWarping(true);
|
||||||
g_StateManager->SetShouldQuitGame(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 (canInspect) {
|
||||||
if (showInspectWindow) {
|
if (showInspectWindow) {
|
||||||
ShowInspectWindow(&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);
|
||||||
|
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
#pragma once
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
@ -419,5 +419,7 @@ public:
|
||||||
|
|
||||||
static void Initialize();
|
static void Initialize();
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
IMGUI_ENTITY_PROTOTYPES
|
||||||
};
|
};
|
||||||
} // namespace metaforce
|
} // namespace metaforce
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue