Mdl (Where it starts)

class valvemdl.Mdl(path=None)[source]

Contains all the data from an Mdl file.

An mdl is small (a couple of kilobytes is typical) and its contents form one interlinked graph rather than a set of independent blocks, so the file is parsed eagerly and in full.

Its sidecars are not. A model is really a set of files – .mdl, .vvd, and one .vtx per graphics backend – and most callers only ever want the mdl. Opening an mdl therefore only detects the sidecars sitting next to it; they are parsed on first access to vvd or vtx, and cached from then on.

__init__(path=None)[source]

Creates an empty instance of Mdl.

Parameters:

path (str, optional) – A path to an existing mdl file.

source_path
Type:

(str) - The location of the parsed file.

sidecar_paths
Type:

(dict[str, str]) - Sidecars found next to the mdl, by extension.

header
Type:

(construct.Container) - The parsed studiohdr_t.

header2
Type:

(construct.Container) - The parsed studiohdr2_t, None when absent.

bones
Type:

(list[construct.Container]) - The skeleton, in file order.

textures
Type:

(list[construct.Container]) - The materials the model names.

cdtextures
Type:

(list[str]) - The material search paths, in engine order.

skins
Type:

(list[list[int]]) - The skin table, one row per skin family.

bodyparts
Type:

(list[construct.Container]) - The geometry tree.

hitboxsets
Type:

(list[construct.Container]) - The hitbox sets.

attachments
Type:

(list[construct.Container]) - The attachment points.

poseparameters
Type:

(list[construct.Container]) - The pose parameters.

includemodels
Type:

(list[construct.Container]) - The $includemodel groups.

bonecontrollers
Type:

(list[construct.Container]) - The bone controllers.

flexdescs
Type:

(list[construct.Container]) - The flex targets.

flexcontrollers
Type:

(list[construct.Container]) - The flex controllers.

flexrules
Type:

(list[construct.Container]) - The flex rules.

flexcontrollerui
Type:

(list[construct.Container]) - The flex controller ui groups.

linearbones
Type:

(construct.Container) - studiohdr2’s linear bone table, or None.

srcbonetransforms
Type:

(list[construct.Container]) - The source bone transforms.

boneflexdrivers
Type:

(list[construct.Container]) - The bone flex drivers.

animations
Type:

(list[construct.Container]) - The animations, local to this file.

sequences
Type:

(list[construct.Container]) - The sequences, local to this file.

ikchains
Type:

(list[construct.Container]) - The ik chains.

property version

Team Fortress 2 ships 44 through 48. See the constants page.

Type:

(int) - The mdl version.

property checksum

The engine refuses to load a set whose checksums disagree.

Type:

(int) - Ties the mdl to its vvd and vtx files.

property name

The model’s own idea of its path, as baked in at compile time.

studiohdr_t.name is a fixed 64 byte buffer, so studiomdl spills longer paths into studiohdr2_t.sznameindex instead. This resolves whichever one is live, the same way the engine’s pszName() does.

Type:

(str) - The model’s path.

property surfaceprop

The model-wide surface property, named in the qc by $surfaceprop. Individual bones carry their own, which is what the engine actually uses when it needs to know what a given bone is made of.

Type:

(str) - A surfaceprop name, e.g. 'metal'.

property models

Every model in the file, flattened out of the bodypart tree.

Note that these are alternatives – a model here is one option inside one bodypart, not one model in the everyday sense. Only one per bodypart is ever drawn at a time.

Type:

(list[construct.Container]) - All the models.

property meshes

Every mesh in the file, flattened out of the bodypart tree.

Type:

(list[construct.Container]) - All the meshes.

bodygroup(bodynum)[source]

Decodes a packed bodygroup int into one model per bodypart.

studiomdl packs the whole choice of alternatives into a single integer, which entities carry as m_nBody. Each bodypart pulls its own choice back out with its base as the stride.

Parameters:

bodynum (int) – The packed value.

Returns:

The chosen model for each bodypart, in bodypart order.

Return type:

list[construct.Container]

save(destination=None)[source]

Writes the model back out.

The bytes are rebuilt from the object graph rather than copied from the file, so what lands on disk reflects the model as it now is.

Parameters:

destination (str, optional) – Where to write. Overwrites the original when not given.

coverage()[source]

Reports how much of the file ValveMDL can account for.

Rebuilding into an empty buffer means every byte has to be put there by something; anything left is something we have not understood. This reports what happened, which is more honest than a bare “it worked”:

  • struct – bytes regenerated from parsed structures.

  • opaque – bytes copied at an extent we worked out ourselves, the compressed animation streams above all.

  • unclaimed – bytes nothing wrote. Harmless where the original is zero (alignment padding, which the rebuild gets for free) and a real gap where it is not.

Returns:

Byte counts, plus differ: how many bytes the rebuild got wrong. Zero means the round trip is byte-exact.

Return type:

dict

skin_texture(skin, material)[source]

Resolves a mesh’s material through the skin table.

A mesh does not name its texture directly. mstudiomesh_t.material is a column in the skin table, and the row is whichever skin the entity happens to be using – which is how one model ships red and blu variants without duplicating any geometry.

Parameters:
  • skin (int) – The skin family, 0 being the default.

  • material (int) – A mesh’s material field.

Returns:

The texture, or None when the model has no skin table to resolve through.

Return type:

construct.Container

property vvd

The model’s vertex file, parsed on first access.

Type:

(Vvd) - The vertex file.

Raises:

MdlSidecarMissingError – when there is no vvd next to the mdl.

property vtx

Defaults to the dx90 flavour; use get_vtx() for the others.

Type:

(Vtx) - The model’s optimized mesh file, parsed on first access.

get_vtx(extension='.dx90.vtx')[source]

Provides one of the model’s vtx files, parsing it on first access.

studiomdl emits a vtx per graphics backend. They describe the same meshes optimized differently, so they are not interchangeable.

Parameters:

extension (str, optional) – Which flavour to load. See the constants page for the available values.

Returns:

The parsed vtx.

Return type:

Vtx

Raises:

MdlSidecarMissingError – when that flavour is not next to the mdl.

validate()[source]

Checks the invariants the format promises, and returns what is broken.

This is deliberately a report rather than an exception: a model that fails one of these is still worth looking at, and the failures themselves are interesting.

Returns:

One human readable string per broken invariant. Empty when the model is sound.

Return type:

list[str]

__repr__()[source]

Return repr(self).