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)
|
||||
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})
|
||||
|
||||
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)); }
|
||||
|
||||
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;
|
||||
for (const auto& pak : g_ResFactory->GetResLoader()->GetPaks()) {
|
||||
if (!pak->IsWorldPak()) {
|
||||
|
@ -54,7 +54,7 @@ static const std::vector<std::pair<std::string, CAssetId>> listWorlds() {
|
|||
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;
|
||||
const auto& world = dummyWorlds[worldId];
|
||||
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;
|
||||
}
|
||||
|
||||
static void warp(const CAssetId worldId, TAreaId aId) {
|
||||
static void Warp(const CAssetId worldId, TAreaId aId) {
|
||||
g_GameState->SetCurrentWorldId(worldId);
|
||||
g_GameState->GetWorldTransitionManager()->DisableTransition();
|
||||
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_Main->SetFlowState(EFlowState::None);
|
||||
g_StateManager->SetWarping(true);
|
||||
g_StateManager->SetShouldQuitGame(true);
|
||||
if (g_StateManager != nullptr) {
|
||||
g_StateManager->SetWarping(true);
|
||||
g_StateManager->SetShouldQuitGame(true);
|
||||
} else {
|
||||
// TODO warp from menu?
|
||||
}
|
||||
}
|
||||
|
||||
static void ShowMenuGame() {
|
||||
|
@ -92,12 +96,13 @@ static void ShowMenuGame() {
|
|||
if (ImGui::MenuItem("Paused", nullptr, &paused)) {
|
||||
g_Main->SetPaused(paused);
|
||||
}
|
||||
if (ImGui::BeginMenu("Warp", g_ResFactory != nullptr && g_ResFactory->GetResLoader() != nullptr)) {
|
||||
for (const auto& world : listWorlds()) {
|
||||
if (ImGui::BeginMenu("Warp", g_StateManager != nullptr && g_ResFactory != nullptr &&
|
||||
g_ResFactory->GetResLoader() != nullptr)) {
|
||||
for (const auto& world : ListWorlds()) {
|
||||
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())) {
|
||||
warp(world.second, area.second);
|
||||
Warp(world.second, area.second);
|
||||
}
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
|
@ -112,13 +117,14 @@ static void ShowMenuGame() {
|
|||
|
||||
static void ShowInspectWindow(bool* isOpen) {
|
||||
if (ImGui::Begin("Inspect", isOpen)) {
|
||||
if (ImGui::BeginTable("Entities", 3,
|
||||
if (ImGui::BeginTable("Entities", 4,
|
||||
ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_RowBg |
|
||||
ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ScrollY)) {
|
||||
ImGui::TableSetupColumn("ID",
|
||||
ImGuiTableColumnFlags_PreferSortAscending | ImGuiTableColumnFlags_DefaultSort |
|
||||
ImGuiTableColumnFlags_WidthFixed,
|
||||
0, 'id');
|
||||
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 0, 'type');
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0, 'name');
|
||||
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
|
@ -143,6 +149,11 @@ static void ShowInspectWindow(bool* isOpen) {
|
|||
int compare = a->GetName().compare(b->GetName());
|
||||
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()) {
|
||||
ImGui::Text("%x", uid.Value());
|
||||
}
|
||||
if (ImGui::TableNextColumn()) {
|
||||
ImGui::Text("%s", item->ImGuiType().data());
|
||||
}
|
||||
if (ImGui::TableNextColumn()) {
|
||||
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());
|
||||
if (ImGui::Begin(name.c_str(), &open, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text("ID: %x", uid.Value());
|
||||
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());
|
||||
}
|
||||
ent->ImGuiInspect();
|
||||
}
|
||||
ImGui::End();
|
||||
return open;
|
||||
|
@ -191,6 +200,7 @@ static bool showEntityInfoWindow(TUniqueId uid) {
|
|||
static void ShowAppMainMenuBar() {
|
||||
static bool showInspectWindow = false;
|
||||
static bool showDemoWindow = false;
|
||||
bool canInspect = g_StateManager != nullptr && g_StateManager->GetObjectList();
|
||||
if (ImGui::BeginMainMenuBar()) {
|
||||
if (ImGui::BeginMenu("Game")) {
|
||||
ShowMenuGame();
|
||||
|
@ -198,18 +208,17 @@ static void ShowAppMainMenuBar() {
|
|||
}
|
||||
ImGui::Spacing();
|
||||
if (ImGui::BeginMenu("Tools")) {
|
||||
ImGui::MenuItem("Inspect", nullptr, &showInspectWindow,
|
||||
g_StateManager != nullptr && g_StateManager->GetObjectList());
|
||||
ImGui::MenuItem("Inspect", nullptr, &showInspectWindow, canInspect);
|
||||
ImGui::Separator();
|
||||
ImGui::MenuItem("Demo", nullptr, &showDemoWindow);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMainMenuBar();
|
||||
}
|
||||
if (showInspectWindow) {
|
||||
ShowInspectWindow(&showInspectWindow);
|
||||
}
|
||||
{
|
||||
if (canInspect) {
|
||||
if (showInspectWindow) {
|
||||
ShowInspectWindow(&showInspectWindow);
|
||||
}
|
||||
auto iter = inspectingEntities.begin();
|
||||
while (iter != inspectingEntities.end()) {
|
||||
if (!showEntityInfoWindow(*iter)) {
|
||||
|
@ -218,6 +227,8 @@ static void ShowAppMainMenuBar() {
|
|||
iter++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
inspectingEntities.clear();
|
||||
}
|
||||
if (showDemoWindow) {
|
||||
ImGui::ShowDemoWindow(&showDemoWindow);
|
||||
|
@ -230,4 +241,4 @@ ImGuiConsole::~ImGuiConsole() {
|
|||
dummyWorlds.clear();
|
||||
stringTables.clear();
|
||||
}
|
||||
} // namespace metaforce
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -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&);
|
||||
const zeus::CAABox& GetRenderBounds() const { return x9c_renderBounds; }
|
||||
void SetNotInSortedLists(bool notIn) { xe4_27_notInSortedLists = notIn; }
|
||||
|
||||
IMGUI_ENTITY_PROTOTYPES
|
||||
};
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -185,6 +185,8 @@ public:
|
|||
virtual bool FixedRandom(CStateManager&, float) { return false; }
|
||||
virtual bool IsDizzy(CStateManager&, float) { return false; }
|
||||
virtual bool ShouldCallForBackup(CStateManager&, float) { return false; }
|
||||
|
||||
IMGUI_ENTITY_PROTOTYPES
|
||||
};
|
||||
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -7,6 +7,18 @@
|
|||
#include "Runtime/World/CEntityInfo.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 {
|
||||
class CStateManager;
|
||||
class IVisitor;
|
||||
|
@ -36,6 +48,10 @@ public:
|
|||
virtual void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr);
|
||||
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; }
|
||||
void ToggleActive() { x30_24_active ^= 1; }
|
||||
|
||||
|
|
|
@ -419,5 +419,7 @@ public:
|
|||
|
||||
static void Initialize();
|
||||
// endregion
|
||||
|
||||
IMGUI_ENTITY_PROTOTYPES
|
||||
};
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -208,5 +208,7 @@ public:
|
|||
|
||||
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 */
|
||||
|
||||
IMGUI_ENTITY_PROTOTYPES
|
||||
};
|
||||
} // namespace metaforce
|
||||
|
|
|
@ -1272,7 +1272,7 @@ static CAssetId UpdatePersistentScanPercent(u32 prevLogScans, u32 logScans, u32
|
|||
|
||||
if (scanPercentProgStep > prevScanPercentProgStep) {
|
||||
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);
|
||||
if (id != nullptr) {
|
||||
return id->id;
|
||||
|
|
|
@ -622,5 +622,7 @@ public:
|
|||
bool IsInWaterMovement() const { return x9c4_31_inWaterMovement; }
|
||||
void SetNoDamageLoopSfx(bool val) { x9c7_24_noDamageLoopSfx = val; }
|
||||
void SetAccelerationChangeTimer(float time) { x2d4_accelerationChangeTimer = time; }
|
||||
|
||||
IMGUI_ENTITY_PROTOTYPES
|
||||
};
|
||||
} // namespace metaforce
|
||||
|
|
Loading…
Reference in New Issue