Way-файлы: различия между версиями

Материал из RnR Wiki
Перейти к навигации Перейти к поиску
м
 
(не показана 1 промежуточная версия этого же участника)
Строка 13: Строка 13:
 
и размер полезной нагрузки в байтах:
 
и размер полезной нагрузки в байтах:
  
<syntaxhighlight lang="c">
+
<pre>
 
struct ChunkHeader {
 
struct ChunkHeader {
 
     char    tag[4];
 
     char    tag[4];
 
     uint32_t size; // little-endian
 
     uint32_t size; // little-endian
 
};
 
};
</syntaxhighlight>
+
</pre>
  
 
После полезной нагрузки добавляются нулевые байты до границы 4 байт. Размер
 
После полезной нагрузки добавляются нулевые байты до границы 4 байт. Размер
 
чанка в заголовке не включает ни сам заголовок, ни это выравнивание.
 
чанка в заголовке не включает ни сам заголовок, ни это выравнивание.
  
<syntaxhighlight lang="text">
+
<pre>
 
padding = (4 - (size mod 4)) mod 4
 
padding = (4 - (size mod 4)) mod 4
</syntaxhighlight>
+
</pre>
  
 
Все числа записываются в порядке байтов ''little-endian''.
 
Все числа записываются в порядке байтов ''little-endian''.
Строка 31: Строка 31:
 
Подтверждённое дерево чанков имеет следующий вид:
 
Подтверждённое дерево чанков имеет следующий вид:
  
<syntaxhighlight lang="text">
+
<pre>
 
WTWR
 
WTWR
 
├── MNAM
 
├── MNAM
Строка 39: Строка 39:
 
         ├── RNOD × N
 
         ├── RNOD × N
 
         └── RSEG × N
 
         └── RSEG × N
