Start with one idea#
A mod supplies instructions and data that X4 reads at the appropriate time. It does not need one main file through which every event passes. Ship data loads as resources, MD waits for conditions, AI runs behavior, and Lua handles UI.
The engine is the executable part of the game: it creates objects, calculates movement, stores the world and performs operations exposed to scripts. Its full source is not in a mod folder. An extension uses supported formats and APIs. An API is a set of available ways to interact with a system, such as reading an object's name or sending an event.
This guide covers regular modding. New examples are explanatory and were not separately executed in game. Original Elite values were checked against the installed X4 9.00 files.
Why several languages are involved#
Different jobs need different representations. A hull value is conveniently stored as data; an event reaction needs a handler; a button needs a widget and a click function.
| Layer | Typical location | Job |
|---|---|---|
| XML data | assets/, libraries/, t/ |
Properties, wares and translated text |
| XML diff | Matching target resource path | Change selected parts of a document |
| Mission Director | md/*.xml |
React to events and perform world logic |
| AI scripts | aiscripts/*.xml |
Actor behavior and orders |
| Lua UI | ui/*.lua, registered in ui.xml |
Windows, tables and input |
| Native code | Engine or a mod's DLL | Lower-level integration |
MD and AI use XML but have their own elements and execution rules. Inspect the root element and directory rather than judging by the extension alone. Python or C# may appear in tools and complex projects; that does not make them built-in MD languages. A first XML patch needs only its manifest and diff.
What happens when an extension loads#
The original diagram below summarizes responsibilities rather than promising an exact universal load order. X4 version, DLC, dependencies, other mods and saved state all affect the result. content.xml identifies the extension and its version/dependencies. ui.xml lists Lua files for a UI environment. Manifest version fields have a defined numeric format; do not substitute an arbitrary human version string such as 0.1.0.
extensions/имя_мода/content.xml
→ игра узнаёт расширение и его зависимости
→ получает ресурсы с учётом расширений и патчей
→ загружает подходящие скрипты и UI
→ события и callbacks вызывают обработчики
→ движок меняет состояние мираExample 1: XML stores a property#
In the shortened macro illustration below, hull is an element, max is an attribute and 1800 is its value. XML itself does not run a loop; the engine interprets that field in the resource context. A separate diff changes the selected attribute.
Read the selector as: enter /macros/macro, retain the macro with the specified name, enter /properties/hull, then select /@max. This is XPath over a document, not an MD condition or a search for a live ship. A resource change still needs testing on existing saved objects. See the complete first patch.
<properties>
<hull max="1800" />
</properties><diff>
<replace sel="/macros/macro[@name='ship_arg_s_fighter_02_a_macro']/properties/hull/@max">3600</replace>
</diff>Example 2: MD performs actions#
The first fragment assigns 3 to $Count, tests whether it is greater than zero and prints a diagnostic. It belongs inside a suitable cue's actions; it is not a standalone extension. XML outer quotes delimit an attribute; inside exact, the number 3 differs from a quoted string.
A full MD script has mdscript, cues, cue conditions and actions. A cue is a logic node with state: it can wait, activate and complete. Think of event-driven handlers rather than an entire file continuously rerun from the top. instantiate=true namespace=this lets repeated events have instances with their own variable contexts. Read cues, variables and the linked primary documentation for the actual game version.
<set_value name="$Count" exact="3" />
<do_if value="$Count gt 0">
<debug_text text="'Есть элементы для обработки'" />
</do_if><set_value name="$Count" exact="3" />
<set_value name="$Label" exact="'Три'" />Example 3: Lua is called by the UI#
The plain Lua example below does not use game APIs. local creates a local name, function defines a function, its argument receives input, return produces a result, and .. joins strings. The original sample messages retain their original language.
A function assigned to a button is called later by the UI; this is a callback. Assigning a function and calling it immediately are different operations. The examples illustrate that distinction without inventing a button API.
local function makeLabel(name)
if type(name) ~= "string" or name == "" then
return "Без имени"
end
return "Корабль: " .. name
end
local label = makeLabel("Север")local callback = makeLabel -- сохранить саму функцию
local result = makeLabel("Север") -- вызвать и сохранить ответHow a window and the world communicate#
Lua has game-reading APIs and some engine operations; MD exposes a different set of actions and properties. Choose the layer based on the available operation and lifecycle. Not every world change must pass through MD.
A common exchange uses AddUITriggeredEvent to MD, then raise_lua_event to a RegisterEvent callback. These are X4 environment facilities: ordinary Lua does not provide them. MD set_value and raise_lua_event are XML elements, not Lua functions. See the paired example.
Lua: AddUITriggeredEvent(screen, control, payload)
→ MD: event_ui_triggered
→ данные запроса: event.param3
→ действия и чтение результата
→ MD: raise_lua_event
→ Lua: RegisterEvent(name, callback)Why editing a file may leave the old result#
A patch may target another macro or be overwritten by a compatibility conflict. Lua may be missing from ui.xml. A cue may already be completed in the save. An object reference may be stale after loading. A save restores world and MD state rather than simply restarting every source file. Some changes need initialization or migration.
Ask separately: did the file load, did the intended handler run, and did the actual object change and retain that change? A log marker for the handler does not prove the final effect. Check new games and relevant existing saves separately.
What to read next#
Continue with operators and common functions, then choose a property patch, an MD script or a window. Official Modding Support is linked among this article's sources.