Skip to content

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.

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.

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.

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.

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

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.

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 case matches it.
  • Code gets the wrong window or nothing. FindChildWnd finds 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 Id reads as 0 (ioXMLElement::GetIntAttribute returns 0 when the attribute is absent, in all three sources), which is one more number to collide with.

Rules to keep when you edit:

  1. Copy the Id values from the window class header and from WndID.h of your own client source. Never invent them.
  2. Do not reuse a number among the siblings of one parent.
  3. Keep the ClassName of a child equal to the class the code casts to.
  4. 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).

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.

  • The full list of ExStyle flags and their parameters.
  • Which ExtraInfo fields each window class reads.
  • How Layer is ordered against the built-in z-order of modal windows.