Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions librecomp/include/librecomp/mods.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ namespace recomp {
void finish_event_setup(const ModContext& context);
void finish_hook_setup(const ModContext& context);
void reset_hooks();
void register_hook_exports();
void run_hook(uint8_t* rdram, recomp_context* ctx, size_t hook_slot_index);

ModOpenError parse_manifest(ModManifest &ret, const std::vector<char> &manifest_data, std::string &error_param);
Expand Down
73 changes: 71 additions & 2 deletions librecomp/src/mod_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ struct HookTableEntry {
// Vector of individual hooks for each hook slot.
std::vector<HookTableEntry> hook_table{};

// Holds the recomp context to restore after running each hook. This is a vector because a hook may end up calling another hooked function,
// so this acts as a stack of contexts to handle that recursion.
thread_local std::vector<recomp_context> hook_contexts = { recomp_context{} };

void recomp::mods::run_hook(uint8_t* rdram, recomp_context* ctx, size_t hook_slot_index) {
// Sanity check the hook slot index.
if (hook_slot_index >= hook_table.size()) {
Expand All @@ -31,7 +35,7 @@ void recomp::mods::run_hook(uint8_t* rdram, recomp_context* ctx, size_t hook_slo
}

// Copy the initial context state to restore it after running each callback.
recomp_context initial_context = *ctx;
hook_contexts.emplace_back(*ctx);

// Call every hook attached to the hook slot.
const std::vector<HookEntry>& hooks = hook_table[hook_slot_index].hooks;
Expand All @@ -44,8 +48,11 @@ void recomp::mods::run_hook(uint8_t* rdram, recomp_context* ctx, size_t hook_slo
}, hook.func);

// Restore the original context.
*ctx = initial_context;
*ctx = hook_contexts.back();
}

// Pop the context after the hook is done.
hook_contexts.pop_back();
}

void recomp::mods::setup_hooks(size_t num_hook_slots) {
Expand Down Expand Up @@ -85,3 +92,65 @@ void recomp::mods::finish_hook_setup(const ModContext& context) {
void recomp::mods::reset_hooks() {
hook_table.clear();
}

void recomphook_get_return_s32(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = (gpr)(int32_t)hook_contexts.back().r2;
}

void recomphook_get_return_u32(uint8_t* rdram, recomp_context* ctx) {
recomphook_get_return_s32(rdram, ctx);
}

void recomphook_get_return_ptr(uint8_t* rdram, recomp_context* ctx) {
recomphook_get_return_s32(rdram, ctx);
}

void recomphook_get_return_s16(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = (gpr)(int16_t)hook_contexts.back().r2;
}

void recomphook_get_return_u16(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = (gpr)(uint16_t)hook_contexts.back().r2;
}

void recomphook_get_return_s8(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = (gpr)(int8_t)hook_contexts.back().r2;
}

void recomphook_get_return_u8(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = (gpr)(uint8_t)hook_contexts.back().r2;
}

void recomphook_get_return_s64(uint8_t* rdram, recomp_context* ctx) {
ctx->r2 = (gpr)(int32_t)hook_contexts.back().r2;
ctx->r3 = (gpr)(int32_t)hook_contexts.back().r3;
}

void recomphook_get_return_u64(uint8_t* rdram, recomp_context* ctx) {
recomphook_get_return_s64(rdram, ctx);
}

void recomphook_get_return_float(uint8_t* rdram, recomp_context* ctx) {
ctx->f0.fl = hook_contexts.back().f0.fl;
}

void recomphook_get_return_double(uint8_t* rdram, recomp_context* ctx) {
ctx->f0.fl = (gpr)(uint8_t)hook_contexts.back().f0.fl;
ctx->f1.fl = (gpr)(uint8_t)hook_contexts.back().f1.fl;
}

#define REGISTER_FUNC(name) recomp::overlays::register_base_export(#name, name)

void recomp::mods::register_hook_exports() {
REGISTER_FUNC(recomphook_get_return_s32);
REGISTER_FUNC(recomphook_get_return_u32);
REGISTER_FUNC(recomphook_get_return_ptr);
REGISTER_FUNC(recomphook_get_return_s16);
REGISTER_FUNC(recomphook_get_return_u16);
REGISTER_FUNC(recomphook_get_return_s8);
REGISTER_FUNC(recomphook_get_return_u8);
REGISTER_FUNC(recomphook_get_return_s64);
REGISTER_FUNC(recomphook_get_return_u64);
REGISTER_FUNC(recomphook_get_return_float);
REGISTER_FUNC(recomphook_get_return_double);
}
1 change: 1 addition & 0 deletions librecomp/src/recomp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ void recomp::start(

recomp::register_heap_exports();
recomp::mods::register_config_exports();
recomp::mods::register_hook_exports();

std::thread game_thread{[](ultramodern::renderer::WindowHandle window_handle, uint8_t* rdram) {
debug_printf("[Recomp] Starting\n");
Expand Down
Loading