The Metin2 client's interface is written entirely in Python, and if you want to shape those windows around your own server, the place to start is the metin2 root python files. You don't need to touch the engine to move the inventory, enlarge the chat window or add a new button — you just need to find the right .py file and make a sensible edit. In this article I'll walk you through how the root package works, how to open and edit the files, and how to test your changes in the client.
The root package and the UI architecture
The client assembles its interface from three separate parts, and without understanding that split you'll get lost in the pile of files:
- root — The actual Python logic lives here.
ui.pydefines the UI framework (classes such as Window, Board, Button, TextLine), while files likeuiInventory.py,uiCharacter.py,uiChat.pyandinterfaceModule.pycontrol how each window behaves. - uiscript — This is where the layout of the windows is kept. Files like
inventorywindow.pyaren't HTML; they describe geometry as a Python dictionary: coordinates, width, height and child elements. - locale — Texts and language-dependent settings (
locale_string.txtand some labels used inuiscript) live here.
So how a window looks is largely defined in uiscript, while how it behaves lives in root. For most visual tweaks, touching uiscript alone is enough.
Unpacking the files and setting up an editing environment
The client stores these files in encrypted packages: root.epk / root.eix and uiscript.epk / uiscript.eix. To edit them, you first have to unpack:
- Use a tool like EterNexus to unpack and repack. When you open the
.eixfile you can extract the folder structure inside. - The files usually ship as compiled
.pyc. If you don't have the source.py, you'll need a Python 2 decompiler (for exampleuncompyle2) to turn them back. Since the client is built on Python 2.2, modern Python 3 tools often won't work. - Many private servers configure the client to read from loose folders instead of packages for easier development. If that's available, you can edit the root and uiscript folders directly and skip the repacking step.
Any editor with syntax highlighting (VS Code, Notepad++) will do. Save the files in the encoding the client expects, and avoid mixing tabs and spaces in your indentation — Python is indentation-sensitive.
Changing a window's layout with uiscript
The most common task is moving or resizing a window. The uiscript/inventorywindow.py file has roughly this structure:
window = {
"name" : "InventoryWindow",
"x" : SCREEN_WIDTH - 176,
"y" : SCREEN_HEIGHT - 37 - 565,
"style" : ("movable", "float",),
"width" : 176,
"height" : 565,
"children" : (
{
"name" : "board",
"type" : "board",
"x" : 0,
"y" : 0,
"width" : 176,
"height" : 565,
"children" : (
# title, tabs, slots...
),
},
),
}
To shift the window left, change the "x" value; to make it wider, change "width". Remember: if you grow the outer window's width, you must also adjust the inner board element's width to match, otherwise the background graphic overflows. The SCREEN_WIDTH and SCREEN_HEIGHT constants let you anchor the window to a screen corner; using them instead of fixed numbers keeps things correct across different resolutions.
Editing the logic inside root
When layout isn't enough, you change behaviour on the root side. For example, uiInventory.py loads the layout file like this:
import ui
import uiScriptLocale
class InventoryWindow(ui.ScriptWindow):
def __LoadWindow(self):
pyScrLoader = ui.PythonScriptLoader()
pyScrLoader.LoadScriptFile(self, "uiscript/inventorywindow.py")
self.wndItem = self.GetChild("ItemSlot")
# ... references to elements
The name in the GetChild call must match the "name" field in the uiscript file exactly. If you've added a new button, you first define it in uiscript, then grab it on the root side with GetChild("NewButton") and bind it to a function via SetEvent. If the names don't match, the client returns None and usually crashes with a 'NoneType' object has no attribute ... error.
Touching ui.py is an advanced move: since every window shares this framework, a single mistake here affects the entire interface. Unless you genuinely need a new component type, leave ui.py as it is.
Repacking, caching and debugging
When you've finished editing, repack the files (or, in loose-folder mode, just save) and restart the client. A few practical notes:
- The client may cache old packages; to be safe, update both the
.epkand.eixfiles together. - If something doesn't work, the first place to look is the
syserr.txtfile in the client folder. Python exceptions, along with the offending line number, are written there. - Common errors: indentation mismatch (
IndentationError), an unclosed bracket, or a missing comma in a uiscript dict. In Python dictionaries, don't forget the trailing comma after each element.
Common mistakes and tips
- Back up the original. Before you start editing, copy the root and uiscript packages so rolling back takes seconds, not minutes.
- Make one change at a time. Don't edit ten files and then test; hunting for the bug becomes torture.
- Name consistency is everything. The
"name"in uiscript and theGetChildin root must be written identically; even case matters. - Think about resolution. Use
SCREEN_WIDTH/SCREEN_HEIGHTinstead of fixed coordinates so the window stays in place on wide screens too.
Frequently Asked Questions
The root files come as .pyc — how do I get the source?
Many files are distributed as compiled .pyc. A Python 2 decompiler (such as uncompyle2) can turn them into readable .py. Some community releases already share clean source; if possible, work with the source directly rather than decompiling.
I only want to move a window — do I have to touch root?
No. Position, size and child layout are entirely on the uiscript side. As long as you're not changing button behaviour, binding events or adding new logic, you never have to open the root files.
My change doesn't show up in the client — why?
Usually either the package wasn't updated (refresh the .eix/.epk pair together) or there's a Python error. Check syserr.txt first; you'll often find the problem there with the exact line number.
Want to redesign the interface around your own server from the ground up? If you need help with Metin2 client customization, root editing or bespoke UI design, get in touch with me — let's bring your project to life together.