read what the binary says about itself: names, signatures, prototypes; gen v2
All checks were successful
CI / lint (push) Successful in 17s
CI / fuzz (push) Successful in 1m52s
CI / test (push) Successful in 24s

This commit is contained in:
Kamal Tufekcic 2026-07-29 20:09:21 +03:00
commit c458b4cb50
34 changed files with 58363 additions and 192 deletions

View file

@ -83,6 +83,29 @@ pub struct GameProfile {
/// from is comparing different objects. A raise is a re-distill, not a config tweak — change it and the
/// model together.
pub max_vtable_slots: usize,
/// Collapse tripwires, ONE PER INDEPENDENTLY-SHAPED TABLE the deriver reads out of the binary rather
/// than deriving. Each is read by its own record shape, so a layout change Valve makes to one yields
/// fewer records from that one alone — safe, but SILENT, and a release shipping zero of any of them at
/// exit 0 is exactly the failure "degrades or stops loudly, never lies" exists to prevent.
///
/// Deliberately NOT one summed floor across all of them: a sum is satisfied by the tables that still
/// work, so it cannot detect the single-table collapse it exists to catch. Set far below the observed
/// count (collapse detectors, not tight bounds); a new game starts every field at 0 and gets no gate
/// until someone measures one.
pub min_pulse_bindings: usize,
/// Bindings whose TYPED SIGNATURE was recovered from their descriptor initializer. Its own floor
/// because it has its own failure mode: the registry can still read perfectly while the descriptor
/// layout moves, and the result would be a release that ships every binding with no signature at all
/// — a silent capability loss rather than a wrong answer, which is precisely what a floor is for.
pub min_pulse_typed: usize,
pub min_entity_io: usize,
pub min_entity_classes: usize,
/// Console commands recovered from their registration calls. Its own floor because it has its own
/// failure mode, and a quiet one: the registrar is identified by SHAPE (it opens by writing the
/// invalid-handle sentinel), so a build that reworks that constructor yields zero commands rather
/// than wrong ones — correct, and invisible without this.
pub min_commands: usize,
pub min_schema_enums: usize,
/// Output game-key the game-keyed emitters use (Metamod `Games { <key> {..} }`, Plugify `{ "<key>": {..} }`).
pub game_key: &'static str,
/// The `--game` CLI token / per-release filename suffix (`cs2`, `dota2`) — distinct from `game_key` (the
@ -108,7 +131,7 @@ pub struct GameProfile {
pub soft_serializer: &'static [&'static str],
/// Method-name prefixes for a this-only blind-callable boolean query — the live call-smoke-test gate.
pub query_prefixes: &'static [&'static str],
/// Live-oracle "famous field" spotlight: per class, the netvars whose live offsets `verify-live` prints
/// Live-oracle "famous field" spotlight: per class, the netvars whose live offsets the oracle prints
/// field-by-field (the ones mods actually read). CS2 gameplay fields on the generic `CBaseEntity`.
pub spotlight_fields: &'static [(&'static str, &'static [&'static str])],
/// Human-readable game name for the shipped gamedata banner.
@ -159,6 +182,13 @@ pub const CS2: GameProfile = GameProfile {
"libvscript.so",
],
max_vtable_slots: 2048,
// observed: 580 Pulse, 715 inputs + 226 outputs, 474 entity classnames, 784 commands, 555 enums
min_pulse_bindings: 300,
min_pulse_typed: 300,
min_entity_io: 400,
min_entity_classes: 200,
min_commands: 400,
min_schema_enums: 250,
game_key: "csgo",
token: "cs2",
executable: "cs2",
@ -255,6 +285,13 @@ pub const DOTA: GameProfile = GameProfile {
"libvscript.so",
],
max_vtable_slots: 2048,
// observed: 500 Pulse, 624 inputs, 3,528 entity classnames, 855 commands, 743 enums
min_pulse_bindings: 250,
min_pulse_typed: 250,
min_entity_io: 300,
min_entity_classes: 1000,
min_commands: 400,
min_schema_enums: 350,
game_key: "dota",
token: "dota2",
executable: "dota2", // bin/linuxsteamrt64/dota2