From 6da000e33211353359c37cae59041eb10965c61f Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 25 May 2021 15:58:18 -0400 Subject: [PATCH] Add Warp menu --- Runtime/ImGuiConsole.cpp | 92 ++++++++++++++++++++++++++++++++++++++++ Runtime/ImGuiConsole.hpp | 3 +- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/Runtime/ImGuiConsole.cpp b/Runtime/ImGuiConsole.cpp index a33ba9ab5..86e06ef60 100644 --- a/Runtime/ImGuiConsole.cpp +++ b/Runtime/ImGuiConsole.cpp @@ -12,12 +12,99 @@ namespace metaforce { static std::set inspectingEntities; +static std::unordered_map> dummyWorlds; +static std::unordered_map> stringTables; + +// utility wrapper to adapt locale-bound facets for wstring/wbuffer convert +template +struct deletable_facet : Facet { + template + deletable_facet(Args&&... args) : Facet(std::forward(args)...) {} + ~deletable_facet() {} +}; + +static std::wstring_convert>, char16_t> conv16; + +std::string readUtf8String(CStringTable* tbl, int idx) { return conv16.to_bytes(tbl->GetString(idx)); } + +static const std::vector> listWorlds() { + std::vector> worlds; + for (const auto& pak : g_ResFactory->GetResLoader()->GetPaks()) { + if (!pak->IsWorldPak()) { + continue; + } + CAssetId worldId = pak->GetMLVLId(); + if (!dummyWorlds.contains(worldId)) { + dummyWorlds[worldId] = std::make_unique(worldId, false); + } + auto& world = dummyWorlds[worldId]; + bool complete = world->ICheckWorldComplete(); + if (!complete) { + continue; + } + CAssetId stringId = world->IGetStringTableAssetId(); + if (!stringId.IsValid()) { + continue; + } + if (!stringTables.contains(stringId)) { + stringTables[stringId] = g_SimplePool->GetObj(SObjectTag{SBIG('STRG'), stringId}); + } + worlds.emplace_back(readUtf8String(stringTables[stringId].GetObj(), 0), worldId); + } + return worlds; +} + +static const std::vector> listAreas(CAssetId worldId) { + std::vector> areas; + const auto& world = dummyWorlds[worldId]; + for (int i = 0; i < world->IGetAreaCount(); ++i) { + const auto* area = world->IGetAreaAlways(i); + if (area == nullptr) { + continue; + } + CAssetId stringId = area->IGetStringTableAssetId(); + if (!stringId.IsValid()) { + continue; + } + if (!stringTables.contains(stringId)) { + stringTables[stringId] = g_SimplePool->GetObj(SObjectTag{SBIG('STRG'), stringId}); + } + areas.emplace_back(readUtf8String(stringTables[stringId].GetObj(), 0), TAreaId{i}); + } + return areas; +} + +static void warp(const CAssetId worldId, TAreaId aId) { + g_GameState->SetCurrentWorldId(worldId); + g_GameState->GetWorldTransitionManager()->DisableTransition(); + if (aId >= g_GameState->CurrentWorldState().GetLayerState()->GetAreaCount()) { + aId = 0; + } + g_GameState->CurrentWorldState().SetAreaId(aId); + g_Main->SetFlowState(EFlowState::None); + g_StateManager->SetWarping(true); + g_StateManager->SetShouldQuitGame(true); +} + static void ShowMenuGame() { static bool paused; paused = g_Main->IsPaused(); 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(world.first.c_str())) { + for (const auto& area : listAreas(world.second)) { + if (ImGui::MenuItem(area.first.c_str())) { + warp(world.second, area.second); + } + } + ImGui::EndMenu(); + } + } + ImGui::EndMenu(); + } if (ImGui::MenuItem("Quit", "Alt+F4")) { g_Main->Quit(); } @@ -138,4 +225,9 @@ static void ShowAppMainMenuBar() { } void ImGuiConsole::proc() { ShowAppMainMenuBar(); } + +ImGuiConsole::~ImGuiConsole() { + dummyWorlds.clear(); + stringTables.clear(); +} } // namespace metaforce \ No newline at end of file diff --git a/Runtime/ImGuiConsole.hpp b/Runtime/ImGuiConsole.hpp index 0c2e61eeb..3800de081 100644 --- a/Runtime/ImGuiConsole.hpp +++ b/Runtime/ImGuiConsole.hpp @@ -3,6 +3,7 @@ namespace metaforce { class ImGuiConsole { public: + ~ImGuiConsole(); void proc(); }; -} +} // namespace metaforce