Files
fparkan/docs/specs/fxid.md

3.3 KiB
Raw Blame History

FXID

Документ описывает контейнер ресурса эффекта и формат команд эффекта.


3.2. Контейнер ресурса эффекта

Эффекты в игровых архивах хранятся как NResentries типа:

  • 0x44495846 ("FXID").

Парсер эффекта находится в Effect.dll!sub_10007650.

3.3. Формат payload эффекта

3.3.1. Header (первые 60 байт)

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 создаётся объект конкретного типа:

  • op1off_1001E78C
  • op2off_1001F048
  • op3off_1001E770
  • op4off_1001E754
  • op5off_1001E360
  • op6off_1001E738
  • op7off_1001E228
  • op8off_1001E71C
  • op9off_1001E700
  • op10off_1001E24C

flags10 & 0x400 включает глобальный runtime-флаг менеджера эффекта (manager+0xA0).

3.5. Алгоритм загрузки эффекта (1:1)

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 в этом наборе не встретился, но поддерживается парсером.