Wolfenstein Modloader Buy me a coffeeKaffee spendieren

Wiki / Research reportsForschungsberichte

Entity-Pipeline: Custom map on Retail geometry via .entities

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

In plain wordsIn einfachen Worten

This report builds a pipeline that turns an existing map of Wolfenstein II: The New Colossus (the Gestapo office) into a custom map by editing its text-based entity file. It changes 49 things a player would notice: tougher enemies, food pickups turned into weapons and ammo, red and green lights, and swapped spawn points. The rebuilt archive passes every offline check. Whether it loads in the game has not been confirmed.

  • The entity reader and writer round-trip 85 of 85 entity files byte-exactly.
  • 49 entities are changed: 4 enemies (for example 3 light soldiers become heavy elites), 10 pickups, 33 lights and 2 spawn points.
  • Changes reuse enemy and item setups that already exist in the same map, so no new assets are needed.
  • The checker rejects 8 of 8 broken test cases; all 7,127 other archive entries stay unchanged.
  • Runtime is unconfirmed; the page includes a short install-and-test runbook.

Dieser Bericht baut eine Pipeline, die eine vorhandene Karte von Wolfenstein II: The New Colossus (das Gestapo-Büro) durch Bearbeiten ihrer textbasierten Entity-Datei in eine eigene Karte verwandelt. Sie ändert 49 Dinge, die man als Spieler bemerkt: stärkere Gegner, Essen wird zu Waffen und Munition, rote und grüne Lichter und vertauschte Startpunkte. Das neu gebaute Archiv besteht alle Offline-Prüfungen. Ob es im Spiel lädt, ist nicht bestätigt.

  • Leser und Schreiber für Entity-Dateien schaffen den Roundtrip bei 85 von 85 Dateien byte-genau.
  • 49 Entities sind geändert: 4 Gegner (zum Beispiel werden 3 leichte Soldaten zu schweren Elitesoldaten), 10 Pickups, 33 Lichter und 2 Startpunkte.
  • Die Änderungen übernehmen Gegner- und Gegenstandsdaten, die in derselben Karte schon existieren. Neue Assets sind daher nicht nötig.
  • Der Prüfer lehnt 8 von 8 kaputten Testfällen ab; alle 7.127 anderen Archiveinträge bleiben unverändert.
  • Im Spiel unbestätigt; die Seite enthält eine kurze Anleitung zum Installieren und Testen.

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-entitypipe-a2, Task entitypipe, 2026-09-23. Third run under this ID (User attempt 1 paused, User attempt 2 cut off by session limit). All numbers below are newly measured in this run; the bundle on disk was rebuilt. Files: tools/build_custom_map.py, tools/probe_entitypipe.py, re_probes/entitypipe/, this report.

Result in one sentence

re_probes/entitypipe/base/chunk_22.resources is the alias map game/dlc/c02/c2v1_custom with 49 modified Entities across four classes (Enemies, Pickups, Lights, Spawn). It consists of probe_datahash 7127/7127, probe_idclhash +0x08/+0x20 OK, and the custom checker. A diff check allows only the 49 claimed Entities as modified, and none of the other 7127 entries are changed except the .entities entry. Structurally valid after these checks; runtime unconfirmed.

1. What was corrected in this run

Finding in Attempt 2 measured now
Reference checker knows 4 keys + targets ("62/62 in c2v1") In c2v1 hit 6 keys (+mapUnlockSecret 4/4, automapMapImage 4/4); across all 82 Retail maps 21 keys and 5 list blocks REF_KEYS = the 21 measured, REF_LIST_BLOCKS = targets/parts/constraints/multiPositions/automapLootRevealEntities
Build gate as set difference A second duplicate of a name that the source already had twice resulted in the same message and failed Multiset difference (Counter)
custom compfile codec Duplicate of wolfsdk/tnccrypt.compfile_unwrap/_wrap (168/168 byte-identical, Master-checked) tnccrypt is used; Bundle bytes therefore unchanged (sha256 equal)
Negative control "hanging reference" Hit any first reference additionally: Spawner c2v1_combat_target_ai_spawn_firstarea loses its Soldier -> rejected
TexDB pass only from finalize() counters Self-report of the writer independently: 7127/7127 other entries identical; Image +0x60 1462/1462 = Retail-dlc_2

The 21 keys are measured, not guessed: every quoted value of each of the 82 different Retail .entities was held against the Entity names of the same file. 22,596 hits; the 314 non-hits (bindParent 238, bodyA 60, arcVolume 9, playFrom 7) are all Entity-form names of removed Entities (..._devcomment_3, Scene-Points) -- genuine Retail defects, no other value types. ai = true (172x) is unquoted and not counted.

