Support for hook unregistration (#109)

This commit is contained in:
Garrett Cox
2024-05-22 09:04:59 -05:00
parent 782c51ccd8
commit 07de3cb172
4 changed files with 43 additions and 12 deletions
+5 -2
View File
@@ -7,6 +7,7 @@
#include <unordered_map>
#include <string>
#include "z64.h"
#include "2s2h/Enhancements/Enhancements.h"
extern bool ShouldClearTextureCacheAtEndOfFrame;
@@ -286,9 +287,11 @@ void DrawDeveloperToolsMenu() {
});
UIWidgets::CVarCheckbox("No Clip", "gDeveloperTools.NoClip");
UIWidgets::CVarCheckbox("Better Map Select", "gDeveloperTools.BetterMapSelect.Enabled");
UIWidgets::CVarCheckbox("Moon Jump on L", "gDeveloperTools.MoonJumpOnL", {
if (UIWidgets::CVarCheckbox("Moon Jump on L", "gDeveloperTools.MoonJumpOnL", {
.tooltip = "Holding L makes you float into the air"
});
})) {
RegisterMoonJumpOnL();
}
if (gPlayState != NULL) {
ImGui::Separator();
UIWidgets::Checkbox("Frame Advance", (bool*)&gPlayState->frameAdvCtx.enabled, {
+12 -6
View File
@@ -10,18 +10,24 @@ extern "C" {
extern PlayState* gPlayState;
}
static uint32_t moonJumpOnLGameStateUpdateHookId = 0;
void RegisterMoonJumpOnL() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameStateUpdate>([]() {
if (!gPlayState) return;
if (CVarGetInteger("gDeveloperTools.MoonJumpOnL", 0)) {
if (moonJumpOnLGameStateUpdateHookId) {
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnGameStateUpdate>(moonJumpOnLGameStateUpdateHookId);
moonJumpOnLGameStateUpdateHookId = 0;
}
if (CVarGetInteger("gDeveloperTools.MoonJumpOnL", 0)) {
moonJumpOnLGameStateUpdateHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameStateUpdate>([]() {
if (!gPlayState) return;
Player* player = GET_PLAYER(gPlayState);
if (CHECK_BTN_ANY(gPlayState->state.input[0].cur.button, BTN_L)) {
player->actor.velocity.y = 6.34375f;
}
}
});
});
}
}
void InitEnhancements() {
+1
View File
@@ -3,6 +3,7 @@ extern "C" {
#endif
void InitEnhancements();
void RegisterMoonJumpOnL();
#ifdef __cplusplus
}
@@ -13,6 +13,8 @@ extern "C" {
#include <vector>
#include <functional>
#include <unordered_map>
#include <cstdint>
#define DEFINE_HOOK(name, type) \
struct name { \
@@ -29,11 +31,30 @@ public:
};
// Game Hooks
template <typename H> struct RegisteredGameHooks { inline static std::vector<typename H::fn> functions; };
template <typename H> void RegisterGameHook(typename H::fn h) { RegisteredGameHooks<H>::functions.push_back(h); }
uint32_t nextHookId = 1;
template <typename H> struct RegisteredGameHooks { inline static std::unordered_map<uint32_t, typename H::fn> functions; };
template <typename H> struct HooksToUnregister { inline static std::vector<uint32_t> hooks; };
template <typename H> uint32_t RegisterGameHook(typename H::fn h) {
// 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;
while (RegisteredGameHooks<H>::functions.find(this->nextHookId) != RegisteredGameHooks<H>::functions.end()) {
this->nextHookId++;
}
RegisteredGameHooks<H>::functions[this->nextHookId] = h;
return this->nextHookId++;
}
template <typename H> void UnregisterGameHook(uint32_t id) {
HooksToUnregister<H>::hooks.push_back(id);
}
template <typename H, typename... Args> void ExecuteHooks(Args&&... args) {
for (auto& fn : RegisteredGameHooks<H>::functions) {
fn(std::forward<Args>(args)...);
for (auto& hookId : HooksToUnregister<H>::hooks) {
RegisteredGameHooks<H>::functions.erase(hookId);
}
HooksToUnregister<H>::hooks.clear();
for (auto& hook : RegisteredGameHooks<H>::functions) {
hook.second(std::forward<Args>(args)...);
}
}