# FXID Документ описывает контейнер ресурса эффекта и формат команд эффекта. --- ## 3.2. Контейнер ресурса эффекта Эффекты в игровых архивах хранятся как NRes‑entries типа: - `0x44495846` (`"FXID"`). Парсер эффекта находится в `Effect.dll!sub_10007650`. ## 3.3. Формат payload эффекта ### 3.3.1. Header (первые 60 байт) ```c struct FxHeader60 { uint32_t cmdCount; // +0x00 uint32_t globalFlags; // +0x04 float durationSec; // +0x08 (дальше умножается на 1000.0) uint32_t unk0C; // +0x0C uint32_t flags10; // +0x10 (используются биты 0x40 и 0x400) uint8_t reserved[0x2C];// +0x14..+0x3B }; ``` Поток команд начинается строго с `offset 0x3C`. ### 3.3.2. Командный поток Каждая команда начинается с `uint32 cmdWord`, где: - `opcode = cmdWord & 0xFF`; - `enabled = (cmdWord >> 8) & 1` (копируется в `obj+4`). Размер команды зависит от opcode и прибавляется в **байтах** (`add edi, ...` в ASM): | Opcode | Размер записи | |--------|---------------| | 1 | 224 | | 2 | 148 | | 3 | 200 | | 4 | 204 | | 5 | 112 | | 6 | 4 | | 7 | 208 | | 8 | 248 | | 9 | 208 | | 10 | 208 | Никакого межкомандного выравнивания нет: следующая команда сразу после `size(opcode)`. ## 3.4. Runtime-классы команд (vtable mapping) В `sub_10007650` для каждого opcode создаётся объект конкретного типа: - `op1` → `off_1001E78C` - `op2` → `off_1001F048` - `op3` → `off_1001E770` - `op4` → `off_1001E754` - `op5` → `off_1001E360` - `op6` → `off_1001E738` - `op7` → `off_1001E228` - `op8` → `off_1001E71C` - `op9` → `off_1001E700` - `op10` → `off_1001E24C` `flags10 & 0x400` включает глобальный runtime-флаг менеджера эффекта (`manager+0xA0`). ## 3.5. Алгоритм загрузки эффекта (1:1) ```c read header60 ptr = data + 0x3C for i in 0..cmdCount-1: op = ptr[0] & 0xFF obj = new CommandClass(op) obj->enabled = (ptr[0] >> 8) & 1 obj->raw = ptr manager.attach(obj) ptr += sizeByOpcode(op) ``` Ошибка формата: - неизвестный opcode; - выход за пределы буфера до обработки `cmdCount`; - непустой «хвост» после `cmdCount` команд (для строгого валидатора). ## 3.6. Проверка на реальных данных Для `testdata/nres/effects.rlb` (923 entries): - `opcode` всегда в диапазоне `1..10`; - stream полностью покрывает payload без хвоста; - частоты opcode: - `1: 618` - `2: 517` - `3: 1545` - `4: 202` - `5: 31` - `7: 1161` - `8: 237` - `9: 266` - `10: 160` - `6` в этом наборе не встретился, но поддерживается парсером. ---