mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-02-16 15:20:11 -05:00
Hook Debugger (#4323)
* Initial implementation * Add call number & relax source_location requirement * Update hookDebugger.cpp
This commit is contained in:
parent
b3b9216b5c
commit
da5cf11449
111
soh/soh/Enhancements/debugger/hookDebugger.cpp
Normal file
111
soh/soh/Enhancements/debugger/hookDebugger.cpp
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#include "hookDebugger.h"
|
||||||
|
#include "../game-interactor/GameInteractor.h"
|
||||||
|
#include "../../UIWidgets.hpp"
|
||||||
|
#include <string>
|
||||||
|
#include <version>
|
||||||
|
|
||||||
|
static std::unordered_map<const char*, std::unordered_map<HOOK_ID, HookInfo>> hookData;
|
||||||
|
|
||||||
|
const ImVec4 grey = ImVec4(0.75, 0.75, 0.75, 1);
|
||||||
|
const ImVec4 yellow = ImVec4(1, 1, 0, 1);
|
||||||
|
const ImVec4 red = ImVec4(1, 0, 0, 1);
|
||||||
|
|
||||||
|
void DrawHookRegisteringInfos(const char* hookName) {
|
||||||
|
if (hookData[hookName].size() == 0) {
|
||||||
|
ImGui::TextColored(grey, "No hooks found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginTable(
|
||||||
|
("Table##" + std::string(hookName)).c_str(),
|
||||||
|
4,
|
||||||
|
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit
|
||||||
|
)) {
|
||||||
|
ImGui::TableSetupColumn("Id");
|
||||||
|
ImGui::TableSetupColumn("Type");
|
||||||
|
ImGui::TableSetupColumn("Registration Info");
|
||||||
|
//ImGui::TableSetupColumn("Stub");
|
||||||
|
ImGui::TableSetupColumn("Number of Calls");
|
||||||
|
ImGui::TableHeadersRow();
|
||||||
|
for (auto& [id, hookInfo] : hookData[hookName]) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%d", id);
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
switch (hookInfo.registering.type) {
|
||||||
|
case HOOK_TYPE_NORMAL:
|
||||||
|
ImGui::Text("Normal");
|
||||||
|
break;
|
||||||
|
case HOOK_TYPE_ID:
|
||||||
|
ImGui::Text("Id");
|
||||||
|
break;
|
||||||
|
case HOOK_TYPE_PTR:
|
||||||
|
ImGui::Text("Ptr");
|
||||||
|
break;
|
||||||
|
case HOOK_TYPE_FILTER:
|
||||||
|
ImGui::Text("Filter");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ImGui::TextColored(red, "[UNKNOWN]");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (hookInfo.registering.valid) {
|
||||||
|
ImGui::Text("%s(%d:%d) %s", hookInfo.registering.file, hookInfo.registering.line, hookInfo.registering.column, hookInfo.registering.function);
|
||||||
|
} else {
|
||||||
|
ImGui::TextColored(yellow, "[Unavaliable]");
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: not currently possible
|
||||||
|
/*
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
|
ImGui::BeginDisabled();
|
||||||
|
|
||||||
|
bool stubButtonPressed = ImGui::Button(("Stub##" + std::to_string(id)).c_str());
|
||||||
|
UIWidgets::SetLastItemHoverText("Stub this hook.\nThis is not possible to automatically undo.");
|
||||||
|
|
||||||
|
if (stubButtonPressed) {
|
||||||
|
//stub
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
*/
|
||||||
|
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::Text("%d", hookInfo.calls);
|
||||||
|
}
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HookDebuggerWindow::DrawElement() {
|
||||||
|
#ifndef __cpp_lib_source_location
|
||||||
|
ImGui::TextColored(
|
||||||
|
yellow,
|
||||||
|
"Some features of the Hook Debugger are unavaliable because SoH was compiled "
|
||||||
|
"without \"<source_location>\" support "
|
||||||
|
"(\"__cpp_lib_source_location\" not defined in \"<version>\")."
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (auto& [hookName, _] : hookData) {
|
||||||
|
if (ImGui::TreeNode(hookName)) {
|
||||||
|
DrawHookRegisteringInfos(hookName);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HookDebuggerWindow::UpdateElement() {
|
||||||
|
hookData.clear();
|
||||||
|
|
||||||
|
#define DEFINE_HOOK(name, _) hookData.insert({#name, GameInteractor::Instance->GetHookData<GameInteractor::name>()});
|
||||||
|
|
||||||
|
#include "../game-interactor/GameInteractor_HookTable.h"
|
||||||
|
|
||||||
|
#undef DEFINE_HOOK
|
||||||
|
}
|
10
soh/soh/Enhancements/debugger/hookDebugger.h
Normal file
10
soh/soh/Enhancements/debugger/hookDebugger.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include <libultraship/libultraship.h>
|
||||||
|
|
||||||
|
class HookDebuggerWindow : public Ship::GuiWindow {
|
||||||
|
public:
|
||||||
|
using GuiWindow::GuiWindow;
|
||||||
|
|
||||||
|
void InitElement() override {};
|
||||||
|
void DrawElement() override;
|
||||||
|
void UpdateElement() override;
|
||||||
|
};
|
@ -458,6 +458,12 @@ void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state);
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <version>
|
||||||
|
#ifdef __cpp_lib_source_location
|
||||||
|
#include <source_location>
|
||||||
|
#else
|
||||||
|
#pragma message("Compiling without <source_location> support, the Hook Debugger will not be avaliable")
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_REMOTE_CONTROL
|
#ifdef ENABLE_REMOTE_CONTROL
|
||||||
#include <SDL2/SDL_net.h>
|
#include <SDL2/SDL_net.h>
|
||||||
@ -466,11 +472,40 @@ void GameInteractor_SetTriforceHuntCreditsWarpActive(uint8_t state);
|
|||||||
|
|
||||||
typedef uint32_t HOOK_ID;
|
typedef uint32_t HOOK_ID;
|
||||||
|
|
||||||
#define DEFINE_HOOK(name, args) \
|
enum HookType {
|
||||||
struct name { \
|
HOOK_TYPE_NORMAL,
|
||||||
typedef std::function<void args> fn; \
|
HOOK_TYPE_ID,
|
||||||
typedef std::function<bool args> filter; \
|
HOOK_TYPE_PTR,
|
||||||
}
|
HOOK_TYPE_FILTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HookRegisteringInfo {
|
||||||
|
bool valid;
|
||||||
|
const char* file;
|
||||||
|
std::uint_least32_t line;
|
||||||
|
std::uint_least32_t column;
|
||||||
|
const char* function;
|
||||||
|
HookType type;
|
||||||
|
|
||||||
|
HookRegisteringInfo() : valid(false), file("unknown file"), line(0), column(0), function("unknown function"), type(HOOK_TYPE_NORMAL) {}
|
||||||
|
|
||||||
|
HookRegisteringInfo(const char* _file, std::uint_least32_t _line, std::uint_least32_t _column, const char* _function, HookType _type) :
|
||||||
|
valid(true), file(_file), line(_line), column(_column), function(_function), type(_type) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HookInfo {
|
||||||
|
uint32_t calls;
|
||||||
|
HookRegisteringInfo registering;
|
||||||
|
|
||||||
|
HookInfo() : calls(0), registering(HookRegisteringInfo{}) {}
|
||||||
|
HookInfo(HookRegisteringInfo _registering) : calls(0), registering(_registering) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_source_location
|
||||||
|
#define GET_CURRENT_REGISTERING_INFO(type) HookRegisteringInfo{location.file_name(), location.line(), location.column(), location.function_name(), type}
|
||||||
|
#else
|
||||||
|
#define GET_CURRENT_REGISTERING_INFO(type) HookRegisteringInfo{}
|
||||||
|
#endif
|
||||||
|
|
||||||
#define REGISTER_VB_SHOULD(flag, body) \
|
#define REGISTER_VB_SHOULD(flag, body) \
|
||||||
GameInteractor::Instance->RegisterGameHookForID<GameInteractor::OnVanillaBehavior>(flag, [](GIVanillaBehavior _, bool* should, void* opt) body)
|
GameInteractor::Instance->RegisterGameHookForID<GameInteractor::OnVanillaBehavior>(flag, [](GIVanillaBehavior _, bool* should, void* opt) body)
|
||||||
@ -479,7 +514,7 @@ class GameInteractor {
|
|||||||
public:
|
public:
|
||||||
static GameInteractor* Instance;
|
static GameInteractor* Instance;
|
||||||
|
|
||||||
// Gsme State
|
// Game State
|
||||||
class State {
|
class State {
|
||||||
public:
|
public:
|
||||||
static bool NoUIActive;
|
static bool NoUIActive;
|
||||||
@ -532,7 +567,11 @@ public:
|
|||||||
inline static std::unordered_map<int32_t, std::unordered_map<HOOK_ID, typename H::fn>> functionsForID;
|
inline static std::unordered_map<int32_t, std::unordered_map<HOOK_ID, typename H::fn>> functionsForID;
|
||||||
inline static std::unordered_map<uintptr_t, std::unordered_map<HOOK_ID, typename H::fn>> functionsForPtr;
|
inline static std::unordered_map<uintptr_t, std::unordered_map<HOOK_ID, typename H::fn>> functionsForPtr;
|
||||||
inline static std::unordered_map<HOOK_ID, std::pair<typename H::filter, typename H::fn>> functionsForFilter;
|
inline static std::unordered_map<HOOK_ID, std::pair<typename H::filter, typename H::fn>> functionsForFilter;
|
||||||
|
|
||||||
|
//Used for the hook debugger
|
||||||
|
inline static std::unordered_map<HOOK_ID, HookInfo> hookData;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename H> struct HooksToUnregister {
|
template <typename H> struct HooksToUnregister {
|
||||||
inline static std::vector<HOOK_ID> hooks;
|
inline static std::vector<HOOK_ID> hooks;
|
||||||
inline static std::vector<HOOK_ID> hooksForID;
|
inline static std::vector<HOOK_ID> hooksForID;
|
||||||
@ -540,50 +579,74 @@ public:
|
|||||||
inline static std::vector<HOOK_ID> hooksForFilter;
|
inline static std::vector<HOOK_ID> hooksForFilter;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename H> std::unordered_map<uint32_t, HookInfo> GetHookData() {
|
||||||
|
return RegisteredGameHooks<H>::hookData;
|
||||||
|
}
|
||||||
|
|
||||||
// General Hooks
|
// General Hooks
|
||||||
template <typename H> HOOK_ID RegisterGameHook(typename H::fn h) {
|
template <typename H> HOOK_ID RegisterGameHook(
|
||||||
|
typename H::fn h
|
||||||
|
#ifdef __cpp_lib_source_location
|
||||||
|
, const std::source_location location = std::source_location::current()
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
// Ensure hook id is unique and not 0, which is reserved for invalid hooks
|
||||||
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1;
|
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1;
|
||||||
while (RegisteredGameHooks<H>::functions.find(this->nextHookId) != RegisteredGameHooks<H>::functions.end()) {
|
while (RegisteredGameHooks<H>::functions.find(this->nextHookId) != RegisteredGameHooks<H>::functions.end()) {
|
||||||
this->nextHookId++;
|
this->nextHookId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisteredGameHooks<H>::functions[this->nextHookId] = h;
|
RegisteredGameHooks<H>::functions[this->nextHookId] = h;
|
||||||
|
RegisteredGameHooks<H>::hookData[this->nextHookId] = HookInfo{GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_NORMAL)};
|
||||||
return this->nextHookId++;
|
return this->nextHookId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename H> void UnregisterGameHook(HOOK_ID hookId) {
|
template <typename H> void UnregisterGameHook(HOOK_ID hookId) {
|
||||||
if (hookId == 0) return;
|
if (hookId == 0) return;
|
||||||
HooksToUnregister<H>::hooks.push_back(hookId);
|
HooksToUnregister<H>::hooks.push_back(hookId);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename H, typename... Args> void ExecuteHooks(Args&&... args) {
|
template <typename H, typename... Args> void ExecuteHooks(Args&&... args) {
|
||||||
for (auto& hookId : HooksToUnregister<H>::hooks) {
|
for (auto& hookId : HooksToUnregister<H>::hooks) {
|
||||||
RegisteredGameHooks<H>::functions.erase(hookId);
|
RegisteredGameHooks<H>::functions.erase(hookId);
|
||||||
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
||||||
}
|
}
|
||||||
HooksToUnregister<H>::hooks.clear();
|
HooksToUnregister<H>::hooks.clear();
|
||||||
for (auto& hook : RegisteredGameHooks<H>::functions) {
|
for (auto& hook : RegisteredGameHooks<H>::functions) {
|
||||||
hook.second(std::forward<Args>(args)...);
|
hook.second(std::forward<Args>(args)...);
|
||||||
|
RegisteredGameHooks<H>::hookData[hook.first].calls += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ID based Hooks
|
// ID based Hooks
|
||||||
template <typename H> HOOK_ID RegisterGameHookForID(int32_t id, typename H::fn h) {
|
template <typename H> HOOK_ID RegisterGameHookForID(
|
||||||
|
int32_t id, typename H::fn h
|
||||||
|
#ifdef __cpp_lib_source_location
|
||||||
|
, const std::source_location location = std::source_location::current()
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1;
|
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1;
|
||||||
while (RegisteredGameHooks<H>::functionsForID[id].find(this->nextHookId) != RegisteredGameHooks<H>::functionsForID[id].end()) {
|
while (RegisteredGameHooks<H>::functionsForID[id].find(this->nextHookId) != RegisteredGameHooks<H>::functionsForID[id].end()) {
|
||||||
this->nextHookId++;
|
this->nextHookId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisteredGameHooks<H>::functionsForID[id][this->nextHookId] = h;
|
RegisteredGameHooks<H>::functionsForID[id][this->nextHookId] = h;
|
||||||
|
RegisteredGameHooks<H>::hookData[this->nextHookId] = HookInfo{GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_ID)};
|
||||||
return this->nextHookId++;
|
return this->nextHookId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename H> void UnregisterGameHookForID(HOOK_ID hookId) {
|
template <typename H> void UnregisterGameHookForID(HOOK_ID hookId) {
|
||||||
if (hookId == 0) return;
|
if (hookId == 0) return;
|
||||||
HooksToUnregister<H>::hooksForID.push_back(hookId);
|
HooksToUnregister<H>::hooksForID.push_back(hookId);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename H, typename... Args> void ExecuteHooksForID(int32_t id, Args&&... args) {
|
template <typename H, typename... Args> void ExecuteHooksForID(int32_t id, Args&&... args) {
|
||||||
for (auto& hookId : HooksToUnregister<H>::hooksForID) {
|
for (auto& hookId : HooksToUnregister<H>::hooksForID) {
|
||||||
for (auto it = RegisteredGameHooks<H>::functionsForID[id].begin(); it != RegisteredGameHooks<H>::functionsForID[id].end(); ) {
|
for (auto it = RegisteredGameHooks<H>::functionsForID[id].begin(); it != RegisteredGameHooks<H>::functionsForID[id].end(); ) {
|
||||||
if (it->first == hookId) {
|
if (it->first == hookId) {
|
||||||
it = RegisteredGameHooks<H>::functionsForID[id].erase(it);
|
it = RegisteredGameHooks<H>::functionsForID[id].erase(it);
|
||||||
HooksToUnregister<H>::hooksForID.erase(std::remove(HooksToUnregister<H>::hooksForID.begin(), HooksToUnregister<H>::hooksForID.end(), hookId), HooksToUnregister<H>::hooksForID.end());
|
HooksToUnregister<H>::hooksForID.erase(std::remove(HooksToUnregister<H>::hooksForID.begin(), HooksToUnregister<H>::hooksForID.end(), hookId), HooksToUnregister<H>::hooksForID.end());
|
||||||
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
@ -591,29 +654,39 @@ public:
|
|||||||
}
|
}
|
||||||
for (auto& hook : RegisteredGameHooks<H>::functionsForID[id]) {
|
for (auto& hook : RegisteredGameHooks<H>::functionsForID[id]) {
|
||||||
hook.second(std::forward<Args>(args)...);
|
hook.second(std::forward<Args>(args)...);
|
||||||
|
RegisteredGameHooks<H>::hookData[hook.first].calls += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PTR based Hooks
|
// PTR based Hooks
|
||||||
template <typename H> HOOK_ID RegisterGameHookForPtr(uintptr_t ptr, typename H::fn h) {
|
template <typename H> HOOK_ID RegisterGameHookForPtr(
|
||||||
|
uintptr_t ptr, typename H::fn h
|
||||||
|
#ifdef __cpp_lib_source_location
|
||||||
|
, const std::source_location location = std::source_location::current()
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1;
|
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1;
|
||||||
while (RegisteredGameHooks<H>::functionsForPtr[ptr].find(this->nextHookId) != RegisteredGameHooks<H>::functionsForPtr[ptr].end()) {
|
while (RegisteredGameHooks<H>::functionsForPtr[ptr].find(this->nextHookId) != RegisteredGameHooks<H>::functionsForPtr[ptr].end()) {
|
||||||
this->nextHookId++;
|
this->nextHookId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisteredGameHooks<H>::functionsForPtr[ptr][this->nextHookId] = h;
|
RegisteredGameHooks<H>::functionsForPtr[ptr][this->nextHookId] = h;
|
||||||
|
RegisteredGameHooks<H>::hookData[this->nextHookId] = HookInfo{GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_PTR)};
|
||||||
return this->nextHookId++;
|
return this->nextHookId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename H> void UnregisterGameHookForPtr(HOOK_ID hookId) {
|
template <typename H> void UnregisterGameHookForPtr(HOOK_ID hookId) {
|
||||||
if (hookId == 0) return;
|
if (hookId == 0) return;
|
||||||
HooksToUnregister<H>::hooksForPtr.push_back(hookId);
|
HooksToUnregister<H>::hooksForPtr.push_back(hookId);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename H, typename... Args> void ExecuteHooksForPtr(uintptr_t ptr, Args&&... args) {
|
template <typename H, typename... Args> void ExecuteHooksForPtr(uintptr_t ptr, Args&&... args) {
|
||||||
for (auto& hookId : HooksToUnregister<H>::hooksForPtr) {
|
for (auto& hookId : HooksToUnregister<H>::hooksForPtr) {
|
||||||
for (auto it = RegisteredGameHooks<H>::functionsForPtr[ptr].begin(); it != RegisteredGameHooks<H>::functionsForPtr[ptr].end(); ) {
|
for (auto it = RegisteredGameHooks<H>::functionsForPtr[ptr].begin(); it != RegisteredGameHooks<H>::functionsForPtr[ptr].end(); ) {
|
||||||
if (it->first == hookId) {
|
if (it->first == hookId) {
|
||||||
it = RegisteredGameHooks<H>::functionsForPtr[ptr].erase(it);
|
it = RegisteredGameHooks<H>::functionsForPtr[ptr].erase(it);
|
||||||
HooksToUnregister<H>::hooksForPtr.erase(std::remove(HooksToUnregister<H>::hooksForPtr.begin(), HooksToUnregister<H>::hooksForPtr.end(), hookId), HooksToUnregister<H>::hooksForPtr.end());
|
HooksToUnregister<H>::hooksForPtr.erase(std::remove(HooksToUnregister<H>::hooksForPtr.begin(), HooksToUnregister<H>::hooksForPtr.end(), hookId), HooksToUnregister<H>::hooksForPtr.end());
|
||||||
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
@ -621,31 +694,42 @@ public:
|
|||||||
}
|
}
|
||||||
for (auto& hook : RegisteredGameHooks<H>::functionsForPtr[ptr]) {
|
for (auto& hook : RegisteredGameHooks<H>::functionsForPtr[ptr]) {
|
||||||
hook.second(std::forward<Args>(args)...);
|
hook.second(std::forward<Args>(args)...);
|
||||||
|
RegisteredGameHooks<H>::hookData[hook.first].calls += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter based Hooks
|
// Filter based Hooks
|
||||||
template <typename H> HOOK_ID RegisterGameHookForFilter(typename H::filter f, typename H::fn h) {
|
template <typename H> HOOK_ID RegisterGameHookForFilter(
|
||||||
|
typename H::filter f, typename H::fn h
|
||||||
|
#ifdef __cpp_lib_source_location
|
||||||
|
, const std::source_location location = std::source_location::current()
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1;
|
if (this->nextHookId == 0 || this->nextHookId >= UINT32_MAX) this->nextHookId = 1;
|
||||||
while (RegisteredGameHooks<H>::functionsForFilter.find(this->nextHookId) != RegisteredGameHooks<H>::functionsForFilter.end()) {
|
while (RegisteredGameHooks<H>::functionsForFilter.find(this->nextHookId) != RegisteredGameHooks<H>::functionsForFilter.end()) {
|
||||||
this->nextHookId++;
|
this->nextHookId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisteredGameHooks<H>::functionsForFilter[this->nextHookId] = std::make_pair(f, h);
|
RegisteredGameHooks<H>::functionsForFilter[this->nextHookId] = std::make_pair(f, h);
|
||||||
|
RegisteredGameHooks<H>::hookData[this->nextHookId] = HookInfo{GET_CURRENT_REGISTERING_INFO(HOOK_TYPE_FILTER)};
|
||||||
return this->nextHookId++;
|
return this->nextHookId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename H> void UnregisterGameHookForFilter(HOOK_ID hookId) {
|
template <typename H> void UnregisterGameHookForFilter(HOOK_ID hookId) {
|
||||||
if (hookId == 0) return;
|
if (hookId == 0) return;
|
||||||
HooksToUnregister<H>::hooksForFilter.push_back(hookId);
|
HooksToUnregister<H>::hooksForFilter.push_back(hookId);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename H, typename... Args> void ExecuteHooksForFilter(Args&&... args) {
|
template <typename H, typename... Args> void ExecuteHooksForFilter(Args&&... args) {
|
||||||
for (auto& hookId : HooksToUnregister<H>::hooksForFilter) {
|
for (auto& hookId : HooksToUnregister<H>::hooksForFilter) {
|
||||||
RegisteredGameHooks<H>::functionsForFilter.erase(hookId);
|
RegisteredGameHooks<H>::functionsForFilter.erase(hookId);
|
||||||
|
RegisteredGameHooks<H>::hookData.erase(hookId);
|
||||||
}
|
}
|
||||||
HooksToUnregister<H>::hooksForFilter.clear();
|
HooksToUnregister<H>::hooksForFilter.clear();
|
||||||
for (auto& hook : RegisteredGameHooks<H>::functionsForFilter) {
|
for (auto& hook : RegisteredGameHooks<H>::functionsForFilter) {
|
||||||
if (hook.second.first(std::forward<Args>(args)...)) {
|
if (hook.second.first(std::forward<Args>(args)...)) {
|
||||||
hook.second.second(std::forward<Args>(args)...);
|
hook.second.second(std::forward<Args>(args)...);
|
||||||
|
RegisteredGameHooks<H>::hookData[hook.first].calls += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -672,59 +756,15 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DEFINE_HOOK(OnLoadGame, (int32_t fileNum));
|
#define DEFINE_HOOK(name, args) \
|
||||||
DEFINE_HOOK(OnExitGame, (int32_t fileNum));
|
struct name { \
|
||||||
DEFINE_HOOK(OnGameFrameUpdate, ());
|
typedef std::function<void args> fn; \
|
||||||
DEFINE_HOOK(OnItemReceive, (GetItemEntry itemEntry));
|
typedef std::function<bool args> filter; \
|
||||||
DEFINE_HOOK(OnSaleEnd, (GetItemEntry itemEntry));
|
}
|
||||||
DEFINE_HOOK(OnTransitionEnd, (int16_t sceneNum));
|
|
||||||
DEFINE_HOOK(OnSceneInit, (int16_t sceneNum));
|
|
||||||
DEFINE_HOOK(OnSceneFlagSet, (int16_t sceneNum, int16_t flagType, int16_t flag));
|
|
||||||
DEFINE_HOOK(OnSceneFlagUnset, (int16_t sceneNum, int16_t flagType, int16_t flag));
|
|
||||||
DEFINE_HOOK(OnFlagSet, (int16_t flagType, int16_t flag));
|
|
||||||
DEFINE_HOOK(OnFlagUnset, (int16_t flagType, int16_t flag));
|
|
||||||
DEFINE_HOOK(OnSceneSpawnActors, ());
|
|
||||||
DEFINE_HOOK(OnPlayerUpdate, ());
|
|
||||||
DEFINE_HOOK(OnOcarinaSongAction, ());
|
|
||||||
DEFINE_HOOK(OnShopSlotChange, (uint8_t cursorIndex, int16_t price));
|
|
||||||
DEFINE_HOOK(OnActorInit, (void* actor));
|
|
||||||
DEFINE_HOOK(OnActorUpdate, (void* actor));
|
|
||||||
DEFINE_HOOK(OnActorKill, (void* actor));
|
|
||||||
DEFINE_HOOK(OnEnemyDefeat, (void* actor));
|
|
||||||
DEFINE_HOOK(OnPlayerBonk, ());
|
|
||||||
DEFINE_HOOK(OnPlayDestroy, ());
|
|
||||||
DEFINE_HOOK(OnPlayDrawEnd, ());
|
|
||||||
|
|
||||||
DEFINE_HOOK(OnVanillaBehavior, (GIVanillaBehavior flag, bool* result, void* opt));
|
#include "GameInteractor_HookTable.h"
|
||||||
|
|
||||||
DEFINE_HOOK(OnSaveFile, (int32_t fileNum));
|
#undef DEFINE_HOOK
|
||||||
DEFINE_HOOK(OnLoadFile, (int32_t fileNum));
|
|
||||||
DEFINE_HOOK(OnDeleteFile, (int32_t fileNum));
|
|
||||||
|
|
||||||
DEFINE_HOOK(OnDialogMessage, ());
|
|
||||||
DEFINE_HOOK(OnPresentTitleCard, ());
|
|
||||||
DEFINE_HOOK(OnInterfaceUpdate, ());
|
|
||||||
DEFINE_HOOK(OnKaleidoscopeUpdate, (int16_t inDungeonScene));
|
|
||||||
|
|
||||||
DEFINE_HOOK(OnPresentFileSelect, ());
|
|
||||||
DEFINE_HOOK(OnUpdateFileSelectSelection, (uint16_t optionIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileSelectConfirmationSelection, (uint16_t optionIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileCopySelection, (uint16_t optionIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileCopyConfirmationSelection, (uint16_t optionIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileEraseSelection, (uint16_t optionIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileEraseConfirmationSelection, (uint16_t optionIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileAudioSelection, (uint8_t optionIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileTargetSelection, (uint8_t optionIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileLanguageSelection, (uint8_t optionIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileQuestSelection, (uint8_t questIndex));
|
|
||||||
DEFINE_HOOK(OnUpdateFileBossRushOptionSelection, (uint8_t optionIndex, uint8_t optionValue));
|
|
||||||
DEFINE_HOOK(OnUpdateFileNameSelection, (int16_t charCode));
|
|
||||||
|
|
||||||
DEFINE_HOOK(OnSetGameLanguage, ());
|
|
||||||
|
|
||||||
DEFINE_HOOK(OnFileDropped, (std::string filePath));
|
|
||||||
DEFINE_HOOK(OnAssetAltChange, ());
|
|
||||||
DEFINE_HOOK(OnKaleidoUpdate, ());
|
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
static bool IsSaveLoaded(bool allowDbgSave = false);
|
static bool IsSaveLoaded(bool allowDbgSave = false);
|
||||||
@ -785,5 +825,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#undef GET_CURRENT_REGISTERING_INFO
|
||||||
|
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
#endif /* GameInteractor_h */
|
#endif /* GameInteractor_h */
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Hook Table
|
||||||
|
*
|
||||||
|
* DEFINE_HOOK arguments:
|
||||||
|
* - Argument 1: Name of the hook
|
||||||
|
* - Argument 2: Function type that the hook uses
|
||||||
|
*/
|
||||||
|
DEFINE_HOOK(OnLoadGame, (int32_t fileNum));
|
||||||
|
DEFINE_HOOK(OnExitGame, (int32_t fileNum));
|
||||||
|
DEFINE_HOOK(OnGameFrameUpdate, ());
|
||||||
|
DEFINE_HOOK(OnItemReceive, (GetItemEntry itemEntry));
|
||||||
|
DEFINE_HOOK(OnSaleEnd, (GetItemEntry itemEntry));
|
||||||
|
DEFINE_HOOK(OnTransitionEnd, (int16_t sceneNum));
|
||||||
|
DEFINE_HOOK(OnSceneInit, (int16_t sceneNum));
|
||||||
|
DEFINE_HOOK(OnSceneFlagSet, (int16_t sceneNum, int16_t flagType, int16_t flag));
|
||||||
|
DEFINE_HOOK(OnSceneFlagUnset, (int16_t sceneNum, int16_t flagType, int16_t flag));
|
||||||
|
DEFINE_HOOK(OnFlagSet, (int16_t flagType, int16_t flag));
|
||||||
|
DEFINE_HOOK(OnFlagUnset, (int16_t flagType, int16_t flag));
|
||||||
|
DEFINE_HOOK(OnSceneSpawnActors, ());
|
||||||
|
DEFINE_HOOK(OnPlayerUpdate, ());
|
||||||
|
DEFINE_HOOK(OnOcarinaSongAction, ());
|
||||||
|
DEFINE_HOOK(OnShopSlotChange, (uint8_t cursorIndex, int16_t price));
|
||||||
|
DEFINE_HOOK(OnActorInit, (void* actor));
|
||||||
|
DEFINE_HOOK(OnActorUpdate, (void* actor));
|
||||||
|
DEFINE_HOOK(OnActorKill, (void* actor));
|
||||||
|
DEFINE_HOOK(OnEnemyDefeat, (void* actor));
|
||||||
|
DEFINE_HOOK(OnPlayerBonk, ());
|
||||||
|
DEFINE_HOOK(OnPlayDestroy, ());
|
||||||
|
DEFINE_HOOK(OnPlayDrawEnd, ());
|
||||||
|
DEFINE_HOOK(OnVanillaBehavior, (GIVanillaBehavior flag, bool* result, void* opt));
|
||||||
|
DEFINE_HOOK(OnSaveFile, (int32_t fileNum));
|
||||||
|
DEFINE_HOOK(OnLoadFile, (int32_t fileNum));
|
||||||
|
DEFINE_HOOK(OnDeleteFile, (int32_t fileNum));
|
||||||
|
|
||||||
|
DEFINE_HOOK(OnDialogMessage, ());
|
||||||
|
DEFINE_HOOK(OnPresentTitleCard, ());
|
||||||
|
DEFINE_HOOK(OnInterfaceUpdate, ());
|
||||||
|
DEFINE_HOOK(OnKaleidoscopeUpdate, (int16_t inDungeonScene));
|
||||||
|
|
||||||
|
DEFINE_HOOK(OnPresentFileSelect, ());
|
||||||
|
DEFINE_HOOK(OnUpdateFileSelectSelection, (uint16_t optionIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileSelectConfirmationSelection, (uint16_t optionIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileCopySelection, (uint16_t optionIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileCopyConfirmationSelection, (uint16_t optionIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileEraseSelection, (uint16_t optionIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileEraseConfirmationSelection, (uint16_t optionIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileAudioSelection, (uint8_t optionIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileTargetSelection, (uint8_t optionIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileLanguageSelection, (uint8_t optionIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileQuestSelection, (uint8_t questIndex));
|
||||||
|
DEFINE_HOOK(OnUpdateFileBossRushOptionSelection, (uint8_t optionIndex, uint8_t optionValue));
|
||||||
|
DEFINE_HOOK(OnUpdateFileNameSelection, (int16_t charCode));
|
||||||
|
|
||||||
|
DEFINE_HOOK(OnSetGameLanguage, ());
|
||||||
|
DEFINE_HOOK(OnFileDropped, (std::string filePath));
|
||||||
|
DEFINE_HOOK(OnAssetAltChange, ());
|
||||||
|
DEFINE_HOOK(OnKaleidoUpdate, ());
|
@ -122,6 +122,7 @@ namespace SohGui {
|
|||||||
std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
|
std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
|
||||||
std::shared_ptr<ColViewerWindow> mColViewerWindow;
|
std::shared_ptr<ColViewerWindow> mColViewerWindow;
|
||||||
std::shared_ptr<SaveEditorWindow> mSaveEditorWindow;
|
std::shared_ptr<SaveEditorWindow> mSaveEditorWindow;
|
||||||
|
std::shared_ptr<HookDebuggerWindow> mHookDebuggerWindow;
|
||||||
std::shared_ptr<DLViewerWindow> mDLViewerWindow;
|
std::shared_ptr<DLViewerWindow> mDLViewerWindow;
|
||||||
std::shared_ptr<ValueViewerWindow> mValueViewerWindow;
|
std::shared_ptr<ValueViewerWindow> mValueViewerWindow;
|
||||||
std::shared_ptr<MessageViewer> mMessageViewerWindow;
|
std::shared_ptr<MessageViewer> mMessageViewerWindow;
|
||||||
@ -179,6 +180,8 @@ namespace SohGui {
|
|||||||
gui->AddGuiWindow(mColViewerWindow);
|
gui->AddGuiWindow(mColViewerWindow);
|
||||||
mSaveEditorWindow = std::make_shared<SaveEditorWindow>(CVAR_WINDOW("SaveEditor"), "Save Editor", ImVec2(520, 600));
|
mSaveEditorWindow = std::make_shared<SaveEditorWindow>(CVAR_WINDOW("SaveEditor"), "Save Editor", ImVec2(520, 600));
|
||||||
gui->AddGuiWindow(mSaveEditorWindow);
|
gui->AddGuiWindow(mSaveEditorWindow);
|
||||||
|
mHookDebuggerWindow = std::make_shared<HookDebuggerWindow>(CVAR_WINDOW("HookDebugger"), "Hook Debugger", ImVec2(1250, 850));
|
||||||
|
gui->AddGuiWindow(mHookDebuggerWindow);
|
||||||
mDLViewerWindow = std::make_shared<DLViewerWindow>(CVAR_WINDOW("DLViewer"), "Display List Viewer", ImVec2(520, 600));
|
mDLViewerWindow = std::make_shared<DLViewerWindow>(CVAR_WINDOW("DLViewer"), "Display List Viewer", ImVec2(520, 600));
|
||||||
gui->AddGuiWindow(mDLViewerWindow);
|
gui->AddGuiWindow(mDLViewerWindow);
|
||||||
mValueViewerWindow = std::make_shared<ValueViewerWindow>(CVAR_WINDOW("ValueViewer"), "Value Viewer", ImVec2(520, 600));
|
mValueViewerWindow = std::make_shared<ValueViewerWindow>(CVAR_WINDOW("ValueViewer"), "Value Viewer", ImVec2(520, 600));
|
||||||
@ -226,6 +229,7 @@ namespace SohGui {
|
|||||||
mValueViewerWindow = nullptr;
|
mValueViewerWindow = nullptr;
|
||||||
mMessageViewerWindow = nullptr;
|
mMessageViewerWindow = nullptr;
|
||||||
mSaveEditorWindow = nullptr;
|
mSaveEditorWindow = nullptr;
|
||||||
|
mHookDebuggerWindow = nullptr;
|
||||||
mColViewerWindow = nullptr;
|
mColViewerWindow = nullptr;
|
||||||
mActorViewerWindow = nullptr;
|
mActorViewerWindow = nullptr;
|
||||||
mCosmeticsEditorWindow = nullptr;
|
mCosmeticsEditorWindow = nullptr;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "Enhancements/debugger/actorViewer.h"
|
#include "Enhancements/debugger/actorViewer.h"
|
||||||
#include "Enhancements/debugger/colViewer.h"
|
#include "Enhancements/debugger/colViewer.h"
|
||||||
#include "Enhancements/debugger/debugSaveEditor.h"
|
#include "Enhancements/debugger/debugSaveEditor.h"
|
||||||
|
#include "Enhancements/debugger/hookDebugger.h"
|
||||||
#include "Enhancements/debugger/dlViewer.h"
|
#include "Enhancements/debugger/dlViewer.h"
|
||||||
#include "Enhancements/debugger/valueViewer.h"
|
#include "Enhancements/debugger/valueViewer.h"
|
||||||
#include "Enhancements/gameplaystatswindow.h"
|
#include "Enhancements/gameplaystatswindow.h"
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "Enhancements/debugger/actorViewer.h"
|
#include "Enhancements/debugger/actorViewer.h"
|
||||||
#include "Enhancements/debugger/colViewer.h"
|
#include "Enhancements/debugger/colViewer.h"
|
||||||
#include "Enhancements/debugger/debugSaveEditor.h"
|
#include "Enhancements/debugger/debugSaveEditor.h"
|
||||||
|
#include "Enhancements/debugger/hookDebugger.h"
|
||||||
#include "Enhancements/debugger/dlViewer.h"
|
#include "Enhancements/debugger/dlViewer.h"
|
||||||
#include "Enhancements/debugger/valueViewer.h"
|
#include "Enhancements/debugger/valueViewer.h"
|
||||||
#include "Enhancements/gameplaystatswindow.h"
|
#include "Enhancements/gameplaystatswindow.h"
|
||||||
@ -1761,6 +1762,7 @@ void DrawCheatsMenu() {
|
|||||||
extern std::shared_ptr<Ship::GuiWindow> mStatsWindow;
|
extern std::shared_ptr<Ship::GuiWindow> mStatsWindow;
|
||||||
extern std::shared_ptr<Ship::GuiWindow> mConsoleWindow;
|
extern std::shared_ptr<Ship::GuiWindow> mConsoleWindow;
|
||||||
extern std::shared_ptr<SaveEditorWindow> mSaveEditorWindow;
|
extern std::shared_ptr<SaveEditorWindow> mSaveEditorWindow;
|
||||||
|
extern std::shared_ptr<HookDebuggerWindow> mHookDebuggerWindow;
|
||||||
extern std::shared_ptr<ColViewerWindow> mColViewerWindow;
|
extern std::shared_ptr<ColViewerWindow> mColViewerWindow;
|
||||||
extern std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
|
extern std::shared_ptr<ActorViewerWindow> mActorViewerWindow;
|
||||||
extern std::shared_ptr<DLViewerWindow> mDLViewerWindow;
|
extern std::shared_ptr<DLViewerWindow> mDLViewerWindow;
|
||||||
@ -1844,6 +1846,12 @@ void DrawDeveloperToolsMenu() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
UIWidgets::Spacer(0);
|
UIWidgets::Spacer(0);
|
||||||
|
if (mHookDebuggerWindow) {
|
||||||
|
if (ImGui::Button(GetWindowButtonText("Hook Debugger", CVarGetInteger(CVAR_WINDOW("HookDebugger"), 0)).c_str(), ImVec2(-1.0f, 0.0f))) {
|
||||||
|
mHookDebuggerWindow->ToggleVisibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UIWidgets::Spacer(0);
|
||||||
if (mColViewerWindow) {
|
if (mColViewerWindow) {
|
||||||
if (ImGui::Button(GetWindowButtonText("Collision Viewer", CVarGetInteger(CVAR_WINDOW("CollisionViewer"), 0)).c_str(), ImVec2(-1.0f, 0.0f))) {
|
if (ImGui::Button(GetWindowButtonText("Collision Viewer", CVarGetInteger(CVAR_WINDOW("CollisionViewer"), 0)).c_str(), ImVec2(-1.0f, 0.0f))) {
|
||||||
mColViewerWindow->ToggleVisibility();
|
mColViewerWindow->ToggleVisibility();
|
||||||
|
Loading…
Reference in New Issue
Block a user