Как пользоваться памяткой#

Сначала определите язык. Одинаковое намерение записывается по-разному в XPath, MD и Lua. Таблицы ниже — выбранные конструкции, нужные для чтения примеров этой вики и исходников проекта. Это не статистический рейтинг всех файлов X4 и не полный справочник.

Если термины пока незнакомы, начните со статьи как работает код X4. Все новые фрагменты здесь учебные; запуск в игровом мире для них не заявлен.

Четыре базовых понятия#

Переменная хранит значение: например, число товаров. Условие отвечает, выполнять ли действие. Функция принимает аргументы и выполняет работу; иногда возвращает результат. Обработчик события — функция или узел MD, который вызывается при определённом событии.

Различайте объявление, вызов и результат. В Lua local function getName() ... end объявляет функцию, getName() вызывает её, а local name = getName() сохраняет ответ.

XML: элементы, атрибуты и селекторы#

Запись Значение
<hull max="1800" /> Элемент с атрибутом; у него нет вложенного содержимого
<actions> ... </actions> Начало и конец контейнера
<!-- пояснение --> Комментарий XML
<replace sel="...">...</replace> Заменить выбранный узел или атрибут diff-патчем
<add sel="...">...</add> Добавить содержимое в выбранное место по правилам diff
<remove sel="..." /> Удалить выбранное
/properties/hull/@max Путь к атрибуту в XPath
[@name='имя'] Фильтр элемента по атрибуту в XPath

Символ & внутри атрибута XML записывают как &amp;, < — как &lt;. Это правила XML, ещё до разбора выражения MD. Поэтому в условиях удобно читать lt, le, gt, ge. Селектор diff и значение do_if имеют разные грамматики.

MD: небольшое действие за действием#

Конструкция Для чего применяется
set_value Создать или изменить значение
do_if, do_elseif, do_else Выбрать ветвь действий
do_for_each Обработать элементы списка
append_to_list Добавить элемент в список
remove_value Удалить переменную или запись
debug_text Вывести диагностику
run_actions ref="..." Выполнить подходящую библиотеку действий
event_ui_triggered Условие приёма UI-события
raise_lua_event Отправить событие в Lua

Это имена элементов MD, а не стандартные функции XML. Их атрибуты и допустимый контекст определяет движок. Например, run_actions требует соответствующую library, а event_ui_triggered находится в условиях cue.

Учебный фрагмент для actions, где $Items создаётся здесь же:

XML
<set_value name="$Items" exact="['Корпус', 'Двигатель']" />
<set_value name="$Count" exact="0" />
<do_for_each name="$Item" in="$Items">
  <set_value name="$Count" operation="add" exact="1" />
</do_for_each>
<do_if value="$Count == 2">
  <debug_text text="'Обработано два элемента'" />
</do_if>

После цикла $Count равен 2. operation="add" exact="1" означает прибавить единицу. Имя $Item обозначает текущий элемент; здесь его содержимое не используется.

Выражения MD#

Запись Как прочитать
$Count Значение переменной
Init.$States Переменная в явно указанном cue
$Count == 2, $Count != 2 Равно / не равно
lt, le, gt, ge Меньше / не больше / больше / не меньше
and, or, not И / или / отрицание
+, -, *, /, % Арифметические действия; % — остаток
'Имя: ' + $Label Соединить строки
$Value? Проверить, разрешается ли переменная или свойство
$Object.exists Проверить существование игрового объекта
typeof $D == datatype.list Проверить тип значения
$D.{1}, $D.count Первый элемент списка / количество элементов
table[], [] Пустая таблица / пустой список
if $Ready then 'да' else 'нет' Выражение, выбирающее одно значение

MD-списки в показанных примерах начинаются с 1. $Value? не означает «значение истинно»: существующая переменная может содержать false. Существование переменной и существование объекта — разные проверки. Контекст переменных особенно важен в экземплярах cue; подробности — в отдельной статье.

Lua: чтение обычной функции#

LUA
local function total(items)
    if type(items) ~= "table" then
        return 0
    end
    local result = 0
    for _, item in ipairs(items) do
        result = result + item.amount
    end
    return result
end

local amount = total({{amount = 3}, {amount = 5}})

Это самостоятельный пример языка без функций X4. amount получается равным 8. У каждого элемента предполагается числовое поле amount.

