mirror of
https://github.com/izzy2lost/2ship2harkinian-Android.git
synced 2026-06-19 01:20:08 -07:00
Add Event Log and more hooks (#247)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user