Добавлены спецификации для сетевой подсистемы, системы звука, загрузки ландшафта, интерфейса пользователя и пайплайна выполнения. Обновлен файл навигации mkdocs.yml для включения новых документов.
This commit is contained in:
112
docs/specs/fxid.md
Normal file
112
docs/specs/fxid.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# 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` в этом наборе не встретился, но поддерживается парсером.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user