Why the Studio asset browser shows no models for The New Order, and how far a reader can get on the skinned mesh format. Static TNO meshes and their material→texture resolution are fully decoded and already in production use, confirmed error-free on two independently checked maps. The Studio shows no skinned/animated models because that code path deliberately raises "unsupported" — a documented stub, not a bug. This pass's main result: the skinned vertex-and-index block, previously the admitted hard, unsolved core, is now decoded exactly and shown to generalize to roughly a quarter of a broad random sample, including multi-thousand-vertex character meshes. A prior "mesh count" header field is shown to be unreliable, and a first, partial step is made on the skeleton format (joint names only). Everything here is static analysis of archive bytes and executable string tables — TNO's code is encrypted and unreadable by any disassembler available to this project — so nothing was observed actually rendering.
Why the Studio shows nothing
The TNO model-loading function in the project's own codebase raises "unsupported" on purpose.
Static meshes — unchanged, fully solved
Static TNO meshes and material→texture resolution are fully decoded and wired end-to-end in production code, re-confirmed error-free on a second map this pass did not originally use.
Skinned vertex/index block (new this pass, the main result)
Format: a plain, big-endian, 32-byte interleaved vertex record —
f32 pos[3] -- position
f32 uv[2] -- texture coordinate
12 bytes -- not yet decoded (very likely normal/tangent/colour, by exact
analogy with the already-solved STATIC mesh vertex, which
uses the identical stride and leading layout)
— followed directly by a bare list of big-endian u16 triangle indices, with no length prefix of its own.
Proven exactly (zero free parameters) on three structurally different single-mesh samples — a 1,001-vertex weapon, a 38-vertex static prop, a 14-vertex non-rendering collision volume — by decoding vertices until one fails a sanity check (finite, non-subnormal, inside the mesh's own bounding box) to get a vertex count, then independently finding the exact byte offset where the mesh's own material name string recurs later in the file (a plain substring search, nothing to do with vertex/index counting) to get the index block's exact byte length with no further free parameter. Little-endian and the other game's own 48-byte vertex stride both fail immediately as negative controls.
A broad, unselective random sample of 150 further entries, decoded the same zero-free-parameter way, fits exactly on 35 (23%) — spanning weapons, vehicle parts, world props, and character meshes up to 5,323 vertices / 8,645 triangles.
Each single-mesh asset's trailing structure: a whole-file (not per-mesh) materials list — one byte count, then that many length-prefixed names — followed by a constant 20-byte tail.
Whole-model header: mesh-count field corrected
The field previously read as "mesh count" reads exactly 1 on every one of 755 sampled model entries and is most likely a different, real field by its RTTI name ("number of meshes before splitting by material"), not the true count. A real counter-example: one model reads 1 there but has 7 real sub-meshes, found by an unbiased full-file string scan. A second field further in the header is the true mesh count and is correct on every sample reached — but the exact byte-width rule that locates that second field corpus-wide is still unsolved (a simple fixed-6-byte-gap guess only works on 270 of 755 entries; two further concrete guesses were tried and explicitly rejected).
Multi-mesh packing (assets with more than one sub-mesh): the per-mesh materials footer found above does not repeat between meshes — consecutive meshes sit back-to-back with a short gap whose exact width is not yet reconciled (one data point requires an odd-byte gap, another fits a clean 4 bytes).
Skeleton — first, partial step
The same brute-force string-scanning technique used for mesh names/materials, applied to a character skeleton, recovers its full joint and facial-control name list for free: 211 plausible names on one sample — a complete, sane body-joint hierarchy down to individual finger phalanges, plus roughly 140 further facial/blend-shape control names. The binary header itself — true joint count, parent-index hierarchy, bind-pose transforms, and which of the 211 names are real skinning joints versus animation-only controls — is not decoded.
Other findings
A field that sits next to the model types in the type table and looked like it might be more mesh-format work turns out to be plain JSON text, not a binary container. Several other asset types (glass/foliage/particle models, animation, joint-conversion data) each open with a short text-like tag, not decoded further. Megatexture-bound models are not a separate format at all: identical geometry/UV/material decode to any other static mesh — only the pixel data behind the material is unavailable, a separate, pre-existing limitation.
Effort estimate for a Studio reader
- Static models: half a day to a day — almost entirely integration, since the parser, material resolver, and validation discipline already exist and are proven on two maps.
- Skinned models: materially de-risked this pass but not finished. Roughly one more focused session for the mesh-count/gap bookkeeping, a further short session for the skeleton header (joint names are already free), plus half a day to wire into the Studio — call it 2–3 days total, down from a prior estimate of about a work-week, since the single biggest unknown (the vertex/index layout) is now resolved.
Open questions
- The exact corpus-wide rule that locates the true mesh-count field (two concrete guesses tried and rejected).
- The exact multi-mesh inter-mesh gap width (4 bytes fits one sample, an odd count is structurally required for another).
- Why roughly a third of the random sample does not fit the simple vertex/index template exactly — plausibly genuine per-vertex skin-weight data for true multi-joint meshes, but not confirmed.
- The 12 unknown vertex bytes' and the per-mesh preamble's field-by-field meaning.
- The skeleton's binary joint hierarchy (parent indices, bind-pose transforms).
No in-game test applies yet — the milestone that would need one (an animated model rendering plausibly in the Studio or map viewer) depends on finishing the mesh-count/gap bookkeeping above first.