UI Flow
This document traces the current client-side UI path: input, menu commands, frame rendering, and unit-data queries.
Overview
Client input
-> UI mouse/key event
-> active uiScreen_t
-> frame tree update
-> UI_DrawFrame
-> renderer API
-> OpenGL renderer or stdout renderer
All FDF parsing, layout solving, screen transitions, and frame rendering happen client-side. The server sends data for game-dependent UI, but it does not author UI frame trees.
Startup Flow
common/main.c
-> Com_Init
-> share/warcraft-3/config.cfg (shipped game defaults)
-> ~/.warcraft-3/config.cfg (writable user config)
-> ~/.warcraft-3/autoexec.cfg (optional local overrides)
-> command-line cvars
-> CL_Init
-> select renderer from r_module
-> re.Init
-> UI_GetAPI
-> ui.Init
-> UI_MenuCommandLocal(ui_start_command)
Important cvars:
| cvar | Purpose |
|---|---|
r_module |
renderer for OpenGL, stdout for text output |
ui_start_command |
Initial command, usually menu_main |
com_frame_limit |
Exit after N frames |
Loading Flow
Loading follows the Quake-style client state split:
CL_BeginLoadingMap()setscls.state = ca_loadingand seeds the loading text/progress.SCR_DrawScreenField()draws the loading plaque only whilecls.state == ca_loading.CL_PrepRefresh()loads configstring-backed assets and registers the map.- Only after all required assets are ready does
CL_PrepRefresh()sendbeginand promote the client toca_active. - Snapshot parsing may update
playerstate, but it must not flipcls.stateby itself.
That separation matters because ca_active means "gameplay can render now", not "we already received a player snapshot." If the loading plaque disappears before the world is ready, the client should keep ca_loading until the precache gate completes.
Menu Navigation Flow
- SDL input is translated by the client input layer.
UI_MouseEventLocalorUI_KeyEventLocalupdates UI state.- The current
uiScreen_treceives the event. - Button frames inspect mouse containment and event state in
games/warcraft-3/ui/ui_render.c. - If a clicked frame has
OnClick,UI_MenuCommandLocalexecutes the command. - Menu commands call direct screen/action handlers.
Example menu command:
The screen switch is local to the client. No network traffic is required for menu transitions.
Draw Flow
Each client frame calls:
ui.Refresh(msec);
CL_Input();
CL_ReadPackets();
CL_SendCommand();
CL_PrepRefresh();
SCR_UpdateScreen();
SCR_UpdateScreen calls the renderer and UI:
re.BeginFramere.RenderFrameui.DrawFrame- console/debug overlay
re.EndFrame
ui.DrawFrame dispatches to the active screen. For menu_main, games/warcraft-3/ui/screens/main_menu.c draws the MainMenu3d portrait background, the logo sprite, and the main menu frame tree.
Stdout Renderer Flow
For automated or text-first diagnostics, use:
This expands to a one-frame run with:
The stdout renderer receives the same UI draw calls as the OpenGL renderer but prints them:
draw_portrait model="UI\\Glues\\MainMenu\\MainMenu3d\\MainMenu3d.mdl" anim="Stand" viewport={...}
draw_sprite model="UI\\Glues\\MainMenu\\WarCraftIIILogo\\WarCraftIIILogo.mdl" anim="Stand" x=0.130000 y=0.080000
draw_image name="UI\\Widgets\\Glues\\GlueScreen-Button1-Border.blp" screen={...} uv={...}
draw_text font="Fonts\\FRIZQT__.TTF" rect={...} text="|CffffffffS|Ringle Player"
Use this output to verify screen composition, layout rects, UVs, text translation, color codes, and button state art before taking screenshots.
Unit Selection and Command Card Flow
Unit UI data still comes from the server because it depends on game rules and selected entities.
client selection
-> CL_RequestUnitUI
-> clc_request_unit_ui
-> server/sv_unit_ui.c
-> games/warcraft-3/game/g_unit_ui.c
-> svc_unit_ui
-> client/cl_unit_ui.c
-> ui.UpdateUnitUI
-> games/warcraft-3/ui/screens/console_ui.c
Client Request
void CL_RequestUnitUI(DWORD num_selected, DWORD *entity_nums) {
MSG_WriteByte(&cls.netchan.message, clc_request_unit_ui);
MSG_WriteByte(&cls.netchan.message, (BYTE)num_selected);
for (DWORD i = 0; i < num_selected; i++) {
MSG_WriteShort(&cls.netchan.message, (SHORT)entity_nums[i]);
}
}
Server Query
The server serializes command buttons, inventory, and build queue data into svc_unit_ui.
Client Cache
void ConsoleUI_UpdateUnitUI(DWORD num_units, uiUnitData_t *units) {
cached_unit_count = num_units;
memcpy(cached_units, units, sizeof(uiUnitData_t) * num_units);
}
The HUD screen renders from this cache on later frames.
Key Decisions
- UI rendering is client-side for instant menu interaction.
- The server remains authoritative for game data.
- FDF assets are parsed by the UI library, not by the game DLL.
- Runtime modules communicate through Quake-style function tables.
r_module=stdoutmakes draw-call output scriptable for UI debugging.