Формат файлов .def

Типы полей, вложенные структуры, ссылки, массивы и версии описаний пакетов TERA.

Что описывает .def

Файл определения связывает последовательность байтов пакета с именованными полями объекта JavaScript. Карта протокола связывает имя пакета с числовым opcode; .def описывает его структуру. Это разные данные: правильный opcode не гарантирует правильную версию структуры.

Имя имеет вид S_EXAMPLE.1.def: имя сообщения, номер определения, расширение. При изменении структуры выпускают новую версию, сохраняя необходимые старые. Версия определения не равна версии патча игры. Исходная спецификация публикуется в репозитории tera-data.

Синтаксис

Строка состоит из типа и имени поля. Комментарий начинается с #. Каждый дефис увеличивает глубину вложения на один уровень. Пробелы служат для выравнивания, но сами по себе не задают вложенность.

uint32 sequence
object position
- vec3 loc
- angle w
array entries
- uint32 id
- string label

Этот учебный пример дает event.sequence, event.position.loc, event.position.w и массив event.entries с объектами { id, label }. object группирует поля в JavaScript и не добавляет отдельного бинарного заголовка. Не создавайте определение реального пакета по этому примеру без проверки его байтов.

Типы полей

Тип Представление
bool Логическое значение, один байт
byte Беззнаковое 8-битное число
int16, int32 Знаковые целые Number
uint16, uint32 Беззнаковые целые Number
int64, uint64 64-битные целые BigInt
float, double Числа с плавающей точкой 32/64 бит
angle Угол: 16-битное представление в пакете, радианы в JavaScript
vec3 Три float-координаты; объект Vec3
vec3fa Три компоненты углового представления, преобразуемые в радианы
skillid, skillid32 Упакованный идентификатор навыка с разобранными свойствами
customize Упакованные параметры внешности
string Строка UTF-16LE с нулевым терминатором
bytes Буфер байтов переменной длины
array Массив объектов с вложенными полями
array<type> Массив значений указанного простого типа
object Логическая группировка вложенных полей

skillid занимает 64 бита в новых структурах, skillid32 — 32 бита в старых. Выбор зависит от структуры пакета. Объект навыка содержит id, type, npc, huntingZoneId, reserved, а также equals, clone, toString. Не заменяйте его полным числом без учета упаковки. Для 64-битных ID используйте литералы 0n, а не 0, когда операция требует BigInt.

Заголовок и порядок байтов

Для обычного пакета первые четыре байта — uint16 общей длины (включая заголовок) и uint16 opcode. Определение не перечисляет их. Числовые поля кодируются little-endian. Специальные особенности транспорта и проверки целостности обрабатывает сетевая часть; .def описывает структуру, с которой работает парсер.

Ссылки на переменные данные

Строки, массивы и байтовые блоки требуют метаданных. По умолчанию парсер автоматически размещает ссылки перед обычными полями соответствующего уровня:

Поле Метаданные
array uint16 количества элементов, затем uint16 смещения
bytes uint16 смещения, затем uint16 длины
string uint16 смещения

Смещения считаются от начала пакета, включая заголовок. Значения смещений и количества вычисляет сериализатор; их не нужно вручную добавлять в объект event.

Явный ref

Если ссылки в реальном пакете находятся в другом месте, укажите ref fieldName в нужной позиции. Наличие явных ссылок отключает автоматический режим для определения: укажите их для всех строк, массивов и bytes. Для вложенного object путь ссылки может быть составным, например position.name.

uint32 sequence
ref entries
array entries
- uint32 id

Здесь счетчик и смещение массива идут после sequence. Без ref они были бы размещены перед ним. Не смешивайте случайным образом явные и неявные ссылки. Старые count/offset распознаются как устаревший формат совместимости; для новых определений используйте ref.

Устройство массива

Каждый элемент обычного массива начинается с двух скрытых uint16: собственное смещение (here) и смещение следующего элемента (next). У последнего next равен нулю. После них идут поля элемента. Вложенные массивы и строки имеют свои ссылки. Таким образом, массив в протоколе — цепочка элементов, а не обязательно сплошной блок одинаковых записей.

# Logical definition
uint32 sequence
array entries
- uint16 value

# Layout: header, entries count/offset, sequence,
# then array nodes: here, next, value

Проверка определения

Проверьте длину пакета, порядок полей, глубину дефисов и расположение всех ссылок. Сравните разбор и повторную сериализацию на известных пакетах нужного сервера. Ошибка типа или версии сдвигает последующие поля и приводит к некорректным значениям. Учтите, что парсер может лишь записать предупреждение для некоторых неверных строк: отсутствие исключения еще не доказывает правильность структуры.

Проверено по node_modules/tera-data-parser/lib/parsers/def.js, lib/protocol/compiler.js и типам парсера; описание формата сверено с README tera-data. Эта статья написана для текущего парсера Toolbox.