Skip to content

Add setup-assets.sh script to automate macOS game asset placement #73

@matmar10

Description

@matmar10

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:

  1. Download assets directly from Steam — using SteamCMD to fetch game depots, requiring only a Steam account that owns the game
  2. Accept a source path — alternatively, copy from a mounted Windows partition, Steam library, or manual file dump
  3. Copy and organize assets into ~/GeneralsX/GeneralsZH/ and ~/GeneralsX/Generals/
  4. Handle Steam directory structure — flatten the ZH_Generals/ subdirectory into ../Generals/
  5. Validate required files — check for essential .big archives and warn on missing assets
  6. Handle the GeneralsMDGeneralsZH 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

  • Script created at scripts/setup-assets.sh
  • --steam flag 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 --validate to 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's ZH_Generals/ nesting)
  • Validates presence of required .big files: generalszh.big, W3DZH.big, MapsZH.big, AudioZH.big
  • Detects and reports language BIG files (EnglishZH.big, GermanZH.big, etc.)
  • Detects legacy ~/GeneralsX/GeneralsMD layout and offers migration to GeneralsZH
  • Normalizes .big filename 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.md and docs/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 steamcmd

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):

  • Create script with --from and --validate flags
  • Implement source layout detection (Steam, side-by-side, flat)
  • Copy logic with directory creation
  • Required .big file validation

Phase 2 (Steam Download):

  • Add --steam flag 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 GeneralsMD migration (--migrate)
  • Case normalization for .big files
  • Interactive prompts (confirm before overwriting existing files)
  • Dry-run mode (--dry-run)

Phase 4 (Integration):

  • Hook into build-macos-zh.sh as an optional pre-check
  • Update docs/BUILD/MACOS.md and docs/BUILD/HOW_TO_RUN.md
  • Add validation step to bundle-macos-zh.sh app 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

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions