FS507D_20161015 release analysis wrap-up (drop itself is gitignored; art-review
folder kept local for review):
- Recovered the only assets our tree lacked: 13 hsh HUD/radar/mech bmps and the
two 5.07D lobby decals (decal_46/47.tga, extracted from release props.mw4 via
a ported gos_LZDecompress).
- ResourceImagePool.cpp: missing-texture placeholder is now LAB_ONLY (editor
keeps degraded mode); Release restores the original fatal STOP. Release +
Profile rebuilt, 0 errors.
Console script reconciled:
- ConLobby.script.new ("BattleTech Console V5.0.7Df", newest revision anywhere)
promoted to Content\ShellScripts\ConLobby.script; .new removed; stale loose
deploy copy removed. Verified in-game (console title shows V5.0.7Df).
- Corrected CLAUDE.md: the release never "renamed" the console to
ComputerPlayer.script -- the resource packer stores script contents under
alphabetically skewed entry names (runtime resolves the same pairing).
Packer quirks documented (stale entry carry-forward on incremental builds,
name/content skew in directory sweeps).
Mechlab bug fix (first FireStorm bug hunt):
- New-Mech dialog showed blank rows for Wolfhound/Zeus and crashed (KERNELBASE
read AV) when creating a Zeus. Root cause: newmech in chassis.script created
its Type droplist without setting $$m_listBoxSize$$, so capacity defaulted to
60 while 65 chassis were written in -- OOB script-array writes. Fixed by
sizing the list from $$m_chassisCount$$. Latent stock-MW4 bug armed when the
FireStorm roster passed 60 chassis. Verified: Zeus variant creates cleanly.
props.mw4 fully repacked (decals + promoted console + mechlab fix, junk
.new/.org entries gone); game deploy refreshed at MW4\. Gitignore: FS507D drop
and player-created MW4\Resource\Variants.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
715 lines
54 KiB
Markdown
715 lines
54 KiB
Markdown
# BattleTech: FireStorm — Project Notes (CLAUDE.md)
|
||
|
||
Working notes for Claude Code. Updated as work progresses.
|
||
|
||
## ⚠️ Repository location, git & auth (relocated 2026-06-26)
|
||
**The whole repo moved from `C:\VWE` → `C:\VWE\firestorm`** so `C:\VWE` can host other
|
||
projects. `firestorm\` is now a **self-contained git repo** (its own `.git`); `C:\VWE` is just
|
||
a parent container (NOT a git repo). All paths in this file and in build/deploy scripts are the
|
||
new `C:\VWE\firestorm\...` paths.
|
||
- **What the move touched:** physical move of all top-level entries (incl. `.git`); no junctions/
|
||
symlinks existed to break; single volume so it was an instant metadata rename. `git status` was
|
||
clean afterward (repo-relative paths unchanged) — the only diff was the path rewrites below.
|
||
- **Hardcoded paths rewritten** `c:\VWE\... → c:\VWE\firestorm\...` (encoding-preserved) in:
|
||
`Gameleap\code\mw4\Libraries\stlport\stl_inc_find.hpp` (stlnative include — build-critical),
|
||
the `build-env\*.ps1` deploy/build scripts, `build-env\play-mr.*`, the `build-env\*.reg` files
|
||
(incl. UTF-16 `vc6-hklm-registration.reg`), and the docs (`CLAUDE.md`/`README.md`/`RECOVERY.md`).
|
||
Stale `build-env\*.log`/`.plg`/`.map` build artifacts still contain old paths (historical, unused).
|
||
- **System registry was repointed to the new paths** (so build + run still work):
|
||
- HKCU: VC6 IDE directories (`...DevStudio\6.0\...\Directories`) + AppCompat `Layers` shims for
|
||
`MW4.exe`, `MW4pro.exe`, `MW4Ed2.exe`; dropped two stale `C:\VWE\MW4Editor\*` entries
|
||
(that dir was removed in STEP 9).
|
||
- HKLM (elevated): VC6 install registration (`Wow6432Node\...\VisualStudio\6.0`, ProductDir) +
|
||
all-users AppCompat shims for `MW4.exe`/`MW4pro.exe`.
|
||
- **Reminder:** AppCompat (`DWM8And16BitMitigation`) is keyed on the exe **PATH** — relocating an
|
||
exe requires re-applying the shim (the `.reg` files + `deploy-*.ps1` now use firestorm paths).
|
||
- **Git remote (new):** `origin = https://gitea.mysticmachines.com/VWE/firestorm.git`
|
||
(was `http://192.168.1.167:3000/cyd/firestorm.git`; host + owner `cyd→VWE` changed; same backend,
|
||
so LFS objects already present — pushes only send new deltas). LFS access hint set to `basic`.
|
||
- **Auth = Personal Access Token over basic auth**, stored in Windows Credential Manager. The Git
|
||
Credential Manager **browser-OAuth flow for Gitea FAILS here** (loopback redirect to
|
||
`127.0.0.1:<port>` does not complete). To (re)seed creds, run in Git Bash:
|
||
`printf 'protocol=https\nhost=gitea.mysticmachines.com\nusername=<USER>\npassword=<PAT>\n' | git credential approve`
|
||
(PAT needs `repository: Read and Write`). Then `git push` uses it with no browser prompt.
|
||
- Uses **Git LFS**; `.gitattributes` forces `* -text` for byte-exact restores regardless of
|
||
`core.autocrlf`.
|
||
|
||
## What this project is
|
||
A total-conversion / expansion ("FireStorm") built on the **MechWarrior 4** game
|
||
engine (the *Gameleap* engine, v5.03), using Microsoft's **GameOS / GOS**
|
||
technology (same lineage as MechWarrior 4 and MechCommander 2). ~60k files mixing
|
||
C++ engine source, an asset/content pipeline, and game-design spreadsheets.
|
||
Toolchain is late-90s/early-2000s **Visual C++ 6.0** — no git, no modern build system.
|
||
|
||
## Repo layout (top level)
|
||
> **2026-06-23 cleanup:** unused/duplicate trees archived to **`_UNUSED\`** to reduce newcomer
|
||
> confusion (Gameleap\{Archive,Drivers,EditorDocs,Notes,batch,utilities}; GameleapCode5_03\{Content,hsh};
|
||
> resource_fullbak). Build paths untouched. See **`README.md`** for the orienting layout map.
|
||
> Build/deploy uses only: `Gameleap\mw4` (data), `Gameleap\code` (code+binaries), `build-env` (toolchain).
|
||
|
||
- **`Gameleap\code/`** — THE BUILD TARGET. Engine + game source + content. *(confirmed by user)*
|
||
(Its `Content\` + `hsh\` were stale 2005 duplicates → moved to `_UNUSED\`; live data is `Gameleap\mw4`.)
|
||
- **`Gameleap/`** — only **`mw4/`** is used (game-data source for resource packing). Former siblings
|
||
(editor docs, drivers, batch tools, runtime env) were historical/utility → moved to `_UNUSED\`.
|
||
- **`BTFrstrm/`** — FireStorm design data: mech stat workbooks (`MechInfo_5.04.xls`, `scriptaddmech.xls`).
|
||
- **`Finished HUDS from J&J/`** — per-mech HUD art (MFD + Radar) for ~15 'Mechs.
|
||
|
||
### Inside `Gameleap\code/`
|
||
- `CoreTech/` — reusable engine layer (GameOS, gosFX, GOSScript, MLR renderer, Network, Stuff, Language, blade) + Tools.
|
||
- `mw4/Code/` — the game itself. `mw4/Code/MW4/` = ~590 files; AI subsystem dominates (~65 `AI_*` files).
|
||
- `mw4/Libraries/` — mw4-local libs (Adept, Compost, ElementRenderer, gosfx, ImageLib, MLR, server, stuff, **stlport**).
|
||
- `Content/` — game content: `ABLScripts/` (ABL scripting language), Defines, Subsystems, Tables, `.build` files.
|
||
- `rel.bin/` `dbg.bin/` `pro.bin/` — **build OUTPUT folders** (libs/exe/dll land here). Generated, not source.
|
||
|
||
---
|
||
|
||
## ✅ STEP 1: Build process reconstruction — COMPLETE
|
||
|
||
### Toolchain
|
||
- **Compiler/IDE:** Visual C++ 6.0 / MSDev98 (all `.dsw`/`.dsp` are "Format Version 6.00").
|
||
- **STL:** bundled **STLport** at `mw4/Libraries/stlport/` (custom, build it first).
|
||
- **External SDKs (NOT bundled)** — exact reqs from `CoreTech/Libraries/GameOS/pch.hpp`:
|
||
- **DirectX 7.0 SDK** — headers must be **FIRST** in include order
|
||
(`#if DIRECTDRAW_VERSION != 0x0700 → #error`; uses ddraw7, dinput7, d3d.h immediate mode, dplay).
|
||
- **DirectX Media 6.0 SDK** — DirectShow video (`amstream.h`, `__IDDrawExclModeVideo`).
|
||
- **EAX SDK** (Creative `eax.h`) — audio.
|
||
- **DirectX 8 link libs** (`d3d8.lib d3dx8.lib dinput8.lib dxguid.lib`) — used by standalone tools
|
||
(Gos2Light/Text, HighTide, etc.).
|
||
- NOTE: SDK paths are NOT in the `.dsp` files — they come from the IDE's global
|
||
**Tools → Options → Directories**, which is why DX7-first ordering matters.
|
||
- Compiler flags of note: `/G6 /Zp4` (struct packing 4 — must be consistent across all libs),
|
||
`/MD` runtime (Release), `/MDd` (Debug). Mismatched packing/runtime = link/crash.
|
||
|
||
### Locating VC6 + SDKs on the ORIGINAL DISK IMAGE
|
||
- **VC6 / MSDev98:** `C:\Program Files\Microsoft Visual Studio\`
|
||
- `VC98\Bin\` (cl.exe, link.exe, `VCVARS32.BAT`), `VC98\Include`, `VC98\Lib`, `VC98\MFC`
|
||
- `Common\MSDev98\Bin\MSDEV.EXE` (IDE + command-line builder).
|
||
- **DirectX/Media/EAX SDKs** — check these era-typical roots:
|
||
- DX7 SDK: `C:\DXSDK\`, `C:\mssdk\`, or `C:\DX7SDK\`
|
||
- DX8 SDK: `C:\DXSDK\` or `C:\Program Files\Microsoft DirectX 8*SDK\`
|
||
- DX Media 6: `C:\DXMedia\` or `C:\DXMEDIASDK\`
|
||
- EAX SDK: under `C:\` or the Creative/SB SDK folder.
|
||
- **⭐ Most valuable artifact — the IDE directory ordering** (reproduces the env exactly).
|
||
Load the build user's `NTUSER.DAT` and read:
|
||
`HKCU\Software\Microsoft\DevStudio\6.0\Build System\Components\Platforms\Win32 (x86)\Directories`
|
||
→ values **"Include Dirs", "Library Dirs", "Path Dirs"** (ordered; copy verbatim).
|
||
Also: `HKLM\SOFTWARE\Microsoft\VisualStudio\6.0`, `HKLM\SOFTWARE\Microsoft\DirectX` (records DX version).
|
||
- **Signature-file search on a mounted image:** `MSDEV.EXE`/`VCVARS32.BAT` → VC6;
|
||
`ddraw.h`/`d3d.h`/`dinput.h` → DX7 includes (verify `DIRECTDRAW_VERSION 0x0700`);
|
||
`amstream.h` → DX Media 6; `d3dx8.lib`/`eax.h` → DX8 / EAX SDK.
|
||
|
||
### Master workspace & final target
|
||
- **Workspace:** `Gameleap\code/mw4/Code/MechWarrior4.dsw` (the modern/current one).
|
||
- Self-contained: all 24 sub-projects verified present on disk, spanning both
|
||
`mw4/Libraries` and `CoreTech/Libraries`.
|
||
- **`MechWarrior4Build.dsw`** = LEGACY/alternate (uses old `MW4Gos`, `Network`, `GamePlatform`,
|
||
`MW4GameEd` v1). Do not use; superseded by `MechWarrior4.dsw`.
|
||
- **Final game target:** project **`MW4Application`** → `MW4.exe`.
|
||
- **Editor target:** project **`MW4GameEd2`** → editor exe (separate).
|
||
|
||
### Build configurations → output paths (from MW4Application.dsp)
|
||
| Config | Defines | Output |
|
||
|---------|------------------------|-------------------|
|
||
| Debug | `_DEBUG _ARMOR` `/MDd` | `dbg.bin/MW4.exe` |
|
||
| Armor | `NDEBUG _ARMOR` `/Zi` | `arm.bin/MW4.exe` |
|
||
| Profile | `NDEBUG` profiling | `rel.bin/MW4pro.exe` |
|
||
| Release | `RELEASE NDEBUG` | `rel.bin/MW4.exe` |
|
||
| icecap | `_ICECAP` | `ice.bin/` |
|
||
|
||
A prior successful **Release build exists** in `rel.bin/` (MW4.exe, MW4pro.exe, all `.lib`s,
|
||
Launcher.exe, ctcls.dll, MissionLang.dll, ScriptStrings.dll, autoconfig.exe, mw4print.exe).
|
||
`arm.bin/` and `ice.bin/` are absent (those configs were never built here).
|
||
|
||
### Build dependency order (topological, from MechWarrior4.dsw)
|
||
1. **`stlport`** — foundation, no deps. Build first.
|
||
2. **Leaf libs** (depend only on stlport / nothing): `GameOS`, `Stuff`, `MLR`, `gosFX`,
|
||
`ImageLib`, `Compost`, `GOSScript`, `ElementRenderer`, `Adept`, `server`,
|
||
`DLLPlatform`, `MFCPlatform`, `GamePlatformNoMain`, `ctcls`.
|
||
3. **`MW4`** — the game library.
|
||
4. **Helper exes/dlls:** `Launcher`, `autoconfig`, `mw4print`, `MissionLang`,
|
||
`ScriptStrings`, `MW4DedicatedUI`.
|
||
5. **`MW4Application`** — links everything into `MW4.exe`. *(Set as Active Project.)*
|
||
|
||
VC6 honors these dependencies automatically via the `.dsw` "Project Dependency" records,
|
||
so a single "Build" of MW4Application pulls the whole chain in order.
|
||
|
||
### How to build
|
||
- **IDE:** Open `mw4/Code/MechWarrior4.dsw` in VC6 → set **MW4Application** as Active Project
|
||
→ pick config (Win32 Debug / Release) → Build.
|
||
- **Command line (VC6):**
|
||
`msdev MechWarrior4.dsw /MAKE "MW4Application - Win32 Debug"`
|
||
(or `"... - Win32 Release"`). Add `/REBUILD` for a clean build.
|
||
|
||
### How to RUN (the `mw4/*.bat` scripts are LAUNCH, not compile)
|
||
- `game_dbg.bat` etc. just run the exe: `binaries\mw4\MW4_dbg -armorlevel 3 -nobuild`.
|
||
- `-build` = (re)build game resource `.erf`s from source assets at startup; `-nobuild` = skip.
|
||
- `bldresources_game_dbg.bat` = run with `-build` to regenerate resources.
|
||
- `editor_dbg.bat` = launch the editor (`MW4Ed2_d`).
|
||
|
||
### ⚠️ Open discrepancies to resolve before a real build
|
||
1. **Output path vs. launch path mismatch:** `.dsp` files emit to `dbg.bin/MW4.exe` /
|
||
`rel.bin/MW4.exe`, but the `game_*.bat` launchers point at `binaries\mw4\MW4_dbg.exe`.
|
||
There is a missing copy/deploy step (or the bats target a different deployed layout).
|
||
`mw4/Binaries/` currently only holds `3DSPlug-ins/`. **TODO: find/recreate the deploy step.**
|
||
2. `FullExport.batch` references dead studio network paths (`\\aas1\...`, `d:\ContentExport\`).
|
||
That's the *art* export pipeline, irrelevant to the code build.
|
||
|
||
---
|
||
|
||
## ✅ STEP 2: Toolchain extracted from original disk image (E:\) — COMPLETE
|
||
Original build machine image mounted at `E:\`. Build user = **`jeff`**.
|
||
Everything needed is now copied into **`build-env/`** (self-contained):
|
||
- **`build-env/VisualStudio6/`** ← `E:\Program Files\Microsoft Visual Studio` (VC6: CL, LINK, NMAKE, MSDEV).
|
||
- **`build-env/dx7asdk/`** ← `E:\Code\dx7asdk` (DirectX **7.0a** SDK; `ddraw.h` = `DIRECTDRAW_VERSION 0x0700` ✓).
|
||
- **`build-env/DXMedia/`** ← `E:\Code\DXMedia` (DirectX **Media 6.0** SDK; amstream/control/strmif + libs).
|
||
- **`build-env/setup-mw4-build.bat`** + **`README.md`** (generated; build instructions).
|
||
|
||
Resolutions to prior open items:
|
||
- **DirectX version pinned:** DX **7.0a** SDK (headers) + DX **Media 6.0** SDK. NOT DX8 for the game.
|
||
- **VC6 located & copied:** VC++ 6.0 at `build-env/VisualStudio6/`.
|
||
- **EAX:** bundled in repo (`GameOS/Eax.h`); no static `eax.lib` needed (runtime-resolved).
|
||
- **DX8 SDK:** absent from image; only blocks 3 standalone tools (Gos2Light/Text, HighTide), not the game/editor.
|
||
- **Critical ordering:** DX7 includes MUST precede VC98\INCLUDE (engine `#error` guard); enforced in setup .bat + README.
|
||
|
||
### ✅ Exact registry directory order RECOVERED (from jeff's NTUSER.DAT)
|
||
Key: `HKCU\...\DevStudio\6.0\Build System\Components\Platforms\Win32 (x86)\Directories`
|
||
- **Include:** `DXMedia\include → dx7asdk\include → VC98\INCLUDE → VC98\MFC\INCLUDE → VC98\ATL\INCLUDE`
|
||
- **Library:** `VC98\LIB → VC98\MFC\LIB` only.
|
||
Two verified facts that make this work:
|
||
1. `DXMedia\include` has NO core DX headers (DirectShow only) → `ddraw.h` still resolves
|
||
from `dx7asdk` before VC98's old one (satisfies the `pch.hpp` 0x0700 guard).
|
||
2. The DX/DShow `.lib`s were **copied into `VC98\Lib`** on the original machine (verified
|
||
present in our copy: ddraw/dinput/dsound/dxguid/strmiids/quartz/strmbase/amstrmid);
|
||
pulled in via `#pragma comment(lib,...)` in `GameOS\guids.cpp`, not the link line.
|
||
Captured as **`build-env/vc6-directories.reg`** (rebased to local copies; HKCU import, no admin)
|
||
and reflected exactly in **`build-env/setup-mw4-build.bat`**.
|
||
|
||
### ✅ HKLM VC6 install registration extracted & rebased
|
||
Exported jeff's offline `software` hive trees (`Microsoft\VisualStudio\6.0`,
|
||
`Microsoft\DevStudio\6.0`) and transformed into **`build-env/vc6-hklm-registration.reg`**:
|
||
- Key root redirected `oldsw` → `HKLM\SOFTWARE\Wow6432Node\...` (32-bit `msdev` on 64-bit Windows
|
||
reads HKLM\SOFTWARE redirected to Wow6432Node; HKCU\Software is NOT redirected).
|
||
- All paths rebased: `C:\Program Files\Microsoft Visual Studio` → `build-env\VisualStudio6`;
|
||
`C:\Program Files\Common Files\Microsoft Shared` → `build-env\CommonFiles-MSShared`
|
||
(copied `VS98` + `MSDesigners98` so those refs resolve).
|
||
- Verified: 0 leftover `oldsw`, 0 un-rebased paths, 202 keys, ProductDir/InstallDir correct.
|
||
- Raw exports kept as `build-env/_raw_*.reg` (provenance).
|
||
- Import order (ELEVATED): `vc6-hklm-registration.reg` then `vc6-directories.reg`.
|
||
|
||
---
|
||
|
||
## ✅ STEP 3: Clean build from source — SUCCESS (game target)
|
||
Registry imported (HKLM `vc6-hklm-registration.reg` + HKCU `vc6-directories.reg`), msdev
|
||
runs from the copy, and a **full clean rebuild of `MW4Application - Win32 Release` succeeds**:
|
||
- 22 projects compiled in dependency order (stlport → GameOS/Stuff/MLR/gosFX/… → MW4 →
|
||
helper exes/dlls → MW4Application). **`MW4.exe` — 0 errors**, 384 warnings (normal for VC6).
|
||
- Output: `rel.bin\MW4.exe` (~3.64 MB), plus fresh `*.lib`, `Launcher.exe`, `autoconfig.exe`,
|
||
`mw4print.exe`, `MissionLang.dll`, `ScriptStrings.dll`, `ctcls.dll`.
|
||
- Build is reproducible head-lessly via:
|
||
`msdev MechWarrior4.dsw /MAKE "MW4Application - Win32 Release" /REBUILD /OUT <log>`
|
||
(run via `Start-Process -Wait`; msdev is a GUI-subsystem app so the shell won't block otherwise).
|
||
- Build logs kept in `build-env\build_*.log`.
|
||
|
||
### ✅ `stlnative` dependency relocated INTO the working tree
|
||
`mw4/Libraries/stlport/stl_inc_find.hpp` hardcoded a native-headers path
|
||
`<c:\stlnative/##x>` (3 macro defs, the only references in the codebase). STLport wraps a
|
||
27 MB snapshot of the VC98 + Platform SDK headers (974 files) restored from the image.
|
||
Originally placed at `C:\stlnative`; now **moved into `build-env\stlnative\`** and the 3
|
||
macros repointed to `<c:\VWE\firestorm\build-env\stlnative/##x>`. Verified: with `C:\stlnative`
|
||
removed, a full clean rebuild still succeeds (MW4.exe, 0 errors). The build is now
|
||
self-contained under `c:\VWE\firestorm` — no external `C:\stlnative` needed.
|
||
|
||
---
|
||
|
||
## ✅ STEP 4: Runnable deployment assembled at `C:\VWE\firestorm\MW4` — DONE
|
||
Rules-based deploy (no image/E: dependency) via **`build-env\deploy-mw4.ps1`**:
|
||
- **Result: `C:\VWE\firestorm\MW4` — 845 files, 895 MB** (target was ~900 MB), with our freshly
|
||
built `MW4.exe` (3,637,248 bytes) + all runtime DLLs + prebuilt `resource\*.mw4`.
|
||
- Sources (all from working dir): runtime base = `Gameleap\mw4`; binaries = `rel.bin`.
|
||
- The old `game_*.bat` assumed a `binaries\mw4\MW4_dbg.exe` layout that the real game
|
||
never used — the runnable game has `MW4.exe` at the deployment root. Launch via
|
||
**`C:\VWE\firestorm\MW4\run-mw4.bat`** (resources prebuilt, no `-build` needed).
|
||
|
||
### Deployment selection rules (the dev tree `Gameleap\mw4` is a ~6 GB bloated superset)
|
||
- KEEP whole: `Resource\` (767 MB .mw4 packages), `hsh\` (102 MB), `Assets\`, `Stats\`.
|
||
- KEEP subset: `Content\shellscripts\` MINUS `Graphics\` (119 MB source .tga) and
|
||
`Original\` (57 MB backups) -> ~9 MB of compiled scripts/.gaf/.d3f.
|
||
- KEEP root: runtime `*.dll/*.ini/*.options/*.txt/*.rtf/*.ico/*.016/*.256/...` + `clokspl.exe`.
|
||
- DROP: `Content\*` (4.6 GB source except shellscripts), `Movies\` (352 MB), `Notes\`,
|
||
`fonts\`, all tool exes (ERF Deluxe, EffectEdit, MapCreator, ResourceBrowser, MW4Ed2, ...).
|
||
- OVERLAY: fresh `rel.bin` binaries (MW4.exe, MW4pro.exe, Launcher, autoconfig, mw4print,
|
||
MissionLang.dll, ScriptStrings.dll, ctcls.dll).
|
||
|
||
---
|
||
|
||
## ✅ STEP 5: Runtime brought up at `C:\VWE\firestorm\MW4` — RUNS (fullscreen + windowed)
|
||
Reference for "working" = **`C:\MW4knowngood`** (NOT `E:\gameleap`, NOT `D:\5.0.8.2_console`
|
||
— those are unrelated). Two independent issues had to be fixed; both are now in
|
||
`deploy-mw4.ps1` so a fresh deploy is runnable out of the box:
|
||
|
||
1. **DirectDraw 16-bit compat shim (Win11).** MW4 runs `bitdepth=16`; modern Windows fails
|
||
its DirectDraw hardware-surface creation with `DDERR_NODIRECTDRAWHW` unless the
|
||
**`DWM8And16BitMitigation`** AppCompat layer is applied to the exe *path*. Our path had a
|
||
stray `HIGHDPIAWARE`-only layer that suppressed the auto-shim. Fix: set HKCU layer
|
||
`DWM8And16BitMitigation HIGHDPIAWARE` for `C:\VWE\firestorm\MW4\MW4.exe` (deploy script does this;
|
||
matching all-users HKLM `$ DWM8And16BitMitigation` is in `build-env\mw4-compat-hklm.reg`).
|
||
Note: AppCompat is keyed on exe PATH, so a copy at a new path needs the layer re-applied.
|
||
2. **Dev-only DLLs shadowing system DLLs.** Our rules copied every root `*.dll`, which pulled
|
||
in `dbghelp.dll`/`imagehlp.dll` (2003 copies that shadow Windows' system DLLs and break
|
||
DirectDraw init) plus tool DLLs `ijl10.dll`, `ctcl.dll`, `Language.oeg.dll`, `Resources.dll`.
|
||
known-good has none of these. Fix: deploy script now excludes those 6 by name. Removing
|
||
them was what made it run in BOTH fullscreen and windowed.
|
||
|
||
Diagnostic note: swapping known-good binaries into our deploy still failed *before* the shim
|
||
was applied — that proved our rebuilt binaries are NOT the cause (the shim + DLL excludes were).
|
||
Final deployment: **`C:\VWE\firestorm\MW4` = 894 MB, 839 files, DLL set identical to known-good**, running
|
||
our freshly built `MW4.exe`.
|
||
|
||
---
|
||
|
||
## Resource (`.mw4`) build process — documented & ✅ VERIFIED
|
||
Full writeup in **`build-env\RESOURCE-BUILD.md`**. Tested end-to-end 2026-06-11 with our
|
||
freshly built `MW4pro.exe` (Profile/LAB_ONLY): minimal `Content\MechWarrior4.build` ->
|
||
`resource\restest.mw4` + `.dep` (exit 0); `#VBD` magic + payload confirmed; `.dep` tracks
|
||
source; incremental skip/rebuild both verified; Release exe confirmed to ignore `-build`.
|
||
Key facts:
|
||
- The resource compiler is **inside the game exe**, triggered by the **`-build`** flag,
|
||
which is `#ifdef LAB_ONLY` — so **only Debug/Armor/Profile (`MW4_dbg`/`MW4_arm`/`MW4pro.exe`)
|
||
can build resources; Release `MW4.exe` cannot**. (That's why `bldresources_game_*.bat`
|
||
use the LAB_ONLY exes.)
|
||
- Entry point: `MW4Application.cpp` -> `Tool::Instance->BuildResources("Content\MechWarrior4.build",
|
||
VER_CONTENTVERSION=63, deps)`; recursive driver `Adept::Tool::BuildResources` /
|
||
`ParseBuildFile`; per-type packers in `Adept\Tool.cpp` + `MW4\MWTool.cpp`.
|
||
- Input: `Content\MechWarrior4.build` (master tree) -> per-package `.build` manifests
|
||
(`[resource\X.mw4]` + `data=`/`instance=`/`file=`/`notation=`/`campaign=`/... entries) ->
|
||
source assets under `Content\`. Output: `resource\*.mw4` + `*.dep` (incremental via `.dep`
|
||
timestamps + content version). Needs the full ~4.6 GB `Content\` source tree.
|
||
|
||
### ⚠️ Resource packer quirks (discovered 2026-07-02, ConLobby promotion)
|
||
1. **Incremental rebuilds carry forward stale entries.** A package rebuild re-packs only
|
||
entries the `.dep` flags as changed and copies the rest — including entries whose SOURCE
|
||
FILES WERE DELETED (they are never dropped) — from the previous `.mw4`. Per-entry FILETIME
|
||
in the directory = when that entry was last (re)packed, not the source mtime. **To pick up
|
||
deletions/renames, force a full repack: delete `resource\<pkg>.mw4` + `<pkg>.dep`, then run
|
||
`build-env\build-resources.ps1`.** Also: `Copy-Item` preserves the source mtime, so a
|
||
promoted/copied file can look OLDER than the package and be skipped — touch it (or full-repack).
|
||
2. **Script entry names are alphabetically skewed vs their contents** (in `directory=` sweeps,
|
||
e.g. props' `content\shellscripts`): e.g. entry `ConLobby.script` holds CreatePilotModal-like
|
||
text, entry `ConLobbyMission.script` holds `GUNStatus.script` (byte-identical), and our 140 KB
|
||
console (source `ConLobby.script`) lands under entry `ComputerPlayer.script` — IDENTICAL skew
|
||
in the 2016 release props.mw4, which shipped and worked. The runtime evidently resolves names
|
||
through the same pairing, so packages are self-consistent in-game; only extraction tools see
|
||
"swapped" names. Don't "fix" packed name mismatches by editing sources — verify in-game.
|
||
|
||
## ✅ STEP 6: Editor (`MW4GameEd2`) builds — DONE (with a 1-line source fix)
|
||
- Target `MW4GameEd2 - Win32 Release` -> **`rel.bin\MW4Ed2.exe`** (3,973,120 bytes, 0 errors).
|
||
MFC app (`Use_MFC 6`); needs `mfc42.dll` (present in deployment) at runtime. Profile config
|
||
also exists (-> `pro.bin\MW4Ed2.exe`).
|
||
- **Source fix required** (editor source had drifted; shipped `MW4Ed2.exe` is from 2003 and
|
||
was never rebuilt against the 2009 code): enum `MPGameTypes` in
|
||
`mw4\Code\MW4GameEd2\ObjectManager.h` was **missing `GT_StockCampaign`**, which
|
||
`ObjectManager.cpp` references (string map @1013, int map `case 14`). Added the enum member
|
||
between `GT_StockSiegeAssault` and `GT_CustomDestruction`. (This is the only repo source edit
|
||
beyond the stlnative relocation; both are marked with `[...]` comments in-place.)
|
||
- Built incrementally but it was a *full* compile of the editor's own sources (none existed
|
||
prior); shared libs reused from the Release game build.
|
||
|
||
---
|
||
|
||
## ⚠️ STEP 7: Editor builds + launches + draws UI, then HANGS (viewport spin)
|
||
Set up via **`build-env\deploy-editor.ps1`**; launches to window
|
||
**"MechWarrior 4 Mission Editor - 05.07.00.00"** and creates its MDI children (Game View,
|
||
Object Manager, Overview Window) — but then **spins one CPU core at ~100% with zero memory
|
||
growth and a stalled message pump** ("not responding"; 282s CPU / 283s uptime). It's a
|
||
busy-loop hang in the editor's real-time 3D viewport/idle loop — a **runtime** compat issue
|
||
on modern hardware, NOT a build issue (it compiled, launched, and drew its UI). The game runs
|
||
fine (different render path: fullscreen exclusive vs the editor's windowed live viewport).
|
||
### ROOT CAUSE FOUND: incomplete dev content + modal-STOP-over-windowed-DDraw
|
||
The editor loads/builds the full content tree at startup and **STOPs (fatal) on missing/
|
||
inconsistent dev content**, one item at a time:
|
||
- `skies\reduex_sky\reduex_night.erf` — misnamed (`Reduex_sky_night.erf`); FIXED by copy.
|
||
- `Texture skyfbb1` (referenced by `Content\Skies\fact01_sky\fact01_sky.hint`) — **genuinely
|
||
absent** from the dev tree (no file of that name anywhere). The FireStorm dev `Content\`
|
||
is an incomplete WIP with real asset gaps.
|
||
GameOS's `STOP` pops a **modal dialog**. Build-specific behavior on that dialog:
|
||
- **Profile** (LAB_ONLY, lighter opt): shows the STOP dialog cleanly; dismissing it exits.
|
||
- **Release** (`/Ox /Og`, no LAB_ONLY): trying to show the modal STOP over the **windowed
|
||
DirectDraw** viewport **hangs (100% spin) or crashes (AV)** — a dialog/DDraw interaction
|
||
fragility under full optimization. So the earlier "hang/crash" was this same content STOP,
|
||
handled badly by the Release build (NOT a separate memory bug as first guessed).
|
||
So: **editor compiles + launches correctly; the blocker is incomplete dev content** (a
|
||
content-curation task on the project's own unfinished assets, distinct from build/toolchain).
|
||
|
||
### Option 2 attempted (make content STOPs non-fatal) -> uncovered the REAL bug: heap corruption
|
||
- Patched `mw4\Libraries\Adept\ResourceImagePool.cpp:385` (texture-not-found): first tried
|
||
`continue` (skip) -> downstream **access violation** (missing texture deref'd later); then a
|
||
**placeholder-substitute** (`file_name="content\\textures\\01AACA1.tga"`) -> got PAST the
|
||
content STOPs. Both are tagged `[editor degraded-mode]` in-source.
|
||
- With content handled, the editor returns to the original symptom: **main UI thread spins at
|
||
100% CPU, not responding**. EIP sampling (`Wow64GetThreadContext`) located the spin in a tight
|
||
loop inside **`SysWOW64\ntdll.dll`** heap code (~`0x76F73E04`) = **walking a corrupted heap
|
||
free-list**. ROOT CAUSE = **heap corruption** (buffer overrun / double-free / use-after-free)
|
||
in the editor; it manifests non-deterministically as the ntdll heap-loop HANG or an AV, and
|
||
shifts with optimization (Release vs Profile) -> exactly the observed behavior.
|
||
- To actually fix: enable **PageHeap** for `MW4Ed2.exe` (registry `Image File Execution
|
||
Options\MW4Ed2.exe` GlobalFlag=0x02000000; needs admin) to trap the corrupting write at its
|
||
source with the Profile build's symbols, then fix the overrun. This is a deep memory-bug hunt
|
||
in old code (the 2003 editor never hit it on XP / with complete content).
|
||
- NOTE: `ResourceImagePool.cpp` placeholder patch is a degraded-mode hack; revert if not wanted.
|
||
|
||
### PageHeap hunt (in progress) — corruption confirmed, but a Heisenbug to pin down
|
||
- Enabled full PageHeap via `build-env\mw4ed2-pageheap.reg` (IFEO GlobalFlag=0x02000000,
|
||
PageHeapFlags=0x3; off-switch in `mw4ed2-pageheap-off.reg`). Confirmed active (editor mem
|
||
45->94 MB). Built `pro.bin\MW4Ed2.map` (added `/map` to the Profile link in MW4GameEd2.dsp,
|
||
preferred base 0x00400000) for address->function resolution.
|
||
- **With PageHeap + NO debugger: editor reliably AVs (0xC0000005) at ~1 s** = the overrun caught
|
||
at the corrupting write (the goal). **But under my PowerShell debug loop it will NOT reproduce**
|
||
(many attempts, even with `_NO_DEBUG_HEAP=1`): attaching perturbs heap/timing so the editor
|
||
takes a different path and exits without faulting -> classic heap-corruption Heisenbug.
|
||
- Conclusion: pinning the exact corrupting instruction needs a REAL debugger that holds heap/
|
||
timing steady. Cleanest: install **Debugging Tools for Windows** (`cdb`) and run
|
||
`cdb -g -G -c "kb;q" -o MW4Ed2.exe` with PageHeap on -> one-shot symbolicated faulting stack.
|
||
Alt: WER LocalDumps (HKLM) -> parse the minidump's exception stream for the faulting EIP ->
|
||
map via `MW4Ed2.map` (uncertain: GameOS's UEF may pre-empt WER). The corruption is in the
|
||
content-load path (~1 s, texture/sky loading).
|
||
- Working dir = proven runtime DLLs from the game deploy (NO `imagehlp`/`dbghelp`) + editor
|
||
tool DLLs (`ctcl`/`ijl10`/`Resources`/`Language.oeg`) + MFC + our `MW4Ed2.exe`; the bulk
|
||
(`Content\`, `resource\`, `hsh\`) are **directory junctions** to the dev tree
|
||
`Gameleap\mw4` (no 5.5 GB copy). Same `DWM8And16BitMitigation` compat shim as the game.
|
||
- **Content data fix needed to launch:** `Content\skies.build:109` declares
|
||
`File=Skies\reduex_sky\reduex_night.erf`, but the night-sky erf was misnamed
|
||
`Reduex_sky_night.erf`. The editor (LAB_ONLY, asserts on missing files) STOPped on it.
|
||
Fixed by adding `reduex_night.erf` (copy of `Reduex_sky_night.erf`) in
|
||
`Gameleap\mw4\Content\Skies\Reduex_sky\`. (A dev-content naming inconsistency, not a
|
||
build/toolchain problem — the editor itself builds+runs correctly.)
|
||
|
||
---
|
||
|
||
## ✅ STEP 8: Editor RUNS — root cause was DirectInput, NOT heap corruption (2026-06-22)
|
||
Installed **Debugging Tools for Windows** (`cdb` at `C:\Program Files (x86)\Windows Kits\10\
|
||
Debuggers\x86\cdb.exe`) and got the first fully-symbolicated faulting stack. **This overturned
|
||
the STEP 7 hypothesis:** the crash is NOT content-load heap corruption — it is a **modern-Windows
|
||
DirectInput init cascade** during `CMInstall` (GameOS), reproducible and deterministic:
|
||
|
||
1. **Joystick enumeration heap-corrupts in modern `dinput.dll`.** `CMInstall` ->
|
||
`CMCreateJoysticks` -> `wEnumDevices(DIEDFL_ATTACHEDONLY)` -> `CMCreateJoystick7`
|
||
(`ControlManager.cpp`). On Win11 the legacy **IDirectInput7** path, when it `Release()`s a
|
||
phantom/virtual HID "joystick" (0-axis "misreported device" at line ~602), corrupts the heap
|
||
inside `dinput.dll`. Surfaces as `RtlFreeHeap` AV (normal heap) or, under full PageHeap, as a
|
||
guard-page over-read in `dinput!DIWdm_InitJoyId` (`[esi+0x44]`). **The PageHeap "AV at ~1s"
|
||
from STEP 7 was THIS, mis-attributed to content loading.** The game survives by heap-layout luck.
|
||
- **FIX (source):** `CoreTech\Libraries\mfcplatform\MFCPlatform.cpp` `InitGameOS` now sets
|
||
`gDisableJoystick=1` (editor/`Platform_MFC` only; the game uses a different platform path and
|
||
is unaffected). Chosen over the `/gosnojoystick` switch because in **LAB_ONLY** builds
|
||
`WinMain.cpp:~398` shows a help dialog and **exits** if any leftover `/gos` token remains on
|
||
the command line — fragile (e.g. cdb perturbs the cmdline -> trips it). Tagged `[editor modern-Windows fix]`.
|
||
|
||
2. **Mouse `SetCooperativeLevel(NULL, FOREGROUND|NONEXCLUSIVE)` fails 0x80070006.**
|
||
`CMCreateMouse` (`Mouse.cpp`) resolves the coop window from `hWindow`, which is **always NULL**
|
||
in the editor at `CMInstall` time: the editor passes `pFrame->GameWnd->m_wndView.m_hWnd`, but
|
||
`InitSecondaryWindows` (`MainFrm.cpp:173`) only `new`s `CGameFrame` and never `Create()`s it, so
|
||
`CGameFrame::OnCreate` (which builds `m_wndView`) hasn't run. XP tolerated a NULL coop window;
|
||
modern DirectInput rejects it -> fatal PAUSE. (Keyboard has no coop-level call, so it survived.)
|
||
- **FIX (source):** `Mouse.cpp` `CMCreateMouse` falls back to `GetForegroundWindow()`/
|
||
`GetDesktopWindow()` with `BACKGROUND|NONEXCLUSIVE` when the resolved window is NULL; the game
|
||
path (valid `hWindow`) is unchanged. Tagged `[editor modern-Windows fix]`.
|
||
|
||
Rebuilt **`MW4GameEd2 - Win32 Profile`** (recompiles GameOS + MFCPlatform, relinks; 0 errors) ->
|
||
deployed `pro.bin\MW4Ed2.exe`+`.pdb` to `C:\VWE\firestorm\MW4Editor`. With both fixes + the content fixes
|
||
below, the editor **launches to a live, responsive, idle (0% CPU) main window** ("MechWarrior 4
|
||
Mission Editor - 05.07.00.00", ~70 MB) — the old "100% spin / not responding" is GONE. Launch with
|
||
just `-armorlevel 3` (no `/gos` flag needed).
|
||
|
||
### Content-curation fixes (FireStorm WIP dev tree, in `Gameleap\mw4\Content`)
|
||
The editor enumerates+loads EVERY mission/map at startup (`ObjMan->BuildResources()`) and STOPs
|
||
fatally on the first defect. Fixed (all additive/non-destructive unless noted):
|
||
- **`_backup` dev-copy dirs** (files named after the original, not the dir): created the missing
|
||
`<dir>.build`/`<dir>.instance` (page `[<dir>]`, unique resource targets):
|
||
`Maps\Colsm01_backup`, `Maps\StormCanyonSiege_Backup`, `Missions\Coliseum_backup`.
|
||
(Editor compiled these into `resource\maps\colsm01_backup.mw4` etc. — confirms they're valid.)
|
||
- **Dangling map refs:** `Missions\EditorTemplate\EditorTemplate.instance` `Map=` arctic01 (exists
|
||
nowhere) -> `arctic04`; `Missions\s1s2\s1s2.instance` `Map=` lunar02 -> `lunar01`.
|
||
- **Double-nested user mission:** `Missions\PhoenixPalaceSTB\PhoenixPalaceSTB\*` moved up one level
|
||
(the files already referenced the top-level path); then its `.instance` `Model=` pointed at
|
||
`dropzones\hill.contents` (page `[droppoints]`) -> fixed to `phoenixpalacestb.data` (page `[gamedata]`).
|
||
- Scans confirmed scope is small: 0 remaining mission page-name mismatches; 1 dangling map ref
|
||
(fixed); arctic01/lunar02 are genuine content gaps absent from ALL installs (dev Resource\Maps
|
||
has 46 .mw4 — MORE complete than game-deploy/knowngood's 26 — so launch folder/junctions are correct).
|
||
|
||
### ✅ 3D viewport FIXED via DDrawCompat (2026-06-22)
|
||
Root cause pinned with temporary diagnostics in `SetupMode`/`DirectDrawCreateAllBuffers`
|
||
(`DXRasterizer.cpp`, since reverted): every surface (front/back/Z), the clipper, and the
|
||
`IDirect3D7` object create fine with a valid `hWindow`, but **`IDirect3D7::CreateDevice` fails
|
||
with `0x88760082 = DDERR_INVALIDOBJECT`** for BOTH the hardware HAL (`IID_IDirect3DTnLHalDevice`
|
||
-> `IID_IDirect3DHALDevice`) and the Blade software device — i.e. **Win11's legacy DirectDraw does
|
||
not support creating a windowed Direct3D7 device** on an offscreen backbuffer (the game avoids
|
||
this by using a fullscreen flip-chain). Not a code-flag issue.
|
||
**Fix:** dropped **DDrawCompat** (narzoul, v0.7.1, `ddraw.dll`) into `C:\VWE\firestorm\MW4Editor\` — a
|
||
drop-in ddraw/d3d7 reimplementation. With it, `CreateDevice` succeeds and the **Game View/Overview
|
||
render** (user-confirmed). Source kept at `build-env\ddrawcompat\ddraw.dll`; `deploy-editor.ps1`
|
||
now copies it. The standalone game (`C:\VWE\firestorm\MW4`, fullscreen) is unaffected and does NOT use it.
|
||
**The editor is now fully working: launches, edits, and renders the 3D viewport.**
|
||
|
||
### ✅ Open-Mission dialog now lists ALL source missions (2026-06-22)
|
||
Symptom: editor's File->Open showed only **5** missions. Cause: `COpenMissionDlg::OnInitDialog`
|
||
(`OpenMissionDlg.cpp`) listed `Resource\UserMissions\*.mw4` (compiled/published user-mission
|
||
packages) — only 5 exist in the dev tree (and **0** in the game deploy `C:\VWE\firestorm\MW4`, so co-locating
|
||
the editor with the game would have shown ZERO, not more). But `CMainFrame::LoadMission` loads from
|
||
`Content\Missions\<name>\<name>.Instance`. **Fix:** changed the dialog to enumerate
|
||
`Content\Missions\*` subdirectories that contain a matching `<name>.instance` -> now lists all **51**
|
||
source missions. Tagged `[editor data fix]`. (Note: `INVALID_FILE_ATTRIBUTES` isn't defined in the
|
||
VC6 SDK; used the literal `0xFFFFFFFF`.) This made the requested "move editor into the game-binaries
|
||
folder" unnecessary — the editor already junctions the dev tree (`Gameleap\mw4`), the most complete
|
||
data (51 missions, 46 maps); the game deploy `C:\VWE\firestorm\MW4` actually has **0** user missions, so it
|
||
would have shown FEWER.
|
||
|
||
**Second half of the fix — actually LOADING the listed missions (`EditorApplication.cpp`
|
||
`LoadMissionResources`):** listing wasn't enough. Opening any non-user mission STOPped with
|
||
`Can't open <garbage>`. Cause: `LoadMissionResources` hardcoded the resource path as
|
||
`"Resource\\User"` + (name after first `\`), i.e. only `Resource\UserMissions\<name>.mw4` (the 5
|
||
user missions), and produced a garbage path (bad `strchr+1` pointer) for other name forms. But
|
||
**stock** missions compile to `Resource\Missions\<short>.mw4` with abbreviated lowercase names
|
||
(`CentralPark`->`cpark.mw4`, `Frostbite`->`fbite.mw4`) that aren't derivable by transform — the
|
||
short name is declared in each mission's `.build` (`[resource\missions\X.mw4]`). Fix: extract the
|
||
bare mission name, prefer `Resource\UserMissions\<name>.mw4`, else read the resource path straight
|
||
out of `Content\Missions\<name>\<name>.build`. Verified headlessly via `-report` (which also calls
|
||
`LoadMissionResources`): Coliseum -> 248 entities, CentralPark (cpark.mw4) -> 1709 entities, no STOP.
|
||
All 51 missions are now openable; the 5 user missions still work. Tagged `[editor data fix]`.
|
||
|
||
### (historical) Editor INTERACTIVE; the (now-fixed) windowed 3D viewport blocker
|
||
Verified via window enumeration: at startup the editor creates ALL its MDI children
|
||
(**Game View, Object Manager, Overview Window**) and presents a modal **"Open Mission"** dialog
|
||
(normal startup; main frame correctly disabled behind it) — the user opens a map from there and
|
||
the UI is usable. (Headless test runs "exit code 1" simply because nothing clicks that modal
|
||
"Open Mission" dialog — NOT a crash. Earlier "idle/Responding" readings were the process sitting
|
||
on that dialog; `Responding=True`+0% CPU cannot distinguish a working UI from a modal dialog —
|
||
enumerate windows to tell them apart.) The only real failure is **live 3D rendering**: selecting
|
||
**Game View** (and the Overview render once a mission draws) STOPs:
|
||
**`No software rasterizer available`**
|
||
(`DXRasterizer.cpp:2488`). Path: `DirectDrawCreateAllBuffers` -> `SetupMode` tries windowed
|
||
**hardware D3D7** (primary surface + clipper on `hWindow` + VRAM 3D backbuffer) which fails on
|
||
Win11's legacy DirectDraw, then falls back to **Blade software** (555 system-mem surface,
|
||
`SetupMode` line ~1816/1835) which also fails -> STOP. This is the **windowed legacy DirectDraw/
|
||
D3D7-on-Win11** problem — the SAME core incompatibility the game avoids by running **fullscreen-
|
||
exclusive** (+ `DWM8And16BitMitigation` shim). It is a distinct, deeper rendering-compat task from
|
||
everything above (which was input + content). To pursue: capture the exact failing `HRESULT` by
|
||
reproducing interactively (open map -> Game View) under cdb; candidate directions = a DDraw
|
||
compat layer (e.g. DDrawCompat), forcing a supported windowed surface format, or hosting the
|
||
viewport via a different present path. NOT yet solved.
|
||
|
||
### ✅ Deployment finalized (2026-06-22)
|
||
- **PageHeap REMOVED** (debug aid only): ran `reg import C:\VWE\firestorm\build-env\mw4ed2-pageheap-off.reg`
|
||
ELEVATED (UAC) -> HKLM IFEO `MW4Ed2.exe` key gone. The real-name `MW4Ed2.exe` now runs directly
|
||
(no longer AVs at ~2s). The `MW4Ed2_nph.exe` copy remains as a page-heap-immune fallback.
|
||
- **`deploy-editor.ps1` updated:** sources the **Profile** build (`pro.bin`, the working config) +
|
||
`.pdb`; writes `run-editor.bat` (`MW4Ed2.exe -armorlevel 3`, no `/gos`); sets the DDraw shim;
|
||
warns if PageHeap IFEO is present. A fresh deploy is runnable to the editor UI.
|
||
- **Launch:** `C:\VWE\firestorm\MW4Editor\run-editor.bat` (or `MW4Ed2.exe -armorlevel 3`). Pick a mission in
|
||
the startup "Open Mission" dialog. Everything except the live 3D render works.
|
||
- Expect more WIP content STOPs only if exercising missions/maps not loaded at startup.
|
||
- (Optional) Build Debug/Armor configs (need `dbg.bin`/`arm.bin` output dirs).
|
||
|
||
## ✅ STEP 9: Editor runs IN PLACE in the data tree — no separate `MW4Editor` dir (2026-06-23)
|
||
The editor's only job is editing the source content/resources in `Gameleap\mw4`, so the separate
|
||
`C:\VWE\firestorm\MW4Editor` deploy (which just junctioned back to `Gameleap\mw4`) was removed. `deploy-editor.ps1`
|
||
now **installs the editor into `Gameleap\mw4`**: copies `MW4Ed2.exe`(+pdb) + DDrawCompat `ddraw.dll`,
|
||
renames the two DDraw-breaking DLLs (`dbghelp.dll`/`imagehlp.dll` → `.disabled`), sets the DWM shim on
|
||
`Gameleap\mw4\MW4Ed2.exe`, and writes `Gameleap\mw4\run-editor.bat`. Verified: editor launches in place
|
||
with the full UI + DDrawCompat viewport (Game View/Overview/Object Manager/Resources).
|
||
- **Conflict handled:** DDrawCompat `ddraw.dll` is **fatal** to `MW4pro.exe`'s fullscreen build init
|
||
(`[DDrawCompat] Fatal Error`). Since the resource builder runs from the same `Gameleap\mw4`,
|
||
`build-resources.ps1` now moves `ddraw.dll` aside (`.buildaside`) for the build and restores it in a
|
||
`finally` (verified: build exit 0, ddraw restored).
|
||
- **Game deploy unaffected:** `deploy-mw4.ps1` adds `ddraw.dll` to its skip list, so DDrawCompat + the
|
||
editor exe/pdb/launcher/`.disabled` DLLs never leak into `C:\VWE\firestorm\MW4` (verified: 682 files / 868 MB,
|
||
58 packages, fullscreen native DDraw). Old launch path `C:\VWE\firestorm\MW4Editor\...` is superseded by
|
||
`C:\VWE\firestorm\Gameleap\mw4\run-editor.bat`.
|
||
|
||
## 📋 Reference: adding a new 'Mech chassis (documented 2026-07-01)
|
||
Full workflow in **`ADDING-A-MECH.md`** (repo root). Key facts: every registration point is
|
||
marked `// MSL ADD MECH` (~41 files); Mech IDs are positional/alphabetical parallel-array
|
||
indices spanning code + tables + shell scripts; `BTFrstrm\scriptaddmech.xls` is a generator
|
||
workbook for the per-mech rows; mechlab hardpoints live in the mech's `.damage` (`OmniSlots=`
|
||
etc.), default loadout in `.subsystems`; 2D HUD/MFD bmps load loose from `hsh\`; a new chassis
|
||
needs MW4.exe rebuild + resource repack + redeploy. `Finished HUDS from J&J\` = pending MFD/
|
||
radar art for ~13 chassis.
|
||
|
||
## 📋 Reference: FS507D_20161015 release drop analyzed (2026-07-01)
|
||
`FS507D_20161015\` (repo root, **gitignored** — not part of the mirror) = a later shipped
|
||
LAN-center release of this game (postinstall.bat maps per-machine 10.0.0.x IPs; Mumble refs).
|
||
**2026-07-02: release contents DELETED (user holds the zip archive); only
|
||
`FS507D_20161015\art-review\` remains** — 800 side-by-side pairs (`*.RELEASE.*` vs `*.OURS.*`,
|
||
flattened paths, `manifest.tsv`) of art whose CONTENT differs from our sources, awaiting the
|
||
user's review: `DIMS-DIFFER\` 451 (structurally different, e.g. 3state button strips grew
|
||
110×105→110×180, btfconsole.tga 800×600 vs 112×112), `PIXELS-DIFFER\` 280 (same format,
|
||
repainted), `HSH\` 69 (loose hsh bmps beyond pure depth-reduction; 91 8bpp-reductions of our
|
||
24bpp sources excluded). ALL packaged art diffs are shell-UI art (`shellscripts\graphics\**`,
|
||
`mechbay\graphics\**`, lobby skins/decals/mechicons) — zero world/mech texture diffs; the
|
||
release = a 5.07D UI-art refresh + the ComputerPlayer console script. (Extraction note:
|
||
6,469 map/mission-package texture entries are 4-byte cross-package reference stubs, not art.)
|
||
Findings vs our tree:
|
||
- **Binaries are a 2016 rebuild of (essentially) our source.** Release `MW4.exe` linked
|
||
2016-10-04, Launcher/MissionLang/ScriptStrings/ctcls 2014, but `mw4pro.exe` is the ORIGINAL
|
||
2009-06-14 build, byte-size-identical to our rebuild. `__TIMESTAMP__` banner in MW4.exe:
|
||
ours `Sun Jun 14 01:45:57 2009` vs release `02:45:57` = same MWApplication.cpp within a DST
|
||
hour. Full strings-diff of the exes: all meaningful strings present on BOTH sides (incl.
|
||
`BiggieSizeIt`/`RuleBook`, which our `VehicleInterface.cpp` has). **No evidence of missing
|
||
source.**
|
||
- **✅ Degraded-mode placeholder patch made LAB-only (2026-07-02).** Our rebuilt game exe used
|
||
to contain the `01AACA1.tga` placeholder (Adept links into the game); release was clean.
|
||
`ResourceImagePool.cpp` now: `#ifdef LAB_ONLY` placeholder (editor keeps degraded mode),
|
||
`#else` original `STOP(("Texture %s could not be found!"))`. Release+Profile rebuilt (0 err),
|
||
verified placeholder gone from `rel.bin\MW4.exe` / present in `MW4pro.exe`; both deployed
|
||
to `C:\VWE\firestorm\MW4`.
|
||
- **✅ `hsh\` mech art synced from release (2026-07-02).** Release hsh was NEWER than our dev
|
||
tree and matches OUR SOURCE'S names (`huddamage.cpp` wants `hud\assassin2/behemoth/
|
||
behemothii`...). Copied the 13 missing files into `Gameleap\mw4\hsh` + deploy (hud/radar
|
||
assassin2+behemoth+behemothii, Mechs behemoth/black hawk/longbow/solitare/victor, decals
|
||
46/47); `Mechs\black hawk.bmp`+`solitare.bmp` upgraded to our 24bpp twins (blackhawk/
|
||
solitaire renames). Did NOT overwrite the ~158 existing bmps that "differ": release ships
|
||
8bpp palette reductions of our 24bpp sources (deploy-mw4.ps1 reduces at deploy anyway).
|
||
- **resource .mw4 detail (via `.dep`/package name-set parsing, 2026-07-02):** entry SETS are
|
||
identical for core/textures/all 26 maps/all 29 missions (maps byte-identical ±2B; mission
|
||
payload drift of ±0.1-33KB = ABL/notation re-serialization, not content). All 29 `.nfo`
|
||
byte-identical. **Only real packing deltas, both in props.mw4:** (1) release packs
|
||
`shellscripts\graphics\multiplayer\lobbydecals\decal_46.tga`+`decal_47.tga` — ✅ RECOVERED
|
||
2026-07-02: decoded the #VBD container (dir records = [len][name][FILETIME][origSize]
|
||
[storedSize][offset]; payload base = dword@0x0C) + ported `gos_LZDecompress` (FileIO.cpp:1693
|
||
— LZW, 9→12-bit LSB-first codes, 256=clear/257=EOF/dict@258) and extracted both TGAs into
|
||
`Content\ShellScripts\graphics\multiplayer\lobbydecals\` (32×32 32bpp, verified: exact RLE/
|
||
size/footer + rendered; 46=radiation emblem, 47="331" crest). Next resource repack picks
|
||
them up and closes the props.mw4 gap;
|
||
(2) OUR props.mw4 sweeps in junk `ConLobby.script.new`/`.script.org` backup files from
|
||
`Content\ShellScripts\` (harmless but shippable-junk; note `.script.new` carries MSL ADD
|
||
MECH markers — review before deleting/moving). Release ships user missions s1s1-s1s3
|
||
(.nfo+.tga only, no .mw4 — campaign coop redirects per missionnames.tbl).
|
||
- **✅ FULL extraction of every release .mw4/.dep done (2026-07-02)** →
|
||
`FS507D_20161015\extracted\<pkg>\...` (~1.3 GB, 60+ packages, 0 decode failures; extractor =
|
||
the ported gos_LZDecompress + #VBD directory parser; raw-vs-LZ rule per Database.cpp:451:
|
||
stored==orig → raw).
|
||
- **✅ Completeness audit (2026-07-02): NOTHING else in the release is absent from our tree.**
|
||
Mapped all ~42k extracted package entries (23,649 unique base source paths after stripping
|
||
`{GameModel}`/`{hint}`/`[page]` qualifiers) against the dev tree by path + whole-tree
|
||
filename index: the only release-assets we lacked were the 13 hsh bmps + 2 lobby decal
|
||
TGAs (recovered) and the JPP console-script revision (superseded by our ConLobby.script.new).
|
||
Residuals: mission root-page pseudo-entries (not files) + 34 `{CampaignInterfacePlug}`
|
||
records = compiled campaign-screen metadata whose `.Campaign` sources we have. (Caveat:
|
||
audit is by existence, not content equality — release re-saved some shared files, e.g.
|
||
decal_00.tga pixels differ.)
|
||
- **The FireStorm console script in the release sits under the package entry name
|
||
`shellscripts\ComputerPlayer.script`** (138,990 B, title "BattleTech Console V5.07.D") — the
|
||
release's `ConLobby.script` ENTRY holds a 6,551 B copy of an old CreatePilotModal.
|
||
**2026-07-02 CORRECTION: nobody renamed anything — this is the packer's name↔content skew**
|
||
(see "Resource packer quirks" below): the console SOURCE file in the 5.07D tree was
|
||
ConLobby.script all along, same as ours; the packer stores script contents under alphabetically
|
||
shifted entry names, and the runtime reproduces the same pairing, so it works in-game and only
|
||
looks swapped to extraction tools. **Console script genealogy (oldest→newest):**
|
||
dev `ConLobby.script` ("V5.07", 138,544 B) → release console ("V5.07.D",
|
||
+29 lines: JPP's decal-dropdown feature adding decals 46=BKG/47=FSA, MAX_DECAL_COUNT 17→20)
|
||
→ dev `ConLobby.script.new` ("V5.0.7Df", 140,532 B, changelog "06/19/18 AVB": includes the
|
||
JPP decal work PLUS ROWFIELD_TYPE_*/MAIL_SLOTTYPE_* slot framework + tab stops). **Our
|
||
`.new` is the newest console revision anywhere** — the release only added what .new already
|
||
contains. ✅ **RECONCILED 2026-07-02:** `.new` promoted to `Content\ShellScripts\ConLobby.script`
|
||
(140,532 B), `.new` file removed, stale loose deploy copy `MW4\Content\shellscripts\ConLobby.script`
|
||
removed (release also ships no loose copy), props.mw4 fully repacked + redeployed. Verified
|
||
in-game: console title shows "BattleTech Console V5.0.7Df".
|
||
- **Release-only config:** `options-game.ini` enables `hardwaremixing=true`, `BiggieSizeIt=1`,
|
||
`RuleBook=1` (our inis don't); ctcl inis use 10.0.0.x (ours 200.0.0.x) + `c:\games\MW4` paths.
|
||
- **Release drops all Movies** (~310 MB) and the loose `content\shellscripts\conlobby.script`
|
||
(both deploys load shell scripts from props.mw4; ours ships that one loose 140 KB script —
|
||
check whether a loose script shadows the packed one).
|
||
|
||
## 📋 Reference: adding a new map/mission (documented 2026-07-01)
|
||
Full workflow in **`ADDING-A-MAP.md`** (repo root). Key facts: unlike mechs, NO code changes /
|
||
positional arrays / exe rebuild — maps+missions are discovered by enumeration. Map (terrain) =
|
||
`Content\Maps\<Map>` (MapCreator.exe tiles) vs Mission (scenario) = `Content\Missions\<Name>`
|
||
(authored in MW4Ed2, which clones `EditorTemplate`). Registration: nest mission .build under its
|
||
map in `MechWarrior4.build` (manual — editor's AddToBuildFile() call is commented out), MP game
|
||
types via loose `Resource\Missions\<Name>.nfo`, `missionnames.tbl` self-row, optional
|
||
`InstantAction.Campaign` page for the IA list; user missions (`Resource\UserMissions\*.mw4+.nfo`,
|
||
editor-published) are auto-discovered with zero manifest edits. Original toolkit tutorials
|
||
(map creation/terrain/NFO/ABL) live in `_UNUSED\Gameleap\EditorDocs\`.
|
||
|
||
## 📋 Reference: raising the MP player cap 16 → 24 (investigated 2026-06-24; NOT planned)
|
||
Captured for the future; **we are not tackling this in the foreseeable future.** Question was
|
||
whether `ConLobby.script`'s `MAX_ROSTER_COUNT 16` could be 24. Findings:
|
||
- **No engine wall at 16 — the real ceiling is 255.** `Adept::Maximum_Players = 255`
|
||
(`mw4\Libraries\Adept\Application.hpp:139`); every per-player fixed array (`servedConnectionData[]`,
|
||
scoreboards, net-stats, mission-review logs, `pdmg_given/rcvd`) is sized to 255. `connectionID`
|
||
is a `BYTE` (0–255). `Environment.NetworkMaxPlayers` is passed straight to DirectPlay's
|
||
`dwMaxPlayers` (`CoreTech\...\GameOS\Net_Main.cpp:2142`) — no GameOS ceiling; `m_maxPlayers` has
|
||
no hard upper clamp (`MW4Shell.cpp:1803` only clamps *bots* down to the player count).
|
||
- **16 is enforced in THREE layers — a script edit alone is insufficient/misleading:**
|
||
1. UI: `Content\ShellScripts\ConLobby.script` `#define MAX_ROSTER_COUNT 16` (already 8→16; gated by
|
||
`USE_O_MORE_PODS`/`g_nMechPodNum`; also clamps vs `MAXTESLA_P` = cafe Tesla count, ≤8).
|
||
2. **Compiled defaults (the real connect gate):** `MW4Shell.cpp:13319-13321` non-coop sets
|
||
`m_maxPlayers=16; Environment.NetworkMaxPlayers=16; m_maxBots=16` (coop branch caps at 9).
|
||
Editing only the `.script` shows 24 slots but the session still rejects the 17th player.
|
||
3. Lobby pods / scoreboard (`hudscore`) / radar UI are laid out for ≤16.
|
||
- **To actually reach 24:** raise `MAX_ROSTER_COUNT` **and** the `m_maxPlayers`/`NetworkMaxPlayers`/
|
||
`m_maxBots` defaults (→ rebuild `MW4.exe`), rework lobby/scoreboard/radar layouts, and ensure maps
|
||
define **≥24 drop zones / start points** (many MP maps only have ~16 — a per-map content limit).
|
||
- **Why the cap exists (the practical blocker):** replication is ~O(n²) — 24 vs 16 ≈ (24/16)² ≈
|
||
**2.25× host outbound + CPU**; the dictionary/culling netcode was tuned for ≤16. Bandwidth, not
|
||
the data structures, is the ceiling.
|
||
|
||
### 📐 PLAN: raise MP cap 16 → 32 (drafted 2026-06-24; NOT scheduled)
|
||
Concrete plan extending the reference above to **32 players**. Phased; each phase is independently
|
||
testable. 32 is safe vs the engine ceiling (255 arrays, `BYTE` connectionID) and has **no 32-bit
|
||
player-mask boundary risk** — verified the only `0x1<<id` masks are per-mech *weapon* bits
|
||
(`MWEntityManager.cpp:1332`, `NetWeapon.cpp`), not player/connection indices.
|
||
|
||
**Phase 1 — Code defaults + lobby-param path (rebuild `MW4.exe`, Release + Profile).**
|
||
- `MW4Shell.cpp:13319-13321` (non-coop game setup): `m_maxPlayers`, `Environment.NetworkMaxPlayers`,
|
||
`m_maxBots` `16 → 32`. Coop branch `13309/13315-13316` (`=16`/`=9`/`=8`) — leave or bump per design.
|
||
- `MW4Shell.cpp:1803-1831` (lobby-driven path): `m_maxPlayers=INTPARM(1)`, `m_maxBots=INTPARM(1)`,
|
||
`Environment.NetworkMaxPlayers = params->m_playerLimit`. No hard upper clamp exists
|
||
(`1808 Max_Clamp(m_maxBots, m_maxPlayers)` only clamps bots down) — but confirm the lobby
|
||
"player limit" control feeds a value up to 32 (param `PLAYER_LIMIT_PARAMETER`, `NetParams.h:53`).
|
||
- Grep-audit for any other implicit ≤16 assumptions before rebuild (none found so far; arrays=255).
|
||
|
||
**Phase 2 — Lobby + in-game UI (repack `props.mw4`). [LOW PRIORITY]**
|
||
Cosmetic/usability, not a functional blocker: with only Phases 1+3 done, 32 players can still
|
||
connect, spawn, and play — the lobby pods/roster and scoreboard/radar just overflow or clip past
|
||
16 (and the host can still set the limit via the param path even if the slider UI caps lower).
|
||
Defer this polish until 32p is otherwise proven; do the minimum to make the lobby usable, leave full
|
||
pod/scoreboard re-layout for later.
|
||
- `Content\ShellScripts\ConLobby.script`: `MAX_ROSTER_COUNT 16→32`, `MAX_TEAMMATE_COUNT 8→16`
|
||
(both under `USE_O_MORE_PODS`/`g_nMechPodNum`); raise the player-limit control's max to 32.
|
||
Note the `MAXTESLA_P` clamp is cafe-only (CTCL Tesla count) and won't block non-cafe play.
|
||
- **Biggest UI lift — the mech-selection "pods":** the lobby draws a fixed grid of player/mech pods;
|
||
32 needs a reworked layout (grid size, scrolling, or smaller pods). Same for the team-assignment
|
||
panel (`TEAM_MAX_PLAYERS`, `team_max_plyrs` @ ConLobby:328).
|
||
- Multiplayer lobby scripts (`Content\ShellScripts\Multiplayer\*` incl. `lobby_listbox.script`,
|
||
`HostLobbyMission.script`): roster list sizing + player-limit slider range.
|
||
- In-game **scoreboard** (`hudscore.cpp`) and **radar** (`GUIRadarManager.cpp`): data is fine
|
||
(255 arrays) but the on-screen score table / legend is laid out for ≤16 → rework for 32 (scroll
|
||
or two columns). `MP_Review.script` top-down review screen likewise.
|
||
|
||
**Phase 3 — Map content (per-map; the gating gameplay task).**
|
||
- Every MP map used at 32p must define **≥32 drop zones / start points**. Most stock maps have ≤16;
|
||
players 17-32 silently fail to spawn otherwise. Audit + author extra drop points in the editor
|
||
(now runnable in place from `Gameleap\mw4\run-editor.bat`). This is per-map, independent of code.
|
||
|
||
**Phase 4 — Netcode / performance. [LIKELY FINE on modern hardware/networks]**
|
||
- Replication is ~O(n²): 32 vs 16 ≈ (32/16)² = 4× host outbound + CPU. This was the limiting factor
|
||
in 2002 (dial-up / early broadband), but **modern broadband upstream + CPU absorb 4× easily** — raw
|
||
bandwidth/CPU is no longer expected to block 32. Demote from "real ceiling" to a verification item.
|
||
- Residual (non-bandwidth) thing to check when implementing: any **fixed-size netcode buffers / per-
|
||
frame packet or replication caps** hardcoded for ≤16 (distinct from bandwidth; e.g. packet-count or
|
||
buffer limits). Audit during Phase 1; bounded by the 255-array design, so likely none. Still do a
|
||
live load test to confirm, but don't expect tuning to be needed.
|
||
|
||
**Verification:** (1) rebuild → headless `-report`/launch sanity; (2) host a game, confirm 32 slots
|
||
in lobby + 17th–32nd players connect (`Environment.NetworkMaxPlayers`/DirectPlay `dwMaxPlayers`);
|
||
(3) confirm spawns on a 32-drop-zone map; (4) load/bandwidth test; (5) check scoreboard/radar/review
|
||
UI legibility. **Primary remaining work:** per-map drop-zone authoring (Phase 3) is now the main
|
||
gating task. UI (Phase 2) is low-priority non-blocking polish; bandwidth/CPU (Phase 4) is expected
|
||
fine on modern hardware — just verify fixed-size netcode buffers and run one live load test.
|
||
|
||
## Next steps (proposed)
|
||
- [x] ~~Windowed 3D viewport on Win11~~ — DONE via DDrawCompat (see STEP 8 viewport section).
|
||
- [ ] (Optional) Curate remaining WIP content as features are exercised (editor loads dev `Content\`).
|
||
- [ ] (Optional) Build Debug/Armor configs (need `dbg.bin`/`arm.bin` output dirs).
|
||
- [ ] (Parked, NOT scheduled) Raise MP cap to 24 or 32 — see "Reference"/"PLAN" sections above.
|