Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 72 additions & 16 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 2 additions & 4 deletions src-tauri/crates/quartz-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,8 @@ image = { version = "0.25", default-features = false, features = ["png", "jpeg"]
# Logging (macros only)
tracing = "0.1"

# RitoShark crates — BIN/format handling + TEX decode. Pinned to a rev branched
# off d6af5ac (the rev Flint uses) that adds Wad::from_reader_toc + seek-per-chunk
# reads for lightweight WAD indexing/extraction (branch: wad-toc-seek).
ritoshark = { git = "https://github.com/RitoShark/RitoShark-Crates", rev = "2ed5554828764cf0ce9f3f426ed6352fea39578a", features = ["tex", "anim", "mesh"] }
# RitoShark crates — BIN/format handling + TEX decode. Same rev Flint pins.
ritoshark = { git = "https://github.com/RitoShark/RitoShark-Crates", rev = "24fe6b3", features = ["tex", "anim", "mesh"] }

[dev-dependencies]
# Scratch dirs for the live-install extraction tests (auto-removed on drop).
Expand Down
55 changes: 54 additions & 1 deletion src-tauri/crates/quartz-lib/src/bin/ritoshark_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,12 @@ pub fn write_bin(tree: &Bin) -> Result<Vec<u8>> {
/// # Returns
/// A String containing the ritobin text format with resolved names
pub fn tree_to_text_with_hashes(tree: &Bin, hashes: &HashMapper) -> Result<String> {
Ok(ritoshark::bin::to_text(tree, Some(hashes)))
/* `AnimationGraphData.mBlendDataTable` keys pack two clip hashes into a u64;
printed plainly they are meaningless 20-digit integers. `from_text` accepts
the readable `"From" -> "To"` form and the raw u64 alike, so every text→bin
path still round-trips whichever form the text carries. */
let opts = ritoshark::bin::TextOptions { blend_keys: true };
Ok(ritoshark::bin::to_text_with(tree, Some(hashes), &opts))
}

/// Load BIN hashes from `hashes-bin.lmdb` (named DB `"bin"`, 4-byte BE keys).
Expand Down Expand Up @@ -283,3 +288,51 @@ pub fn text_to_tree(text: &str) -> Result<Bin> {
ritoshark::bin::from_text(text, None)
.map_err(|e| BinError(format!("Failed to parse text: {}", e)))
}

#[cfg(test)]
mod blend_text_tests {
use super::*;
use ritoshark::bin::{BinEntry, BinType, BinValue, BlendKey, BLEND_DATA_TABLE};
use ritoshark::hash::fnv1a;

#[test]
fn blend_keys_print_readable_and_round_trip() {
let resolved = BlendKey::from_names("Attack1", "Laugh").to_u64();
let unresolved = ((fnv1a("Attack1") as u64) << 32) | 0xdead_beef;
let mut fields = indexmap::IndexMap::new();
fields.insert(
BLEND_DATA_TABLE,
BinValue::Map {
key: BinType::U64,
value: BinType::F32,
entries: vec![
(BinValue::U64(resolved), BinValue::F32(0.1)),
(BinValue::U64(unresolved), BinValue::F32(0.2)),
],
},
);
let mut bin = Bin::new();
bin.entries.push(BinEntry {
path_hash: 0x1,
class_hash: 0x2,
fields,
});

let mut mapper = HashMapper::new();
mapper.insert(fnv1a("Attack1") as u64, "Attack1");
mapper.insert(fnv1a("Laugh") as u64, "Laugh");

let text = tree_to_text_with_hashes(&bin, &mapper).unwrap();
assert!(
text.contains("\"Attack1\" -> \"Laugh\""),
"resolved pair readable: {text}"
);
assert!(
text.contains("\"Attack1\" -> 0xdeadbeef"),
"unresolved half stays hex: {text}"
);

let parsed = text_to_tree(&text).unwrap();
assert_eq!(write_bin(&bin).unwrap(), write_bin(&parsed).unwrap());
}
}