@@ -21,6 +21,10 @@ struct HookTableEntry {
2121// Vector of individual hooks for each hook slot.
2222std::vector<HookTableEntry> hook_table{};
2323
24+ // Holds the recomp context to restore after running each hook. This is a vector because a hook may end up calling another hooked function,
25+ // so this acts as a stack of contexts to handle that recursion.
26+ thread_local std::vector<recomp_context> hook_contexts = { recomp_context{} };
27+
2428void recomp::mods::run_hook (uint8_t * rdram, recomp_context* ctx, size_t hook_slot_index) {
2529 // Sanity check the hook slot index.
2630 if (hook_slot_index >= hook_table.size ()) {
@@ -31,7 +35,7 @@ void recomp::mods::run_hook(uint8_t* rdram, recomp_context* ctx, size_t hook_slo
3135 }
3236
3337 // Copy the initial context state to restore it after running each callback.
34- recomp_context initial_context = *ctx;
38+ hook_contexts. emplace_back ( *ctx) ;
3539
3640 // Call every hook attached to the hook slot.
3741 const std::vector<HookEntry>& hooks = hook_table[hook_slot_index].hooks ;
@@ -44,8 +48,11 @@ void recomp::mods::run_hook(uint8_t* rdram, recomp_context* ctx, size_t hook_slo
4448 }, hook.func );
4549
4650 // Restore the original context.
47- *ctx = initial_context ;
51+ *ctx = hook_contexts. back () ;
4852 }
53+
54+ // Pop the context after the hook is done.
55+ hook_contexts.pop_back ();
4956}
5057
5158void recomp::mods::setup_hooks (size_t num_hook_slots) {
@@ -85,3 +92,65 @@ void recomp::mods::finish_hook_setup(const ModContext& context) {
8592void recomp::mods::reset_hooks () {
8693 hook_table.clear ();
8794}
95+
96+ void recomphook_get_return_s32 (uint8_t * rdram, recomp_context* ctx) {
97+ ctx->r2 = (gpr)(int32_t )hook_contexts.back ().r2 ;
98+ }
99+
100+ void recomphook_get_return_u32 (uint8_t * rdram, recomp_context* ctx) {
101+ recomphook_get_return_s32 (rdram, ctx);
102+ }
103+
104+ void recomphook_get_return_ptr (uint8_t * rdram, recomp_context* ctx) {
105+ recomphook_get_return_s32 (rdram, ctx);
106+ }
107+
108+ void recomphook_get_return_s16 (uint8_t * rdram, recomp_context* ctx) {
109+ ctx->r2 = (gpr)(int16_t )hook_contexts.back ().r2 ;
110+ }
111+
112+ void recomphook_get_return_u16 (uint8_t * rdram, recomp_context* ctx) {
113+ ctx->r2 = (gpr)(uint16_t )hook_contexts.back ().r2 ;
114+ }
115+
116+ void recomphook_get_return_s8 (uint8_t * rdram, recomp_context* ctx) {
117+ ctx->r2 = (gpr)(int8_t )hook_contexts.back ().r2 ;
118+ }
119+
120+ void recomphook_get_return_u8 (uint8_t * rdram, recomp_context* ctx) {
121+ ctx->r2 = (gpr)(uint8_t )hook_contexts.back ().r2 ;
122+ }
123+
124+ void recomphook_get_return_s64 (uint8_t * rdram, recomp_context* ctx) {
125+ ctx->r2 = (gpr)(int32_t )hook_contexts.back ().r2 ;
126+ ctx->r3 = (gpr)(int32_t )hook_contexts.back ().r3 ;
127+ }
128+
129+ void recomphook_get_return_u64 (uint8_t * rdram, recomp_context* ctx) {
130+ recomphook_get_return_s64 (rdram, ctx);
131+ }
132+
133+ void recomphook_get_return_float (uint8_t * rdram, recomp_context* ctx) {
134+ ctx->f0 .fl = hook_contexts.back ().f0 .fl ;
135+ }
136+
137+ void recomphook_get_return_double (uint8_t * rdram, recomp_context* ctx) {
138+ ctx->f0 .fl = (gpr)(uint8_t )hook_contexts.back ().f0 .fl ;
139+ ctx->f1 .fl = (gpr)(uint8_t )hook_contexts.back ().f1 .fl ;
140+ }
141+
142+ #define REGISTER_FUNC (name ) recomp::overlays::register_base_export(#name, name)
143+
144+ void recomp::mods::register_hook_exports () {
145+ REGISTER_FUNC (recomphook_get_return_s32);
146+ REGISTER_FUNC (recomphook_get_return_u32);
147+ REGISTER_FUNC (recomphook_get_return_ptr);
148+ REGISTER_FUNC (recomphook_get_return_s16);
149+ REGISTER_FUNC (recomphook_get_return_u16);
150+ REGISTER_FUNC (recomphook_get_return_s8);
151+ REGISTER_FUNC (recomphook_get_return_u8);
152+ REGISTER_FUNC (recomphook_get_return_s64);
153+ REGISTER_FUNC (recomphook_get_return_u64);
154+ REGISTER_FUNC (recomphook_get_return_float);
155+ REGISTER_FUNC (recomphook_get_return_double);
156+ }
0 commit comments