feat(formats,viewer): movie subtitles, voice decode, and the movie manifest
The movie cutscene subtitle + voice pipeline, driven by the ADVERTISE_MOVIE manifest (the authoritative movie -> subtitle -> voice index). Also flushes several sessions of local WIP (async viewer loading, grouped-pool XBG7/hero-ship decode, drawlog tooling). See docs/HANDOFF-movie-voice-subtitles-2026-07-19.md. Subtitles (movie_subtitle.rs): - Full movie->track->text chain; join multi-line captions sharing one timing (fixes S13A dropped "Look at it father" line); overlap-safe active_cues(); Latin-1 accents preserved. Voice (slb.rs): XACT .slb -> XMA1 RIFF; take the FIRST sub-wave bounded by its declared data size (fixes S10-S16 alternate-take garble); list_voice_clips. Manifest (movie_manifest.rs): parse ADVERTISE_MOVIE (0x5B983A08) for the real movie->voice binding (not always VOICE_<movie>; e.g. hokyu -> VOICE_D_* in etc\). Resolve the token's sound.pak path via sounds.tbl. DIRECT bindings only — the demo-id shared-clip fallback for unbound hokyu movies was verified WRONG in-game and reverted (unbound hokyu stay unvoiced; correct join key is an OPEN problem). Viewer: manifest-driven voice (movie player toggle + solo button), standalone "Voice Lines" browser, stacked caption overlay. Tests: 46 formats-lib + 11 viewer-lib + movie_manifest/movie_subtitle/slb disc tests; full workspace green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -178,6 +178,18 @@ impl PakArchive {
|
||||
})
|
||||
}
|
||||
|
||||
/// Parse **only** the TOC from a `.pak` index, without any segment data.
|
||||
///
|
||||
/// For huge archives (`sound.pak` is ~1 GB across `.p00..p04`) this lets a
|
||||
/// caller locate one entry's `(offset, size)` and read just that byte range
|
||||
/// from the segments, instead of loading the whole thing into memory. The
|
||||
/// returned entries are sorted by `name_hash` (binary-searchable).
|
||||
pub fn parse_toc(index: &[u8]) -> Result<Vec<PakEntry>, PakError> {
|
||||
// Reuse from_parts' validation with an empty data blob; the entries are
|
||||
// independent of the data.
|
||||
Ok(Self::from_parts(index, Vec::new())?.entries)
|
||||
}
|
||||
|
||||
/// All TOC entries, in stored order (ascending `name_hash`).
|
||||
pub fn entries(&self) -> &[PakEntry] {
|
||||
&self.entries
|
||||
|
||||
Reference in New Issue
Block a user