{} создаёт таблицу. В Lua таблицы используются и как списки, и как записи с именованными полями. item.amount равно item["amount"]. В for _, item первая переменная получает индекс; _ — обычное имя, которым автор показывает «это значение мне не нужно».

Операторы Lua#

Запись Значение Пример
= Присваивание count = 3
==, ~= Равенство / неравенство role ~= "host"
<, <=, >, >= Сравнения count >= 1
and, or, not Логические операции ready and loaded
+, -, *, /, % Арифметика count % 2 == 0
.. Соединение строк "Имя: " .. name
#value Длина строки или граница последовательности #items
object.field Доступ к полю таблицы state.active
object:method(x) Вызов с передачей object первым аргументом Эквивалент object.method(object, x)

Не полагайтесь на #table как на число произвольных ключей: таблица с пропусками или строковыми ключами не является плотным списком. Длина строки считается в байтах, что важно для UTF-8.

В Lua ложными считаются false и nil; 0 и пустая строка истинны. Выражение value or fallback выбирает запасной вариант также при value == false. and/or возвращают выбранное значение, а не обязательно true или false. Точная основа языка — Lua 5.1; расширения LuaJIT сверяются с его документацией.

Стандартные функции Lua#

Вызов Назначение и пример
type(value) Узнать тип: type("Север") даёт "string"
tostring(value) Получить текстовое представление
tonumber(text) Попробовать прочитать число; ошибка формата даёт nil
ipairs(list) Последовательные числовые элементы с 1, до первого отсутствующего
pairs(table) Перебрать ключи и значения без гарантии порядка
table.insert(list, value) Добавить элемент списка
table.remove(list, index) Удалить элемент с уплотнением списка
table.concat(list, "|") Соединить последовательность подходящих значений разделителем
string.format("%s: %d", name, count) Собрать строку по шаблону
text:match(pattern) Найти совпадение с шаблоном Lua
text:gsub(pattern, replacement) Заменить совпадения
math.min(a, b), math.max(a, b) Выбрать меньшее / большее
pcall(fn, arg) Вызвать функцию с перехватом ошибки Lua
require("module") Загрузить модуль по правилам среды

Не каждый стандартный модуль обязательно доступен в игровом окружении. Например, наличие debug или файловых операций нельзя выводить из одного знакомства с обычной Lua. pcall возвращает флаг и ответ/ошибку; проглоченная ошибка может скрыть проблему. Неверный нативный вызов не становится безопасным из-за pcall.

Функции X4 и собственные функции мода#

Имя Откуда оно Что читать в нашем примере
GetComponentData(component, "name") Lua API X4 Чтение имени уже разрешённого объекта
IsValidComponent(component) Lua API X4 Проверка пригодности компонента в текущем контексте
GetCurRealTime() Lua API X4 Часы для интервалов обработки; не календарь симуляции
AddUITriggeredEvent(...) Lua API X4 Отправка события в MD
RegisterEvent(...) Lua API X4 Регистрация обработчика события
Helper.getMenu("MapMenu") Средства UI X4 Поиск зарегистрированного меню; готовность нужно проверить
ffi.cdef, ffi.string Библиотека FFI LuaJIT Описание C-типов / преобразование подходящей C-строки
app.requestObjectRename(...) Собственный Lua-код X4FO Поиск определения в проекте, не в справочнике X4
ObjectNameAuthority.request(...) Собственный Python-код X4FO Серверная обработка запроса

Последние два имени приведены только для различения происхождения API. Они не доступны в обычном одиночном моде без кода соответствующего проекта.

ID объекта нужно получить заранее в нужной форме. Не подставляйте в GetComponentData случайное число или имя корабля. Строковый сетевой ID, UI handle и 64-битный UniverseID нельзя свободно менять местами: подробнее о типах ID.

Пять ошибок, которые легко заметить при чтении#

  1. В Lua неравенство пишется ~=, в MD — !=.
  2. Соединение строк в Lua — .., в MD встречается +.
  3. = в Lua присваивает значение; сравнение записывается ==.
  4. Изменение текста собственного окна ещё не означает изменение объекта мира.
  5. Объявить обработчик недостаточно: файл должен загрузиться, событие — прийти, вход — пройти проверки.

Для практики прочитайте обмен Lua ↔ MD и попробуйте своими словами объяснить каждую строку до установки примера в тестовый профиль.