diff --git a/CMakeLists.txt b/CMakeLists.txt index ab7277e..ca607a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -322,10 +322,12 @@ target_link_libraries(btl4 PRIVATE "${DXSDK}/Lib/x86/dxguid.lib" "${DXSDK}/Lib/x86/DxErr.lib" winmm dbghelp shell32 user32 gdi32 ole32 ws2_32) -# /FORCE: the 1995 headers define free funcs/globals without inline/extern, so -# identical symbols land in every TU (~124 LNK2005); MULTIPLE keeps the first. -# UNRESOLVED tolerates the dead offline-tool factory in mech3.cpp. See docs. -target_link_options(btl4 PRIVATE /FORCE) +# /FORCE:MULTIPLE: the 1995 headers define free funcs/globals without +# inline/extern, so identical symbols land in every TU (~124 LNK2005); +# MULTIPLE keeps the first. UNRESOLVED is gone (BT412/v143): the dead +# offline-tool factory in mech3.cpp is neutralized behind BT412_OFFLINE_TOOLS, +# so any unresolved external is now a REAL link error, not a runtime AV. +target_link_options(btl4 PRIVATE /FORCE:MULTIPLE) # Copy the third-party runtime DLLs next to the built exe. add_custom_command(TARGET btl4 POST_BUILD diff --git a/README.md b/README.md index 11c33d8..19f1952 100644 --- a/README.md +++ b/README.md @@ -50,9 +50,10 @@ CLAUDE.md knowledge-base ROUTER — identity, protocols, quick-lookup, ## Prerequisites -- **Visual Studio 2019 BuildTools** (MSVC v142, x86). The Community install on the original dev - box was broken, hence the explicit BuildTools instance in the configure line below; adjust to - your install. +- **Visual Studio 2022 BuildTools** (MSVC v143, x86) — the BT412 toolchain of record (moved from + the 2019/v142 line at the 4.12 fork; v142 still builds if you swap the generator back). The + explicit BuildTools instance in the configure line below matches the dev box; adjust to your + install. - **CMake ≥ 3.20**. - **Legacy DirectX SDK (June 2010)** — the engine uses `d3dx9`/`dinput`/`dxerr`, removed from the modern Windows SDK. Default path `C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)`; @@ -65,16 +66,19 @@ the exe automatically at build time. ## Build (32-bit / Win32) ``` -cmake -S . -B build -G "Visual Studio 16 2019" -A Win32 ^ - -DCMAKE_GENERATOR_INSTANCE="C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools" +cmake -S . -B build -G "Visual Studio 17 2022" -A Win32 ^ + -DCMAKE_GENERATOR_INSTANCE="C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools" cmake --build build --config Debug ``` -Must be **Win32** — the DirectX SDK link libs are `Lib/x86`. The link uses `/FORCE`: the 1995 -headers define free functions/globals without `inline`/`extern`, so identical symbols appear in -many translation units (~124 `LNK2005`); `/FORCE:MULTIPLE` keeps the first. `UNRESOLVED` tolerates -a dead offline-tool factory in `mech3.cpp` that is never called at runtime. (Cleanup task: move -those definitions to single TUs + neutralize the dead factory, then drop `/FORCE`.) +Must be **Win32** — the DirectX SDK link libs are `Lib/x86`. The link uses `/FORCE:MULTIPLE`: the +1995 headers define free functions/globals without `inline`/`extern`, so identical symbols appear +in many translation units (~124 `LNK2005`); `MULTIPLE` keeps the first. `UNRESOLVED` is gone as of +4.12 — the v143 linker refuses to emit an image with unresolved externals even under `/FORCE`, so +the dead offline-tool factory in `mech3.cpp` is neutralized behind `BT412_OFFLINE_TOOLS` (default +off) and a genuinely unresolved symbol is now a hard link error instead of a hidden runtime AV. +(Remaining cleanup task: move the multiply-defined globals to single TUs, then drop `/FORCE` +entirely.) ## Run diff --git a/context/build-and-run.md b/context/build-and-run.md index e242ba4..fb6ed51 100644 --- a/context/build-and-run.md +++ b/context/build-and-run.md @@ -13,20 +13,24 @@ The one top-level `CMakeLists.txt` builds `munga_engine` (engine) + `bt410_l4` ( game lib) + `btl4.exe`. Full recipe + repo-layout map: `docs/PROGRESS_LOG.md §10a / §10a-bis` + `README.md`. Env-gate table: [[decomp-reference]] §6. -## Build (Win32 / VS2019 BuildTools — the DXSDK link libs are Lib/x86) +## Build (Win32 / VS2022 BuildTools — the DXSDK link libs are Lib/x86) ``` -# configure once: -cmake -S C:\git\bt411 -B C:\git\bt411\build -G "Visual Studio 16 2019" -A Win32 \ - -DCMAKE_GENERATOR_INSTANCE="C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools" +# configure once (BT412 toolchain of record, moved from VS2019/v142 at the 4.12 fork): +cmake -S . -B build -G "Visual Studio 17 2022" -A Win32 \ + -DCMAKE_GENERATOR_INSTANCE="C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools" # build: -cmake --build C:\git\bt411\build --config Debug +cmake --build build --config Debug ``` - Links DXSDK d3d9/d3dx9/dinput8 + OpenAL/libsndfile (`engine/lib/`). DXSDK June 2010 at `C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\` (overridable `-DDXSDK`). [T2] -- Linker uses **`/FORCE`** — tolerates header-defined globals + the **dead offline-factory - unresolved externals in mech3.cpp** (`Mech::CreateSubsystemStream` references `void*`-signature - `CreateStreamedSubsystem` for every class; never called at runtime). ⚠ `/FORCE` also HIDES real - unresolved symbols as runtime AVs — see [[reconstruction-gotchas]] §6. [T2] +- Linker uses **`/FORCE:MULTIPLE`** — tolerates the ~124 header-defined-global LNK2005s. + **`UNRESOLVED` is gone (BT412, 2026-07-14):** the v143 linker refuses to emit an image with + unresolved externals even under `/FORCE`, so the dead offline-tool ladders in `mech3.cpp` + (`Mech::CreateSubsystemStream` / `Mech::SubsystemDefaultData` — never called at runtime) are + compiled out behind `BT412_OFFLINE_TOOLS` (default off). A genuinely unresolved symbol is now a + hard LINK ERROR, not a hidden runtime AV — the [[reconstruction-gotchas]] §6 hazard class is + retired for the exe link. No other source changes were needed for v143 (verified: clean build, + solo DEV.EGG run, two-instance loopback MP with replication). [T2] - Editing an `engine/` file rebuilds the engine lib automatically (one project). A NEW member on a `DPLRenderer`/`d3d_OBJECT` class needs the game objs that embed its layout recompiled — delete stale objs if layout-mismatch corruption appears. [T2] diff --git a/context/steamification.md b/context/steamification.md index 6dec628..e4b1a14 100644 --- a/context/steamification.md +++ b/context/steamification.md @@ -30,7 +30,17 @@ pattern). Forked at BT411 `4e72f0c` (2026-07-14). `run/run.cmd` working-tree edit discarded (committed version is the documented solo launcher), identity pass (README/CLAUDE.md/CMake `project(bt412)`), this topic + roadmap authored. -- Phase 1 (VS2022 v143): not started. +- **Phase 1 (VS2022 v143) — DONE 2026-07-14.** Generator moved to + `Visual Studio 17 2022` (v143, Win32). One real change was forced: the v143 linker + fails the image on unresolved externals even under `/FORCE`, so the dead + offline-tool ladders in `game/reconstructed/mech3.cpp` are neutralized behind + `BT412_OFFLINE_TOOLS` (default off) and the exe now links `/FORCE:MULTIPLE` + (UNRESOLVED retired — real unresolved symbols are hard errors now). None of RP412's + other v143 source fixes (TIME.h, NETWORK.h, L4DINPUT, CAMMGR) were needed — BT's + tree was already v142-clean. Verified: clean build; solo DEV.EGG runs (gait/target/ + 31-subsystem ticks); two-instance loopback MP via btconsole.py — mesh forms + (console + 1502↔1602 game ports, "All connections completed!"), mission runs both + sides, each world ticks its master + the remote replicant. [T2] - Phases 2–7: not started — see the roadmap. ## The seams (what plugs in where) [T0 unless noted] @@ -60,6 +70,23 @@ pattern). Forked at BT411 `4e72f0c` (2026-07-14). ## Known merge risks (from the 3-way BT411 / RP411-baseline / RP412 comparison) +**Quantified 2026-07-14 [T1]** — BT-vs-RP411-baseline divergence measured with +`diff --strip-trailing-cr` (baseline extracted from RP412 history, `git show +3b8b729:MUNGA_L4/`); RP412-side change sizes from `git diff 3b8b729..HEAD`: + +| File | BT vs baseline | RP412 change | Treatment | +|------|----------------|--------------|-----------| +| `L4RIO.h` | identical | 125 lines (RIOBase split) | RP412 verbatim | +| `L4RIO.cpp` | identical | 0 | nothing to do | +| `L4CTRL.h`, `L4NET.H`, `L4PLASMA.*`, `L4KEYBD.h` | identical | small | RP412 verbatim | +| `L4CTRL.cpp` | 29 diff lines | 17 (PadRIO hook) | apply RP412 diff | +| `L4GREND.cpp` | 6 diff lines | 15 (PlasmaScreen selector) | apply RP412 diff | +| `L4VIDEO.cpp` | **2725** diff lines (BT render work) | only 14 | apply RP412 diff — small despite BT divergence | +| `L4VIDEO.h` | 29 diff lines | 7 | apply RP412 diff | +| `L4NET.CPP` | 23 diff lines (BT_NET_TRACE ×5) | 345 (seam refactor) | **MEDIUM** — apply seam refactor, re-site traces | +| `L4VB16.cpp` | **514** diff lines (dev-gauge dock) | 350 (split view) | **HIGH** — true hand-merge | +| `L4VB16.h` | 14 diff lines | 32 | hand-merge with L4VB16.cpp | + - **`L4VB16.cpp` — HIGH.** RP412 rebuilt ~3846–4046 (splitViews/canvas/present); BT rebuilt the same window-management region for dev-gauge docking (`BT_DEV_GAUGES`, `BT_DEV_GAUGES_WINDOW`, `BT_DEV_GAUGES_DOCK`, `BT_GAUGE_SCALE`, `BT_GAUGE_SEC_ROT`, @@ -67,8 +94,6 @@ pattern). Forked at BT411 `4e72f0c` (2026-07-14). - **`L4NET.CPP` — MEDIUM.** RP412 rerouted all ~22–26 Winsock call sites through `NetTransport_Get()`; BT's 5 `BT_NET_TRACE` diagnostic blocks sit exactly on those send/receive sites and must be re-sited onto the seam calls. -- **`L4RIO.*`, `L4CTRL.cpp`, `L4GREND.cpp` — LOW.** BT never customized these - (verified: zero BT_ hits); take RP412's versions after the 3-way check. - **CMake**: engine sources are explicit per-file lines (no globs) — every ported `.cpp` needs its own `add_library` line or it silently doesn't compile. New deps: `xinput9_1_0.lib` (PadRIO), C++/WinRT (KeyLight, per-file C++17), Steamworks SDK + diff --git a/game/reconstructed/mech3.cpp b/game/reconstructed/mech3.cpp index b04e42b..deae01f 100644 --- a/game/reconstructed/mech3.cpp +++ b/game/reconstructed/mech3.cpp @@ -96,9 +96,11 @@ // Those ~21 classes live in sibling modules not visible here (and PPC / // GaussRifle / SubsystemMessageManager have no reconstructed class at all), // so the uniform factory surface is declared here as minimal stubs. The -// bodies/data are resolved at link against the real subsystem modules; these -// declarations only let the dispatch compile. Kept LOCAL so they never -// collide with the real sibling classes. +// bodies/data were NEVER reconstructed anywhere -- under v142 the link +// left them unresolved and /FORCE tolerated it (the path is dead at +// runtime); the v143 linker does not, so the dispatch ladders below are +// compiled out unless BT412_OFFLINE_TOOLS is defined. Kept LOCAL so they +// never collide with the real sibling classes if ever reconstructed. //===========================================================================// typedef Mech::SharedData SharedData; // namespace-scope alias (== Entity__SharedData) @@ -711,6 +713,20 @@ void NotationFile *subsystem_file, // param_8 const ResourceDirectories *directories) // param_9 { +#if !BT412_OFFLINE_TOOLS + //----------------------------------------------------------------------- + // BT412 NEUTRALIZED (offline authoring path -- never called at runtime; + // resources ship prebuilt in BTL4.RES). The ~21 per-subsystem + // CreateStreamedSubsystem statics were never reconstructed, and the + // VS2022 (v143) linker fails the image on unresolved externals even + // under /FORCE (the v142 linker tolerated them). The authentic + // dispatch ladder is preserved under BT412_OFFLINE_TOOLS for the day + // the offline tool path is reconstructed. + //----------------------------------------------------------------------- + DEBUG_STREAM << "[offline] Mech::CreateSubsystemStream(" << type_name + << ") reached with BT412_OFFLINE_TOOLS off\n" << std::flush; + return -1; +#else int result; if (Streq(type_name, "HeatSinkClassID")) @@ -765,6 +781,7 @@ void } return (result == 0) ? -1 : 1; +#endif // BT412_OFFLINE_TOOLS } @@ -909,6 +926,8 @@ fail: Mech::SubsystemDefaultData(const char *type_name) { if (Streq(type_name, "")) return &Mech::DefaultData; // 0050bde4 (DAT_0050dc1f == "") +#if BT412_OFFLINE_TOOLS // BT412 NEUTRALIZED with the factory above -- the per-subsystem + // DefaultData statics were never reconstructed (no callers at runtime). if (Streq(type_name, "ControlsMapper")) return &MechControlsMapper::DefaultData; // 0050ee00 if (Streq(type_name, "AmmoBinClassID")) return &AmmoBin::DefaultData; // 005125bc if (Streq(type_name, "HeatSinkClassID")) return &HeatSink::DefaultData; // 0050e580 @@ -930,6 +949,7 @@ fail: if (Streq(type_name, "GaussRifleClassID")) return &GaussRifle::DefaultData; // 00512478 (shares MissileLauncher table) if (Streq(type_name, "ControlsMapper")) return &MechControlsMapper::DefaultData; // 0050ee00 (2nd alias) if (Streq(type_name, "MechTech")) return &MechTech::DefaultData; // 0050e270 +#endif // BT412_OFFLINE_TOOLS return 0; }