# Fox Engine file formats *Shard of mgsv-modding-pack — generated 2026-08-11. 52 files. Provenance is on every entry as `source:path`.* Format documentation and the parser code that is the real spec. When docs and code disagree, the code wins. ## TPP.FileFormats — Atvaark's format library ### `formats:README.md` #### TPP.FileFormats Fox Engine / Metal Gear Solid V: The Phantom Pain file format research dump. ##### References These are tools that were originally created to unpack and repack Metal Gear Solid V: Ground Zeroes (PC) files. These might work with the file formats used in The Phantom Pain. [GzsTool](https://github.com/Atvaark/GzsTool) [FtexTool](https://github.com/Atvaark/FtexTool) [FoxTool](https://github.com/Atvaark/FoxTool) [FoxEngine.TranslationTool](https://github.com/Atvaark/FoxEngine.TranslationTool) [MGSV QAR Tool v1.3 by Sergeanur](https://www.dropbox.com/s/0rtpumx2mxsjaby/MGSV_QAR_Tool.rar?dl=0) [MGSV FPK Tool v1.1 by Sergeanur](https://www.dropbox.com/s/8g8qg35jmluqqlx/MGSV_FPK_Tool.rar?dl=0) ##### Files and file formats ###### Files by platform | Platform | Files | | ------------------ | -------------------------------------- | | PC | [See files_pc.md](files_pc.md) | | Playstation 3 | [See files_ps3.md](files_ps3.md) | | Xbox 360 | [See files_360.md](files_360.md) | ###### Versions | Platform | Versions | | ------------------ | -------------------------------------- | | PC | [See versions_pc.md](versions_pc.md) | ###### Files with associated tools | Extension | Description | Associated tools | | ------------------ | -------------------------------------- | -------------------------------------------- | | .lua | Script | Your preferred text editor | | .json | Settings | Your preferred text editor | | .xml | Settings | Your preferred text editor | | .fpk | Archive | GzsTool | | .fpkd | Archive | GzsTool | | .pftxs | Texture archive | GzsTool | | .sbp | Sound archive | GzsTool | | .qar | Archive | GzsTool | | .qar | Archive | MGSV QAR Tool 1.3 | | .fpk | Archive | MGSV FPK Tool 1.1 | | .fpkd | Archive | MGSV FPK Tool 1.1 | | .ftex | Texture head | FtexTool | | .ftexs | Texture data | FtexTool | | .bnd | Graph bounder data | FoxTool | | .clo | Cloth settings | FoxTool | | .des | Destruction settings | FoxTool | | .evf | Event settings | FoxTool | | .fox2 | Scene settings | FoxTool | | .fsd | Facial settings | FoxTool | | .ph | Physics object settings | FoxTool | | .phsd | Physics sound settings | FoxTool | | .sdf | Sound data file info | FoxTool | | .sim | Simulation object settings | FoxTool | | .parts | Model parts settings | FoxTool | | .tgt | Geometry target settings | FoxTool | | .veh | Vehicle driving settings | FoxTool | | .lad | Lip adjust settings | FoxTool | | .subp | Subtitles | FoxEngine.TranslationTool | | .ffnt | Bitmap font | FoxEngine.TranslationTool | | .lng | String table | FoxEngine.TranslationTool | | .lng2 | String table | FoxEngine.TranslationTool | ###### General formats | Extension | Associated tools | | ------------------ | -------------------------------------------- | | .ag.evf | | | .aia | | | .aib | | | .aibc | | | .aig | | | .aigc | | | .ladb | | | .aim | | | .aip | | | .ait | | | .atsh | | | .bnd | FoxTool | | .cc.evf | | | .clo | FoxTool | | .des | FoxTool | | .ese | | | .evb | | | .evf | FoxTool | | .fag | | | .fage | | | .fago | | | .fagp | | | .fagx | | | .fclo | | | .fcnp | | | .fcnpx | | | .fdes | | | .fdmg | | | .fmdl | | | .fnt | | | .fova | | | .fox | | | .fox2 | FoxTool | | .fpk | MGSV FPK Tool 1.1 or GzsTool | | .fpkd | MGSV FPK Tool 1.1 or GzsTool | | .fpkl | | | .frdv | | | .frig | | | .frt | | | .fsd | FoxTool | | .fsm | | | .fsml | | | .fstb | | | .ftex | FtexTool | | .ftexs | FtexTool | | .fx.evf | | | .fxp | | | .gani | | | .geom | | | .gpfp | | | .grxla | | | .grxoc | | | .gskl | | | .htre | | | .json | Any text editor | | .lad | FoxTool | | .lani | | | .las | | | .lba | | | .lng | FoxEngine.TranslationTool | | .lng2 | FoxEngine.TranslationTool | | .lpsh | | | .lua | Any text editor | | .mas | | | .mog | | | .mtar | | | .mtl | | | .nav2 | | | .obr | | | .obrb | | | .parts | FoxTool | | .path | | | .pftxs | GzsTool | | .ph | FoxTool | | .phep | | | .phsd | FoxTool | | .rbs | | | .rdb | | | .rdf | | | .sad | | | .sani | | | .sbp | GzsTool | | .spch | | | .sd.evf | | | .sdf | FoxTool | | .sim | FoxTool | | .simep | | | .sub | | | .subp | FoxEngine.TranslationTool | | .tgt | FoxTool | | .tre2 | | | .txt | | | .uia | | | .uif | | | .uig | | | .uigb | | | .uil | | | .uilb | | | .utxl | | | .veh | FoxTool | | .vfx | | | .vfxbin | | | .vfxdb | | | .vo.evf | | | .wem | | | .xml | Any text editor | | .ffnt | FoxEngine.TranslationTool | | .fsop | | | .fv2 | | | .1.nav2 | | | .csnav | | | .vnav | | | .dnav | | | .snav | | | .rnav | | | .info | | | .fmdlb | | | .dnav2 | | | .mbl | | | .sand | | | .qar | MGSV QAR Tool 1.3 or GzsTool | | .nta | | ### `formats:files_360.md` | Path | Format | Encrypted | Compressed | | -------------------------------------- | ------------------ | --------- | ---------- | | \Default.xex | XEX/ELF | | | | \mgo_x360.xex | XEX/ELF | | | | \nxeart\nxeslot.jpg | JPG | | | | \nxeart\nxebg.jpg | JPG | | | | \master\foxfs.dat | | | | | \master\175c\bae03369822f9cd5.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae05f60242ccd2a.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae06a52209c50f3.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae070f9c41cf615.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae087f1766c0416.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae0a9716c9ea2b0.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae0afd57fc868ee.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae0bfb16e93035a.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae10bc48b5a4089.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae116bf50ce2437.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1176c96e9a76d.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae133560534324e.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae164922e2a663d.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae19ff0e374d252.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1ae0951f4d6fe.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1c1b86c51dff5.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1dce12d65cb26.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1e2d4545f2efc.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1fcdacf7e2b0b.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae20a0ef5fe0cf1.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae22f41aeeddc85.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2318534a3d236.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2710337c5462c.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae27bb0e6aa35dc.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae27f49d9b85f6d.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae288430200d870.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2a048b8f40ddd.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2b81de7abbac5.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2d53245b31df8.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2ea68547418fb.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2f127503d5b63.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3051bd7e8cf18.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae33a0325c0c91e.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae33de510351e7e.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae34a6480f857e6.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3796a5a6a947a.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3892d532462ef.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae39cba8726faf1.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3a62bee990521.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3c23e12826fd5.dat | SBPB/BKHD (Wwise) | | | | \master\1a6\d3007709f21c5ab.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3009d9825df0e8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300a1a2fade8b5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300ad01912c14e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300c3b056dd659.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300f560ed8ecaa.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300fd85831ccee.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d301066f0842506.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3010c2f7552b23.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d301454bc3f8612.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3018235b2e51eb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3028b2e0559c2e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d302a142d1e4632.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d302b52aa6d6588.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d302d8bf5ac1151.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3031adcb95b866.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3035990a061d4e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d303662fb300672.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30438987918812.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3049df18c0ab66.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d304e6b38b62a68.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d305391b52d5dcb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d305a60103ffb5d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d305c03c21041b0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d305fcbb15b7796.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3061b6f08d85f9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d306b356b17bb04.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d306e204c4ee341.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d307230c78e3f89.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30747739219f19.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3079341715a14a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d307fbb1a9ab650.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3088d4e916fca5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d308de589264ba4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3093103a9db7a9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d309803cc01451a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d309a08f7990ce2.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d309fdeed260ac2.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30a053a1cd3c45.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30add1e4561841.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30af9031ee9e74.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30b06e19f2f8a3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30b629391c3fef.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30b6440cd6e816.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30bd0758e36e65.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30c227a7334946.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30c49b60d2e1ec.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30c74914fea819.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30cfa231234ff1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30dd084b8c33f8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30e3f0e49cc8cc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30ea045c1c7df3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30edaf8ccddca8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30ee5ed971719a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30efe7f4c700fe.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30f0bb2d75ab96.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30f4b8cc8c45ea.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30fee5cdc60c9e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3103a345941963.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d310cd8cae7f7d5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d310f1e99bea406.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d310fccde9502e9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31125bbe85a74f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d311555d0ce5e16.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d311b2e566a7c41.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d311f8e1305a4c1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d311fdb8a33020e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31206e370f12d1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3122b117263780.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3123687e7dde3d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31253490c4e260.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d312562560bfe98.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d312a7582de72a0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31353a3d3bf643.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3137af3276be5f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d313bb47367a113.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d313e8e3a018242.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d313fb8cbd49ab7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d314011b9588b6a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31509905564500.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31521578b7b67f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31543b55c0a44c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31576e79bf83fc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d315fe8f46d1952.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3161b51090426b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3163862ea6817d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316403de1df8bc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316451b13fa356.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316609860e4993.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316989e8946616.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316f0a0275c009.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3170c367d4f4c2.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3175ec6505e1bb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31760ca1136165.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3179de63b9023c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31800c72a0da2c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3180590720c1b7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3183c83f5305df.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3184270f2e59b4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d318d4af8db8c20.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d318d864974291c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d318dd745376ea1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3190ca7f8bd7f1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3192224e279268.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3192ec770e94a4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31a3b690accac2.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31a4ad497de8b8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31a63e8de35384.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31ad863986ea8b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31ad949a93c37e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31b1fac854e6de.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31b42a1a88bc4e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31b5da43037af7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31b802f3cc6969.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31bd4980072f55.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31c20d3215a222.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31c5fafc9add52.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31c62a88005f19.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31cbfce5a7bd50.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31d07590e2ba69.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31d17424d0a9dd.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31d6a915bcbe0b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31db8f96c61b97.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31dcd9eb183960.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e1a3dcf7589a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e5c98e22c56e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e7ad3635044c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e7d2c0b74e8c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e85198c1b16b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31eec508437213.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31ef1c03f965f9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31f7bb935a7046.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31f9d9727caa77.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3200019b0d1999.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3201abe001263a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32024c9787c7ae.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32068fe78331f8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d320e8497fb7217.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32111c44fb7041.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3212de45ed1f50.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3219c41a60a777.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d321f3d5e4d6a4f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3228d9aa0e5478.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d323107237adebc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32331b35498cca.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3233c886d0fb0d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32388e79cca8ef.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d323e96325a4624.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32435ea02ed4f3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3247823c3bd96e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32539f32273dcd.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3255eb166afd73.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325a266de59229.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325ab59815e9ec.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325bd6ed89bc30.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325bf2ae2d87f1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325c49c5e5f1a7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325e5d50591f8b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32628652950d43.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3262e731ebadf7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3267e430f191b6.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d326bd1ef719682.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328633074c70eb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3287b343e93973.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3287f3935701a4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328a57c9616aac.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328acff2bc08d8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328c62cca102d6.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328cc7ab5cdf63.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328d4d9449c059.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328db86e2eb7f3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328ea859a4963c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3293f92be8143a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d329526e9d123cf.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d329a3bdb93afbe.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d329bf899b8d0da.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d329f6c1e99ac05.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32a12b2bb0c584.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32b174c7302451.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32bab52858cbfb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32bb25e925aeaf.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32c07ce1083415.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32caeafe4ee161.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32d06eac1b6114.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32d8fb754c5566.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32e3bc8c1df427.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32e7b00044c120.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32eaefd8fcec7f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32eb391c2ecc54.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32ed512713ac7b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f07f849a6075.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f255de267ed8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f35a7d12b7db.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f58473f3c513.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f6d2b45dc802.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f9355ecfc843.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3300d713441b6b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33066b0469ffa8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3307253d34a83e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3309f6295901ac.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d330eb176d1f864.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d330fd4a87b3394.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3311ca408b3b0e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d331ab5b13c6ced.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33218daf7c7fc0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3322746c733db4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3336ad4f5497ce.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3338a11fde9f0b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d333d8fddb3c6a5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d334522bb9de9e4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3349b388c305a9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3352faec5a4c53.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3354cf4f461a3d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3357e4a2af9d1c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33583f9aeda484.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3358bf4316f562.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d335d2936ef913c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d335f4884aff887.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d335fe8150681fc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3361a58a710a16.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33621331275fc8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d336860b312a2f0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d336de5b478da8c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d336e61a8477297.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33785a65fef353.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d337923698b4e59.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d337a3f57a1821f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d337c22907d6371.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d337f31cc23d10e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3380dc4ef80fb8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33893c5dc319c5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d338af57359d8d3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d338e31025fb33e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3393ab6ad4884f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3394055ea2ea55.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33989a37687b76.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d339ed2f96511f0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a48f646a842c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a4e9dc78e8c9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a604c3fc8e27.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a7e73f1e7d0f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a9a521bc8098.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33b3b9d26f467f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33b58a33dddf86.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33ba916ec99213.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33bed453195d70.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33bffc3ecf6ab5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33c4451fc5539f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33e553fbb1d936.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33e74a9a4194f3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33e8abe913de69.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33ecd8c902897b.dat | RIFF WAVE (RIFX) | | | | \master\1f8a\fc521c2d8c376f41.dat | | | | | \master\c3b\61d80447152a6ca7.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d81198663eb2d9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d81c56eb47c92e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d81ebdcdd9fa0c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8228fe47ba517.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d82502e3cef9a1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d82c4ea4605f5f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8326a4e7707f7.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8344feb4c795c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d834c55307c83f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83588b040bd35.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83aacb701e36b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83d8728177933.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83f13172e9a6f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83f3725bc0516.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83fb4840b0a2c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d84555120d38a1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d854595a48a815.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8582c06304501.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d85b9b431d871a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d85ded7faa0c18.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d85fa09eb7652a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d860bb2422b685.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d862ee216c1a5d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d865899bae9e8a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d868cc926d02d7.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d875f69337181c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d878b09cc28804.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87a9b93ffffbb.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87b4b23a8d43d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87e8966244e34.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87f2eb8072fe0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87f9edac8e4fd.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8802869fdbc29.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8915aff32f94d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8941947006380.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d895b491852685.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d89abdff80a30e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8a2ae09b88499.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8a3d2d8899476.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8a4d3ca8e298b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8a887f1670e9a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8bc5ed5e0daa5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8c177284ce05b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8c8120e467a21.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ca0c8b440fe1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ca4f16dace16.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ce10c60378db.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ce3b75a89ffc.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ce6463a50ee9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8cf461544ecf6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8d780296045d6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8f2f6a22586b7.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8f6184bee2d9d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8f8c83a801123.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d905a1028f38ff.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9075c0348f89f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d913203f7ed613.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d916b140bddebf.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d918b4f7019242.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9198e3710e6d8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d91bb437b47659.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d91e3bcf97d8c8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d91e77004ed049.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d91f911a67fcc1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d935b64d8ef6d3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d938836d5fc6d4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d93cd48165ab68.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d93f9be65db363.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d940c8093c17b3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d941977a6d6c10.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d94248af4951fb.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9434fd5634bf5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9461e573637e2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d952fdda1ab2af.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d957f9c50cef61.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d95a4fad94cac9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d95c197a08b032.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9601f7a219a30.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d965451e2e2a17.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d96a6363f0a19c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d96a7b49e913a0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d96c512ce2f481.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d96c895a7248e2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9713e3565157b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9786079fbddda.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d97d31d6e49f75.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d97e354f6f8477.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9895fde53e6f8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d98c39429d0f6a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d98fe62f91245e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9908e8190de77.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d991bcf10015af.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d99475c79cd1d4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d996d290c1bbab.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d99b2c04d9e508.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d99dc8e59d6c9b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d99fe0c3fa15df.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9a789de035b55.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9ada3eb2ec1b9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9b283e7dd34a3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9b5ddbfa69e96.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9bd48e12d550b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9c0fb75590734.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9c86a6dc30c66.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9ca2892e36d95.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9cc9c5e1d0001.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9dc6b889d61db.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9df0de86fdf5d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9ed6f1bce21d4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f21bbd93e2ae.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f2df512b991d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f3bcad949bd1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f59987bd204e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f6bfcaa1f646.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9ff49191ce4d5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da03816dc2b984.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da0620ea6de744.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da091f26acab14.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da0dd4c6fda65a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da0f425b199482.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da125fa27e76b2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da14dfaa96823b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da14ed53ebc442.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da1891676ad248.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da1b942c1ab693.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da1f07e4f74290.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da23f3bc996983.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da26b63431039b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da2b46c3233b41.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da2cbfc20ac3b5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da2d79ebb07b85.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da2eb9c673761d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da33223908d05f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da3dab9602596f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da40ef2d47a6ad.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da423db343e166.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da4343f79672ee.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da44e884077a6a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da461b3b3f8d62.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da4f761e29b8fc.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da51c001a3d696.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da561059ba362b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da5614da5a2d27.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da593fe37cf7ba.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da596060a752e0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da5c928b9a5ea5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da5fcc2d0a734c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da6025fd7baab5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da69730b7151c4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da6db2d2cd52c2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da6f792f9ea166.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da73f0d2adc8b9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da7ad36c3720e6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da7cd00e5eadae.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da8f463dba700c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da9063016657c0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da931c8714f6f6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da9519f5851fe8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da966bf2d839da.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da9b01ccdace57.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daa2b6d138400d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daa68b3eb4965a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daa6a6f9812559.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dab7fc75ff6661.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dac57eb48214e1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dac76ccf6656c5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dac9a13c17d0d0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dacdacb91a9d11.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dacf4b7317d7b8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dad4a6446e18a8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dad8c2b8a09e93.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadb6d3ff90a49.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadbfde4c36099.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadc44164c45f5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadddc1955bff4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dade709bf5722c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadf82c6132426.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dae1762337346a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dae296851f86b8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dae5a38582f197.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dae5f6fb40be5c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daeecd9e8332d8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daf838ad3250fd.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daf8bdba38176b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db058b43c772dc.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db06d78607d661.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db074b9b129a52.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db0828c28f0366.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db0c64d2b12997.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db0f951f4767ec.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db11147d0e0892.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db11e48fd15b13.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db2337db6cea1e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db2abafc1eb901.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db2dcfc6bae6f2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db38bbae2c5bce.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db38d3120305f0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db3d9009821914.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db4704466c5485.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db474e693993c4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db491f9d3353f2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db4c4834f6d79b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db4e24d7e854e0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db4fb5608975b3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db5e199813544e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db631ce930c4d2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db648a1983793d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db6a63b8b3e4f0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db71eb418a6819.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db785322dbf9a6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db7f9cbbc004d4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db83d71f9a46d3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db87e8f7cb0848.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db890c569c8f55.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db8f69fd4e4b91.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db94b9bcdfdd63.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dba234d160e16d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dba57a8be34dcf.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbb11cf685d760.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbb1231d72d6d3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbb666bc5ceb8d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbc036f393231c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbc12b28e05e5c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbc8c6dc496c1f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbcb13913e4784.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbd1b6ce74b49f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbd2954cc5e64c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbd5542cd25a99.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbd9c245cdcc28.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbdb69b3433aae.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbdb783dec6fde.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbe940e60c6026.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbf1eadbfc42fc.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbf7b2063d6de8.dat | SYS/DEMO (.fsm) | | | | \master\c6c\6360574cffb65151.dat | KB2i | | | | \master\c6c\6361879759c1ab95.dat | KB2i | | | | \master\c6c\63628f97fe3f1e9b.dat | KB2i | | | | \master\c6c\6362ab1e26d2949a.dat | KB2i | | | | \master\c6c\636349d5343fb2fb.dat | KB2i | | | | \master\ef\77d720e8d8714bc.dat | Archive (qar/g0s) | Yes | | | \master\ef\77e669ec815e58f.dat | Archive (qar/g0s) | Yes | | | \master\ef\77e6d53969026de.dat | Archive (qar/g0s) | Yes | | | \master\ef\77fe67b0ff6b88a.dat | Archive (qar/g0s) | Yes | | ### `formats:files_pc.md` | Path | Description | Format | Encrypted | Compressed | | --------------------------------------| ---------------------------------------------- | ------------------ | --------- | ---------- | | \mgsvtpp.exe | | EXE | | | | \0\00.dat | Patch files | QAR | | | | \0\01.dat | | QAR | | | | \master\chunk0.dat | cypr | QAR | | | | \master\chunk1.dat | base | QAR | | | | \master\chunk2.dat | afgh | QAR | | | | \master\chunk3.dat | mtbs | QAR | | | | \master\chunk4.dat | mafr | QAR | | | | \master\data1.dat | | QAR | | | | \master\e2f8e499bc8f3606.dat | Prerendered movie | WMV | | | | \master\e2f9a1fda590d087.dat | Prerendered movie | WMV | | | | \master\e2faa449a7e0781d.dat | Prerendered movie | WMV | | | | \master\e2fb02c35da41a21.dat | Prerendered movie | WMV | | | | \master\e2fbebbd66f86086.dat | Prerendered movie | WMV | | | | \master\texture0.dat | cypr | QAR | | | | \master\texture1.dat | base | QAR | | | | \master\texture2.dat | afgh | QAR | | | | \master\texture3.dat | mtbs | QAR | | | | \master\texture4.dat | mafr | QAR | | | ### `formats:files_ps3.md` | Path | Format | Encrypted | Compressed | | -------------------------------------- | ------------------ | --------- | ---------- | | \EBOOT.BIN | ELF | Yes | | | \mgo.self | SELF | Yes | | | \contents\ICON0.PNG | PNG | | | | \contents\PIC1.PNG | PNG | | | | \master\foxfs.dat | | | | | \master\175c\bae03369822f9cd5.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae05f60242ccd2a.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae06a52209c50f3.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae070f9c41cf615.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae087f1766c0416.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae0a9716c9ea2b0.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae0afd57fc868ee.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae0bfb16e93035a.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae10bc48b5a4089.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae116bf50ce2437.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1176c96e9a76d.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae133560534324e.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae164922e2a663d.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae19ff0e374d252.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1ae0951f4d6fe.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1c1b86c51dff5.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1dce12d65cb26.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1e2d4545f2efc.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae1fcdacf7e2b0b.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae20a0ef5fe0cf1.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae22f41aeeddc85.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2318534a3d236.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2710337c5462c.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae27bb0e6aa35dc.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae27f49d9b85f6d.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae288430200d870.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2a048b8f40ddd.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2b81de7abbac5.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2d53245b31df8.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2ea68547418fb.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae2f127503d5b63.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3051bd7e8cf18.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae33a0325c0c91e.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae33de510351e7e.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae34a6480f857e6.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3796a5a6a947a.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3892d532462ef.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae39cba8726faf1.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3a62bee990521.dat | SBPB/BKHD (Wwise) | | | | \master\175c\bae3c23e12826fd5.dat | SBPB/BKHD (Wwise) | | | | \master\1a6\d3007709f21c5ab.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3009d9825df0e8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300a1a2fade8b5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300ad01912c14e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300c3b056dd659.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300f560ed8ecaa.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d300fd85831ccee.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d301066f0842506.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3010c2f7552b23.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d301454bc3f8612.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3018235b2e51eb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3028b2e0559c2e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d302a142d1e4632.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d302b52aa6d6588.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d302d8bf5ac1151.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3031adcb95b866.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3035990a061d4e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d303662fb300672.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30438987918812.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3049df18c0ab66.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d304e6b38b62a68.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d305391b52d5dcb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d305a60103ffb5d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d305c03c21041b0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d305fcbb15b7796.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3061b6f08d85f9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d306b356b17bb04.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d306e204c4ee341.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d307230c78e3f89.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30747739219f19.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3079341715a14a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d307fbb1a9ab650.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3088d4e916fca5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d308de589264ba4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3093103a9db7a9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d309803cc01451a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d309a08f7990ce2.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d309fdeed260ac2.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30a053a1cd3c45.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30add1e4561841.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30af9031ee9e74.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30b06e19f2f8a3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30b629391c3fef.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30b6440cd6e816.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30bd0758e36e65.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30c227a7334946.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30c49b60d2e1ec.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30c74914fea819.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30cfa231234ff1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30dd084b8c33f8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30e3f0e49cc8cc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30ea045c1c7df3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30edaf8ccddca8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30ee5ed971719a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30efe7f4c700fe.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30f0bb2d75ab96.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30f4b8cc8c45ea.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d30fee5cdc60c9e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3103a345941963.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d310cd8cae7f7d5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d310f1e99bea406.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d310fccde9502e9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31125bbe85a74f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d311555d0ce5e16.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d311b2e566a7c41.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d311f8e1305a4c1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d311fdb8a33020e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31206e370f12d1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3122b117263780.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3123687e7dde3d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31253490c4e260.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d312562560bfe98.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d312a7582de72a0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31353a3d3bf643.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3137af3276be5f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d313bb47367a113.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d313e8e3a018242.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d313fb8cbd49ab7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d314011b9588b6a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31509905564500.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31521578b7b67f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31543b55c0a44c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31576e79bf83fc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d315fe8f46d1952.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3161b51090426b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3163862ea6817d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316403de1df8bc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316451b13fa356.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316609860e4993.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316989e8946616.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d316f0a0275c009.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3170c367d4f4c2.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3175ec6505e1bb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31760ca1136165.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3179de63b9023c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31800c72a0da2c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3180590720c1b7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3183c83f5305df.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3184270f2e59b4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d318d4af8db8c20.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d318d864974291c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d318dd745376ea1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3190ca7f8bd7f1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3192224e279268.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3192ec770e94a4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31a3b690accac2.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31a4ad497de8b8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31a63e8de35384.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31ad863986ea8b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31ad949a93c37e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31b1fac854e6de.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31b42a1a88bc4e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31b5da43037af7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31b802f3cc6969.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31bd4980072f55.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31c20d3215a222.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31c5fafc9add52.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31c62a88005f19.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31cbfce5a7bd50.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31d07590e2ba69.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31d17424d0a9dd.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31d6a915bcbe0b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31db8f96c61b97.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31dcd9eb183960.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e1a3dcf7589a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e5c98e22c56e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e7ad3635044c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e7d2c0b74e8c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31e85198c1b16b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31eec508437213.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31ef1c03f965f9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31f7bb935a7046.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d31f9d9727caa77.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3200019b0d1999.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3201abe001263a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32024c9787c7ae.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32068fe78331f8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d320e8497fb7217.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32111c44fb7041.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3212de45ed1f50.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3219c41a60a777.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d321f3d5e4d6a4f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3228d9aa0e5478.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d323107237adebc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32331b35498cca.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3233c886d0fb0d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32388e79cca8ef.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d323e96325a4624.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32435ea02ed4f3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3247823c3bd96e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32539f32273dcd.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3255eb166afd73.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325a266de59229.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325ab59815e9ec.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325bd6ed89bc30.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325bf2ae2d87f1.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325c49c5e5f1a7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d325e5d50591f8b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32628652950d43.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3262e731ebadf7.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3267e430f191b6.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d326bd1ef719682.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328633074c70eb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3287b343e93973.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3287f3935701a4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328a57c9616aac.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328acff2bc08d8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328c62cca102d6.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328cc7ab5cdf63.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328d4d9449c059.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328db86e2eb7f3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d328ea859a4963c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3293f92be8143a.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d329526e9d123cf.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d329a3bdb93afbe.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d329bf899b8d0da.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d329f6c1e99ac05.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32a12b2bb0c584.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32b174c7302451.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32bab52858cbfb.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32bb25e925aeaf.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32c07ce1083415.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32caeafe4ee161.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32d06eac1b6114.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32d8fb754c5566.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32e3bc8c1df427.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32e7b00044c120.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32eaefd8fcec7f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32eb391c2ecc54.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32ed512713ac7b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f07f849a6075.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f255de267ed8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f35a7d12b7db.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f58473f3c513.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f6d2b45dc802.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d32f9355ecfc843.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3300d713441b6b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33066b0469ffa8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3307253d34a83e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3309f6295901ac.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d330eb176d1f864.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d330fd4a87b3394.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3311ca408b3b0e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d331ab5b13c6ced.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33218daf7c7fc0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3322746c733db4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3336ad4f5497ce.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3338a11fde9f0b.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d333d8fddb3c6a5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d334522bb9de9e4.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3349b388c305a9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3352faec5a4c53.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3354cf4f461a3d.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3357e4a2af9d1c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33583f9aeda484.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3358bf4316f562.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d335d2936ef913c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d335f4884aff887.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d335fe8150681fc.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3361a58a710a16.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33621331275fc8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d336860b312a2f0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d336de5b478da8c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d336e61a8477297.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33785a65fef353.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d337923698b4e59.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d337a3f57a1821f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d337c22907d6371.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d337f31cc23d10e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3380dc4ef80fb8.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33893c5dc319c5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d338af57359d8d3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d338e31025fb33e.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3393ab6ad4884f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d3394055ea2ea55.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33989a37687b76.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d339ed2f96511f0.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a48f646a842c.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a4e9dc78e8c9.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a604c3fc8e27.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a7e73f1e7d0f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33a9a521bc8098.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33b3b9d26f467f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33b58a33dddf86.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33ba916ec99213.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33bed453195d70.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33bffc3ecf6ab5.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33c4451fc5539f.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33e553fbb1d936.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33e74a9a4194f3.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33e8abe913de69.dat | RIFF WAVE (RIFX) | | | | \master\1a6\d33ecd8c902897b.dat | RIFF WAVE (RIFX) | | | | \master\7b9\3dc88e788a5a8740.dat | PNG | | | | \master\7b9\3dc8acbf53e78f06.dat | PNG | | | | \master\7b9\3dc8c0b801b23384.dat | PNG | | | | \master\7b9\3dc94f8dc8ba0dc6.dat | PNG | | | | \master\7b9\3dcaf02e913fdcfd.dat | PNG | | | | \master\7b9\3dcba13eb2703fc0.dat | PNG | | | | \master\c3b\61d80447152a6ca7.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d81198663eb2d9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d81c56eb47c92e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d81ebdcdd9fa0c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8228fe47ba517.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d82502e3cef9a1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d82c4ea4605f5f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8326a4e7707f7.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8344feb4c795c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d834c55307c83f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83588b040bd35.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83aacb701e36b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83d8728177933.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83f13172e9a6f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83f3725bc0516.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d83fb4840b0a2c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d84555120d38a1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d854595a48a815.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8582c06304501.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d85b9b431d871a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d85ded7faa0c18.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d85fa09eb7652a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d860bb2422b685.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d862ee216c1a5d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d865899bae9e8a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d868cc926d02d7.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d875f69337181c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d878b09cc28804.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87a9b93ffffbb.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87b4b23a8d43d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87e8966244e34.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87f2eb8072fe0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d87f9edac8e4fd.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8802869fdbc29.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8915aff32f94d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8941947006380.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d895b491852685.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d89abdff80a30e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8a2ae09b88499.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8a3d2d8899476.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8a4d3ca8e298b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8a887f1670e9a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8bc5ed5e0daa5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8c177284ce05b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8c8120e467a21.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ca0c8b440fe1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ca4f16dace16.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ce10c60378db.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ce3b75a89ffc.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8ce6463a50ee9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8cf461544ecf6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8d780296045d6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8f2f6a22586b7.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8f6184bee2d9d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d8f8c83a801123.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d905a1028f38ff.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9075c0348f89f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d913203f7ed613.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d916b140bddebf.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d918b4f7019242.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9198e3710e6d8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d91bb437b47659.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d91e3bcf97d8c8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d91e77004ed049.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d91f911a67fcc1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d935b64d8ef6d3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d938836d5fc6d4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d93cd48165ab68.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d93f9be65db363.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d940c8093c17b3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d941977a6d6c10.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d94248af4951fb.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9434fd5634bf5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9461e573637e2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d952fdda1ab2af.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d957f9c50cef61.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d95a4fad94cac9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d95c197a08b032.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9601f7a219a30.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d965451e2e2a17.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d96a6363f0a19c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d96a7b49e913a0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d96c512ce2f481.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d96c895a7248e2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9713e3565157b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9786079fbddda.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d97d31d6e49f75.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d97e354f6f8477.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9895fde53e6f8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d98c39429d0f6a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d98fe62f91245e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9908e8190de77.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d991bcf10015af.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d99475c79cd1d4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d996d290c1bbab.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d99b2c04d9e508.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d99dc8e59d6c9b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d99fe0c3fa15df.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9a789de035b55.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9ada3eb2ec1b9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9b283e7dd34a3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9b5ddbfa69e96.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9bd48e12d550b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9c0fb75590734.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9c86a6dc30c66.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9ca2892e36d95.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9cc9c5e1d0001.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9dc6b889d61db.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9df0de86fdf5d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9ed6f1bce21d4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f21bbd93e2ae.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f2df512b991d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f3bcad949bd1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f59987bd204e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9f6bfcaa1f646.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61d9ff49191ce4d5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da03816dc2b984.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da0620ea6de744.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da091f26acab14.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da0dd4c6fda65a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da0f425b199482.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da125fa27e76b2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da14dfaa96823b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da14ed53ebc442.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da1891676ad248.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da1b942c1ab693.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da1f07e4f74290.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da23f3bc996983.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da26b63431039b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da2b46c3233b41.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da2cbfc20ac3b5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da2d79ebb07b85.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da2eb9c673761d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da33223908d05f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da3dab9602596f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da40ef2d47a6ad.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da423db343e166.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da4343f79672ee.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da44e884077a6a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da461b3b3f8d62.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da4f761e29b8fc.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da51c001a3d696.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da561059ba362b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da5614da5a2d27.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da593fe37cf7ba.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da596060a752e0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da5c928b9a5ea5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da5fcc2d0a734c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da6025fd7baab5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da69730b7151c4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da6db2d2cd52c2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da6f792f9ea166.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da73f0d2adc8b9.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da7ad36c3720e6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da7cd00e5eadae.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da8f463dba700c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da9063016657c0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da931c8714f6f6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da9519f5851fe8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da966bf2d839da.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61da9b01ccdace57.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daa2b6d138400d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daa68b3eb4965a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daa6a6f9812559.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dab7fc75ff6661.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dac57eb48214e1.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dac76ccf6656c5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dac9a13c17d0d0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dacdacb91a9d11.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dacf4b7317d7b8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dad4a6446e18a8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dad8c2b8a09e93.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadb6d3ff90a49.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadbfde4c36099.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadc44164c45f5.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadddc1955bff4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dade709bf5722c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dadf82c6132426.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dae1762337346a.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dae296851f86b8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dae5a38582f197.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dae5f6fb40be5c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daeecd9e8332d8.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daf838ad3250fd.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61daf8bdba38176b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db058b43c772dc.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db06d78607d661.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db074b9b129a52.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db0828c28f0366.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db0c64d2b12997.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db0f951f4767ec.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db11147d0e0892.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db11e48fd15b13.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db2337db6cea1e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db2abafc1eb901.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db2dcfc6bae6f2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db38bbae2c5bce.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db38d3120305f0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db3d9009821914.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db4704466c5485.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db474e693993c4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db491f9d3353f2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db4c4834f6d79b.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db4e24d7e854e0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db4fb5608975b3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db5e199813544e.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db631ce930c4d2.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db648a1983793d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db6a63b8b3e4f0.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db71eb418a6819.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db785322dbf9a6.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db7f9cbbc004d4.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db83d71f9a46d3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db87e8f7cb0848.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db890c569c8f55.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db8f69fd4e4b91.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61db94b9bcdfdd63.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dba234d160e16d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dba57a8be34dcf.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbb11cf685d760.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbb1231d72d6d3.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbb666bc5ceb8d.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbc036f393231c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbc12b28e05e5c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbc8c6dc496c1f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbcb13913e4784.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbd1b6ce74b49f.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbd2954cc5e64c.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbd5542cd25a99.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbd9c245cdcc28.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbdb69b3433aae.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbdb783dec6fde.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbe940e60c6026.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbf1eadbfc42fc.dat | SYS/DEMO (.fsm) | | | | \master\c3b\61dbf7b2063d6de8.dat | SYS/DEMO (.fsm) | | | | \master\c6c\6360574cffb65151.dat | KB2i | | | | \master\c6c\6361879759c1ab95.dat | KB2i | | | | \master\c6c\63628f97fe3f1e9b.dat | KB2i | | | | \master\c6c\6362ab1e26d2949a.dat | KB2i | | | | \master\c6c\636349d5343fb2fb.dat | KB2i | | | | \master\ce0\670025dbda89496e.dat | Headerless archive | | zlib? | | \master\ce0\67009992255e886c.dat | Headerless archive | | zlib? | | \master\ce0\6700be0e12345701.dat | Headerless archive | | zlib? | | \master\ce0\6700cfbf3855d573.dat | Headerless archive | | zlib? | | \master\ce0\6700f0716b3ff2b4.dat | Headerless archive | | zlib? | | \master\ce0\6700fa956395a744.dat | Headerless archive | | zlib? | | \master\ce0\6701226ded1cb814.dat | Headerless archive | | zlib? | | \master\ce0\67015ffeb6da9089.dat | Headerless archive | | zlib? | | \master\ce0\67019a8e22da65ed.dat | Headerless archive | | zlib? | | \master\ce0\67024fa413d50b03.dat | Headerless archive | | zlib? | | \master\ce0\67025d96b054683e.dat | Headerless archive | | zlib? | | \master\ce0\6702e6947df38fc1.dat | Headerless archive | | zlib? | | \master\ce0\6702f66d52247699.dat | Headerless archive | | zlib? | | \master\ce0\6703221631244f28.dat | Headerless archive | | zlib? | | \master\ce0\67037d219a0d4afe.dat | Headerless archive | | zlib? | | \master\ce0\67038efe0b98f465.dat | Headerless archive | | zlib? | | \master\ef\77d720e8d8714bc.dat | Archive (qar/g0s) | Yes | | | \master\ef\77e669ec815e58f.dat | Archive (qar/g0s) | Yes | | | \master\ef\77e6d53969026de.dat | Archive (qar/g0s) | Yes | | | \master\ef\77fe67b0ff6b88a | Archive (qar/g0s) | Yes | | | \master\ef\77fe67b0ff6b88a.dat | Archive (qar/g0s) | Yes | | | \master\prx\prx_cypr_ps3.sprx | SPRX/ELF | Yes | | | \master\prx\prx_horvr_ps3.sprx | SPRX/ELF | Yes | | | \master\prx\prx_lqd_ps3.sprx | SPRX/ELF | Yes | | | \master\prx\prx_qui_ps3.sprx | SPRX/ELF | Yes | | | \master\prx\prx_sah_ps3.sprx | SPRX/ELF | Yes | | | \master\prx\prx_sample_ps3.sprx | SPRX/ELF | Yes | | | \master\prx\prx_uav_ps3.sprx | SPRX/ELF | Yes | | | \master\prx\prx_vol_ps3.sprx | SPRX/ELF | Yes | | | \master\prx\prx_volvr_ps3.sprx | SPRX/ELF | Yes | | | \master\prx\prx_wmu_ps3.sprx | SPRX/ELF | Yes | | | \master\sdata\d71c05effb453d61.sdat | NPD/decals | AESCBC128 | | | \master\sdata\d71c380a3592e3e4.sdat | NPD/decals | AESCBC128 | | | \master\sdata\d71f8fae7780a08f.sdat | NPD/decals | AESCBC128 | | | \master\sdata\d71fac2a1196883d.sdat | NPD/decals | AESCBC128 | | | \mgo\foxfs.dat | | | | | \mgo\1f8a\fc521c2d8c376f41.dat | | | | | \mgo\ce0\670025dbda89496e.dat | Headerless archive | | zlib? | | \mgo\ce0\67009992255e886c.dat | Headerless archive | | zlib? | | \mgo\ce0\6700be0e12345701.dat | Headerless archive | | zlib? | | \mgo\ce0\6700cfbf3855d573.dat | Headerless archive | | zlib? | | \mgo\ce0\6700f0716b3ff2b4.dat | Headerless archive | | zlib? | | \mgo\ce0\6701226ded1cb814.dat | Headerless archive | | zlib? | | \mgo\ce0\67015ffeb6da9089.dat | Headerless archive | | zlib? | | \mgo\ce0\67019a8e22da65ed.dat | Headerless archive | | zlib? | | \mgo\ce0\67024fa413d50b03.dat | Headerless archive | | zlib? | | \mgo\ce0\67025d96b054683e.dat | Headerless archive | | zlib? | | \mgo\ce0\6702e6947df38fc1.dat | Headerless archive | | zlib? | | \mgo\ce0\6702f66d52247699.dat | Headerless archive | | zlib? | | \mgo\ce0\6703221631244f28.dat | Headerless archive | | zlib? | | \mgo\ce0\67037d219a0d4afe.dat | Headerless archive | | zlib? | | \mgo\ef\77d720e8d8714bc.dat | Archive (qar/g0s) | Yes | | | \mgo\ef\77e6d53969026de.dat | Archive (qar/g0s) | Yes | | | \mgo\ef\77fe67b0ff6b88a.dat | Archive (qar/g0s) | Yes | | | \mgo\sdata\d71c05effb453d61.sdat | NPD/decals | AESCBC128 | | | \mgo\sdata\d71c380a3592e3e4.sdat | NPD/decals | AESCBC128 | | | \mgo\sdata\d71f8fae7780a08f.sdat | NPD/decals | AESCBC128 | | | \mgo\sdata\d71fac2a1196883d.sdat | NPD/decals | AESCBC128 | | ### `formats:versions_pc.md` | Master version | Patch GUID | Patch version | | ------------------------------------- | ------------------------------------ | ------------- | | f0c9f82d-61cc-46d6-95f3-eff6492368c3 | | | | f0c9f82d-61cc-46d6-95f3-eff6492368c3 | fc4385d4-f3f2-423f-b5f2-45db88a2ed82 | 101 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ## Fox_Parser / modbldr-tools — the sanctioned format converter ### `foxparser:MOG_FORMAT.md` #### FOXMOTIONGRAPH (.mog) — format notes 03/08/2026 ##### Tooling ```bash modbldr-tools # -> file.mog.xml modbldr-tools # -> file.mog (refuses to write a graph that fails validation) modbldr-tools mog # structure report modbldr-tools mog --validate # every structural invariant modbldr-tools mog --pool # gani PathIds resolved to names modbldr-tools mog --diff # compare two graphs modbldr-tools mog --repath-gz2tpp -o out.mog modbldr-tools mog --graft --regate -o out.mog ``` `--graft` replicates the donor's states for clips the host lacks, anchored on animations both graphs play, and re-gates the edges onto the host's own tag vocabulary. It is the whole workflow in one command — no scripts. **`--validate` runs automatically on every pack.** The engine checks almost nothing, so a broken graph loads and silently produces no pose; the tool refuses to emit one instead. It catches all of: unsorted tag map, node id != index+1, dangling self-relative offsets, out-of-range or unsorted tag sets, adjacency outside 1..n, non-boundary edge endpoints, missing `0xA7` filler. The XML carries the decoded structure **plus the original file as a base64 ``**. Parts of a mog are still undecoded, and writing from structure alone would drop them; building starts from the image and overwrites only what the XML describes. Round trip is **byte-exact** on all 37 corpus files, and `test mog` gates it. Arrays that keep their length are written back in place. An array that grows is appended at the end of the file and its owning offset repointed — safe because every offset is self-relative, so moving an array invalidates only the one field addressing it. Verified: adding 2 comp tags to a node and 3 request tags to an edge grew the file by exactly 10 bytes, relocated both arrays, and left all 3,087 edges resolving. Decoded from the TPP dev decompile (`C:\rsearch\Tpp_main_win64.exe.c`) and checked against two real files: | file | size | source | |---|---|---| | `TppPlayer2_layers.mog` | 732,872 | TPP `player2_resident_motion.fpk` (live `Z:\` build) | | `TppGzPlayer_layers.mog` | 1,343,232 | GZ `data_02.g0s` → `plmot_base_gz.fpk` | Engine classes: `fox::motiongraph::MogFile` / `MogFileImpl`, structs `MotionGraphFormat*`. --- ##### Offset convention Every offset in the file is **self-relative**: the target is the address of the field that holds it, plus the value. Confirmed in `MogFileImpl::BindTagMap`: ```c pcVar2 = header->Signature + header->ParamsOffset + 0x30; // params pcVar2 = &pcVar2->NextParamOffset + pcVar2->NextParamOffset; // next param TagsMap.Tag = &pcVar2->DataOffset + pcVar2->DataOffset; // param payload ``` Padding filler byte is `0xA7` throughout. ##### Header — `MotionGraphFormatHeader` ``` 0x00 char[16] Signature "FOXMOTIONGRAPH\0" + 0xA7 0x10 u32 Unknown TPP 6, GZ 5 0x14 i32 UnknownOffset -> same target as DefaultAnimParamsOffset in both files 0x18 u8 AnimLayerCount 9 in both 0x19 u8 UnknownD 5 in both; must be > 4 or the tag map is skipped 0x1C u32 GraphCount 4 in both 0x20 i32 GraphHeadersOffset 0x24 u32 DefaultAnimParamsCount 0 in both 0x28 i32 DefaultAnimParamsOffset 0x2C u32 ParamsRelated TPP 5, GZ 4 0x30 i32 ParamsOffset ``` ##### Graph headers — stride 0x38 `MogFileImpl::ConvertToGraphLayerIndex` walks these at `GraphHeadersOffset + 0x24 + n*0x38` reading one byte, summing it until it exceeds a global layer index — so **+0x04 is `AnimLayerCount`** and the per-graph counts sum to the header's `AnimLayerCount`. ``` 0x00 i32 MaskArrayOffset -> array of 8-byte StringIds (NOT a string) 0x04 u8 AnimLayerCount 0x08 u32 StateNodeCount 0x0C i32 StateNodesOffset 0x34 i32 AnimLayerInfosOffset ``` Observed: | graph | TPP layers / stateNodes | GZ layers / stateNodes | |---|---|---| | 0 | 2 / 1871 | 2 / 1688 | | 1 | 1 / 4 | 5 / 450 | | 2 | 5 / 122 | 1 / 114 | | 3 | 1 / 3 | 1 / 3 | Layer sums are 9 in both. Graphs 1 and 2 are swapped in order between the games; the mask StringIds are **byte-identical across games** (`0000e6fbf8fad071`, `0000f4cd88fb8ae1`), so both graphs use the same mask vocabulary. ##### Param chain ``` 0x00 i32 NextParamOffset 0 = end 0x04 u32 Name StrCode32 0x08 u32 Count 0x0C i32 DataOffset ``` Two params in both files: - `0x859bd53e` count 4 (== GraphCount) — four u32s, purpose not yet confirmed. - `0x185ebb9f` — **the tag map**, consumed by `MogFileImpl::BindTagMap` as an array of 8-byte `StringId`, sorted ascending. **TPP 63 tags, GZ 329 tags.** Neither name reverses against the dictionaries (motion-graph vocabulary is not dictionary content, same as Lua command verbs). ##### Animation binding `MotionGraphFormatNode` (0x48 bytes) holds **no animation hash**. Animations are reached through `AnimParamBinaryArray`: ``` AnimParamBinaryArray AnimParamBinaryPath 0x00 i32 Count 0x00 u32 IdOffset -> self-relative to an 8-byte PathId 0x04 i32 DataOffset (element size 4) ``` Elements live at `&DataOffset + DataOffset + i*4` (`fox::gk::SetTargetPose`). ```c // fox::anim::AnimParamBinaryPath::GetPathId uVar1 = *(PathId**)(&this->IdOffset + (int)this->IdOffset); if ((uVar1 & 0xffff000000000000) != 0) return uVar1; // else null ``` **A PathId whose top 16 bits are zero is treated as null.** Both games satisfy this: TPP `.gani` ids carry ext code `0xfc5x` in the top 16 bits, GZ ids are `hash48 | (11 << 52)` = `0x00b0`. So the ids differ in *both* the base hash and the ext code, but neither is null. Path pointers do not appear in packed arrays inside the graph body. They sit at a **16-byte stride**, one 4-byte pointer per slot, with every other byte in the slot left as `0xA7` filler. TPP has 3,211 such pointers into 2,188 distinct pool slots; GZ has 5,243 into 2,406. Animations are referenced by more than one node. ###### The PathId pool Both files end with a large, essentially contiguous array of 8-byte PathIds: | | pool range | entries matched | |---|---|---| | TPP | `0xa6828` .. `0xb2ec0` | 2188 hits / 2186 distinct, 2170 of 2187 gaps are exactly 8 | | GZ | `0x13dea8` .. `0x142a00` | 2406 hits / 2406 distinct, one 32-byte gap | The TPP pool covers **all 30 TPP player mtars**, not just `player2_resident` — matching against `resident` alone makes it look like 121 scattered runs. GZ's pool references every one of its 2406 animations exactly once. ##### Graph header — the rest of it The header is a run of (count, self-relative offset) pairs. Confirmed against both files: ``` 0x00 i32 MaskArrayOffset -> array of 8-byte StringIds 0x04 u8 AnimLayerCount 0x08 u32 StateNodeCount 0x0C i32 StateNodesOffset -> nodes, stride 0x48 0x10 u32 EdgeCount 0x14 i32 EdgesOffset -> edges, stride 0x28 0x18 u32 EntryNodeCount 0x1C i32 EntryNodesOffset -> sorted u16 node indices 0x20 u32 SpecialNodeCount 0x24 i32 SpecialNodesOffset -> sorted u16 node indices 0x34 i32 AnimLayerInfosOffset -> AnimLayerCount x {u8 maxDatas, u8 maxNodes} ``` `AnimLayerInfos` matches the decompile's 2-byte `MotionGraphFormatAnimLayerInfo`: TPP graph 0 has 2 layers and reads `(12,20)`, `(8,32)`. **Entry node list (+0x18/+0x1C).** Sorted `u16` node indices, all below `StateNodeCount`. Its members are overwhelmingly the tag-gated types — TPP 21 of 33 are Type 2, GZ 145 of 250 are Type 2 plus 42 Type 7 — exactly the types `CheckPathTransition` tests with `CompTag`. They average ~2.4x the outgoing edges and about half the blend nodes of unlisted nodes. Reading it as *the index of states reachable by tag query* fits every observation: it saves the engine scanning all 1871 nodes to answer "enter the state matching these tags". This matters for authoring: making a new state reachable by TPP's code plausibly requires it to be Type 2 or 7, carry a `CompTag` set, **and** be listed here. **Special node list (+0x20/+0x24).** Same encoding, tiny (3, 3, 3, 1 entries observed), always near the end of the node array. Purpose unconfirmed — likely default/fallback states. ##### State nodes — 0x48 stride `MogFileImpl::CreateTagMap` walks them with `jOff += 0x48`. The array base is `&graphHeader.StateNodesOffset + StateNodesOffset`, i.e. base `graphHeader + 0x0C`. Settled empirically, since the decompile's `&graphHeader->field_0x28` reads ambiguously: for every node in every graph of both files, `SelfOffset` resolves to a node boundary under base `+0x0C`, and never under base `+0x28`. ``` 0x00 u32 CountA 0x04 i32 OffsetA (see caveat below) 0x08 u32 BlendNodeCount 0x0C i32 BlendNodesOffset 0x14 u8 Type 0x18 i32 NameTagOffset -> one 8-byte StringId (TPP 670 nodes have one, GZ 1664) 0x1C u32 CompTagCount 0x20 i32 CompTagOffset -> sorted u16 INDICES into the tag map — the node's transition gate 0x12 u16 NodeId **index + 1** — exact on every node of every graph in both games 0x28 i32 SelfOffset always exactly -0x28, i.e. a pointer to the node itself 0x2C u32 ? equals the out-edge count on most, but not all, stock nodes ``` **`+0x12` is load-bearing when authoring.** It is a 1-based node id, verified on 1871/1871, 4/4, 122/122 and 3/3 TPP nodes and 1688/1688, 450/450, 114/114, 3/3 GZ nodes. A newly authored node left at 0 produces a graph that loads but yields **no pose at all — the player is invisible and cannot move** (observed in-game 03/08/2026, twice, before this was found). `MogBuilder` now writes it for every node, which is a no-op on existing ones. New nodes also need a real StringId at `+0x18`; zero makes the field point at the node itself and the engine reads garbage. The XML carries it as `name`. The `CompTag` set is what `CheckPathTransition` tests via `CompTag(..., &node->CompTagThing)` for nodes of Type 2 and 7. Validated as sorted `u16` below the tag count on **1871/1871** TPP nodes and **1688/1688** GZ nodes. **TPP: 1,201 of 1,871 nodes carry no comp tags at all. GZ: every node carries 3–7.** GZ's graph is tag-driven; TPP's is mostly reached structurally through edges. Two corrections to earlier drafts of this file: - `SelfOffset` is **-0x28 on all 1871 TPP nodes** — a self-pointer, so `if (SelfOffset != 0) node = &node->SelfOffset + SelfOffset` is a no-op. GZ stores 0 and behaves identically. There is no "redirect mechanism" and no TPP/GZ difference here. - `+0x00`/`+0x04` is **not** the tag list. It is the node's **outgoing edge list** — see below. (The pairs of negative i32s it lands on, e.g. `0xfff82c4cfff71700`, are simply an edge's two node pointers.) ###### Node -> edges, and edge orientation `node+0x00` is a count and `node+0x04` a self-relative offset to that many `i32`s, each self-relative to an edge. Verified exhaustively: across every graph in both files, **every listed pointer lands on an edge boundary, every edge is referenced exactly once, and the referencing node is always the node at `edge+0x00`** — 3087/3087 and 5610/5610, zero exceptions, no edge referenced twice. ``` edge + 0x00 -> SOURCE node (the node whose list holds this edge) edge + 0x04 -> DESTINATION node ``` That settles the orientation and gives the complete transition graph. ##### Animation link `blendNode + 0x04` is self-relative to an `AnimParamBinaryPath` (a 4-byte self-relative pointer), which points to the 8-byte PathId. Confirmed on 3,487 of 5,130 TPP blend nodes and 5,235 of 8,809 GZ ones; the remainder are non-leaf blend operators with no animation of their own. So the chain is **state node -> blend nodes -> PathId**. ##### Blend nodes — 0x2C stride From `MotionGraphBlendValueBinderImpl::SetUseValuesNew`: the array runs from `&node.BlendNodesOffset + BlendNodesOffset` for `BlendNodeCount` records of 0x2C. ``` 0x00 u8 Type 0x01 u8 FloatIndex 0x02 u8 Flags 0x10 u32 ValueCount 0x14 i32 ValuesOffset -> ValueCount records of 8 bytes; byte 0 is a blend-value index, 0xFF = none (used as bit (v&0x1f) of word (v>>5)) ``` Counts from the real files: TPP 2000 state nodes / 5130 blend nodes; GZ 2255 / 8809. ##### Edges — 0x28 stride, the graph header's second block The transition list. `graphHeader + 0x10` is the count, `+0x14` the offset. Stride settled empirically: at 0x28 the `+0x20/+0x24` field validates as a sorted `u16` set with every value below the file's tag count, on **every** record — TPP 3087/3087, 120/120, 2/2; GZ 5611/5611. No other stride comes close. ``` 0x00 i32 -> state node (self-relative) 0x04 i32 -> state node (self-relative) 0x20 u32 RequestTagCount 0x24 i32 -> RequestTagCount sorted u16 INDICES into the tag map (self-relative) ``` Both node pointers land exactly on a state-node boundary for every edge in every graph of both files, and never on the same node. Which end is source and which is destination is **not** established — neither side is sorted; fan-out maxima are 28 (side A) vs 136 (side B) in TPP graph 0. The `u16` set is `AnimParamBinarySet`, read by `impl::CheckRequestTagsEdge`, which merge-intersects it against the controller's dynamic tags and bails the moment the sorted sets diverge — so the edge is taken only when every request tag is currently set. Totals: TPP 3,210 edges (0 unresolved), GZ 7,119 (1 unresolved, a null pointer). **TPP has zero tag-gated edges; GZ has 1,595.** TPP gates transitions on the node's own `AnimParamBinarySet` at node +0x1C instead — `CheckPathTransition` calls `CompTag(..., &node->CompTagThing)` for nodes of Type 2 and 7. This is a real architectural divergence, not a data difference, and it is why the two graphs cannot be spliced naively. ##### Enum meanings ###### Blend node `Flags` — bit 0 is MIRROR `(Flags & 1)` makes the engine play that leaf's animation mirrored. It is not just a pose reflection: `MotionUtility::NormarizeEventName(name, isMirror)` swaps the event through `AnimEventMirrorMap::GetPairName(0x7bf9301d, name)`, so **`MTEV_AG_SYNC_L` becomes `MTEV_AG_SYNC_R`** and the mirrored clip lands on the opposite foot. One clip therefore covers both foot phases. `LayerControl::IsMirror` reads the resulting runtime flag as bit 9 of the data control's word at +0x30. TPP's player graph: **3,396 leaves at 0x80, 91 at 0x81** — 74 distinct clips played mirrored, and **20 of them have no foot-phase sibling in the archive at all**, because the mirror IS the sibling. This matters when porting animations in: replacing a mirror-played clip changes BOTH directions, and a donor clip authored without mirroring in mind plays correctly one way and wrong the other. `transcode --mirror-safe ` skips them. TPP has the mirroring machinery GZ lacks — `AnimControlImpl::CalcMirrorOffset`, `RigPose::MirrorPose`, `LayerControl::IsMirror`, `animx::MirrorOperator` — which is why GZ ships separate clips where TPP mirrors one. ###### Blend node `Type` From the `switch (param_1->Type)` in `MotionGraphBlendNodeTraverser::BuildTree`: ``` 0 leaf — plays the animation, no sub-tree built 1 Two 2 Layers 3 Custom 4 Select 5 StringSelect 6 Add 7 Subtract 9 Single ``` ###### Node `Type` From `CheckNodePair` / `CheckPathTransition`: - `Type == 1` — acts as a wildcard source: `if (node1->Type != 1 && node1 != node2) reject`. - `Type == 2` or `7` — directly enterable; both skip the `MotionGraphPathFinder::IsLogicalAdjacentNode` check, and both are what `CompTag` gates. These dominate the entry-node list. - `Type == 4` — `CheckPathTransition` returns success immediately (already there / terminal). ###### Edge `+0x18/+0x1C` — a second tag set `CheckNodePair` reads `(AnimParamBinarySet*)(edge + 0x18)` and `CompTag`s it against a node's own `CompTagThing`. So an edge carries **two** conditions: this destination comp-tag set, and the request-tag set at `+0x20/+0x24` matched against the controller's dynamic tags. Validated as sorted `u16` below the tag count on **3210/3210** TPP edges and **7119/7119** GZ edges. TPP uses it on 189 edges, GZ on 4,829. The pair also forms a match score in `CheckNodePair`: 1 base, 2 if the comp-tag set is non-empty, 3 or 4 if request tags are present too — more specific edges win. ``` edge 0x00 i32 source node 0x04 i32 destination node 0x18 u32 CompTagCount 0x1C i32 -> sorted u16 tag indices 0x20 u32 RequestTagCount 0x24 i32 -> sorted u16 tag indices ``` ##### Complete state node layout — 0x48 ``` 0x00 u32 OutEdgeCount 0x04 i32 OutEdgesOffset -> OutEdgeCount i32 self-rel ptrs to edges 0x08 u32 BlendNodeCount 0x0C i32 BlendNodesOffset -> blend nodes, stride 0x2C 0x10 u16 ? 0x12 u16 NodeId = index + 1, exact on every node 0x14 u8 Type 0x15..0x17 0xA7 filler 0x18 i32 NameTagOffset -> one 8-byte StringId 0x1C u32 CompTagCount 0x20 i32 CompTagsOffset -> sorted u16 tag-map indices 0x24 u32 ? 0 on 1798 of 1871 0x28 i32 SelfOffset always -0x28 (points at the node itself) 0x2C u32 AdjacentCount 0x30 i32 AdjacentOffset -> sorted u16 NodeIds (1-based) 0x34 u32 ? (always 0) 0x38 i32 ?Offset 0x3C u32 ? (0/1/2) 0x40 i32 ?Offset -> u16 array 0x44 i32 GroupTagOffset -> one 8-byte StringId, distinct from NameTag ``` **Adjacency (`+0x2C/+0x30`)** is a precomputed logical-adjacency list — sorted `u16` node ids, **1123/1123 sorted and all within 1..n in TPP, 1470/1470 in GZ**. It is a superset of the node's own out-edge destinations for 924 of 1123, so it is reachability, not just direct edges. `MotionGraphPathFinder::IsLogicalAdjacentNode` is what consumes it. **GroupTag (`+0x44`)** resolves to a valid 48-bit StringId on **1871/1871** nodes and shares its target with `NameTag` on exactly 1 — a genuinely separate per-node id, matching the engine's `CompareCurrentGroup` / `ComparePreviousGroup` pair. ##### Complete edge layout — 0x28 ``` 0x00 i32 -> SOURCE node 0x04 i32 -> DESTINATION node 0x08 .. 0x17 TRIGGER DATA (see below) — NOT independent enum bytes 0x18 u32 CompTagCount 0x1C i32 -> sorted u16 tag indices 0x20 u32 RequestTagCount 0x24 i32 -> sorted u16 tag indices ``` ###### `0x08..0x17` is trigger data, and it is a pointer chain Reading those bytes as small enums cost a crash. `MotionGraphControlBuiltin::TriggerCheck`: ```asm movsxd rax, dword ptr [rbx+10h] ; i32 add rbx, 10h test eax, eax je skip ; ZERO = this edge has no trigger mov rdx, rax add rdx, rbx ; self-relative -> trigger record call IsOnTriggerEventName ``` and the callee dereferences again — `movsxd rcx,[rdx]` then `mov r8d,[rcx+rdx]`. So the region holds **self-relative offsets**, and a value copied from another file points nowhere: ``` rcx = ffffffffa7000002 <- 0xA7000002, i.e. bytes "02 00 00 A7" synthesised into an edge mov r8d, dword ptr [rcx+rdx] ACCESS VIOLATION CheckPath -> CheckPathTransition -> CheckNodePair -> CheckEdge -> TriggerCheck from BasicActionImpl::StateStandMoveTurn (crash on the player's first move) ``` **An authored edge must leave `0x08..0x17` entirely zero** — that is the engine's own encoding for "no trigger", short-circuited by the `test/je`. Stock edges always carry trigger data (with `0xA7` filler at `+0x0B`), so the validator only demands the filler when the region is non-zero. `+0x08`..`+0x0C` are single bytes, not u32s — the u32 reads `0xA700A701` / `0xA7A7A700` because `0xA7` filler sits between them. `+0x0B` is `0xA7` on all 3,087 edges. ##### Relocating a struct must repoint EVERY self-relative field This was the real cause of three "invisible, immobile player" builds, and it affected the **existing** nodes, not the authored ones. Relaying the node array copies each node's raw bytes verbatim — including offsets measured from its **old** address. Repointing only the obvious three (`+0x04` out-edges, `+0x0C` blend nodes, `+0x20` comp tags) left **`+0x18`, `+0x30`, `+0x38`, `+0x40`, `+0x44` dangling on all 1,871 nodes**; many landed past end-of-file. Edges have the same trap at `+0x14`, `+0x1C`, `+0x24`. A node has eight self-relative fields and an edge five. Move the struct, recompute all of them: ``` NODE 0x04 0x0C 0x18 0x20 0x30 0x38 0x40 0x44 EDGE 0x00 0x04 0x14 0x1C 0x24 ``` Detection: walk every offset field after building and check the target is in-file; the out-of-bounds adjacency reads are what exposed it. ##### Authoring a node or edge — what a new struct needs A field-by-field diff of authored structs against the stock distribution (`mog_fielddiff.py`) found these mandatory fields, all now written by `MogBuilder`: ``` NODE +0x30 +0x38 +0x40 +0x44 zero in all 433 authored, NEVER zero in 1871 stock nodes 1642 / 1607 / 1607 / 1765 distinct values = four offsets EDGE +0x08 +0x0c zero in all 651 authored, NEVER zero in 3087 stock edges 20 / 15 distinct = counts or enums EDGE +0x14 zero in all 651, NEVER zero in stock; 3087 distinct = one per edge, an offset to per-edge data ``` Also cosmetic but worth matching: the `u32` at node `+0x14` reads `0xa7a7a700` in stock (Type byte plus `0xA7` filler), not `0`. Two real bugs were found and fixed along the way — the unsorted tag map and the missing node id at `+0x12` — but neither was the blocker. **Editing existing structures is proven and safe (byte-exact round trip, verified array growth); creating new ones needs these seven fields decoded first.** ##### Authoring new states `modbldr-tools ` creates any node, edge or blend node whose element has **no `at` attribute**. The builder allocates it, relocates the owning array, and repoints everything into it. Worked example — grafting a GZ-only animation as a new TPP state: ```xml ``` plus adding `3087` to node 0's `outEdges` and `1871` to the graph's `entryNodes`. Result: 1871 -> 1872 nodes, 3087 -> 3088 edges, 33 -> 34 entry nodes, node type 2, `SelfOffset` -0x28, a leaf blend node resolving to the grafted PathId, and **all 1,872 nodes' out-edge pointers still landing on edge boundaries**. Relocating an array leaves the old copy as dead space — the authored file above is 991,326 bytes against 732,872, which is exactly the original plus the relocated node (134 KB) and edge (123 KB) arrays. Harmless, and it keeps every untouched structure byte-stable. ##### Tag names — the vocabulary is plain CamelCase English Neither mog stores a single string, and the internal writers (`AddCurrentNodeTag`, `SetCurrentNodeTags`, `QueryNode`) have no game-code callers carrying constants. The hashes crack directly instead: `modbldr-tools unhash -d candidates.txt` against a generated wordlist. Tags are **StrCode64 of plain CamelCase English, no prefix**. TPP's 63, of which 18 are named so far (`mog_tagnames.tsv`, 85 named across both games): ``` Back Crawl Damage Dead Front Horse Idle Left MoveStart MoveStop Normal RideOn Right Squat Stand Throw Wall init ``` Those are exactly the tags that dominate the Rosetta co-occurrence — Squat 397, Stand 361, Crawl 84. Identical names hash identically, so the 24 "shared" tags are literally the same words; the vocabularies need no translation, GZ simply uses ~300 concepts TPP never raises. Node names (+0x18) follow the same convention — 1,603 distinct in TPP's graph. ##### The tag map MUST stay sorted Both stock mogs store the tag map ascending, and it is load-bearing: `FindTagIndex` resolves a StringId against it, and `CheckRequestTagsEdge` merge-intersects sorted `u16` sets, bailing the moment the sets diverge. Appending new tags unsorted breaks every lookup — no tag resolves, so no state matches, so the player gets **no pose at all: invisible and unable to move** (observed in-game 03/08/2026). Merging new tags into sorted order shifts the original indices, so every existing node `CompTag` set and every edge comp/request set has to be rewritten through the old->new map, and each set re-sorted. Verified lossless: across all four graphs, **0 of 2,000 original nodes and 0 of 3,210 original edges changed which tag StringIds they resolve to**. ##### Which out-edge wins — the selection scoring `MotionGraphControlBuiltin::CanMoveState` scores each candidate out-edge, and `SelectMoveEdge` keeps the best. This is absolute priority, not a hint. ```c bVar2 = 1; if (edge->CompTagCount != 0) bVar2 = 2; // edge +0x18 if (CheckRequestTagsEdge(edge, this->field_0x108)) { if (edge->RequestTagCount != 0) // edge +0x20 bVar2 = (bVar2 == 2) + 3; // 4 when comp too, else 3 if (bVar2 < param_4) return bVar2; // can't beat the best so far — early out if (node1==node2 || node2->Type==2 || node2->Type==7 || IsLogicalAdjacentNode(node1,node2)) return PathCheck(...) ? bVar2 : 0; } return 0; ``` | condition carried by the edge | score | |---|---| | none | 1 | | CompTags only | 2 | | RequestTags only | 3 | | both | 4 | `SelectMoveEdge` then: - keeps a candidate only when `bestSoFar <= score`; - on a strictly higher score (`bestSoFar < score`) **wipes the winner and the whole candidate list** — a higher-scoring edge does not merely outrank a lower one, it erases it; - on an equal score tiebreaks on tag *count* — `CompTagCount` at score 2, `RequestTagCount` at score 3-4 — and needs `iVar9 < iVar12`, strictly greater, so an **exact tie goes to whichever edge comes first in the node's out-edge list**; - passes `bestSoFar` as `CanMoveState`'s `param_4`, which is why a hopeless candidate returns its score without running the adjacency and `PathCheck` work. `CanMoveStateByTagsNode` / `SelectMoveEdgeByTagsNode` are the same scoring with the threshold written as `param_3 <= bVar4`. **The two tag sets are different checks and cannot be folded together.** `CompTag` tests the edge's set against the *path node's* own CompTag set — graph-internal data, so a donor-only tag here is still satisfiable by a donor node carrying it. `CheckRequestTagsEdge` tests against `this->field_0x108`, the control's **live** tag set written by game code (`TppPlayer2`), so a tag the host game never sets leaves that edge permanently dormant. **Only the first `field_0x17c` out-edges of a node are ever evaluated** — `SelectMoveEdge` returns out of its loop at that index. It comes from the control's createContext byte 2 and is **100** when absent. Edges past it are silently dead; `--validate` checks this. Measured on stock `TppPlayer2_layers.mog` (graph0, 3,087 edges): **2,898 score 1, 189 score 2, 0 score 3, 0 score 4.** Stock never exceeds 2, so scores 3 and 4 are free for authored edges that must take precedence. ###### The consequence for grafting Filtering a donor condition down to the host's shared vocabulary **broadens** it — 329 GZ tags against 63 TPP tags, 24 shared, so a five-tag GZ condition can survive as one. The edge then fires in contexts the donor never meant, and because a conditional edge outscores a stock unconditional one it wins those contexts *outright*. That is the movement race observed in-game (v15): the GZ clip starts, then flips back to TPP's the moment the diluted tag stops matching. The fix is not to lose the race but to stop entering it: - keep donor conditions **faithful** — an unsatisfiable tag leaves the edge dormant and stock behaviour simply carries on, which is strictly safer than a broadened one that wins; - lift genuine entries to **score 4** by *also* placing the shared-vocabulary part of the condition in RequestTags. That outranks anything stock can field, and it **narrows** the edge — both checks must now pass — instead of widening it; - leave exits out of grafted states **unconditional** (score 1) so escape is always available; internal donor-to-donor edges keep their real conditions. Winning the score is only half of it. A dominant edge with a diluted condition is worse than no edge at all, because it wins everywhere it should have stayed quiet. ##### Blend nodes — the tree, from the engine `fox::motiongraph::MotionGraphFormatBlendNode` is named in the decompile: ``` 0x00 u8 Type 0 leaf, 1 Two, 2 Layers, 3 Custom, 4 Select, 5 StringSelect, 6 Add, 7 Subtract, 9 Single 0x01 u8 FloatIndex 0x02 u8 Flags (bit 0 = MIRROR) 0x04 i32 DataOffset self-relative, TYPE-SPECIFIC (see below) 0x08 u32 LinkDescCount 0x0C i32 LinkDescsOffset 0x14 i32 self-rel to 8-byte records, indexed by FloatIndex 0x20 f32 UnkFloat 0x24 i32 self-rel pointer 0x28 u8 FunctionOutParam ``` **Children are indices, not pointers.** `MotionGraphFormatUtility::GetConnectBlendNode`: ```c childIndex = *(byte*)(&blend->LinkDescCount + idx*8 + blend->LinkDescsOffset + 4); if (childIndex != 0xff && childIndex < stateNode->ConnectNodeCount) return (BlendNode*)(&stateNode->BlendNodesOffset + childIndex*0x2c + stateNode->BlendNodesOffset); ``` So LinkDescs are **8-byte records** self-relative from `+0x0C`, byte 0 is the child's index into the OWNING STATE NODE's blend array (`0xff` = unconnected). The whole tree therefore lives inside that one array — nothing outside it, and no pointer chasing. `MotionGraphBlendNodeTraverser:: BuildTree` switches on `Type` and each type's `BuildTree` calls `GetConnectBlendNode` per port. `+0x04` is type-specific: a leaf points at an `AnimParamBinaryPath`; `MotionGraphLayersBlendNodeData ::BuildTree` reads `{ u32 Count; i32 RecordsOffset; }` then `Count` 8-byte records, each self-relatively addressing an 8-byte StringId. ##### How much of the format is actually modelled The XML carries the original file as a base64 ``, so a byte-exact round trip proves nothing about how much is understood. `modbldr-tools test mog` measures the real thing over the 37-file corpus (28 TPP + 9 GZ, `gzanim_tmp\corpus`): ``` model accounts for 88.1% of 3,577 KB unmodelled: 262,645 B 0xA7 filler (alignment slack) 38,955 B zero bytes 134,270 B REAL DATA still undecoded ``` Padding is two thirds of the gap, so **96.3% of the real bytes are accounted for**; 3.7% is genuinely undecoded. What is left, all named rather than mysterious: blend `+0x14` and `+0x24`, the type-specific `+0x04` blocks for types 1/3/4/5/6/7 (only leaf and Layers are decoded), node `+0x24` and the two u16 arrays at `+0x34/+0x38` and `+0x3C/+0x40`, the edge trigger chain at `0x08..0x17`, and the four u32s of param `0x859bd53e`. ##### Grafting rules learned the hard way **Close the donor subgraph.** Cloning only the nodes that play a wanted clip is not enough: a state's real exit often leads to a donor node that plays nothing new — a pure transition state. Skip it and that exit is dropped, stranding the player. Pull in every unanchored node the seeds can reach until every edge lands on a node that exists: another new one, or an anchored host state. **Never drop an exit when re-gating.** Dropping a conditional edge stops the player *entering* a donor state unprompted, which is the point. Applying the same rule to edges *out of* a donor state strands them — that is the input lock, in-game. Leaving a state is always safe, so exits keep their filtered tags and are never dropped. This alone took dropped edges 232 -> 67 and playable clips 249 -> 295. **Never create an entry edge into a state the player cannot leave.** This is the in-game input lock, and it is the one rule worth checking mechanically. A grafted state is a *trap* if it cannot reach the host graph again — and escape is transitive, so a state whose exits all lead to other trapped states is itself a trap. Measured on the v12 build: **24 of 122 enterable grafted states were traps.** Dropping those entry edges (47 of them) leaves 98 enterable states, 0 traps. Bisecting proved where the fault lived, after several wrong guesses: a build with all 464 grafted **nodes and zero new edges** played normally. So node presence is harmless and the lock is entirely a property of the edges. `--no-edges` and `--max-states N` exist for exactly this. **Terminal states are normal — do not "fix" them.** A node with no outgoing edge is ordinary: **TPP graph 0 has 744 of 1,871 (39.8%)**, GZ has 220 of 1,688 (13%). The engine leaves them by some route other than an edge. Synthesising fallback edges back to a predecessor is solving a problem that does not exist. ##### Learning a GZ -> TPP tag mapping (the Rosetta run) 1,373 animations are played by nodes in **both** player graphs, so their nodes' tag sets can be paired to learn a correspondence. Method: repath GZ's pool into TPP id space, index each graph as animation -> nodes -> tags, then score every (GZ tag, TPP tag) pair by Jaccard over the shared animations. Result in `gz2tpp_tags.tsv`. ``` GZ tags with a confident mapping (co>=3, J>=0.5) : 47 of 329 identity (same StringId) : 6 learned cross-mappings : 41 TPP tags never reached by any mapping : 54 of 63 ``` Several are unambiguous (J = 1.000 at co = 30 and 22), and the identical-id tags carry the bulk of the weight (`49a67b579157` co=397, `7a4db14d320a` co=361, `98736ff23fa2` co=84). **But 282 of GZ's 329 tags have no confident TPP equivalent, and 54 of TPP's 63 tags are never reached.** The vocabularies genuinely diverge outside the shared core. Re-tagging GZ-only nodes into TPP's space is therefore *partial*: it can carry the clips whose gating happens to sit in the mapped 47, and cannot carry the rest. That is consistent with the GZ-only clips being moves TPP's player controller has no state for. ##### Can GZ's mog be dropped into TPP? No. The tag maps were compared directly (`0x185ebb9f` payload, both files): ``` TPP tags = 63 GZ tags = 329 shared = 24 TPP-only = 39 GZ-only = 305 ``` **39 of TPP's 63 tags do not exist in GZ's graph.** TPP player code that queries one of them would find nothing, so replacing `TppPlayer2_layers.mog` with a converted GZ graph silently removes those behaviours. GZ's graph is not an older TPP graph — the two diverged. What *would* be needed to run GZ's graph on TPP data is only a pool rewrite (each 8-byte PathId GZ id -> name -> TPP PathCode64, in place, same size, no offsets move). That part is cheap and safe. The tag gap is the blocker, not the hashes. ##### Verification ledger VERIFIED — offset convention; header fields; graph-header stride, `AnimLayerCount` slot and count/offset pairs; state node array base and 0x48 stride; node tag list; blend node 0x2C stride and blend-value sets; **edge 0x28 stride, both node pointers and the request-tag set**; param chain walk; tag map identity and counts; `AnimParamBinaryArray`/`AnimParamBinaryPath` layout; `GetPathId` top-16-bits rule; pool extents and coverage; GZ→TPP pool repath (cross-checked to the name-derived 1,431 / 975 split). SUSPECTED — param `0x859bd53e` is per-graph (count matches GraphCount, values are plausible self-relative offsets but only two of four land on a graph's mask array). Also VERIFIED — node out-edge list at +0x00/+0x04 and **edge orientation** (source = +0x00, destination = +0x04); node `CompTag` gate at +0x1C/+0x20; node name tag at +0x18; the animation link `blend node +0x04 -> AnimParamBinaryPath -> PathId`; entry-node and special-node index lists; `AnimLayerInfos` as `{u8 maxDatas, u8 maxNodes}` pairs; `SelfOffset` is a constant -0x28 self-pointer. SUSPECTED — the entry-node list (+0x18/+0x1C) is the index of states reachable by tag query (its members are overwhelmingly the Type 2/7 nodes `CompTag` gates, with far more edges and fewer blend nodes than average); param `0x859bd53e` is one StringId per graph (count matches GraphCount, all four targets are 8-byte StringIds, two coincide with a graph's mask array). Also VERIFIED — blend node `Type` dispatch table; node `Type` roles for 1, 2, 4 and 7; edge `+0x18/+0x1C` as a second `AnimParamBinarySet` (3210/3210 and 7119/7119); node and edge creation with array relocation and repointing. NOT DECODED (semantics only; every byte is now located and sized) — node `+0x10`, `+0x24`, `+0x34/+0x38`, `+0x3C/+0x40`; edge `+0x08`, `+0x09`, `+0x0A`, `+0x0C` and the per-layer u16 array at `+0x10/+0x14`; node `Type` 0 and 6 (the common cases; 1,567 of TPP's nodes are Type 0, so it is presumably the plain state with no special entry behaviour); blend-node `Flags` bits; blend node fields at 0x08/0x0C, the float at 0x20 and the int at 0x24; the special-node list's purpose. **Every array in the file can now be located, sized and walked**, and the full transition graph (nodes, out-edges, destinations, tag gates, animations) can be reconstructed. What is left is the meaning of individual enum values, not structure. ### `foxparser:MOTIONPOINTS.md` #### Motion points (root trajectory) — GZ vs TPP 03/08/2026 Motion points are the trajectory tracks that move a character's root and its attach locators. Strip them and anything glued to a surface (ladder, wall climb, vehicle) plays in place while the game keeps moving you — the "slides across the map" symptom. ##### Why the port lost them `GaniV1`/`GaniV2` in `Tools.Mtar/Transcode` parse **units, segments, params and events only**. Nothing reads or writes motion points, so every transcoded clip shipped with `MotionPointTracksDataSize = 0`. Measured against stock: 715 of `player2_resident`'s replaced clips and 4 of 5 in `player2_ladder` lost them. Guarded for now in `TranscodeCmd` (skip replacement when the TPP clip has motion points, keyed on `MtarGaniNames.NameHash` — **not** by table index, `outFile.files` order does not match the raw entry table). Cost: the port drops from 1,886 clip slots to 353. ##### Where the data lives **Entry table** (`MtarTableList2`, stride 32): `MotionPointTracksOffset` at `+0x0E` (u16), `MotionPointTracksDataSize` at `+0x10` (u16). **Header**: `MotionPointUnitCount` at `+0x10`. **GZ (v1 FoxData)** — three children of the `MOTION` node, alongside `UNIT` (`0xc6e937b9`) and the event list (`0x1622762d`): | node | payload | meaning | |---|---|---| | `0xeab12d21` | 32..576 B | **name table** — `{u32 count}` then `{u32 StrCode32, u32 strOffset}` pairs, then the strings | | `0xf0f377d9` | 32..240 B | `{u32 count}` then 8-byte records — parent/attach info | | `0x1d75f6f3` | 96..23168 B | the **track data** | Present in 335 of the first 400 ganis. The names are literal `MTP_*` strings, e.g. ``` 02 00 00 00 | 5b8c79b2 1c000000 | 2dfc9f5d 24000000 | ... | "MTP_ADJUST_HEAD\0MTP_ADJUST_CHEST" ``` `StrCode32("MTP_ADJUST_HEAD") = b2798c5b` — verified against `modbldr-tools hash`. TPP v2 mtars keep only the hash, so this table is the bridge between the two games. ##### TPP's vocabulary is a SUBSET of GZ's Searching both mtars for the 28 `MTP_*` hashes: ``` GZ player 28 of 28 TPP resident 21 of 28 — every one of the 21 also exists in GZ TPP ladder 2 of 28 — MTP_LHAND_A, MTP_RHAND_A (the hands gripping the rungs) ``` **Every motion point TPP uses, GZ has.** So the mapping is a by-name selection, not a remap. This corrects an earlier reading of "GZ 27 units vs TPP 8": those are per-mtar `MotionPointUnitCount` values (how many units that archive uses), not the vocabulary. The vocabularies are compatible, so motion-point transcoding is feasible. Ladder using only `MTP_LHAND_A`/`MTP_RHAND_A` is exactly why dropping motion points made the player slide off ladders. ##### SOLVED — the v1 node payload IS the v2 file, byte for byte No track decoding was needed. GZ's `0x1d75f6f3` payload and TPP's per-clip motion-point file are the same format: ``` TPP 02 00 00 00 | 04 00 00 00 | 00 00 00 01 | 87 00 00 00 | 05 00 00 00 | 28 00 00 00 | 40 ... GZ 02 00 00 00 | 04 00 00 00 | 00 00 00 01 | 14 00 00 00 | 05 00 00 00 | 28 00 00 00 | 40 ... ``` `TrackHeader` (UnitCount, SegmentCount, TrackId/flags, FrameCount, FrameRate — 0x14 bytes), then one u32 offset per unit, then units in the same layout as bone units: `{u32 StrCode32 name, u8 segCount, u8 flags}` followed by 8-byte segment records. Exactly the same relationship `.enchnk` has to the event node — copy the payload across, no re-encoding. The real cause was one line in `TranscodeCmd`: it **deleted** the file on every replacement ("the template's exchnk described its body, not ours"). It now ships GZ's own tracks. Verified: 944 of `player2_resident`'s entries carry this data, and unpacking produces exactly 944 files whose size distribution matches `field+0x10 * 0x10` exactly (min 80, max 18,672). ##### The file is called `.mtp` now The original MtarTool author named it `.exchnk`, which describes nothing. It holds MTP_* track data, so it unpacks as `.mtp`. `.exchnk` is still accepted on read for existing unpacked folders. Field renamed `exChunkSize` -> `motionPointsSize`, `ReadExChunkData` -> `ReadMotionPointData`, `HasExChunk` -> `HasMotionPoints`. ##### The archive's motion-point budget (mtar header +0x10) `MtarHeader` +0x10 (`unknown4` in the tool) is the **largest motion-point unit count of any clip in that archive**. Confirmed exactly on stock data: ``` player2_ladder hdr=2 maxUnitsPerClip=2 player2_resident hdr=8 maxUnitsPerClip=8 player2_cqc hdr=5 maxUnitsPerClip=5 player2_jump hdr=2 maxUnitsPerClip=2 player2_vehicle hdr=5 maxUnitsPerClip=5 player2_behind hdr=4 maxUnitsPerClip=4 ``` The engine sizes per-archive motion-point storage from it, so importing GZ clips — which reach **27 units** where TPP tops out at 8 — while leaving the old value lets a clip overrun that storage. **This is the best explanation yet for the original additive-build symptoms** (flying around the map, wrong animations, inputs ignored): memory corruption, not a lookup failure. The entry table itself was ruled out — an additive build is sorted ascending, has zero duplicates, and every id carries TPP's ext code 8074. `0` is a sentinel: 5 of 7 v2 fixtures store 0 while carrying up to 10 units, and **every** archive with a non-zero value already covers its own worst case. So `MtarFile2.Import` now leaves 0 alone, never lowers a real value, and raises one only when an imported clip needs more. This lives in the packer, so any unpack -> repack is correct, not just transcode. Budget raised on the current build: resident 8 -> 27, vram_resident 6 -> 24, cqc 5 -> 23, vehicle 5 -> 23, ladder 2 -> 9, jump 2 -> 6, behind 4 -> 6, carry 4 -> 6. ##### Result Port restored to **1,879 clip slots** (from 353). Only 4 clips are still held back, where GZ genuinely has no motion points for a clip TPP gives them to. Verified across all 24 changed mtars: **0 entry tables altered, 0 clips losing motion points, 0 mtars losing foot-sync, 31 clips GAINING motion points** GZ has that TPP lacked. Ladder went 5 -> 6 clips with trajectory data, 1,968 -> 2,912 bytes. ### `foxparser:MTAR_FORMAT.md` #### MTAR — motion archive Field names are the engine's own, taken from `fox::anim::MtarHeader`, `MtarTableList2`, `TrackHeader` and `MtarFlags` in the dev-exe decompile (`C:\rsearch\Tpp_main_win64.exe.c`). Verified against every stock player archive: **30/30 repack byte-identical**. ##### File layout ``` 0x00 MtarHeader (0x20) 0x20 MtarTableList2[FileCount] (0x20 each, sorted by Path.id) CommonInfoOffset CommonInfo node chain (see below) first UnitTracksOffset gani bodies, each optionally followed by its motion-point tracks last section motion-event packages (EvpHeader), contiguous, run to EOF ``` The file is always a whole number of **16-byte lines** — pad the tail or the last event package runs off a ragged edge. ##### MtarHeader — 0x20 ``` 0x00 u32 Version 201403250 on TPP/GZ player archives 0x04 u32 FileCount 0x08 u16 UnitCount tracks (bones); mirrors the common TrackHeader 0x0A u16 SegmentCount mirrors the common TrackHeader 0x0C u16 ShaderNodeCount 0 in every archive measured 0x0E u16 ShaderUnitCount 0 in every archive measured 0x10 u16 MotionPointUnitCount largest motion-point unit count of any clip here 0x12 u16 Flags MtarFlags 0x14 u32 CommonInfoOffset SELF-RELATIVE FROM 0x10 0x18..0x1F unused ``` `MotionPointUnitCount` sizes the engine's per-archive motion-point storage. Importing clips with more units than it declares overruns that storage — corrupt animation, dead inputs. **0 is a sentinel**: leave it, never lower it, raise it only when a clip needs more. `CommonInfoOffset` is relative to the address of the `MotionPointUnitCount` field, not to the file start: `MtarFile::GetCommonTrackHeader` returns `&MotionPointUnitCount + CommonInfoOffset`. ```c enum MtarFlags { NEW = 0x1000, HAS_SKEL_LIST = 0x4000 }; ``` `NEW` selects the 32-byte `MtarTableList2` entry; without it the engine reads the 16-byte v1 table. Observed across 49 fixtures: `0x0` (26 files, v1), `0x1000` (7), `0x5000` (16). ##### MtarTableList2 — 0x20, the v2 entry ``` 0x00 u64 Path PathId; the table MUST be sorted ascending on it 0x08 u32 UnitTracksOffset absolute file offset of the gani body 0x0C u16 UnitTracksDataSize in 16-byte lines 0x0E u16 MotionPointTracksOffset 0x10 u16 MotionPointTracksDataSize in 16-byte lines 0x12 u16 ShaderTracksOffset 0 on every entry measured 0x14..0x17 unused 0x18 u32 MotionEventsOffset absolute offset of this clip's EvpHeader 0x1C..0x1F unused ``` **The table is sorted by hash, the payload is not.** `MtarFile::GetAnimFile` runs `SearchGani`, a binary search over `Path.id`, so the table order is mandatory — but Konami lays the gani bodies out in an unrelated order (93 of 94 entries differ from table order in `player2_cqc`). A packer that writes bodies in table order relocates every clip in the file. Motion-event packages follow the same order as the bodies. ##### What the payload files are | unpacked as | engine type | what it is | |---|---|---| | `.gani` | `TrackMiniHeader` | the animation itself | | `.mtp` | motion-point tracks | root trajectory; stripping it makes clips slide | | `.enchnk` | `EvpHeader` | event package — carries `MTEV_AG_SYNC_L/R` foot plants | | `.trk` | node `0x4fbdaaef` | the common track layout every clip shares | | `.chnk` | the remaining nodes | motion-point table and/or skeleton list | `TrackHeader` (0x14): `int UnitCount, uint SegmentCount, u16 TrackId, byte UnknownA, byte UnknownB, int FrameCount, sbyte FrameRate`. Its `UnitCount`/`SegmentCount` mirror the file header's, which is what makes them a usable compatibility check: a clip set can only be dropped into an archive whose track layout matches. All three payloads are decoded and modelled — the XML carries typed ``, ``, ``, `` and `` elements, not `.trk`/`.chnk` blobs. `NextNodeOffset` is always `align16(16 + DataSize)`, and the gap from the chain to the first gani body follows the same rule, so no padding is stored: it is derived. ##### CommonInfo — a chain of named nodes Everything between the entry table and the first gani body is a **singly linked list of `MtarMiniDataNode`**, starting at `CommonInfoOffset` (from the FILE START — the +0x10 base in `GetCommonTrackHeader` is just that function returning the first node's payload). `AnimFile::GetSkeletonList2` walks it looking for a node by name. ``` MtarMiniDataNode (0x10 header, payload follows) 0x00 u32 Name StrCode32 0x04 u32 DataSize payload bytes after this 16-byte header 0x08 u32 NextNodeOffset self-relative from &Name; 0 = last node 0x0C u32 (0) ``` There is no separate ".chnk" section — the old reader misread node 0's fields as "signature / length / chunkOffset" and treated everything after it as an opaque chunk. | Name | payload | |---|---| | `0x4fbdaaef` | common track info — the shared `TrackHeader` and its units | | `0x3b9a7784` | motion-point unit table | | `0x91e4534b` | skeleton list (`HAS_SKEL_LIST` only) | ###### 0x4fbdaaef — common track info ``` TrackHeader (0x14) u32 unitOffsets[UnitCount] SELF-RELATIVE TO THE TRACKHEADER START, 0 = absent per unit: TrackUnit { u32 Name (StrCode32); u8 SegmentCount; u8 Flags; u16 pad } TrackData[SegmentCount] { i32 DataOffset; i16 SegmentId; u8 Packed_Type4_NextEntryOffset4; u8 ComponentBitSize } ``` The walk is `TrackControl::GetTrackControlSize(TrackHeader*)`: unit at `&common->UnitCount + unitOffsets[i]`, segments at `unit + 1`, segment type is `*(u8*)(segment + 6) & 0xf`. `TrackUnitFlags { LOOP=1, HERMITE_VECTOR_INTERPOLATION=2, IS_STATIC=4 }`. Verified on player2_resident: 18 units whose `SegmentCount`s sum to **56**, exactly the `TrackHeader.SegmentCount`. ###### 0x3b9a7784 — motion-point unit table ``` u32 Count [Count] x { u32 MotionPointName, u32 BoneName } both StrCode32 ``` `DataSize == 4 + 8*Count` exactly. player2_ladder declares two: `MTP_RHAND_A` (0x632c5c53) -> `SKL_023_RHAND`, `MTP_LHAND_A` (0x47bbfc94) -> `SKL_013_LHAND` — the hand attachments, which is why stripping motion points made the player slide off ladders. **This count is NOT `MtarHeader.MotionPointUnitCount`.** In stock archives the header is always less than or equal to the table count and is frequently the 0 sentinel (trashbox 0/4, cqc 0/6, gimmick 5/11). The header bounds units per CLIP; the table is the archive-wide vocabulary. ###### 0x91e4534b — skeleton list ``` u32 Count u32 BoneName[Count] StrCode32 ``` TppHeliEast declares 21: `SKL_000_ROOT`, `SKL_002_GUN`, `SKL_004_ROTORCONT`, `SKL_006_SUBROTOUT`, `SKL_008_LLWDOOR`, `SKL_010_RUPDOOR`... — the helicopter rig. ##### Sizing rules — derive, never scan Both original sizing routines guessed by scanning for magic values, and both could run off the end of the file. Sizes come from layout boundaries instead: - **event package**: packages are contiguous and are the last section, so each runs to the next one's offset and the final one to EOF. - **chunk**: runs from its offset to the first gani body. The scans survive only as bounded fallbacks. ##### Authoring A new archive needs a hand-written XML plus the payload files; the table, hashes, offsets, sizes and alignment are all derived. Verified: a 3-entry archive built from scratch unpacks correctly with a properly hash-sorted table. The one hard requirement is a **`.trk`** — it pins the track layout every clip must match, so a new archive for an existing rig reuses that rig's `.trk`. A novel skeleton needs the `.trk` payload format decoded, which is not done. ##### Moving ganis between the two games ``` raw Ground Zeroes Version 201304220 Flags 0x0 -> 16-byte v1 table, NO common TrackHeader MGSV TPP Version 201403250 Flags 0x1000 -> 32-byte v2 table, ONE shared TrackHeader ``` `MtarFile::GetCommonTrackHeader` returns null unless `Flags & NEW`, so **a GZ archive has no shared track layout — each gani carries its own. A TPP gani does not; it depends on the archive's common TrackHeader.** That is the real portability boundary, and it is why clips must be transcoded rather than copied. What makes the port possible anyway: the human rig is unchanged between the games — GZ `hostage_layers` and TPP `player2_*` both declare **UnitCount 18, SegmentCount 56**. Different rigs are not interchangeable (GZ `TppHeliEast_layers` is UnitCount 22, SegmentCount 24). So moving a clip needs three things to line up: 1. **container version** — rebuild the entry table, v1 (16 bytes) <-> v2 (32 bytes); 2. **track layout** — source and destination `UnitCount`/`SegmentCount` must match, which is the check the transcoder already enforces against the destination `.trk`; 3. **motion-point units** — every `MTP_*` the clip uses must be declared in the destination's MotionPointUnitTable, and `MotionPointUnitCount` must cover it. ##### Importing clips — the table has to grow `.mtp` tracks use the SAME layout as the shared track info: `TrackHeader`, unit offsets at +0x14 self-relative to the payload start, each unit's first u32 being an `MTP_*` name. That is `AnimFile::GetMotionPointIndex` walking it. A clip's units must all appear in the destination's MotionPointUnitTable, or `GetMotionPointParent` returns 0 and the point has no bone to hang off. Konami's archives are always self-consistent — player2_ladder declares 2 and uses 2. Importing GZ clips broke that: the same archive then used 9. `transcode` now merges each imported clip's units into the table, taking the bone from the source gani's own parent records (FoxData node `0xf0f377d9`, pairs indexed by unit index, second word = bone — exactly what `GetMotionPointParent` reads). Verified: **0 undeclared units across all 17 converted archives**, 131 units added. ##### Names, not hashes Bone and motion-point ids are StrCode32 and both vocabularies ship as dictionaries, so the XML carries `SKL_023_RHAND` and `MTP_LHAND_A`. Writing accepts either form — anything that is not exactly 8 hex digits is hashed — so an edited file still round-trips byte for byte. The 28 `MTP_*` names came out of GZ archives with `ganis --mtp-names`, which harvests the literal strings and forward-hashes each one. That needs no knowledge of GZ's name-table layout, which is just as well: `0xeab12d21` is the `.sand` ROOT node in TPP, and no engine function reads a motion-point name table, so a parse of it could not be checked against anything. The 18 track-unit names in the player rig resolve in no dictionary and are left as hashes. ##### Still open - `TrackData.DataOffset` is stored but never dereferenced by the runtime — `ChangeTimeFast`, `GetTrackControlSize` and the TrackControl ctor all index keyframes by `SegmentId` instead and only use `&record->DataOffset` as the record's own address. Carried as authored. - The skeleton list's fixed 12-byte trailer. `MakeMatchList2` reads exactly `Count` hashes and stops, so nothing in the engine consumes it; purpose unidentified. ### `foxparser:MgsvModBldr.Tools.Ui/FORMATS.md` #### Fox UI formats: GZ vs TPP delta specs (RE notes) 09/07/2026 ##### STATUS: all four converters BUILT and gated (test ui = 2189/0 suite-wide) - uilb/uigb: byte-identical round-trips (320+762 / 77+64) + convert gates. - uif: geometry/ref equivalence gate 331/331 (independent TPP-layout parse). - uia: copy (identity proven). - CLI: `modbldr-tools gzui [-o out]`. ##### Late corrections (trust these over older sections) - uif GZ string table = u64 StrCode64 × header@0x0C (count = ENTRY count, no /2 halving — FoxUiEditor's reader was wrong). - uigb GZ header: @0x24 = links+params POOL (== TPP buffers), @0x1C = pool SIZE; StrCode64 table at pool+size; path strings after it. (The reader's "@0x24 = strT" was wrong.) - uigb layout entry GZ 8 B == first 8 B of TPP's 12 B; append {ffff,0}. - uigb SetText params: GZ 72 B → TPP 64 B; tail 4×u32 → 4×u8 + pad; done IN PLACE (parB=64, pool keeps 8 slack bytes → no offset cascades). - uif technique table @hdr 0x2C (rel buffers): {str32 technique, u32 const} before pathIds; const stable per technique corpus-wide (LyBL=359, LyADD=1651, LyMUL=17803...). Emitted from the file's str-table technique. - uif vertex controls: GZ 16 B {desc8, f32 a, f32 b} → TPP 24 B {desc8, vec4}; desc u32@+4 = runtime destination (kept verbatim, fail-soft — verify in-game). - uif common prio: GZ f32@0x38 × 4095 → TPP i16@+2 (corpus: 0.5→2047, 0.1→409, 1.0→4095), clamped to i16. - uif stencil (typ 4): geometry like mesh; tail +0x24..0x38 verbatim EXCEPT +0x28 u16 = total geometry bytes before strT (== strRel; patched after layout). - GZ "/as/" texture refs: cipher unrecoverable, but PS3 GZ uifs predate it and carry REAL paths → per-(node,slot) join mined `Uif/gz_as_texmap.tsv` (140 refs; embedded resource; conflicts exist from PS3/PC authoring drift — first-wins). TPP ships the entire GZ texture set (texture6_gzs0.dat), so mapped refs all resolve in TPP. ##### In-game debugging findings (09/07/2026 night — all fixed, gates green) - uif buffers: POOLS FIRST. vertsRel=0 <= uvsRel <= colorsRel, all three always set (796/796) — the engine sizes vertex/uv/color streams from the offset deltas. Remap/idx/tri tables AFTER pools. Tables-first + colorsRel = -1 renders alpha textures as opaque white boxes. - uif header flags: bit1 set on every TPP file — OR it in on convert. - uif TEXT nodes: POSITIONAL tail right after the 0x8C(GZ)/0x88(TPP) base — {u16,u16} pair list + 8 B shader-param entries, all str-table INDEX based → copy verbatim, no rebase. 97/486 GZ text nodes have one (up to ~3 KB). Truncating it = engine walks garbage when building text units (crash). - GZ vertex control record = 16 B {desc 8, f32 a, f32 b} (not 8) → TPP 24 B {desc 8, vec4 (a,b,0,0)}; desc u32@+4 = runtime dest, keep verbatim. - Packaging: TPP's fpkd PRELOADS layout paths at boot (e.g. hud_lmenu/equip_cross.uilb) — those paths must keep TPP-parseable content; ship GZ top layouts at their own gz/ paths and let the (converted) graph reference them. ##### Equip cross staging (09/07/2026) `C:\rsearch\gz_equip_cross_mod\` = 79 files at game paths: converted gz_equip_cross.uigb (+ copy at TPP's GraphAsset .../ld_layer/equip_cross.uigb), 5 uilb, 7 uif (texmapped, prio-scaled), ~60 uia. TPP's own cross lives in chunk0 `.../pack/ui/ui_default_data2.fpk`. 6 meshes carry fail-soft controls. Goal: convert GZ-era uilb/uif/uigb/uia to TPP so GZ UI assets load in TPP. Evidence: GZ loader FUN_14128e4b0 (MgsGroundZeroes.exe Ghidra export), TPP loader fox::ui::GraphResourceLayout::SetupResourceFromRawFile (Tpp_main_win64 dev exe, VA 0x141c5f9b0), fixture pair `test_fixtures/ui/ui format examples/uilb/PC {GZ,TPP}/UI_bino.uilb`. Status ledger: VERIFIED = byte-checked vs real files + both loaders. ##### Cross-format facts (VERIFIED) - GZ id tables hold u64 **StrCode64(name)**; TPP holds u32 **StrCode32(name)**; StrCode32 = low 32 bits of StrCode64 → **conversion = truncation**, works for every id without knowing the plaintext. (bino ids match "UI_bino", "UI_bino_setin", "UI_bino_setout" stems.) - GZ path references are plaintext strings (`/Assets/tpp/...` — GZ already uses the tpp namespace); TPP replaces them with u64 **PathCode64(path)** (QAR/PathServer hash: 51-bit base + 13-bit ext code). Verified: 4/4 bino PathIds = modbldr PathCode64 of the GZ strings, same order. - TPP loaders hard-reject GZ versions (uif: `!= 0x202` @ 0x141c295f7; uilb: u32@4 `!= 0x101`) and contain no string-path fallback → data-side conversion is the only route. - .uia magic 0x0bfca2d2 = GANI family (TPP checks it in fox::anim::GaniBaseFile) and has no GZ/TPP version split in the header — see uia section. ##### UILB (VERIFIED) Common skeleton, little-endian: | off | type | meaning | |------|------|---------| | 0x00 | u32 | 'UILB' | | 0x04 | u32 | GZ: 0x001, TPP: 0x101 (byte4 magic=1, byte5 version 0/1) | | 0x08 | u16 | model count (entries 0x64 B) | | 0x0A | u16 | anim count (entries 0x14 B) | | 0x0C | u16 | camera count (entries 0x34 B) | | 0x0E | u16 | graph count (entries 0x50 B) | | 0x10 | u16 | name-id count | | 0x12 | u16 | path count | | 0x14 | u32 | model table off (abs; -1 = none) | | 0x18 | u32 | anim table off (abs) | | 0x1C | u32 | camera table off (abs; -1 = none) | | 0x20 | u32 | graph table off (abs; -1 = none) | | 0x24 | u32 | id table off RELATIVE to blob (= size of pre-list region) | | 0x28 | u32 | GZ: ABSOLUTE off of string-entry table; TPP: PathId table off RELATIVE to blob | | 0x2C | u32 | blob base (abs). GZ blob: [pre-lists][u64 ids][strings]; TPP blob: [pre-lists][u32 ids][u64 PathIds] | - GZ string entry (at abs @0x28, 8 B each): {u32 len, u32 relOff}; string at blob+relOff, NUL-terminated. - Pre-list region (blob+0 .. blob+@0x24): u16 id-table indexes for model child lists (entry+0x5C relOff into blob, entry+0x60 count) and connection lists. Byte-copy on convert. - Model entry 0x64 B, layouts identical GZ/TPP: +0 u16 nameIdx, +2 u16 pathIdx (uif), +4 u32 flags (0x80→colorFlag4, 2→0x1000, 4→0x4000, 8→billboard, 0x10→stencilModel, 0x20→stencilOut), +8 u32 priority, +0x0C..0x4B transform floats (trans/rot-quat/scale/color; the wiki's mystery 0x803F = 1.0f), +0x4C f32 billboardMin, +0x50 f32 billboardMax (only read by TPP; GZ files carry 0 — byte-copy), +0x54/+0x56 u16 connection id idxs (0xffff none), +0x58 u32 inherit flags (0x1F default), +0x5C u32 child list relOff, +0x60 u16 child count, +0x62 u8 stencilTest. - Anim entry 0x14 B identical: +0 u16 nameIdx, +2 u16 fileIdxA (uia), +4 u16 fileIdxB (paired _s uia, 0xffff none), +0x10 f32 speed. - Camera entry 0x34 B identical: +0 u16 nameIdx, then projection params. - Graph entry 0x50 B identical: +0 u16 nameIdx, +2 u16 pathIdx (uigb), +0x48/+0x4A u16 connection idxs, +0x4E u16 mode. ###### Conversion GZ→TPP 1. u32@4 = 0x101. 2. Byte-copy model/anim/camera/graph tables + pre-list region. 3. id table: each u64 → u32 (truncate). Self-consistency (children, connections, anim keys) is preserved because every reference goes through the same table. 4. Drop string-entry table + strings; emit u64 PathId table in the SAME order = PathCode64(string). Entry indexes in tables stay valid. 5. Recompute @0x28 (= @0x24 + 4*idCount, blob-relative) and @0x2C (shrinks by 8*pathCount: string-entry table removal). 6. Note: GZ/TPP same-name retail files can differ in authoring (TPP bino pre-lists {1,2} vs GZ {0,0}+{1,2}); conversion preserves GZ content, NOT the TPP retail file. ##### UIF (VERIFIED structure; empirics flagged) Evidence: GZ chain FUN_14126d6f0 (SetUp) → FUN_14126bb80 (parse) → FUN_14126c040 (node factory) → FUN_141261f80 (common) / FUN_141268c00+d80+830 (mesh) / FUN_141269020 (vertex controls) / FUN_141258c90 (text). TPP: typed structs in dev Ghidra project (ModelNodeCommonInfo/MeshInfo/ LineInfo/TextInfo/ModelNodeHeader) + FoxBrowser UifReader (796-fixture verified) + fox::ui::Model::CreateAllModelNodes @6423774. ###### Header | off | GZ (0x20 hdr) | TPP (0x30 hdr) | |------|----------------|----------------| | 0x00 | 'UIF ' | same | | 0x04 | u32 0x102 | u32 0x202 | | 0x08 | u16 flags (bit0 → model flag 0x100000) | same | | 0x0A | u16 node count | same | | 0x0C | u16 str count — counts u32 SLOTS (GZ hashes = count/2 u64s!) | u16 count of u32 StrCode32s | | 0x0E | u16 path count | same | | 0x10 | u32 node table off (abs) | same | | 0x14 | u32 str table off rel to buffers | same (u32 entries) | | 0x18 | u32 path ENTRY table off (ABS): {u32 len, u32 relOff}×n, relOff → buffers+relOff cstring; entry.len==-1 → none | u32 PathCode64 table off rel to buffers | | 0x1C | u32 buffers off (abs) | same | | 0x20 | — (header ends) | u32 vertsRel (shared vertex pool, rel buffers) | | 0x24 | — | u32 uvsRel | | 0x28 | — | u32 colorsRel | | 0x2C | — | u32 (== @0x18 dup? assert across corpus) | - Node table both: {i16 nameIdx, u16 type, u32 dataOff(abs)} ×n + 0xFFFF sentinel entry. Types: 0 Null, 1 Common, 2 Mesh, 3 Text, 4 Stencil, 5 Line, 6 Invalid(skip). - GZ nodes link parents by comparing 48-bit StrCode64 (mask 0xffffffffffff; root sentinel = 0xb8a0bf169f98). ###### ModelNodeCommonInfo: GZ 0x50 vs TPP 0x4C | field | GZ | TPP | |---|---|---| | parent name idx | i16 @0x00 | i16 @0x00 | | priority | ??? @0x02 unread; float @0x38 → node+0x98 | i16 @0x02 | | flags | u32 @0x04 (same ModelNodeInfoFlags enum: 1 USE_PALETTE, 0x100 ROT_QUAT, 0x10000 HAS_VERTICES, text align bits 0x100000.., same in both) | u32 @0x04 | | scale vec3 | @0x08 | @0x08 | | rot vec3/quat4 | @0x18 (+W @0x24 if 0x100) | same | | translate vec3 | @0x28 | same | | color rgba | @0x3C | @0x38 | | secondary name idx | u16 @0x4C (unconfirmed) | u16 @0x48 (UnknownSecondaryNameStrCode32Index) | | palette color idx | u16 @0x4E | u16 @0x4A | Conversion: color moves -4; palette/secondary move -4; TPP priority i16 = (short)(GZ float @0x38) — CHECK CORPUS (GZ @0x02 values, float ranges, cross-check same-name pairs UI_bino.uif etc). ###### ModelNodeMeshInfo (at common end: GZ +0x50, TPP +0x4C), field offs rel to mf Identical positions: +0x00 u16 vCnt, +0x02 u16 triCnt, +0x14 u32 triOff, +0x18 u16 vColorCtrlCount, +0x1A u16 vCtrlCount, +0x1C u32 vColorCtrlsOff, +0x20 u32 vCtrlsOff, +0x24 u16 materialInstanceNameIdx, +0x26 u16 shaderTechniqueNameIdx, +0x28 u16 texParamCount, +0x2A u16 shaderParamCount, +0x2C u32 texParamsOff (ABS), +0x30 u32 shaderParamsOff (ABS), +0x34 u32 billboardLimitsOff (ABS → 2 floats min/max). Geometry fields differ: - GZ: +0x04 vertsOff, +0x08 uvsOff, +0x0C colorsOff (flag 0x40000), +0x10 extra buf (node+0x138), all rel-to-buffers DIRECT arrays of 16B Vector4 records, indexed by vertex i. Tris: u16×3 per tri at +0x14 (rel buffers). - TPP: +0x04 vertexRemapOff, +0x08 uvRemapOff, +0x0C colorIndicesOff, +0x10 uvIndicesOff, +0x14 triIndicesOff — u16 remap tables (rel buffers) into SHARED pools at header vertsRel/uvsRel/colorsRel. pos[i]=Verts[remap[i]], uv[i]=UVs[uvRemap[i]], color[i]=Colors[colorIdx[i]]. Conversion: concat GZ per-mesh arrays into shared pools, emit identity remap tables (remap[i]=poolBase+i). Tri indices are logical (0..vCnt) in both — byte-copy. - Tex params both: {u16 slotNameIdx, u16 pathIdx}×count @texParamsOff. - Shader params both: 8B {u16, u16 nameIdx, f32 value} (TPP typedef says {u16 Type, u16 NameIdx, Vector4} — reader uses 8B stride, verified). - Vertex controls: GZ 8B descriptors {u16 nameIdx, u8, u8, u32 relOff → Vector4 at buffers+relOff}; TPP 24B inline {8B descriptor + Vector4}. Repack on convert (exact TPP descriptor semantics: pin via fixtures / BN fox/ui/ModelNodeMesh.cpp during implementation). ###### Text node (GZ +4 shift throughout) Same flag-bit alignment enum. GZ: color idx @0x80, font idx @0x82, billboardOff @0x88 (TPP: 0x7C/0x7E/0x84); font W/H/textSpace/lineSpace bytes follow. TPP TextInfo = common 0x4C + bbox 0x20 + scale vec @0x6C. ###### Stencil/Line Stencil ≈ mesh (own create path, same info layout, flag bit17 variants). Line: TPP ModelNodeLineInfo typedef known ({u16 lineCount, u16 vCnt, linesOff, vertsOff, colorsOff, controls, billboard}); GZ analog direct- buffer. RARE — count corpus occurrences before investing (maybe none in GZ ui set). ###### uif conversion summary 1. Header 0x20→0x30 (add verts/uvs/colors rel + @0x2C), version 0x202. 2. Str table: u64×(count/2) → u32×count' (truncate; header count semantics change: GZ counts u32 slots = 2×hashes, TPP counts hashes — keep INDEXES identical, they already index hash-positions in both). 3. Path entries+strings → PathCode64 table (same order); refs unchanged. 4. Per node: common -4 repack, mesh geometry direct→shared+remap, controls repack, text -4 repack; recompute all dataOffs/table offs. 5. Texture paths (from tex params) are GZ ftex assets — packaging must ship converted GZ ftex (modbldr ftex GZ support) or retarget to TPP textures. Log referenced texture paths per file. ##### UIGB (VERIFIED structure; empirics flagged) Evidence: GZ FUN_141264f40 (ref collector) + FUN_14124c460 (validator); UiCore UigbReader (TPP full parse incl. node graph, GZ branch parses nodes with the SAME body parser); SubtitlesBasic.uigb exists in BOTH fixture sets with identical node count (14) and string count (38) — the Rosetta pair for byte-level diffs. ###### Header | field | GZ | TPP | |---|---|---| | magic | 'UIGB' @0 | same | | u32@4 | 1 | 0x101 (byte5 version 0→1) | | node count | u16 @0x08 | same | | uilb count | u8 @0x0A | same | | uigb count | u8 @0x0B | same | | str count | u16 @0x0C | u32 @0x10 (0x0C u8 = StrCodeCount=0, 0x0D u8 = section6 count) | | path count | u16 @0x0E | same | | node table | u32 @0x10 | u32 @0x14 | | layout table | u32 @0x14 | u32 @0x18 | | section4 (child uigb) | u32 @0x18 | u32 @0x1C | | ??? | u32 @0x1C (0xD8 in SubtitlesBasic — pin via differ) | u32 @0x20 = section5/o2 (-1 in shipped set) | | path table | u32 @0x20 | rel off u32 @0x28 (rel to buffers) | | str table / buffers | u32 @0x24 (StrCode64 table; also base for path strings + params) | strRel u32 @0x2C + strings(-1) @0x30 + buffers @0x34 | | section6 | (none?) | u32 @0x24, count u8 @0x0D — purpose TBD; check if 0/-1 legal across corpus | - Str table: GZ u64 StrCode64 → TPP u32 StrCode32 (truncate; identity verified again — reader keeps low-32 and node types resolve). - Path table: GZ {u32 len, u32 relOff → buffers+relOff cstring} → TPP PathCode64 (hash the string; order/indexes preserved). - Layout entries: GZ 8 B {u16 nameIdx, u16 pathIdx, u16 drawPriIdx, u16 connIdx} → TPP 12 B {u16 nameIdx, u16 pathIdx, u8 flag1, u8 n2, u16 drawPriIdx, u16 connIdx, u16 u1} — synthesize flag1/n2/u1 (pin defaults via Rosetta diff). - Node headers {u16 typeIdx, u16 nameIdx, u8 size, u8 type} + per-type inline bodies (Page/Phase 6, Event 30, Action 34, Operation 26 B): SAME in both (GZ parses fine with the TPP body parser). Bodies carry ABSOLUTE offsets (input edges 8 B {nodeIdx,prop1,prop2 u16}, out edges 4 B) and buffers-RELATIVE param offsets + link pool cursor — all must be rebased on write. - Param blobs: type-specific packed values; refs are table INDEXES (survive conversion if table order kept). Diff Rosetta params to confirm no encoding drift. - Section4 (child graphs): GZ 0x54 B entries {u16 nameIdx, u16 pathIdx, ..., u8 loadFlag @+7?}; TPP stride ~12 (derived). Rare (uigbCount>0); pin via corpus scan. - GZ sentinel StrCode64 0xb8a0bf169f98 (="empty/root") skipped in ref walks. ###### Rosetta findings 09/07/2026 (SubtitlesBasic GZ 0x517 vs TPP 0x449) - Node tables IDENTICAL node-for-node: same type/name INDEXES, sizes, kinds, edge counts. Only offsets shift (+0x10 = header growth 0x28→0x38) and param offsets/sizes differ per kind. - File order GZ: hdr, nodes, edge pools (8 B in-edges, then frefs, then 4 B out-edges — exactly filling to layoutT), layoutT, pathT, StrCode64 table, PARAMS pool, links, path strings. File order TPP: hdr, nodes, edge pools, layoutT, section6, buffers (= [4 B?][links u16×n][params]), StrCode32 table, PathCode64 table. - GZ @0x1C = params pool total SIZE (0xD8 = exact span of all parB). Params pool sits after the StrCode64 table (base needs 1 more probe — first par@16 suggests a 16 B pool head: 4 unknown + 3 links + pad). - Param blobs embed RAW StrCode64 VALUES (48-bit) in BOTH games (TPP kind-13 params: 3×StrCode64 + 4 floats + box floats 32/48 + flags) — params are NOT index-based for hashes. Sizes differ per kind: Action kind=13: GZ 72 → TPP 64 (-8); kind=8: 2=2; kind=3: 40=40; Event: 8=8. Per-kind translation tables needed (diff more pairs: SubtitlesSideshow + kind census over 77 GZ files). - GZ pathT can contain EMPTY entries {len=0} (TPP drops them — converter should too, remapping path indexes). - TPP section6 (count@0x0D, off@0x24): 12 B/entry sample `00000000 60010000 00000000` — purpose TBD; GZ has no equivalent. - TPP file ends with 1 stray byte after pathT (0x449) — align/terminator, check corpus. ###### Semantic caveat (validation phase) Node TypeHash = StrCode32 of node class name. GZ-era native callback classes (EvCall/Act nodes) must exist in the TPP exe to instantiate. Inventory all GZ TypeHashes across the 77 GZ uigb fixtures, resolve against TPP's registered classes, report unmapped (those nodes will be inert or need substitution). ##### UIA (VERIFIED identical — no conversion) FoxData container (magic 0x0bfca2d2, 32 B header, 48 B nodes, TrackHeader payloads), GANI family. BOTH games key nodes by 32-bit hash (GZ uses fox::SearchDataNodeHash32 too — FUN_140dc8040), so uia carries StrCode32- compatible ids natively; uilb name ids truncate to exactly these. Cross-parse proof 09/07/2026: 1053/1053 GZ + 1097/1097 TPP fixtures parse with the same layout (uia_crossparse.py), zero failures. Conversion = copy the file. (Segment codecs = shared anim codecs; in-game test is the final gate.) ## FtexTool — FTEX/DDS conversion ### `ftex:README.md` FtexTool ======== [![Build status](https://ci.appveyor.com/api/projects/status/fyes86rw8kb6xcj5?svg=true)](https://ci.appveyor.com/project/Atvaark/ftextool) A tool for converting files between Fox Engine texture (.ftex) and DirectDraw Surface (.dds). Requirements -------- ``` Microsoft .NET Framework 4.5 SharpZipLib ``` Usage -------- ``` FtexTool [options] input [output_folder] ``` Options: -------- ``` -h|help Displays the help message -t|type [type_name] d|diffuse (default) m|material n|normal c|cube -fl|flags [flag_name] Default (default) Clp Unknown -f|ftexs [number] e. g. 3 to create up to 3 ftexs files 0 to embed all ftexs files inside the ftex file -i|input file_name|folder_Name -o|output folder_name ``` Examples -------- Converting an .ftex file to .dds: ``` FtexTool file_name.ftex ``` Converting all .ftex files in a folder to .dds: ``` FtexTool folder_name ``` Converting a .dds file to .ftex: ``` FtexTool file_name.dds ``` Converting a .dds file to an .ftex and 3 .ftexs files: ``` FtexTool -f 3 file_name.dds ``` Converting a .dds normalmap file to .ftex ``` FtexTool -t n file_name.dds ``` Converting a .dds Clp file to .ftex ``` FtexTool -fl Clp file_name_clp.dds ``` Important -------- * When repacking custom textures remember to also repack all .pftxs files that contain the changed files with the [GzsTool](https://github.com/Atvaark/GzsTool) * Fox Engine uses the pixel format DXT1 for textures without alpha channel and DXT5 for textures with alpha channel. Changing the pixel format could lead to unexpected results. * Fox Engine 2015 (MGSV) doesn't support embedding .ftexs files inside .ftex files. ## FoxEngineTemplates — 010 binary templates for the formats ### `templates:BynaryData.bt` ```cpp #include "common/common.bt" #include "common/gr_sh_common.bt" typedef struct { uint Time ; VectorB4 Color; float Scale; } LightKeyframe ; typedef struct { enum WEATHER_TYPE { Clear=0, Cloudy=1, Rainy=2, Foggy=3, SandStom=4,//[sic] } WeatherType; uint KeyframeCount ; uint DataOffset ; FSeek(DataOffset); local uint i; for(i = 0; i < KeyframeCount; i++) LightKeyframe Keyframes; } LightTrackHeader ; struct BynaryDataHeader { uint Version; Assert((Version & 0x7fffffff) == 0); uint TotalSize; uint WeatherCount; } Header ; local uint i; for(i = 0; i < Header.WeatherCount; i++) { FSeek(startof(Header) + sizeof(Header) + 12 * i); LightTrackHeader Tracks; } ``` ### `templates:ExecCommand.bt` ```cpp //first intparam struct Header{ short version; enum Flags { DISABLE=0x1, SKIP=0x2, MULTIGROUP=0x4, INTERPOLATE=0x8, UNKNOWN5=0x10 } flags; } header; //second intparam struct ParamGroupsInfo{ short intIndexToEventParamCount; short eventParamGroupCount; } paramGroupsInfo; //2.5th intparams if ( header.flags & SKIP ) { struct TimeSection{ int startFrame; int endFrame; } timeSection; }; //third intparam(s) FSeek(paramGroupsInfo.intIndexToEventParamCount*4); struct ParamGroupInfo{ short intIndexToIntValues; ubyte paramCount; ubyte isInterpolate; } paramGroupInfo[paramGroupsInfo.eventParamGroupCount]; //event param definitions local int paramGroupIndex; local int paramIndex; for (paramGroupIndex = 0; paramGroupIndex < paramGroupsInfo.eventParamGroupCount; paramGroupIndex++) { FSeek((paramGroupInfo[paramGroupIndex].intIndexToIntValues*4)); struct ParamGroup { for (paramIndex = 0; paramIndex < paramGroupInfo[paramGroupIndex].paramCount; paramIndex++) { FSeek(paramGroupInfo[paramGroupIndex].intIndexToIntValues*4+paramIndex*8); struct Param{ short valueIndex; enum PropertyType { Int8 = 0, UInt8 = 1, Int16 = 2, UInt16 = 3, Int32 = 4, UInt32 = 5, Int64 = 6, UInt64 = 7, Float = 8, Double = 9, Bool = 10, String = 11, Path = 12, EntityPtr = 13, Vector3 = 14, Vector4 = 15, Quat = 16, Matrix3 = 17, Matrix4 = 18, Color = 19, FilePtr = 20, EntityHandle = 21, EntityLink = 22, PropertyInfo = 23, WideVector3 = 24 } paramType; ubyte flag;//? uint paramName; } param; } } paramGroup; } //integer values for (paramGroupIndex = 0; paramGroupIndex < paramGroupsInfo.eventParamGroupCount; paramGroupIndex++) { for (paramIndex = paramGroupInfo[paramGroupIndex].paramCount; paramIndex-- > 0; paramIndex) { switch(paramGroup[paramGroupIndex].param[paramIndex].paramType) { case Int8: case UInt8: case Int16: case UInt16: case Int32: case UInt32: case Bool: uint value; break; default: break; }; } } ``` ### `templates:MogDetector.bt` ```cpp // char sig[16]; typedef struct { uint a, b; }TupleAddr; string ReadTuple(TupleAddr &t) { string s = ""; SPrintf(s, "(%u, %u)", t.a, t.b); return s; } typedef struct { int hash0; int unkn[4]; int hash1; int dat[12]; }TestSubEntry; typedef struct { uint addr; //float weight; (Does not appear to be a float for player) uint tag1; uint tag2; uint flags; uint hash; TupleAddr addr0; TupleAddr addr1; TupleAddr addr2; }LayerDef; typedef struct { int a; uint b; LayerDef def[4]; int unkn[8]; short c; short count; TestSubEntry test[count]; }Layer; string ReadLayer(Layer &l) { string s = ""; SPrintf(s, "count: %u (c=%d)", l.count, l.c); return s; } typedef struct { int id; int hash0; uint hash1; uint flags; }EntryHeader; string ReadEntHeader(EntryHeader &e) { string s = ""; SPrintf(s, "sig: %d, hash0: %d, hash1: %u, flags: %u", e.id, e.hash0, e.hash1, e.flags); return s; } local int i =0; local int t =0; local int e =0; local int bac = 0; do { FSeek(i * 16); int a; if(a[i] == 6) { bac = i*16; FSkip(8); int b; if(b[t] < 10) { FSeek(bac); EntryHeader header; Printf("\nEntry[%d].pos = %d", e, bac); if(e > 0) Layer layer; ++e; } ++t; } else FSkip(12); ++i; } while(FTell() < FileSize()-16); ``` ### `templates:README.md` #### Fox Engine Templates Fox Engine file format 010 Editor templates. #### Special Thanks To Atvaark BobDoleOwndU caplag (AKA kapuragu AKA rlc) Half Way Lambda HeartlessSeph Highflex id-Daemon Jayveer Joey35233 Kaz Mana Morbidslinky (AKA CalibratedMishap AKA Joseph Zoeller) MrDev (AKA JohnHudeski AKA NewStudent) OldBanana sai (AKA youarebritish) SecaProject Shigu (AKA NoShigu) tinmantex unknown321 Ventos ### `templates:adm.bt` ```cpp LittleEndian(); #include "common/common.bt" struct AdmHeader { char Signature[4] ; Assert(Signature == "ADML"); ushort GridSize ; // Meters ushort CellCountX ; ushort CellCountZ ; // Bounds: ushort MinX ; // (MinX, MinX + (CellCountX - 1) * GridSize) ushort MinZ ; // (MinZ, MinZ + (CellCountZ - 1) * GridSize) } Header; FAlign(16); struct AdmCell { ushort MainAmbientIndex : 3; // TppSoundWorld.ambientParameter[] ushort SecondaryAmbientIndex : 3; // TppSoundWorld.ambientParameter[] ushort SecondaryRtpcValue : 4 ; // MainRtpcValue = 1.0f - SecondaryRtpcValue, seems to be for `ambient_volume` rtpc - see tpp::sd::AmbientSourceBody::ExecAmbientUpdate for more ushort Padding : 6 ; Assert(Padding == 0); } Cells[Header.CellCountX * Header.CellCountZ] ; ``` ### `templates:atsh.bt` ```cpp #include "common/common.bt" #include "common/gr_sh_common.bt" typedef struct(int selfIndex) { local int SelfIndex = selfIndex; // Band Basis VectorH3 c00; // 0 0 VectorH3 c10; // 1 -1 VectorH3 c11; // 1 0 VectorH3 c12; // 1 1 VectorH3 c20; // 2 -2 VectorH3 c21; // 2 -1 VectorH3 c22; // 2 0 VectorH3 c23; // 2 1 VectorH3 c24; // 2 2 VectorH3 SunColor; // a0 = sqrt(1/(4pi)) = 0.282095 // a1 = sqrt(3/(4pi)) = 0.488603 // a2 = sqrt(15/(4pi)) = 1.092548 // a3 = sqrt(5/(16pi)) = 0.315392 // a4 = sqrt(15/(16pi)) = 0.546274 // Stored in SH matrix used in SH_SphereMap.hlsl: // [ +a4*c24 , a2*c20/2 , a2*c23/2 , a1*c12/2 ] // [ a2*c20/2 , -a4*c24 , a2*c21/2 , a1*c10/2 ] // [ a2*c23/2 , a2*c21/2 , 3*a3*c22 , a1*c11/2 ] // [ a1*c12/2 , a1*c10/2 , a1*c11/2 , a0*c00-a3*c22 ] } CoefficientSet ; string ReadCoefficientSetString(uint time, int index) { return index < 0 ? "" : ReadUInt24HTime(time); } typedef struct { local uint numDiv = parentof(this).Parameter[GetFoxDataNodeParamIndex(parentof(this), "numDiv")].Value; local uint numWeathers = parentof(this).Parameter[GetFoxDataNodeParamIndex(parentof(this), "numWeathers")].Value; uint Times[numDiv] ; FAlign(16); local int i = 0; for (i = 0; i < numWeathers; i++) { struct { local uint k; for (k = 0; k < numDiv; k++) CoefficientSet Times(k); } Weathers; } } AtmosphereSHCoefficients ; #define FOX_DATA_PAYLOAD AtmosphereSHCoefficients #include "common/FoxData_common.bt" FoxDataHeader Header; Assert(Header.Version == 1); FSeek(Header.NodesOffset); FoxDataNodes Nodes; FAlign(16); Assert(FTell() == FileSize()); ``` ### `templates:caar.bt` ```cpp #include "mtar.bt" ``` ### `templates:common/FoxData_common.bt` ```cpp #ifndef FOXDATA_COMMON_BT #define FOXDATA_COMMON_BT #include "common/common.bt" // For TRAP, the FoxDataHeader string hash is known to be a StrCode32. So globally overriding for stuff like GeoNameHashes, which may literally not exist at all outside of material names, may not be right. #ifndef FOX_DATA_HASH_TYPE #define FOX_DATA_HASH_TYPE StrCode32 #endif enum FOX_DATA_NODE_ENTRY_PARAM_TYPE { FOX_DATA_NODE_ENTRY_PARAM_TYPE_UINT = 0, FOX_DATA_NODE_ENTRY_PARAM_TYPE_STRING = 1, FOX_DATA_NODE_ENTRY_PARAM_TYPE_FLOAT = 2, }; typedef struct { FOX_DATA_HASH_TYPE Hash; uint StringOffset; } FoxDataName ; string ReadFoxDataName(FoxDataName& str) { #ifdef FOX_DATA_RESOLVE_HASH_FUNC local string resolvedName = FOX_DATA_RESOLVE_HASH_FUNC(str.Hash); if (resolvedName != "") return resolvedName; #endif if (str.StringOffset == 0) if (str.Hash.hash == 3205930904 || str.Hash.hash == 0) // Empty string hash return "null"; else return Str("%u", str.Hash.hash); else if (str.Hash.hash == 2283831924 || str.Hash.hash == 4127755893 || str.Hash.hash == 981817376) // Hack for ObjectBrush (.obr, not .obrb), AtmosphereSHCoefficients (.atsh), and LightProbeSHCoefficients (.lpsh) which use an absolute string offset for this particular string for some reason return ReadString(str.StringOffset); else return ReadString(startof(str) + str.StringOffset); } typedef struct { FOX_DATA_NODE_ENTRY_PARAM_TYPE Type; short NextParameterOffset; FoxDataName Name; switch (Type) { case FOX_DATA_NODE_ENTRY_PARAM_TYPE_UINT: uint Value; break; case FOX_DATA_NODE_ENTRY_PARAM_TYPE_STRING: FoxDataName Value; break; case FOX_DATA_NODE_ENTRY_PARAM_TYPE_FLOAT: float Value; break; default: Assert(false, "Unknown parameter type."); break; } } FoxDataNodeParameter ; string ReadFoxDataNodeParameter(FoxDataNodeParameter& param) { switch (param.Type) { case FOX_DATA_NODE_ENTRY_PARAM_TYPE_UINT: return Str("uint %s = %u", ReadFoxDataName(param.Name), param.Value); case FOX_DATA_NODE_ENTRY_PARAM_TYPE_STRING: return Str("string %s = %s", ReadFoxDataName(param.Name), ReadFoxDataName(param.Value)); case FOX_DATA_NODE_ENTRY_PARAM_TYPE_FLOAT: return Str("float %s = %f", ReadFoxDataName(param.Name), param.Value); default: return "null"; } return result; } struct FoxDataNode; typedef struct { FoxDataNode Node; if (Node.NextNodeOffset != 0) { local int64 nodeStartPos = startof(Node) + Node.NextNodeOffset; do { FSeek(nodeStartPos); FoxDataNode Node; nodeStartPos += Node.NextNodeOffset; } while (Node.NextNodeOffset != 0); } } FoxDataNodes ; typedef struct { FoxDataName Name ; uint Flags ; // Unknown. Greatest diversity is in GEOM and HTRE nodes. Most other formats have 0 or 1 (see their asserts for details). int DataOffset ; // 0 means no data uint DataSize ; // 0 means no data int ParentNodeOffset ; // Surmised based on confirmation of ChildNodeOffset and behavior (if slightly wonky; see htre.bt for details) in HTRE V3 format. int ChildNodeOffset ; // Confirmed thanks to PES SO int PreviousNodeOffset ; // 0 means no previous nodes int NextNodeOffset ; // 0 means no more nodes int ParametersOffset ; // 0 means no params FAlign(16); if (ChildNodeOffset != 0) { FSeek(startof(this) + ChildNodeOffset); FoxDataNodes Children; } #ifndef FOX_DATA_NO_USE_PARAMS // For some reason, TRAP files hack this to use as the entry count if (ParametersOffset != 0) { local int64 paramStartPos = startof(this) + ParametersOffset; do { FSeek(paramStartPos); FoxDataNodeParameter Parameter; paramStartPos += Parameter.NextParameterOffset; } while(Parameter.NextParameterOffset != 0); } #endif #ifdef FOX_DATA_PAYLOAD #ifdef FOX_DATA_FLAG_IS_HAS_PAYLOAD if (DataOffset != 0 && (Flags & 1 || DataSize != 0)) #else if (DataSize != 0 && DataOffset != 0) #endif { FSeek(startof(this) + DataOffset); FOX_DATA_PAYLOAD Payload; } #endif } FoxDataNode ; int GetFoxDataNodeParamIndex(FoxDataNode& node, string name) { local uint pIdx; for (pIdx = 0; exists(node.Parameter[pIdx]); pIdx++) { if (Strcmp(ReadFoxDataName(node.Parameter[pIdx].Name), name) == 0) return pIdx; } return -1; } int GetFoxDataNodeIndex(FoxDataNodes& nodes, string name) { local uint nIdx; for (nIdx = 0; exists(nodes.Node[nIdx]); nIdx++) { if (Strcmp(ReadFoxDataName(nodes.Node[nIdx].Name), name) == 0) return nIdx; } return -1; } typedef struct { #ifdef FOX_DATA_FORCE_LITTLE_ENDIAN LittleEndian(); #define FOX_DATA_FORCED_ENDIAN #endif #ifdef FOX_DATA_FORCE_BIG_ENDIAN BigEndian(); BitfieldRightToLeft(); #define FOX_DATA_FORCED_ENDIAN #endif #ifndef FOX_DATA_FORCED_ENDIAN if (ReadUShort() == 0 || ReadUInt() == 372637195 || ReadUInt() == 1144389900) // 201209110, 201406020 { BigEndian(); BitfieldRightToLeft(); } else { LittleEndian(); } #endif uint Version; uint NodesOffset; uint FileSize; FoxDataName Name; uint Flags; FAlign(16); } FoxDataHeader ; #endif ``` ### `templates:common/anim_FoxData.bt` ```cpp string ResolveHashFunc(StrCode32& hash) { switch (hash.hash) { case 3933341002: return "ROOT"; case 3254096966: return "DEMO"; case 2620425302: return "CAMERA"; case 3150281601: return "MOVE"; case 2862912361: return "CameraParam"; case 1885607306: return "SI Frame"; case 1889896775: return "SKEL"; case 2454300086: return "MESH_EVENT"; case 143688520: return "MOTION"; case 3337172921: return "UNIT"; case 2215748180: return "MODEL"; case 3736262940: return "SKELINFO"; case 917055795: return "MTPINFO"; case 2846912397: return "MTEV"; case 494270195: return "MTP"; case 371357229: return "EVP"; case 2250865118: return "SHADER"; case 3937479969: return "MTP_LIST"; case 4042487769: return "MTP_PARENT_LIST"; case 2447659851: return "SKL_LIST"; case 3187573380: return "LOCATOR"; case 2036377104: return "GLOBALSRT"; case 2053459263: return "FRAGMENT"; // Parameter names case 2570203771: return "TARGET_NAME"; case 3426329078: return "SLOPE_DIR"; case 35201703: return "SLOPE_ANGLE"; // Shader nodes case 1097923221: return "TENSION_CHEEKL"; case 890100143: return "TENSION_CHEEKR"; case 2155534022: return "TENSION_NECK"; default: return ""; } } struct FoxDataName; struct ANIM_FOX_DATA_PAYLOAD { switch (ResolveHashFunc(parentof(this).Name.Hash)) { case "MOVE": case "CameraParam": case "SI Frame": case "SKEL": case "UNIT": case "FRAGMENT": case "CAMERA": case "MOTION": case "GLOBALSRT": case "MTP": Assert(parentof(this).Flags == NODE_TYPE_TRACKS); TrackHeader Tracks; break; case "MTP_LIST": case "MTP_PARENT_LIST": Assert(parentof(this).Flags == NODE_TYPE_STRINGDATA); StringData List ; break; case "SKL_LIST": Assert(parentof(this).Flags == NODE_TYPE_STRINGDATA); #ifdef FILE_TYPE_GANI //Assert((Header.Flags & GANI_HEADER_FLAGS) == 0); #endif StringData List ; break; case "EVP": Assert(parentof(this).Flags == NODE_TYPE_EVENTS); EvpHeader MotionEvents; break; default: { // Each keyframed shader property is a child node of SHADER with the name of the property Assert(parentof(this).Flags == NODE_TYPE_TRACKS); if (parentof(this).ParentNodeOffset != 0) { if (ReadUInt(startof(parentof(this)) + parentof(this).ParentNodeOffset) == 2250865118 /*SHADER*/) { TrackHeader Tracks; } } } } }; #define FOX_DATA_FLAG_IS_HAS_PAYLOAD #define FOX_DATA_RESOLVE_HASH_FUNC ResolveHashFunc #define FOX_DATA_PAYLOAD ANIM_FOX_DATA_PAYLOAD #include "common/FoxData_common.bt" ``` ### `templates:common/anim_common.bt` ```cpp #ifndef ANIM_COMMON_BT #define ANIM_COMMON_BT typedef struct { ushort value ; } AnimHalf ; string ReadAnimHalf(AnimHalf& animHalf) { local uint num1 = (animHalf.value & 0x7C00); if (num1 > 0) num1 = (num1 + 0x1dc00) << 13; num1 |= ((animHalf.value & 0x8000) << 16) | ((animHalf.value & 0x3FF) << 13); local ubyte value[4]; value[0] = (ubyte)((num1 >> 0) & 0xFF); value[1] = (ubyte)((num1 >> 8) & 0xFF); value[2] = (ubyte)((num1 >> 16) & 0xFF); value[3] = (ubyte)((num1 >> 24) & 0xFF); float result = ConvertBytesToFloat(value); return Str("%f", result); } enum SEGMENT_TYPE { SEGMENT_TYPE_QUAT = 0, SEGMENT_TYPE_FLOAT = 1, SEGMENT_TYPE_VECTOR2 = 2, SEGMENT_TYPE_VECTOR3 = 3, SEGMENT_TYPE_VECTOR4 = 4, SEGMENT_TYPE_QUAT_DIFF = 5, SEGMENT_TYPE_VECTOR_DIFF = 6, }; typedef struct { AnimHalf x; AnimHalf y; AnimHalf z; } VectorAnimH3 ; typedef struct { AnimHalf x; AnimHalf y; AnimHalf z; AnimHalf w; } VectorAnimH4 ; // These are not padded! BitfieldDisablePadding() needs to be called before using them. // The frame count after each instance is also not padded! typedef struct { ushort Theta : 12; ushort Y : 12; ushort Z : 12; ushort X_Sign : 1; ushort Y_Sign : 1; ushort Z_Sign : 1; } QuatAnim12; typedef struct { ushort Theta : 13; ushort Y : 13; ushort Z : 13; ushort X_Sign : 1; ushort Y_Sign : 1; ushort Z_Sign : 1; } QuatAnim13; typedef struct { ushort Theta : 15; ushort Y : 15; ushort Z : 15; ushort X_Sign : 1; ushort Y_Sign : 1; ushort Z_Sign : 1; } QuatAnim15; struct SegmentKeyframeData(SEGMENT_TYPE type, ubyte componentBitSize) { switch (type) { case SEGMENT_TYPE_QUAT: switch (componentBitSize) { case 12: QuatAnim12 Value; break; case 13: QuatAnim13 Value; break; case 15: QuatAnim15 Value; break; default: Assert(false); break; } break; case SEGMENT_TYPE_FLOAT: switch (componentBitSize) { case 16: AnimHalf Value; break; case 32: float Value; break; default: Assert(false); break; } break; case SEGMENT_TYPE_VECTOR3: switch (componentBitSize) { case 0: break; case 16: VectorAnimH3 Value; break; case 32: Vector3 Value; break; default: Assert(false); break; } break; case SEGMENT_TYPE_VECTOR4: switch (componentBitSize) { case 16: VectorAnimH4 Value; break; case 32: Vector4 Value; break; default: Assert(false); break; } break; case SEGMENT_TYPE_QUAT_DIFF: switch (componentBitSize) { case 12: QuatAnim12 Value; break; case 15: QuatAnim15 Value; break; default: Assert(false); break; } break; case SEGMENT_TYPE_VECTOR_DIFF: switch (componentBitSize) { case 32: Vector3 Value; break; case 16: VectorAnimH3 Value; break; default: Assert(false); break; } break; default: Printf("@%Lx Unknown component bit size: %u\n", FTell(), componentBitSize); Assert(false); break; } }; struct TrackDataBlob(SEGMENT_TYPE type, ubyte componentBitSize, ubyte isStatic) { if (!(componentBitSize == 16 || componentBitSize == 32)) BitfieldDisablePadding(); SegmentKeyframeData FirstKey(type, componentBitSize); if (!(componentBitSize == 16 || componentBitSize == 32)) BitfieldEnablePadding(); if (!(componentBitSize == 16 || componentBitSize == 32)) BitfieldDisablePadding(); if (isStatic == 0) { local uint frameIndex = 0; do { struct AnimKeyframe(SEGMENT_TYPE type, ubyte componentBitSize) { ubyte FrameCount : 8; SegmentKeyframeData Data(type, componentBitSize); } Key(type, componentBitSize); frameIndex += Key.FrameCount; } while (frameIndex < FrameCount); } if (!(componentBitSize == 16 || componentBitSize == 32)) BitfieldEnablePadding(); FAlign(2); }; typedef enum { TRACK_UNIT_FLAGS_LOOP = 0x1, TRACK_UNIT_FLAGS_HERMITE_VECTOR_INTERPOLATION = 0x2, TRACK_UNIT_FLAGS_IS_STATIC = 0x4, } TRACK_UNIT_FLAGS ; string ReadTrackUnitFlags(TRACK_UNIT_FLAGS flags) { local string result = flags == 0 ? "" : "| "; local ubyte i; local string enumName; local TRACK_UNIT_FLAGS temp; for (i = 1; i < 0x8; i = i << 1) { temp = flags & i; enumName = EnumToString(temp); if (enumName != "") result += " " + enumName + " |"; } return result; } local int disableTrackData = false; typedef struct { int UnitCount; uint SegmentCount; ushort Id; byte UnknownA ; Assert(UnknownA == 0); byte UnknownB; Assert(UnknownB == 1||UnknownB == 3); //cypr_hall001_rbbl002.mtar, rbbl001, door006_rbbl001 is 3 uint FrameCount; byte FrameRate; FSkip(3); if (UnitCount > 0) { uint UnitOffsets[UnitCount] ; local uint trkIdx; local uint sgmIdx; for (trkIdx = 0; trkIdx < UnitCount; trkIdx++) { FSeek(startof(this) + UnitOffsets[trkIdx]); struct TrackUnit { // For SAND, hash of the sub object, like a bone, ie SKL_000_WAIST. For GANI, it's the name of a Motion Point. enum TrackName_StrCode32Alias { // CANI, UIA, etc. ROTATE = 283103795, SCALE = 2236677358, TRANSLATE = 2739596730, COLOR = 1662570759, //IK RIG_ROOT = 3552837520, // MTAR TensionController = 2275904709, TensionShift = 2003538961, TensionRate = 853304191, // } Name; ubyte SegmentCount; sgmIdx = sgmIdx + SegmentCount; TRACK_UNIT_FLAGS Flags; ushort Padding ; Assert(Padding == 0); if (SegmentCount != 0) { struct TrackData { int DataOffset; short Id; // Segment id SEGMENT_TYPE Type : 4; ubyte NextEntryOffset : 4; Assert(NextEntryOffset == 0 || NextEntryOffset == 8); // The offset to the next entry is (NextEntryOffset & 0x8). since NextEntryOffset is always 0 or 8, this does nothing. ubyte ComponentBitSize; if (DataOffset != 0 && !disableTrackData) { FSeek(startof(this) + DataOffset); TrackDataBlob Data(Type, ComponentBitSize, Flags & TRACK_UNIT_FLAGS_IS_STATIC); if (NextEntryOffset != 0) FSeek(startof(this) + NextEntryOffset); } } Segments[SegmentCount] ; } } Track; } } } TrackHeader ; struct FoxDataName; struct StringData { uint EntryCount ; local int64 strIdx; for (strIdx = 0; strIdx < EntryCount; strIdx++) { FoxDataName Entry ; } }; struct StringData2 { uint EntryCount ; local int64 strIdx; StrCode32 Entries[EntryCount] ; }; enum NODE_TYPE { NODE_TYPE_STRINGDATA = 0, NODE_TYPE_TRACKS = 1, NODE_TYPE_EVENTS = 3, }; //Hack for PS3 files typedef struct { uint paramA ; uint paramB ; local StrCode param; param.hash = (uint64)paramA | ((uint64)paramB << 32); } PARAM_STRING ; typedef struct { enum EvfCategoryName_StrCode32Alias { Normal = 3371498678, ag = 2079928349, cc = 3342815349, fx = 2569337208, sd = 179473302, vo = 1455888052, } CategoryName; ushort UnitCount ; ushort CacheOffset; if (UnitCount != 0) uint UnitOffsets[UnitCount] ; local uint sIdx; for (sIdx = 0; sIdx < UnitCount; sIdx++) { FSeek(startof(this) + UnitOffsets[sIdx]); struct EventUnitInfo { enum EventUnitInfoName_StrCode32Alias { // fx FX_CREATE_EFFECT_WITH_SKL = 312449893, // ag MTEV_AG_SYNC_L = 877721620, MTEV_AG_SYNC_R = 3647133869, MTEV_FOOT_STOP_R = 2051014260, MTEV_FOOT_STOP_L = 4246579437, MTEV_FOOT_START_R = 3689287927, MTEV_FOOT_START_L = 3049626829, // sd right_foot_ground = 2122718581, right_foot_leave = 3453979597, left_foot_ground = 1190238672, left_foot_leave = 3446064903, rattle_weapon = 2416440354, rattle_suit = 1532442511, // Demo ExecCommand = 595181585, DemoStart = 3541589503, DemoEnd = 3534133658, CreateLocator = 2523762371, CreateModel = 3313525351, VisibleModel = 1040836537, VisibleMesh = 1799953944, DeleteLocator = 826863926, DeleteModel = 1968729831, CreateCamera = 2135789169, DeleteCamera = 4099945744, ClipEnd = 708232468, // 3487515216 - List of StringParams passed to MotionGraphControl::AddCurrentNodeTag (and seemingly removes them at the end with MotionGraphControl::RemoveCurrentNodeTag) } Name; //Printf(Str("%u\n",Name)); byte TimeSectionCount : 6 ; enum TIME_SECTION_FORMAT { TIME_SECTION_FORMAT_INT = 0, TIME_SECTION_FORMAT_SHORT = 1, TIME_SECTION_FORMAT_BYTE = 2, TIME_SECTION_FORMAT_INFINITE = 3, } Format : 2 ; byte IntParamCount ; byte FloatParamCount ; byte StringParamCount ; if (TimeSectionCount != 0) { struct TimeSection { switch (parentof(this).Format) { case TIME_SECTION_FORMAT_INT: int StartFrame ; int EndFrame ; break; case TIME_SECTION_FORMAT_SHORT: short StartFrame; short EndFrame; break; case TIME_SECTION_FORMAT_BYTE: byte StartFrame; byte EndFrame; break; case TIME_SECTION_FORMAT_INFINITE: break; } // This read function gets messy because of the formats but basically it's just saying TIME_SECTION_FORMAT_INFINITE -> (-1, 1), else to whatever the read function above is (which is only non-default for TYPE_INT). } TimeSections[TimeSectionCount] ; } FAlign(4); if (IntParamCount != 0) uint IntParams[IntParamCount]; if (FloatParamCount != 0) float FloatParams[FloatParamCount]; if (StringParamCount != 0) { PARAM_STRING StringParams[StringParamCount] ; //event string hash dump /* local uint stringIdx; for (stringIdx = 0; stringIdx < StringParamCount; stringIdx++) { Printf(Str("%I64u\n",StringParams[stringIdx].param.hash)); } */ //vfx name dump /* if (Name==595181585) { if (StringParamCount>7) { if (StringParams[6].param.hash==39224491583389 ||StringParams[6].param.hash==72256544285556 ||StringParams[6].param.hash==32886448170624 ||StringParams[7].param.hash==173102471356897 ||StringParams[6].param.hash==34251201099326) { Printf(Str("%I64u\n",StringParams[0].param.hash)); }; }; } */ //human target hash dump /*if (Name==1968729831) { if (StringParamCount!=0) { Printf(Str("%I64u\n",StringParams[0].param.hash)); } }*/ //mesh group hash dump /*if (Name==1799953944) { Printf(Str("target: %I64u mesh group: %I64u\n",StringParams[0].param.hash,StringParams[1].param.hash)); }*/ //prp_ hash dump /*if (Name==2523762371) { Printf(Str("%I64u\n",StringParams[0].param.hash)); }*/ // if (Name==595181585) // { // if (StringParamCount>6) // { // if (StringParams[5].param.hash==84993817083062) // { // local float divisor = 0.6*1000/1001; // Printf(Str("%f,%I64u\n",TimeSections[0].StartFrame/divisor,StringParams[1].param.hash)); // } // } // } //event string hash dump /* local uint stringIdx; for (stringIdx = 0; stringIdx < StringParamCount; stringIdx++) { Printf(Str("%I64u\n",StringParams[stringIdx].param.hash)); } */ //vfx name dump /* if (Name==595181585) { if (StringParamCount>7) { if (StringParams[6].param.hash==39224491583389 ||StringParams[6].param.hash==72256544285556 ||StringParams[6].param.hash==32886448170624 ||StringParams[7].param.hash==173102471356897 ||StringParams[6].param.hash==34251201099326) { Printf(Str("%I64u\n",StringParams[0].param.hash)); }; }; } */ //human target hash dump /*if (Name==1968729831) { if (StringParamCount!=0) { Printf(Str("%I64u\n",StringParams[0].param.hash)); } }*/ //mesh group hash dump /*if (Name==1799953944) { Printf(Str("target: %I64u mesh group: %I64u\n",StringParams[0].param.hash,StringParams[1].param.hash)); }*/ //prp_ hash dump /*if (Name==2523762371) { Printf(Str("%I64u\n",StringParams[0].param.hash)); }*/ //.sani subtitles dump /*if (Name==595181585) { if (StringParamCount>6) { if (StringParams[5].param.hash==84993817083062) { local float divisor = 0.60075*1000/1001; Printf(Str("subp: %f,%I64u\n",TimeSections[0].StartFrame/divisor,StringParams[1].param.hash)); } } }*/ } } Event ; } if (CacheOffset != 0) { FSeek(startof(this) + CacheOffset); struct EventCache { switch (parentof(this).CategoryName) { case ag: struct AnimGraphEventCache { struct MotionGraphFootFitEventCacheData // MotionGrpahFootFitEventCacheData { // Completely derived from MTEV_AG_SYNC_L and MTEV_AG_SYNC_R events. Frames list is from respective event time sections sorted in order by StartFrame. // If animation is loop, Info.StartFrame = -(first event in order).Section.StartFrame, else 0. struct MotionGraphFootFitInfo // MotionGrpahFootFitInfo { uint FramesOffset; uint FrameCount; int StartFrame; enum FOOT_FIT_INFO_FLAGS { FOOT_FIT_INFO_FLAGS_IS_LOOP = 0x1, FOOT_FIT_INFO_FLAGS_START_LEFT = 0x2, // Left foot first } Flags; if (FramesOffset != 0) { FSeek(startof(FramesOffset) + FramesOffset); uint Frames[FrameCount]; } } Info; FSeek(startof(Info) + 0x10); // sizeof(MotionGraphFootFitInfo) } FootFitData; // A list of hashes which matches the StringParams used in event named 3487515216. // Calls MotionGraphControl::AddCurrentNodeTag and MotionGraphControl::RemoveCurrentNodeTag uint TagsOffset; uint TagCount; if (TagCount != 0) { FSeek(startof(TagsOffset) + TagsOffset); enum TagString_StrCodeAlias { Hold = 10946689085138, Cqc = 15970714994597, Left = 168562599339607, Right = 186371849431182, Start = 256657689349378, Carry = 274098151722498, Damage = 43102718049991, DisableGunHold = 46337489715398, Idle = 61907898383491, DisableMove = 7660441078150, Cliff = 94765518158100, Stand = 134474105696778, Crawl = 167621566807970, AttachWeaponToLHand = 171276586778105, Supine = 207439181639403, Hung = 236773365968224, Squat = 80979382735191, } Tags[TagCount]; } } Cache; break; default: Assert(false); break; } // Debug // local uint tgIdx = 0; // for (tgIdx = 0; tgIdx < TagCount; tgIdx++) // Printf("%Lu\n", Tags[tgIdx]); } Cache; } } EvpData ; typedef struct { uint Version ; short Count ; ushort Padding ; Assert(Padding == 0); uint EntryOffsets[Count] ; local uint eIdx; for (eIdx = 0; eIdx < Count; eIdx++) { FSeek(startof(this) + EntryOffsets[eIdx]); EvpData Data; } } EvpHeader ; typedef enum { TRACK_STREAM_FLAGS_HAS_EVENT_PACKET = 0x1, TRACK_STREAM_FLAGS_HAS_SEGMENT_FLAGS = 0x2, TRACK_STREAM_FLAGS_HAS_BASE_OFFSET = 0x4, TRACK_STREAM_FLAGS_HAS_EVENTS = 0x8, } TRACK_STREAM_FLAGS ; string ReadTrackStreamFlags(TRACK_STREAM_FLAGS flags) { local string result = flags == 0 ? "" : "| "; local ubyte i; local string enumName; local TRACK_STREAM_FLAGS temp; for (i = 1; i < 0x10; i = i << 1) { temp = flags & i; enumName = EnumToString(temp); if (enumName != "") result += " " + enumName + " |"; } return result; } typedef enum { TRACK_STREAM_SEGMENT_FLAGS_IS_STATIC = 0x1, TRACK_STREAM_SEGMENT_FLAGS_NO_DATA = 0x2, TRACK_STREAM_SEGMENT_FLAGS_HAS_BASE_OFFSET = 0x4, } TRACK_STREAM_SEGMENT_FLAGS ; string ReadTrackStreamSegmentFlags(TRACK_STREAM_SEGMENT_FLAGS flags) { local string result = flags == 0 ? "" : "| "; local ubyte i; local string enumName; local TRACK_STREAM_SEGMENT_FLAGS temp; for (i = 1; i < 0x8; i = i << 1) { temp = flags & i; enumName = EnumToString(temp); if (enumName != "") result += " " + enumName + " |"; } return result; } enum PACKET_TYPE { PACKET_TYPE_STREAM = 0, PACKET_TYPE_NODES = 1, //GZ/PT/that unused FSM in TPP only PACKET_TYPE_EVENTS = 2, }; struct FoxDataNodes; struct PacketHeader { PACKET_TYPE Type; uint NextPacketOffset; uint Padding ; Assert(Padding == 0); switch (Type) { case PACKET_TYPE_NODES: FoxDataNodes Nodes; break; case PACKET_TYPE_EVENTS: EvpData Events; break; } }; struct TrackStream { PACKET_TYPE Type; TRACK_STREAM_FLAGS Flags; uint StartFrame; uint FrameCount; uint SegmentCount; uint NextPacketOffset; uint EventsOffset; uint SegmentOffsets[SegmentCount]; if ((Flags & TRACK_STREAM_FLAGS_HAS_BASE_OFFSET) != 0) Vector3 BaseOffset; if ((Flags & TRACK_STREAM_FLAGS_HAS_SEGMENT_FLAGS) != 0) TRACK_STREAM_SEGMENT_FLAGS SegmentFlags[SegmentCount]; if ((Flags & TRACK_STREAM_FLAGS_HAS_EVENTS) != 0 && EventsOffset != 0) { FSeek(startof(this) + EventsOffset); EvpData Events; } }; typedef enum { A = 0, AH = 1, AY = 2, B = 3, C = 4, CH = 5, D = 6, E = 7, EE = 8, ER = 9, F = 10, G = 11, H = 12, I = 13, J = 14, L = 15, M = 16, N = 17, NG = 18, OH = 19, OO = 20, OU = 21, OW = 22, OY = 23, P = 24, R = 25, S = 26, SH = 27, T = 28, TH = 29, TT = 30, U = 31, V = 32, W = 33, Y = 34, Z = 35, _i = 36, _tH = 37, } LipAnimIndex; #endif ``` ### `templates:common/common.bt` ```cpp #ifndef COMMON_BT #define COMMON_BT typedef struct { ushort value ; } half ; string ReadHalf(half& value) { local uint tempA = (uint)value.value << 0x10; local uint tempB = 0; if ((tempA & 0x7fffffff) == 0) tempB = 0; else tempB = tempA & 0xb8000000 | 0x38000000; tempA = ((tempA & 0x7fffffff) >> 3) + tempB; local ubyte out[4]; ConvertDataToBytes(tempA, out); float result = ConvertBytesToFloat(out); return Str("%f", result); } typedef struct { uint hash; } StrCode32 ; typedef struct { uint64 hash; } StrCode ; typedef struct { uint64 hash; } PathCode64 ; typedef struct { float x; float y; } Vector2 ; typedef struct { float x; float y; uint64 Padding ; } Vector2W ; typedef struct { half x; half y; } VectorH2 ; typedef struct { float x; float y; float z; } Vector3 ; typedef struct { float x; float y; float z; uint Padding ; } Vector3W ; typedef struct { float x; float y; float z; short x_offset; short z_offset; } WideVector3 ; typedef struct { half x; half y; half z; } VectorH3 ; typedef struct { float x; float y; float z; float w; } Vector4 ; typedef struct { half x; half y; half z; half w; } VectorH4 ; typedef struct { ubyte x ; ubyte y ; ubyte z ; ubyte w ; } VectorB4 ; typedef struct { float x; float y; float z; float w; } Quaternion ; typedef struct { half x; half y; half z; half w; } QuaternionH ; typedef struct { float x0; float y0; float z0; float w0; float x1; float y1; float z1; float w1; float x2; float y2; float z2; float w2; float x3; float y3; float z3; float w3; } Matrix4; typedef struct { Vector3W Min; Vector3W Max; } BoundingBox; typedef struct { Vector3 scale; Quaternion rotation_quat; Vector3 translation; } Transform; typedef struct { byte Data[16]; } MD5; void FAlign(int alignment) { local int64 alignmentRequired = FTell() % alignment; if (alignmentRequired > 0) FSeek(FTell() + alignment - alignmentRequired); } #endif ``` ### `templates:common/fs_common.bt` ```cpp #ifndef FS_COMMON_BT #define FS_COMMON_BT struct StreamChunk { char Type[4]; uint Size; double Time; if (Type != "END " && Type != " DNE") FS_CHUNK_PAYLOAD Payload; }; while (true) { StreamChunk Chunk; if (Chunk.Type == "END " || Chunk.Type == " DNE") break; // This check is only used for applying template to single, extracted chunks if (startof(Chunk) + Chunk.Size == FileSize()) break; FSeek(startof(Chunk) + Chunk.Size); // Only if (FTell() == FileSize()) break; } #endif ``` ### `templates:common/geo_common.bt` ```cpp #ifndef GEO_COMMON_BT #define GEO_COMMON_BT #include "common/common.bt" typedef struct { uint hash ; } GeoNameHash ; string ResolveHashFunc(GeoNameHash& hash) { switch (hash.hash) { //Bone name case 7050094: return "GEOM"; case 279943692: return "BLOCK"; default: Printf("Unknown hash: %u\n",hash.hash); return ""; } } #define FOX_DATA_RESOLVE_HASH_FUNC ResolveHashFunc #define COLOR_BG_TAGS 0xFF00FF #define COLOR_FG_TAGS 0x00FF00 typedef struct { //BitfieldDisablePadding(); uint64 GEO_TRAP_TAGS_Intrude : 1; // 0x1 uint64 GEO_TRAP_TAGS_Tower : 1; // 0x2 uint64 GEO_TRAP_TAGS_InRoom : 1; // 0x4 uint64 GEO_TRAP_TAGS_FallDeath : 1; // 0x8 uint64 GEO_TRAP_TAGS_NearCamera1 : 1; // 0x10 uint64 GEO_TRAP_TAGS_NearCamera2 : 1; // 0x20 uint64 GEO_TRAP_TAGS_NearCamera3 : 1; // 0x40 uint64 GEO_TRAP_TAGS_NearCamera4 : 1; // 0x80 uint64 GEO_TRAP_TAGS_NoCliff : 1; // 0x100 uint64 GEO_TRAP_TAGS_NoRainEffect : 1; // 0x200 uint64 GEO_TRAP_TAGS_x60e79a58dcc3 : 1; // 0x400 uint64 GEO_TRAP_TAGS_GimmickNoFulton : 1; // 0x800 uint64 GEO_TRAP_TAGS_innerZone : 1; // 0x1000 uint64 GEO_TRAP_TAGS_outerZone : 1; // 0x2000 uint64 GEO_TRAP_TAGS_hotZone : 1; // 0x4000 uint64 GEO_TRAP_TAGS_x439898dcbf83 : 1; // 0x8000 uint64 GEO_TRAP_TAGS_xe780e431a068 : 1; // 0x10000 uint64 GEO_TRAP_TAGS_x53827eed3fbc : 1; // 0x20000 uint64 GEO_TRAP_TAGS_x7e1121c5cb93 : 1; // 0x40000 uint64 GEO_TRAP_TAGS_xcadd57b76a83 : 1; // 0x80000 uint64 GEO_TRAP_TAGS_xe689072c4df8 : 1; // 0x100000 uint64 GEO_TRAP_TAGS_x6d14396ebbe5 : 1; // 0x200000 - from 2020 caplag: "mgo/cuba underground, and also watchtower south of helipad" + "Doors? Something with doors? 2 x 2 x 25" uint64 GEO_TRAP_TAGS_NoStepOn : 1; // 0x400000 uint64 GEO_TRAP_TAGS_HalationEffect : 1; // 0x800000 uint64 GEO_TRAP_TAGS_Unnamed1 : 1; // 0x1000000 uint64 GEO_TRAP_TAGS_Unnamed2 : 1; // 0x2000000 uint64 GEO_TRAP_TAGS_Unused2 : 1 ; Assert(GEO_TRAP_TAGS_Unused2 == 0); // 0x4000000 uint64 GEO_TRAP_TAGS_Unused3 : 1 ; Assert(GEO_TRAP_TAGS_Unused3 == 0); // 0x8000000 uint64 GEO_TRAP_TAGS_xd6ee65d20b7a : 1; // 0x10000000 uint64 GEO_TRAP_TAGS_xf287ba9cb7e3 : 1; // 0x20000000 uint64 GEO_TRAP_TAGS_NoFulton : 1; // 0x40000000 uint64 GEO_TRAP_TAGS_Waterfall: 1; // 0x80000000 for convenience in 010 but the tag is actually 0xffffffff80000000, signalling that there are no higher-value tags //BitfieldEnablePadding(); } GEO_TRAP_TAGS ; typedef struct { // https://github.com/TinManTex/mgsv-deminified-lua/blob/3b8d6a0487ce45f69502d40e684b3d653d3b8965/data1/Tpp/start.lua#L292 uint64 GEO_PATH_TAGS_Elude : 1; uint64 GEO_PATH_TAGS_Jump : 1; uint64 GEO_PATH_TAGS_Fence : 1; uint64 GEO_PATH_TAGS_StepOn : 1; uint64 GEO_PATH_TAGS_Behind : 1; uint64 GEO_PATH_TAGS_Urgent : 1; uint64 GEO_PATH_TAGS_Pipe : 1; uint64 GEO_PATH_TAGS_Climb : 1; uint64 GEO_PATH_TAGS_Rail : 1; uint64 GEO_PATH_TAGS_ForceFallDown : 1; uint64 GEO_PATH_TAGS_DontFallWall : 1; uint64 GEO_PATH_TAGS_Move : 1; } GEO_PATH_TAGS ; typedef struct { // https://github.com/TinManTex/mgsv-deminified-lua/blob/3b8d6a0487ce45f69502d40e684b3d653d3b8965/data1/Tpp/start.lua#L292 uint GEO_EDGE_TAGS_Stand : 1; uint GEO_EDGE_TAGS_Squat : 1; uint GEO_EDGE_TAGS_BEHIND_LOW : 1; uint GEO_EDGE_TAGS_FenceElude : 1; uint GEO_EDGE_TAGS_Elude : 1; uint GEO_EDGE_TAGS_Jump : 1; uint GEO_EDGE_TAGS_Fence : 1; uint GEO_EDGE_TAGS_StepOn : 1; uint GEO_EDGE_TAGS_Behind : 1; uint GEO_EDGE_TAGS_Urgent : 1; uint GEO_EDGE_TAGS_NoEnd : 1; uint GEO_EDGE_TAGS_NoStart : 1; uint GEO_EDGE_TAGS_FenceJump : 1; uint GEO_EDGE_TAGS_Wall : 1; uint GEO_EDGE_TAGS_NoWall : 1; uint GEO_EDGE_TAGS_ToIdle : 1; uint GEO_EDGE_TAGS_EnableFall : 1; uint GEO_EDGE_TAGS_NoFreeFall : 1; uint GEO_EDGE_TAGS_Fulton : 1; uint GEO_EDGE_TAGS_BEHIND_SNAP : 1; uint GEO_EDGE_TAGS_LineCheck : 1; uint GEO_EDGE_TAGS_FallNear : 1; uint GEO_EDGE_TAGS_FenceToStepOn : 1; uint GEO_EDGE_TAGS_ForceFallCatch : 1; uint GEO_EDGE_TAGS_Window : 1; uint GEO_EDGE_TAGS_AimIsBack : 1; } GEO_EDGE_TAGS ; typedef struct { // https://github.com/TinManTex/mgsv-deminified-lua/blob/3b8d6a0487ce45f69502d40e684b3d653d3b8965/data1/Tpp/start.lua#L292 uint GEO_NODE_TAGS_Edge : 1; uint GEO_NODE_TAGS_Cover : 1; uint GEO_NODE_TAGS_BEHIND_LOOK_IN : 1; uint GEO_NODE_TAGS_CHANGE_TO_60 : 1; uint GEO_NODE_TAGS_NoTurn : 1; uint GEO_NODE_TAGS_BEHIND_STOP : 1; uint GEO_NODE_TAGS_NoOut : 1; uint GEO_NODE_TAGS_NoStart : 1; uint GEO_NODE_TAGS_EludeToElude : 1; } GEO_NODE_TAGS ; typedef struct { uint64 Padding0 : 1 ; Assert(Padding0 == 0); uint64 RECOIL : 1; // (MGS4) TYPRECOIL uint64 CHARA : 1; // (TPP) 0x80000004 CHARA, (MGS4) 0x4 TYPFLOOR uint64 SOUND : 1; uint64 PLAYER : 1; uint64 ENEMY : 1; uint64 BULLET : 1; uint64 MISSILE : 1; uint64 BOMB : 1; uint64 RADOR_MGS4 : 1 ; Assert(RADOR_MGS4 == 0); // (MGS4) uint64 BLOOD : 1; uint64 IK : 1; uint64 STAIRWAY : 1; uint64 STOP_EYE : 1; uint64 CLIFF : 1; uint64 TYPTHROUGH_MGS4 : 1 ; Assert(TYPTHROUGH_MGS4 == 0); // (MGS4) uint64 LEAN_MGS4 : 1 ; Assert(LEAN_MGS4 == 0); // (MGS4) uint64 DONT_FALL : 1; uint64 CAMERA : 1; uint64 SHADOW_MGS4 : 1 ; Assert(SHADOW_MGS4 == 0); // (MGS4) uint64 INTRUDE_MGS4 : 1 ; Assert(INTRUDE_MGS4 == 0); // (MGS4) uint64 ATTACK_GUARD_MGS4 : 1 ; Assert(ATTACK_GUARD_MGS4 == 0); // (MGS4) uint64 CLIFF_FLOOR : 1; uint64 BULLET_MARK : 1; uint64 HEIGHT_LIMIT : 1; uint64 NO_BEHIND_MGS4 : 1 ; Assert(NO_BEHIND_MGS4 == 0); // (MGS4) uint64 BEHIND_THROUGH_MGS4 : 1 ; Assert(BEHIND_THROUGH_MGS4 == 0); // (MGS4) uint64 Padding1 : 1 ; Assert(Padding1 == 0); uint64 Padding2 : 1 ; Assert(Padding2 == 0); uint64 DOUBLE_SIDE : 1; uint64 WATER_SURFACE : 1; uint64 CHARA_Part2 : 1 ; Assert(CHARA == CHARA_Part2); uint64 TARGET_BLOCK : 1; uint64 DOG : 1; uint64 Padding3 : 1 ; Assert(Padding3 == 0); uint64 NO_EFFECT : 1; uint64 EVENT_PHYSICS : 1; uint64 NO_WALL_MOVE : 1; uint64 MISSILE2 : 1; uint64 Padding4 : 1 ; Assert(Padding4 == 0); uint64 TppReserve1 : 1; uint64 TppReserve2 : 1; uint64 TppReserve3 : 1; uint64 TppReserve4 : 1; uint64 Padding5 : 1 ; Assert(Padding5 == 0); uint64 Padding6 : 1 ; Assert(Padding6 == 0); uint64 Padding7 : 1 ; Assert(Padding7 == 0); uint64 Padding8 : 1 ; Assert(Padding8 == 0); uint64 Sahelan : 1; uint64 RIDE_ON_OUTER : 1; uint64 FLAME : 1; uint64 IGNORE_PHYSICS : 1; uint64 CLIMB : 1; uint64 HORSE : 1; uint64 VEHICLE : 1; uint64 MARKER : 1; uint64 RIDE_ON : 1; uint64 THROUGH_LINE_OF_FIRE : 1; uint64 THROUGH_ITEM_CHECK : 1; uint64 NO_CREEP : 1; uint64 NO_FULTON : 1; uint64 FULTON : 1; uint64 ITEM : 1; uint64 BOSS : 1; } GEO_COL_A ; enum GEO_PRIM_TYPE { GEO_PRIM_TYPE_DOT = 0, // Multi-entry (zero means only one allowed) size: 0x30 GEO_PRIM_TYPE_LINE = 1, // Multi-entry (zero means only one allowed) size: 0x30 GEO_PRIM_TYPE_POLY = 2, // Multi-entry (zero means only one allowed) size: 0xA GEO_PRIM_TYPE_BOX = 3, // Multi-entry (zero means only one allowed) size: 0x60 GEO_PRIM_TYPE_AABB = 4, // Multi-entry (zero means only one allowed) size: 0x20 GEO_PRIM_TYPE_REFERENCE = 5, // Multi-entry (zero means only one allowed) size: 0x80 GEO_PRIM_TYPE_UNKNOWN6 = 6, // Multi-entry (zero means only one allowed) size: 0 GEO_PRIM_TYPE_PYRAMID = 7, // Multi-entry (zero means only one allowed) size: 0 GEO_PRIM_TYPE_PATH = 8, // Multi-entry (zero means only one allowed) size: 0x8 GEO_PRIM_TYPE_UNKNOWN9 = 9, // Multi-entry (zero means only one allowed) size: 0 GEO_PRIM_TYPE_UNKNOWN10 = 10, // Multi-entry (zero means only one allowed) size: 0 GEO_PRIM_TYPE_FREE_AREA = 11, // Multi-entry (zero means only one allowed) size: 0x10 }; typedef enum { GEO_SHAPE_FLAGS_UNKNOWN6 = 0x1, // Tpp_main_win64.exe!141a3b26d, Found in TRAP. GEO_SHAPE_FLAGS_UNKNOWN9 = 0x2, // Tpp_main_win64.exe!141a3b26d GEO_SHAPE_FLAGS_UNKNOWN4 = 0x4, // Tpp_main_win64.exe!141a3b26d, Found in GPFP. GEO_SHAPE_FLAGS_IS_INSERTED_CHILD = 0x10, // Tpp_main_win64.exe!141a3b1bc // info << 8 GEO_SHAPE_FLAGS_DISABLED = 0x20, // mgsvtpp.exe!141bdc498 // info & 0x200 GEO_SHAPE_FLAGS_DOUBLE_SIDED = 0x200, // Tpp_main_win64.exe141a05b40 GEO_SHAPE_FLAGS_USE_FMDL_VERTICES = 0x800, // mgsvtpp.exe!141bd7e30 // info & 0x8000 GEO_SHAPE_FLAGS_UNKNOWN10 = 0x1000, // Tpp_main_win64.exe!141a4b3a2 // info & 0x10000 GEO_SHAPE_FLAGS_HAS_CHILD = 0x2000, // mgsvtpp.exe!141bdc7a7 // info >> 0x11 GEO_SHAPE_FLAGS_UNKNOWN7 = 0x4000, // ????????????????????? // info >> 0x12 GEO_SHAPE_FLAGS_HAS_REF_MATRIX = 0x8000, // mgsvtpp.exe!141bdc830, Tpp_main_win64.exe!141a3b26d, 141a45f50 // info >> 0x13, runtime-only, adds 0x40-byte payload GEO_SHAPE_FLAGS_UNKNOWN3 = 0x20000, // Tpp_main_win64.exe!141a3b26d, Tpp_main_win64.exe!141a4b370 // info >> 0x15, & 0x200000 adds some sort of 0x20-byte payload GEO_SHAPE_FLAGS_UNKNOWN5 = 0x80000, // Found in GPFP and TRAP. // mgsvtpp.exe!141bdc830 } GEO_SHAPE_FLAGS ; string ReadGEO_SHAPE_FLAGS(GEO_SHAPE_FLAGS flags) { local string result = flags == 0 ? "" : "| "; local uint i; local string enumName; local GEO_SHAPE_FLAGS temp; for (i = 1; i < 0x100000; i = i << 1) { temp = flags & i; enumName = EnumToString(temp); if (enumName != "") result += " " + enumName + " |"; } return result; } struct GeoGeomHeader { GEO_PRIM_TYPE Type : 4 ; GEO_SHAPE_FLAGS Flags : 20 ; Assert((Flags & ~(GEO_SHAPE_FLAGS_DOUBLE_SIDED | GEO_SHAPE_FLAGS_UNKNOWN7 | GEO_SHAPE_FLAGS_HAS_CHILD | GEO_SHAPE_FLAGS_USE_FMDL_VERTICES)) == 0); // mgsvtpp.exe!141bdc492 //Assert(((Flags & GEO_SHAPE_FLAGS_DOUBLE_SIDED) != 0) == ((Flags & GEO_SHAPE_FLAGS_UNKNOWN7) != 0)); if ((Flags & GEO_SHAPE_FLAGS_UNKNOWN7) != 0) Printf("GeoGeomHeader with GEO_SHAPE_FLAGS_UNKNOWN7 at %Lu.\n", startof(this)); uint PrimCount : 8 ; // Each of these offsets are in terms of the number of lines, so scale them by 16, aka shift by 4 bits. // To check if the VertexBufferOffset goes anywhere, it checks if (VertexBufferOffset & 0x0fffffff) == 0. // Those "mystery" "4 bits are probably from the shift, especially since PES, which doesn't do any shifting by 4, just treats the whole uint as the offset // Nonetheless, ensure the top 4 bits aren't used. int NextHeaderOffset : 28 ; int NextHeaderOffsetPadding : 4 ; Assert(NextHeaderOffsetPadding == 0); int PreviousHeaderOffset : 28 ; int PreviousHeaderOffsetPadding : 4 ; Assert(PreviousHeaderOffsetPadding == 0); int ChildHeaderOffset : 28 ; Assert(((Flags & GEO_SHAPE_FLAGS_HAS_CHILD) != 0) == (ChildHeaderOffset != 0)); //Assert(((Flags & GEO_SHAPE_FLAGS_NO_CHILD) != 0) == (ChildHeaderOffset == 0)); int ChildHeaderOffsetPadding : 4 ; Assert(ChildHeaderOffsetPadding == 0); GEO_COL_A Tags; StrCode32 Name; int VertexBufferOffset : 28 ; int VertexBufferOffsetPadding : 4 ; Assert(VertexBufferOffsetPadding == 0); }; struct GeoPathGeomHeader { GEO_PRIM_TYPE Type : 4 ; GEO_SHAPE_FLAGS Flags : 20 ; Assert(Flags == (GEO_SHAPE_FLAGS_UNKNOWN4 | GEO_SHAPE_FLAGS_UNKNOWN5)); uint PrimCount : 8 ; // Each of these offsets are in terms of the number of lines, so scale them by 16, aka shift by 4 bits. // To check if the VertexBufferOffset goes anywhere, it checks if (VertexBufferOffset & 0x0fffffff) == 0. // Those "mystery" "4 bits are probably from the shift, especially since PES, which doesn't do any shifting by 4, just treats the whole uint as the offset // Nonetheless, ensure the top 4 bits aren't used. int NextHeaderOffset; Assert(NextHeaderOffset == 0); int PreviousHeaderOffset; Assert(PreviousHeaderOffset == 0); int ChildHeaderOffset; Assert(ChildHeaderOffset == 0); GEO_PATH_TAGS Tags; StrCode32 Name; // With gimmicks, it has to be the gimmick instance name as StrCode32 hash, ie <_n0000|srt_>. // If there's more than one path for one instance, the hash is the same, but with the seventh of the eight bits shifted by 2 int VertexBufferOffset; }; struct GeoTrapGeomHeader { GEO_PRIM_TYPE Type : 4 ; GEO_SHAPE_FLAGS Flags : 20 ; Assert(Flags == (GEO_SHAPE_FLAGS_UNKNOWN5 | GEO_SHAPE_FLAGS_UNKNOWN6)); uint PrimCount : 8 ; // Each of these offsets are in terms of the number of lines, so scale them by 16, aka shift by 4 bits. // To check if the VertexBufferOffset goes anywhere, it checks if (VertexBufferOffset & 0x0fffffff) == 0. // Those "mystery" "4 bits are probably from the shift, especially since PES, which doesn't do any shifting by 4, just treats the whole uint as the offset // Nonetheless, ensure the top 4 bits aren't used. int NextHeaderOffset; Assert(NextHeaderOffset == 0); int PreviousHeaderOffset; Assert(PreviousHeaderOffset == 0); int ChildHeaderOffset; Assert(ChildHeaderOffset == 0); GEO_TRAP_TAGS Tags; StrCode32 Name; // With gimmicks, it has to be the gimmick instance name as StrCode32 hash, ie <_n0000|srt_>. // If there's more than one path for one instance, the hash is the same, but with the seventh of the eight bits shifted by 2 int VertexBufferOffset; Assert(VertexBufferOffset == 0); }; typedef struct { short IndexA; short IndexB; short IndexC; short IndexD; struct GeoQuadMaterialInfo { BitfieldDisablePadding(); byte NoUseMaterial : 1; byte NoUseAuxMaterial : 1; // Presumptive, but *super* likely given the parallelism in the materials section and the fact that the normal materials do the exact same thing in this section (they have NoUseMaterial = 1 and then a 7-bit -1) byte MaterialIndex : 7 ; // Sign-extend to a type that'll actually display negative numbers byte AuxMaterialIndex : 7 ; BitfieldEnablePadding(); } Info; } GeoPrimPoly ; // Name taken from PES RTTI typedef struct { Vector4 Scale; // cap - I seem to remember Intrude triggers needing to be scaled up by two, but I don't remember if it applies to all boxes uint64 Padding0 ; Assert(Padding0 == 0); uint64 Padding1 ; Assert(Padding1 == 0); Matrix4 transform; } GeoPrimBox; // Name taken from PES RTTI typedef struct { Vector3W BoundingBoxRadii ; Vector3W BoundingBoxCenter ; } GeoPrimAabb; // Name taken from PES RTTI typedef struct { GEO_EDGE_TAGS Tags; ushort InIndex; ushort OutIndex; } GeoPrimPath; typedef struct { float YMinimum; float YMaximum; uint VertexCount/* */; int VertexDataOffset/* */; // FSeek(startof(this) + VertexDataOffset); // Vector3W Vertices[VertexCount] ; } GeoPrimFreeArea; struct GeoVertexHeader // Name taken from PES RTTI { uint VertexCount; uint VerticesIndexOffset; uint Unknown0Or1; Assert(Unknown0Or1 == 0 || Unknown0Or1 == 1); uint OriginIndex; int64 VertexDataOffset; // This gets patched at runtime to use a FMDL pointer. uint FmdlVertexBufferOffset; uint Padding0 ; Assert(Padding0 == 0); }; #endif ``` ### `templates:common/gr_common.bt` ```cpp #ifndef GR_COMMON_BT #define GR_COMMON_BT #include "common/common.bt" // Only used for OBR(B) typedef struct { float YPosition; short XPosition ; short ZPosition ; QuaternionH Rotation; ushort BlockIndex; ubyte PluginIndex; // Index of ObjBrush dataset entity's pluginHandle list entry ubyte NormalizedScale ; // scale = lerp(minScale, maxScale, (float)NormalizedScale / 0xFF) found in DataSet plugin definition uint GlobalIndex; } DataUnit ; #endif ``` ### `templates:common/gr_sh_common.bt` ```cpp #ifndef GR_SH_COMMON_BT #define GR_SH_COMMON_BT string ReadUInt24HTime(uint time) { //https://github.com/TinManTex/mgsv-deminified-lua/blob/3b8d6a0487ce45f69502d40e684b3d653d3b8965/data1/Assets/tpp/script/lib/TppClock.lua#L15 const float t=(1.0/60.0)/60.0; const float c=1.0/60.0; const float hour=60.0*60.0; const float minute=60.0; local byte hours = Floor(time * t); local byte minutes = Floor((time-(hours*hour)) * c); local byte seconds = Floor((time-(hours*hour)) - (minutes*minute)); return Str("%02d:%02d:%02d",hours,minutes,seconds); }; #endif ``` ### `templates:common/gr_terrain_common.bt` ```cpp #ifndef GR_TERRAIN_COMMON_BT #define GR_TERRAIN_COMMON_BT typedef struct { ubyte r ; ubyte g ; ubyte b ; ubyte a ; } Pixel ; struct _HeightMap { uint HeightFormat; Assert(HeightFormat == 1 || HeightFormat == 4); // 1 for PC, 4 for PS3 float MaxHeightWS; float MinHeightWS; uint HeightMapOffset; // selfpos + HeightMapOffset points to start of heightMap uint HeightMapSize; // guess: heightMap size in bytes }; struct _PatchConfiguration { uint64 BaseOffset; Assert(BaseOffset == 0); // Probably added to all the other offsets below uint MaterialIdsOffset; // selfpos + MaterialIdsOffset points to start of materialIds uint ConfigrationIdsOffset; // selfpos + ConfigrationIdsOffset points to start of configrationIds uint MaxHeightOffset; // selfpos + MaxHeightOffset points to start of maxHeight uint MinHeightOffset; // selfpos + MaxHeightOffset points to start of minHeight uint ParamOffset; // selfpos + ParamOffset points to start of param }; struct _Patch { _HeightMap HeightMap; uint ComboFormat; // 6 for PC, 7 for PS3. But PC won't read the file if greater than 6. uint ComboTextureOffset; // selfpos + ComboTextureOffset points to start of comboTexture uint ComboTextureSize; // guess: comboTexture size in bytes _PatchConfiguration PatchConfiguration; FAlign(8); uint Unknown; Assert(Unknown == 0); uint Height; uint Width; ushort ClusterGridSize; Assert(ClusterGridSize == 32); ushort MaxLodLevel; ushort LodCount; }; #endif ``` ### `templates:common/sd_common.bt` ```cpp #ifndef SD_COMMON_BT #define SD_COMMON_BT enum CODEC_TYPE { CODEC_TYPE_PCM = 0, CODEC_TYPE_ADPCM = 1, CODEC_TYPE_VORBIS = 2, CODEC_TYPE_XMA = 3, }; struct SoundStreamHeader // custom name { uint DataSize; //Full size of the .wem file - the uint at 0x4 of the .wem, +8 CODEC_TYPE CodecType; uint64 Padding ; Assert(Padding == 0); }; #endif ``` ### `templates:dfrm.bt` ```cpp LittleEndian(); struct DfrmHeader { char Signature[4]; //DFRM float Version; Assert(Version == 1.0); //1.0 uint HeaderSize; Assert(HeaderSize == 0x40); uint SubmeshDefCount; uint BlendShapeSpanCount; uint Block5SpanCount; uint BlendShapeSpanIndexCount; uint BlendShapeCount; uint Block5Count; uint SubmeshDefsOffset; uint BlendShapeSpansOffset; uint Block5SpansOffset; uint BlendShapeSpanIndicesOffset; uint BlendShapesOffset; uint Block5sOffset; FSkip(4); } Header; // Just Span for BlendShapeSpanIndices the size of the submesh's vertex count FSeek(Header.SubmeshDefsOffset); struct SubmeshDef { uint BlendShapeSpanIndices_Count; uint BlendShapeSpanIndices_StartOffset; } SubmeshDefs[Header.SubmeshDefCount] ; // Just Span FSeek(Header.BlendShapeSpansOffset); struct BlendShapeSpan { uint BlendShape_Count; uint BlendShape_StartOffset; } BlendShapeSpans[Header.BlendShapeSpanCount] ; // Just Span FSeek(Header.Block5SpansOffset); struct Block5Span { uint Block5_Count; uint Block5_StartOffset; } Block5Spans[Header.Block5SpanCount] ; FSeek(Header.BlendShapeSpanIndicesOffset); uint BlendShapeSpanIndices[Header.BlendShapeSpanIndexCount] ; // Unknown FSeek(Header.BlendShapesOffset); struct BlendShape { ushort SubmeshIndex; ushort Unknown1; } BlendShapes[Header.BlendShapeCount] ; // Unknown FSeek(Header.Block5sOffset); struct Block5 { uint BlendShapeSpanIndex; } Block5s[Header.Block5Count] ; ``` ### `templates:ends.bt` ```cpp //ENDS - Ending Credits //By RLC, inspired by the work of Modders' Heaven! #define C_H 0x000000 #define C_0 0xFF0000 #define C_1 0x00FF00 #define C_2 0x0000FF #define C_3 0x00FFFF #define C_4 0xFF00FF #define C_5 0xFFFF00 #define C_6 0xFFFFFF #define C_7 0x494949 #define C_8 0x7a7a7c #define C_9 0x735dff struct Header { char header[7]; // ENDSwin, similar header chars to fova, same creator? byte version; } header ; local int pos = FTell(); struct Section0 { uint offset0; uint count0; pos = FTell(); FSeek(offset0); struct Array0 { uint64 hash; uint unknown0; uint unknown1; }array0[count0]; FSeek(pos); } section0 ; struct Section1 { uint offset1; uint count1; pos = FTell(); FSeek(offset1); struct Array1 { uint unknown0; uint unknown1; }array1[count1]; FSeek(pos); } section1 ; struct Section2 { uint offset2; uint count2; pos = FTell(); FSeek(offset2); struct Array2 { uint64 hash0; uint64 hash1; int unknown0; int unknown1; int unknown2; int unknown3; }array2[count2]; FSeek(pos); } section2 ; struct Section3 { uint offset3; uint count3; pos = FTell(); FSeek(offset3); struct Array3 { uint64 hash; int unknown0; byte u0; byte u1; byte u2; byte u3; int unknown2; int unknown3; }array3[count3]; FSeek(pos); } section3 ; struct Section4 { uint offset4; uint offset4a; uint count4; pos = FTell(); FSeek(offset4); uint unknown4; struct Array4 { uint64 hash; int unknown; byte u0; byte u1; byte u2; byte u3; int unknown2; int unknown3; }array4[count4]; FSeek(pos); } section4 ; struct Section5 { uint offset5; uint offset5a; uint count5; pos = FTell(); FSeek(offset5); uint unknown5; struct Array5 { int unknown; int unknown2; }array5[count5]; FSeek(pos); } section5 ; struct Section6 { uint offset6; uint count6; pos = FTell(); FSeek(offset6); struct Array6 { uint64 hash; int unknown; int unknown2; int unknown3; int unknown4; }array6[count6]; FSeek(pos); } section6 ; struct Section7 { uint offset7; uint count7; pos = FTell(); FSeek(offset7); struct Array7 { uint64 hash; int unknown; int unknown2; int unknown3; int unknown4; }array7[count7]; FSeek(pos); } section7 ; struct Section8 { uint offset8; uint count8; pos = FTell(); FSeek(offset8); struct Array8 { byte u0; byte u1; byte u2; byte u3; }array8[count8]; FSeek(pos); } section8 ; struct Section9 { uint offset9; pos = FTell(); FSeek(offset9); struct Array9 { int unknown; }array9[2]; FSeek(pos); } section9 ; ``` ### `templates:fclo.bt` ```cpp LittleEndian(); #define TEXT_COLOR 0xF6F7ED #define COLOR_HEADER 0xA46026 #define COLOR_SECTION0 0x5399F1 #define COLOR_SECTION2 0x3573C4 #define COLOR_SECTION3 0x1E3556 #define COLOR_SECTION3B 0x018FF1 #define COLOR_SECTION3C 0xA88B04 #define COLOR_SECTION4 0xA741D7 #define COLOR_SECTION5 0x73173A #include "common/common.bt" struct SimClothFileHeader { char Signature[4]; if (Signature == "fclo") BigEndian(); else Assert(Signature == "olcf"); FSkip(12); uint SimulatedParticleCount; uint FixedParticleCount; uint TensionLinkCount; uint QuadCount; uint BodyBoneCount; } Header ; struct ParticleUnit { Vector3 Position; StrCode32 AssociatedBoneName; }; ParticleUnit SimulatedParticles[Header.SimulatedParticleCount] ; ParticleUnit FixedParticles[Header.FixedParticleCount] ; struct BodyBoneWeightUnit { uint BodyBoneIndices[4]; float Weights[4]; } BodyBoneWeights[Header.SimulatedParticleCount + Header.FixedParticleCount] ; struct TensionLinkUnit { uint ParticleAIndex; uint ParticleBIndex; } TensionLinks[Header.TensionLinkCount] ; struct QuadUnit { uint ParticleAIndex; uint ParticleBIndex; uint ParticleCIndex; uint ParticleDIndex; } Quads[Header.QuadCount] ; StrCode32 BodyBones[Header.BodyBoneCount] ; ``` ### `templates:fcnp.bt` ```cpp LittleEndian(); #include "common/common.bt" typedef struct { Vector4 Translation; Assert(Translation.w == 1); Vector4 Rotation; Vector4 Scale; Assert(Scale.w == 1); } FCNP; #define FOX_DATA_PAYLOAD FCNP #define FOX_DATA_FORCE_LITTLE_ENDIAN #include "common/FoxData_common.bt" FoxDataHeader Header; FSeek(Header.NodesOffset); FoxDataNodes Nodes; ``` ### `templates:fdes.bt` ```cpp #include "common/common.bt" #include "common/geo_common.bt" #include "common/FoxData_common.bt" #define C_HEADER 0x527f4b #define C_ROOT 0x81d17d #define C_UNIT 0xF7BEC3 #define C_SUBENTRY 0xFF4F8A #define C_FOOTER 0xbce896 struct FdesHeader { char Signature[4] ; char Version[4] ; uint FileSize; uint Padding[2] ; Assert(Padding[0] == 0 && Padding[1] == 0); uint DataOffset; Assert(DataOffset == 32); uint RootNodeCount; uint NameTableOffset; } Header ; enum FDES_SHAPE_TYPE { FDES_SHAPE_TYPE_NONE = 0, FDES_SHAPE_TYPE_SPHERE = 1, FDES_SHAPE_TYPE_BOX = 2, FDES_SHAPE_TYPE_CYLINDER = 3, FDES_SHAPE_TYPE_CAPSULE = 4, FDES_SHAPE_TYPE_POLYHEDRON = 5, }; struct QuadDef { uint A; uint B; uint C; uint D; }; typedef struct { // See: PhShape and PhShapeParam Vector3 Offset; uint Padding0 ; Quaternion Rotation; Vector3 Size; uint Padding1 ; FDES_SHAPE_TYPE ShapeType; uint VertexBufferOffset; uint VertexCount; FSeek(startof(this) + VertexBufferOffset); Vector4 Vertex[VertexCount]; FSeek(startof(VertexCount) + sizeof(VertexCount)); uint QuadDefTableOffset; uint QuadCount; FSeek(startof(this) + QuadDefTableOffset); QuadDef Quad[QuadCount]; FSeek(startof(QuadCount) + sizeof(QuadCount)); FAlign(16); } FdesShapeDef ; typedef struct { Matrix4 MatrixA; Matrix4 MatrixB; uint NameIndex ; uint Padding ; Assert(Padding == 0); uint ShapeDefsOffset ; uint ShapeDefCount ; FSeek(startof(this) + ShapeDefsOffset); FdesShapeDef ShapeDef[ShapeDefCount] ; FSeek(startof(ShapeDefCount) + sizeof(ShapeDefCount)); } FdesNode ; typedef struct { FdesNode Node ; uint ChildNodesOffset ; uint ChildNodeCount ; uint Padding[2] ; FdesNode ChildNodes[Root.ChildNodeCount] ; } FdesRootNode ; FSeek(Header.DataOffset); local uint rIdx = 0; for (rIdx = 0; rIdx < Header.RootNodeCount; rIdx++) { FdesRootNode Root; //then another array of two or three or a lot of vectors and some 8 integers //60 weird integers at the end too } typedef struct { GeoNameHash Hash; uint Length; string CString; } FdesNodeName ; FSeek(Header.NameTableOffset); struct FdesNodeNameTable { uint Count ; uint Offsets[Count] ; local uint i = 0; for (i = 0; i < Count; i++) { FSeek(startof(this) + Offsets[i]); FdesNodeName Name; } } NameTable ; ``` ### `templates:fmdl.bt` ```cpp LittleEndian(); #include "common/common.bt" #define COLOR_Header 0xDFEFAA #define COLOR_FeatureHeader 0x7DE39E #define COLOR_BufferHeader 0x00AAFF #define COLOR_FmdlBoneDef 0xAED2E8 #define COLOR_FmdlMeshGroupHeader 0xB9E8DD #define COLOR_FmdlMeshGroupDef 0xF7F205 #define COLOR_FmdlMeshDef 0x763765 #define COLOR_FmdlMaterialInstanceHeader 0x3C8D86 #define COLOR_FmdlBoneGroup 0x8A9872 #define COLOR_FmdlTextureRefUnit 0xED688E #define COLOR_FmdlMaterialParameter 0x7C706F #define COLOR_FmdlShaderPlatformAliasUnit 0x939FC8 #define COLOR_FmdlMeshDataLayoutDesc 0x000080 #define COLOR_FmdlMeshBufferHeader 0x008000 #define COLOR_FmdlMeshBufferFormatElement 0x008080 #define COLOR_FmdlStringHeader 0x800000 #define COLOR_FmdlBoundingBox 0x800080 #define COLOR_FmdlFileMeshBufferHeader 0x808000 #define COLOR_FmdlLodInfo 0x808080 #define COLOR_FmdlIBufferSlice 0x000040 #define COLOR_FmdlType18 0x0000c0 #define COLOR_FmdlType20 0x008040 #define COLOR_PathCode64 0x0080c0 #define COLOR_StrCode 0x800040 #define COLOR_FmdlMaterialParameterVector 0x8000c0 #define COLOR_Vertices 0x00c0c0 #define COLOR_BoneWeights 0x808040 #define COLOR_Normals 0x8080c0 #define COLOR_Colors 0x004000 #define COLOR_BoneIndices 0x004080 #define COLOR_Uv1 0x804000 #define COLOR_Uv2 0x804080 #define COLOR_Uv3 0x80c000 #define COLOR_Uv4 0x80c080 #define COLOR_UnknownWeights 0x004040 #define COLOR_UnknownIndices 0x0040c0 #define COLOR_Tangents 0x00c040 #define COLOR_Triangles 0x804040 enum FMDL_FEATURE_TYPE { FMDL_FEATURE_TYPE_BONE_DEFS = 0, FMDL_FEATURE_TYPE_MESH_DEFS_GROUP_HEADERS = 1, FMDL_FEATURE_TYPE_MESH_DEFS_GROUP_DEFS = 2, FMDL_FEATURE_TYPE_MESH_DEFS = 3, FMDL_FEATURE_TYPE_MATERIAL_INSTANCE_HEADERS = 4, FMDL_FEATURE_TYPE_BONE_GROUPS = 5, FMDL_FEATURE_TYPE_TEXTURE_REFS = 6, FMDL_FEATURE_TYPE_MATERIAL_PARAMS = 7, FMDL_FEATURE_TYPE_SHADER_PLATFORM_ALIASES = 8, FMDL_FEATURE_TYPE_MESH_DATA_LAYOUT_DESCS = 9, FMDL_FEATURE_TYPE_MESH_BUFFER_HEADERS = 10, FMDL_FEATURE_TYPE_MESH_BUFFER_FORMAT_ELEMENTS = 11, FMDL_FEATURE_TYPE_STRING_HEADER = 12, FMDL_FEATURE_TYPE_BOUNDING_BOXES = 13, FMDL_FEATURE_TYPE_FILE_MESH_BUFFER_HEADERS = 14, FMDL_FEATURE_TYPE_LOD_INFO = 16, FMDL_FEATURE_TYPE_IBUFFER_SLICES = 17, FMDL_FEATURE_TYPE_UNK_18 = 18, FMDL_FEATURE_TYPE_UNK_19 = 19, FMDL_FEATURE_TYPE_UNK_20 = 20, FMDL_FEATURE_TYPE_PATH_HASHES = 21, FMDL_FEATURE_TYPE_NAME_HASHES = 22, }; enum FMDL_BUFFER_TYPE { FMDL_BUFFER_TYPE_MATERIAL_PARAMS = 0, FMDL_BUFFER_TYPE_VERTICES = 2, FMDL_BUFFER_TYPE_STRINGS = 3 }; typedef struct { FMDL_FEATURE_TYPE Type; ubyte CountOverflow; ushort EntryCount; // Entry count == CountOverflow * (UINT16_MAX + 1) + EntryCount uint DataOffset; } FeatureHeader ; uint GetFeatureEntryCount(FeatureHeader& header) { return (uint)header.CountOverflow * 0x10000 + header.EntryCount; } typedef struct { FMDL_BUFFER_TYPE Type; uint DataOffset; uint DataSize; } BufferHeader ; typedef ushort _NameIndex; typedef ushort _PathIndex; struct FMDL_BONE_FLAGS { ushort HasBoundingBox : 1; ushort B : 1; ushort C : 1; ushort : 5; }; typedef struct { _NameIndex NameIndex; short ParentIndex; ushort AABBIndex; FMDL_BONE_FLAGS Flags; Assert(Flags.B == 0); FSkip(8); Vector4 LocalPosition; Vector4 WorldPosition; } FmdlBoneDef ; struct FMDL_MESH_GROUP_HEADER_FLAGS { ushort Invisible : 1; ushort A : 1; ushort B : 1; ushort : 5; }; typedef struct { _NameIndex NameIndex; FMDL_MESH_GROUP_HEADER_FLAGS Flags; Assert(Flags.B == 0); short ParentIndex; short VectorsIndex; // used for type A } FmdlMeshGroupHeader ; typedef struct { uint Unknown; Assert(Unknown == 0); ushort MeshGroupHeaderIndex; ushort MeshCount; ushort MeshesStartIndex; ushort AABBIndex; uint Padding0 ; Assert(Padding0 == 0); ushort IBufferSlicesStartIndex; ushort Padding1 ; Assert(Padding1 == 0); uint Padding2 ; Assert(Padding2 == 0); uint64 Padding3 ; Assert(Padding3 == 0); } FmdlMeshGroupDef ; /* enum TEMP_FINAL_BLENDSTATE { TEMP_FINAL_BLENDSTATE_None, TEMP_FINAL_BLENDSTATE_AlphaBlend, TEMP_FINAL_BLENDSTATE_Add, TEMP_FINAL_BLENDSTATE_Sub, TEMP_FINAL_BLENDSTATE_Mul, TEMP_FINAL_BLENDSTATE_Min, TEMP_FINAL_BLENDSTATE_Max, TEMP_FINAL_BLENDSTATE_PreMultiplied-AlphaBlend, TEMP_FINAL_BLENDSTATE_PreMultiplied-Add, TEMP_FINAL_BLENDSTATE_Unknown }; */ struct FMDL_MESH_DEF_FLAGS { // POLY // ModelDecal::Create@14024e656, & 0x6d0 (TODO_USE_DEPTHBIAS, TODO_PD, TODO_PB_01, C, A) // BYTE 0 // ========= // ModelPacketRenderControlBase::GetRenderState@14023d0f9, & 0xF uint TODO_DEPTHBIAS_OR_BLENDMODE : 4; // ModelPacketRenderControlBase::GetRenderState@14023d0f9, & 0x10, some value = (UseUnknownOffset ? UnknownOffset + 1 : 0); // DrawModelArrayMultiObject@14023966b uint TODO_USE_DEPTHBIAS : 1; // ModelPacketRenderControlBase::GetRenderState@14023d0c7, >> 5 uint TODO_CULLING : 1; // ModelPacketRenderControlBase::GetRenderState@14023d0e5, >> 6 uint TODO_DEPTHTESTMODE : 1; // ModelPacketRenderControlBase::GetRenderState@14023d0d2, >> 7 // 14025b2a3, set in code uint TODO_ALPHATESTMODE_01 : 1; // BYTE 1 // ========= // 14025b2a3 sets it in code uint NoShadow : 1; // SEE: ModelDecal::Create above uint C : 1; // 14026c5c0, >> 10 uint A : 1; uint : 2; // 14026c5c6, >> 13 uint B : 1; // ModelPacketRenderControlBase::GetRenderState@14023d0d2, >> 14 uint TODO_ALPHATESTMODE_2 : 1; // DrawModelArrayMultiObject@1402398fc, >> 0xF uint L: 1; // BYTE 3 // ========= // DrawModelArrayMultiObject@140239648, >> 0x10 & 0xF uint D : 4; // DrawModelArrayMultiObject@140239912, & 0x7f00000 uint M : 7; }; struct FmdlIBufferSlice; typedef struct { FMDL_MESH_DEF_FLAGS Flags; ushort MaterialInstanceIndex; ushort BoneGroupIndex; ushort DataLayoutIndex; ushort VertexCount; ushort VerticesStartIndex; ushort Padding0 ; Assert(Padding0 == 0); FmdlIBufferSlice HighLodSlice; uint IBufferSlicesStartIndex; // Only actually used if some EXE byte says to use multiple slices. Each slice's StartIndex is relative to the main slice. FSkip(0x14); } FmdlMeshDef ; typedef struct { _NameIndex NameIndex; ushort Padding0 ; Assert(Padding0 == 0); _NameIndex MaterialIndex; byte TextureParamCount; byte VectorParamCount; ushort TextureParamsStartIndex; ushort VectorParamsStartIndex; uint Padding1 ; Assert(Padding1 == 0); } FmdlMaterialInstanceHeader ; typedef struct { ushort UseWeightCount; Assert(UseWeightCount <= 4); // What is the largest number of bones any given vertex referencing this bone group use? ushort BoneCount; Assert(UseWeightCount <= BoneCount); ushort BoneIndices[BoneCount]; FSkip(0x40 - BoneCount * sizeof(ushort)); } FmdlBoneGroup ; typedef struct { _NameIndex NameIndex; // For "/Assets/path/name.ftex" this is StrCode("name") if TPP or just "name.ext" (ext can be tga, psd, etc.) if GZ _PathIndex PathIndex; // For "/Assets/path/name.ftex" this is PathCode64("/Assets/path/name.ftex") if TPP or just "/Assets/path/" if GZ } FmdlTextureRefUnit ; typedef struct { _NameIndex ParamNameIndex; ushort ReferenceIndex; // Can be either a path index to a .ftex or an index into the material params buffer } FmdlMaterialParameter ; typedef struct { _NameIndex ShaderNameIndex; _NameIndex TechniqueNameIndex; } FmdlShaderPlatformAliasUnit ; typedef struct { byte BufferCount; byte FormatElementCount; byte Unknown0; //Assert(Unknown0 == 0); //Possibly the first UV set's index. byte UvCount; ushort BufferHeadersStartIndex; ushort FormatElementsStartIndex; } FmdlMeshDataLayoutDesc ; typedef struct { byte FileMeshBufferHeaderIndex; byte FormatElementCount; byte Stride; byte BindSlot; Assert(BindSlot <= 3); uint Offset; } FmdlMeshBufferHeader ; enum MESH_BUFFER_FORMAT_ELEMENT_USAGE { MESH_BUFFER_FORMAT_ELEMENT_USAGE_POSITION = 0, MESH_BUFFER_FORMAT_ELEMENT_USAGE_BONE_WEIGHT0 = 1, MESH_BUFFER_FORMAT_ELEMENT_USAGE_NORMAL = 2, MESH_BUFFER_FORMAT_ELEMENT_USAGE_COLOR = 3, MESH_BUFFER_FORMAT_ELEMENT_USAGE_BONE_INDEX0 = 7, MESH_BUFFER_FORMAT_ELEMENT_USAGE_UV0 = 8, MESH_BUFFER_FORMAT_ELEMENT_USAGE_UV1 = 9, MESH_BUFFER_FORMAT_ELEMENT_USAGE_UV2 = 10, MESH_BUFFER_FORMAT_ELEMENT_USAGE_UV3 = 11, MESH_BUFFER_FORMAT_ELEMENT_USAGE_BONE_WEIGHT1 = 12, MESH_BUFFER_FORMAT_ELEMENT_USAGE_BONE_INDEX1 = 13, MESH_BUFFER_FORMAT_ELEMENT_USAGE_TANGENT = 14, }; enum MESH_BUFFER_FORMAT_ELEMENT_TYPE { MESH_BUFFER_FORMAT_ELEMENT_TYPE_R32G32B32_FLOAT = 1, // MESH_BUFFER_FORMAT_ELEMENT_TYPE_R16_UINT = 4, MESH_BUFFER_FORMAT_ELEMENT_TYPE_R16G16B16A16_FLOAT = 6, MESH_BUFFER_FORMAT_ELEMENT_TYPE_R16G16_FLOAT = 7, MESH_BUFFER_FORMAT_ELEMENT_TYPE_R8G8B8A8_UNORM = 8, MESH_BUFFER_FORMAT_ELEMENT_TYPE_R8G8B8A8_UINT = 9, }; typedef struct { MESH_BUFFER_FORMAT_ELEMENT_USAGE Usage; Assert(Usage != 4 && Usage != 5 && Usage != 6 && Usage < 15); MESH_BUFFER_FORMAT_ELEMENT_TYPE Type; Assert(Type != 0 && Type != 2 && Type != 3 && Type != 5 && Type < 10); Assert(Usage != 4); ushort Offset; } FmdlMeshBufferFormatElement ; typedef struct { ushort BufferType; Assert(BufferType == FMDL_BUFFER_TYPE_STRINGS); ushort Length; uint Offset; } FmdlStringHeader ; typedef struct { Vector4 Max; Vector4 Min; } FmdlBoundingBox ; enum FMDL_FILE_MESH_BUFFER_TYPE { FMDL_FILE_MESH_BUFFER_TYPE_VBUFFER = 0, FMDL_FILE_MESH_BUFFER_TYPE_INDEX_BUFFER = 1, }; typedef struct { FMDL_FILE_MESH_BUFFER_TYPE Type; FSkip(2); uint DataSize; uint DataOffset; uint Padding ; Assert(Padding == 0); } FmdlFileMeshBufferHeader ; typedef struct { uint StartIndex; uint Count; } FmdlIBufferSlice ; typedef struct { ushort LodCount; FSkip(2); float unknown0; float unknown1; float unknown2; } FmdlLodInfo ; typedef struct { uint64 unknown0; //Always 0. } FmdlType18 ; typedef struct { uint Unknown0 ; Assert(Unknown0 == 0); float unknown0; //Nulling triggers lowest LOD faces. float unknown1; float unknown2; float LodPolygonSize; //Always a whole number? float LodNearSize; float LodFarSize; byte DrawRejectionLevel; // StaticModel's enum gets converted to this number FSkip(3); byte RejectFarRangeShadowCastLevel ; // StaticModel's enum gets converted to this number FSkip(0x5C); } FmdlType20 ; struct FmdlHeader { char Signature[4]; Assert(Signature == "FMDL"); float Version; Assert(Version == 2.03f || Version == 2.04f); uint FileDescOffset; uint Padding0 ; Assert(Padding0 == 0); uint FeatureTypes; uint Padding1 ; Assert(Padding1 == 0); uint BufferTypes; uint Padding1 ; Assert(Padding1 == 0); uint FeatureCount; uint BufferCount; uint FeaturesDataOffset; uint FeaturesDataSize; uint BuffersDataOffset; uint BuffersDataSize; } Header ; FSeek(Header.FileDescOffset); // FileDesc FeatureHeader FeatureHeaders[Header.FeatureCount] ; local int _FeatureIndices[23]; local int fFit; local int fIdx; local int rFIdx; for (fIdx = 0, rFIdx = 0, fFit = 1; fIdx < 23; fIdx++, fFit = fFit << 1 | ((int)fFit < 0)) _FeatureIndices[fIdx] = ((Header.FeatureTypes & fFit) == 0) ? -1 : rFIdx++; BufferHeader BufferHeaders[Header.BufferCount] ; local int _BufferIndices[4]; local int bFit; local int bIdx; local int rBIdx; for (bIdx = 0, rBIdx = 0, bFit = 1; bIdx < 4; bIdx++, bFit = bFit << 1 | ((int)bFit < 0)) _BufferIndices[bIdx] = ((Header.BufferTypes & bFit) == 0) ? -1 : rBIdx++; // Features if (_FeatureIndices[FMDL_FEATURE_TYPE_BONE_DEFS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_BONE_DEFS]].DataOffset); FmdlBoneDef BoneDefs[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_BONE_DEFS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DEFS_GROUP_HEADERS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DEFS_GROUP_HEADERS]].DataOffset); FmdlMeshGroupHeader MeshGroupHeaders[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DEFS_GROUP_HEADERS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DEFS_GROUP_DEFS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DEFS_GROUP_DEFS]].DataOffset); FmdlMeshGroupDef MeshGroupDefs[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DEFS_GROUP_DEFS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DEFS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DEFS]].DataOffset); FmdlMeshDef MeshDefs[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DEFS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_MATERIAL_INSTANCE_HEADERS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MATERIAL_INSTANCE_HEADERS]].DataOffset); FmdlMaterialInstanceHeader MaterialInstanceHeaders[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MATERIAL_INSTANCE_HEADERS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_BONE_GROUPS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_BONE_GROUPS]].DataOffset); FmdlBoneGroup BoneGroups[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_BONE_GROUPS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_TEXTURE_REFS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_TEXTURE_REFS]].DataOffset); FmdlTextureRefUnit TexturesRefs[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_TEXTURE_REFS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_MATERIAL_PARAMS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MATERIAL_PARAMS]].DataOffset); FmdlMaterialParameter MaterialParameters[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MATERIAL_PARAMS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_SHADER_PLATFORM_ALIASES] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_SHADER_PLATFORM_ALIASES]].DataOffset); FmdlShaderPlatformAliasUnit ShaderAliases[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_SHADER_PLATFORM_ALIASES]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DATA_LAYOUT_DESCS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DATA_LAYOUT_DESCS]].DataOffset); FmdlMeshDataLayoutDesc MeshDataLayoutDescs[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_DATA_LAYOUT_DESCS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_MESH_BUFFER_HEADERS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_BUFFER_HEADERS]].DataOffset); FmdlMeshBufferHeader MeshBufferHeaders[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_BUFFER_HEADERS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_MESH_BUFFER_FORMAT_ELEMENTS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_BUFFER_FORMAT_ELEMENTS]].DataOffset); FmdlMeshBufferFormatElement MeshBufferFormatElements[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_MESH_BUFFER_FORMAT_ELEMENTS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_STRING_HEADER] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_STRING_HEADER]].DataOffset); FmdlStringHeader StringHeaders[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_STRING_HEADER]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_BOUNDING_BOXES] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_BOUNDING_BOXES]].DataOffset); FmdlBoundingBox BoundingBoxes[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_BOUNDING_BOXES]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_FILE_MESH_BUFFER_HEADERS] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_FILE_MESH_BUFFER_HEADERS]].DataOffset); FmdlFileMeshBufferHeader FileMeshBufferHeaders[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_FILE_MESH_BUFFER_HEADERS]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_LOD_INFO] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_LOD_INFO]].DataOffset); FmdlLodInfo LodInfo; Assert(GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_LOD_INFO]]) == 1); } if (_FeatureIndices[FMDL_FEATURE_TYPE_IBUFFER_SLICES] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_IBUFFER_SLICES]].DataOffset); FmdlIBufferSlice IBufferSlices[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_IBUFFER_SLICES]])]; } if (_FeatureIndices[FMDL_FEATURE_TYPE_UNK_18] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_UNK_18]].DataOffset); FmdlType18 Type18; Assert(GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_UNK_18]]) == 1); } if (_FeatureIndices[FMDL_FEATURE_TYPE_UNK_20] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_UNK_20]].DataOffset); FmdlType20 Type20; Assert(GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_UNK_20]]) == 1); } if (_FeatureIndices[FMDL_FEATURE_TYPE_PATH_HASHES] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_PATH_HASHES]].DataOffset); PathCode64 Paths[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_PATH_HASHES]])] ; } if (_FeatureIndices[FMDL_FEATURE_TYPE_NAME_HASHES] != -1) { FSeek(Header.FeaturesDataOffset + FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_NAME_HASHES]].DataOffset); StrCode Names[GetFeatureEntryCount(FeatureHeaders[_FeatureIndices[FMDL_FEATURE_TYPE_NAME_HASHES]])] ; } ``` ### `templates:fnt.bt` ```cpp struct FntHeader { ushort Version; Assert(Version == 0); // Guess ushort TexCellWidth; ushort TexCellHeight; ushort GlyphWidth; ushort GlyphHeight; ushort GlyphCount; } Header; struct GlyphDesc { uint Character; ushort TexCellOffsetY; ushort TexCellOffsetX; ushort PaddingTop; ushort PaddingBottom; ushort PaddingLeft; ushort PaddingRight; } Glyphs[Header.GlyphCount]; ``` ### `templates:fova.bt` ```cpp // FOVA - FormVariation (GZ version of .FV2) // By RLC - inspired by other FOX templates by the researchers of Modders' Heaven! // https://metalgearmodding.fandom.com/wiki/FV2#Ground_Zeroes_.FOVA LittleEndian(); struct Header { char signature[7]; if (signature=="FOVAps3") { BigEndian(); } byte version; int offsetToEntries ; int entryCount; int seven ; Assert(seven==7); } header ; struct Entries { Assert(header.offsetToEntries==FTell()); struct Entry { byte type ; //Printf("type:%x,",type); byte visibility ; Printf("visible:%u,",visibility); byte meshCount; byte textureCount; if (meshCount>0) { struct MeshGroups { uint meshGroup ; Printf("meshgroup:%x,",meshGroup); } meshGroups[meshCount] ; } if (textureCount>0) { struct Textures { uint materialInstance ; uint textureType ; byte texturePathLength; char texturePath[texturePathLength-1] ; // Someone who worked on FPK Tool back in the day might know how to handle them. Printf("materialInstance:%x,textureType:%x,texturePath:%s,\n",materialInstance,textureType,texturePath); } textures[textureCount] ; } Printf("\n"); } entry[header.entryCount] ; } entries; Assert(FTell() == FileSize(), "Failed to reach EoF."); ``` ### `templates:fox2.bt` ```cpp #define COLOR_MS_BLU 0xFBB700 #define COLOR_MS_RED 0x3F00D0 #define COLOR_MS_PRP 0xFB00B7 #define COLOR_MS_ONG 0x00B7FB #include "common/common.bt" struct DataSetFile2Header { uint Unknown0; Assert(Unknown0 == 2020565746); uint Unknown1; Assert(Unknown1 == 53); int EntityCount; int StringTableOffset; int EntitiesOffset; } Header