Wolfenstein Modloader Buy me a coffeeKaffee spendieren

In plain wordsIn einfachen Worten

This page is a task description for Wolfenstein II: The New Colossus. A map there is made of many placed models (for example 955 'model', 253 'modelAsset' and 249 'modelstream' entries in one archive), so understanding this mesh format would make new shapes possible. The worker was asked to work out the layout, prove it by rebuilding at least 300 real models byte for byte, and then write a minimal new box mesh. The archive container side was already solved, so only the model data itself remained; the result is on a separate report page.

  • Goal: understand how model, modelAsset and modelstream relate and store vertices and detail levels.
  • Required: a parser for at least 300 real models across 3 archives, with every byte accounted for.
  • Load-bearing check: rebuilt models must match the originals byte for byte.
  • Negative controls: a flipped size, cut-off data or wrong vertex count must make the parser fail.
  • A new box mesh is allowed, but must be clearly marked as untested in the game.

Diese Seite ist eine Aufgabenbeschreibung für Wolfenstein II: The New Colossus. Eine Karte besteht dort aus vielen platzierten Modellen (z. B. 955 'model', 253 'modelAsset' und 249 'modelstream'-Einträge in einem Archiv), daher würde das Verständnis dieses Mesh-Formats neue Formen möglich machen. Der Worker sollte den Aufbau ermitteln, ihn durch byte-genaues Nachbauen von mindestens 300 echten Modellen beweisen und dann ein minimales neues Box-Mesh schreiben. Die Archiv-Seite war bereits gelöst, es ging nur noch um die Modelldaten selbst; das Ergebnis steht auf einer eigenen Berichtsseite.

  • Ziel: verstehen, wie model, modelAsset und modelstream zusammenhängen und Eckpunkte sowie Detailstufen speichern.
  • Gefordert: ein Parser für mindestens 300 echte Modelle aus 3 Archiven, jedes Byte erklärt.
  • Tragende Prüfung: Nachgebaute Modelle müssen byte-genau den Originalen entsprechen.
  • Gegenproben: falsche Größe, abgeschnittene Daten oder falsche Eckpunktzahl müssen den Parser scheitern lassen.
  • Ein neues Box-Mesh ist erlaubt, muss aber klar als im Spiel ungetestet markiert sein.

Technical detailsTechnische Details

Der technische Teil ist auf Englisch – so, wie er im Wiki steht. Unterstrichene Begriffe haben eine Erklärung auf Deutsch.

Worker: w-meshfmt-a1; Task: meshfmt; Status: research/implement. Read .agent-cache/WORKER.md. Bus: python "%USERPROFILE%/.claude/skills/agent-cache-orchestrator/scripts/acbus.py" Parallel tasks: w-cmfmt-a1 (collision), w-entitypipe-a1 (placement), w-matpipe-a1 (surfaces), w-mapmanifest-a1 (streaming/manifest). You own geometry.

Objective

Make new 3D geometry writable. This is the single hardest remaining piece of "a real custom map", and the survey states it is tractable: a TNC map has no monolithic world blob—it consists of 955 model + 253 modelAsset + 249 modelstream entries placed into the world. Solve the mesh triple, and new shapes become possible.

Answer, with code and corpus evidence:

  1. The binary layout of model, and how modelAsset and modelstream relate to it (which holds vertices, which holds LODs/streamed tails, which is a descriptor).
  2. Can a NEW mesh be authored—a trivial one is enough, e.g., a box—such that the engine's own loader accepts it? Provide the writer.
  3. What else must exist for a mesh to be usable: a md6Def/modelAsset declaration, a material binding, bounds, LOD entries? Name the minimum set.

What is already solved - build on it, do not redo it

