|
| 1 | +// mlugg's playground :) |
| 2 | + |
| 3 | +#include "Event.hpp" |
| 4 | +#include "Entity.hpp" |
| 5 | +#include "Hook.hpp" |
| 6 | +#include "Scheduler.hpp" |
| 7 | +#include "Command.hpp" |
| 8 | +#include "Variable.hpp" |
| 9 | +#include "Modules/Console.hpp" |
| 10 | +#include "Modules/Client.hpp" |
| 11 | +#include "Modules/Engine.hpp" |
| 12 | +#include "Modules/Server.hpp" |
| 13 | + |
| 14 | +// hooking stuff |
| 15 | +#define _PAT_HOOK_INIT(module, pat, name) \ |
| 16 | + static void _init_fn_##name() { \ |
| 17 | + _orig_##name = (decltype (_orig_##name))Memory::Scan(module ".so", pat); \ |
| 18 | + _hook_##name.SetFunc(_orig_##name); \ |
| 19 | + if (!_orig_##name) Scheduler::InHostTicks(30, []() { console->Print("PATTERN HOOK FAILED: " #name); }); \ |
| 20 | + } \ |
| 21 | + static SarInitHandler _init_##name(_init_fn_##name); |
| 22 | + |
| 23 | +#define PAT_HOOK(module, pat, ret, name, ...) \ |
| 24 | + static ret _detour_##name(__VA_ARGS__); \ |
| 25 | + static ret (*_orig_##name)(__VA_ARGS__); \ |
| 26 | + static Hook _hook_##name(&_detour_##name); \ |
| 27 | + _PAT_HOOK_INIT(module, pat, name) \ |
| 28 | + static ret _detour_##name(__VA_ARGS__) |
| 29 | + |
| 30 | +#define HOOK_ORIG(out, name, ...) \ |
| 31 | + _hook_##name.Disable(); \ |
| 32 | + auto out = _orig_##name(__VA_ARGS__); \ |
| 33 | + _hook_##name.Enable(); |
| 34 | + |
| 35 | +#define HOOK_ORIG_V(name, ...) \ |
| 36 | + _hook_##name.Disable(); \ |
| 37 | + _orig_##name(__VA_ARGS__); \ |
| 38 | + _hook_##name.Enable(); |
| 39 | + |
| 40 | +#define GEN_HOOK(ret, name, ...) \ |
| 41 | + static ret _detour_##name(__VA_ARGS__); \ |
| 42 | + static ret (*_orig_##name)(__VA_ARGS__); \ |
| 43 | + static Hook _hook_##name(&_detour_##name); \ |
| 44 | + static ret _detour_##name(__VA_ARGS__) |
| 45 | + |
| 46 | +#define INIT_HOOK(name, ptr) \ |
| 47 | + _orig_##name = (ptr); \ |
| 48 | + _hook_##name.SetFunc(_orig_##name); |
| 49 | + |
| 50 | +// small wrappers for command and cvar creation |
| 51 | +#define TEST_CMD(name) CON_COMMAND(test_##name, "Playground test command\n") |
| 52 | +#define TEST_VAR(name) Variable name("test_" #name, "0", "Playground test variable\n", 0) |
| 53 | + |
| 54 | +// convenience macros for common ops |
| 55 | +#define CL_P client->GetPlayer(1) |
| 56 | +#define SV_P server->GetPlayer(1) |
| 57 | +#define CON(s, ...) console->Print(s "\n", __VA_ARGS__) |
| 58 | +#define BREAKPOINT raise(SIGTRAP) |
| 59 | + |
| 60 | +// example usage below |
| 61 | + |
| 62 | +/* |
| 63 | +PAT_HOOK("server", "01 23 45 67", void, MyFunction, void *arg1, bool arg2) { |
| 64 | + if (use_hook.GetBool()) CON("hookification complete"); |
| 65 | + HOOK_ORIG(res, MyFunction, arg1, arg2); |
| 66 | + return res; |
| 67 | +} |
| 68 | +
|
| 69 | +TEST_CMD(pos) { CON("ur at %.2f %.2f %.2f", SV_ORG(SV_P).x, SV_ORG(SV_P).y, SV_ORG(SV_P).z); } |
| 70 | +TEST_VAR(use_hook) |
| 71 | +*/ |
| 72 | + |
| 73 | +// real |
| 74 | + |
| 75 | +GEN_HOOK(void, ButtonTriggerEndTouch, void *thisptr, void *other) { |
| 76 | + console->Print("ENDTOUCH!!!\n"); |
| 77 | + HOOK_ORIG_V(ButtonTriggerEndTouch, thisptr, other); |
| 78 | +} |
| 79 | + |
| 80 | +ON_EVENT(PRE_TICK) { |
| 81 | + static bool inited = false; |
| 82 | + if (inited) return; |
| 83 | + |
| 84 | + for (int i = 0; i < Offsets::NUM_ENT_ENTRIES; ++i) { |
| 85 | + void *ent = server->m_EntPtrArray[i].m_pEntity; |
| 86 | + if (!ent) continue; |
| 87 | + |
| 88 | + auto classname = server->GetEntityClassName(ent); |
| 89 | + if (!classname || strcmp(classname, "trigger_portal_button")) continue; |
| 90 | + |
| 91 | + INIT_HOOK(ButtonTriggerEndTouch, Memory::VMT<void (*)(void *, void *)>(ent, Offsets::StartTouch + 2)); |
| 92 | + inited = true; |
| 93 | + |
| 94 | + console->Print("HOOKDED\n"); |
| 95 | + |
| 96 | + break; |
| 97 | + } |
| 98 | +} |
0 commit comments