Union provides a hooks system that lets us intercept calls to the engine functions and methods with our custom interceptor. To hook a function or method we need to know its address which can be acquired either from Engine SDK/[Engine]/Names_[Engine].hpp or from the engine classes headers Engine SDK/[Engine]/Headers.
Intercepting functions
To declare a hook we can use CInvoke class or HOOK AS macros.
// 0x0042C450 int __cdecl Apply_Options_Video(void)// Forward declarationintApply_Options_Video();// Hook declarationCInvoke<int(*)()>Ivk_Apply_Options_Video(0x0042C450,&Apply_Options_Video);// Equivalent:// HOOK Ivk_Apply_Options_Video AS(0x0042C450, &Apply_Options_Video);// Implementation of interceptorintApply_Options_Video(){Message::Info("Before original Apply_Options_Video()");// Original function can be called using CInvoke pointer.intresult=Ivk_Apply_Options_Video();Message::Info("After original Apply_Options_Video()");returnresult;}
Member function
Member functions are the functions declared as non-static class members and they take a class instance pointer as an implicit first argument (__thiscall calling convention). We can hook them in two ways using either a regular function or declaring a new method in User API.
// 0x006015D0 public: virtual int __fastcall zCVob::Render(struct zTRenderContext &)// Forward declarationint__fastcallzCVob_Render(zCVob*_this,zTRenderContext&context);// Hook declarationCInvoke<int(__fastcall*)(zCVob*_this,zTRenderContext&context)>Ivk_zCVob_Render(0x006015D0,&zCVob_Render);// Equivalent:// HOOK Ivk_zCVob_Render AS(0x006015D0, &zCVob_Render);// Implementation of interceptor as regular function// Notice the first argument that's a pointer to class instance (this)int__fastcallzCVob_Render(zCVob*_this,zTRenderContext&context){if(_this==player){screen->PrintCX(1000,"Rendering a player zCVob");}// Call original methodreturnIvk_zCVob_Render(_this,context);}
Option #2 - User API
In Engine SDK/User API we can find a .inl file for the class we are hooking and define a new member method there. In this case, we are looking for zCVob.inl:
enumEInterMode{// Hook will not intercept the function.IVK_DISABLED=1<<1,// Normal hook. If other hook is already defined for the same address, an error pops up.IVK_NORMAL=1<<2,// Hook will automatically create an interception tree to allow multiple hooks for the same address.IVK_AUTO=1<<3,// Overrides any hook defined for the same address before.IVK_REDEFINE=1<<4,// Makes it impossible to override or disable the hook.// It should be used only in very specific cases.IVK_PROTECTED=1<<5,// Same as IVK_DISABLEDIVK_READONLY=IVK_DISABLED};