Skip to content

LuaUI Files

wezzzyrek1 edited this page Aug 13, 2026 · 3 revisions

Lua UI - File Map

Two script trees, one on each side. Neither knows the other's paths; they meet only at the numbers in the protocol files.

Two dialects, not one

The two sides do not run the same Lua:

Client Server
Runtime LuaJIT - Lua 5.1 Lua 5.3
Integers none; every number is a double real 64-bit integers
Bitwise and // operators not available available
string.pack / string.unpack not available available
Unpacking a table unpack(t) table.unpack(t)

A helper written for a server window will not necessarily run in the client script. Write each side in its own dialect rather than copying code between them.

Two consequences:

  • Bit twiddling. On the server, flags & 0xFF is ordinary code. On the client, write the arithmetic out (flags % 256) or use LuaJIT's bit library.
  • Big numbers. The client cannot hold an exact integer beyond 2^53, so a value that is exact on the server can come back rounded. See Protocol for what to do about item serials.

The payload reader and writer already hide this: each side has its own implementation with the same method names, so w:dword(v) means the same thing in both halves regardless of dialect.

Client

Everything lives under Data\Custom\Scripts.

File What it is
UI\UI.lua The window library. ui.Window{...}, layout columns and rows, and the helpers every window script uses. You call it, you do not edit it.
UI\Registry.lua The one place window ids and texture slots are named. Every script reads the same table.
UI\Protocol.lua Your wire contract: per system, its actions, result codes and limits. Mirrored on the server.
UI\Enums.lua Named client values, grouped Enums.Group.VALUE the way the server's Defines\Enums.lua is.
UI\Net.lua Routes incoming window packets to the handler that registered for them, and builds outgoing ones.
UI\Windows\*.lua One file per window. This is where you work.
UI\Windows\UIPlacement.lua A ruler for laying windows out - see below.
SimpleXml.lua Small XML reader, for windows that load a catalogue from a file.

The placement helper

UIPlacement.lua is a small HUD panel that answers the question you have while writing a window: what number do I type here? Press F11 and it reports, live:

It shows Use it for
cursor the mouse position - paste it straight into x/y
over which Lua window is under the cursor, and its id
pos that window's top-left corner
size its declared size, and in brackets what it covers on screen
anchor what the anchor you gave the helper itself resolved to
canvas the coordinate space all of the above is in

Placing a control: open your window and the helper, put the cursor where the control's top-left corner belongs, read cursor, use those two numbers. Sizing a panel: read cursor at one corner, then the other, and subtract.

Trying an anchor is the same trick applied to the helper itself. Edit its ANCHOR and MARGIN, press F9, and anchor prints where that combination lands - which beats guessing whether bottomright with margin = { 6, 140 } clears the panel already sitting there.

The bracketed pair in size is worth understanding: 280x380 (140x190) means the window declares 280x380 and covers 140x190 on screen at a render scale of 0.50. Sizes scale, x/y do not - the same asymmetry the anchors exist for.

Delete the file to drop the helper; nothing depends on it.

How window scripts get loaded

Everything in UI\Windows\ is loaded automatically, in alphabetical order, once the client has connected to the GameServer and received its settings - so the window scripts only exist from that point on, never on the login screen. There is no list to register in: dropping a file in the folder is all it takes, and deleting it removes the window.

Encrypted .usc files are always loaded. Plain .lua files are loaded only in dev mode (see Lua UI). If a script of yours silently does nothing on a live server, that setting is the first thing to check.

Reloading while you work

In dev mode, F9 reloads the whole client-side Lua without restarting the client. Edit a window script, press F9, and the change is on screen.

It is a full reset, not a per-file refresh:

  • every window is destroyed, then rebuilt by the scripts that run again
  • every Event.on and net.on handler is dropped and re-registered
  • anything a script kept in a local - a cached list, a counter - starts over
  • load fires again, and ingame right after it if you are already in the world

So a window that shows itself from ingame reopens on its own, and because opening is a request, the server sees a fresh open and answers with fresh state. Nothing special is needed to get the data back.

The console reports each pass, and a script with a syntax error says so there rather than reloading silently.

F9 is the client only. The GameServer's Lua reloads through its own console command; a client reload never touches the server half of a window.

The libraries in UI\ are not auto-loaded - they arrive through require:

local ui  = require("UI")
local R   = require("Registry")
local net = require("Net")
local P   = require("Protocol")

require follows the same rule as the window scan: it loads the encrypted .usc of a library whenever one is present, and falls back to a plain .lua only in dev mode. On a live server a library is loaded from its .usc and never from source, so the UI\ libraries ship encrypted just like the window scripts do.

Bind them to lowercase locals. UI and Net are global tables the client already provides, and a local with the same name would hide them.

Server

Everything lives under Data\Plugins\LuaAPI.

File What it is
Includes\UIWindow.lua Holds what each window registered and routes calls to it.
Includes\UIPacket.lua Reader and writer for payloads - the server's half of the wire format.
Includes\Net.lua The same, for the general (non-window) channel.
Defines\UIProtocol.lua Mirror of the client's Protocol.lua, plus the window ids.
CallbacksUI.lua The entry points the server calls. You do not normally touch it.
Windows\*.lua One file per window - the server half of what you wrote on the client.

How server scripts get loaded

Unlike the client, the server scans nothing. It loads Main.lua, and everything else is pulled in from there:

LoadScript(BASE .. "Windows\\CoinExchange.lua")

Forget that line and the window will open but never answer - the handlers were never registered. It is the single most common mistake when adding a window.

Which file gets your code

You want to Edit
add a window a new file in client UI\Windows\ + a new file in server Windows\ + one LoadScript line
name a new window id or texture client Registry.lua
add actions or result codes client Protocol.lua and server Defines\UIProtocol.lua
change how a window looks only its own client script

The libraries (UI.lua, Net.lua, UIWindow.lua, UIPacket.lua) are shared by every window - patching them to suit one window is how the next update overwrites your work.

See Also

Clone this wiki locally