Today the whole container layer fell, and it is all independently re-verified:

  • wolfsdk/idclwrite.py writes containers; round-trip on 3 retail archives is BYTE-IDENTICAL, 6/6 negative controls. You can put any payload into an archive and the engine will consider the archive sound.
  • entry +0x50 = MurmurHash64B(uncompressed payload, seed 0xDEADBEEF); +0x60, header +0x20/+0x08 all derived. finalize() handles them.
  • So your problem is ONLY the payload bytes. Nothing about the archive is in your way any more.
  • re_probes/runtime_87400/module.bin is a read-only capture of the RUNNING, SteamStub-unpacked executable (virtual RVA layout, file offset == RVA, sections in manifest.json, .pdata for function bounds). Five formats fell to code-driven RE from it today; brute-force sweeps solved none. Go through the loader.

Sources / starting points

  • The corpus is huge, which is your advantage: 955 models in dlc_2/base/chunk_22.resources alone, plus every base chunk. Differential reading across many samples is cheap here.
  • Find the loader by its error strings in .rdata and their xrefs, the way re_probes/agent_reports/{idclhash,datahash,texdbkey,cfilekey2}.md did—read at least one of those reports for the method before starting.
  • re_probes/agent_reports/texdbkey.md additionally decoded the TNC .bimage mip table; the same report shows how a "header 0x32 bytes, then fixed-size records" layout was cracked. Meshes tend to look similar.
  • Part 1 knowledge, read-only: docs/formats.md, docs/moddingflaeche-tno.md (md6Def is text, geometry in binary .md6mesh), wolfsdk/bim.py. TNC is id Tech 6; its md6Def entries (31 in chunk_22) are the descriptor side and are likely text—read some first, they may name the fields.
  • capstone 5.0.7 vendored: PYTHONPATH=re_probes/python_deps
  • Game data READ ONLY: /steamapps/common/Wolfenstein.II.The.New.Colossus

Ownership

tools/probe_meshfmt.py (new), re_probes/meshfmt/ (new dir), re_probes/agent_reports/meshfmt.md (new). wolfsdk/idcl.py, wolfsdk/idclwrite.py, wolfsdk/oodle.py, tools/probe_*.py from other workers: READ-ONLY, import them.

Forbidden / do not touch

No game launch, no process attach, no writes under the Steam install or "%USERPROFILE%/Saved Games". Do not touch other workers' files or dirs (tools/probe_cmfmt.py, probe_entitypipe.py, probe_matpipe.py, probe_mapmanifest.py, and re_probes/{cmfmt,entitypipe,matpipe,mapmanifest,execcarrier,cfilekey,idclwriter,save_structure,map_alias_v3}/), docs/*, config.json. No pip install.

Hard constraints

Python 3.11, stdlib plus vendored capstone. Reuse wolfsdk/oodle.py for Kraken. Reproducible from the command line, no running game.

Acceptance criteria

  • A parser that reads the mesh payload of a large sample and reports structure without guessing: state n/n over at least 300 real models across 3 archives, where "parsed" means every field consumed and the declared sizes land exactly on the payload end. Partial parses must be reported as partial.
  • Round-trip: re-serialize a parsed retail mesh and reproduce the original bytes exactly, n/n on the same sample. This is the load-bearing control - a writer that cannot reproduce retail bytes cannot be trusted to author new ones.
  • Negative controls: a flipped size field, a truncated tail and a wrong vertex count must each make the parser fail, not silently produce something.
  • If you get that far: author a minimal new mesh (a box is fine) and place it in a container. Say plainly that it is untested at runtime.

Failure honesty

If the vertex data turns out to be in a compressed or GPU-specific encoding you cannot decode, say exactly where you stopped and what the obstacle is. A precise negative here redirects the whole program and is worth more than a hopeful half-parser. Report failed hypotheses with numbers.

Coordination / deliverable

Checkpoint at milestones (loader located; parser n/n; round-trip n/n). Publish a bus fact when the round-trip succeeds - w-cmfmt-a1 and w-entitypipe-a1 both need to know whether new geometry is on the table. Concise German report in re_probes/agent_reports/meshfmt.md. Finish the bus task.