2. Format -- Text, no binary format

compfile:maps/game/dlc/c02/c2v1_custom.entities = 16 bytes (usize, csize) + Kraken; therein text. The 411,568 lines of Retail c2v1.entities are exactly five forms: 2 headers (Version 5, HierarchyVersion 2), 103,461 <kopf> {, 103,461 }, 204,499 schluessel = wert;, 145 quoted layer names. Indentation is not depth (the } of entityDef stands one level further left), therefore each node remembers its tabs -- hence byte-exact instead of just equivalent. The alias source brings two non-Retail single lines from codex (lightColor = { r = 0.05; g = 0.8; b = 1; }); exactly this form is accepted, in Retail it occurs 0 times.

8 of the 85 files are not valid UTF-8 (name = "break\xa8" in c09p1, c09p2, c1v3, c1v3_venus, each with patch copies); surrogateescape carries the byte unchanged through.

3. Evidence (all in this run)

Test Result
Round-Trip over every .entities of the installation 85/85 byte-exact (82 distinct contents, 23 archives)
Retail against Checker rules 34/85 clean (with 6 keys it was 40/85); Findings: 23 duplicate names, 1050 dangling references; other finding types: 0 (otherwise failure)
Surgical: 1 property changed Diff exactly -lightIntensity = 16; / +lightIntensity = 7.5;, 1 line different in position
Negative controls 8/8: Positive anchors clean; extra } / unclosed block / missing ; / dangling reference / Spawner-targets to empty / inherit without Chunk (player/start_v2) / duplicate name -- all rejected
probe_datahash on the Bundle 7127/7127 (1 entry Mode 4 without decoder, unchanged from Retail)
probe_idclhash on the Bundle +0x08 1/1, +0x20 1/1
Modified copy (1 byte in Entities payload) probe_datahash exit 1, BAD compfile:...c2v1_custom.entities
Table-Diff Source -> Bundle 0 of 7127 other entries changed (Payload + all fields except Offset); on the Entity entry only +0x40/+0x48/+0x50
Image-+0x60 (TexDB key) against Retail-dlc_2 1462/1462 equal -> the installed chunk_22.texdb fits
Payload read back from container byte-exact Round-Trip, Checker clean including inherit against 996 entityDefs of mounted chunks
New Asset-/Decl-names against source 0
Diff Source against Bundle 49 Entities changed, 49 claimed in manifest, no deviation
Reproducibility two builds sha256-identical: a8da9e4ed82e7e8793c467a66a56b3ff9363ee4b8646b69b4fc0fd8035a4d19a
Uninstall assumption installed dlc_4/base/chunk_22.resources and .texdb byte-identical to dlc_2 via cmp

finalize() has exactly one entry rehashed ([7079] compfile:...c2v1_custom.entities), hash_0x60: 0, deps: 0.

4. The Changes -- what a player sees

Every type change is a Body Transplantation from a donor existing within c2v1 itself: edit {} is a full property dump, a new inherit alone changes nothing visible. Name, Position, Orientation, targets, and bindParent remain from the target. Since every donor is already in the map, Models, Sounds, and Decls are in the mounted chunks, and the Builder breaks if a new name appears. Measured: no transplanted body carries a reference from the donor area, every Soldier keeps its own Roam point (roam_22/30/61/5).

4.1 Enemies (4)

Entity before -> after where
..._soldier_generic_soldier_light_1 soldier_light -> elite/generic/elite_heavy Lobby (-7.4, -185.1)
..._soldier_generic_soldier_light_3 dito Lobby (-4.4, -192.5)
..._soldier_generic_soldier_light_5 dito Lobby (-1.3, -186.8)
..._soldier_generic_soldier_heavy_3 soldier_heavy -> ubersoldat/ubersoldat_cannon Commander area (24.6, -30.6)

All four have flags { hide = true; } (before, after, and from donor) and are spawned by idTarget_AISpawn (c2v1_combat_target_ai_spawn_firstarea or ..._commanderarea_initial); the names remain, so the Spawners find them further. Player sees: in the first Lobby wave 3 heavily armored Elite Soldiers instead of light soldiers, in the Commander area an Ubersoldat with a cannon.

4.2 Pickups (10) -- Food becomes Equipment

Entity after
c2v1_pu_prop_pickup_health_food_pretzel_1_1 MP (weapons/smg/smg), Lobby (-3.1, -176.1)
..._pretzel_1_2 Sturmgewehr (battlerifle)
..._pretzel_1_3 Pistole (handgun), (-2.3, -159.5)
..._pretzel_1_4 MP-Ammo
..._fruit_01_1 MP
..._fruit_01_2 Pistol Ammo
..._fruit_02_1 Sturmgewehr
..._fruit_02_2 Soldier Helmet (Armor), 4 m from Office Spawn
..._grapes_1 large Medikit
..._meal_dogfood_1 MP

