Vfx
- Source
docs/executable/effects.md- SHA-256
6f6fa036…e8904903
Summary · The files · Vfx IDs · indices.bin · EffectMaterialData.bin · Loading · Replacing a vfx · Functions · Leads
How the game picks, loads and plays a vfx (a visual effect, the game's effect/ files): which file a vfx ID opens, the two small files beside them (indices.bin and EffectMaterialData.bin), and what a modder has to keep when replacing one. The files themselves are EFX0011 in an MLZ0 wrapper, played by the vfx player of the game's Libra library. The work it serves is R7, media. "Effect" alone means an effect_data row; the game's folder effect/ and its EffectManager.cpp keep their names.
| Based on | The unpacked executable, SHA-256 7b0230a11498f40396c9048345e7cfe0ef442cb7ca8faffc6f197920d2669599; every file under effect/ (2,085 .efz, effect/global/common/indices.bin, effect/EffectMaterialData.bin); FileTable.bin (filetable.md); the decoded effect_data rows (data/game/battle/battle_data_release.dat/16.effect_data.jsonl). |
| Checked | 2026-10-11 |
| Method | Static analysis with Ghidra 12.1.4: the decompiled code in local/exe/decomp/ and the indexes exe.calls and exe.strings (The indexes); xxd of the executable. Single-file C# programs (session scratchpad, effect/scan.cs): a walk of FileTable.bin listing every file of group 200, and scans of every vfx file. DuckDB over the decoded effect_data rows. Facts from the code alone are at most likely. No in-game tests. |
Summary
- Every
effect/file is in group 200 of the file table, and the game opens it by file ID, never by name. - A vfx ID picks a file: IDs
0x000–0x260play a set of the sharedc_all.efz, found throughindices.bin; the higher IDs each open their own file, most of them in the player's language folder (Vfx IDs). - A caller also passes a variant number: which set (variant) of the vfx to play.
- A replaced vfx has to be a valid
MLZ0andEFX0011file with its exact size inFileTable.bin; it doesn't have to be byte-identical (Replacing a vfx).
The files
confirmed: group 200 has 10,135 file IDs (0–10,134), every effect/ path is in it and in no other group, and 2,087 of its files are in Data/ (the other 8,048 file records have size 0). Source: C# walk of FileTable.bin.
| File ID | File | What it is |
|---|---|---|
| 0 | effect/EffectMaterialData.bin |
Vfx material settings (EffectMaterialData.bin). |
| 1 | effect/global/common/indices.bin |
Vfx ID → set in c_all.efz (indices.bin). |
| 2 | effect/global/common/c_all.efz |
The shared vfx: 655 sets. |
| 3–67 | effect/global/magic/m0000.efz–m0064.efz |
Spell vfx; m0000–m0050 (IDs 3–53) are on disk. |
| 68–75 | effect/<lang>/results/r0001.efz |
The battle results screen, one per language. |
| 76–1,107 | effect/<lang>/event/e0000.efz–e0128.efz |
Event vfx; 21 per language on disk (e0000–e0018, e0100, e0101). |
| 1,108–1,659 | effect/<lang>/chr_make/cm*.efz |
Character creation; 68 per language on disk. |
| 1,660–1,795 | effect/<lang>/title/t0000.efz–t0016.efz |
Title; t0001 and t0002 on disk. |
| 1,796–10,123 | effect/<lang>/victory/v0000.efz–v1040.efz |
The victory/ vfx; 161 per language on disk (162 in ja-jp). |
| 10,124–10,134 | effect/global/chr_make_god/gcm0000.efz–gcm0010.efz |
Character creation (the gods); 8 on disk. |
- confirmed: the language folders interleave: a localized vfx's file ID is a base + 8 × its number + the language, with the languages in this order: 0
ja-jp, 1en-us, 2fr-fr, 3de-de, 4es-es, 5zh-cn, 6zh-tw, 7ko-kr. Source: C# walk ofFileTable.bin(e.g.results/r0001.efzis file 68 forja-jpto 75 forko-kr). - likely: the language added is the game's language setting (
0x14026CA60, the value at0x140CDE968), the same one the text loader uses (txte.md). Source:0x140311a40.
Vfx IDs
The game turns a vfx ID into a file ID with 0x140311a40 (likely, static analysis). lang is the language, 0–7.
| Vfx ID | File ID | File |
|---|---|---|
0x000–0x260 (0–608) |
2 | c_all.efz, set indices[id] + variant (indices.bin). |
0x261–0x2A1 (609–673) |
ID − 0x25E (3–67) |
global/magic/m<ID − 0x261>.efz. Higher IDs up to 0x313 follow the same rule and land on the language folders' files. |
0x314 (788) |
68 + lang | <lang>/results/r0001.efz. |
0x315–0x38D (789–909) |
76 + 8 × (ID − 0x315) + lang |
<lang>/event/e<ID − 0x315>.efz, e0000–e0120. |
0x38F–0x3D2 (911–978) |
1,108 + 8 × (ID − 0x38F) + lang |
<lang>/chr_make/: the (ID − 0x38F)th file, in file-ID order (cm0000_0000, cm0000_1000, cm0001_0001, …). |
0x3D4–0x3DD (980–989) |
ID + 0x23B8 (10,124–10,133) |
global/chr_make_god/gcm<ID − 0x3D4>.efz, the same for every language. |
0x3DF–0x3E2 (991–994) |
1,660 + 8 × (ID − 0x3DF) + lang |
<lang>/title/t<ID − 0x3DF>.efz, t0000–t0003. |
0x3E4 and up (996–) |
1,796 + 8 × (ID − 0x3E4) + lang |
<lang>/victory/v<ID − 0x3E4>.efz. |
0x38E, 0x3D3, 0x3DE, 0x3E3 |
ID − 0x25E |
Fall through to the magic rule, landing on one language's event files; probably never used. |
Who passes vfx IDs (likely, static analysis):
- Battle actions: an effect_data row's u16 at
0x84is the vfx ID and its byte at0x86the variant (vfx_id,vfx_variant), or the pair at0xAE/0xB0. Source:0x140336140,0x14044bc10,Taco::Application::VfxJob::vfunction5(0x14044bda0). confirmed: the rows use IDs 0–148 (inc_all.efz, variants up to 25) and 610–659 (m0001–m0050, variants up to 13). Source: DuckDB over16.effect_data.jsonl, both pairs. - Event scripts: native 240 plays a vfx ID as given, 242 plays ID +
0x261(m<n>.efz) and 244 plays ID +0x315(<lang>/event/e<n>.efz); 241, 243 and 245 add a variant (natives). - Others: the battle results (
ClearStageSequence::vfunction6,0x140371580, ID0x314), character creation (0x1404afcc0), and battle jobs such asPickupBuffCardSignalJob(0x1403b2070) call the same function,0x1403124d0.
indices.bin
effect/global/common/indices.bin, 2,452 bytes, not wrapped: a table, effect_indices, with one row per vfx ID 0–608 giving the set of c_all.efz it starts at (first_set). The game reads it whole at startup (0x140311b20, group 200 file 1) and plays set first_set[id] + variant (0x1403124d0). Its layout, values and the sets no ID points at are on the table's page.
EffectMaterialData.bin
effect/EffectMaterialData.bin, 480 bytes, an unwrapped xlce table of 4 rows of 0x74 bytes, effect_material_data. The game reads it whole at startup (0x140311b20, group 200 file 0) and sets 28 engine values from row 0. Its layout and how the game reads it are on the table's page.
Loading
Every fact here is static analysis, so at most likely.
- likely: at startup the effect manager (
0x140311b20) sets the vfx group to 200 (0x140C9DB38), reads files 0 and 1 as they are, and reads file 2,c_all.efz, unwrapped asMLZ0(unwrap kind 2, containers.md), waiting for it. Its loader0x1404141f0parses it once (EFX0011); it stays loaded. - likely: any other vfx is loaded when asked for (
0x140414bc0): the game queues a request with the file ID and the variant, and a per-frame update (0x140414fe0) reads one file at a time, unwrapped asMLZ0into a buffer of the wrapper's size (0x140414930,0x140415190), then parses it in place. Up to 16 loaded vfx are tracked at once (handles index 16 slots). - likely: when the file isn't in
Data/, the game loads file 3,global/magic/m0000.efz, instead; a file whose table size is 0 loads nothing. Source:0x140414bc0(path from0x1402af530, existence check through0x1402af780, then file ID 3),0x140414930(size must be above 0). - likely: a variant of a loaded file plays set variant + 1, and nothing plays when the file has fewer sets. A variant of a
c_all.efzvfx plays setfirst_set[id]+ variant, unchecked. Source:0x140414d40(compares variant + 1 with the file's set count),0x1403124d0,0x1404134c0. - likely: a vfx's handle says which kind it is:
0x1xxxxxxxa loaded file,0x2xxxxxxxac_all.efzset. Source:0x140311b00,0x140312540,0x1404134c0.
Replacing a vfx
What a mod has to do to replace a vfx file, from the facts above and in EFX0011:
- Keep the path and file ID. The game opens the file by its ID in group 200; a new name is never looked up. A localized vfx exists once per language: replacing it for every language means replacing all eight files.
- Wrap it as
MLZ0with the exact unpacked size at byte 4. Any valid LZ4 block works; LZ4's default compressor reproduces the originals byte for byte (Rebuilding). - Set its size in
FileTable.binto the file's exact size: the game reads exactly that many bytes and takes all but the first 8 as the LZ4 block (filetable.md). - Keep it a valid
EFX0011: the 8-byte magic, chunks that fill the file exactly with sizes in multiples of 16, and set IDs 1, 2, 3, … (EFX0011). - Keep enough sets for every variant the game asks for: variant n plays set n + 1 (the most an
effect_datarow asks of a magic file is variant 13). - Keep the texture names game code looks up, such as
__dummy__card_normalandcard_normalin the character-creation vfx (R: texture). - To change a shared battle vfx, edit
c_all.efz's sets; to point a vfx ID at another set, change itsfirst_setinindices.bin(not wrapped; its size doesn't change). IDs pointing at set 105 look unused.
None of this has been tested in the game yet.
Functions
| Address | Name | What it does |
|---|---|---|
0x14026ca60 |
Language_Get |
Returns the game's language, 0–7. |
0x140311a40 |
Vfx_IdToFileId |
Vfx ID → file ID in group 200; 2 means c_all.efz. |
0x140311b00 |
Vfx_GetState |
A vfx's state, by handle kind. |
0x140311b20 |
EffectManager_Init |
Loads files 0, 1 and 2 of group 200 and fills the vfx player's callback table. |
0x1403124a0 |
Vfx_FileExists |
Whether a vfx ID's file is in the file table (0 for c_all.efz IDs). |
0x1403124d0 |
Vfx_Load |
Vfx ID and variant → handle: a c_all.efz set, or a file load request. |
0x140312540 |
Vfx_Start |
Starts a loaded vfx, by handle kind. |
0x140313820 |
Vfx_StartChild |
Vfx player callback: starts a c_all.efz set by number from a parent vfx. |
0x140410f80 |
VfxParam_Set |
Sets one of the 28 engine values from EffectMaterialData.bin. |
0x140412220 |
VfxFile_FindTexture |
Finds a texture of a loaded vfx by name. |
0x1404134c0 |
VfxCommon_New |
New handle for a c_all.efz set. |
0x1404135a0 |
VfxCommon_Start |
Starts a c_all.efz set. |
0x1404141f0 |
VfxCommon_Parse |
Parses c_all.efz once it's read. |
0x140414240 |
VfxCommon_GetState |
State of a c_all.efz vfx. |
0x140414930 |
VfxFile_StartRead |
Opens a vfx file and queues its MLZ0 read, one at a time. |
0x140414aa0 |
VfxFile_GetState |
State of a loaded-file vfx (16 slots). |
0x140414bc0 |
VfxFile_Request |
Queues a file load; falls back to file 3 when the file is missing. |
0x140414d40 |
VfxFile_Start |
Starts set variant + 1 of a loaded file. |
0x140414fe0 |
VfxFile_Update |
Per frame: starts queued reads, parses files that have arrived, frees finished ones. |
0x140415190 |
VfxFile_AllocBuffer |
Allocates the unpack buffer for a vfx file. |
0x1404a2c60 |
Libra_AllocBuffer |
Allocates through the Libra allocator (Libra\TsMalloc.cpp). |
0x1404a49b0 |
Efx_GetSet |
Finds or makes a set by ID (up to 1,024). |
0x1404a4a70 |
Efx_ReadSet |
Reads a 0x600 chunk in place. |
0x1404a4d10 |
Efx_ReadChunk610 |
Reads a 0x610 chunk in place. |
0x1404a4920 |
Efx_ReadChunk620 |
Reads a 0x620 chunk in place. |
0x1404a51f0 |
Efx_ReadChunk700 |
Reads a 0x700 chunk in place. |
0x1404a7250 |
Efx_ReadChunk800 |
Reads a 0x800 chunk in place. |
0x1404a75b0 |
Efx_ReadChunkA00 |
Reads a 0xA00 chunk in place. |
0x1404a84f0 |
Efx_ReadResource |
Reads a 0xB00 chunk by kind (P, Q, R, S, T, W). |
0x1404a8760 |
Efx_FindTextureByName |
Finds an R resource by name. |
0x1404a87e0 |
Efx_RegisterSoundBank |
Registers a W resource's sabf bank (64 entries). |
0x1404ab1b0 |
Efx_CopyChunks |
Copies chunks 16 bytes at a time (not used for effect/ files). |
0x1404ab220 |
Efx_ReadChunk |
Picks a chunk's reader by type. |
0x1404ab460 |
Efx_Load |
Checks the EFX0011 magic and reads every chunk. |
0x14050d500 |
Efx_ReadSoundBank |
Reads a W resource. |
0x14050dfe0 |
Efx_RunCommand |
Runs one command of a 0x1000 chunk (21 opcodes); no shipped file has one. |
Leads
- What happens when a
c_all.efzvfx asks for a set past the last one (655), or a missing file's fallbackm0000.efzhas too few sets for the variant. - What the 28
EffectMaterialData.binvalues control (the engine values at the pointers at0x140C9DC00), and whether rows 1–3 are read anywhere. - How many file load requests can wait at once (the free list at
0x140F30DC0), and how manyc_all.efzinstances can play at once (0x140F307F8). - What the vfx player's other callbacks do (the table filled by
0x140311b20at0x140C9DB50–0x140C9DBF8). bl::efx, the engine's own effect system (overview), reads none of theeffect/files that way; what it plays is open.- Confirm in the game (R14) that a re-compressed vfx with a different LZ4 block, and a modified vfx with a new size in
FileTable.bin, play.