ISource2ModTypes
Types shared by every source2mod callback.
Defines:
- Action -- what a callback tells Source2Mod to do with the original (KHook::Action)
- HookChain -- whether an SDK helper's call into the game runs the hooks on it
Header source2mod/ISource2ModTypes.h
Types
PluginId
using PluginId = int;A plugin's id; the core hands it to Load().
Source2ModHookId
using Source2ModHookId = int;What a Register* / Hook* call returns and the matching Unregister* / Unhook* takes: the one handler it registered. 0 is never handed out.
Action
using Action = KHook::Action;What a source2mod callback (command listener, game event hook, net message hook, entity output listener) did about the original.
KHook's own result type, so a KHook handler hands a listener's answer straight through and a listener returns what a hook would:
- Ignore -- did nothing; the original runs as it would have.
- Override -- changed something (the event, the return value) but the original still runs. Pre only.
- Supersede -- block the original entirely. Pre only.
Enums
HookChain
enum class HookChain : uint8_tWhether an SDK helper's call into the game goes through the hooks plugins placed on the function it calls.
Every schema helper that calls a hookable game function (TakeDamage, GiveNamedItem, TerminateRound, SetModel, ...) takes one as its last argument:
- Run -- through the Pre/Post chain, as if the game made the call. Right when the plugin stands in for the game -- a weapon dealing damage, a round reward handing out an item -- and other plugins' rules should apply.
- Bypass -- straight to the original, past every hook (inline detours and vtable hooks alike). Right when the server was told to do it -- an admin command, a forced round end -- or when calling the very function you are hooking, where Run would recurse.
The default of each helper is what it always did, so existing calls keep their behaviour; see the helper's declaration.
pItemServices->GiveNamedItem("weapon_ak47"); // hooks run
pController->TakeDamage(pAttacker, 50, DMG_BULLET, HookChain::Run); // opt in| Name |
|---|
Run |
Bypass |
Functions
defined
template <typename T> #if !defined(_MSC_VER) #endif void CallbackOrigin();One per callable type, instantiated where the callable is: its address is a code address inside the plugin that made the callable, which is how the core tells whose a handler is. Hidden, so the dynamic linker never hands another module's copy out for it.
| Parameter | Type |
|---|---|
— | _MSC_VER |
MethodOrigin
template <typename M> const void* MethodOrigin(const void* object, M method);A code address of a method: its entry, or for a virtual method the object's vtable (both live in the module that defined the class).
| Parameter | Type |
|---|---|
object | const void* |
method | M |
ResolveHookChain
template <typename FN> inline FN ResolveHookChain(FN fn, HookChain eChain);The function to call for a resolved address: the address itself, or, for HookChain::Bypass, the original behind any detour on it.
Resolve at the call, not once: a hook installed later changes the answer.
| Parameter | Type |
|---|---|
fn | FN |
eChain | HookChain |
ResolveHookChainVirtual
inline void* ResolveHookChainVirtual(void* pThis, int nIndex, HookChain eChain);The function to call for vtable slot nIndex of pThis: whatever the slot holds, or, for HookChain::Bypass, the original behind both a vtable hook on the slot and a detour on the function it points at.
| Parameter | Type |
|---|---|
pThis | void* |
nIndex | int |
eChain | HookChain |
Macros
SOURCE2MOD_STATIC
#define SOURCE2MOD_STATIC(func) (func)SourceHook's SH_STATIC / SH_MEMBER, for a source2mod handler argument.
g_pSource2ModEvents->HookGameEvent("round_end", SOURCE2MOD_STATIC(OnRoundEnd), true);
g_pSource2ModEvents->HookGameEvent("round_end", SOURCE2MOD_MEMBER(this, &Plugin::OnRoundEnd), true);
// ... and later the same delegate takes it off again:
g_pSource2ModEvents->UnhookGameEvent("round_end", SOURCE2MOD_MEMBER(this, &Plugin::OnRoundEnd), true);Plain OnRoundEnd / { this, &Plugin::OnRoundEnd } do the same; these only spell it the SourceHook way. The owner is the plugin whose code the function or method is, as for every handler.
Other macros
| Macro | Expands to |
|---|---|
SOURCE2MOD_MEMBER(inst, func) | { inst, func } |
KHOOK_NEW(member, ...) | member(new std::remove_pointer_t<decltype(member)>(__VA_ARGS__)) |