_igamesystem_dispatch_common
Overview
ida_preprocessor_scripts/_igamesystem_dispatch_common.py is the shared preprocess entry for IGameSystem dispatch-style skills. The design is deterministic: collect all dispatch calls first, then map targets by stable vfunc_index/vfunc_offset ordering.
Current Design
1) Collect all dispatch entries
_build_dispatch_py_eval(...)collects all candidates from the source function (or resolved internal wrapper).- Windows path: scans
lea rdx, callback, then parses callbackcall/jmp [reg+disp]. - Linux path: scans
mov esi/rsi, odd_imm+ nextcall, computesvfunc_off = imm - 1. - Only non-negative, 8-byte aligned offsets are accepted.
2) Strict count validation
expected_dispatch_countcontrols the required total entry count.- Validation requires
len(entries) == expected_dispatch_count. - If omitted:
- without
dispatch_rank: defaults totarget_count - with
dispatch_rank: defaults tomax(dispatch_rank) + 1
- without
3) Stable mapping with dispatch_rank
target_specsfields:target_name(required)rename_to(optional)dispatch_rank(optional)
- If
dispatch_rankis used:- all specs must provide it
- ranks must be unique and non-negative
- entries are sorted by
(vfunc_index, vfunc_offset) - each target picks by rank
- If
dispatch_rankis not used:- mapping uses scan order for selected entries
expected_dispatch_countmust equaltarget_count
Public API Snapshot
preprocess_igamesystem_dispatch_skill(...) relevant args:
target_specsmulti_order(scan/index)expected_dispatch_count=Nonedebug=False
Behavior Notes
- Fail-fast on validation/extraction mismatch (
Falsereturn). multi_order == "index"is honored for multi-target mapping.- If
dispatch_rankis present, stable index sorting is forced even withmulti_order="scan". - Internal/callback renaming remains best-effort (non-fatal).
Updated Callers (current)
SpawnGroup series
find-IGameSystem_PreSpawnGroupLoad.pydispatch_rank=0EXPECTED_DISPATCH_COUNT=2
find-IGameSystem_PostSpawnGroupLoad.pydispatch_rank=1EXPECTED_DISPATCH_COUNT=2
find-IGameSystem_PostSpawnGroupUnload.pydispatch_rank=1EXPECTED_DISPATCH_COUNT=2
find-IGameSystem_PreSpawnGroupUnload.py- single-target default mapping
ClientPreEntityThink case
find-IGameSystem_ClientPreEntityThink.py- observed dispatch indices:
22 / 23 / 24 IGameSystem_ClientPreEntityThinkusesdispatch_rank=0(index 22)EXPECTED_DISPATCH_COUNT=3
- observed dispatch indices:
Rationale
Mapping now relies on deterministic index ordering plus strict entry-count assertions, which is more stable under compiler/reordering differences.
SpawnGroupPrecache / SpawnGroupUncache
find-IGameSystem_SpawnGroupPrecache.py- source:
CSpawnGroupMgrGameSystem_SpawnGroupPrecache - single-target default mapping (1 dispatch)
- source:
find-IGameSystem_SpawnGroupUncache.py- source:
CSpawnGroupMgrGameSystem_SpawnGroupActuallyShutdown dispatch_rank=0EXPECTED_DISPATCH_COUNT=2
- source:
Files Involved
ida_preprocessor_scripts/_igamesystem_dispatch_common.pyida_preprocessor_scripts/find-IGameSystem_PreSpawnGroupLoad.pyida_preprocessor_scripts/find-IGameSystem_PostSpawnGroupLoad.pyida_preprocessor_scripts/find-IGameSystem_PostSpawnGroupUnload.pyida_preprocessor_scripts/find-IGameSystem_PreSpawnGroupUnload.pyida_preprocessor_scripts/find-IGameSystem_SpawnGroupPrecache.pyida_preprocessor_scripts/find-IGameSystem_SpawnGroupUncache.pyida_preprocessor_scripts/find-IGameSystem_ClientPreEntityThink.py