Scoped weapons hold breath with recovery feedback and sound. Riot shields block and deflect bullets in hand and on the back; explosive crossbow bolts, destructible map cars with round resets, and T5 map model collision work. Remote players show last stand, weapon change, jump, mantle, landing, ladder and stun animations, and server hitboxes follow the shared torso tree. GSC gains spectator follow cameras, chat, kick, vehicle paths and flight controls, physics spheres, slow motion, slide and mantle movers, damage triggers, music, ambience, rumble and live audio fades over a shared mixer. IW5 and T5 maps get sun shadows with per-stage sun selection; post-fx pipelines compile before a vision blend needs them. The lobby browser keeps focus and selection, and rooms can be password protected. Console supply and give commands search every item category. Frames and replays decode only the current wire protocol. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4.2 KiB
Native data contracts
Direct C calls use libc. On Unix with perf/native, perfetto-sdk also calls
the C ABI of a C++ Perfetto implementation. Other platform calls are behind
Rust libraries such as Bevy/wgpu/winit and the Windows allocator.
| Interface | Creates data | Owns data | Valid until | Frees memory | Null | Size / error | Types / calling convention |
|---|---|---|---|---|---|---|---|
getenv |
Rust static key; C environment value | Rust key; C value | Key: process; value: environment change | C runtime; Rust only checks presence | Key: no; result: yes (absent) | Key ends in NUL; result checked | c_char*, C ABI |
malloc_trim (Linux GNU) |
No transferred buffer | Allocator heap | Call | Allocator releases free pages | No pointer | size_t pad, int status ignored (best effort) |
usize / c_int, C ABI |
sched_getaffinity |
Rust zeroed cpu_set_t |
Rust stack | Call | Rust stack | No | sizeof(cpu_set_t); failure becomes None before mask use |
libc target types, C ABI |
sched_setaffinity |
Rust populated cpu_set_t |
Rust stack | Call | Rust stack | No | Same size; bootstrap checks status, load worker ignores it | libc target types, C ABI |
atexit (perf, bench, capture) |
Rust function pointer | Program code; state in Rust statics | Process exit | No transferred allocation | Callback: no | No payload/length; registration status currently ignored | extern "C" fn() → C void (*)(void); i32 → int on supported targets |
| Perfetto category / track | Rust static categories; SDK descriptor Vec |
Rust statics / SDK track | Emission; tracks retained in OnceLock |
Rust / SDK | Required names and descriptors: no | NUL names; descriptor pointer + size_t; registration results checked for tracks |
SDK repr(C) structs, C ABI |
| Perfetto debug string | IW4L display string; SDK CStrings |
Rust / SDK EventContext |
Synchronous emission returns | Rust drops SDK strings | Name/value: no | NUL terminated; interior NUL rendered as literal \0 |
SDK const char*, C ABI |
| Perfetto config / heap buffer | Rust protobuf writer; C heap buffer | Rust writer; SDK owns C handle; Rust output Vec |
Writer outlives buffer; config borrowed during setup | SDK C destroy; Rust drops Vec |
Required handles: no | Written size = output length; setup parses during call | SDK pointer + size_t, C ABI |
| Perfetto trace read | C chunk; SDK boxed Rust callback | C chunk; Rust callback and copied bytes | Chunk: callback only; callback: final chunk | C chunk owner; Rust box on has_more=false |
C can return null/0; SDK 1.1.1 unconditionally forms a slice | Pointer + size_t + bool; IW4L copies each chunk |
SDK C callback types match; null contract differs |
| Perfetto flush / session | C session; Rust wrapper | Rust wrapper owns opaque C handle | Until SDK drop; process static retains it | SDK calls C destroy on drop | Create may return null, checked | Timeout is uint32_t; SDK 1.1.1 discards C flush bool status |
C ABI and scalar types match |
| Global allocator adapter | System / Windows MiMalloc | Rust allocation consumer | Until deallocation or successful reallocation | Same backing allocator with matching Layout |
Allocation can fail with null | Layout and new size forwarded unchanged | Rust GlobalAlloc; native ABI handled by backing library |
All dynamic debug strings in crates/perf/src/event.rs pass through str_arg.
Master-protocol map names accept length-bounded UTF-8, including interior NUL.
observe_master_bridge → follow_master_match → request_zone →
perf::swap can therefore supply such a string before any map file is opened.
The adapter renders NUL for diagnostics; the original gameplay value is unchanged.
It allocates a temporary display string only when NUL is present. The SDK
copies this string into its own CString before that temporary is dropped.
The C consumer serializes it before the SDK drops the event context.
Adapter display examples:
| Rust input | Perfetto display |
|---|---|
"", "mp_test", "карта" |
unchanged |
"a\0b" |
a\0b with a visible backslash and digit zero |
"\0a\0", "\0\0" |
every NUL rendered, including at the ends |
"a\\0b" |
unchanged; display escaping is not a reversible encoding |