This document describes the complete code flow of the SwgClient application, from startup through the main game loop to shutdown.
- Overview
- Entry Point (WinMain)
- Main Initialization (ClientMain)
- Game Loop (Game::run)
- Shutdown Sequence
- Visual Flow Diagram
The SwgClient follows a traditional game engine architecture:
- Startup: Initialize all subsystems in dependency order
- Main Loop: Update game state, process input, render graphics
- Shutdown: Clean up resources and save user settings
Key files:
src/game/client/application/SwgClient/src/win32/WinMain.cpp- Windows entry pointsrc/game/client/application/SwgClient/src/win32/ClientMain.cpp- Initialization and shutdownsrc/engine/client/library/clientGame/src/shared/core/Game.cpp- Main game loop
Location: src/game/client/application/SwgClient/src/win32/WinMain.cpp (Lines 111-122)
The Windows WinMain function is the application entry point and performs initial memory setup:
-
User-Selected Memory Target (Lines 24-46):
- Checks
SWGCLIENT_MEMORY_SIZE_MBenvironment variable - Parses the value (manual atoi implementation)
- Sets memory limit via
MemoryManager::setLimit(megabytes, false, false)
- Checks
-
Default Memory Target (Lines 50-68):
- Queries system RAM using
GlobalMemoryStatusEx() - Allocates 75% of available RAM, capped at 1536MB
- Without PAE (Physical Address Extension), 2048MB is max for 32-bit process
- SWG can crash if given all available RAM, so 1536MB limit ensures stability
- Queries system RAM using
-
Delegate to ClientMain (Line 121):
- Calls
ClientMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow) - Returns result code to operating system
- Calls
Location: src/game/client/application/SwgClient/src/win32/ClientMain.cpp (Lines 127-397)
The ClientMain function orchestrates the initialization of all game subsystems in the correct dependency order.
SetupSharedThread::install();- Initializes threading primitives used throughout the engine
SetupSharedDebug::install(4096);- Sets up debug output with 4KB buffer
- Enables logging and assertion systems
SetupSharedFoundation::install(data);Initializes core engine with:
- Window Configuration:
- Title: "SWG: Titan" (production) or custom development name
- Window icons (normal and small)
- Window instance handle
- Config File:
- Production:
client.cfg - Debug:
client_d.cfg
- Production:
- Clock Settings:
- Uses sleep for timing (
clockUsesSleep = true) - Minimum frame rate: 1 FPS
- Maximum frame rate: 144 FPS
- Uses sleep for timing (
- Crash Reporting: Always writes mini-dumps on crashes
- Command Line: Passes through for parameter processing
-
Config File Validation (Lines 181-182):
- Verifies config file loaded successfully
- Fatal error if config is empty
-
Single Instance Check (Lines 186-191):
- Creates named semaphore "SwgClientInstanceRunning"
- Prevents multiple instances (configurable in non-production)
- Shows message box and exits if another instance exists
-
Game Feature Bits (Lines 195-213):
- Loads from
[Station]section:gameFeatures - Clears bits specified in
[ClientGame]:gameBitsToClear - Feature flags include:
Base- Core gameSpaceExpansionRetail- Jump to Lightspeed (JTL)Episode3ExpansionRetail- Rage of the WookieesTrialsOfObiwanRetail- Trials of Obi-Wan
- Automatically promotes beta/preorder flags to retail
- Sets subscription feature bits
- Registers external command handler
- Loads from
-
Compression (Lines 216-219):
- Initializes zlib with 3 threads for concurrent access
-
Regular Expressions (Line 222):
- Enables regex support for string parsing
-
File System (Lines 225-238):
- Determines SKU bits based on owned expansions
- Installs TreeFile system with appropriate SKU mask
- Loads
misc/override.cfgif present (Lines 99-110)
-
Math Library (Line 243):
- Vector, matrix, quaternion operations
-
Utility System (Lines 246-249):
- Game-specific utility functions
- Enables file caching
-
Random Number Generator (Line 252):
- Seeds with current time:
time(NULL)
- Seeds with current time:
-
Logging (Line 254):
- Creates "SwgClient" log file
-
Image Loading (Lines 257-259):
- TGA, DDS, and other image format support
-
Network Layer (Lines 262-267):
- Client-specific network configuration
- Message factory registration
- Game and SWG network message handlers
-
Object System (Lines 269-278):
- Time-based appearance templates
- Slot/hardpoint system (for attachments, weapons)
- Customization data (character appearance)
- Movement tables (animation blending)
-
Game Core (Lines 281-289):
- Game scheduler for time-based events
- Mount validation tables
- Debug callback for bad string IDs:
CuiManager::debugBadStringIdsFunc - Commodities/auction search attributes
- Auction filter display strings
-
Terrain System (Lines 292-294):
- Game-specific terrain configuration
-
XML Parsing (Line 297):
- XML file loading and processing
-
Pathfinding (Line 300):
- AI navigation system
-
Audio System (Line 305):
- Sound effects and music playback
-
Graphics System (Lines 308-314):
- Default resolution: 1024x768
- Alpha buffer bit depth: 0 (no alpha buffer)
- Direct3D initialization
- Window/fullscreen mode support
-
Splash Screen (Lines 317-318):
SplashScreen::install(); SplashScreen::render();
- Displays loading screen immediately after graphics init
- Provides visual feedback during remaining initialization
-
Video Playback (Line 320):
- Bink video support for cutscenes
- Uses Miles Sound System driver
-
DirectInput (Lines 323-327):
- Keyboard and mouse input
- Registers callbacks:
- Screenshot:
ScreenShotHelper::screenShot(F10 key) - Toggle windowed:
Graphics::toggleWindowedMode(Alt+Enter) - Debug menu:
Os::requestPopupDebugMenu
- Screenshot:
- Lost focus handler:
DirectInput::unacquireAllDevices
-
Client Objects (Lines 330-332):
- Game-specific object types
- Client-side object controllers
-
Animation (Lines 335-339):
- Basic animation system
- Skeletal animation with game-specific configuration
-
Texture Renderer (Line 342):
- Dynamic texture generation (e.g., UI elements)
-
Client Terrain (Line 345):
- Terrain rendering and collision
-
Particle System (Line 348):
- Visual effects (explosions, weather, etc.)
-
Client Game (Lines 351-356):
- Game-specific client logic
- Scene management
- Camera control
- UI manager implementation callbacks:
CuiManager::setImplementationInstallFunctions( SwgCuiManager::install, SwgCuiManager::remove, SwgCuiManager::update );
-
Bug Reporting (Line 358):
- Disabled customer service features (per README.md)
-
IoWin (Input/Output Windows) (Line 361):
- Window management system
-
SwgClientUserInterface (Line 364):
- SWG-specific UI components
- HUD, inventory, chat, etc.
-
G15 LCD Support (Line 367):
- Logitech G15 keyboard LCD display
rootInstallTimer.manualExit();
SetupSharedFoundation::callbackWithExceptionHandling(Game::run);- Stops initialization timer
- Invokes
Game::run()with exception handling wrapper - Control remains in
Game::run()until game exits
After Game::run() returns:
-
Save Settings (Lines 375-386):
- UI workspace settings (window positions, states)
- Chat window settings (filters, tabs)
- CuiSettings (general UI preferences)
- Chat history
- User options (keybindings, graphics settings)
- Local machine options
-
Remove Core Systems (Lines 390-391):
SetupSharedFoundation::remove()- Cleans up foundationSetupSharedThread::remove()- Cleans up threading
-
Release Instance Lock (Lines 393-394):
- Closes semaphore handle
- Allows another instance to start
-
Return to OS (Line 395):
- Returns 0 (success)
Location: src/engine/client/library/clientGame/src/shared/core/Game.cpp
The main game loop function with minimal overhead:
void Game::run()
{
DEBUG_REPORT_LOG_PRINT(true, ("Game::run\n"));
Game::install(Game::A_client);
ms_loops = 0;
while (!isOver())
{
runGameLoopOnce(false, NULL, 0, 0);
}
delete ms_sceneCreator;
ms_sceneCreator = 0;
if (ms_cutSceneHelper)
ms_cutSceneHelper->endCutScene(true);
}-
Game::install(Game::A_client) (Lines 691-970):
- Registers debug flags
- Allocates crash report buffers
- Installs game managers in order:
- Options: Brightness, contrast, gamma (ground & space)
- Game Managers:
- MoodManager (emotional states)
- ObjectAttributeManager (item stats)
- DraftSchematicManager (crafting)
- AuctionManager (bazaar/market)
- PlanetMapManager (map system)
- ResourceIconManager (resource display)
- ClientRegionManager (areas/zones)
- QuestJournalManager (quest tracking)
- RoadmapManager (tutorial guidance)
- QuestManager (quest logic)
- CommandCppFuncs (command system)
- ClientCommandQueue (command buffering)
- ClientCombatPlaybackManager (combat animations)
- CellProperty (building interiors)
- Network: GameNetwork::install()
- CutScene: Playback system
- UI: CuiManager with asynchronous loader
-
Reset Loop Counter (Line 1042):
ms_loops = 0for tracking frame count
Continues while !isOver(), which checks:
ms_doneflag (set byGame::quit())- Window close requested
- OS indicates application should exit
Each iteration calls runGameLoopOnce(false, NULL, 0, 0).
After loop exits:
- Deletes pending scene creator
- Ends any active cutscene
Each frame executes these steps in order:
Os::update(); // Process Windows messages
VideoList::service(); // Update video playback
const float elapsedTime = Game::getElapsedTime();- OS Update: Processes Windows message queue (WM_PAINT, WM_KEYDOWN, etc.)
- Video Service: Updates playing cutscene videos
- Elapsed Time: Gets frame delta time from clock
- Memory Tracking: Updates memory statistics
Periodic cleanup to manage memory:
- Object Templates:
ObjectTemplate::garbageCollect() - Terrain Chunks:
TerrainObject::garbageCollect() - Animations:
AnimationStateHierarchyTemplate::garbageCollect()
If exit timer active:
- Check if countdown elapsed
- Call
quit()when time expires
if (AsynchronousLoader::isEnabled())
AsynchronousLoader::processLoadRequests(0.030f);- Loads assets in background (30ms per frame)
- Prevents hitches during gameplay
if (Os::isMainWindowFocus())
{
GameScheduler::alter(elapsedTime);
}
else
{
GameScheduler::alterNetworkMessagingOnly(elapsedTime);
}- With Focus: Updates all game logic (objects, combat, etc.)
- Without Focus: Only processes network messages
- Prevents game state updates when minimized
DirectInput::update(elapsedTime);- Reads keyboard and mouse state
- Triggers callbacks for hotkeys
- Builds input event queue
static Timer networkTimer(0.05f); // 50ms = 20Hz
if (networkTimer.updateZero(elapsedTime))
{
GameNetwork::update();
}- Updates network at fixed 20Hz rate (every 50ms)
- Sends/receives packets
- Processes incoming messages
- Independent of frame rate
ClientCommandQueue::update(elapsedTime);
ObjectAttributeManager::update();- Command Queue: Executes queued player commands
- Attributes: Updates item/creature stats display
if (Os::isMainWindowFocus())
{
IoWinManager::update(elapsedTime); // UI input processing
IoWinManager::beginFrame(); // Start UI frame
CuiManager::update(elapsedTime); // Update UI logic
IoWinManager::endFrame(); // End UI frame
}
CuiManager::sendHeartbeat(); // Keep-alive
ClientEffectManager::update(elapsedTime); // Visual effects- IoWinManager: Processes UI mouse/keyboard events
- CuiManager: Updates UI state (animations, tooltips, etc.)
- Heartbeat: Sent even without focus (prevents timeout)
- Effects: Updates particle effects, lights, sounds
Object * const playerSoundObject = getPlayerSoundObject();
Audio::alter(elapsedTime, playerSoundObject);- Updates 3D audio positions
- Streams music
- Processes sound cue triggers
if (TextureBaker::update(elapsedTime))
Graphics::setStaticShaders(ShaderTemplate::getStaticShaderVector());- Bakes dynamic textures (character customization)
- Updates shader list when complete
Graphics::update(elapsedTime); // Prepare for frame
Graphics::beginScene(); // Clear buffers
Graphics::setRenderWorldSetupFunction(Appearance::setupRenderWorld);
IoWinManager::draw(); // Render all UI and 3D
Graphics::endScene(); // Finalize frame
VideoList::drawFrameIfPlaying(); // Render video frame
Graphics::present(hwnd, rect); // Flip buffers (present to screen)Rendering Pipeline:
- Graphics Update: Updates dynamic buffers, preps render state
- Begin Scene: Clears render target and depth buffer
- Setup Render World: Configures camera, fog, lighting
- IoWinManager Draw: Renders in this order:
- 3D scene (terrain, objects, characters)
- Particle effects
- UI elements (HUD, windows, cursor)
- End Scene: Finalizes draw calls
- Video: Overlays fullscreen video if playing
- Present: Swaps back buffer to screen (vsync optional)
Appearance::updateAppearanceTemplateTimeout(elapsedTime); // Timeout unused templates
GameNetwork::getNetworkStatistics(); // Update bandwidth stats
Clock::limitFrameRate(); // Sleep if ahead of target FPS
++ms_loops; // Increment frame counter- Template Timeout: Releases unused appearance data
- Network Stats: Calculates ping, bandwidth
- Frame Rate Limiter: Sleeps to maintain target FPS (144 Hz max)
- Loop Counter: Increments total frame count
| System | Frequency | Notes |
|---|---|---|
| OS Update | Every frame | Windows message processing |
| Garbage Collection | Every frame | Templates, terrain, animations |
| Async Loading | Every frame | 30ms budget per frame |
| Game Scheduler | Every frame | Full update when focused |
| Input | Every frame | Keyboard and mouse |
| Network | 20 Hz (50ms) | Fixed update rate |
| Commands | Every frame | Command queue processing |
| UI | Every frame | Only when focused |
| Audio | Every frame | 3D positional updates |
| Graphics | Every frame | Render at target FPS |
| Frame Limiter | Every frame | Caps at 144 FPS |
Called after main loop exits:
-
Unregister Debug Flags (Lines 976-978):
- Removes client-specific debug commands
-
Clear Crash Buffers (Lines 980-983):
- Deallocates crash report string buffers
-
Cleanup Managers (Lines 985-988):
- PlaybackScriptManager::remove()
- Other manager cleanup
-
Delete Emitter (Lines 990-991):
- Releases message dispatch emitter
Cleans up active scene:
if (ms_scene)
{
ms_scene->quit();
delete ms_scene;
ms_scene = NULL;
}- Calls scene's quit() method
- Deletes scene object
- Nulls pointer
After Game::run() returns:
-
Save All Settings:
- Workspace layout
- Chat configuration
- UI preferences
- Chat history
- User keybindings
- Machine-specific options
-
Remove Foundation Systems:
- Foundation shutdown (closes log files)
- Thread system cleanup
-
Release Instance Lock:
- Close semaphore
- Allow new instance
-
Return Success:
- Exit code 0
┌─────────────────────────────────────────────────────────────────┐
│ WinMain Entry │
│ │
│ 1. Setup Memory Manager (user setting or 75% RAM, max 1536MB) │
│ 2. Call ClientMain() │
└────────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ ClientMain Initialization │
├─────────────────────────────────────────────────────────────────┤
│ Phase 1: Core Foundation │
│ • Thread System │
│ • Debug System (4KB buffer) │
│ • Foundation (window, config, clock) │
├─────────────────────────────────────────────────────────────────┤
│ Phase 2: Shared Engine Subsystems │
│ • Config validation & single instance check │
│ • Game feature bits (Base, JTL, Ep3, ToOW) │
│ • Compression, Regex, File System, Math │
│ • Utility, Random, Logging, Image │
│ • Network Layer & Message Handlers │
│ • Object System (slots, customization, movement) │
│ • Game Core (scheduler, mounts, commodities) │
│ • Terrain, XML, Pathfinding │
├─────────────────────────────────────────────────────────────────┤
│ Phase 3: Client-Specific Subsystems │
│ • Audio System │
│ • Graphics System (D3D, 1024x768) │
│ • Splash Screen ★ (rendered immediately) │
│ • Video Playback (Bink) │
│ • DirectInput (keyboard, mouse, hotkeys) │
│ • Client Objects, Animation, Skeletal Animation │
│ • Texture Renderer, Client Terrain, Particles │
│ • Client Game (scene, camera) │
│ • UI Manager (CuiManager, SwgCuiManager) │
│ • IoWin, SwgClientUserInterface │
│ • G15 LCD Support │
├─────────────────────────────────────────────────────────────────┤
│ Phase 4: Main Loop │
│ • Game::run() ──────────────────────────┐ │
│ │ │
└────────────────────────────────────────────┼────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Game::run() │
├─────────────────────────────────────────────────────────────────┤
│ Initialization: │
│ • Game::install(A_client) │
│ - Register debug flags │
│ - Install game managers (Mood, Auction, Quest, etc.) │
│ - Install GameNetwork │
│ - Install CutScene system │
│ - Install CuiManager with async loader │
│ • Reset loop counter (ms_loops = 0) │
├─────────────────────────────────────────────────────────────────┤
│ Main Loop: while (!isOver()) │
│ │ │
│ └─► runGameLoopOnce() ────────────────┐ │
│ │ │
└───────────────────────────────────────────┼──────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ runGameLoopOnce() - Each Frame │
├─────────────────────────────────────────────────────────────────┤
│ 1. Frame Timing & OS │
│ • Os::update() - Process Windows messages │
│ • VideoList::service() - Update cutscene video │
│ • Calculate elapsed time │
│ • Update memory statistics │
├─────────────────────────────────────────────────────────────────┤
│ 2. Garbage Collection │
│ • Object templates │
│ • Terrain chunks │
│ • Animation templates │
├─────────────────────────────────────────────────────────────────┤
│ 3. Exit Timer Check │
│ • Check if countdown elapsed │
├─────────────────────────────────────────────────────────────────┤
│ 4. Asynchronous Loading │
│ • Process load requests (30ms budget) │
├─────────────────────────────────────────────────────────────────┤
│ 5. Game Scheduler (60+ FPS) │
│ • If focused: GameScheduler::alter() - full update │
│ • If not focused: network messages only │
├─────────────────────────────────────────────────────────────────┤
│ 6. Input Processing (60+ FPS) │
│ • DirectInput::update() - keyboard & mouse │
├─────────────────────────────────────────────────────────────────┤
│ 7. Network Update (20 Hz = every 50ms) │
│ • GameNetwork::update() │
│ • Send/receive packets │
│ • Process messages │
├─────────────────────────────────────────────────────────────────┤
│ 8. Commands & Attributes │
│ • ClientCommandQueue::update() │
│ • ObjectAttributeManager::update() │
├─────────────────────────────────────────────────────────────────┤
│ 9. UI & Input Windows (only if focused) │
│ • IoWinManager::update() - UI input │
│ • IoWinManager::beginFrame() │
│ • CuiManager::update() - UI logic │
│ • IoWinManager::endFrame() │
│ • CuiManager::sendHeartbeat() - always │
│ • ClientEffectManager::update() │
├─────────────────────────────────────────────────────────────────┤
│ 10. Audio Update │
│ • Get player sound object │
│ • Audio::alter() - 3D sound, music streaming │
├─────────────────────────────────────────────────────────────────┤
│ 11. Texture Baking │
│ • TextureBaker::update() │
│ • Update static shaders if complete │
├─────────────────────────────────────────────────────────────────┤
│ 12. Graphics Rendering │
│ • Graphics::update() - prepare frame │
│ • Graphics::beginScene() - clear buffers │
│ • Graphics::setRenderWorldSetupFunction() │
│ • IoWinManager::draw() ─────────────────┐ │
│ │ ├─ 3D Scene (terrain, objects) │ │
│ │ ├─ Particle effects │ │
│ │ └─ UI elements (HUD, windows) │ │
│ • Graphics::endScene() - finalize │ │
│ • VideoList::drawFrameIfPlaying() │ │
│ • Graphics::present() - flip buffers ◄──┘ │
├─────────────────────────────────────────────────────────────────┤
│ 13. Post-Frame │
│ • Timeout unused appearance templates │
│ • Update network statistics │
│ • Clock::limitFrameRate() - sleep if needed (144 FPS max) │
│ • Increment loop counter │
└────────────────────────────┬────────────────────────────────────┘
│
│ (Loop continues until quit)
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Shutdown Sequence │
├─────────────────────────────────────────────────────────────────┤
│ Game::run() Cleanup: │
│ • Delete scene creator │
│ • End cutscene │
├─────────────────────────────────────────────────────────────────┤
│ Game::remove(): │
│ • Unregister debug flags │
│ • Clear crash buffers │
│ • Remove PlaybackScriptManager │
│ • Delete emitter │
├─────────────────────────────────────────────────────────────────┤
│ ClientMain Cleanup: │
│ • Save workspace settings │
│ • Save chat settings │
│ • Save UI settings │
│ • Save chat history │
│ • Save user options │
│ • Save machine options │
│ • SetupSharedFoundation::remove() │
│ • SetupSharedThread::remove() │
│ • Close instance semaphore │
│ • Return 0 (success) │
└─────────────────────────────────────────────────────────────────┘
Different systems run at different rates to balance performance and responsiveness:
| System | Rate | Interval | Notes |
|---|---|---|---|
| Frame Loop | 1-144 Hz | 6.9-1000ms | Capped at 144 FPS max |
| OS Messages | Every frame | ~6.9ms @ 144Hz | Windows event queue |
| Input | Every frame | ~6.9ms @ 144Hz | Keyboard/mouse polling |
| Game Logic | Every frame | ~6.9ms @ 144Hz | Objects, combat, etc. |
| Graphics | Every frame | ~6.9ms @ 144Hz | Rendering pipeline |
| Audio | Every frame | ~6.9ms @ 144Hz | 3D sound updates |
| Network | 20 Hz | 50ms | Fixed rate, frame-independent |
| Async Loading | Every frame | 30ms budget | Background asset loading |
| Garbage Collection | Every frame | Variable | Template/terrain cleanup |
Note: Frame times shown at max 144 FPS. Actual frame time varies with settings and hardware.
All subsystems initialize in dependency order:
- Foundation (threading, debug, memory)
- Core libraries (math, file, network)
- Game systems (objects, terrain, audio)
- Client-specific (graphics, UI, input)
- Game::run() - Main loop orchestration
- runGameLoopOnce() - Single frame execution
- ClientMain() - Initialization and shutdown
- WinMain() - Platform-specific entry
Network updates at fixed 20 Hz (50ms) regardless of frame rate. This ensures consistent network behavior across different hardware.
Assets load in background with 30ms per-frame budget, preventing frame rate hitches during gameplay.
Game logic pauses when window loses focus, but network continues to process messages preventing disconnects.
Main loop wrapped in exception handler (SetupSharedFoundation::callbackWithExceptionHandling) to capture crashes and write dump files.
- Memory manager configured (instant)
- Core systems initialized (< 1 second)
- Splash screen shown (first visual feedback)
- Graphics subsystems loaded (1-2 seconds)
- Game content loaded asynchronously (continues during play)
- OS/Input/Network (< 5ms)
- Game logic (5-20ms, scene dependent)
- Rendering (10-30ms, resolution/detail dependent)
- Frame limiter (0-13ms, sleeps if ahead of target)
- Save settings (< 100ms)
- Cleanup resources (< 500ms)
- Close gracefully (< 1 second total)
Key configuration files:
client.cfgorclient_d.cfg- Main settingsmisc/override.cfg- Optional overrides loaded after main configoptions.cfg- User preferences (saved on exit)
Environment variables:
SWGCLIENT_MEMORY_SIZE_MB- Override memory allocation
Command line parameters processed via SetupSharedFoundation::Data::commandLine.
For more information, see:
- README.md - Build instructions and project overview
- Source code comments in key files:
WinMain.cpp- Entry pointClientMain.cpp- InitializationGame.cpp- Main loop- Individual Setup*.cpp files - Subsystem initialization details
This documentation was created based on the CSRC repository codebase. Last updated: 2026-01-19