Window XML
Every window of the client (lobby, shop, inventory, popups) is an XML file in xml/. The XML describes the look and layout. The behaviour is in a C++ class. The two meet at the class name and at the Id of each window.
This page follows the client loader (ioGUIManager and ioWnd in io3DEngine, window classes in LSClient\GUI) and the web tools. Anything marked not confirmed yet was not verified.
How the client opens a window
Section titled “How the client opens a window”Code calls g_GUIMgr.AddWnd("XML/rollbookwnd.xml"). The loader reads the file through the packs (see IOP Pack Format), parses it as XML and builds the window tree from the root <Window> element. The result is cast to the C++ class the code expects, for example RollBookWnd.
File layout
Section titled “File layout”A window file is a tree of <Window> elements. Child windows are nested <Window> elements.
<?xml version="1.0" encoding="euc-kr" ?><Window ClassName="RollBookWnd" Id="6272" IDName="" MemberName=""> <Size X="100" Y="50" Width="400" Height="300" XAlign="Center" YAlign="Center" /> <Style>IWS_CANMOVE|IWS_EXIT_ESC</Style> <Title> ... </Title> <Imagery> ... </Imagery> <Window ClassName="ioButton" Id="1"> ... </Window></Window>The values are made up to show the shape.
Attributes of <Window>
Section titled “Attributes of <Window>”| Attribute | Meaning |
|---|---|
ClassName |
Name of the C++ window class. Built-in classes are ioWnd, ioButton, ioEdit, ioScroll, ioProgressBar and the ...EX family. Game classes (RollBookWnd, LobbyWnd, …) are registered by name in ioSP2GUIManager::RegisterWndCreator |
SubClassName |
Used when the main class is unknown: the client tries this name next. If nothing matches, a non-debug build makes a plain ioCustomWnd, so a typo shows an empty window instead of an error |
Id |
Number that identifies the window. See the next section |
IDName, MemberName |
Names added for the layout tool. The client stores them; their use in game code is not confirmed yet |
Layer |
Draw order inside the parent (2019 and 2021 only) |
In a debug build an unknown class name logs “Unknown ClassName” and the window is skipped.
Child elements
Section titled “Child elements”The loader handles these tags and ignores any other:
| Tag | Content |
|---|---|
Size |
X, Y, Width, Height in pixels (Width="Parent" / Height="Parent" follow the parent), XAlign and YAlign, CheckParentOutSide |
Style |
Text with flags joined by | (list below) |
ExStyle |
Extra style flags, some with a parameter |
Title |
Format (offset, size, style, alignment), Color per state (Normal, Over, Push, Disable, NoneSelected) and Text |
Tooltip |
Help rows with Text, Align, TextColor |
DragRect |
Left, Top, Right, Bottom: the grab area for dragging |
Imagery |
DefaultFrameImagery (a frame from DefaultUIFrame.xml by Templete), FrameImagery, and Image rows (Type, Imageset, Image, or File) |
ExtraInfo |
Free data for the window class; its meaning depends on the class |
Text |
Extra text lines (2019 and 2021 only) |
Template |
Child window blueprints made later by code (2019 and 2021 only) |
Window |
A child window |
The Imageset and Image attributes of an Image row name a box of UI Image Set XML. The attribute is spelled Templete in the files (the game’s own spelling).
Style flags
Section titled “Style flags”IWS_START_HIDE, IWS_INACTIVE, IWS_BACKMOST, IWS_CANMOVE, IWS_MODAL, IWS_EXIT_ESC, IWS_PROCESS, IWS_DRAG_DROP, IWS_NO_MOUSE_RESPONSE, IWS_CHILD_ONLY_RESPONSE, IWS_TOPMOST, IWS_EXACTIVE, IWS_MODAL_TOOLTIP, IWS_MODAL_EXTEND, IWS_ISINRECT_CENTER. An unknown flag is ignored. A window without IWS_START_HIDE is shown as soon as it is built.
The Id rule
Section titled “The Id rule”There are two kinds of ID, and both come from C++ code, not from the XML.
| Kind | Where the number is defined | How code uses it |
|---|---|---|
| Top-level window | #define in LSClient\WndID.h, for example ROLLBOOK_WND = 6272 |
g_GUIMgr.FindWnd(ROLLBOOK_WND), ShowWnd, HideWnd, DeleteWnd |
| Child window | enum inside the window class header, for example ID_CLOSE_BTN = 1, ID_TOOL_TIP = 10 |
FindChildWnd(ID_CLOSE_BTN), and case ID_CLOSE_BTN: in the command handler |
The XML Id must be the same number. The lookup is a plain number match (GetID() == dwID), and FindChildWnd looks only at the direct children and returns the first match.
What goes wrong with a wrong Id:
- A button does nothing. The click arrives with the XML number; no
casematches it. - Code gets the wrong window or nothing.
FindChildWndfinds another child with that number, or none, and the cast to the button class gives a null pointer. - Two children share a number. Only the first can be found. The other never gets its updates, so buttons seem to overlap or one stays frozen.
- A missing
Idreads as 0 (ioXMLElement::GetIntAttributereturns 0 when the attribute is absent, in all three sources), which is one more number to collide with.
Rules to keep when you edit:
- Copy the
Idvalues from the window class header and fromWndID.hof your own client source. Never invent them. - Do not reuse a number among the siblings of one parent.
- Keep the
ClassNameof a child equal to the class the code casts to. - When you add a child that the code does not know, give it a number that is not in the class enum.
Top-level numbers can differ between clients because each WndID.h has its own list. The 2014 header has fewer entries than 2019 and 2021, and 2019 and 2021 are identical. Windows copied from another client may therefore carry a number that means something else in yours (not confirmed yet for each pair of clients).
Differences between the sources
Section titled “Differences between the sources”| Part | 2014 | 2019 | 2021 |
|---|---|---|---|
Window, Size, Style, ExStyle, Title, Tooltip, DragRect, Imagery, ExtraInfo |
yes | yes | yes |
Text, Template, Layer |
no | yes | yes |
| Separate list for tooltip windows | no | yes | yes |
ioGUIManager.cpp, ioWnd.cpp |
own version | same as 2021 | same as 2019 |
| Tool | Use |
|---|---|
| UI Windows | Draws a window the way the game does, edits the tree and attributes, saves the XML as a download. Edits change only the characters you touch |
| UI Image Sets | The images the window refers to |
| IOP Manager | Puts the edited XML into rs.iop |
The tools cannot read your C++ headers, so they cannot check an Id for you. Compare by hand with the class header.
Not confirmed yet
Section titled “Not confirmed yet”- The full list of
ExStyleflags and their parameters. - Which
ExtraInfofields each window class reads. - How
Layeris ordered against the built-in z-order of modal windows.
