Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
7.9 KiB
Building the .mw4 resource files
How the runtime game resources (resource\*.mw4 + resource\*.dep) are produced from
the Content\ source tree. Reverse-engineered from the engine source
(mw4\Code\MW4Application, mw4\Code\MW4, mw4\Libraries\Adept).
VERIFIED end-to-end (2026-06-11) with our freshly built
MW4pro.exe(Profile/LAB_ONLY): a minimalContent\MechWarrior4.buildpacked a test file intoresource\restest.mw4+.dep(exit 0, ~4 s). Confirmed:.mw4carries the#VBDResourceFile magic + content version + payload;.deprecords the source dependency; incremental logic works — re-running with no change skipped (timestamp unchanged), changing the source triggered a rebuild (new timestamp + new payload). The Release exe was also confirmed to ignore-buildas predicted. Run line used:MW4pro.exe -build -norun -window -nosound -nocd -noeula(cwd = a dir containingContent\).
TL;DR
- The resource compiler is built into the game executable itself, not a separate tool.
- It runs when the exe is launched with the
-buildflag. - Only
LAB_ONLYbuild configs can build resources — i.e.MW4_dbg(Debug),MW4_arm(Armor), orMW4pro.exe(Profile). The ReleaseMW4.execannot (the-buildhandling is#ifdef LAB_ONLY). - It reads
Content\MechWarrior4.build(a master manifest) and writes the.mw4/.deppackages intoresource\. - It is incremental: a package is only rebuilt if missing or out of date.
The exe-config requirement (important)
MW4Application.cpp parses -build only inside #ifdef LAB_ONLY:
#ifdef LAB_ONLY
Application::BuildOK = (strstr(all_lower, "-build") != NULL);
#endif
From the .dsp preprocessor defines (see CLAUDE.md):
| Config | LAB_ONLY? | exe | can -build? |
|---|---|---|---|
| Release | no (RELEASE) |
rel.bin\MW4.exe |
NO |
| Profile | yes | rel.bin\MW4pro.exe |
yes |
| Armor | yes | arm.bin\MW4.exe |
yes |
| Debug | yes | dbg.bin\MW4.exe |
yes |
That is why the stock bldresources_game_*.bat invoke the LAB_ONLY exes:
bldresources_game_dbg.bat -> ...\MW4_dbg -armorlevel 3 -build
bldresources_game_armor.bat -> ...\MW4_arm -armorlevel 3 -build
bldresources_game_profile.bat -> ...\MW4_prf -armorlevel 3 -build
(-armorlevel 3 is an assertion/validation level; -build does the work. Without
-build the same exe just runs the game using whatever .mw4 files already exist.)
Inputs
- Master manifest:
Content\MechWarrior4.build— a NotationFile whose top level is a tree of other.buildfiles to process, e.g.:The nesting expresses build order + scope (children are built within the parent's context).textures.build={ core.build={ props.build={ maps\alpine02\alpine02.build={ missions\timberline\timberline.build={ } } ... - Per-package
.buildfiles — each defines exactly ONE output package. The single page name is the output path; the entries are the source items to pack. e.g.core.build:[resource\core.mw4] <- output package core=yes <- mark as a "core" (global/shared) package data=Effects\AC_Flare\AC20_Flare.data data=Effects\AC_hit\AC10Hit_Grass.data ... - Source assets under
Content\referenced by the entries (.data, instance files, textures, etc.). The full source content tree must be present.
Entry types (what can go into a package)
Handled by Adept::Tool::BuildResource (generic) and MechWarrior4::MWTool::BuildResource
(game-specific override). Each entry becomes one record in the output .mw4:
Generic (Adept\Tool.cpp):
instance=— an entity instance (compiled CreateMessage)data=— a data list (ConstructDataList)notation=— a notation file embedded verbatimfile=— an arbitrary file embedded verbatimdirectory=— every file in a directory embedded verbatim
Game-specific (MW4\MWTool.cpp): campaign, lancemate, salvage, armature,
subsystems, damage, mwtable, options — each parses a source NotationFile and
constructs a typed stream.
Output
Tool::BuildResources first ensures the output dirs exist:
resource\, resource\Maps\, resource\Missions\, resource\Variants\.
For each .build it produces:
resource\<name>.mw4— the packedResourceFile(records keyed by ID).resource\<name>.dep— theFileDependencieslist (source files + timestamps) used to decide staleness on the next build.
A content version is stamped into every package: VER_CONTENTVERSION (currently
63, from Buildnum\buildnum.h). The runtime uses it to reject mismatched resources.
Incremental rebuild logic (Tool::BuildResources)
For each package:
build_age = max(timestamp(this .build file), parent build_age)
dirty = (timestamp(resource_file) < build_age) OR (.dep file missing)
open ResourceFile(name, dep, level, content_version, dirty)
ParseBuildFile(...) // each entry: BuildResource() only re-packs if the
// individual Resource DoesResourceExist()==false
// or IsResourceUpToDate()==false
res_file->Save()
core=yespackages: the engine ignores per-file dependency chaining (they're treated as global/shared and always considered in-scope for children).- Non-core packages: the package adds itself to the dependency set passed to its children, so a map/mission package depends on its parent map package, etc.
- Net effect: re-running
-buildafter editing one source file rebuilds only the affected package(s), not the whole 1 GB set.
How to (re)build resources in practice
- Build a LAB_ONLY game config (Profile is the lightest): in the VC6 IDE build
MW4Application - Win32 Profile(outputsrel.bin\MW4pro.exe). See CLAUDE.md / build-env\README.md for the toolchain. - Run it from a directory that has the
Content\source tree (and where you wantresource\written), with-build:(AddMW4pro.exe -armorlevel 3 -build-window -nosoundetc. as desired; it still launches the game after building, so-noruncan be used to build-and-exit — see the flag parser in MW4Application.cpp.) - The engine creates/updates
resource\*.mw4+*.dep. Copy the resultingresource\into the deployment (the deploy script already treatsresource\as a whole-keep dir).
Integrated into deployment (2026-06-23)
build-env\build-resources.ps1 wraps the above (stages the fresh MW4pro.exe, applies the
DDraw shim, runs -build -norun -window -nosound -nocd -noeula in the source tree with a
timeout guard, reports rebuilt packages). deploy-mw4.ps1 now calls it as step [0/5] so a
deploy repacks resource\*.mw4 from current source before copying to the target — this is
what makes loose source edits (e.g. Content\ShellScripts\ConLobby.script) actually take
effect, since the runtime loads packed resources before loose disk files (s_DiskFirst
defaults to false in Application::GetFileForGOS). Use deploy-mw4.ps1 -SkipResourceBuild to
deploy the existing prebuilt packages unchanged. The build writes into Gameleap\mw4\resource
(the editor junctions this, so it benefits automatically). A modal content STOP in the WIP tree
trips the timeout and is reported (fix the asset, re-deploy) rather than hanging the deploy.
Caveats
- The Release build will silently ignore
-build— you must use a LAB_ONLY exe. - Requires the full
Content\source tree (the devGameleap\mw4\Content, ~4.6 GB). The trimmed runtime deployment does NOT contain it. -buildbuilds againstContent\MechWarrior4.build; to build a subset, point a smaller master build file at just the packages you want (the format is plain NotationFile text).- Bump
VER_CONTENTVERSIONinBuildnum\buildnum.hif resource formats change, or the runtime will load stale.mw4files.