M2 entity¶
The user-facing compound M2 — the assembly with everything baked in (the
MD20 body, the Legion+ chunks and every satellite file) — plus the other
file-level entities of the family: the external Skin LOD view, the shared
Skeleton and the .bone facial-pose file. Each family is documented as its version-agnostic
base plus a representative per-version class, shown generically as
M2⟨version⟩ — the field set is identical across the versions a family
supports. Construct a concrete version with for_version(expansion);
read/write speak the filesystem gateway.
The MD20 body (M2Root) and the Legion+ chunked shell (M2ChunkedFile) are the
assembly's two halves; their field-by-field references, with expansion and
FourCC badges, live on M2 root and M2 chunks.
The M2 assembly¶
M2
¶
Bases: FileEntity
A whole model, abstract over the client version — the MD20 body with its satellite files (.skin, .anim) baked in. Construct the concrete version with M2.for_version(expansion), then read()/write(); the per-version M2* classes are subclasses. See https://wowdev.wiki/M2.
read
¶
read(source: FileSystem, key: FileKey) -> None
Load the model and every satellite file it references (.skin/.anim/ .skel/.bone/.phys) from a client filesystem, replacing this entity's contents.
for_version staticmethod¶
for_version(expansion: Expansion) -> M2⟨version⟩Construct the concrete M2 for a client version — the abstract M2 is never instantiated directly. The return type narrows per expansion (a typed overload per Expansion member), so for_version(Expansion.Wotlk) returns a M2Wotlk; a runtime Expansion value yields the AnyM2 union.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
FileSystem
|
the filesystem gateway |
required |
key
|
FileKey
|
the .m2 identity (path and/or FileDataID) |
required |
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises on a missing file or malformed model |
write
¶
write(dest: FileSystem, key: FileKey) -> None
Serialize the model, re-splitting and writing its satellite files, through the filesystem's project overlay; satellite names derive from the key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dest
|
FileSystem
|
the filesystem gateway |
required |
key
|
FileKey
|
the .m2 identity; must resolve to a path |
required |
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises when the key has no path or a file fails to write |
convert
¶
convert(target: Literal[Vanilla]) -> M2⟨version⟩
convert(target: Literal[Tbc]) -> M2⟨version⟩
convert(target: Literal[Wotlk]) -> M2⟨version⟩
convert(target: Literal[Cata]) -> M2⟨version⟩
convert(target: Literal[Mop]) -> M2⟨version⟩
convert(target: Literal[Wod]) -> M2⟨version⟩
convert(target: Literal[Legion]) -> M2⟨version⟩
convert(target: Literal[Bfa]) -> M2⟨version⟩
convert(target: Literal[Shadowlands]) -> M2⟨version⟩
convert(target: Literal[Dragonflight]) -> M2⟨version⟩
convert(target: Literal[TheWarWithin]) -> M2⟨version⟩
convert(target: Expansion) -> AnyM2
Rebuild this model as the target expansion's concrete class, stepping the version ladder one adjacent release at a time (this instance is left unchanged). The return type narrows when the target is a literal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
Literal[Vanilla]
|
the expansion to convert to |
required |
Returns:
| Type | Description |
|---|---|
M2⟨version⟩
|
the converted model; raises when a ladder step is not implemented |
validate
¶
Check the logical integrity contracts this file must satisfy to LOAD in the client, which write() deliberately never enforces. Call it before writing when you want to know the result will load. A file read from a client and left unmodified reports no errors; warnings mark states real client files ship.
Returns:
| Type | Description |
|---|---|
ValidationReport
|
every violated contract, each with its member path |
ensure_valid
¶
Validate and raise on the first error instead of returning a report — the assert-style face of validate().
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises when validate() finds any error |
M2⟨version⟩
¶
Bases: M2
A whole model for one client version: the MD20 body with skins and external sequence data baked in. A written model is canonical-layout and re-reads equal (no byte-perfect guarantee for offset formats). See https://wowdev.wiki/M2.
skins
property
¶
skins: list[Skin⟨version⟩]
The model's LOD views, in view order ("{model}0N.skin" files, WotLK+). The source of truth for the view count: write() stamps the body's num_skin_profiles layout field from this vector's length.
chunks
property
writable
¶
chunks: M2ChunkedFile⟨version⟩
The chunked .m2 stream (Legion+): the satellite chunks
(FileDataIDs, extended particles, parent overrides)
plus preserved unknown chunks. The MD21 transport blob
inside is TRANSIENT: read() decodes it into root and
drops the bytes; write() re-encodes root into the
stream and refreshes the FileDataID chunks.
lod_skins
property
¶
lod_skins: list[Skin⟨version⟩]
The LOD-band skins (the SFID entries beyond num_skin_profiles), in band order.
phys
property
writable
¶
phys: ChunkBlob
The referenced .phys file bytes (PFID), baked in verbatim — structured physics is a follow-up milestone. Inline physics (PFDC) stays a chunk on the stream.
skel
property
writable
¶
skel: Skeleton⟨version⟩
The shared skeleton (SKID), fully baked in — bones, attachments, sequences and the parent link. Engaged exactly when the chunk stream carries a skeleton FileDataID; skeletons are shared between models, so edit with care or write the .skel standalone.
bone_files
property
¶
bone_files: list[BoneFile]
The .bone facial-pose files (BFID; the skeleton's when skel-based), in variant order.
root
property
writable
¶
root: M2Root⟨version⟩
The MD20 body — the model's root, uniform across every era (pre-Legion it IS the file; Legion+ it is the decoded MD21 image, whose transport blob chunks drops after read).
validate
¶
Check the logical integrity contracts this model must satisfy to LOAD in the client — across the body AND every skin — which write() deliberately never enforces. Call it before writing when you want to know the model will load. A model read from a client and left unmodified reports no errors; warnings mark states real client files ship.
Returns:
| Type | Description |
|---|---|
ValidationReport
|
every violated contract, each with its member path |
ValidationReport
|
("root..." / "skins[i]...") |
ensure_valid
¶
Validate and raise on the first error instead of returning a report — the assert-style face of validate().
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises when validate() finds any error |
Skin — the .skin LOD view¶
The external skin file (WotLK+; embedded in the body before that): submeshes, render batches and the index/triangle tables of one LOD view.
Skin
¶
An external model LOD view (.skin file), abstract over the client version. Construct a concrete version with Skin.for_version(expansion); the per-version Skin* classes are subclasses. See https://wowdev.wiki/M2/.skin.
for_version staticmethod¶
for_version(expansion: Expansion) -> Skin⟨version⟩Construct the concrete Skin for a client version — the abstract Skin is never instantiated directly. The return type narrows per expansion (a typed overload per Expansion member), so for_version(Expansion.Wotlk) returns a SkinWotlk; a runtime Expansion value yields the AnySkin union.
validate
¶
Check the logical integrity contracts this file must satisfy to LOAD in the client, which write() deliberately never enforces. Call it before writing when you want to know the result will load. A file read from a client and left unmodified reports no errors; warnings mark states real client files ship.
Returns:
| Type | Description |
|---|---|
ValidationReport
|
every violated contract, each with its member path |
ensure_valid
¶
Validate and raise on the first error instead of returning a report — the assert-style face of validate().
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises when validate() finds any error |
Skin⟨version⟩
¶
Bases: Skin
One external LOD view (.skin file, WotLK+): the 'SKIN' magic plus the profile tables (local lookups, submeshes, render batches). See https://wowdev.wiki/M2/.skin.
profile
property
writable
¶
profile: M2SkinProfile⟨version⟩
The LOD view's tables (local lookups, submeshes, batches).
read
¶
Deserialize file bytes into this entity, replacing its contents. Offsets resolve against the given buffer; sequence-gated data is read inline.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
the file (or containing-chunk payload) bytes |
required |
write
¶
Serialize this entity in wowlib's canonical layout (an offset format has no byte-perfect round-trip guarantee; a written entity re-reads equal instead).
Returns:
| Type | Description |
|---|---|
bytes
|
the file bytes |
validate
¶
Check the logical integrity contracts this file must satisfy to LOAD in the client — companion-array counts, lookup ranges — which write() deliberately never enforces. Call it before writing when you want to know the result will load. A file read from a client and left unmodified reports no errors; warnings mark states real client files ship.
Returns:
| Type | Description |
|---|---|
ValidationReport
|
every violated contract, in member order |
ensure_valid
¶
Validate and raise on the first error instead of returning a report — the assert-style face of validate().
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises when validate() finds any error |
Skeleton — the shared .skel¶
The shared model skeleton (Legion 7.3+): bones, attachments and sequences a
skel-based model moved out of its MD20 image, shareable between models via the
parent link. The SK*1 chunk payload records (SkelHeader, SkelBones, …) are
documented with the other records.
Skeleton
¶
Bases: FileEntity
A shared model skeleton (.skel, Legion 7.3+), abstract over the client version. Construct a concrete version with Skeleton.for_version(expansion); the per-version Skeleton* classes are subclasses. See https://wowdev.wiki/M2/.skel.
validate
¶
Check the logical integrity contracts this file must satisfy to LOAD in the client, which write() deliberately never enforces. Call it before writing when you want to know the result will load. A file read from a client and left unmodified reports no errors; warnings mark states real client files ship.
for_version staticmethod¶
for_version(expansion: Expansion) -> Skeleton⟨version⟩Construct the concrete Skeleton for a client version — the abstract Skeleton is never instantiated directly. The return type narrows per expansion (a typed overload per Expansion member), so for_version(Expansion.Legion) returns a SkeletonLegion; a runtime Expansion value yields the AnySkeleton union.
Returns:
| Type | Description |
|---|---|
ValidationReport
|
every violated contract, each with its member path |
ensure_valid
¶
Validate and raise on the first error instead of returning a report — the assert-style face of validate().
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises when validate() finds any error |
Skeleton⟨version⟩
¶
Bases: Skeleton
A shared model skeleton (.skel, Legion 7.3+): bones, attachments and sequences for skel-based models, shareable between models via the parent link. See https://wowdev.wiki/M2/.skel.
sequence_block
property
writable
¶
sequence_block: SkelSequences⟨version⟩
The sequence tables (SKS1).
parent_link
property
¶
parent_link: list[SkelParentData]
The parent-skeleton link (SKPD); 0 or 1 entries.
anim_fdids
property
¶
anim_fdids: list[AnimFileEntry]
.anim FileDataIDs (AFID); absent on child skeletons, which share the parent's (see parent_anim_fdids).
bone_fdids
property
¶
.bone FileDataIDs (BFID); absent on child skeletons, which share the parent's (see parent_bone_fdids).
attachment_block
property
writable
¶
attachment_block: SkelAttachments⟨version⟩
The attachments (decoded SKA1).
parent_anim_fdids
property
¶
parent_anim_fdids: list[AnimFileEntry]
The parent's AFID entries when this skeleton is a child (filled by read(fs, key); not part of this file).
parent_bone_fdids
property
¶
The parent's BFID entries when this skeleton is a child (filled by read(fs, key); not part of this file).
read
¶
read(source: FileSystem, key: FileKey) -> None
Deserialize file bytes into this entity, replacing its contents. Unmodeled chunks are preserved so an unmodified entity rewrites byte-for-byte.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
the file bytes |
required |
Load the .skel (and its .bone files) from a client filesystem, replacing this entity's contents.
Parameters:
| Name | Description | Default |
|---|---|---|
source
|
the filesystem gateway |
required |
key
|
the .skel identity (path and/or FileDataID) |
required |
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises on a missing file or malformed chunk stream |
write
¶
write(dest: FileSystem, key: FileKey) -> None
Serialize this entity.
Returns:
| Type | Description |
|---|---|
bytes
|
the file bytes |
Serialize the .skel (and its .bone files) through the filesystem's project overlay; file names derive from the key.
Parameters:
| Name | Description | Default |
|---|---|---|
dest
|
the filesystem gateway |
required |
key
|
the .skel identity; must resolve to a path |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
nothing; raises when the key has no path or a file fails to write |
validate
¶
Check the logical integrity contracts this file must satisfy to LOAD in the client — companion-chunk counts, index ranges, flag/presence coherence — which write() deliberately never enforces. Call it before writing when you want to know the result will load. A file read from a client and left unmodified reports no errors; warnings mark states real client files ship.
Returns:
| Type | Description |
|---|---|
ValidationReport
|
every violated contract, in member order |
ensure_valid
¶
Validate and raise on the first error instead of returning a report — the assert-style face of validate().
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises when validate() finds any error |
effective_anim_fdids
¶
effective_anim_fdids() -> list[AnimFileEntry]
The effective AFID entries: own when present, else the parent's.
effective_bone_fdids
¶
The effective BFID entries: own when present, else the parent's.
BoneFile — the .bone facial poses¶
One .bone file per FacePose (808) sequence variant (WoD+), referenced by
BFID: which bones get facial-pose offset matrices, and the matrices. The layout
is stable across every client that ships them, so the entity is not
version-templated.
BoneFile
¶
A .bone file (WoD+): facial-pose (FacePose 808) bone offset matrices, one file per pose variant, referenced by BFID. See https://wowdev.wiki/BONE.
bone_offset_matrices
property
¶
bone_offset_matrices: list[C44Matrix]
The per-bone offset matrices (BOMT), same count as bone_ids.
read
¶
Deserialize file bytes into this entity, replacing its contents. Unmodeled chunks are preserved so an unmodified entity rewrites byte-for-byte.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
the file bytes |
required |
validate
¶
Check the logical integrity contracts this file must satisfy to LOAD in the client — companion-chunk counts, index ranges, flag/presence coherence — which write() deliberately never enforces. Call it before writing when you want to know the result will load. A file read from a client and left unmodified reports no errors; warnings mark states real client files ship.
Returns:
| Type | Description |
|---|---|
ValidationReport
|
every violated contract, in member order |
ensure_valid
¶
Validate and raise on the first error instead of returning a report — the assert-style face of validate().
Returns:
| Type | Description |
|---|---|
None
|
nothing; raises when validate() finds any error |