Wolfenstein Modloader Buy me a coffeeKaffee spendieren

Wiki / Latest research roundsNeueste Forschungsrunden

A Box Map Under a New Map Name (game/wolfsdk/box)

Partly solvedTeilweise gelöst Original page in the GitHub wikiOriginalseite im GitHub-Wiki

In plain wordsIn einfachen Worten

UpdateAktualisierung Newer than this page: another map under a new name, game/wolfsdk/modtest, has since loaded in game (2026-10-02, see TNC Custom Map Status); the box map itself is still not confirmed in game.Neuer als diese Seite: Eine andere Karte unter neuem Namen, game/wolfsdk/modtest, lädt inzwischen im Spiel (02.10.2026, siehe TNC Custom Map Status); die Box-Karte selbst ist im Spiel noch nicht bestätigt.

This round-9 report asked whether a custom map for Wolfenstein II: The New Colossus can use a name the retail game never had. Reading the code found no step that limits map names to the retail list: the name only has to be listed in the dlc_0 folder's map list. A closed grey test room (8 × 8 × 4 m) was built under the name game/wolfsdk/box as a third map in the same archive, and all 31 build checks pass. Everything is static analysis; the box was not loaded in the game, and the route depended on the developer menu, which was itself still unconfirmed at the time.

  • The name lookup is a plain case-insensitive text compare over the map lists, with no hash and no fixed list; base maps are checked before DLC maps.
  • The box adds 29 entries (17 map-level files copied under the new name, 12 new model and collision entries); all 7,130 existing entries stay unchanged.
  • The new name needs its own textures.cache file, provided as a link to c2v1's; without it the game warns 'Failed to open'.
  • No chapter data is needed: without it the player falls back to the generic player definition; map sound banks are missing, so ambience is silent.
  • Not proven in game: devmap with a non-retail name, new model and collision entries, and the lighting, which may look blotchy or dark.

Dieser Bericht aus Runde 9 fragte, ob eine eigene Karte für Wolfenstein II: The New Colossus einen Namen tragen kann, den die Verkaufsversion nie hatte. Das Lesen des Codes fand keinen Schritt, der Kartennamen auf die Liste des Spiels beschränkt: Der Name muss nur in der Kartenliste des Ordners dlc_0 stehen. Ein geschlossener grauer Testraum (8 × 8 × 4 m) wurde unter dem Namen game/wolfsdk/box als dritte Karte im selben Archiv gebaut, und alle 31 Prüfungen des Builds bestehen. Alles ist statische Analyse; die Box wurde im Spiel nicht geladen, und der Weg hing vom Entwicklermenü ab, das damals selbst noch unbestätigt war.

  • Die Namenssuche ist ein einfacher Textvergleich ohne Beachtung der Groß- und Kleinschreibung über die Kartenlisten, ohne Hash und ohne feste Liste; Basis-Karten werden vor DLC-Karten geprüft.
  • Die Box fügt 29 Einträge hinzu (17 Dateien der Kartenebene unter neuem Namen kopiert, 12 neue Modell- und Kollisionseinträge); alle 7.130 vorhandenen Einträge bleiben unverändert.
  • Der neue Name braucht eine eigene textures.cache-Datei, als Verknüpfung auf die von c2v1; ohne sie meldet das Spiel „Failed to open“.
  • Kapiteldaten sind nicht nötig: Ohne sie wird der Spieler zur allgemeinen Spielerdefinition; Karten-Soundbanks fehlen, die Umgebung bleibt also stumm.
  • Im Spiel nicht bewiesen: devmap mit einem Namen außerhalb der Verkaufsversion, neue Modell- und Kollisionseinträge und die Beleuchtung, die fleckig oder dunkel aussehen kann.

Technical detailsTechnische Details

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

Round-9 pass: can a TNC custom map use a brand-new map name? Static analysis of the runtime snapshot found no step that limits map names to the retail list — the name only has to be listed in dlc_0's packagemapspec.json. A box map is built as a third map in dlc_0's own chunk_22, next to c2v1 and c2v1_custom, and all build checks pass. Not yet seen in the game; the route also depends on the dev-menu command branch, which is itself still unconfirmed in game.

Date: 2026-10-02. Nothing was installed and the game was not started. Nothing was written under <Steam library> or Saved Games; the install was only read. Builds went only to D:/wolf-decomp/tmp/boxmap/. New files: tools/build_boxmap.py and this report.

