Add Layer info overlay

This commit is contained in:
Luke Street 2021-05-30 20:29:27 -04:00
parent f4b845484d
commit 2fc4a9c0e3
6 changed files with 82 additions and 33 deletions

View File

@ -38,6 +38,16 @@ static std::unordered_map<CAssetId, TCachedToken<CStringTable>> stringTables;
static std::string ReadUtf8String(CStringTable* tbl, int idx) { return hecl::Char16ToUTF8(tbl->GetString(idx)); }
static std::string LoadStringTable(CAssetId stringId, int idx) {
if (!stringId.IsValid()) {
return ""s;
}
if (!stringTables.contains(stringId)) {
stringTables[stringId] = g_SimplePool->GetObj(SObjectTag{SBIG('STRG'), stringId});
}
return ReadUtf8String(stringTables[stringId].GetObj(), 0);
}
static bool ContainsCaseInsensitive(std::string_view str, std::string_view val) {
return std::search(str.begin(), str.end(), val.begin(), val.end(),
[](char ch1, char ch2) { return std::toupper(ch1) == std::toupper(ch2); }) != str.end();
@ -62,10 +72,7 @@ static std::vector<std::pair<std::string, CAssetId>> ListWorlds() {
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);
worlds.emplace_back(LoadStringTable(stringId, 0), worldId);
}
return worlds;
}
@ -82,10 +89,7 @@ static std::vector<std::pair<std::string, TAreaId>> ListAreas(CAssetId worldId)
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});
areas.emplace_back(LoadStringTable(stringId, 0), TAreaId{i});
}
return areas;
}
@ -721,24 +725,28 @@ void ImGuiConsole::ShowDebugOverlay() {
if (hasPrevious) {
ImGui::Separator();
}
ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {}\n"), metaforce::CGraphics::GetFPS()));
hasPrevious = true;
ImGuiStringViewText(fmt::format(FMT_STRING("FPS: {}\n"), metaforce::CGraphics::GetFPS()));
}
if (m_inGameTime && g_GameState != nullptr) {
if (hasPrevious) {
ImGui::Separator();
}
hasPrevious = true;
double igt = g_GameState->GetTotalPlayTime();
u32 ms = u64(igt * 1000) % 1000;
auto pt = std::div(int(igt), 3600);
ImGuiStringViewText(
fmt::format(FMT_STRING("Play Time: {:02d}:{:02d}:{:02d}.{:03d}\n"), pt.quot, pt.rem / 60, pt.rem % 60, ms));
hasPrevious = true;
}
if (m_roomTimer && g_StateManager != nullptr) {
if (hasPrevious) {
ImGui::Separator();
}
hasPrevious = true;
double igt = g_GameState->GetTotalPlayTime();
if (m_currentRoom != g_StateManager->GetCurrentArea()) {
m_currentRoom = static_cast<const void*>(g_StateManager->GetCurrentArea());
@ -750,12 +758,13 @@ void ImGuiConsole::ShowDebugOverlay() {
u32 lastFrames = u32(std::round(u32(m_lastRoomTime * 60)));
ImGuiStringViewText(fmt::format(FMT_STRING("Room Time: {:7.3f} / {:5d} | Last Room:{:7.3f} / {:5d}\n"),
currentRoomTime, curFrames, m_lastRoomTime, lastFrames));
hasPrevious = true;
}
if (m_playerInfo && g_StateManager != nullptr && g_StateManager->Player() != nullptr) {
if (hasPrevious) {
ImGui::Separator();
}
hasPrevious = true;
const CPlayer& pl = g_StateManager->GetPlayer();
const zeus::CQuaternion plQ = zeus::CQuaternion(pl.GetTransform().getRotation().buildMatrix3f());
const zeus::CTransform camXf = g_StateManager->GetCameraManager()->GetCurrentCameraTransform(*g_StateManager);
@ -772,26 +781,25 @@ void ImGuiConsole::ShowDebugOverlay() {
pl.GetMomentum().x(), pl.GetMomentum().y(), pl.GetMomentum().z(), pl.GetVelocity().x(),
pl.GetVelocity().y(), pl.GetVelocity().z(), camXf.origin.x(), camXf.origin.y(), camXf.origin.z(),
zeus::radToDeg(camQ.roll()), zeus::radToDeg(camQ.pitch()), zeus::radToDeg(camQ.yaw())));
hasPrevious = true;
}
if (m_worldInfo && g_StateManager != nullptr) {
if (hasPrevious) {
ImGui::Separator();
}
TLockedToken<CStringTable> tbl =
g_SimplePool->GetObj({FOURCC('STRG'), g_StateManager->GetWorld()->IGetStringTableAssetId()});
const metaforce::TAreaId aId = g_GameState->CurrentWorldState().GetCurrentAreaId();
ImGuiStringViewText(fmt::format(FMT_STRING("World: 0x{}{}, Area: {}\n"), g_GameState->CurrentWorldAssetId(),
(tbl.IsLoaded() ? (" " + hecl::Char16ToUTF8(tbl->GetString(0))).c_str() : ""),
aId));
hasPrevious = true;
const std::string name = LoadStringTable(g_StateManager->GetWorld()->IGetStringTableAssetId(), 0);
ImGuiStringViewText(
fmt::format(FMT_STRING("World Asset ID: 0x{}, Name: {}\n"), g_GameState->CurrentWorldAssetId(), name));
}
if (m_areaInfo && g_StateManager != nullptr) {
if (hasPrevious) {
ImGui::Separator();
}
const metaforce::TAreaId aId = g_GameState->CurrentWorldState().GetCurrentAreaId();
if (g_StateManager->GetWorld() != nullptr && g_StateManager->GetWorld()->DoesAreaExist(aId)) {
if (hasPrevious) {
ImGui::Separator();
}
hasPrevious = true;
const auto& layerStates = g_GameState->CurrentWorldState().GetLayerState();
std::string layerBits;
u32 totalActive = 0;
@ -805,30 +813,51 @@ void ImGuiConsole::ShowDebugOverlay() {
}
CGameArea* pArea = g_StateManager->GetWorld()->GetArea(aId);
CAssetId stringId = pArea->IGetStringTableAssetId();
if (!stringTables.contains(stringId)) {
stringTables[stringId] = g_SimplePool->GetObj(SObjectTag{SBIG('STRG'), stringId});
ImGuiStringViewText(
fmt::format(FMT_STRING("Area Asset ID: 0x{}, Name: {}\nArea ID: {}, Active Layer bits: {}\n"),
pArea->GetAreaAssetId(), LoadStringTable(stringId, 0), pArea->GetAreaId(), layerBits));
}
}
if (m_layerInfo && g_StateManager != nullptr) {
const metaforce::TAreaId aId = g_GameState->CurrentWorldState().GetCurrentAreaId();
const auto* world = g_StateManager->GetWorld();
if (world != nullptr && world->DoesAreaExist(aId) && world->GetWorldLayers()) {
if (hasPrevious) {
ImGui::Separator();
}
ImGuiStringViewText(fmt::format(FMT_STRING("Area ID: {} Name: {}\nArea AssetId: 0x{}, Total Objects: {}\n"
"Active Layer bits: {}\n"),
pArea->GetAreaId(), ReadUtf8String(stringTables[stringId].GetObj(), 0),
pArea->GetAreaAssetId(), g_StateManager->GetAllObjectList().size(), layerBits));
hasPrevious = true;
ImGuiStringViewText("Area Layers:");
ImVec4 activeColor = ImGui::GetStyleColorVec4(ImGuiCol_Text);
ImVec4 inactiveColor = activeColor;
inactiveColor.w = 0.5f;
const CWorldLayers& layers = world->GetWorldLayers().value();
const auto& layerStates = g_GameState->CurrentWorldState().GetLayerState();
for (int i = 0; i < layerStates->GetAreaLayerCount(aId); ++i) {
ImGui::PushStyleColor(ImGuiCol_Text, layerStates->IsLayerActive(aId, i) ? activeColor : inactiveColor);
ImGuiStringViewText(" " + layers.m_names[i]);
ImGui::PopStyleColor();
}
}
}
if (m_randomStats) {
if (hasPrevious) {
ImGui::Separator();
}
hasPrevious = true;
ImGuiStringViewText(
fmt::format(FMT_STRING("CRandom16::Next calls: {}\n"), metaforce::CRandom16::GetNumNextCalls()));
hasPrevious = true;
}
if (m_resourceStats) {
if (hasPrevious) {
ImGui::Separator();
}
ImGuiStringViewText(fmt::format(FMT_STRING("Resource Objects: {}\n"), g_SimplePool->GetLiveObjects()));
hasPrevious = true;
ImGuiStringViewText(fmt::format(FMT_STRING("Resource Objects: {}\n"), g_SimplePool->GetLiveObjects()));
}
// Code -stolen- borrowed from Practice Mod
if (m_showInput && g_InputGenerator != nullptr) {
@ -837,6 +866,8 @@ void ImGuiConsole::ShowDebugOverlay() {
if (hasPrevious) {
ImGui::Separator();
}
hasPrevious = true;
ImDrawList* dl = ImGui::GetWindowDrawList();
zeus::CVector2f p = ImGui::GetCursorScreenPos();
@ -964,7 +995,6 @@ void ImGuiConsole::ShowDebugOverlay() {
}
ImGui::Dummy(zeus::CVector2f(270, 130) * scale);
hasPrevious = true;
}
}
if (ImGui::BeginPopupContextWindow()) {
@ -1024,6 +1054,9 @@ void ImGuiConsole::ShowAppMainMenuBar(bool canInspect) {
if (ImGui::MenuItem("Area Info", nullptr, &m_areaInfo)) {
m_cvarCommons.m_debugOverlayAreaInfo->fromBoolean(m_areaInfo);
}
if (ImGui::MenuItem("Layer Info", nullptr, &m_layerInfo)) {
m_cvarCommons.m_debugOverlayLayerInfo->fromBoolean(m_layerInfo);
}
if (ImGui::MenuItem("Random Stats", nullptr, &m_randomStats)) {
m_cvarCommons.m_debugOverlayShowRandomStats->fromBoolean(m_randomStats);
}

View File

@ -72,6 +72,7 @@ private:
bool m_playerInfo = m_cvarCommons.m_debugOverlayPlayerInfo->toBoolean();
bool m_worldInfo = m_cvarCommons.m_debugOverlayWorldInfo->toBoolean();
bool m_areaInfo = m_cvarCommons.m_debugOverlayAreaInfo->toBoolean();
bool m_layerInfo = m_cvarCommons.m_debugOverlayLayerInfo->toBoolean();
bool m_randomStats = m_cvarCommons.m_debugOverlayShowRandomStats->toBoolean();
bool m_resourceStats = m_cvarCommons.m_debugOverlayShowResourceStats->toBoolean();
bool m_showInput = m_cvarCommons.m_debugOverlayShowInput->toBoolean();

View File

@ -362,7 +362,7 @@ bool CWorld::CheckWorldComplete(CStateManager* mgr, TAreaId id, CAssetId mreaId)
x84_defAudioTrack = g_TweakManager->GetTweakValue(trackKey)->GetAudio().GetFileName();
}
CWorldLayers::ReadWorldLayers(r, version, x8_mlvlId);
m_worldLayers = CWorldLayers::ReadWorldLayers(r, version, x8_mlvlId);
x3c_loadToken.reset();
x40_loadBuf.reset();
@ -728,4 +728,6 @@ TAreaId CWorld::GetAreaIdForSaveId(s32 saveId) const {
return TAreaId(std::distance(x18_areas.cbegin(), iter));
}
const std::optional<CWorldLayers>& CWorld::GetWorldLayers() const { return m_worldLayers; }
} // namespace metaforce

View File

@ -21,6 +21,8 @@ class CResFactory;
class IGameArea;
class IObjectStore;
struct CWorldLayers;
class IWorld {
public:
virtual ~IWorld() = default;
@ -35,6 +37,8 @@ public:
virtual bool ICheckWorldComplete() = 0;
virtual std::string IGetDefaultAudioTrack() const = 0;
virtual int IGetAreaCount() const = 0;
// Metaforce addition
virtual const std::optional<CWorldLayers>& GetWorldLayers() const = 0;
};
struct CWorldLayers {
@ -69,6 +73,7 @@ class CDummyWorld : public IWorld {
u32 x38_bufSz;
TAreaId x3c_curAreaId = kInvalidAreaId;
// Metaforce addition
std::optional<CWorldLayers> m_worldLayers;
public:
@ -85,7 +90,7 @@ public:
bool ICheckWorldComplete() override;
std::string IGetDefaultAudioTrack() const override;
int IGetAreaCount() const override;
const std::optional<CWorldLayers>& GetWorldLayers() const;
const std::optional<CWorldLayers>& GetWorldLayers() const override;
};
class CWorld : public IWorld {
@ -160,6 +165,9 @@ private:
EEnvFxType xc4_neededFx = EEnvFxType::None;
rstl::reserved_vector<CSfxHandle, 10> xc8_globalSfxHandles;
// Metaforce addition
std::optional<CWorldLayers> m_worldLayers;
void LoadSoundGroup(int groupId, CAssetId agscId, CSoundGroupData& data);
void LoadSoundGroups();
void UnloadSoundGroups();
@ -210,6 +218,7 @@ public:
bool ICheckWorldComplete() override;
std::string IGetDefaultAudioTrack() const override;
int IGetAreaCount() const override;
const std::optional<CWorldLayers>& GetWorldLayers() const override;
static void PropogateAreaChain(CGameArea::EOcclusionState occlusionState, CGameArea* area, CWorld* world);
static constexpr CGameArea::CConstChainIterator GetAliveAreasEnd() { return CGameArea::CConstChainIterator{}; }

View File

@ -31,6 +31,7 @@ struct CVarCommons {
CVar* m_debugOverlayPlayerInfo = nullptr;
CVar* m_debugOverlayWorldInfo = nullptr;
CVar* m_debugOverlayAreaInfo = nullptr;
CVar* m_debugOverlayLayerInfo = nullptr;
CVar* m_debugOverlayShowFrameCounter = nullptr;
CVar* m_debugOverlayShowFramerate = nullptr;
CVar* m_debugOverlayShowInGameTime = nullptr;

View File

@ -35,6 +35,9 @@ CVarCommons::CVarCommons(CVarManager& manager) : m_mgr(manager) {
"debugOverlay.areaInfo"sv,
"Displays information about the current area, such as asset ID, object/layer counts, and active layer bits"sv,
false, hecl::CVar::EFlags::Game | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ReadOnly);
m_debugOverlayLayerInfo = m_mgr.findOrMakeCVar(
"debugOverlay.layerInfo"sv, "Displays information about the currently active area layers"sv, false,
hecl::CVar::EFlags::Game | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ReadOnly);
m_debugOverlayShowFrameCounter =
m_mgr.findOrMakeCVar("debugOverlay.showFrameCounter"sv, "Displays the current frame index"sv, false,
hecl::CVar::EFlags::Game | hecl::CVar::EFlags::Archive | hecl::CVar::EFlags::ReadOnly);
@ -78,4 +81,4 @@ CVarCommons::CVarCommons(CVarManager& manager) : m_mgr(manager) {
}
CVarCommons* CVarCommons::instance() { return m_instance; }
} // namespace hecl
} // namespace hecl