</syntaxhighlight>
+
</pre>
  
 
{| class="wikitable"
 
{| class="wikitable"
Строка 66: Строка 66:
 
Контейнер <code>RNOD</code> состоит из трёх обязательных чанков:
 
Контейнер <code>RNOD</code> состоит из трёх обязательных чанков:
  
<syntaxhighlight lang="text">
+
<pre>
 
RNOD
 
RNOD
 
├── NNAM
 
├── NNAM
 
├── POSN
 
├── POSN
 
└── FLAG
 
└── FLAG
</syntaxhighlight>
+
</pre>
  
 
{| class="wikitable"
 
{| class="wikitable"
Строка 92: Строка 92:
 
обязательных чанков:
 
обязательных чанков:
  
<syntaxhighlight lang="text">
+
<pre>
 
RSEG
 
RSEG
 
├── ATTR
 
├── ATTR
 
├── WDTH
 
├── WDTH
 
└── VDAT
 
└── VDAT
</syntaxhighlight>
+
</pre>
  
 
=== ATTR ===
 
=== ATTR ===
Строка 103: Строка 103:
 
<code>ATTR</code> всегда имеет размер 16 байт:
 
<code>ATTR</code> всегда имеет размер 16 байт:
  
<syntaxhighlight lang="c">
+
<pre>
 
struct SegmentAttributes {
 
struct SegmentAttributes {
 
     uint32_t attr_a;
 
     uint32_t attr_a;
Строка 109: Строка 109:
 
     uint32_t attr_b;
 
     uint32_t attr_b;
 
}; // последовательная упаковка: <IdI
 
}; // последовательная упаковка: <IdI
</syntaxhighlight>
+
</pre>
  
 
В исследованных файлах встречаются <code>attr_a</code> со значениями 1, 2, 6,
 
В исследованных файлах встречаются <code>attr_a</code> со значениями 1, 2, 6,
Строка 123: Строка 123:
 
<code>WDTH</code> имеет размер 16 байт:
 
<code>WDTH</code> имеет размер 16 байт:
  
<syntaxhighlight lang="c">
+
<pre>
 
struct SegmentWidth {
 
struct SegmentWidth {
 
     double width_left;
 
     double width_left;
 
     double width_right;
 
     double width_right;
 
};
 
};
</syntaxhighlight>
+
</pre>
  
 
Обычно оба значения одинаковы: например, <code>3.0 / 3.0</code>,
 
Обычно оба значения одинаковы: например, <code>3.0 / 3.0</code>,
Строка 139: Строка 139:
 
<code>VDAT</code> содержит вершины полилинии:
 
<code>VDAT</code> содержит вершины полилинии:
  
<syntaxhighlight lang="c">
+
<pre>
 
struct VertexData {
 
struct VertexData {
 
     uint32_t count;
 
     uint32_t count;
 
     struct { double x, y, z; } points[count];
 
     struct { double x, y, z; } points[count];
 
};
 
};
</syntaxhighlight>
+
</pre>
  
 
Размер полезной нагрузки должен соответствовать формуле:
 
Размер полезной нагрузки должен соответствовать формуле:
  
<syntaxhighlight lang="text">
+
<pre>
 
VDAT.size = 4 + count × 24
 
VDAT.size = 4 + count × 24
</syntaxhighlight>
+
</pre>
  
 
Начальная и конечная вершины часто совпадают с концами других сегментов и тем
 
Начальная и конечная вершины часто совпадают с концами других сегментов и тем
Строка 160: Строка 160:
 
Координаты точек и узлов хранятся как три <code>float64</code>:
 
Координаты точек и узлов хранятся как три <code>float64</code>:
  
<syntaxhighlight lang="text">
+
<pre>
 
X, Y, Z
 
X, Y, Z
</syntaxhighlight>
+
</pre>
  
 
Для двумерного отображения обычно используются <code>X</code> и
 
Для двумерного отображения обычно используются <code>X</code> и
Строка 187: Строка 187:
 
Требуют дальнейшего исследования:
 
Требуют дальнейшего исследования:
  
* точная игровая роль полей <code>attr_a</code>, <code>attr_value</code> и
+
* точная игровая роль полей <code>attr_a</code>, <code>attr_value</code> и <code>attr_b</code>;
  <code>attr_b</code>;
 
 
* значение <code>FLAG</code> у разных видов RNOD;
 
* значение <code>FLAG</code> у разных видов RNOD;
 
* направление движения по массиву точек;
 
* направление движения по массиву точек;

Текущая версия на 12:32, 19 июля 2026

WAY-файлы — бинарные файлы дорожной и маршрутной сети в игре Дальнобойщики 2 / Hard Truck 2: King of the Road. Обычно находятся в папке ENV и имеют имена, соответствующие участкам карты: например, aa.way, ab.way или da.way.

Файл хранит геометрию маршрутов в трёхмерных координатах, ширину сегментов, служебные узлы и набор атрибутов. Точная игровая семантика части атрибутов пока не установлена; ниже описана подтверждённая бинарная структура.

Общая структура

Файл состоит из вложенных чанков. Каждый чанк имеет четырёхсимвольный ASCII-тег и размер полезной нагрузки в байтах:

struct ChunkHeader {
    char     tag[4];
    uint32_t size; // little-endian
};

После полезной нагрузки добавляются нулевые байты до границы 4 байт. Размер чанка в заголовке не включает ни сам заголовок, ни это выравнивание.

padding = (4 - (size mod 4)) mod 4

Все числа записываются в порядке байтов little-endian.

Подтверждённое дерево чанков имеет следующий вид:

WTWR
├── MNAM
└── GDAT
    └── GROM × N
        ├── RNAM
        ├── RNOD × N
        └── RSEG × N
Чанк Назначение Тип
WTWR Корневой контейнер файла контейнер
MNAM Короткое имя карты, например aa строка с NUL в конце
GDAT Данные дорожного графа контейнер
GROM Дорожная комната/группа сегментов контейнер
RNAM Имя комнаты строка с NUL в конце
RNOD Именованный служебный узел контейнер
RSEG Сегмент маршрута контейнер

Строки в исследованных файлах совместимы с ASCII и Windows-1251; при чтении строка заканчивается на первом байте 00.

Узлы RNOD

Контейнер RNOD состоит из трёх обязательных чанков:

RNOD
├── NNAM
├── POSN
└── FLAG
Чанк Размер Содержимое
NNAM переменный имя узла или служебной позиции
POSN 24 байта double x, double y, double z
FLAG 4 байта uint32 flag

Примеры имён: node_store_1000, pos_hidden_0100, STO_AA. Встречаются значения FLAG 0 и 1, но их точное значение для игровой логики не подтверждено.

Сегменты RSEG

Контейнер RSEG описывает одну полилинию и состоит из трёх обязательных чанков:

RSEG
├── ATTR
├── WDTH
└── VDAT

ATTR

ATTR всегда имеет размер 16 байт:

struct SegmentAttributes {
    uint32_t attr_a;
    double   attr_value;
    uint32_t attr_b;
}; // последовательная упаковка: <IdI

В исследованных файлах встречаются attr_a со значениями 1, 2, 6, 22, 34, 53, 57, 97 и 98; attr_b — 1, 2 и 3. Это наблюдаемые значения, а не расшифрованные типы дороги.

В частности, attr_a = 98 нельзя однозначно считать тупиком: в разных картах он встречается как на коротких соединителях, так и на длинных цепочках. Автоматически менять этот атрибут без проверки в игре небезопасно.

WDTH

WDTH имеет размер 16 байт:

struct SegmentWidth {
    double width_left;
    double width_right;
};

Обычно оба значения одинаковы: например, 3.0 / 3.0, 4.0 / 4.0 или 8.0 / 8.0. Вероятнее всего, это ширина слева и справа от осевой линии сегмента, однако это ещё не подтверждено исходным кодом игры.

VDAT

VDAT содержит вершины полилинии:

struct VertexData {
    uint32_t count;
    struct { double x, y, z; } points[count];
};

Размер полезной нагрузки должен соответствовать формуле:

VDAT.size = 4 + count × 24

Начальная и конечная вершины часто совпадают с концами других сегментов и тем самым задают геометрические связи маршрута. Удаление или перенос этих точек может разорвать дорожную сеть.

Координаты

Координаты точек и узлов хранятся как три float64:

X, Y, Z

Для двумерного отображения обычно используются X и -Y, поскольку в SVG и на экране ось Y направлена вниз. Координата Z соответствует высоте.

Безопасное редактирование

При записи WAY-файла необходимо:

  1. сохранять порядок чанков и неизвестные чанки без изменений;
  2. пересчитывать размеры изменённых чанков и их контейнеров;
  3. сохранять выравнивание до 4 байт;
  4. записывать числа в little-endian;
  5. завершать строки нулевым байтом;
  6. создавать резервную копию исходного файла;
  7. после записи повторно разобрать файл и проверить структуру.

Для файла без изменений корректный сериализатор должен давать побайтно тот же результат, что и исходный файл.

Неизвестные части формата

Требуют дальнейшего исследования:

  • точная игровая роль полей attr_a, attr_value и attr_b;
  • значение FLAG у разных видов RNOD;
  • направление движения по массиву точек;
  • односторонность, полосы движения и скрытые ссылки между сегментами;
  • безопасное добавление и удаление RSEG без изменения других ресурсов игры.

Утилиты

Для просмотра и аккуратного редактирования формата существует HT2 WAY Tool. Утилита поддерживает просмотр структуры, экспорт JSON/SVG/CSV, резервные копии и проверку сегментов с attr_a = 98.