Updated: 2026-02-19
Status: Root cause hypothesis identified — needs verification in Session 49
- Game launches and shows the main menu successfully
- Static background image is displayed instead of the 3D animated shell map
- Behavior is identical to passing
-noshellmapon the command line - The 3D rotating battlefield scene (shell game) never starts
-
GameClient::update()→TheShell->showShellMap(TRUE)→TheShell->showShell()(GameClient.cpp#L608) -
Shell::showShellMap(useShellMap)at Shell.cpp#L537:- If
useShellMap && TheGlobalData->m_shellMapOn→ sendsMSG_NEW_GAME(GAME_SHELL)withm_pendingFile = m_shellMapName - Else → loads
Menus/BlankWindow.wnd(static background)
- If
-
Default:
m_shellMapOn = TRUE,m_shellMapName = "Maps\\ShellMap1\\ShellMap1.map"(GlobalData.cpp#L1008) -
GameData.ini(insideINIZH.big) overrides the name to the correct ZH value:ShellMapName = Maps\ShellMapMD\ShellMapMD.map -
Maps\ShellMapMD\ShellMapMD.mapIS present inMapsZH.big✅
The BIG VFS on Linux may fail to match the path Maps\ShellMapMD\ShellMapMD.map because
of backslash vs forward-slash handling inconsistency. If MSG_NEW_GAME(GAME_SHELL) is
dispatched but the map fails to load, the game likely falls back to the static background
without user-visible error.
Where to check: StdBIGFileSystem::openFile() path comparison — does it normalize
\ → / before comparing against BIG entry names?
If INIZH.big fails to load or GameData.ini parsing is skipped, m_shellMapName
stays as Maps\ShellMap1\ShellMap1.map (Generals, not ZH). That path doesn't exist
in any BIG archive → map load fails → static background.
Where to check: Print m_shellMapName and m_shellMapOn at runtime just before
showShellMap(TRUE) is called.
Some code path calls parseNoShellMap() or directly sets m_shellMapOn = FALSE before
showShellMap(TRUE) runs. Possible if Linux SDL command-line args are being mis-parsed
by the game's arg parser.
Where to check: Add log at entry of parseNoShellMap().
Map IS found but the shell game logic (W3D terrain setup, heightmap, etc.) crashes or is silently skipped on Linux. The shell then never enters the game mode.
Add before showShellMap(TRUE) in GameClient.cpp:
fprintf(stderr, "[SHELL_DIAG] m_shellMapOn=%d m_shellMapName='%s'\n",
(int)TheGlobalData->m_shellMapOn, TheGlobalData->m_shellMapName.str());
fflush(stderr);Add at top of Shell::showShellMap():
fprintf(stderr, "[SHELL_DIAG] showShellMap(use=%d) shellMapOn=%d -> %s\n",
useShellMap, TheGlobalData->m_shellMapOn,
(useShellMap && TheGlobalData->m_shellMapOn) ? "3D MAP" : "STATIC BG");
fflush(stderr);Follow GameLogic's handling of GAME_SHELL new game message.
Check if m_shellMapName is the correct ZH path, and whether m_shellMapOn became FALSE.
| File | Purpose |
|---|---|
| GlobalData.cpp#L1008 | Default init of shellMapName / shellMapOn |
| Shell.cpp#L537 | The showShellMap() decision branch |
| GameClient.cpp#L608 | Initial showShellMap(TRUE) call |
| CommandLine.cpp#L776 | parseNoShellMap() — should NOT be called |
Core/GameEngineDevice/Source/StdDevice/Common/StdBIGFileSystem.cpp |
BIG VFS path comparison / normalization |
-noshellmapCLI arg: NOT passed ✅- Default
m_shellMapOn: TRUE ✅ - Replay mode: NOT active ✅
ShellMapMD.mapin archive: File IS inMapsZH.big✅GameData.inivalue: Correct ZH path inINIZH.big✅
Updated: 2026-02-19 | Session 48
- Entry: GeneralsMD/Code/GameEngine/Source/Common/GameMain.cpp
- Invocation:
TheGameEngine->init(); - Debug Output: "DEBUG: GameEngine::init() START" APPEARS in logs
###3. Initialization Sequence Maps Correctly ✅
main() [SDL3Main.cpp]
↓
GameMain() [GameMain.cpp]
↓
GameEngine::init() [GameEngine.cpp:359] ← CALLED ✅
├─ TheSubsystemList = new SubsystemInterfaceList
├─ initSubsystem(TheLocalFileSystem...)
├─ initSubsystem(TheArchiveFileSystem...)
├─ initSubsystem(TheWritableGlobalData...) ← **HANGS HERE** ⚠️
│ └─ Calls GlobalData::parseSpecialFile() → generates ExeCRC
└─ TheShell->push("Menus/MainMenu.wnd") [line 703] ← UNREACHED
- Function: GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp:1295
- Linux Optimization: Skips 178MB binary read, uses version-based CRC
- Debug Output: "DEBUG: generateExeCRC() - END, about to execute return statement" APPEARS
- Status: Function completes without error
Debug traces confirmed:
✅ "DEBUG: GameEngine::init() START"
✅ "DEBUG: GameEngine::init() - INI created"
✅ "DEBUG: GameEngine::init() - About to call initSubsystem(TheWritableGlobalData...)"
✅ "DEBUG: generateExeCRC() about to return CRC: 0x00000002"
✅ "DEBUG: generateExeCRC() - END, about to execute return statement"
❌ "DEBUG: GameEngine::init() - initSubsystem(TheWritableGlobalData) returned" ← NEVER APPEARS
Conclusion: Program hangs AFTER generateExeCRC() returns but BEFORE initSubsystem(TheWritableGlobalData) completes.
initSubsystem()triggersGlobalData::parseSpecialFile()or similar- INI file parsing code may have synchronization issue
- Candidate:
std::lock_guard,CriticalSection, or similar locking mechanism
- GlobalData initialization reads
Data\INI\Default\GameDataandData\INI\GameData - May be stuck parsing specific INI field
- Memory issues or string operations causing hang
- TheArchiveFileSystem (BIG file system) just initialized
- INI parsing may be querying archive for data files
- Possible race condition or deadlock between file systems
- stderr output stops abruptly after "END, about to execute return statement"
- Could indicate buffer not being flushed in signal handler context
- Less likely given that prior fprintf calls work fine
-
Add debug to TheSubsystemList->initSubsystem()
- Trace exactly when it hangs
- Check if it's in GlobalData parsing or elsewhere
-
Isolate INI Parsing
- Add debug before/after GlobalData::parseSpecialFile()
- Check which INI field causes hang
-
Check for Lock/Mutex Issues
- Search for CriticalSection usage in GlobalData
- Look for HANDLE or std::mutex acquisitions
- Verify no recursive locks
-
Disable INI parsing (test-only)
- Comment out initSubsystem(TheWritableGlobalData) temporarily
- See if program continues to shell menu push
-
Add stack trace on timeout
- Use GDB to get backtrace when timeout triggers
- Shows exactly which function is executing when hang occurs
- SubsystemInterfaceList.cpp - initSubsystem() implementation
- GlobalData.cpp parseSpecialFile() - INI parsing entry
- CriticalSection.h - Synchronization primitives
- INI parsing code - Field parsing logic
- SDL3 initialization ✅
- DXVK graphics device ✅
- Audio system (OpenAL) ✅
- File system initialization ✅
- Command line parsing ✅
- Version object creation ✅
- Deadlock mystery: Program hangs synchronously; likely requires advanced debugging (GDB stack trace) to identify
- Binary location:
/home/felipe/Projects/GeneralsX/build/linux64-deploy/GeneralsMD/GeneralsXZH - Build command:
./scripts/docker-build-linux-zh.sh linux64-deploy - Run command:
timeout 30s ./build/linux64-deploy/GeneralsMD/GeneralsXZH -win 2>&1 - Debug markers now in code at:
- GameEngine::init() START/END
- initSubsystem() call points
- generateExeCRC() entry/exit
Successfully narrowed hang from "entire initialization" down to single function call initSubsystem(TheWritableGlobalData). This is major progress - we now have a precise location to investigate. Next session should focus on GDB debugging of that specific call stack.
Investigator: GitHub Copilot (Claude Haiku)
Date: February 18, 2026
Status: 🔴 Blocked - Requires GDB/stack tracing
Confidence: 95% - Hang location precisely identified