Context
Getting game assets into the correct directory layout is the most error-prone step of running GeneralsX on macOS. The build toolchain (build-macos-zh.sh, deploy-macos-zh.sh, bundle-macos-zh.sh) is fully automated, but the prerequisite — placing retail game files where the engine expects them — is entirely manual and under-documented.
Users must know:
- Which files to copy from their Windows/Steam installation
- That the expected target is
~/GeneralsX/GeneralsZH/ (not ~/GeneralsX/GeneralsMD/, which is legacy)
- That base Generals assets must live in a sibling
~/GeneralsX/Generals/ directory
- That the Steam layout nests base Generals assets inside a
ZH_Generals/ subdirectory that needs flattening
None of this is obvious, and getting it wrong produces silent failures or crashes with no actionable error messages. Mac users face an additional hurdle: the game is only sold as a Windows title on Steam, so there is no native macOS Steam install path to copy from.
Goal
Create a setup-assets.sh script that automates and validates game asset placement for macOS (and Linux) users. It should:
- Download assets directly from Steam — using SteamCMD to fetch game depots, requiring only a Steam account that owns the game
- Accept a source path — alternatively, copy from a mounted Windows partition, Steam library, or manual file dump
- Copy and organize assets into
~/GeneralsX/GeneralsZH/ and ~/GeneralsX/Generals/
- Handle Steam directory structure — flatten the
ZH_Generals/ subdirectory into ../Generals/
- Validate required files — check for essential
.big archives and warn on missing assets
- Handle the
GeneralsMD → GeneralsZH migration — detect legacy layout and offer to migrate
Why This Is Needed
1. No native macOS Steam install — users must manually obtain Windows game files
C&C Generals Zero Hour is a Windows-only title on Steam (App ID 2732960). macOS users cannot simply install it through Steam. They must either:
- Have access to a Windows machine or Boot Camp partition to copy the files
- Use a compatibility layer (Crossover, Whisky) to run the Steam client and download it
- Manually obtain the files some other way
This is a major friction point. SteamCMD (Valve's command-line Steam client) runs natively on macOS and can download Windows game depots cross-platform, given valid Steam credentials that own the game. Automating this removes the biggest barrier to entry for Mac users.
2. Steam directory structure doesn't match expected layout
Steam installs Zero Hour to a flat directory with base Generals assets nested in ZH_Generals/. The engine (registry.cpp) has auto-detection for this at runtime, but only when assets are already in the right parent structure. Users copying files from Steam don't know which subdirectories matter or whether the hierarchy must be preserved.
3. No Windows Registry on macOS — path resolution is fragile
On Windows, InstallPath comes from the registry. On macOS/Linux, this was replaced with environment variables (CNC_GENERALS_INSTALLPATH, CNC_GENERALS_ZH_PATH) and a registry.ini fallback. The deploy/bundle scripts set these automatically, but they rely on .big files being in the expected directories. If assets are misplaced, the game silently fails to load archives.
4. Two competing directory names create ambiguity
The project migrated from ~/GeneralsX/GeneralsMD to ~/GeneralsX/GeneralsZH as the canonical Zero Hour path. Legacy fallback logic in every script scans both directories and prefers whichever contains .big files. New users don't know which to use, and the fallback heuristic is invisible.
5. Base Generals assets must be in a specific sibling location
Zero Hour probes ../Generals/ relative to its working directory for base game assets. If a user copies only Zero Hour files, the game may crash or show missing content with no clear error.
6. Case sensitivity edge case
The engine probes both original-case and lowercase .big filenames (doesLanguageBigExist() in registry.cpp). Files copied from Windows may have mixed case. This works on default macOS (case-insensitive APFS) but breaks on case-sensitive volumes.
Acceptance Criteria
Architecture (RFC)
setup-assets.sh --steam
├─ Check for SteamCMD (install via Homebrew if missing)
├─ Prompt for Steam credentials
├─ Download depot for Zero Hour (App 2732960)
│ └─ SteamCMD: +login <user> +force_install_dir <tmpdir> +app_update 2732960 validate +quit
├─ Detect downloaded layout
│ ├─ Extract ZH assets → ~/GeneralsX/GeneralsZH/
│ └─ Extract base Generals assets (ZH_Generals/) → ~/GeneralsX/Generals/
├─ Normalize filename case
└─ Validate + print summary
setup-assets.sh --from <source>
├─ Detect source layout
│ ├─ Steam standalone? (ZH_Generals/ subdir present)
│ ├─ Side-by-side install? (../Generals/ sibling)
│ └─ Flat dump? (all .big files in one directory)
│
├─ Copy Zero Hour assets → ~/GeneralsX/GeneralsZH/
├─ Copy base Generals assets → ~/GeneralsX/Generals/
├─ Normalize filename case
│
└─ Validate
├─ Required .big files present?
├─ Language BIG detected?
├─ Base Generals sibling reachable?
└─ Print summary + warnings
setup-assets.sh --validate
└─ Run validation only (no copy, no download)
SteamCMD Details
SteamCMD is Valve's official command-line client. It runs natively on macOS (arm64 via Rosetta) and can download Windows game depots cross-platform.
Installation:
Download flow:
# Downloads the Windows build of the game to a local directory
steamcmd +@sSteamCmdForcePlatformType windows \
+login <username> \
+force_install_dir ~/GeneralsX/_steam_download \
+app_update 2732960 validate \
+quit
Key considerations:
- Requires a Steam account that owns C&C Generals Zero Hour
- Steam Guard (2FA) will prompt for a code on first login — the script should handle this gracefully
+@sSteamCmdForcePlatformType windows is required since the game has no macOS depot
- Downloaded files land in a staging directory; the script reorganizes them into the expected layout
- SteamCMD caches credentials after first login, so subsequent runs are non-interactive
Example Usage
# Download directly from Steam (recommended for Mac users)
./scripts/setup-assets.sh --steam
# Download with explicit Steam username
./scripts/setup-assets.sh --steam --username mysteamaccount
# From a mounted Windows/Boot Camp partition
./scripts/setup-assets.sh --from "/Volumes/BOOTCAMP/Program Files (x86)/Steam/steamapps/common/Command & Conquer Generals - Zero Hour"
# From a manual file dump
./scripts/setup-assets.sh --from ~/Downloads/generals-zh-files/
# Validate existing setup
./scripts/setup-assets.sh --validate
# Migrate legacy GeneralsMD layout
./scripts/setup-assets.sh --migrate
Implementation Strategy
Phase 1 (Core):
Phase 2 (Steam Download):
Phase 3 (Polish):
Phase 4 (Integration):
References
- Asset path resolution:
GeneralsMD/Code/GameEngine/Source/Common/System/registry.cpp
- BIG file loading:
Core/GameEngineDevice/Source/StdDevice/Common/StdBIGFileSystem.cpp
- macOS deploy script:
scripts/build/macos/deploy-macos-zh.sh
- macOS bundle script:
scripts/build/macos/bundle-macos-zh.sh
- macOS run script:
scripts/build/macos/run-macos-zh.sh
- macOS build docs:
docs/BUILD/MACOS.md
- Runtime docs:
docs/BUILD/HOW_TO_RUN.md
- SteamCMD docs: https://developer.valvesoftware.com/wiki/SteamCMD
- Steam App ID: 2732960
Context
Getting game assets into the correct directory layout is the most error-prone step of running GeneralsX on macOS. The build toolchain (
build-macos-zh.sh,deploy-macos-zh.sh,bundle-macos-zh.sh) is fully automated, but the prerequisite — placing retail game files where the engine expects them — is entirely manual and under-documented.Users must know:
~/GeneralsX/GeneralsZH/(not~/GeneralsX/GeneralsMD/, which is legacy)~/GeneralsX/Generals/directoryZH_Generals/subdirectory that needs flatteningNone of this is obvious, and getting it wrong produces silent failures or crashes with no actionable error messages. Mac users face an additional hurdle: the game is only sold as a Windows title on Steam, so there is no native macOS Steam install path to copy from.
Goal
Create a
setup-assets.shscript that automates and validates game asset placement for macOS (and Linux) users. It should:~/GeneralsX/GeneralsZH/and~/GeneralsX/Generals/ZH_Generals/subdirectory into../Generals/.bigarchives and warn on missing assetsGeneralsMD→GeneralsZHmigration — detect legacy layout and offer to migrateWhy This Is Needed
1. No native macOS Steam install — users must manually obtain Windows game files
C&C Generals Zero Hour is a Windows-only title on Steam (App ID 2732960). macOS users cannot simply install it through Steam. They must either:
This is a major friction point. SteamCMD (Valve's command-line Steam client) runs natively on macOS and can download Windows game depots cross-platform, given valid Steam credentials that own the game. Automating this removes the biggest barrier to entry for Mac users.
2. Steam directory structure doesn't match expected layout
Steam installs Zero Hour to a flat directory with base Generals assets nested in
ZH_Generals/. The engine (registry.cpp) has auto-detection for this at runtime, but only when assets are already in the right parent structure. Users copying files from Steam don't know which subdirectories matter or whether the hierarchy must be preserved.3. No Windows Registry on macOS — path resolution is fragile
On Windows,
InstallPathcomes from the registry. On macOS/Linux, this was replaced with environment variables (CNC_GENERALS_INSTALLPATH,CNC_GENERALS_ZH_PATH) and aregistry.inifallback. The deploy/bundle scripts set these automatically, but they rely on.bigfiles being in the expected directories. If assets are misplaced, the game silently fails to load archives.4. Two competing directory names create ambiguity
The project migrated from
~/GeneralsX/GeneralsMDto~/GeneralsX/GeneralsZHas the canonical Zero Hour path. Legacy fallback logic in every script scans both directories and prefers whichever contains.bigfiles. New users don't know which to use, and the fallback heuristic is invisible.5. Base Generals assets must be in a specific sibling location
Zero Hour probes
../Generals/relative to its working directory for base game assets. If a user copies only Zero Hour files, the game may crash or show missing content with no clear error.6. Case sensitivity edge case
The engine probes both original-case and lowercase
.bigfilenames (doesLanguageBigExist()inregistry.cpp). Files copied from Windows may have mixed case. This works on default macOS (case-insensitive APFS) but breaks on case-sensitive volumes.Acceptance Criteria
scripts/setup-assets.sh--steamflag downloads game assets directly via SteamCMD (installs SteamCMD via Homebrew if needed)--from <path>to specify a local source directory as an alternative to downloading--validateto check an existing~/GeneralsX/layout without copying or downloading~/GeneralsX/GeneralsZH/~/GeneralsX/Generals/(handling Steam'sZH_Generals/nesting).bigfiles:generalszh.big,W3DZH.big,MapsZH.big,AudioZH.bigEnglishZH.big,GermanZH.big, etc.)~/GeneralsX/GeneralsMDlayout and offers migration toGeneralsZH.bigfilename case (lowercase) for case-sensitive volume compatibilitydocs/BUILD/MACOS.mdanddocs/BUILD/HOW_TO_RUN.mdArchitecture (RFC)
SteamCMD Details
SteamCMD is Valve's official command-line client. It runs natively on macOS (arm64 via Rosetta) and can download Windows game depots cross-platform.
Installation:
Download flow:
Key considerations:
+@sSteamCmdForcePlatformType windowsis required since the game has no macOS depotExample Usage
Implementation Strategy
Phase 1 (Core):
--fromand--validateflags.bigfile validationPhase 2 (Steam Download):
--steamflag with SteamCMD integration+@sSteamCmdForcePlatformType windowsPhase 3 (Polish):
GeneralsMDmigration (--migrate).bigfiles--dry-run)Phase 4 (Integration):
build-macos-zh.shas an optional pre-checkdocs/BUILD/MACOS.mdanddocs/BUILD/HOW_TO_RUN.mdbundle-macos-zh.shapp launcherReferences
GeneralsMD/Code/GameEngine/Source/Common/System/registry.cppCore/GameEngineDevice/Source/StdDevice/Common/StdBIGFileSystem.cppscripts/build/macos/deploy-macos-zh.shscripts/build/macos/bundle-macos-zh.shscripts/build/macos/run-macos-zh.shdocs/BUILD/MACOS.mddocs/BUILD/HOW_TO_RUN.md