Development Diary - March 2026¶
2026-03-31 (SESSION 101): Refactor OpenALAudioDevice to Core/GameEngineDevice¶
Moved the OpenALAudioDevice from GeneralsMD/Code/GameEngineDevice/ to Core/GameEngineDevice/ to properly position it as the cross-platform Linux/macOS equivalent of the Windows MilesAudioDevice.
2026-03-31 (SESSION 100): Pin DXVK macOS Remote Source to Immutable SHA¶
Implemented a safety change on main to avoid breakages from mutable DXVK branch heads during configure/build.
What was changed:
- Updated cmake/dx8.cmake macOS remote DXVK path to use an immutable commit ref instead of a branch name.
- Added DXVK_REMOTE_REF and wired ExternalProject_Add(... GIT_TAG ...) to that commit.
Pinned ref:
- 35965877b85c22c8bd0ce54b099a96bd9954b411 (from fbraz3/dxvk branch generalsx-macos-v2.6 at pin time)
Why:
- Prevent main from breaking when the tracked DXVK branch head moves unexpectedly.
- Make CI/local configure reproducible and promote DXVK updates explicitly via controlled SHA bumps.
Validation:
- cmake --preset macos-vulkan
- cmake --build build/macos-vulkan --target z_generals -- -j4
- cmake --build build/macos-vulkan --target g_generals -- -j4
All three commands completed successfully in this session.
2026-03-31 (SESSION 99a): Issue #59 WideChar Portability Fix + macOS Build Unblock¶
Addressed issue #59 by removing remaining 2-byte WideChar assumptions in shared Unicode serialization paths and validated both macOS game targets build successfully.
What was changed:
- Fixed UnicodeString::nextToken() copy size in shared Core code:
- replaced memcpy(..., len*2) with memcpy(..., len * sizeof(WideChar)).
- Reworked quoted-printable Unicode conversion in both game variants:
- GeneralsMD/Code/GameEngine/Source/Common/System/QuotedPrintable.cpp
- Generals/Code/GameEngine/Source/Common/System/QuotedPrintable.cpp
- encode/decode now operates on explicit UTF-16 code units (low/high byte pair), avoiding host wchar_t width dependency.
- Added a lesson entry in docs/WORKDIR/lessons/2026-03-LESSONS.md describing this portability class and prevention guidance.
Build/test status:
- macOS configure/build was initially failing in DXVK with unknown type name 'size_t' from the remote DXVK source copy.
- Local fork already contained the required #include <cstddef> in references/fbraz3-dxvk/src/util/util_math.h.
- Reconfigured with -DSAGE_DXVK_USE_LOCAL_FORK=ON and rebuilt successfully:
- z_generals build: OK
- g_generals build: OK
Notes:
- Build logs still contain existing warnings (deprecated sprintf, duplicate libs, deployment target mismatch warnings), but both targets link successfully.
2026-03-31 (SESSION 99b): Issue #57 Linux LAN IP Enumeration Fix¶
Implemented the fix for issue #57 where Linux LAN IP selection only exposed hostname/loopback-derived addresses.
What was changed:
- Updated Core/GameEngine/Source/GameNetwork/IPEnumeration.cpp to enumerate active IPv4 interfaces on Linux using getifaddrs().
- Applied filtering for AF_INET, interface IFF_UP, and non-loopback (!IFF_LOOPBACK) addresses.
- Preserved the legacy hostname-based path as fallback to avoid regressions when interface enumeration fails.
- Added duplicate-IP suppression in addNewIP() while keeping deterministic sorted insertion behavior.
- Recorded the lesson in docs/WORKDIR/lessons/2026-03-LESSONS.md.
Validation: - Base Generals and Zero Hour manual runtime validation reported as working by user. - Language diagnostics returned no errors for touched files.
2026-03-31 (SESSION 98): PR Review Follow-up - Watermark Lifetime and Label Gate Cleanup¶
Addressed PR review findings on the main-menu watermark implementation for both Zero Hour and Generals.
What was changed:
- Reworked W3DGeneralsXCreditDraw to avoid static managed DisplayString lifetime risk.
- Previous path allocated once with TheDisplayStringManager->newDisplayString() and never freed.
- New path reuses callback instData text display string (instData->setText(...) + getTextDisplayString()), removing the shutdown-assert leak risk.
- Updated initLabelVersion() logic in both game variants:
- removed unnecessary TheVersion && TheGlobalData gate for fixed watermark text
- now always sets watermark text when optional MainMenu.wnd:LabelVersion exists
- Updated stale legacy comments that still described version-hash behavior.
Validation:
- No diagnostics errors in touched files after patching.
- Diff reviewed for parity across Generals and GeneralsMD.
2026-03-31 (SESSION 97): Main Menu Watermark Finalization + Cleanup¶
Finalized the GeneralsX watermark rollout for both Zero Hour and Generals main menu paths, including lifecycle fixes and cleanup of temporary fallback draw routes.
What was done:
- Added and validated W3DGeneralsXCreditDraw registration in both game variants (W3DFunctionLexicon + W3DGUICallbacks declarations).
- Ensured watermark draw works in active menu render paths (W3DMainMenuDraw, W3DMainMenuFourDraw, and clock callback path).
- Added robust UI fallback for layouts without LabelVersion and repositioned it to the desired bottom-left placement with transparent background style.
- Fixed a build break in menu fallback code by switching to valid APIs:
- TheWindowManager->winFindFont(...)
- GameMakeColor(...)
- Fixed a critical lifecycle bug where fallback watermark persisted into gameplay by:
- creating fallback label under parentMainMenu (not root)
- destroying it in menu shutdown paths (shutdownComplete and MainMenuShutdown)
- Cleaned temporary attempt residue by removing redundant fallback credit draws from map-border and button-drop-shadow draw callbacks.
Validation: - Rebuilt macOS Zero Hour target successfully after each fix iteration. - Confirmed no new compile errors in touched menu/callback files. - User-confirmed final visual behavior in menu and requested cleanup.
Notes: - Warnings from legacy memory-pool macros remain unrelated to this feature and did not block successful link.
2026-03-29 (SESSION 96): Network/LAN Documentation Consolidation¶
Consolidated the current project position on LAN readiness into a dedicated support document instead of treating inherited upstream networking behavior as immediate blockers without reproduction.
What was documented:
- Added a focused network status note at docs/WORKDIR/support/NETWORK_LAN_STATUS_2026-03-29.md.
- Recorded the current stance that LAN should be tested after unrelated runtime bugs are resolved.
- Separated accepted legacy behavior from real LAN blockers and future online compatibility concerns.
- Clarified that GameSpy-related compatibility should be preserved when practical for future Generals Online integration.
Documentation cleanup:
- Updated docs/WORKDIR/lessons/2026-02-LESSONS.md to clarify that earlier GameSpy stubbing guidance was a historical Linux bring-up tactic, not a permanent project-wide rule.
Notes: - No gameplay or networking code changed in this session. - Manual two-machine LAN validation remains pending after the current runtime bug backlog is reduced.
2026-03-27 (SESSION 95): TheSuperHackers Upstream Sync (March) + Conflict Reconciliation¶
Performed a full upstream sync from thesuperhackers/main into thesuperhackers-sync-03-27-2026 and completed manual conflict reconciliation focused on preserving the GeneralsX cross-platform stack.
What was done:
- Created sync branch thesuperhackers-sync-03-27-2026 and merged thesuperhackers/main.
- Resolved merge conflicts in camera and FFmpeg-adjacent runtime paths with a hybrid strategy:
- keep upstream API/consistency improvements where safe
- preserve GeneralsX SDL3/DXVK/OpenAL/FFmpeg runtime behavior where required for macOS/Linux
- Documented a detailed conflict-resolution plan and risk map in:
- docs/WORKDIR/planning/PLAN-THESUPERHACKERS_SYNC_2026-03-27.md
Important merge decisions:
- Retained local camera defaults flow where it protects existing GeneralsX UX/runtime expectations.
- Kept cross-platform media/runtime guards and integration hooks that upstream does not maintain as a priority.
- Avoided blanket “ours/theirs” picks in unified Core/ areas; decisions were made per conflict based on platform strategy impact.
Validation status: - macOS configure/build workflow was rechecked during the merge cycle. - Manual runtime verification was reported as successful before finalizing the branch for Linux manual test handoff.
Notes: - This sync intentionally prioritizes preserving working cross-platform architecture while importing useful upstream fixes. - Follow-up validation on Linux runtime behavior remains part of the post-push checklist.
2026-03-27 (SESSION 95): GitHub Actions Artifact Layout Cleanup (revised)¶
Tightened artifact uploads further based on code review: archives now preserve POSIX permissions and the Linux artifact name is preset-aware.
What was changed (revision):
- Linux and macOS workflows now create a tar (uncompressed) archive before upload so POSIX executable bits and symlinks are preserved after download.
- Linux: tar -C /tmp -cf GeneralsX-<game>-<preset>.tar GeneralsX-<game>-deploy/
- macOS: tar -C <artifact_dir> -cf <AppName>.tar <AppName>.app
- Linux artifact name now includes inputs.preset so builds from linux64-testing produce a distinct artifact name and no collision with deploy artifacts:
- linux-generalsxzh-linux64-deploy-bundle / linux-generalsxzh-linux64-testing-bundle
- linux-generalsx-linux64-deploy-bundle / linux-generalsx-linux64-testing-bundle
- Opened follow-up GitHub issue #53 to remove the internal GeneralsMD naming from future Zero Hour user-facing paths.
Why:
- actions/upload-artifact@v4 does not preserve executable bits or symlinks when uploading a raw directory; a tar archive ensures the bundle rehydrates correctly for end users.
- Hardcoding linux64 in the artifact name caused ambiguity when the workflow is triggered with the linux64-testing preset.
Validation: - Verified workflow YAML remains error-free after the artifact path/name changes.
2026-03-24 (SESSION 94): macOS Load/Replay Crash Investigation + Runtime Path Unification¶
Investigated a macOS crash reported when opening Load Game / Replay and consolidated user data/runtime paths for both games.
What was changed:
- Updated user data directory defaults in both game variants to a unified tree under ~/Library/Application Support/GeneralsX/ (macOS) and ~/.local/share/GeneralsX/ (Linux fallback).
- Base game now writes to GeneralsX/Generals and Zero Hour writes to GeneralsX/GeneralsZH.
- Hardened HOME/XDG fallback handling to avoid null-path usage when environment variables are missing.
- Updated macOS ZH deploy and bundle scripts to ship Fontconfig configuration (fonts.conf + conf.d) and export FONTCONFIG_FILE/FONTCONFIG_PATH in generated launchers.
Why: - Save/Load and Replay paths should be deterministic and not depend on legacy folder names. - Runtime logs showed repeated Fontconfig configuration failures during UI layout creation; packaging explicit Fontconfig config removes this host-dependent behavior.
Validation performed: - macOS builds for both Generals and Zero Hour completed successfully. - ZH deploy completed and launcher now reports bundled Fontconfig path in runtime summary.
Notes:
- The crash flow around Menus/SaveLoad.wnd now has cleaner runtime environment setup for follow-up testing.
2026-03-24 (SESSION 93): TheSuperHackers Upstream Sync + macOS Build Recovery¶
Performed a full upstream sync merge from thesuperhackers/main into the dedicated sync branch and resolved the resulting conflict set manually.
What was merged/resolved:
- Merged upstream changes across CI workflows, Core engine headers/sources, shared networking/game client paths, and both game variants.
- Resolved localized merge conflicts in:
- Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp
- Generals/Code/GameEngine/Source/Common/RTS/Player.cpp
- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp
- GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp
- GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp
Important merge decisions:
- Preserved GeneralsX tactical camera-height default behavior instead of taking upstream setDefaultView(...) change blindly.
- Combined upstream battle-plan safety fix (invert a local copy instead of mutating source bonus data) with GeneralsX portability fix (std::max instead of __max).
- Preserved existing GeneralsX DX8 present-parameter policy in dx8wrapper.cpp for cross-platform stability.
macOS follow-up fix:
- Build initially failed because GameEngine now requires createParticleSystemManager(Bool dummy) after upstream sync, while SDL3 backends still implemented the old void signature.
- Updated SDL3GameEngine headers/implementations in both GeneralsMD and Generals to match the new pure-virtual signature.
Validation:
- [macOS] Configure completed successfully.
- cmake --build build/macos-vulkan --target z_generals -j 8 returned EXIT:0 after the SDL3GameEngine signature fix.
Notes:
- Added planning/report context in docs/WORKDIR/planning/PLAN-THESUPERHACKERS-SYNC-2026-03-24.md.
- Added a lessons-learned note about pure-virtual signature drift after upstream merges.
2026-03-24 (SESSION 92): macOS Bundle Dependency Resolver + OpenAL Audio Restore¶
Focused on two macOS runtime regressions found during app bundle testing.
What was changed:
- Fixed false unresolved dependency warnings in macOS bundle scripts by resolving @rpath entries against staged sibling dylibs before LC_RPATH traversal.
- Applied the same fix to both bundle scripts:
- scripts/build/macos/bundle-macos-zh.sh
- scripts/build/macos/bundle-macos-generals.sh
- Restored audio on macOS by scoping PipeWire/OpenAL environment workaround to Linux only.
- Updated both game entrypoints for parity:
- GeneralsMD/Code/Main/SDL3Main.cpp
- Generals/Code/Main/SDL3Main.cpp
Root causes:
- Bundle resolver treated some staged @rpath deps as unresolved because it skipped direct same-directory lookup.
- FilterPipeWireOpenAL() exported Linux-only ALSOFT_DRIVERS (pulse,alsa,oss,jack,null,wave) on macOS, which can exclude CoreAudio and lead to silent audio.
Validation:
- Re-ran ./scripts/build/macos/bundle-macos-zh.sh with zero WARNING: Unable to resolve dependency lines.
- Rebuilt/deployed ZH and verified runtime log reports OpenAL: keeping default driver selection on non-Linux platform.
- User-confirmed audio playback works again on macOS.
2026-03-23 (SESSION 91): Backport Camera Aspect-Ratio Default Fixes to Generals Base¶
Backported the camera default-height integration from ZH to Generals base game paths after validating file-by-file equivalence.
What was changed in Generals:
- Replaced direct setDefaultView(0.0f, 0.0f, 1.0f) usage in InGameUI::init() and InGameUI::reset() with setCameraHeightAboveGroundLimitsToDefault().
- Updated scripted camera default action to use height-scale-aware flow (setCameraHeightAboveGroundLimitsToDefault, setPitch, setAngle) and synced header signature.
- Updated GameLogic::startNewGame() to initialize camera height limits before default angle/pitch/zoom and force setZoomToMax().
- Updated OptionsMenu::saveOptions() to refresh shell-map camera limits and zoom after runtime resolution changes.
- Added contextual note in GlobalData.h documenting that max/min camera height are treated as 4:3 baseline values and scaled for other aspect ratios.
Validation:
- Confirmed pending patch scope is limited to 6 Generals files.
- Checked for accidental literal \\n artifacts in edited files; none found.
- Language service reports no syntax errors on changed files.
2026-03-23 (SESSION 90): Issue #16 Skirmish Instant-End + Neutral/White Enemy on Linux¶
Problem observed:
- Starting a Skirmish match opened SkirmishGameOptionsMenu and then immediately pushed ScoreScreen.
- In runs that did not hard-end immediately, enemy sides could appear as neutral/white due to broken script/player setup.
Root causes identified:
1. Player::initFromDict consumed skirmish qualification logic before loading m_mpStartIndex, corrupting qualified player/team/script naming in MP/skirmish flows.
2. Runtime script loading for SkirmishScripts.scb and MultiplayerScripts.scb failed on Linux because loose-file lookups were resolved from binary CWD only.
3. Linux runtime layout uses separate directories for binary CWD (~/GeneralsX/GeneralsMD/) and asset root (~/GeneralsX/data/GeneralsMD/), unlike classic Windows install assumptions.
Fixes implemented:
- Reordered m_mpStartIndex initialization in both Generals and GeneralsMD Player.cpp before skirmish qualification logic.
- Corrected script references to Data\\Scripts\\SkirmishScripts.scb and Data\\Scripts\\MultiplayerScripts.scb where required.
- Added targeted SKIRMISH_DIAG stderr probes in ZH runtime paths to confirm open/parse status and score-screen trigger path.
- Added LocalFileSystem::setAssetRootPath() (default no-op) and implemented fallback support in StdLocalFileSystem.
- Wired StdBIGFileSystem::init() to propagate resolved primary asset directory to local filesystem fallback so relative loose-file paths resolve from asset root when CWD lookup fails.
Validation:
- Linux linux64-deploy Docker build completed successfully.
- Deploy completed successfully.
- Diagnostic logs clearly showed previous open failures and enabled direct confirmation of the filesystem root-cause chain.
Result: - Issue #16 received root-cause-level fixes across script loading and player initialization paths, with platform-safe handling for Linux split runtime/data layouts and no Win32 behavior regression by interface defaulting.
2026-03-21 (SESSION 89): Issue #15 Shadow Artifacts - Major Visual Improvement + Commit-Worthy Stabilization¶
Worked another focused pass on animated shadow artifacts in Zero Hour (especially rotor-driven cases).
What improved in this session:
- Restored matrix conversion parity in volumetric shadow world transforms (To_D3DMATRIX path), aligning Zero Hour behavior with the Generals baseline.
- Fixed shadow type routing and projected-shadow update logic to respect bitmask flags (SHADOW_DYNAMIC_PROJECTION), improving animated shadow refresh behavior.
- Stabilized volumetric strip construction by removing unsafe edge-pair swaps that used Int* reinterpret casts on Short silhouette indices (64-bit/ARM UB risk).
- Added a hard clamp for volumetric extrusion length before volume build to avoid runaway spikes under shallow light angles.
Validation:
- macOS target GeneralsXZH built successfully.
- macOS deploy completed successfully.
- Runtime feedback confirmed major lighting/shadow quality improvement, although a residual rotor-line artifact can still appear in specific intro camera/angle situations.
Decision: - Changes were considered commit-worthy due to substantial visual improvement and clear root-cause hardening, even without full artifact elimination yet.
2026-03-20 (SESSION 88): macOS CI Bundle Crash — Root Cause: Missing DXVK_WSI_DRIVER + SDL3 WSI Not Compiled¶
Problem: CI-built .app bundle crashes immediately with ERROR: TheDisplay->init() threw unknown exception.
Root cause analysis (multi-session investigation):
1. DXVK_WSI_DRIVER env var is required on non-Win32 platforms by DXVK's wsi_platform.cpp. When unset, DXVK throws DxvkError("DXVK_WSI_DRIVER environment variable unset").
2. DxvkError did not inherit std::exception, so the game's catch (std::exception& e) never caught it — always "unknown exception".
3. On CI, SDL3 was not installed via Homebrew, so DXVK's meson build found only SDL2 (from ffmpeg dependency) → compiled with -DDXVK_WSI_SDL2 only. Setting DXVK_WSI_DRIVER=SDL3 at runtime then fails with "Failed to initialize WSI." because SDL3 WSI backend is not compiled in.
4. VK_ICD_FILENAMES deprecated in Vulkan Loader 1.3.236+ — must use VK_DRIVER_FILES instead.
Fixes applied:
- references/fbraz3-dxvk/src/util/util_error.h: DxvkError now inherits std::exception with what() override — exposes actual error messages.
- references/fbraz3-dxvk/src/wsi/wsi_platform.cpp: Auto-select best available WSI backend when DXVK_WSI_DRIVER is unset (SDL3 > SDL2 > GLFW priority).
- All macOS run scripts: added export DXVK_WSI_DRIVER="SDL3".
- All macOS bundle run.sh generators: added DXVK_WSI_DRIVER="SDL3" + VK_DRIVER_FILES alongside VK_ICD_FILENAMES.
- .github/workflows/build-macos.yml: added brew install sdl3 so DXVK meson finds SDL3 via pkg-config and compiles SDL3 WSI backend.
- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp: improved error logging around Direct3DCreate8 call.
Key insight: DXVK's WSI selection is compile-time (which backends are compiled via -DDXVK_WSI_SDL3/-DDXVK_WSI_SDL2), but the selection of WHICH one to use is runtime (via DXVK_WSI_DRIVER). Both must be correct.
Files changed:
- references/fbraz3-dxvk/src/util/util_error.h
- references/fbraz3-dxvk/src/wsi/wsi_platform.cpp
- scripts/build/macos/run-macos-zh.sh
- scripts/build/macos/bundle-macos-zh.sh
- scripts/build/macos/bundle-macos-generals.sh
- scripts/build/macos/deploy-macos-zh.sh
- scripts/build/macos/deploy-macos-generals.sh
- .github/workflows/build-macos.yml
- Generals/Code/Libraries/Source/WWVegas/WW3D2/dx8wrapper.cpp
2026-03-17 (SESSION 87): macOS CI Bundle Parity with Local Deploy (Generals + Zero Hour)¶
What was implemented:
- Updated .github/workflows/build-macos.yml bundle step to align runtime contract with local deploy scripts for both games.
- Added DXVK config packaging from resources/dxvk/dxvk.conf into CI runtime bundle.
- Replaced generic wrapper copy with generated macOS-specific run.sh that:
- sets DYLD_LIBRARY_PATH to runtime root
- exports VK_ICD_FILENAMES when MoltenVK_icd.json is present
- supports both GeneralsX and GeneralsXZH
- preserves optional CNC_GENERALS_INSTALLPATH auto-detection for sibling data layout
Root cause found:
- CI packed dylibs at bundle root, but old wrapper expected ${SCRIPT_DIR}/lib.
- This mismatch made runtime behavior diverge from local deploy and could break launch despite successful builds.
Additional notes:
- Relaxed required-library check in CI bundle validation by removing hard requirement on libopenal.1.dylib for current runtime package shape.
- Documented the lesson in docs/WORKDIR/lessons/2026-03-LESSONS.md to avoid future drift between CI and local runtime packaging.
Result: - CI macOS bundle now mirrors local deploy expectations for library lookup and Vulkan ICD setup, reducing "build green, runtime broken" regressions.
2026-03-16 (SESSION 86): Asset Root Overrides for Packaged Layouts + Language Detection Follow-up¶
What was implemented:
- Added runtime asset root resolution in BIG filesystem initialization for both backends:
- Core/GameEngineDevice/Source/StdDevice/Common/StdBIGFileSystem.cpp
- Core/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp
- Resolution priority now follows:
1. Environment variables
2. Options.ini
3. Default install-path resolution
4. Current working directory
- Adopted preferred env names:
- CNC_GENERALS_PATH
- CNC_GENERALS_ZH_PATH
- Kept compatibility fallback for older env variable names.
Diagnostics hardening:
- Added startup logs indicating selected asset root source (env, ini, default, cwd).
- Added path sanitization (trim/quote removal) for ENV/INI values.
Language detection follow-up:
- Fixed Linux registry language auto-detection so it checks localized BIG files in configured asset roots, not only current working directory:
- Generals/Code/GameEngine/Source/Common/System/registry.cpp
- GeneralsMD/Code/GameEngine/Source/Common/System/registry.cpp
- Added case-tolerant checks for localized BIG filenames.
Documentation:
- Updated README.md with a new runtime asset path section describing env vars, Options.ini keys, and final precedence.
Result: - Packaged/disconnected executable layouts now resolve asset roots deterministically via env/ini overrides. - Runtime logs clearly show which source was selected.
2026-03-16 (SESSION 85): README English Proofreading and Clarity Pass¶
What was updated: - Revised README.md for native English grammar, spelling, and phrasing. - Corrected multiple typos and non-native sentence constructions. - Kept the structure concise and avoided reintroducing previously removed redundant sections.
Notable wording improvements: - Standardized status bullets for Linux, macOS, and Windows. - Rewrote project-difference and naming-origin sections for clarity. - Fixed capitalization and wording consistency (for example, "Windows only" and "minor issues").
Result: - README is now cleaner and more natural for native English readers while preserving the streamlined content scope.
2026-03-16 (SESSION 84-HOTFIX): Add Linux Generals Base Build Job¶
What was fixed:
- Realized that build-linux-generals job was missing from ci.yml orchestrator.
- After granular change detection refactor, base-should-build filter was created but only build-macos-generals was added.
- Result: Generals base changes→macOS build only; no Linux Generals base build triggered.
Root cause: - When refactoring to granular detection, split outputs per platform variant but didn't add all platform jobs for base game. - Copy-paste incomplete: added macOS base job, forgot Linux parity.
What was added:
- build-linux-generals job (mirrors build-macos-generals pattern)
- Updated ci-summary needs: array to include build-linux-generals
- Updated summary status table with new Linux Generals Base row
- Updated Fail if Any Build Failed condition to check build-linux-generals.result
Result:
- Now have complete coverage: Generals base builds on both Linux and macOS when base-should-build filter triggers
- ZH variants (GeneralsMD) continue to build on Linux, macOS, Windows when zh-should-build filter triggers
Commit: eb5598562
2026-03-16 (SESSION 84): CI Granular Change Detection Refactor¶
What was implemented:
- Refactored .github/workflows/ci.yml to use granular change detection instead of single boolean filter.
- Split detect-changes job outputs into two independent selectors:
- zh-should-build: Triggered on GeneralsMD/**, Core/**, cmake/** changes → builds Zero Hour variants (Linux, macOS, Windows)
- base-should-build: Triggered on Generals/**, Core/**, cmake/** changes → builds Generals base variant (macOS)
Pre-refactor problem:
- Single should-build boolean fired on ANY change to either game, causing wasteful multi-platform CI builds when only one variant was modified.
- PR #36 had macOS Generals job added but wasn't selectively triggered.
Solution implemented:
- Each build job now checks only its relevant output:
- build-linux (GeneralsMD) checks zh-should-build
- build-macos (GeneralsMD) checks zh-should-build
- build-macos-generals (Generals base) checks base-should-build
- build-windows (GeneralsMD) checks zh-should-build
- workflow_dispatch still overrides with || github.event_name == 'workflow_dispatch' (force-run always available)
- Summary job displays granular status table showing which variant detected changes
Benefits: - Faster CI feedback (only relevant platforms build) - Reduced CI minutes for feature branches targeting specific game variant - Clearer workflow visibility (summary shows per-variant build triggers)
Commit: 99a46314d on feat/macos-generals-base-build-deploy
2026-03-15 (SESSION 83): macOS Generals Base Build/Deploy Parity¶
What was implemented:
- Created dedicated macOS base-game scripts:
- scripts/build/macos/build-macos-generals.sh
- scripts/build/macos/deploy-macos-generals.sh
- Added VS Code tasks in .vscode/tasks.json:
- [macOS] Build GeneralsX
- [macOS] Deploy GeneralsX
- [macOS] Pipeline: Configure + Build + Deploy Generals
Backport scope from macOS Zero Hour flow:
- Vulkan SDK prerequisite validation.
- Build using preset macos-vulkan and target g_generals.
- Deploy of runtime dependencies (SDL3, SDL3_image, GameSpy, DXVK d3d8/d3d9, libvulkan, libMoltenVK).
- MoltenVK ICD manifest generation (MoltenVK_icd.json).
- Runtime wrapper generation (run.sh) for local dylib loading via DYLD_LIBRARY_PATH.
- DXVK dylib fallback lookup (installed path and Meson output path).
Validation:
- Build completed successfully for g_generals on macOS.
- Deploy completed successfully to ~/GeneralsX/Generals.
- No runtime auto-launch was performed by pipeline (manual execution retained by request).
2026-03-14 (SESSION 82): Generals Base Fixes - Shell Map and Skirmish SIGSEGV¶
What was fixed:
- Restored Linux hardware fallback in Generals/Code/GameEngine/Source/Common/GameLOD.cpp so base Generals no longer disables shell map because Windows-only RAM/CPU detection returns zeros on non-Windows builds.
- Ported 64-bit safe pointer cast in Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupPlayerInfo.cpp for battle honor listbox item data.
- Fixed root cause of skirmish crash in shared text renderer (Core/Libraries/Source/WWVegas/WW3D2/render2dsentence.cpp) by normalizing incoming WCHAR to 16-bit code units before unicode font array growth/indexing.
Crash details validated:
- User-provided GDB trace showed SIGSEGV in FontCharsClass::Get_Char_Spacing during SkirmishGameOptionsMenuInit map display text update.
- Backtrace text payload contained packed UTF-16-like values, matching out-of-range indexing risk on Linux where wchar_t is 32-bit.
Result: - Base Generals shell map path and skirmish text-render path are now aligned with Linux runtime constraints and 64-bit safety expectations.
2026-03-12 (SESSION 81): Save/Replay Path Separator Fix + New Compat Layer Issue¶
What was fixed:
- Fixed Linux path separator handling for save/replay runtime directories in both Zero Hour and Generals.
- Updated affected runtime call sites so non-Windows builds use / where paths are assembled from user data roots.
Result:
- Save/replay paths no longer create literal backslash file names like Save\\00000002.sav on Linux.
New issue found:
- Opened ISSUE-013_findfirstfile_pattern_ignored_on_linux.md.
- Root problem: Linux compat FindFirstFile implementation currently opens . and ignores wildcard/path filtering semantics.
Status: - Issue documented as OPEN for follow-up implementation in compat layer.
2026-03-13 (SESSION 81): Fix macOS Terrain Texture Failure (ISSUE-009 / GH #12)¶
Status: Manually validated by user as fixed in runtime test.
Problem Found:
- macOS runtime repeatedly failed during terrain-related shader pipeline creation.
- Logs showed recurring MoltenVK shader compile errors with undeclared shadow sampler symbols such as s0_2d_shadowSmplr.
Root Cause: - DXVK shader generation path emitted a shadow-compare sampler wrapper branch that produced invalid symbol usage for this workload on macOS/MoltenVK.
Fix Applied:
- Updated DXVK fork on branch generalsx-macos-v2.6 in:
- references/fbraz3-dxvk/src/dxso/dxso_compiler.cpp
- Added a macOS-guarded path that avoids the problematic shadow-compare branch for the affected emission block and uses the color sampling path.
Build/Source Policy Hardening:
- Updated cmake/dx8.cmake to use remote DXVK fork tracking by default for macOS (generalsx-macos-v2.6) with updates enabled.
- Added explicit local development mode via -DSAGE_DXVK_USE_LOCAL_FORK=ON.
- Documented source-of-truth rules in:
- .github/instructions/generalsx.instructions.md
- .github/copilot-instructions.md
Validation:
- User performed manual runtime test after rebuild/deploy and confirmed success (FUNCIONOU!).
2026-03-12 (SESSION 81): Save/Replay Path Separator Fix + New Compat Layer Issue¶
What was fixed:
- Fixed Linux path separator handling for save/replay runtime directories in both Zero Hour and Generals.
- Updated affected runtime call sites so non-Windows builds use / where paths are assembled from user data roots.
Result:
- Save/replay paths no longer create literal backslash file names like Save\\00000002.sav on Linux.
New issue found:
- Opened ISSUE-013_findfirstfile_pattern_ignored_on_linux.md.
- Root problem: Linux compat FindFirstFile implementation currently opens . and ignores wildcard/path filtering semantics.
Status: - Issue documented as OPEN for follow-up implementation in compat layer.
2026-03-12 (SESSION 80): Correction — macOS terrain textures issue still persists¶
Correction: Earlier February diary entries stated that missing terrain textures on macOS had been fixed and were rendering correctly. That conclusion was incorrect or incomplete.
Current understanding:
- Terrain textures are still failing to load on macOS
- The issue remains open and is tracked in ISSUE-009_macos_terrain_textures_missing.md
- Previous notes likely captured a partial fix, a non-representative test result, or an incomplete end-to-end validation
Action taken: - Updated known issue documentation to treat this as an active open bug - Removed speculative wording that framed it as merely a regression candidate - Recorded this correction so future sessions do not assume the problem was solved
2026-03-10 (SESSION 79): Fix CI Bundle Wrapper Path (macOS + Linux)¶
Problem Found: GitHub Actions bundling step failed on both macOS and Linux workflows with:
cp: scripts/run-bundled-game.sh: No such file or directory
Root Cause:
Workflow YAML still referenced the old wrapper location (scripts/run-bundled-game.sh) after script directory reorganization.
The current wrapper path is scripts/qa/smoke/run-bundled-game.sh.
Fix:
- Updated wrapper copy path in .github/workflows/build-macos.yml.
- Updated wrapper copy path in .github/workflows/build-linux.yml.
Validation:
- Verified no stale references remain: rg "scripts/run-bundled-game.sh" .github/workflows scripts returns no matches.
2026-03-10 (SESSION 78): Fix macOS CI Build -- OpenAL via FetchContent¶
Problem Found:
fatal error: 'AL/al.h' file not found
openal-soft was intentionally NOT installed (Intel Homebrew installs x86_64-only binaries that fail on ARM64). Without Homebrew, CMake fell back to Apple's deprecated OpenAL.framework which uses <OpenAL/al.h> instead of the standard <AL/al.h> expected throughout the codebase.
Root Cause:
cmake/openal.cmake had Homebrew detection but no FetchContent fallback. When Homebrew openal-soft was absent (CI), find_package(OpenAL) silently picked up the Apple system framework.
Fix (porting pattern from windows-sdl branch):
- Rewrote cmake/openal.cmake to use FetchContent for all platforms unconditionally (no Homebrew detection).
- Included openal.cmake from the root CMakeLists.txt before Core subdirectory so OpenAL::OpenAL target is available when Core/GameEngineDevice processes.
- Updated Core/GameEngineDevice/CMakeLists.txt: uses if(TARGET OpenAL::OpenAL) CMake-native guard.
- Updated GeneralsMD/Code/GameEngineDevice/CMakeLists.txt: uses if(NOT TARGET OpenAL::OpenAL) guard before find_package.
Validation:
- Local configure passes: Configuring OpenAL Soft (v1.24.2) with FetchContent... → OpenAL Soft configured: target OpenAL::OpenAL available.
- No Apple OpenAL.framework or Homebrew path in configure output.
2026-03-09 (SESSION 77): Stabilize macOS DXVK Source and Deploy Flow¶
Status: Validated locally. Game now passes Direct3DCreate8 startup path and enters runtime loop.
Work completed:
- Switched macOS DXVK source in cmake/dx8.cmake from upstream repo to forked pinned commit (fbraz3/dxvk, commit ffcdbcaf...) to avoid patch drift.
- Disabled dynamic patch step in CMake for macOS DXVK source (PATCH_COMMAND "") because patch 6 (util_env.cpp) was not being applied reliably.
- Fixed macOS deploy/bundle scripts to resolve DXVK libraries from both possible outputs:
- install copy: build/macos-vulkan/libdxvk_*.dylib
- meson output: build/macos-vulkan/_deps/dxvk-build-macos/src/*/libdxvk_*.dylib
- Fixed PROJECT_ROOT resolution for build scripts under scripts/build/linux/ and scripts/build/macos/ using BASH_SOURCE[0] + ../../...
Root cause resolved:
- Runtime SIGTRAP on macOS came from missing __APPLE__ implementation in DXVK src/util/util_env.cpp (getExePath/getExeName path).
Validation:
- Configure/build/deploy succeeded.
- Runtime no longer traps at Direct3DCreate8; process continues into game initialization loop.
2026-03-03 (SESSION 76): Fix macOS Build — Install FFmpeg and Missing Dependencies in CI¶
Problem Found:
CMake Error: The following required packages were not found:
- libavcodec
- libavformat
- libavutil
- libswscale
Root Cause: CI workflow only installed cmake ninja meson but was missing:
- ffmpeg — required by Core/GameEngineDevice/CMakeLists.txt via pkg_check_modules(FFMPEG REQUIRED ...)
- pkg-config — required to find FFmpeg modules
- freetype fontconfig — required by font rendering (locally available, missing in CI)
Complete dependency audit of macOS build (macos-vulkan preset):
| Dependency | Source | Status |
|---|---|---|
| cmake, ninja, meson | Homebrew | Already in workflow |
| pkg-config | Homebrew | Added |
| ffmpeg | Homebrew | Added |
| freetype, fontconfig | Homebrew | Added |
| Vulkan SDK + MoltenVK | LunarG ZIP | Already handled |
| SDL3, SDL3_image | CMake FetchContent | Auto-fetched |
| OpenAL | Xcode SDK (Apple framework) | Auto-found |
| PNG, zlib | Xcode SDK | Auto-found |
Fix Applied: Updated Install Dependencies step with all required packages + added verification for libavcodec via pkg-config --modversion.
2026-03-03 (SESSION 75): Fix macOS Build — Vulkan SDK Path Normalization¶
Status: find_package(Vulkan) now succeeds locally and CI should pass.
Problem Found:
CMake Error: Could NOT find Vulkan (missing: Vulkan_LIBRARY Vulkan_INCLUDE_DIR MoltenVK)
Root Cause:
The LunarG installer places libraries at $INSTALL_TARGET/macOS/lib/libvulkan.dylib, but CMake's
FindVulkan.cmake searches in $VULKAN_SDK/lib/ and $VULKAN_SDK/include/.
- Locally:
VULKAN_SDK=/Users/felipebraz/VulkanSDK/1.4.341.0/macOS(already normalized, works) - CI:
VULKAN_SDK=/Users/runner/VulkanSDK/1.4.341.1(version root, not platform dir — fails)
The SDK directory structure is:
$HOME/VulkanSDK/1.4.341.1/
└── macOS/ ← CMake FindVulkan expects VULKAN_SDK to point HERE
├── lib/
│ ├── libvulkan.dylib
│ └── libMoltenVK.dylib
└── include/
└── vulkan/
Fixes Applied:
.github/workflows/build-macos.yml— NormalizeVULKAN_SDKbefore export:- After install: if
$INSTALL_TARGET/macOSexists, setVULKAN_SDK=$INSTALL_TARGET/macOS - Final normalization block: if
VULKAN_SDK/macOS/lib/libvulkan.dylibexists, append/macOS -
Simplified MoltenVK check: now only one path to check (
lib/, notmacOS/lib/) -
cmake/dx8.cmake— Simplified and unified Vulkan SDK detection: - If
$ENV{VULKAN_SDK}points to version root (hasmacOS/lib/libMoltenVK.dylib), normalize tomacOS/subdir - Home dir search now looks for
~/VulkanSDK/*/macOSdirectly - Single final check:
${VULKAN_SDK_ENV}/lib/libMoltenVK.dylib - Removed dual-path (
macOS/libvslib) complexity in favor of normalized path
Verified: cmake --preset macos-vulkan locally completes:
-- Found Vulkan: .../macOS/lib/libvulkan.dylib (found version "1.4.341") found components: MoltenVK
-- MoltenVK (Vulkan on macOS) detected and enabled
-- Configuring done (229.2s)
2026-03-03 (SESSION 74): Fix macOS Build Failure — CMake else Without Parentheses¶
Status: CMake configuration now completes successfully locally.
Problem Found:
CMake kept failing with the same error at line 119:
CMake Error at cmake/dx8.cmake:119:
Parse error. Expected "(", got newline with text "".
Root Cause:
In SESSION 71, when adding the else block for the MoltenVK fallback, else was written without parentheses:
elseif(VULKAN_SDK_ENV AND EXISTS "...")
set(VULKAN_SDK_ENV_VAR "VULKAN_SDK=...")
else ← ERROR: must be else()
message(WARNING "...")
endif()
CMake requires else() with empty parentheses (unlike bash/C). Line 118 with bare else (no ())
caused a parse error at line 119 where message() was being parsed.
Fix Applied:
Changed else → else() in cmake/dx8.cmake.
Also:
Consolidated ExternalProject_Add(dxvk_macos_build) to single-line per argument key (avoids future
parse issues with empty variable expansions in multiline format).
Verified: cmake --preset macos-vulkan completes successfully:
-- Configuring done (183.0s)
-- Generating done (1.4s)
-- Build files have been written to: .../build/macos-vulkan
2026-03-03 (SESSION 73): Fix macOS Build Failure — CMake Parse Error in dx8.cmake¶
Status: Fixed CMake syntax error in ExternalProject_Add configure command.
Problem Found:
CMake config failed with:
CMake Error at cmake/dx8.cmake:119:
Parse error. Expected "(", got newline with text "".
Root Cause:
In ExternalProject_Add(dxvk_macos_build) CONFIGURE_COMMAND, the variable ${VULKAN_SDK_ENV_VAR} was on its own line:
CONFIGURE_COMMAND
${CMAKE_COMMAND} -E env
CC=clang CXX=clang++
"CFLAGS=..."
"CXXFLAGS=..."
"LDFLAGS=..."
${VULKAN_SDK_ENV_VAR} ← On own line!
${MESON_EXECUTABLE} setup ...
When this variable expands to an empty string, CMake's parser sees:
${CMAKE_COMMAND} -E env ...
← Empty line (just spaces)
${MESON_EXECUTABLE} setup ...
This confuses CMake's argument parser, which expects the next token after -E env arguments, not a newline.
Solution Applied:
Moved ${VULKAN_SDK_ENV_VAR} to the same line as the env command:
CONFIGURE_COMMAND
${CMAKE_COMMAND} -E env CC=clang CXX=clang++ "CFLAGS=..." "CXXFLAGS=..." "LDFLAGS=..." ${VULKAN_SDK_ENV_VAR}
${MESON_EXECUTABLE} setup ${DXVK_BUILD_DIR} ${DXVK_SOURCE_DIR}
...
When VULKAN_SDK_ENV_VAR is empty, the line becomes:
${CMAKE_COMMAND} -E env CC=clang CXX=clang++ "CFLAGS=..." "CXXFLAGS=..." "LDFLAGS=..."
Expected Outcome: - CMake parses dx8.cmake successfully - DXVK Meson build configuration can proceed
2026-03-03 (SESSION 72): Fix macOS Build Failure — vcpkg Toolchain + Ninja + Compilers¶
Status: Fixed CMake preset inheritance and toolchain issues. Compiler now explicitly available.
Problems Found in SESSION 71:
CMake config failed with:
Could not find toolchain file: "/scripts/buildsystems/vcpkg.cmake"
CMAKE_MAKE_PROGRAM not set
CMAKE_C_COMPILER not set, after EnableLanguage
Root Causes:
-
Incorrect preset inheritance:
macos-vulkaninherited fromdefault-vcpkg, which required:Since"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"VCPKG_ROOTis unset in CI, CMake tried to find/scripts/buildsystems/vcpkg.cmake(absolute path with empty prefix). -
Homebrew formula caching:
brew installmay hit stale cache; needsbrew updatefirst. -
Compilers not exported to CMake: Even though
clang --versionworked in shell, compilername was not passed to CMake environment.
Fixes Applied:
CMakePresets.json— Changedmacos-vulkan:- Before:
"inherits": "default-vcpkg"(requires VCPKG_ROOT) - After:
"inherits": "default"(no vcpkg dependency) -
Removed
"VCPKG_OVERLAY_TRIPLETS"(not needed for macOS brew-based build) -
.github/workflows/build-macos.yml— Install Dependencies step: - Added
brew updatebeforebrew install(ensures fresh formulas) -
Prevents stale Ninja formula causing CMAKE_MAKE_PROGRAM not set
-
.github/workflows/build-macos.yml— Configure CMake step: - Explicitly set
CC=clangandCXX=clang++as environment variables - Added debug output: echo CC=$CC, echo CXX=$CXX
-
CMake will now use these compilers instead of default detection
-
.github/workflows/build-macos.yml— Deploy Bundle step: - Updated MoltenVK copy logic to check both
macOS/libandlibpaths - Added informative messages about which path was used
Expected Outcome: - CMake finds Ninja (via fresh brew formula) - CMake finds clang/clang++ (via environment variables) - No invalid toolchain path error - Configuration should complete successfully
2026-03-03 (SESSION 71): Fix macOS Build Failure — Compiler + MoltenVK Paths¶
Status: CI workflow now gets further — Vulkan SDK installs successfully, but CMake configuration fails due to:
1. Missing clang/clang++ compiler (even though xcode selected)
2. MoltenVK path mismatch: installer deploys to macOS/lib/libMoltenVK.dylib, not lib/libMoltenVK.dylib
Problems Found:
CI log excerpt:
⚠️ MoltenVK not found at expected location; build may still work if system Vulkan is available
Checking for alternate locations...
/Users/runner/VulkanSDK/1.4.341.1/macOS/lib/libMoltenVK.dylib ← FOUND HERE
/Users/runner/VulkanSDK/1.4.341.1/macOS/lib/MoltenVK.xcframework/...
CMake Error at /opt/homebrew/share/cmake/Modules/CMakeDetermineSystem.cmake:159 (message):
Could not find toolchain file: "/scripts/buildsystems/vcpkg.cmake"
CMake Error: CMAKE_MAKE_PROGRAM is not set. You probably need to select a different build tool.
CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
Root Causes:
- Compiler not detected:
.github/workflows/build-macos.ymldoes not verifyxcode-selectinstallation; macOS runner may not have xcode-command-line-tools enabled. - MoltenVK path off by one: Vulkan SDK 1.4.341.1 installer puts MoltenVK at
$VULKAN_SDK/macOS/lib/libMoltenVK.dylib, but: cmake/dx8.cmakechecks only${VULKAN_SDK_ENV}/lib/libMoltenVK.dylib(nomacOScomponent).github/workflows/build-macos.ymlverification also checks onlylib/libMoltenVK.dylib
Fixes Applied:
.github/workflows/build-macos.yml— Ensure compiler is available:- Added explicit
xcode-select --install(harmless if already installed) - Added path check:
xcode-select -pwith error message if fails - Added verification:
clang --versionto confirm compiler available -
Added verification:
meson --versionto confirm Meson available -
.github/workflows/build-macos.yml— Check both MoltenVK path variants: - Primary:
$VULKAN_SDK/macOS/lib/libMoltenVK.dylib - Fallback:
$VULKAN_SDK/lib/libMoltenVK.dylib -
If neither found: still proceed (may use system Vulkan)
-
cmake/dx8.cmake— Update Vulkan SDK detection for both macOS/lib paths: VULKAN_HOME_DIRSsearch now checks both${POTENTIAL_SDK}/macOS/lib/libMoltenVK.dylibAND${POTENTIAL_SDK}/lib/libMoltenVK.dylib- Final check after MoltenVK lookup: try
macOS/libfirst, thenlibfallback - Enhanced logging: show which paths were checked and what was found
Expected Outcome:
- Compiler available → CMake preset configuration should work
- MoltenVK found → Meson can properly configure DXVK build with VULKAN_SDK env var
2026-03-03 (SESSION 70): Fix macOS Build Failure — Vulkan SDK Download (FINAL FIX)¶
Third iteration: Manual download verification revealed actual structure.
Discovery:
- Manual download + extraction on local macOS: ZIP extracts correctly to .app bundle
- GitHub Actions extraction: Shows only executable file (not .app bundle structure)
- Root cause: unzip -q (quiet mode) was silencing critical extraction errors
- Possible triggers: ZIP corruption during download, I/O errors, or permission issues in CI
Correct SDK Structure:
vulkansdk-macOS-1.4.341.1.zip
└── vulkansdk-macOS-1.4.341.1.app/
└── Contents/
├── MacOS/
│ └── vulkansdk-macOS-1.4.341.1 (executable)
├── Resources/
│ ├── installer.dat
│ └── vulkansdk-macOS-1.4.341.1.icns
├── Info.plist
├── PkgInfo
└── _CodeSignature/
└── CodeResources
Final Fixes Applied:
.github/workflows/build-macos.yml— Enhanced extraction diagnostics:- ZIP integrity check:
unzip -tbefore extraction (catches corrupted files early) - Verbose extraction: Removed
-qflag; show all extraction output for debugging - Pre-extraction listing:
unzip -lto show contents before extraction - Post-extraction tree:
findto print directory structure (first 30 entries) -
Revised installer search strategy:
- Strategy 1 (Primary): Look for
.appbundle →Contents/MacOS/vulkansdk-macOS-1.4.341.1 - Strategy 2 (Fallback): Direct executable
vulkansdk-macOS-*if no.app - Strategy 3: Make non-executable variants executable with
chmod +x
- Strategy 1 (Primary): Look for
-
Improved error handling:
- If ZIP corrupted: show test results and skip extraction
- If extraction fails: detailed directory listing printed
- Each strategy logs success/failure and path discovered
-
Installer executable name corrected from
InstallVulkantovulkansdk-macOS-1.4.341.1 -
Diagnostics output (for troubleshooting):
- Shows first 20 lines of ZIP contents
- Shows first 30 entries of extracted directory tree
- Lists
.appstructure if found - Full error messages from
unzip -tif file corrupted
Key Learnings:
1. -q (quiet) flag in CI hides critical errors that developers need to see
2. ZIP integrity test (unzip -t) must run BEFORE extraction to catch issues early
3. GitHub Actions CI environment may have different I/O behavior than local macOS
4. SHA256 validation catches download corruption, but not extraction issues
5. Verbose logging in CI is essential for debugging ephemeral failures
Testing Path: - Next CI run will show detailed extraction output - If ZIP corrupts: error caught at integrity test stage - If structure differs: directory tree printed for analysis - If installer not found: detailed path dump provided for debugging
2026-03-03 (SESSION 70, ITERATION 1): Original Analysis¶
Root Cause Analysis:
- Original URL https://sdk.lunarg.com/download/latest/mac/vulkan-sdk.dmg was returning redirects or HTTP errors (~1426 bytes HTML).
- LunarG's SDK delivery changed: latest version (1.4.341.1) is now distributed as .zip containing a macOS app installer bundle.
- Correct direct URL: https://sdk.lunarg.com/sdk/download/1.4.341.1/mac/vulkansdk-macos-1.4.341.1.zip (318 MB).
- SHA256 hash for validation: 632cbe96c8ed6ed00c6ce25e3a7738c466134f76586e1c51f1419410d7f9042e.
Architecture of Vulkan SDK 1.4.341.1:
- ZIP contains: vulkansdk-macOS-1.4.341.1.app (macOS application bundle)
- Inside .app: /Contents/MacOS/InstallVulkan (executable installer script)
- Installer accepts command-line parameters for unattended deployment
- Target install path: $HOME/VulkanSDK/1.4.341.1/ (version-specific directory)
Fixes Applied:
.github/workflows/build-macos.yml— Updated Vulkan SDK installation strategy (REVERSED PRIORITY):- Strategy 1 (PREFERRED): Direct download of versioned SDK (1.4.341.1) with SHA256 validation
- Download from:
https://sdk.lunarg.com/sdk/download/1.4.341.1/mac/vulkansdk-macos-1.4.341.1.zip - Validate SHA256:
632cbe96c8ed6ed00c6ce25e3a7738c466134f76586e1c51f1419410d7f9042e - Extract ZIP to find
.appbundle - Execute installer:
./vulkansdk-macOS-1.4.341.1.app/Contents/MacOS/InstallVulkan - Install to:
$HOME/VulkanSDK/1.4.341.1/ - Retry up to 3 times with 15s delays
- Download from:
- Strategy 2 (FALLBACK): Homebrew (
brew install --cask vulkan-sdk)- Only attempted if versioned download fails
- May install older version than 1.4.341.1, but guarantees working installation
- Better than nothing if LunarG CDN is unreachable
-
Why reversed: Versioned download is more reliable (direct URL, SHA256 validated, specific version known to work); Homebrew is fallback in case LunarG CDN is down
-
Installation parameters:
--root $HOME/VulkanSDK/1.4.341.1— version-specific path (supports coexistence)--accept-licenses— non-interactive (skip dialog)--default-answer— use presets for all prompts-
--confirm-command install— execute install (not just preview) -
cmake/dx8.cmake— Updated Vulkan SDK detection paths: - First: Check
$VULKAN_SDKenvironment variable - Second: Search
$HOME/VulkanSDK/*/directories (find latest version) - Third: Try Homebrew locations (Intel:
/usr/local/Caskroom/vulkan-sdk, ARM64:/opt/homebrew/Caskroom/vulkan-sdk) - Validate MoltenVK:
lib/libMoltenVK.dylibmust exist -
Pass detected path to Meson via
VULKAN_SDKenv var -
Diagnostics & Error Handling:
- SHA256 mismatch detected early (prevent .app corruption)
- File size checks reveal HTML error responses (< 10MB)
- First 20 lines of invalid files printed for debugging
- Installer failures reported with exit status
- Graceful fallback if primary strategy fails
- Warns if MoltenVK not found (system Vulkan may still work)
Testing in CI: 1. GitHub Actions will retry 3 times on download failure (15s between attempts) 2. SHA256 validation ensures downloaded file integrity 3. Logs show which strategy succeeded (Homebrew vs manual installer) 4. MoltenVK verification confirms complete installation
Lessons Learned:
- LunarG changed distribution format (DMG→ZIP with app installer) — needed URL and extraction method updates.
- macOS app installers need explicit --accept-licenses --confirm-command for headless operation.
- Version-specific paths ($HOME/VulkanSDK/1.4.341.1/) better than generic ($HOME/VulkanSDK/) for multi-version coexistence.
- SHA256 validation critical for supply-chain security (detect corrupted/HTML responses immediately).
2026-03-03 (SESSION 69): PR Review Feedback — macOS Build Cleanup¶
Objective: Address code review feedback from PR #3 macOS build.
Changes Applied:
- README.md: Replaced UTF-8 replacement character (U+FFFD) with plain text on macOS status line.
- CMakePresets.json: Updated
macos-vulkandisplay name from "Universal Binary" to "arm64 Native" to accurately reflect single-arch build. - cmake/dxvk-macos-patches.py: Removed versioned
libvulkan.1.4.341.dylibfrom the macOS Vulkan loader patch; use stable names only (libvulkan.dylib,libvulkan.1.dylib,libMoltenVK.dylib). - cmake/dx8.cmake: Pinned DXVK
GIT_TAGto immutable commit SHAad253b8a(v2.6) instead of mutable tagv2.6for supply-chain security. - cmake/ccache.cmake: Replaced
ccache -o sloppiness=...(global config mutation) withset(ENV{CCACHE_SLOPPINESS} ...)scoped to the build. - cmake/config-build.cmake: Fixed Vulkan SDK error message to point to LunarG installer, not
brew install --cask. - .github/workflows/build-macos.yml: Dropped
pull-requests: writetoread(least privilege); removedsudofrom VulkanSDK copy under$HOME; fixed$?check after pipe to use${PIPESTATUS[0]}. - scripts/build-macos-zh.sh: Added
pipefailtoset -eso failing cmake pipes are not silently masked. - scripts/run-macos-zh.sh: Replaced slow
findover$HOMEto locateMoltenVK_icd.jsonwith direct lookup in game dir and Vulkan SDK. - scripts/test_ccache.sh: Replaced hard-coded local path with script-relative
PROJECT_DIR; addedpipefail. - scripts/setup_ccache.sh: Removed hard-coded
/Users/felipebrazpath and unconditional global config overwrite; now shows recommended config and asks for confirmation. - scripts/monitor-dxvk-build.py: Replaced hard-coded path with CLI argument (
--log); replaced bareexcept:with specificOSErrorcatches. - Core/GameEngine/Source/Common/System/Debug.cpp: Added explicit
#include "thread_compat.h"for non-Windows builds. - Documentation translations: Translated
MACOS_PORT_ANALYSIS.md,TERRAIN_SHADER_FIX_PLAN.md,PLANO_B_WORKAROUND.md,CCACHE_DIAGNOSIS.mdfrom Portuguese to English. - Documentation corrections: Updated binary paths in
macOS-Workflow-Before-After.mdandGitHub-Actions-macOS-Improvements.md; updated DXVK patch count from 10 to 13 inMACOS_BUILD_INSTRUCTIONS.md.