4.3 Lights (33)

All LIGHT_POINT (16) and LIGHT_SPOT (17) within the range of both Spawn Points: Lobby has 18 red lights (1, 0.12, 0.05), Office has 18 green lights (0.15, 1, 0.35), intensity at least 4 each (raised to 26). Spotlights and ambient light remain untouched.

4.4 Spawn (2)

c2v1 has exactly two idPlayerStart: sacramento_gameplay_player_start_1 (Lobby, -18.3/-205.9) and c2v1_ps_challenge_01 (Office, 29.1/-77.2). Which one applies on a map call is undecidable offline: the chapter variant dlc/c2v1 requires spawnSpot = "c2v1_gameplay_player_start_1", a name that neither Retail nor Alias Entities contain (0 hits); the Challenge variant requires c2v1_ps_challenge_01. The two starts therefore swap places: whichever the Engine picks, the player stands at the Retail location of the other. Both locations are spots where the game itself spawns a player; they are the only offline evidence for fixed ground. Side effect: the room in which you wake up reveals which start the Engine chose.

5. What Remains Open

  • Runtime. Nothing is seen in-game. The bundle inherits all open points from the Alias bundle (Mount of dlc_4, Alias names, load path via the resourceExec carrier, whose Mount timestamp in the main menu is unrecorded, see execcarrier.md §4), which itself was never loaded.
  • Mission Logic. Kiscule scripts can hang at Lobby Start (idKisculeNodePlayerStartNotification exists in the Exe). If the player starts in the Office, Intro/Objectives may be missed; combat and pickups are unaffected.
  • Lights. Direct light from point/spotlights is calculated at runtime; baked portions (Spotlights, Lightmaps) remain Retail-colored. How strongly the color shift affects gameplay is untested.
  • Spawners and Type. Whether idTarget_AISpawn generates a different enemy type under the same name without further checks has not been verified via disassembly. Whether the Navmesh in the Commander area is designed for the large Super Soldier is unverified offline (the donor stands 39 m further south, at -69.3). The Super Soldier brings spawnSleepingDuration = -1 from its donor.
  • New Enemies instead of Type Conversion (Increase count) is not built: a new Entity name must also appear in a Spawner's targets, and whether the Engine requires more Pool/Streaming budget (.mapresources) for more instances is unrecorded. Type conversion and relocation work without new names.
  • --roundtrip takes ~10 min (82 files at ~10 MB each in pure Python).

6. Reproduction

python tools/build_custom_map.py                  # builds re_probes/entitypipe/ (~4 min)
python tools/probe_entitypipe.py --roundtrip      # 85/85 byte-exact
python tools/probe_entitypipe.py --surgical       # 1 line Diff
python tools/probe_entitypipe.py --negative       # 8/8
python tools/probe_entitypipe.py --bundle         # Hash samples, manipulation, table and entity diff (~2-6 min)

Runbook

  1. Install (PowerShell, Repo root; delete first, then copy to avoid writing via a hardlink in DLC2): $G="<Steam library>\steamapps\common\Wolfenstein.II.The.New.Colossus"; Remove-Item "$G\dlc\dlc_4\base\chunk_22.resources"; Copy-Item re_probes\entitypipe\base\chunk_22.resources "$G\dlc\dlc_4\base\"; python tools/install_exec_carrier.py install
  2. Start: Launch the game with +com_enableDeveloperMode 1, then in the main menu console: resourceExec wolfsdk_test.cfg (loads map game/dlc/c02/c2v1_custom; remains silent, use resourceExec wolfsdk_test.cfg -s).
  3. Observe: Wake up in the red-lit entrance area or the green-lit office (the room reveals which start the engine took); in the office lies a soldier's helmet 4 meters away, and in the lobby at (-3, -176) there is an MP instead of a pretzel, and the first lobby wave brings 3 heavy elite soldiers.
  4. Has worked if the map loads and the lights at spawn are red/green. If it loads with retail colors, our container is not being read; if it does not load at all, repeat the same test with re_probes/idclwriter/chunk_22.resources (alias without our edits) to separate the alias layer from the entity edit; if can't generate in production appears, the Traeger chunk was not mounted (execcarrier.md §4).
  5. Uninstall: Remove-Item "$G\dlc\dlc_4\base\chunk_22.resources"; Copy-Item "$G\dlc\dlc_2\base\chunk_22.resources" "$G\dlc\dlc_4\base\"; python tools/install_exec_carrier.py uninstall -- restores the current state (the installed dlc_4 chunk today is byte-identical to dlc_2 per cmp).