re: the dialog id to pak-entry join is not positional -- hypothesis refuted
GP_DIALOG has exactly 140 entries against the table's 70 records, a 2:1 ratio that would make the unbound join an ordering question. It does not hold: adjacent pairing gives identical element-name sets on 2 of 65 pairs, halves pairing on 0. GP_TITLE's language pairs share element sets exactly, so identical sets are the signature there; in GP_DIALOG almost nothing matches. Residual and unexplained: the only two adjacent pairs that DO match are entries 0/1 and 2/3, and 2/3 is the DIFFICULTY build. A reading I am not asserting: dialog text may be baked into language-specific sprites, which would explain the 63 by construction but leaves the 2 needing their own explanation. Not tested. The join stays unbound; positional ordering is now ruled out, which narrows where to look next. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
This commit is contained in:
47
crates/sylpheed-formats/examples/dialog_pairing.rs
Normal file
47
crates/sylpheed-formats/examples/dialog_pairing.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! Are `GP_DIALOG`'s 140 entries adjacent EN/JP pairs, one per dialog record?
|
||||
//!
|
||||
//! The dialog table has 70 records and the archive has 140 entries. If the
|
||||
//! pairing is adjacent — (0,1), (2,3), … — then dialog index = entry / 2, and the
|
||||
//! unbound id-to-entry join becomes an ordering question rather than a search.
|
||||
//!
|
||||
//! Test: for each pair, compare the SET of element names. GP_TITLE's EN/JP pairs
|
||||
//! share their sprite sets exactly except for the title art (4/7), so identical
|
||||
//! sets are the signature of a language pair.
|
||||
//!
|
||||
//! cargo run -p sylpheed-formats --example dialog_pairing
|
||||
use sylpheed_formats::{pak::PakArchive, ui_layout};
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn names(ar: &PakArchive, i: usize) -> Option<BTreeSet<String>> {
|
||||
let by = ar.read(&ar.entries()[i]).ok()?;
|
||||
let b = ui_layout::parse_build(&by)?;
|
||||
Some(b.elements.iter().map(|e| e.name.clone()).collect())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC"));
|
||||
let ar = PakArchive::open(root.join("dat/GP_DIALOG.pak")).expect("GP_DIALOG");
|
||||
let n = ar.entries().len();
|
||||
let (mut adj_same, mut adj_diff, mut skipped) = (0, 0, 0);
|
||||
for k in (0..n).step_by(2) {
|
||||
match (names(&ar, k), names(&ar, k + 1)) {
|
||||
(Some(a), Some(b)) => {
|
||||
if a == b { adj_same += 1; println!(" identical pair: entries {k}/{}", k+1) } else { adj_diff += 1 }
|
||||
}
|
||||
_ => skipped += 1,
|
||||
}
|
||||
}
|
||||
println!("ADJACENT pairing (2k, 2k+1): identical {adj_same} differing {adj_diff} unreadable {skipped}");
|
||||
// rival hypothesis: halves, (i, i+70)
|
||||
let (mut h_same, mut h_diff, mut h_skip) = (0, 0, 0);
|
||||
for k in 0..n / 2 {
|
||||
match (names(&ar, k), names(&ar, k + n / 2)) {
|
||||
(Some(a), Some(b)) => {
|
||||
if a == b { h_same += 1 } else { h_diff += 1 }
|
||||
}
|
||||
_ => h_skip += 1,
|
||||
}
|
||||
}
|
||||
println!("HALVES pairing (i, i+70): identical {h_same} differing {h_diff} unreadable {h_skip}");
|
||||
}
|
||||
29
crates/sylpheed-formats/examples/dialog_pak_shape.rs
Normal file
29
crates/sylpheed-formats/examples/dialog_pak_shape.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
//! How is `GP_DIALOG.pak` organised? Testing whether dialog id maps positionally.
|
||||
//!
|
||||
//! The dialog table gives name -> id (70 records, `DLG_SELECT_DIFFICULTY` = 2000)
|
||||
//! and the disc gives a unique four-button build at GP_DIALOG entries 2/3. Nothing
|
||||
//! joins them. If the archive were laid out in table order, or in id order, the
|
||||
//! join would be positional — this checks.
|
||||
//!
|
||||
//! cargo run -p sylpheed-formats --example dialog_pak_shape
|
||||
use sylpheed_formats::{pak::PakArchive, ui_layout};
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let root = PathBuf::from(std::env::var("SYLPHEED_DISC").expect("SYLPHEED_DISC"));
|
||||
let ar = PakArchive::open(root.join("dat/GP_DIALOG.pak")).expect("GP_DIALOG");
|
||||
let n = ar.entries().len();
|
||||
let mut builds = 0;
|
||||
let mut with_btn = 0;
|
||||
for e in ar.entries() {
|
||||
let Ok(by) = ar.read(e) else { continue };
|
||||
if let Some(b) = ui_layout::parse_build(&by) {
|
||||
builds += 1;
|
||||
if b.elements.iter().any(|el| el.name.contains("btn")) {
|
||||
with_btn += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("entries {n}, parse as builds {builds}, of those with a btn element {with_btn}");
|
||||
println!("dialog table has 70 records; 70 x 2 (EN/JP) = 140");
|
||||
}
|
||||
Reference in New Issue
Block a user