Studio header¶
The root of every Mdl file.
studiohdr_tsits at file offset 0 and is always exactly 408 bytes long. Nearly every other structure in the file is reached by following one of its*indexfields.Offsets. Every
*indexfield in the studio formats is a byte offset relative to the base of the structure that contains it, not to the start of the file. The two happen to coincide here only becausestudiohdr_tlives at offset 0; the distinction becomes real as soon as you follow an index into a nested structure. An index of0means null, not offset zero. Counts and indices come in pairs (numbones/boneindex), and a count of 0 leaves its index meaningless.Runtime fields. Several fields are scratch space that the engine writes into once the file is mapped into memory:
virtualModel,animblockModel,pVertexBaseandpIndexBaseare pointers, andactivitylistversion/eventsindexedare caches. They are zero in every shipped file examined so far, and this library writes zeros back. The pointer fields are 4 bytes because the on-disk layout is the 32 bit one; 64 bit builds of the engine relocate them intostudiohdr2_tprecisely so that the file layout does not change.Versions.
versionis a plain integer, not a bitfield. Team Fortress 2 ships versions 44 through 48, and 48 accounts for the overwhelming majority. The layout ofstudiohdr_titself does not change across that range – version differences live in the interpretation of other structures, so this header parses identically for all of them.studiohdr2_t exists because Valve ran out of room in the 408 byte header and did not want to bump the file version, which would have invalidated every shipped model.
studiohdr2indexpoints at it,0meaning absent, and the engine guards every access on that check. The SDK notes an intention to fold these fields back intostudiohdr_t“next time we up the .mdl file format”, which never happened.
- struct valvemdl.structs.studiohdr.studiohdr_t¶
-
-
checksum
(<parsed from long>¶int) must match the checksum in the vvd, vtx and phy files for the engine to load them together
-
name
(<parsed from a 64 bytes long padded string>¶string) stored inline as a fixed 64 byte buffer, not as an offset; see
studiohdr2_t.sznameindex for the overflow path
-
flags
(<parsed from unsigned long>¶int) Represents a flags Enum 0x1 STUDIOHDR_FLAGS_AUTOGENERATED_HITBOX 0x2 STUDIOHDR_FLAGS_USES_ENV_CUBEMAP 0x3 STUDIOHDR_FLAGS_FORCE_OPAQUE 0x4 STUDIOHDR_FLAGS_TRANSLUCENT_TWOPASS 0x5 STUDIOHDR_FLAGS_STATIC_PROP 0x6 STUDIOHDR_FLAGS_USES_FB_TEXTURE 0x7 STUDIOHDR_FLAGS_HASSHADOWLOD 0x8 STUDIOHDR_FLAGS_USES_BUMPMAPPING 0x9 STUDIOHDR_FLAGS_USE_SHADOWLOD_MATERIALS 0xa STUDIOHDR_FLAGS_OBSOLETE 0xb STUDIOHDR_FLAGS_UNUSED 0xc STUDIOHDR_FLAGS_NO_FORCED_FADE 0xd STUDIOHDR_FLAGS_FORCE_PHONEME_CROSSFADE 0xe STUDIOHDR_FLAGS_CONSTANT_DIRECTIONAL_LIGHT_DOT 0xf STUDIOHDR_FLAGS_FLEXES_CONVERTED 0x10 STUDIOHDR_FLAGS_BUILT_IN_PREVIEW_MODE 0x11 STUDIOHDR_FLAGS_AMBIENT_BOOST 0x12 STUDIOHDR_FLAGS_DO_NOT_CAST_SHADOWS 0x13 STUDIOHDR_FLAGS_CAST_TEXTURE_SHADOWS 0x16 STUDIOHDR_FLAGS_VERT_ANIM_FIXED_POINT_SCALE
-
boneindex
(<parsed from long>¶int) offset to an array of
mstudiobone_t
-
bonecontrollerindex
(<parsed from long>¶int) offset to an array of
mstudiobonecontroller_t
-
hitboxsetindex
(<parsed from long>¶int) offset to an array of
mstudiohitboxset_t
-
numlocalanim
(<parsed from long>¶int) local only; a model that gets its animations from an $includemodel may have 0 here
-
localanimindex
(<parsed from long>¶int) offset to an array of
mstudioanimdesc_t
-
localseqindex
(<parsed from long>¶int) offset to an array of
mstudioseqdesc_t
-
textureindex
(<parsed from long>¶int) offset to an array of
mstudiotexture_t
-
cdtextureindex
(<parsed from long>¶int) offset to an array of int, each itself an offset to a string; both hops are relative to
studiohdr_t
-
skinindex
(<parsed from long>¶int) offset to a short[numskinfamilies][numskinref] replacement table
-
bodypartindex
(<parsed from long>¶int) offset to an array of
mstudiobodyparts_t
-
localattachmentindex
(<parsed from long>¶int) offset to an array of
mstudioattachment_t
-
localnodeindex
(<parsed from long>¶int) offset to a byte[numlocalnodes*numlocalnodes] transition matrix
-
localnodenameindex
(<parsed from long>¶int) offset to an array of int, each itself an offset to a string
-
flexdescindex
(<parsed from long>¶int) offset to an array of
mstudioflexdesc_t
-
flexcontrollerindex
(<parsed from long>¶int) offset to an array of
mstudioflexcontroller_t
-
flexruleindex
(<parsed from long>¶int) offset to an array of
mstudioflexrule_t
-
ikchainindex
(<parsed from long>¶int) offset to an array of
mstudioikchain_t
-
mouthindex
(<parsed from long>¶int) offset to an array of
mstudiomouth_t
-
localposeparamindex
(<parsed from long>¶int) offset to an array of
mstudioposeparamdesc_t
-
localikautoplaylockindex
(<parsed from long>¶int) offset to an array of
mstudioiklock_t
-
numincludemodels
(<parsed from long>¶int) $includemodel; the source of the animations this model borrows at runtime
-
includemodelindex
(<parsed from long>¶int) offset to an array of
mstudiomodelgroup_t
-
szanimblocknameindex
(<parsed from long>¶int) offset to a string; the name of the external .ani file
-
animblockindex
(<parsed from long>¶int) offset to an array of
mstudioanimblock_t
-
bonetablebynameindex
(<parsed from long>¶int) offset to a byte[numbones] of bone indices, sorted by bone name
-
constdirectionallightdot
(<parsed from unsigned char>¶int) only meaningful when STUDIOHDR_FLAGS_CONSTANT_DIRECTIONAL_LIGHT_DOT is set
-
flexcontrolleruiindex
(<parsed from long>¶int) offset to an array of
mstudioflexcontrollerui_t
-
flVertAnimFixedPointScale
(<parsed from float>¶float) only meaningful when STUDIOHDR_FLAGS_VERT_ANIM_FIXED_POINT_SCALE is set; otherwise the engine uses 1/4096
-
studiohdr2index
(<parsed from long>¶int) offset to a
studiohdr2_t; 0 means absent
-
checksum
- struct valvemdl.structs.studiohdr.studiohdr2_t¶
-
-
flMaxEyeDeflection
(<parsed from float>¶float) cosine of the max eye deflection; 0.0 means unset, in which case the engine substitutes cos(30) = 0.866
-
linearboneindex
(<parsed from long>¶int) offset to a
mstudiolinearbone_t
-
sznameindex
(<parsed from long>¶int) when non-zero, overrides
studiohdr_t.name; exists because that field is a fixed 64 byte buffer
-
flMaxEyeDeflection