use anyhow::anyhow; use log::warn; use std::{ env::args, fs::{File, create_dir_all}, io::{BufReader, Read, Seek, SeekFrom}, }; use unity_tools::{ classes::{FromValue, texture2d::Texture2D}, object::read_value, serialized_file::read_serialized_file, unityfs::UnityFS, }; fn main() -> anyhow::Result<()> { env_logger::init_from_env("LOG"); let file = || BufReader::new(File::open(args().nth(1).unwrap()).unwrap()); let mut fs = UnityFS::open(file())?; let mut fs2 = UnityFS::open(file())?; let mut i = 0; create_dir_all("/tmp/tex").unwrap(); let cabfile = fs .nodes() .iter() .find(|n| !n.name.ends_with(".resource") && !n.name.ends_with(".resS")) .ok_or(anyhow!("no CAB file found"))? .to_owned(); let ressfile = fs2 .nodes() .iter() .find(|n| n.name.ends_with(".resS")) .cloned(); let mut cab = fs.read(&cabfile)?; let mut ress = ressfile.map(|p| fs2.read(&p)).transpose()?; let file = read_serialized_file(&mut cab)?; for ob in file.objects { cab.seek(SeekFrom::Start(ob.data_offset))?; let typetree = if ob.type_id < 0 { unimplemented!() } else { &file.types[ob.type_id as usize] }; if let Some(typetree) = &typetree.type_tree { if typetree.type_string != "Texture2D" { continue; } let value = read_value(typetree, file.endianness, &mut cab)?; let mut texture = Texture2D::from_value(value).unwrap(); if texture.image_data.len() == 0 { let ress = ress.as_mut().unwrap(); ress.seek(SeekFrom::Start(texture.stream_data.offset as u64))?; ress.by_ref() .take(texture.stream_data.size as u64) .read_to_end(&mut texture.image_data)?; } let path = format!( "/tmp/tex/{}_{i}.png", texture.name.replace("/", "-").replace(".", "-") ); match texture.to_image() { Ok(im) => { im.save(&path).unwrap(); println!("{path}"); } Err(e) => warn!("{e}"), } i += 1; } } Ok(()) }