Repository navigation
Research Report R3 Animdecode
This research continues a multi-pass effort to decode TNC's compressed .md6anim animation format, and to explain why the soldier model's skeleton does not pose correctly from the already-proven formula while a pistol's does. This pass found that two "candidate decoder" functions flagged by an earlier reviewer belong to a completely separate, independently-shipped animation system called "Geist" (identified directly from the game's own embedded debug strings, not guessed), not to .md6anim itself. No weapon in the game has a Geist identity file, but the soldier does, which plausibly explains the bind-pose mismatch without yet fixing it. Rotation (quaternion) compression was solved in an earlier pass and remains confirmed; a full byte-for-byte decode of a .md6anim animation is still not achieved. Everything here is static disassembly/format research — no game launch was involved and there is nothing to test in-game yet.
-
Rotation ("smallest three" quaternion) compression: fully solved, round-trips 86/86 samples. Dequantizer at
.text 0x54bfa0, quantizer at0x54bdd0. -
0x1169530isidCompressedRigAnimation::Compress, part of C++ namespaceGeist050::Mercury(source file.../geist/lib/core/compiler/animation/riganimationcompressed.cpp) — identified from its own embedded debug strings (source path, log tags, aLinear/Scalar/Quat2/Quat4channel-type enum), not inferred from structure. -
Zero code calls in either direction between the
.md6animcluster (0x549e70-0x552210) and the Geist cluster (0x1168000-0x116f000), except two shared low-level quaternion primitives (0x54bdd0/0x54bfa0). The two systems are siblings, not one wrapping the other. -
0x116d212, the strongest "separate decoder" candidate an earlier pass found, has zero static callers anywhere in.text, no RTTI vtable slot, and shares its only two internal helper calls exclusively withCompressitself — more likely part of the compiler's own machinery (e.g. a keyframe-fidelity check) than a standalone runtime decoder. - Geist is a large, independently-shipped system in the retail content: 2,818
.geistanimfiles, 66.geistidentityfiles (includinggeist/identity/soldier.identity). No weapon has a.geistidentity(0/66 checked) — weapons stay entirely in the plain.md6skl/.md6animworld. - The 10-float TRS record right after
.md6anim's outer header is now precisely decoded: translation (3 floats) + quaternion xyzw (4) + scale (3). - The
"_FRAMESET_"tag occurs twice per file, not once as earlier passes assumed.
- The likely explanation for the bind-pose puzzle: Geist (not
idMD6Anim) builds the soldier's actual runtime skin pose, while.md6skl/.md6animmay serve the humanoid rig for something else (attachment points, a ragdoll proxy, a distant-LOD fallback) where literal bone-length reproduction isn't expected. Motivated by the code separation above but not proven — Geist's own bind-pose/skin-matrix construction code was not found or disassembled. -
0x116d212's 4-mode dispatch likely corresponds toCompress's ownLinear/Scalar/Quat2/Quat4channel types, with mode 3 (Quat4) being the one that touches quaternion data — a clean structural match, not confirmed by a trace.
- Where inside the (now precisely located)
"_FRAMESET_"regions the per-joint rotation data actually sits. Two sample files have substantial non-zero payload there (75–92% non-zero bytes) and are better decode targets than the "none_additive" sample earlier passes used, which turned out to be a near-empty additive placeholder. - Which function dequantizes translation.
-
.md6settings, a resource path pattern (md6/geist/<name>/face.md6settings) referenced byCompress's only known caller, is not among the 174 resource types that actually ship in the retail archive index — possibly unused/cut content, not resolved further.
Nothing here changes what's achievable in a mod today: reusing an existing weapon's full animation set still works (see the weapon-decl report), but no new .md6anim content can be authored or decoded yet. This is pure format research with no mod-facing recipe of its own.
English Wiki generated from the measured research notes in docs/. Evidence grades and uncertainty are preserved intentionally.
- WolfSDK Loader · DE
- WolfSDK Studio · DE
- FAQ · DE
- Mod format · DE
- Modding Guide
- Modding Surface
- CVar Catalog
- CVar Validation (old scrape)
- Texture Database
- Developer Mode
- Dev Menu
- Custom-Map Status