Repository navigation
Add setup-assets.sh script to automate macOS game asset placement #73
Description
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
.bigarchives and warn on missing assets - Handle the
GeneralsMD→GeneralsZHmigration — 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
- Script created at
scripts/setup-assets.sh -
--steamflag downloads game assets directly via SteamCMD (installs SteamCMD via Homebrew if needed) - Handles Steam authentication (username prompt, Steam Guard support)
- Downloads correct depots for Zero Hour (App 2732960) and base Generals
- Accepts
--from <path>to specify a local source directory as an alternative to downloading - Accepts
--validateto check an existing~/GeneralsX/layout without copying or downloading - Copies/moves Zero Hour assets to
~/GeneralsX/GeneralsZH/ - Copies/moves base Generals assets to
~/GeneralsX/Generals/(handling Steam'sZH_Generals/nesting) - Validates presence of required
.bigfiles:generalszh.big,W3DZH.big,MapsZH.big,AudioZH.big - Detects and reports language BIG files (
EnglishZH.big,GermanZH.big, etc.) - Detects legacy
~/GeneralsX/GeneralsMDlayout and offers migration toGeneralsZH - Normalizes
.bigfilename case (lowercase) for case-sensitive volume compatibility - Prints clear summary of what was copied/downloaded and any missing/optional files
- Documentation updated in
docs/BUILD/MACOS.mdanddocs/BUILD/HOW_TO_RUN.md
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:
brew install steamcmdDownload 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 \
+quitKey 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 windowsis 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 --migrateImplementation Strategy
Phase 1 (Core):
- Create script with
--fromand--validateflags - Implement source layout detection (Steam, side-by-side, flat)
- Copy logic with directory creation
- Required
.bigfile validation
Phase 2 (Steam Download):
- Add
--steamflag with SteamCMD integration - Auto-install SteamCMD via Homebrew if not present
- Handle Steam authentication (username prompt, Steam Guard 2FA)
- Download correct app/depot with
+@sSteamCmdForcePlatformType windows - Reorganize downloaded files into expected layout
- Clean up staging directory after successful setup
Phase 3 (Polish):
- Legacy
GeneralsMDmigration (--migrate) - Case normalization for
.bigfiles - Interactive prompts (confirm before overwriting existing files)
- Dry-run mode (
--dry-run)
Phase 4 (Integration):
- Hook into
build-macos-zh.shas an optional pre-check - Update
docs/BUILD/MACOS.mdanddocs/BUILD/HOW_TO_RUN.md - Add validation step to
bundle-macos-zh.shapp launcher
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
Activity
matmar10 commentedon Apr 4, 2026
@fbraz3 Feel free to assign to me; I created a very basic script to set up my Macs. This Issue outlines a more comprehensive approach.
fbraz3 commentedon Apr 5, 2026
Hey @matmar10 thank you very much for contributing. I've assigned the issue to you as requested.
I never heard about
steamcmdbefore btw. It will be a good enhancement for the project.fbraz3 commentedon Aug 14, 2026
@matmar10 are you still working on this?
matmar10 commentedon Aug 15, 2026
Hi @fbraz3, have been busy with new gig and also relocating family internationally - I can still pick this up, but would be later this week at the earliest. My kids have been bugging me to install Generals on their Macs so that's a good excuse to prioritize 😅