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_t

Whether 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.

ParameterType
—_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).

ParameterType
objectconst void*
methodM

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.

ParameterType
fnFN
eChainHookChain

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.

ParameterType
pThisvoid*
nIndexint
eChainHookChain

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

MacroExpands to
SOURCE2MOD_MEMBER(inst, func){ inst, func }
KHOOK_NEW(member, ...)member(new std::remove_pointer_t<decltype(member)>(__VA_ARGS__))

On this page