Files
fparkan/docs/specs/fxid.md

113 lines
3.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FXID
Документ описывает контейнер ресурса эффекта и формат команд эффекта.
---
## 3.2. Контейнер ресурса эффекта
Эффекты в игровых архивах хранятся как NResentries типа:
- `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` в этом наборе не встретился, но поддерживается парсером.
---