1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
#include "HookDebugger.h"
#include "2s2h/GameInteractor/GameInteractor.h"
#include "2s2h/BenGui/UIWidgets.hpp"
#include <string>
static std::map<const char*, std::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) {
size_t numHooks = (*hookData[hookName]).size();
if (numHooks == 0) {
ImGui::TextColored(grey, "No hooks found");
return;
}
ImGui::Text("Total Registered: %d", numHooks);
if (ImGui::BeginTable(("Table##" + std::string(hookName)).c_str(), 4,
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable |
ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit)) {
ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Registration Info", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("# Calls", ImGuiTableColumnFlags_WidthFixed);
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) {
// Replace the space after the return type of the parent function with a non-breaking space
std::string parentFunction = std::string(hookInfo.registering.function);
size_t pos = parentFunction.find_first_of(" ");
if (pos != std::string::npos) {
parentFunction.replace(pos, 1, "\u00A0");
}
// Non breaking space to keep the arrow with the parent function
ImGui::TextWrapped("%s(%d:%d) <-\u00A0%s", hookInfo.registering.file, hookInfo.registering.line,
hookInfo.registering.column, parentFunction.c_str());
} else {
ImGui::TextColored(yellow, "[Unavailable]");
}
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 unavailable 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::InitElement() {
#define DEFINE_HOOK(name, _) hookData.insert({ #name, GameInteractor::Instance->GetHookData<GameInteractor::name>() });
#include "2s2h/GameInteractor/GameInteractor_HookTable.h"
#undef DEFINE_HOOK
}
|