Wolfenstein II ships with three released DLCs. Each registers via its own packagemapspec.json and brings its own chunk_<id>.resources. If such a chunk can overwrite an existing asset, then the entire patch machinery for Part 2 becomes optional: a mod would then be a folder you drop in and take out — without backup, without journaling, without rollback, without a single write operation to the 40-GB installation.
All of this is lifted read-only from the unmodified Retail installation at <Steam library>\steamapps\common\Wolfenstein.II.The.New.Colossus and …\Wolfenstein.The.New.Order. Reproducible with:
python tools/dlcmod.py messung # the decisive measurement
python tools/dlcmod.py felder # packagemapspec fields, with prediction tests
python tools/dlcmod.py selbsttest # the archiver builder
python tools/dlcmod.py bauen --ziel <folder outside the Steam library>
Grades like those in docs/patchvorrang.md: MEASURED (read from files), DEDUCED (inferred from structure), SPECULATED (plausible, not secured).
0. Answer with Evidence Grade
Short: Not determinable from the files — and for a reason that is itself an outcome: the three released DLCs do not overwrite a single asset. They double. In 7,733 instances, the same
(Type,Name)pair exists in both a DLC chunk and a base archive, and in 7,733 instances the content is bit-identical. There is therefore no released precedent case from which to read the precedence rule.What the 7,733 instances do show: a name collision between a DLC chunk and the base archive is in this engine not an error case, but everyday occurrence. The engine has a resolution rule — otherwise it could not load the three DLCs. Only open is how that rule reads.
| # | Finding | Grade |
|---|---|---|
| 1 | 7,733 (Type,Name) overlaps between DLC chunk ↔ base archive, 0 with differing data_hash |
MEASURED |
| 2 | The engine keeps these 7,733 collisions out of the Retail game. A collision is not an error. | MEASURED |
| 3 | Exactly one pair in the entire installation where a DLC chunk and a Patch container carry different content: perks:perk/player/sp/grenadier_fc_base |
MEASURED |
| 4 | refchunks literally means "dependency chunks" in the Exe: an registered refchunk is not doubled in the DLC chunk (15 remaining cases), a non-registered one is (1,495 cases) |
MEASURED |
| 5 | gameresources and chunkbase_6 are not meaningfully doubled by any DLC (11 vs. 0 cases respectively) — they are always mounted |
MEASURED |
| 6 | layer is not f(basechunkid): basechunkid 6 carries layer 1 in the base game, layer −1 in the DLC. The 1:1 coverage from Patch-Precedence.md applies only within base/. |
MEASURED, correcting a previous statement |
| 7 | The Exe knows an entitlement check for DLCs (idEntitlements::Get DLC %d not installed) with exactly three named keys ENTITLEMENT_DLC1..3 — contrary to docs/ladepfade.md, which notes "no visible ownership check" for Part 2 |
MEASURED, correcting a previous statement |
| 8 | The DLC virtual textures overwrite nothing: they land in their own quadrant (vt_useDLCVmtrPageFiles) |
MEASURED |
| 9 | There can always be only one DLC sound container mounted simultaneously (MountDlc: another dlc already mounted) |
MEASURED |
| 10 | Part 1 has no packagemapspec.json equivalent. Instead, master.index — a pure file list without map names, layers, or refchunks. |
MEASURED |
Runtime Addendum, September 22, 2026
The controlled gameplay test now yields a narrower, more reliable answer than the pure file analysis:
- A newly built
dlc_4is detected:found dlc id 4 at ../dlc//dlc_4,SearchDLC: found 4 dlcs. The ownership check does not block Discovery. resource_dlcDbgSearchPathcannot be set in this Retail build; the log reportsUnknown command 'resource_dlcDbgSearchPath'.- A
refchunks: [26]forc02p0actually requestschunk_26. However, a deliberately different but valid card Canary (c02p0.entities,...100000→...900000) was not used: the log still shows...100000. The primarychunk_1therefore wins against an additionally mounted Refchunk. MEASURED. - A freshly built IDCL container is strictly validated before loading. It requires the second
IDCLdirectly following the metadata pools and a correct FarmHash64 at Header+0x20. Both are now present in the builder. - Header
+0x08is also actively checked; its algorithm remains undisclosed. The engine reports the calculated 64-bit value in the log upon deviation, thereby creating a targeted oracle, but no general formula exists yet.
Current Conclusion: An additional Refchunk is not an override path. The potential path via a DLC chunk selected as primary remains verifiable only when Header +0x08 can be calculated universally. All test files have been removed from the game folder and the original packagemapspec.json has been byte-for-byte restored.
1. The Decisive Measurement
python tools/dlcmod.py messung. All 24 base archives (178,077 entries, 167,694 unique pairs) against the three DLC chunks.
| DLC / Chunk | Entries | Also in Base | Content Same | Content Different |
|---|---|---|---|---|
dlc_1/chunk_20.resources |
13,366 | 2,422 | 2,422 | 0 |
dlc_2/chunk_22.resources |
6,985 | 1,326 | 1,326 | 0 |
dlc_3/chunk_24.resources |
12,754 | 3,985 | 3,985 | 0 |
| Sum | 33,105 | 7,733 | 7,733 | 0 |
MEASURED. The statement is complete; no sample: every single one of the 33,105 DLC entries was checked against the base index.
data_hash is content-dependent — the cross-check in tools/dlcmod.py unpacks 60 overlapping pairs from dlc_1/chunk_20 and the respective base archive and compares them byte-by-byte: 60 of 60 bit-identical. Thus, "same data_hash" here truly means "same content" rather than just "same length". MEASURED.
The Types of Overlap
The 7,733 are not an anomaly but precisely what a level needs:
cm 3119 image 1837 model 1395 material 591 anim 215 sound 118
entityDef 56 decalatlas 56 perks 74 particle 50 md6Def 30 …
Collision models, images, models, materials — geometry and surfaces appearing in multiple chapters. A DLC chunk is a self-sustaining copy of everything its maps need and what isn't mounted anyway.
Why This Does Not Answer the Question — And What It Is Still Worth
From 7,733 content-identical collisions it does not follow that the engine prefers a copy when content differs, nor that it does not. However, three things follow, and this is no comfort but substance:
- A collision is not an error case. Anyone fearing that a self-built DLC chunk with an already existing name could drive the engine into
resource '%s' of type '%s' is orphanedorcontainer entry defaulted: this happens in the Retail game 7,733 times per DLC map. MEASURED. - The resolution rule exists and runs. Every time someone plays Gunslinger Joe, the engine decides between two containers 2,422 times. UNLOCKED.
- The attempt is cheap. It requires no rebuilding of a base archive and no backup — just a folder that can be deleted again.
2. The One Case Where Two Containers Conflict
Beyond perks 7 and 733, there is exactly one pair where a DLC chunk differs in content from another provided container — not from a base archive, but from a patch layer:
perks : perk/player/sp/grenadier_fc_base
chunk_16 263 B 2017-11-03 hash 189cd9c94538365b
dlc_1/chunk_20 263 B 2017-12-07 hash 189cd9c94538365b <- identical to chunk_16
patch_3_chunkbase_6 322 B 2018-02-24 hash ca35f0735b7b555b <- divergent
The difference, unpacked and diffed (MEASURED):
regionUnlockName = "#str_perk_grenadier_fc_tracking";
+ activateOnPerkItem = true;
+ item = "player/perkitem";
The timeline explains it completely. dlc_1 was built on 2017‑12‑07 — which is bit-exact the date of the most recent entry in patch_2. Thus, it took on the content valid at that time. patch_3 (2018‑02‑24) added two fields to the perk after that. And dlc_1 reports patchlevel 2.
RESOLVED, by backtracking across all three DLCs:
| DLC | patchlevel |
most recent entry in Chunk | most recent entry in Patch Layer |
|---|---|---|---|
dlc_1 |
2 | 2017‑12‑07 | patch_2: 2017‑12‑07 |
dlc_2 |
3 | 2018-01-25 | — (between patch_2 and patch_3) |
dlc_3 |
3 | 2018-02-24 | patch_3: 2018-02-24 |
Thus, patchlevel in a DLC spec is the search upper bound for patch layers when loading a map from this spec — the same meaning as in base/packagemapspec.json (docs/patchvorrang.md, Finding 7), but applied card-locally. Under this interpretation, the contradiction is none: patch_3_chunkbase_6 is not sought at all for a dlc_1 map, and thus dlc_1 brings the version fitting patchlevel 2.
The flip side is important for us: a self-built dlc_4, which declares a Base Map but reports an insufficiently low patchlevel, would strip its patch layers from that map. Therefore, both provided specs list patchlevel: 4 — the same value as in base/.
(CONJECTURED whether patchlevel applies per spec or globally takes the maximum. patchlevel: 4 is harmless under either interpretation.)
3. The packagemapspec Fields — with Prediction Tests
python tools/dlcmod.py fields. 41 map entries: 31 from base/, 10 from the three DLCs. basechunkid, chunkid, isbasechunk, layer, name appear in all 41; refchunks only in 7 (4 × dlc_1, 3 × dlc_2).
| Field | Meaning | Status |
|---|---|---|
name |
Map name, as loaded by the game | MEASURED |
chunkid |
In which chunk_<id>.resources/.texdb the map lies; 0 = gameresources |
MEASURED |
basechunkid |
Common base archive: 0 = gameresources, 6 = chunkbase_6 |
MEASURED |
isbasechunk |
Only common and init, both chunkid 0 |
MEASURED |
refchunks |
Dependency Chunks: in addition to mounted chunks | MEASURED, see 3.1 |
layer |
Load layer. See 3.2 — the previous interpretation was too narrow. | PARTIALLY REFUTED |
patchinfo.patchlevel |
Search upper bound for patch_N layers |
RESOLVED, see 2 |
3.1 refchunks — the prediction that holds
The exe names it. 0x1426CF933, MEASURED:
idResourceManagerLocal::GetIsChunkForMapInstalled: dlc maps are considdered
installed for now %s, but checking dependency chunks
From this, the verifiable prediction: a chunk registered as refchunks will be mounted — thus the DLC chunk does not need its own copy of its assets. A chunk not registered must be duplicated.
Tested on the three chunks from which all three DLCs draw (MEASURED):
chunk_9 |
chunk_12 |
chunk_13 |
registered | |
|---|---|---|---|---|
dlc_1 |
10 | 4 | 0 | 9, 12, 13 |
dlc_2 |
0 | 127 | 1 | 9, 13 |
dlc_3 |
692 | 459 | 217 | none |
Six cells, six hits. Logged in → 0–10 copies. Not logged in → 127 to 692. dlc_2 is the sharpest case: the same DLC doubles from chunk_12 twelve times and exactly once from the two logged-in chunk_9/chunk_13.
Overall picture across all three DLCs: 15 copies from logged-in refchunks, 1,495 from non-logged-in.
The 15 remaining cases are explained, not dismissed. All 14 from dlc_1 are image entries with $streamed in the name:
image models/food/textures/icecream_01.tga$mtlkind=albedo$streamed
image models/modules/neworleans/doors/textures/doorknob_01.tga$…$streamed
$streamed images do not carry their payload data in the archive, but in streamed.resources (docs/streamed.md); the archive entry is a stub. SPECULATED: such a stub must reside in the container from which the map loads, and is therefore excluded from refchunk savings.
3.2 layer — the previous interpretation was too narrow
docs/patchvorrang.md notes: "layer matches basechunkid 1:1, without exception across all 31 maps." Across all 41 entries this is no longer true (MEASURED):
layer=-1 basechunkid=6 dlc 10 entries
layer= 0 basechunkid=0 base 9 entries
layer= 1 basechunkid=6 base 22 entries
basechunkid 6 carries two different layer values. The 1:1 match applies only within base/; layer −1 is a separate value led exclusively by DLC maps.
What layer is remains open. The Exe has the Cvar resource_ignoreLayers with the description "ignore layer bits and load all layers during map loads" (docs/patchvorrang.md, Section 1) — Layer Bits, i.e., a bitmask. SPECULATED: −1 is the mask "all bits set" and means "no layer restriction", which fits a DLC that is not part of the base game's chapter streaming. Not proven.
3.3 What is mounted without being logged in
The doubling numbers say it directly (MEASURED):
| Target Archive | Total Duplications from all three DLCs combined |
|---|---|
gameresources |
11 |
chunkbase_6 |
0 |
| logged-in refchunks | 15 |
present only in patch_* |
4 |
non-logged-in chunk_* |
7,703 |
| Sum | 7,733 |
ELUCIDATED: gameresources and chunkbase_6 are mounted for every map, so no one duplicates them. This is the decisive number for a mod: the seven table:playerdamage/* entries lie exclusively in gameresources — i.e., in exactly the container every map brings along that no DLC has ever duplicated. Whether a DLC chunk can override it is thus the ultimate untested case.
4. What the Exe Says About the DLC Path
NewColossus_x64vk.exe, 58,062,032 bytes, .text SteamStub encrypted. Readable is .rdata. All addresses MEASURED, Virtual Addresses:
The SearchDLC Block
0x1426CF690 resource_dlcDbgSearchPath
0x1426CF6E0 %s/dlcinfo.json
0x1426CF730 %s/base
0x1426CF738 SearchDLC: Could not load mapspec for dlc id %d from %s
0x1426CF770 SearchDLC: could not read existing dlc info file: %s
0x1426CF7A8 dlcid
0x1426CFAF0 SearchDLC: found %d dlcs
0x1426CFB30 found dlc id %d at %s <- new, the success line per DLC
0x1426CFB48 ../dlc/
found dlc id %d at %s has previously appeared in no document. This is the line where one sees in the log per DLC that it was recognized, with ID and path — more precisely than the summary line found %d dlcs.
No ownership check exists in this literal block. MEASURED.
The Installation Check
0x1426CF8E3 GetIsChunkForMapInstalled: can't find chunk for map %s
0x1426CF933 GetIsChunkForMapInstalled: dlc maps are considdered installed
for now %s, but checking dependency chunks
0x1426CF9C3 GetIsChunkForMapInstalled: chunk %d for map %s is not installed
0x1426CFA43 GetIsChunkForMapInstalled: chunk %d is a dlc and base chunk %d
is not in fast storage for map %s
MEASURED. The engine explicitly tracks that a chunk is "a dlc" and checks the associated basechunkid. The message can't find chunk for map %s appears when a map name lacks a Spec entry — this is the first error that would trigger an incorrectly constructed dlc_4.
The Ownership Check That Exists for Part 2
docs/ladepfade.md states that the TNC path contains "no visible ownership check." This holds true for the SearchDLC block. However, elsewhere in the executable, it is clearly present (MEASURED):
0x1426DBD10 idEntitlements::Get DLC %d not installed
idEntitlements::Get DLC %d installed
idEntitlements::Get entitlements are empty
New DLC installed
.?AUCCallbackInternal_OnDLCInstalled@idEntitlements@@
and, with exactly three named identifiers:
GDM_CONNECTION_TO_HOST_DENIED_MISSING_ENTITLEMENT_DLC1 / _DLC2 / _DLC3
GDM_KICKED_MISSING_ENTITLEMENT_DLC1 / _DLC2 / _DLC3
GDM_DLC_ERROR_REMOVED / _MISSING_GENERIC / _CORRUPT
SAVEGAME_E_DLC_NOT_FOUND
idDeclChapter::DLC_CHAPTER_PRESENCE_00 / _01 / _02 / _03
ENTITLEMENT_DLC exists only with the digits 1, 2, and 3 — MEASURED, across the entire executable. DLC_CHAPTER_PRESENCE has four slots, from 00 to 03.
UNCOVERED: There is an entitlement layer, and it is hardwired for three entitlements. Whether SearchDLC queries it during mount is recorded in .text but is not measurable. This is the one risk that cannot be seen with a dlcid: 4 — and the reason why the guide below searches the log precisely for this.
Sound and Virtual Textures
0x14268C377 MountDlc: Could not mount dlc sound containers for %s
0x14268C587 MountDlc: another dlc already mounted (%s) while mounting %s
MountDlc: dlc %s already mounted
MountDlc: mounting %s
UnmountDlc: unmounting %s
MEASURED. There can only ever be one DLC sound container mounted simultaneously. This matches the file layout: each DLC has a complete, independent base/sound/soundbanks/pc/ with the same filenames as the base game (sound.pack, english(us).pack, prodspec.json, wwise_project.bin) and its own prodspec.json with patchlevel: 0 containing only the banks for its own maps. UNCOVERED: The DLC sound path replaces the base game's path for the duration of the DLC map — this is the only measured location where a DLC actually displaces a base game resource, and it does so via the file path, not the resource container.
For virtual textures, it is reversed. 0x142679478/0x1426794B8, two strings immediately adjacent, MEASURED:
"Loads the dlc vmtr list for storing pages in the dlc quadrant."
vt_useDLCVmtrPageFiles
(The mapping of Description↔Name here is unusually secure: in the same block directly before stands "Loads the intro vmtr list for storing pages in the first quadrant." / vt_useIntroVmtrPageFiles, and directly after are two further pairs in the same order, description then name.)
UNCOVERED: dlc_1/virtualtextures/maps/game/dlc/c01/*.pages is not a replacement for the base game's virtualtextures/, but rather an additional page source in its own quadrant of the physical page buffer. A DLC does not overwrite anything here either. For a dlc_4 that brings no new maps, the folder is simply superfluous — which is why the built package omits it.
5. Part 1 — no packagemapspec.json, but master.index
MEASURED, WolfNewOrder_x64.exe and …\Wolfenstein.The.New.Order\base\:
- The strings
packagemapspecandmapspecappear 0 times in the executable. - There is no
packagemapspec.jsonon disk. - Instead:
master.index, 520 bytes, Magic\x03SER, followed by a u32 (big endian)14and 28 length-prefixed names:
chunk0.index chunk0.resources chunk1.index chunk1.resources …
chunk13.index chunk13.resources
This is a pure file list — no card names, no layer, no refchunks, no patchlevel. It includes gamechunktoinstallchunk.gic (678 bytes, Magic \x02CIG), which maps game chunks to install chunks.
OPEN: Part 1 has no equivalent for packagemapspec.json. The map-to-chunk assignment is not in a plaintext file, but in the .index files and the .gic. Therefore, a Part 1 DLC cannot "register" anything — it can only carry packages that the engine opens via OpenDLCFileHandles.
The hurdle remains that from docs/ladepfade.md E7: info.txt with appID and dlcID, and the message User does not own this DLC. There, ownership verification is explicitly stated in the literal block of the Mount function — whereas in Part 2 it resides in a different translation unit (idEntitlements).
Conclusion for Part 1: The DLC path there is not cheaper than in Part 2, but rather more expensive — more guessing involved (the info.txt dialect, four versions in tools/dlcinfo.py), an additional verified ownership check, and no spec format through which something could be registered. Part 2 is the path that should be taken.
6. The built package dlc_4
python tools/dlcmod.py build --target <folder>. This tool refuses to write into the Steam library; placing it there is a manual step for the user.
dlc_4/dlcinfo.json 19 Byte { "dlcid" : 4 }
dlc_4/base/packagemapspec.json 233 Byte
dlc_4/base/chunk_26.resources 90 172 Byte 7 entries, all uncompressed
dlc_4/base/chunk_26.texdb 32 Byte empty
stufe_b/packagemapspec.json Exchange file, see 7
stufe_c/packagemapspec.json Exchange file, see 7
Content: the seven table:playerdamage/* from mods/tnc_erste — the multiplier for incoming player damage, set to 0 in all seven difficulty tables. Nothing new invented; the tool reads mods/tnc_erste/mod.json and applies the same wolfsdk.decl.apply_patch rule as the regular patch path.
{ spline clamp min 0.5 max 0.5 … } -> { spline clamp min 0.0 max 0.0 … }
All seven replacements are byte-identical — csize and usize remain as they were. The tool aborts if a replacement changes the length.
The selected identifiers
dlcid: 4. Released are 1, 2, 3 (dlc_1/2/3), so 4 is the first free one. It collides with neither an existing folder nor any identifier provided by the game. The known risk: the entitlement layer knows only ENTITLEMENT_DLC1..3 (Section 4). If SearchDLC queries it, dlcid 4 fails — and exactly that appears in the log (idEntitlements::Get DLC 4 not installed). The attempt thus answers the question even when it fails.
The alternative would be to use an occupied identifier (1, 2, or 3) — but this would mean competing with a released DLC for the same identifier (found dlc id %d at %s suggests a mapping from identifier to path). Try only after dlcid 4 fails at entitlement, and then with the knowledge that the path is no longer interference-free.
chunkid: 26. Occupied are 0 (gameresources), 1, 3, 4, 5, 6 (chunkbase_6), 7–16, and the DLC chunks 20, 22, 24. 26 continues the two-step sequence of DLCs and leaves 21/23/25 free, should the engine expect partner files there.
What the tool does not compute
Three fields tools/dlcmod.py cannot calculate, and this is also stated in the source text:
data_hashandhash_0x60of the entries. The algorithm is unknown (wolfsdk/idcl.py: neither CRC32/64, Adler32, FNV-1a, Murmur, xxHash64, MD5, SHA-1, FarmHash Fingerprint64 nor CityHash64 over stored or unpacked bytes).tools/probe_tnc_hash.pyadditionally checked Type/Path combinations and both halves of CityHash128: 2,000 uncompressed Retail entries, 0 hits on both fields, including byte order. The EXE contains the CityHash constantsk1/k0at file offset0x25C8330/0x25C8338; nevertheless, it is demonstrably not using the direct standard form. Therefore, the built entries carry the hashes of the originals — that is, hashes that do not match the new content. This is precisely the same state as with the regular In-Place path, which loaded flawlessly in Part 1 with 373 patched assets (verified). Unverified for Part 2. IfresourceStorage_checkDataCheckSumtriggers, the log showscontainer entry defaulted(0x1426CDDF8).- Header hash at
+0x08. This is actively checked upon mounting and causescontainer ... has corrupt headeron deviation. The algorithm remains open; however, the Engine outputs the calculated value in the log.+0x20is resolved: FarmHash64 from the entry table (0x78) up to and including the secondIDCLmarker. - No dependencies.
chunk_26reportsnum_dependencies = 0. No released archive does this (MEASURED, all 24 have some), but all seven entries havenum_deps = 0ingameresourcesthemselves, so an empty dependency table is structurally sound. Unrecorded.
The self-test (python tools/dlcmod.py selbsttest) checks what is verifiable: the builder writes an archive that wolfsdk.idcl.Archive — the same parser that reads the 24 Retail archives — fully re-reads, with correct types, names, payload data, and shared pool strings; and the replacement remains length-neutral.
7. The Guide
First, once: Enable log file. Part 2 otherwise writes no qconsole.log (docs/ladepfade.md). Start parameters:
+logFile 1 +logFilePersistent 1
The log lands under %USERPROFILE%\Saved Games\MachineGames\Wolfenstein II The New Colossus\base\qconsole.log.
Retrieve baseline value first: start without dlc_4 and search for SearchDLC: found 3 dlcs in the log. If a different number appears, the initial state is incorrect and everything else is uninterpretable.
Stage 0 — no file at all
+resource_dlcDbgSearchPath "C:/wolfdlc"
If the log subsequently shows SearchDLC: found 0 dlcs instead of 3, the Cvar has indeed moved the search path — and the entire attempt can occur on C:\wolfdlc\ without a single file in the Steam folder. If this works, use this path for everything that follows and read <SearchPath> below instead of …\Wolfenstein.II.The.New.Colossus\dlc.
Stage A — place it, do not register (safe)
Copy dlc_4/ unchanged to <SearchPath>. The included packagemapspec.json reports a custom, non-existent map (game/dlc/c04/c4v1) and collides with nothing.
What Stage A answers:
- Is a self-built DLC ever found and its Spec accepted?
- Are DLC chunks mounted globally? If yes, the invulnerability works immediately and everywhere — and then the entire question is answered without ever touching a base map.
| In Log | Meaning |
|---|---|
SearchDLC: found 4 dlcs |
Found. The spec was accepted. |
found dlc id 4 at <path> |
ID and path confirmed. |
SearchDLC: found 3 dlcs (unchanged) |
The folder was not seen. Wrong location, or dlcinfo.json is unreadable. |
SearchDLC: could not read existing dlc info file: <path> |
dlcinfo.json found, but unreadable/unparseable. |
SearchDLC: Could not load mapspec for dlc id 4 from <path> |
Folder OK, packagemapspec.json rejected. Tinker the JSON, not the folder. |
idEntitlements::Get DLC 4 not installed |
The entitlement layer is active. dlcid 4 is not possessed. This is a valid result: the interference-free path then leads nowhere. |
Then start any mission and take a hit:
- No damage → DLC chunks are globally mounted and override
gameresources. Both open questions answered at once, and Mods for Part 2 are now just a folder. - Normal damage (with
found 4 dlcs) → the DLC is found, but its Chunk is not mounted for foreign maps. Expected. Continue with Level B.
Level B — register an existing map
Copy stufe_b/packagemapspec.json over dlc_4/base/packagemapspec.json.
It reports game/wolf/c01/c01p1 — the same map that base/ also
reports, but with chunkid 26 and refchunks: [1], so that chunk_1 (where
the map actually resides) is still mounted, and patchlevel 4 like in
base/.
Then restart (do not load — a savegame can store values between runs), start Chapter 1 via the chapter selection, and take the first hit.
| Observation | Conclusion |
|---|---|
| No damage | A DLC Chunk overrides. The DLC Spec entry displaces the Base one, and chunk_26 beats gameresources. The answer to the title question is Yes. |
| Normal damage, map loads cleanly | The DLC entry is not prioritized, or gameresources wins. Answer: No. |
| Map does not load / missing Assets | The DLC entry has displaced, but the refchunk contributes nothing. The mechanism works, the recipe is wrong. Try again with refchunks: [1, 0]. |
GetIsChunkForMapInstalled: can't find chunk for map game/wolf/c01/c01p1 |
Both Spec entries are mixed up. Level C. |
SearchDLC: Could not load mapspec for dlc id 4 |
The spec is rejected in this form. Level C. |
container entry defaulted: table:playerdamage/normal |
The entry was found and discarded — the integrity check works, so the uncomputable data_hash fields from 6 are out. Then the path failed not on priority, but on the hash. |
resource 'playerdamage/normal' of type 'table' is orphaned |
No container knows the name anymore — the spec displaced gameresources instead of complementing it. Revert immediately. |
Level C — same map in DLC form
stufe_c/packagemapspec.json differs from B in only two fields:
layer: -1 and basechunkid: 6 instead of 0/0 — the form used by all three delivered DLCs. Try this if B fails with
Could not load mapspec or can't find chunk for map.
Revert
Delete dlc_4/. That is all. No delivered file was touched, so there is nothing to restore — that is the whole point of this path.
How to recognize that it did not work
In summary, after ascending depth of failure:
SearchDLC: found 3 dlcs— never observed.could not read existing dlc info file—dlcinfo.jsoncorrupted.Could not load mapspec for dlc id 4— spec rejected.idEntitlements::Get DLC 4 not installed— entitlement missing.can't find chunk for map …— spec accepted, mapping broken.container entry defaulted— entry found, content discarded (hash check).… is orphaned (no container contains it anymore)— the DLC was superseded rather than supplemented, and the target is now nowhere.- All quiet, normal damage — the DLC chunk loses to
gameresources. This is the clean no-answer.
8. What remains open, and which experiment decides it
In this order, each builds on the previous:
| # | Question | Experiment | Cost |
|---|---|---|---|
| 1 | Does relocating resource_dlcDbgSearchPath move the search path? |
Stage 0 | 1 start, 0 files |
| 2 | Is a custom-built DLC found? | Stage A, log line found dlc id 4 |
1 start, 1 folder |
| 3 | Does the entitlement check access dlcid 4? |
Stage A, log line idEntitlements |
same |
| 4 | Are DLC chunks globally mounted? | Stage A, tally hits | same |
| 5 | Does a DLC chunk overwrite a base asset? | Stage B | 1 start, 1 file swap |
| 6 | Is the data_hash check active? |
falls into 5 together (container entry defaulted) |
— |
Question 5 is the one everything hinges on. It cannot be decided without a game launch — the files yield 7,733 collisions and zero disagreements, and the place where the engine chooses lies in the SteamStub-encrypted .text. This is the same hard limit as in docs/patchvorrang.md, Section 4.
The difference from Patch-Precedence.md: there, the decisive experiment costs four changed bytes across two delivered archives and 129 MiB backup. Here it costs a folder that gets deleted again. If both attempts are scheduled anyway, this one should go first.
Sources
tools/dlcmod.py— all numbers in this document, plus the packerwolfsdk/idcl.py— archive format,data_hash, the hash notewolfsdk/decl.py—apply_patch, the replacement rulemods/tnc_erste/mod.json— the seven tables and their target valuesdocs/patchvorrang.md—patchlevel, patch precedence,containerType_t::PATCHdocs/ladepfade.md—dlcfolders of both games, E7/E8, partial-1 stringsdocs/streamed.md—$streamedimagesdocs/virtualtextures.md,docs/vt-planes.md—.pages, quadrants