diff options
| author | Garrett Cox <garrettjcox@gmail.com> | 2024-04-28 19:27:28 -0500 |
|---|---|---|
| committer | Garrett Cox <garrettjcox@gmail.com> | 2024-05-22 09:05:02 -0500 |
| commit | 16e4ccf9af84d2e4160f0e8ad55d235ef496e068 (patch) | |
| tree | b0a4964198322c10d21e19ae5bfe9c58e690ba2c /mm/2s2h/DeveloperTools/EventLog.cpp | |
| parent | 0da645e7e63f1c76de2dbee56574c3e2753ed467 (diff) | |
Add Event Log and more hooks (#247)
Diffstat (limited to 'mm/2s2h/DeveloperTools/EventLog.cpp')
| -rw-r--r-- | mm/2s2h/DeveloperTools/EventLog.cpp | 400 |
1 files changed, 400 insertions, 0 deletions
diff --git a/mm/2s2h/DeveloperTools/EventLog.cpp b/mm/2s2h/DeveloperTools/EventLog.cpp new file mode 100644 index 000000000..a1871307e --- /dev/null +++ b/mm/2s2h/DeveloperTools/EventLog.cpp @@ -0,0 +1,400 @@ +#include "EventLog.h" + +#include <iostream> +#include <iomanip> +#include <ctime> +#include <sstream> + +#include "2s2h/BenGui/UIWidgets.hpp" +#include "2s2h/Enhancements/GameInteractor/GameInteractor.h" + +extern "C" { +#include <z64.h> +} + +typedef enum { + EVENT_LOG_ENTRY_TYPE_FLAG_SET, + EVENT_LOG_ENTRY_TYPE_FLAG_UNSET, + EVENT_LOG_ENTRY_TYPE_SCENE_FLAG_SET, + EVENT_LOG_ENTRY_TYPE_SCENE_FLAG_UNSET, + EVENT_LOG_ENTRY_TYPE_ACTOR_INIT, + EVENT_LOG_ENTRY_TYPE_ACTOR_KILL, + EVENT_LOG_ENTRY_TYPE_SCENE_INIT, + EVENT_LOG_ENTRY_TYPE_ROOM_INIT, + EVENT_LOG_ENTRY_TYPE_OPEN_TEXT, + EVENT_LOG_ENTRY_TYPE_ITEM_GIVE, +} EventLogEntryType; + +const char* eventLogEntryTypeNames[] = { + "FlagSet", + "FlagUnset", + "SceneFlagSet", + "SceneFlagUnset", + "ActorInit", + "ActorKill", + "SceneInit", + "RoomInit", + "OpenText", + "ItemGive", +}; + +struct EventLogEntry { + std::string timestamp; + EventLogEntryType type; + std::string meta; +}; + +std::vector<EventLogEntry> eventLogEntries; + +const char* flagTypeNames[] = { + "", + "weekEventReg", + "eventInf", + "scenesVisible", + "owlActivation", + "chest", + "switch", + "clearedRoom", + "collectible", + "unk_14", + "rooms", + "chest *", + "switch *", + "clearedRoom *", + "collectible *", +}; + +#define DEFINE_ACTOR(name, _enumValue, _allocType, _debugName, _humanName) {_enumValue, _debugName}, +#define DEFINE_ACTOR_INTERNAL(_name, _enumValue, _allocType, _debugName, _humanName) {_enumValue, _debugName}, +#define DEFINE_ACTOR_UNSET(_enumValue) {_enumValue, "Unset"}, + +std::unordered_map<s16, const char*> actorNames = { +#include "tables/actor_table.h" +}; + +#undef DEFINE_ACTOR +#undef DEFINE_ACTOR_INTERNAL +#undef DEFINE_ACTOR_UNSET + +// 2S2H Added columns to scene table: entranceSceneId, betterMapSelectIndex, humanName +#define DEFINE_SCENE(_name, enumValue, _textId, _drawConfig, _restrictionFlags, _persistentCycleFlags, _entranceSceneId, _betterMapSelectIndex, humanName) \ + { enumValue, humanName }, +#define DEFINE_SCENE_UNSET(_enumValue) + +std::unordered_map<s16, const char*> sceneNames = { +#include "tables/scene_table.h" +}; + +#undef DEFINE_SCENE +#undef DEFINE_SCENE_UNSET + +static HOOK_ID onFlagSetHookId = 0; +static HOOK_ID onFlagUnsetHookId = 0; +static HOOK_ID onSceneFlagSetHookId = 0; +static HOOK_ID onSceneFlagUnsetHookId = 0; +static HOOK_ID onActorInitHookId = 0; +static HOOK_ID onActorKillHookId = 0; +static HOOK_ID onSceneInitHookId = 0; +static HOOK_ID onRoomInitHookId = 0; +static HOOK_ID onOpenTextHookId = 0; +static HOOK_ID onItemGiveHookId = 0; + +std::string CurrentTime() { + auto t = std::time(nullptr); + auto tm = *std::localtime(&t); + + std::ostringstream oss; + oss << std::put_time(&tm, "%I:%M:%S"); + return oss.str(); +} + +void TrimEventLog() { + while (eventLogEntries.size() > CVarGetInteger("gEventLog.MaxEntries", 1000)) { + eventLogEntries.pop_back(); + } +} + +void RegisterEventLogHooks() { + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnFlagSet>(onFlagSetHookId); + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnFlagUnset>(onFlagUnsetHookId); + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnSceneFlagSet>(onSceneFlagSetHookId); + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnSceneFlagUnset>(onSceneFlagUnsetHookId); + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorInit>(onActorInitHookId); + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnActorKill>(onActorKillHookId); + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnSceneInit>(onSceneInitHookId); + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnRoomInit>(onRoomInitHookId); + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnOpenText>(onOpenTextHookId); + GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnItemGive>(onItemGiveHookId); + onFlagSetHookId = 0; + onFlagUnsetHookId = 0; + onSceneFlagSetHookId = 0; + onSceneFlagUnsetHookId = 0; + onActorInitHookId = 0; + onActorKillHookId = 0; + onSceneInitHookId = 0; + onRoomInitHookId = 0; + onOpenTextHookId = 0; + onItemGiveHookId = 0; + + if (!CVarGetInteger("gEventLog.Enabled", 0)) { + return; + } + + onFlagSetHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagSet>([](FlagType type, u32 flag) { + if (type == FlagType::FLAG_WEEK_EVENT_REG) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_FLAG_SET, + .meta = fmt::format("WEEKEVENTREG_{:02d}_{:02x}", flag >> 8, flag & 0xFF), + }); + } else if (type == FlagType::FLAG_EVENT_INF) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_FLAG_SET, + .meta = fmt::format("EVENTINF_{:02x}", flag), + }); + } else { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_FLAG_SET, + .meta = fmt::format("{}({:02d}) {:02x}", flagTypeNames[type], flag >> 8, flag & 0xFF), + }); + } + TrimEventLog(); + }); + + onFlagUnsetHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnFlagUnset>([](FlagType type, u32 flag) { + if (type == FlagType::FLAG_WEEK_EVENT_REG) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_FLAG_UNSET, + .meta = fmt::format("WEEKEVENTREG_{:02d}_{:02x}", flag >> 8, flag & 0xFF), + }); + } else if (type == FlagType::FLAG_EVENT_INF) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_FLAG_UNSET, + .meta = fmt::format("EVENTINF_{:02x}", flag), + }); + } else { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_FLAG_UNSET, + .meta = fmt::format("{}({:02d}) {:02x}", flagTypeNames[type], flag >> 8, flag & 0xFF), + }); + } + TrimEventLog(); + }); + + onSceneFlagSetHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneFlagSet>([](s16 sceneId, FlagType type, u32 flag) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_SCENE_FLAG_SET, + .meta = fmt::format("{}({:02d}) {:02x}", flagTypeNames[type], flag >> 8, flag & 0xFF), + }); + TrimEventLog(); + }); + + onSceneFlagUnsetHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneFlagUnset>([](s16 sceneId, FlagType type, u32 flag) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_SCENE_FLAG_UNSET, + .meta = fmt::format("{}[{:02d}] {:02x}", flagTypeNames[type], flag >> 8, flag & 0xFF), + }); + TrimEventLog(); + }); + + onActorInitHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorInit>([](Actor* actor) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_ACTOR_INIT, + .meta = fmt::format("{} {}", actorNames[actor->id], actor->params), + }); + TrimEventLog(); + }); + + onActorKillHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnActorKill>([](Actor* actor) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_ACTOR_KILL, + .meta = fmt::format("{} {}", actorNames[actor->id], actor->params), + }); + TrimEventLog(); + }); + + onSceneInitHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnSceneInit>([](s16 sceneId, s8 spawnNum) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_SCENE_INIT, + .meta = fmt::format("{} {}", sceneNames[sceneId], spawnNum), + }); + TrimEventLog(); + }); + + onRoomInitHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnRoomInit>([](s16 sceneId, s8 roomId) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_ROOM_INIT, + .meta = fmt::format("{} {}", sceneNames[sceneId], roomId), + }); + TrimEventLog(); + }); + + onOpenTextHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnOpenText>([](s16 textId) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_OPEN_TEXT, + .meta = fmt::format("0x{:02x}", textId), + }); + TrimEventLog(); + }); + + onItemGiveHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemGive>([](u8 item) { + eventLogEntries.insert(eventLogEntries.begin(), { + .timestamp = CurrentTime(), + .type = EVENT_LOG_ENTRY_TYPE_ITEM_GIVE, + .meta = fmt::format("0x{:02x}", item), + }); + TrimEventLog(); + }); +} + +void EventLogWindow::DrawElement() { + ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("Event Log", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) { + ImGui::End(); + return; + } + + if (UIWidgets::CVarCheckbox("Enable", "gEventLog.Enabled")) { + RegisterEventLogHooks(); + } + + ImGui::SameLine(); + + if (UIWidgets::Button("Filters", { .size = UIWidgets::Sizes::Inline })) { + ImGui::OpenPopup("eventLogFiltersPopup"); + } + + if (ImGui::BeginPopup("eventLogFiltersPopup")) { + bool allChecked = + CVarGetInteger("gEventLog.Filter.FlagSet", 1) && + CVarGetInteger("gEventLog.Filter.FlagUnset", 1) && + CVarGetInteger("gEventLog.Filter.SceneFlagSet", 1) && + CVarGetInteger("gEventLog.Filter.SceneFlagUnset", 1) && + CVarGetInteger("gEventLog.Filter.ActorInit", 1) && + CVarGetInteger("gEventLog.Filter.ActorKill", 1) && + CVarGetInteger("gEventLog.Filter.SceneInit", 1) && + CVarGetInteger("gEventLog.Filter.RoomInit", 1) && + CVarGetInteger("gEventLog.Filter.OpenText", 1) && + CVarGetInteger("gEventLog.Filter.ItemGive", 1); + bool someChecked = + CVarGetInteger("gEventLog.Filter.FlagSet", 1) || + CVarGetInteger("gEventLog.Filter.FlagUnset", 1) || + CVarGetInteger("gEventLog.Filter.SceneFlagSet", 1) || + CVarGetInteger("gEventLog.Filter.SceneFlagUnset", 1) || + CVarGetInteger("gEventLog.Filter.ActorInit", 1) || + CVarGetInteger("gEventLog.Filter.ActorKill", 1) || + CVarGetInteger("gEventLog.Filter.SceneInit", 1) || + CVarGetInteger("gEventLog.Filter.RoomInit", 1) || + CVarGetInteger("gEventLog.Filter.OpenText", 1) || + CVarGetInteger("gEventLog.Filter.ItemGive", 1); + + ImGuiContext* g = ImGui::GetCurrentContext(); + ImGuiItemFlags backup_item_flags = g->CurrentItemFlags; + if (!allChecked && someChecked) g->CurrentItemFlags |= ImGuiItemFlags_MixedValue; + if (UIWidgets::Checkbox("All", &allChecked)) { + if (allChecked) { + CVarSetInteger("gEventLog.Filter.FlagSet", 1); + CVarSetInteger("gEventLog.Filter.FlagUnset", 1); + CVarSetInteger("gEventLog.Filter.SceneFlagSet", 1); + CVarSetInteger("gEventLog.Filter.SceneFlagUnset", 1); + CVarSetInteger("gEventLog.Filter.ActorInit", 1); + CVarSetInteger("gEventLog.Filter.ActorKill", 1); + CVarSetInteger("gEventLog.Filter.SceneInit", 1); + CVarSetInteger("gEventLog.Filter.RoomInit", 1); + CVarSetInteger("gEventLog.Filter.OpenText", 1); + CVarSetInteger("gEventLog.Filter.ItemGive", 1); + } else { + CVarSetInteger("gEventLog.Filter.FlagSet", 0); + CVarSetInteger("gEventLog.Filter.FlagUnset", 0); + CVarSetInteger("gEventLog.Filter.SceneFlagSet", 0); + CVarSetInteger("gEventLog.Filter.SceneFlagUnset", 0); + CVarSetInteger("gEventLog.Filter.ActorInit", 0); + CVarSetInteger("gEventLog.Filter.ActorKill", 0); + CVarSetInteger("gEventLog.Filter.SceneInit", 0); + CVarSetInteger("gEventLog.Filter.RoomInit", 0); + CVarSetInteger("gEventLog.Filter.OpenText", 0); + CVarSetInteger("gEventLog.Filter.ItemGive", 0); + } + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + } + g->CurrentItemFlags = backup_item_flags; + + UIWidgets::CVarCheckbox("FlagSet", "gEventLog.Filter.FlagSet", { .defaultValue = 1 }); + UIWidgets::CVarCheckbox("FlagUnset", "gEventLog.Filter.FlagUnset", { .defaultValue = 1 }); + UIWidgets::CVarCheckbox("SceneFlagSet", "gEventLog.Filter.SceneFlagSet", { .defaultValue = 1 }); + UIWidgets::CVarCheckbox("SceneFlagUnset", "gEventLog.Filter.SceneFlagUnset", { .defaultValue = 1 }); + UIWidgets::CVarCheckbox("ActorInit", "gEventLog.Filter.ActorInit", { .defaultValue = 1 }); + UIWidgets::CVarCheckbox("ActorKill", "gEventLog.Filter.ActorKill", { .defaultValue = 1 }); + UIWidgets::CVarCheckbox("SceneInit", "gEventLog.Filter.SceneInit", { .defaultValue = 1 }); + UIWidgets::CVarCheckbox("RoomInit", "gEventLog.Filter.RoomInit", { .defaultValue = 1 }); + UIWidgets::CVarCheckbox("OpenText", "gEventLog.Filter.OpenText", { .defaultValue = 1 }); + UIWidgets::CVarCheckbox("ItemGive", "gEventLog.Filter.ItemGive", { .defaultValue = 1 }); + ImGui::EndPopup(); + } + + ImGui::SameLine(0); + + std::string maxEntriesStr = std::string("Max Entries: ") + std::to_string(eventLogEntries.size()) + "/"; + ImGui::Text("%s", maxEntriesStr.c_str()); + + ImGui::SameLine(0); + + UIWidgets::PushStyleCombobox(); + ImGui::PushItemWidth(50); + s32 maxEntries = CVarGetInteger("gEventLog.MaxEntries", 1000); + if (ImGui::InputScalar("##maxEntriesInput", ImGuiDataType_S32, &maxEntries)) { + CVarSetInteger("gEventLog.MaxEntries", MAX(0, maxEntries)); + LUS::Context::GetInstance()->GetWindow()->GetGui()->SaveConsoleVariablesOnNextTick(); + TrimEventLog(); + } + ImGui::PopItemWidth(); + UIWidgets::PopStyleCombobox(); + + ImGui::SameLine(0); + + if (UIWidgets::Button("Clear", { .color = UIWidgets::Colors::Red, .size = UIWidgets::Sizes::Inline })) { + eventLogEntries.clear(); + } + + if (ImGui::BeginTable("events", 3, ImGuiTableFlags_ScrollY, ImVec2(0, 0))) { + ImGui::TableSetupColumn("Timestamp", ImGuiTableColumnFlags_WidthFixed, 70); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 100); + ImGui::TableSetupColumn("Meta", ImGuiTableColumnFlags_WidthStretch, 0); + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableHeadersRow(); + + for (int i = 0; i < eventLogEntries.size(); i++) { + if (!CVarGetInteger((std::string("gEventLog.Filter.") + eventLogEntryTypeNames[eventLogEntries[i].type]).c_str(), 1)) { + continue; + } + + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::Text("%s", eventLogEntries[i].timestamp.c_str()); + ImGui::TableSetColumnIndex(1); + ImGui::Text("%s", eventLogEntryTypeNames[eventLogEntries[i].type]); + ImGui::TableSetColumnIndex(2); + ImGui::Text("%s", eventLogEntries[i].meta.c_str()); + } + + ImGui::EndTable(); + } + + ImGui::End(); +} + +void EventLogWindow::InitElement() { + RegisterEventLogHooks(); +} |
