Find CEntitySystemInit-decompiles (final-guarantee fallback)
SkillDev toolsFinal-guarantee fallback for the find-CEntitySystem_Init-decompiles preprocessor. Recovers the struct members, indirect virtual-function offsets, and de-inlined helpers that CEntitySystem::Init sets up, by decompiling CEntitySystem_Init in CS2 server.dll / libserver.so and following de-inlined callees when a target is no longer accessed directly. Use this skill when the deterministic/LLM preprocessor (ida_preprocessor_scripts/find-CEntitySystem_Init-decompiles.py) could not resolve every target because a member or vfunc was inlined or de-inlined in a way the LLM_DECOMPILE references do not cover. Trigger: CEntitySystem_m_sEntSystemName, CEntitySystem_m_eNetworkSerializationMode, CEntitySystem_m_Symbols, CEntitySystem_m_ComponentUnserializerInfoAllocator, CEntitySystem_m_pNetworkFieldChangedEventQueue, CEntitySystem_m_pNetworkFieldScratchData, CEntitySystem_m_pFieldChangeLimitSpew, CEntitySystem_m_EntityMaterialAttributes, INetworkMessages_SetNetworkSerializationContextData, IFlattenedSerializers_CreateFieldChangedEventQueue, CEntitySystem_ProcessEntityRegistration
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Find CEntitySystemInit-decompiles (final-guarantee fallback) skill
What this skill tells your AI
The instructions your AI receives, as published by hlnd2t/cs2_vibesignatures in .claude/skills/find-CEntitySystem_Init-decompiles/SKILL.md and read by ahel’s review.
Recover every symbol that CEntitySystem::Init wires up, in CS2 server.dll / libserver.so, using IDA Pro
MCP tools. This is the Agent fallback for the find-CEntitySystem_Init-decompiles skill: it only runs when
the preprocessor script returned failure, which almost always means one target's access pattern moved —
either it was inlined into CEntitySystem_Init where the reference expected a separate function, or it was
de-inlined out of CEntitySystem_Init into a helper the reference does not know about.
Your job is to produce the missing output YAMLs regardless of that inline/de-inline boundary.
Realworld Function References
Read the platform-relevant real-world YAMLs before searching in IDA. They provide concrete disassembly, decompiler output, semantic anchors, and both sides of the known inline/de-inline boundary. Treat their addresses and offsets as reference-build values only; verify every result against the current binary.
- Windows inline baseline:
ida_preprocessor_scripts/references/server/CEntitySystem_Init.windows.yaml - Linux baseline:
ida_preprocessor_scripts/references/server/CEntitySystem_Init.linux.yaml - Windows de-inlined
CEntitySystem_Initvariant:ida_preprocessor_scripts/references/server/CEntitySystem_Init-noinline.windows.yaml - Windows de-inlined material helper:
ida_preprocessor_scripts/references/server/CEntitySystem_InitEntityMaterialAttributes.windows.yaml - Linux registration helper:
ida_preprocessor_scripts/references/server/CEntitySystem_ProcessEntityRegistration.linux.yaml
Background — what CEntitySystem_Init does
CEntitySystem_Init(this, const char *name, int a3, int mode, char a5) is a long constructor-style routine.
Along the way it:
- copies the system name into
this->m_sEntSystemName; - stores the serialization
modeintothis->m_eNetworkSerializationMode; - initializes
this->m_ComponentUnserializerInfoAllocator(aCUtlScratchMemoryPool); - registers all entity/component classes;
- calls
g_pNetworkMessages->SetNetworkSerializationContextData("string_t_table", m_eNetworkSerializationMode, &m_Symbols)through theINetworkMessagesvtable (an indirect virtual call); - when
m_eNetworkSerializationModeis set, allocates aCNetworkFieldScratchDataintothis->m_pNetworkFieldScratchDataand callsg_pFlattenedSerializers->CreateFieldChangedEventQueue(m_pNetworkFieldScratchData, m_pFieldChangeLimitSpew)through theIFlattenedSerializersvtable, storing the result intothis->m_pNetworkFieldChangedEventQueue; - (Linux) tail-calls the de-inlined
CEntitySystem_ProcessEntityRegistration; - (Windows) runs the entity-material-attributes registration loop that touches
this->m_EntityMaterialAttributes.
All member accesses are relative to this (the first argument — rcx on Windows, rdi on Linux — usually
copied to rsi/rbx). This is the key to robustness: this + offset is stable whether the access sits in
CEntitySystem_Init itself or in a helper that received this as its first argument.
Robustness principle — follow the de-inline boundary
For every target below:
- First look for its access pattern inside
CEntitySystem_Init. - If it is not there, it has been de-inlined into a callee. Enumerate the functions that
CEntitySystem_Initcalls (read the pseudocode / disassembly and collect eachsub_*/ namedcalltarget), decompile the plausible ones, and search there. The owning helper takesthis(theCEntitySystem *) as its first parameter, so the samethis + offsetpattern appears. Recurse one or two levels if needed. - Conversely, a target the reference expected in a separate function (e.g. Linux
CEntitySystem_ProcessEntityRegistration, or Windowsm_EntityMaterialAttributes) may have been inlined back intoCEntitySystem_Init— in that case find the pattern directly inCEntitySystem_Init.
Anchor each target by its semantic fingerprint (the strings, constants, and neighboring calls listed below), not by a fixed address or a fixed containing function.
Output inventory
struct_name is always CEntitySystem. Offsets are reference values from the 14168 build — verify against
the binary, do not assume; they change across updates and differ per platform.
| # | Output symbol | Kind | Windows | Linux | Writer skill |
|---|---|---|---|---|---|
| 1 | CEntitySystem_m_sEntSystemName | struct member | 0xA88 | 0xA88 | /write-structoffset-as-yaml |
| 2 | CEntitySystem_m_eNetworkSerializationMode | struct member | 0xBBC | 0xBBC | /write-structoffset-as-yaml |
| 3 | CEntitySystem_m_ComponentUnserializerInfoAllocator | struct member | 0xCB8 | 0xCC0 | /write-structoffset-as-yaml |
| 4 | CEntitySystem_m_Symbols | struct member | 0x1EC8 | 0x1ED0 | /write-structoffset-as-yaml |
| 5 | CEntitySystem_m_pNetworkFieldChangedEventQueue | struct member | 0xC80 | 0xC88 | /write-structoffset-as-yaml |
| 6 | CEntitySystem_m_pNetworkFieldScratchData | struct member | 0xC88 | 0xC90 | /write-structoffset-as-yaml |
| 7 | CEntitySystem_m_pFieldChangeLimitSpew | struct member | 0xC90 | 0xC98 | /write-structoffset-as-yaml |
| 8 | INetworkMessages_SetNetworkSerializationContextData | indirect vcall | vtable INetworkMessages, offset 0xA0, index 20 | same | /write-vfunc-as-yaml |
| 9 | IFlattenedSerializers_CreateFieldChangedEventQueue | indirect vcall | vtable IFlattenedSerializers, offset 0x118, index 35 | same | /write-vfunc-as-yaml |
| 10 | CEntitySystem_ProcessEntityRegistration | function | inlined — do NOT emit | separate func (func_sig) | /write-func-as-yaml |
| 11 | CEntitySystem_m_EntityMaterialAttributes | struct member | 0x2070 | inlined — do NOT emit | /write-structoffset-as-yaml |
Platform gating: symbols 1–9 are produced on both platforms. Symbol 10 is Linux-only (on Windows the
routine is inlined into CEntitySystem_Init). Symbol 11 is Windows-only (on Linux the access lives inside
CEntitySystem_ProcessEntityRegistration, symbol 10).
Step 0. Skip targets already produced
Some outputs may already exist beside the binary — written by the preprocessor before it failed, or by the
find-CEntitySystem_InitEntityMaterialAttributes / find-CEntitySystem_m_EntityMaterialAttributes fallback
pair that runs before this skill. For each output, if <name>.<platform>.yaml already exists next to the
binary and parses to a non-empty mapping, skip it and spend effort only on the missing ones. You can list
the binary directory with:
mcp__ida-pro-mcp__py_eval code="import idaapi, os; d=os.path.dirname(idaapi.get_input_file_path()); print('\n'.join(sorted(f for f in os.listdir(d) if f.endswith('.yaml'))))"
/get-func-from-yaml also reports existence for functions/vfuncs (returns an error when absent).
Step 1. Load and decompile the predecessor
ALWAYS Use SKILL /get-func-from-yaml with func_name=CEntitySystem_Init to obtain its func_va.
If the skill returns an error, STOP and report to user (this fallback cannot run without the predecessor).
Decompile it, and keep the list of functions it calls for the de-inline search in later steps:
mcp__ida-pro-mcp__decompile addr="<CEntitySystem_Init.func_va>"
Confirm the this register (first argument) and note where it is copied (typically rsi on Windows, rbx on
Linux). Every struct-member offset below is this + offset.
Step 2. Resolve the struct members
For each member: locate the access, read the displacement in the instruction (that is the offset), confirm
it is relative to this (the CEntitySystem *), and confirm struct_name = CEntitySystem. Then generate a
signature and write the YAML (Step 5).
2a. m_sEntSystemName
The very first meaningful call in CEntitySystem_Init:
CUtlString::Set((CUtlString *)(this + 0xA88), name); // name == arg a2
Anchor: the lea/add that forms this + off immediately before the CUtlString::Set call whose second
argument is the incoming name string. off is m_sEntSystemName (ref 0xA88).
2b. m_eNetworkSerializationMode
The int/enum mode stored from the mode parameter (a4) near the top:
*(_DWORD *)(this + 0xBBC) = mode; // ref 0xBBC
It is read again later as the middle argument to the SetNetworkSerializationContextData vcall (Step 3a),
right next to the "string_t_table" string — that read site is an equally good anchor.
Decoy: a byte flag
*(_BYTE *)(this + 0xBDA) = (a3 == 1 && g_pNetworkMessages != nullptr)is set a few instructions away. That0xBDAboolean is notm_eNetworkSerializationMode— the target is the DWORD at0xBBC. Do not confuse them.
2c. m_ComponentUnserializerInfoAllocator
The CUtlScratchMemoryPool initialized near the top:
CUtlScratchMemoryPool::Init((CUtlScratchMemoryPool *)(this + 0xCB8/*win*/), 0x400, 0, nullptr, 0);
Anchor: the lea rcx/rdi, [this + off] feeding the CUtlScratchMemoryPool::Init call whose first immediate is
0x400. off is m_ComponentUnserializerInfoAllocator (ref 0xCB8 Windows / 0xCC0 Linux).
2d. m_Symbols
The last argument to the SetNetworkSerializationContextData vcall (Step 3a):
g_pNetworkMessages->SetNetworkSerializationContextData("string_t_table", m_eNetworkSerializationMode, this + 0x1EC8/*win*/);
Anchor: the lea that forms this + off as the third argument, in the block that also loads
"string_t_table". off is m_Symbols (ref 0x1EC8 Windows / 0x1ED0 Linux).
2e. The field-change trio — m_pNetworkFieldScratchData, m_pFieldChangeLimitSpew, m_pNetworkFieldChangedEventQueue
All three live in the if (m_eNetworkSerializationMode) block, around the CreateFieldChangedEventQueue vcall
(Step 3b):
// m_pNetworkFieldScratchData: object from operator new(0x58) with a CNetworkFieldScratchData vtable,
// stored at this + off, and passed as the 1st data argument to CreateFieldChangedEventQueue.
*(_QWORD *)(this + 0xC88/*win*/) = scratch; // ref 0xC88 win / 0xC90 linux
m_pNetworkFieldChangedEventQueue = // stored from the vcall's return value
g_pFlattenedSerializers->CreateFieldChangedEventQueue(
m_pNetworkFieldScratchData, // this + 0xC88 win / 0xC90 linux
m_pFieldChangeLimitSpew); // this + 0xC90 win / 0xC98 linux
*(_QWORD *)(this + 0xC80/*win*/) = <return value>; // m_pNetworkFieldChangedEventQueue, ref 0xC80 win / 0xC88 linux
Distinguish them by role:
m_pNetworkFieldScratchData— the object written just above the call (theoperator new(0x58)result with a vtable) and read as the vcall's second argument (rdx/2nd data reg). Ref0xC88win /0xC90linux.m_pFieldChangeLimitSpew— read as the vcall's third argument (r8/3rd data reg). Ref0xC90win /0xC98linux.m_pNetworkFieldChangedEventQueue— the member the vcall's return value is stored into. Ref0xC80win /0xC88linux.
These three signatures may need to span a function boundary (the block is easily de-inlined). If
/generate-signature-for-structoffsetcannot find a unique signature, it is acceptable to write the member with the offset only (omitoffset_sig) — the offset is the required output.
Step 3. Resolve the indirect virtual-call offsets
Symbols 8 and 9 are indirect virtual calls, not concrete functions. The YAML records the interface vtable
and slot, and a vfunc_sig that pins the call instruction — there is no func_va. Do not try to resolve a
concrete implementation address.
For each: find the call qword ptr [reg + disp] instruction, take vfunc_offset = disp and
vfunc_index = disp / 8.
3a. INetworkMessages_SetNetworkSerializationContextData
- Call site:
call qword ptr [reg + 0xA0]whereregholdsg_pNetworkMessages(typeINetworkMessages *), in the block that loads the"string_t_table"string and passesm_eNetworkSerializationModeand&m_Symbols. vtable_name = INetworkMessages,vfunc_offset = 0xA0(ref),vfunc_index = 20.
3b. IFlattenedSerializers_CreateFieldChangedEventQueue
- Call site:
call qword ptr [reg + 0x118]whereregholdsg_pFlattenedSerializers(typeIFlattenedSerializers *), passingm_pNetworkFieldScratchDataandm_pFieldChangeLimitSpew, with the return stored intom_pNetworkFieldChangedEventQueue. vtable_name = IFlattenedSerializers,vfunc_offset = 0x118(ref),vfunc_index = 35.
g_pNetworkMessages and g_pFlattenedSerializers are already-named globals in the database; use their type to
confirm the interface, and confirm the semantic role from the neighboring arguments described above. If the
whole call has been de-inlined into a helper, follow the callees (Robustness principle) — the [reg + disp]
instruction and its argument setup move together.
Step 4. Platform-specific de-inlined targets
4a. Linux only — CEntitySystem_ProcessEntityRegistration (symbol 10)
On Linux, CEntitySystem_Init tail-calls this de-inlined helper near its end (after the class-table loop):
CEntitySystem_ProcessEntityRegistration(this); // last call before Init returns
Anchor: the last call in CEntitySystem_Init that takes only this. Decompile it to confirm it performs the
entity-material-attributes registration (the FNV-1a hashing loop over material names — constants
0x811C9DC5 and 0x1000193). Rename it to CEntitySystem_ProcessEntityRegistration with
mcp__ida-pro-mcp__rename, then treat it as a normal function (Step 5c).
If (on some future Windows build) this routine is emitted as a separate function too, apply the same method on Windows. On the current Windows build it is inlined into
CEntitySystem_Init— do not emit it there.
4b. Windows only — m_EntityMaterialAttributes (symbol 11)
On Windows this member is accessed inside the material-attributes loop, whether that loop is inlined in
CEntitySystem_Init or de-inlined into CEntitySystem_InitEntityMaterialAttributes (a helper taking this):
lea reg, [this + 0x2070] // ref 0x2070 = m_EntityMaterialAttributes
Anchor: the lea this + off used as the map/dictionary base in the loop that FNV-1a-hashes material name
strings (constants 0x811C9DC5, 0x1000193; a small default string blob is the hash seed). Follow the callees
of CEntitySystem_Init if the loop is not inlined. off is m_EntityMaterialAttributes (ref 0x2070).
On Linux this access lives inside
CEntitySystem_ProcessEntityRegistration(symbol 10) and is not emitted as a separate member YAML.
Step 5. Generate signatures and write the YAMLs
5a. Struct members (symbols 1–7, and 11 on Windows)
For each resolved member:
- ALWAYS Use SKILL
/generate-signature-for-structoffseton the instruction that contains the offset to obtainoffset_sig/offset_sig_disp. (Best-effort for the field-change trio — see the note in Step 2e.) - ALWAYS Use SKILL
/write-structoffset-as-yamlwith:struct_name:CEntitySystemmember_name: the member (e.g.m_sEntSystemName)offset: the resolved hex offsetsize:Noneoffset_sig: the signature from step 1 (orNoneif not found)offset_sig_disp: from step 1 (orNone)
5b. Indirect vcalls (symbols 8–9)
For each:
- ALWAYS Use SKILL
/generate-signature-for-vfuncoffseton thecall qword ptr [reg + offset]instruction to obtainvfunc_sig(the offset bytes are fixed in the signature;vfunc_sig_dispis0). - ALWAYS Use SKILL
/write-vfunc-as-yamlwith:func_name: e.g.INetworkMessages_SetNetworkSerializationContextDatavtable_name:INetworkMessages/IFlattenedSerializersvfunc_offset: the resolved offset (0xA0/0x118)vfunc_index:vfunc_offset / 8(20/35)vfunc_sig: from step 1func_addr:None(no concrete implementation address for an interface vcall)func_sig:None
5c. Function (symbol 10, Linux only)
- ALWAYS Use SKILL
/generate-signature-for-functionwithaddr=<CEntitySystem_ProcessEntityRegistration_addr>. - ALWAYS Use SKILL
/write-func-as-yamlwith:func_name:CEntitySystem_ProcessEntityRegistrationfunc_addr: the resolved addressfunc_sig: the validated signature from step 1
Failure handling
- If the predecessor
CEntitySystem_InitYAML is missing → STOP and report to user. - If an individual required target cannot be located even after following callees → resolve the ones you can, then STOP and report exactly which output(s) could not be found, so the user can extend the references.
- Never emit a platform-gated symbol on the wrong platform (symbol 10 Windows, symbol 11 Linux).
Output YAML filenames
Written beside the binary by the writer skills, one file per symbol:
- Windows (
server.dll):<symbol>.windows.yaml - Linux (
libserver.so):<symbol>.linux.yaml
e.g. CEntitySystem_m_Symbols.windows.yaml, INetworkMessages_SetNetworkSerializationContextData.linux.yaml,
CEntitySystem_ProcessEntityRegistration.linux.yaml, CEntitySystem_m_EntityMaterialAttributes.windows.yaml.
Why this is robust
- Members are anchored to
this + offset, so they are recoverable whether the access is inlined inCEntitySystem_Initor de-inlined into a helper that receivesthis. - Each target has a semantic fingerprint (a string, a constant, a neighboring interface call) that survives offset changes and function-boundary moves across updates.
- The indirect vcalls are pinned by their call-site displacement, which is stable even when the surrounding code is reorganized.
- Already-produced outputs are skipped, so this fallback composes with the preprocessor and with the windows de-inline fallback pair instead of fighting them.
Signals
- GitHub stars
- 65
- Forks
- 10
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
find-centitysystem-init-decompiles- Source
- github.com/hlnd2t/cs2_vibesignatures