Answer

Yes, a new map name works. Static analysis of the runtime snapshot (re_probes/runtime_87400/module.bin, same EXE SHA256 as installed) found no step that limits map names to the retail list. You only have to list the name in dlc/dlc_0/base/packagemapspec.json. The box map is therefore built as a third map in dlc_0's own chunk_22, next to c2v1 and c2v1_custom. Retail does the same thing: dlc_2's chunk_22 holds c2v1, c2v2 and c2v3. The c2v1 slot (kit level H) stays byte-identical, so the box costs no map slot. A second folder such as dlc_00 is worse because:

  • it would need its own dlcid (SearchDLC drops a duplicate id, 0xabe2c6);
  • it would need its own 886 MB texdb link, sound packs and pages.

Not yet seen in the game. Static analysis covers every step up to the spawn. The whole route depends on the dev menu command branch (mods/tnc_devmenu_fix), and that branch is itself still unconfirmed in game.

Research, step by step

"Read" means the result comes from disassembly or decompiled code of the snapshot. "Measured" means it was observed in data or in the game.

# Step Address Result Basis
1 devmap callback 0xa7e0d0 → parser 0xa7bd10 The only map-related rejection in the parser is the existence check (#2). The parser's other strings are argument errors for -spawnspot, -checkpoint, -layername and the like. read
2 Existence check 0xa7b330, called at 0xa7cd07 The check builds maps/<name> ('maps/%s' 0x26c6418) and appends '.%s'. If [0x30b54e8] >= 2 it calls only resource-manager slot +0x80, then slot +0x88. Slot +0x80 failing gives "Map %s is not present in this package". Slot +0x88 failing gives "map %s is not installed". The loose-file test ("Can't find map") runs only when the value is below 2. read
2a Value of [0x30b54e8] 0x30b54e8 2 in the snapshot. Map load sets it to 3 (0xac407d). measured (snapshot)
2b Slot +0x80 = 0xabf3d0 vtbl 0x26d2a08 Returns true if the name is in the base spec or in any DLC spec. read
2c Slot +0x88 = GetIsChunkForMapInstalled 0xabf6a0 0xabf841, 0xabf86e Spec lookup 0xabf440. For a DLC entry it logs "dlc maps are considdered installed for now". It then checks only base/ref chunks with IsChunkInstalled, which is always 1 on PC (chunklist.md). The result is true. read
3 Name lookup 0xac5d10 Strips the extension and every leading maps/, then runs a linear, case-insensitive string compare over the spec entries (stride 0x68). There is no hash and no fixed list. read
4 Base before DLC, first hit 0xabf440, 0xabf500 Searches this+8 (base) first, then the DLC list (this+0x30, 0x160 per DLC) in folder-scan order. The first hit wins. Prefix '%s/%s' = DLC path + base/. Matches dlc4_cfile.md. read; DLC-vs-DLC precedence measured in game on 2026-09-24
5 Mount by name (LoadNamedResourceBlock) 0xac1730 Calls 0xabf6a0. For a DLC entry it mounts DLC sound at 0xac1a47 with the prefix, then base chunk/chunkbase, then <prefix>chunk_<chunkid>.resources and .texdb (0xac2308–0xac241c). Refchunks are mounted from base/ (0xac24ef loop). read
6 The map needs its mapresources 0xac217b, 0xac27a9, 0xac281d Formats 'generated/buildGame/%s.mapResources' and looks it up in the mounted containers. If it is missing: "The map %s isn't present in the cache file" and the load is aborted. Retail stores the name in lower case, so the lookup is case-insensitive. read
7 Other resources named after the map strings + refs '%s/_combo/%s.proc' 0x26c64b0; '_combo/_world.tome' 0x381d78; '_combo/sky.bmodel' 0x381b9f; '_combo/_world.bmodel' 0x26062e0; '_combo/_world.bshadows' 0x381fcf; '/_combo/world.hkshape' (fn 0x4b0700); '_combo/_world.pvs' 0x2651bc8; '%s/%s.ambientsh' 0x75a4a2; '%s/mega.decl' (MapInit 0x11b55f0); 'generated/staticstreamtree/%s.bsstree' 0x2606448; '/devmapinfo.json' (0xafcc20, only on the -checkpoint path); 'maps/%s/lightprobes/%s_row.bimage' (per light-probe entity; the box has none). The .prockd and .hknavmesh names follow the retail pattern; I found no format string for them. read
8 Side file textures.cache 0xac40a7–0xac40c9 '%smaps/%s/textures.cache' = <dlc>/base/maps/<name>/textures.cache → MountMemoryDatabase 0x793090. If the file is missing: warning "Failed to open", then return without popping the heap it pushed, so the heap stack loses one slot per load. The box needs this file under its own name. read
9 Virtual texture pages 0x8457cb–0x845871 '%s%s/%s.pages' = DLC prefix + virtualtextures/ + the material's landpagefile. That file name comes from the mega.decl text, not from the map name. The box keeps c2v1's landpagefile, so it reads dlc_0/virtualtextures/maps/game/dlc/c02/c2v1.pages, which already exists. The _vmtr pages (0xac5471) are optional (file-exists test first). read
10 Sound 0x8cb91f, caller 0x8cc6a7 prodspec has no entry for the map, so the game logs "[SOUND] No banks found for map '%s'" (a warning). The caller ignores the result. The box therefore has no map-specific banks; global sounds still play. read
11 MapInit with no chapter part resolver call 0x11b6733, writes 0x11b6798–0x11b6818 0xDF5860 matches the map name first; no part names game/wolfsdk/box, so it returns false. Chapter, variation and part stay 0, because each load gets a fresh game: AllocGame 0x11a7aa0 → 0x11ade60 zeroes +0x163a08/10/18. The playerDef comes from the worldspawn's reflected playerDef field (+0x930, record 0x20eaea0; set at 0x11b55f0, decomp line 1248). That field is null here. read
12 Player with null playerDef SetupPlayer 0x11bb7b9–0x11bb7f3 Falls back to entityDef "player". It is fatal ("Failed to load player entityDef") only if that decl is missing. It is in gameresources.resources. Mission init 0xf973b0 tests part and variation for 0. No chapter or variation data is needed. read; the player decl's presence was measured (archive index)
13 An extra name in dlc_0's spec does not break startup installed dlc/dlc_0/base/packagemapspec.json Lists game/dlc/c02/c2v1_custom as well as c2v1 since 2026-09-24. The kit levels have loaded with it since then. measured (indirect)

Gaps: 0xabf3d0 and 0xabf6a0 were read from disassembly, not run. SearchDLC (0xabdcf0) was not re-traced; it is taken from dlc4_cfile.md and r2_mapnodlc.md. There it is measured by log order and a screenshot-confirmed run.

What was built

python tools/build_boxmap.py takes about 2 minutes and builds twice. --once builds once. Output in D:/wolf-decomp/tmp/boxmap/box/:

File Content
dlc_0/base/chunk_22.resources 147,335,539 B, sha256 1fc43560a43cb6f833c0261bfda1245b54cddcb2546946645c92ef84c167a58f. It is kit level H (sha cd7e9340…, identical to the installed dlc_0 chunk) plus 29 added entries. Nothing was replaced or removed.
dlc_0/base/packagemapspec.json c2v1_custom and c2v1 as mapinstall writes them, plus {"name": "game/wolfsdk/box", "chunkid": 22, "basechunkid": 6, "layer": -1, "refchunks": [9, 13]}, patchlevel 3
dlc_0/dlcinfo.json {"dlcid": 4}
side_files.json The 14 dlc_2 side files mapinstall already links, plus one new link name: base/maps/game/wolfsdk/box/textures.cache → dlc_2's base/maps/game/dlc/c02/c2v1/textures.cache
box.glb The room as glTF: 6 nodes, so it can be opened in Blender
devmenu_entry.txt, manifest.json The dev menu item, plus hashes, added names, engine-name evidence and check results

The 29 entries:

  • 17 map-level c2v1 entries copied under the new name:
    • maps/game/wolfsdk/box.entities
    • .../box/_combo/box.proc
    • .../box/box.prockd
    • generated/buildgame/game/wolfsdk/box.mapresources
    • _world.tome (0 B, as in H) and -metadata.json
    • box.ambientsh, box.hknavmesh, devmapinfo.json
    • mega/megatrans/megafoliagetrans.decl
    • _world.bmodel and sky.bmodel (40 B each in H)
    • _world.pvs
    • world.hkshape (c06p2's, as in H)
    • generated/staticstreamtree/game/wolfsdk/box.bsstree
  • 12 new entries: a model and a cm for each of the 6 slabs.

The rename rule (maplevel()/rename()) takes the map's own entries:

  • maps/<m>.entities, generated/buildgame|staticstreamtree/<m>.*;
  • under maps/<m>/: _combo/*, <base>.*, devmapinfo.json, mega*.decl.

Per-entity resources stay under c2v1 (trigger cms, lightprobes, kiscules). The box has none of those entities.

The box itself is reused, not newly written code:

  • Room: inside 8 × 8 × 4 m, slabs 0.25 m thick, floor top at (5, -183, -4.5). That is the kit hall floor inside c2v1's proc areas. c06p2's world collision is ≥ 295 m away.
  • Slabs: build_gltfmap.pieces() builds them: r4 model writer, box cm with contents | 0x18 (variant D), megatexturedModel = false, material textures/common/blockout_gray, one .proc texel each (variant H recipe).
  • .entities: H's worldspawn verbatim; player_start_1, cloned from c2v1_ps_challenge_01 with no layer, 2 m south of the centre and 0.1 m above the floor; wolfsdk_box_light, a clone of H's point light kitmap_light_hall_fill at 3.2 m, radius 9, warm white.
  • .mapresources: H's 20,838 rows with the map-level rows renamed, the map list set to maps/game/wolfsdk/box, and 12 always-load rows.

Checks (all 31 OK, 0 FAIL; D:/wolf-decomp/tmp/boxmap/build_log.txt)

  • Container:
    • Before finalize, probe_idclhash rejects the file (negative control).
    • Finalize moves the data hash of exactly the 29 added entries.
    • Entry count is 7,130 + 29.
    • All 7,130 base entries are unchanged (payload, version, flags, dependencies), so c2v1 is still kit level H.
    • The 29 entries are each present once, as written.
    • probe_datahash +0x50 7158/7158 (the 1 mode-4 entry is skipped, as in every build). probe_idclhash +0x08 1/1 +0x20 1/1.
  • Naming: naming_problems() returns [] on the built container. It checks four things:
    • every map-level c2v1 entry has a copy under the new name;
    • no mapresources row of the box still names a map-level c2v1 resource;
    • every such row exists renamed, and the map list is the new name;
    • the box's text payloads do not contain game/dlc/c02/c2v1. The only allowed exception is the mega*.decl page reference (#9).

The controls each fail as they should: - A: box.ambientsh left under the old name only; - B: its mapresources row left on the old name; - C: the old map path inside the box .entities.

Separately, all 14 engine-derived names from the format strings exist under game/wolfsdk/box. _world.bshadows is missing on purpose, as it is in H, which loaded in game. - .entities: - byte-exact round trip; - build_custom_map.check finds nothing (996 entityDefs mounted through the new spec); - exactly 1 worldspawn, 1 start, 1 light and 6 static instances; - every slab model resolves, and every cm resolves "exact" to our own cm; - the start and the light are inside the room; - the 6 collision boxes equal the designed slabs (closed room). - .mapresources and .proc: base rows kept in order with only the map-level ones renamed, plus 12 always-load rows; the only unresolved map-level row is _world.bshadows, exactly as in H; the .proc keeps all base records and gains 1 record per slab. - Determinism: two builds give the same sha256.

Install (game closed; Freedom Chronicles still required)

wolfsdk/mapinstall.py and the devmenu builder belong to others, so here is what they would need:

  1. mapinstall.py:
    • let install() write the box entry as a third spec map (or take the spec from the build);
    • add one hardlink: dlc_0/base/maps/game/wolfsdk/box/textures.cache → dlc_2/base/maps/game/dlc/c02/c2v1/textures.cache;
    • record both in wolfsdk_karte.json, so uninstall recognises them.

After that: python -m wolfsdk map-install D:\wolf-decomp\tmp\boxmap\box\dlc_0\base\chunk_22.resources. 2. tools/build_devmenu_fix.py: add the item below to devmenuoption/main and raise num from 3 to 4. Field order and quoting are the same as the existing campaign command entries.

item[3] = {
    devMenuDisplayName = "WolfSDK: Box";
    devMenuCommandStrings = {
        num = 7;
        item[0] = "si_spawnspot \"player_start_1\"";
        item[1] = "si_nextlayeractive \"layer/dlc/c2v1\"";
        item[2] = "si_filllayeractive \"\"";
        item[3] = "si_devprogression \"\"";
        item[4] = "si_checkpointName \"\"";
        item[5] = "si_gamemode 0";
        item[6] = "devmap game/wolfsdk/box";
    }
}

layer/dlc/c2v1 loads the same layered preload rows as in the kit-level tests. The box's own entities have no layer.

Manual route until then (PowerShell)

Revert the mods in the loader first: mapinstall forbids creating files in dlc_0 while tncpatch journals it.

$g = "<Steam library>\steamapps\common\Wolfenstein.II.The.New.Colossus\dlc"
$b = "D:\wolf-decomp\tmp\boxmap\box\dlc_0\base"
Copy-Item "$g\dlc_0\base\packagemapspec.json" "D:\wolf-decomp\tmp\boxmap\spec_before.json"
Copy-Item "$b\chunk_22.resources" "$g\dlc_0\base\chunk_22.resources.new"
Move-Item -Force "$g\dlc_0\base\chunk_22.resources.new" "$g\dlc_0\base\chunk_22.resources"
Remove-Item "$g\dlc_0\base\packagemapspec.json"; Copy-Item "$b\packagemapspec.json" "$g\dlc_0\base\packagemapspec.json"
New-Item -ItemType Directory -Force "$g\dlc_0\base\maps\game\wolfsdk\box" | Out-Null
New-Item -ItemType HardLink -Path "$g\dlc_0\base\maps\game\wolfsdk\box\textures.cache" -Target "$g\dlc_2\base\maps\game\dlc\c02\c2v1\textures.cache"

Never open the hardlinked files for writing. To replace one, delete it first and then copy. Undo:

  • copy re_probes\kitmap\variants\H\chunk_22.resources back the same way;
  • put spec_before.json back;
  • Remove-Item -Recurse "$g\dlc_0\base\maps\game". This only unlinks the link; dlc_2's file stays.

Until it is restored, the loader's uninstall will name the changed chunk and spec as unknown.

In-game test

  1. Apply the mods (with the box item in tnc_devmenu_fix) and start the game. Open the dev menu → "WolfSDK: console test". The console must show g_debugLayerChanges = 1. If it does not, the command branch does not work and the box test means nothing.
  2. Dev menu → "WolfSDK: Box".
    • Pass: you spawn in a closed grey room (8 × 8 × 4 m) lit by one warm light, can walk, do not fall, and cannot leave through the walls.
  3. Afterwards type condump boxmap1.txt in the console and send the file from Saved Games/.../base/. Lines that explain a failure:
Log line Meaning
Map game/wolfsdk/box is not present in this package spec not installed
map ... is not installed the installed check in step 2c failed
The map ... isn't present in the cache file the old chunk is still in dlc_0
MountMemoryDatabase: Failed to open ...box/textures.cache the link is missing
[SOUND] No banks found for map 'game/wolfsdk/box' expected, harmless
Failed to load player entityDef the player fallback broke

Falling through the floor means a collision problem. A black room means a lighting problem.

Variant B if campaign mode misbehaves: use si_gamemode 5 plus an extra line si_mainmenustart 1, which is what the c2v1 entries use.

Not proven (worst first)

  1. The dev menu command branch, and devmap itself, have never run in game. All of r8's analysis is static.
  2. A non-retail map name has never been loaded: steps 1–12 are static only.
  3. New model/cm entries have never been loaded in game. This is DESIGN.md risk 1, the same as the build_gltfmap build.
  4. Campaign mode (si_gamemode 0) with no chapter part on a DLC-chunk map:
    • the player becomes the generic player entityDef, with that decl's default inventory;
    • whether the game makes an initial autosave for a chapterless map is unknown.
  5. Lighting: borrowed lightmap texels plus one dynamic light. The room may look blotchy or dark (variant G looked blotchy).
  6. No map sound banks (the warning from step 10). Ambience will be silent.
  7. Static reading: the heap-stack leak when textures.cache is missing is inferred from decompiled code. The link avoids that case, so it is not tested.

No fallback into the c2v1 slot was built, because the new name is not ruled out. If the box fails at steps 2–6 (one of the "not present", "not installed" or "cache file" lines above), the same pieces can go into c2v1.entities the way the kit level does, launched with the existing "Death is Coming (C2V1)" dev menu entry.

Related: Research Report: Chunklist, Research Report: Dlc4 Cfile, Research Report: R2 Mapnodlc, Research Report: R8 Devmenu Fix Verify, Research Report: R10 Modtest Map, TNC Custom Map Status, DLC Overrides.