|
| 1 | +# Depack / repack: the full mod loop for Xenosaga III |
| 2 | + |
| 3 | +The kit's extraction pipeline (prep → scan → extract) is the **depack** |
| 4 | +half: it mirrors every file on the disc into a `dump/` tree. |
| 5 | +[`repack.py`](../repack.py) is the **repack** half: it writes files back |
| 6 | +into an ISO, in place, for *any* file type on either disc — models, audio, |
| 7 | +movies, event packages, textures, tables. |
| 8 | + |
| 9 | +The character-texture tools ([MODDING-CHARACTERS.md](MODDING-CHARACTERS.md)) |
| 10 | +are a format-aware front end; this layer works on whole files and is |
| 11 | +format-agnostic. |
| 12 | + |
| 13 | +## The loop |
| 14 | + |
| 15 | +```sh |
| 16 | +# 0. depack once (or reuse your existing dump/) — see the README pipeline |
| 17 | +# 1. start a mod tree containing ONLY the files you change, |
| 18 | +# mirroring the in-game paths: |
| 19 | +mkdir -p mymod/mdl/chr/pc |
| 20 | +cp dump/mdl/chr/pc/C3shion00.chr mymod/mdl/chr/pc/ |
| 21 | +# ... edit mymod/mdl/chr/pc/C3shion00.chr with whatever tool ... |
| 22 | + |
| 23 | +# 2. clone the ISO (instant on APFS) and repack the tree into it |
| 24 | +cp -c "Xenosaga ... (Disc 1).iso" MOD.iso |
| 25 | +python3 cli.py repack-tree --iso MOD.iso --mod mymod --dry-run # preview |
| 26 | +python3 cli.py repack-tree --iso MOD.iso --mod mymod # do it |
| 27 | +``` |
| 28 | + |
| 29 | +Every write is read back and verified. The GUI exposes this as card 14; |
| 30 | +single files go through `repack-extract` / `repack-patch`, and |
| 31 | +`repack-info` shows where any path lives: |
| 32 | + |
| 33 | +``` |
| 34 | +$ python3 cli.py repack-info --iso MOD.iso --path '\mdl\chr\pc\C3kosmos00.chr' |
| 35 | +\mdl\chr\pc\C3kosmos00.chr |
| 36 | + table Lba0.txt offset 0x0CCF6000 size 432384 (0x69900) |
| 37 | + lives in X3.01 -> ISO byte 0xD326800 |
| 38 | + sector allocation 434176 bytes (1792 slack) |
| 39 | +``` |
| 40 | + |
| 41 | +## Disc model (why this works, and its one hard limit) |
| 42 | + |
| 43 | +Files hide inside the `X3.*` containers, indexed by three byte-addressed |
| 44 | +tables: `Lba0` (shared system/model/audio data — **byte-identical on both |
| 45 | +discs**, so one mod tree patches Disc 1 and Disc 2 copies with identical |
| 46 | +commands), `Lba1` (Disc 1 story content, X3.11–13), `Lba2` (Disc 2 story |
| 47 | +content, X3.21–23). `repack.py` reads the ISO's own root directory for the |
| 48 | +container extents, so it works on any dump of either disc; it auto-detects |
| 49 | +which tables apply and refuses paths from the wrong disc. |
| 50 | + |
| 51 | +The engine's on-disc catalogs (`X3.00` / `X3.10` / `X3.20`) store the file |
| 52 | +tree with **literal sizes but implicit offsets** — files pack back-to-back |
| 53 | +at 2048-byte sector granularity, each starting on the sector after its |
| 54 | +predecessor's last. Consequences: |
| 55 | + |
| 56 | +* **Same-size replacement** — always safe. This is the default; anything |
| 57 | + else is rejected. |
| 58 | +* **Different size within the sector allocation** (`--pad`): the file is |
| 59 | + zero-padded to its original allocation so nothing moves. The engine |
| 60 | + still *reads* the original byte count, so this is only correct for |
| 61 | + formats that carry their own internal sizes and ignore trailing bytes |
| 62 | + (Xc/`.chr`/`.sme` packages, `txy`, ADX). Opt-in for that reason. |
| 63 | + `repack-info`'s "slack" line tells you the headroom (0–2047 bytes, |
| 64 | + whatever the original left in its final sector). |
| 65 | +* **Anything bigger** means every later file in that container shifts and |
| 66 | + the binary catalog's size chain must be rewritten — a full container |
| 67 | + rebuild. Nothing supports that yet; it is the known limit. (The catalog |
| 68 | + format is a front-coded name trie with LE32 sizes — decoded enough to |
| 69 | + know the layout, not enough to regenerate. Future work.) |
| 70 | + |
| 71 | +## Practical notes |
| 72 | + |
| 73 | +* Always patch a **copy** (`cp -c` on macOS is a free clone). Keep your |
| 74 | + originals pristine. |
| 75 | +* Patched ISOs boot in PCSX2 and on real hardware — there are no |
| 76 | + checksums or anti-tamper anywhere in the read path. |
| 77 | +* Testing in PCSX2: load from a memory-card save, not a savestate — |
| 78 | + savestates restore the *old* data from saved RAM/VRAM until the game |
| 79 | + re-streams it (any map change). |
| 80 | +* Duplicate data: unlike Xenosaga I (which buries byte-copies of textures |
| 81 | + inside battle/scene bundles), XS3 keeps one file per asset. What *does* |
| 82 | + repeat is per-variant data — each costume/cutscene model is its own |
| 83 | + `.chr` with its own palettes — so "change X everywhere" means patching |
| 84 | + every variant file, which is what mirror trees and `chr-iso-sweep` are |
| 85 | + for. |
| 86 | +* `--lba` points the resolver at a different directory of `Lba*.txt` |
| 87 | + tables if you're not using the kit's bundled ones. |
0 commit comments