aboutsummaryrefslogtreecommitdiff
path: root/exporter/src
diff options
context:
space:
mode:
Diffstat (limited to 'exporter/src')
-rw-r--r--exporter/src/bin/debug.rs61
-rw-r--r--exporter/src/bin/gltf.rs99
-rw-r--r--exporter/src/bin/json.rs34
-rw-r--r--exporter/src/bin/meshes.rs59
-rw-r--r--exporter/src/bin/probe.rs21
-rw-r--r--exporter/src/bin/textures.rs55
-rw-r--r--exporter/src/bin/typegraph.rs124
-rw-r--r--exporter/src/bin/yaml.rs50
-rw-r--r--exporter/src/main.rs3
9 files changed, 506 insertions, 0 deletions
diff --git a/exporter/src/bin/debug.rs b/exporter/src/bin/debug.rs
new file mode 100644
index 0000000..92713ba
--- /dev/null
+++ b/exporter/src/bin/debug.rs
@@ -0,0 +1,61 @@
+use std::{env::args, fs::File, io::BufReader};
+use unity_tools::{serialized_file::SerializedFile, unityfs::UnityFS};
+
+fn main() -> anyhow::Result<()> {
+ env_logger::init_from_env("LOG");
+ let file = BufReader::new(File::open(args().nth(1).unwrap())?);
+ let mut fs = UnityFS::open(file)?;
+
+ let node = fs.find_main_file().unwrap().to_owned();
+ let mut cab = fs.read(&node)?;
+ let file = SerializedFile::read(&mut cab)?;
+
+ for ob in file.objects {
+ // eprintln!("{:#?}", ob);
+ let typetree = if ob.type_id < 0 {
+ unimplemented!()
+ } else {
+ // file.types
+ // .iter()
+ // .find(|t| t.class_id == ob.type_id)
+ // .expect("unknown type")
+ &file.types[ob.type_id as usize]
+ };
+ // fn print_types(tt: &TypeTreeNode) {
+ // println!("{}", tt.type_string);
+ // for c in &tt.children {
+ // print_types(&c);
+ // }
+ // }
+ // fn print_crit_types(tt: &TypeTreeNode) {
+ // let mut crit = tt.byte_size == -1 || tt.children.is_empty();
+ // for c in &tt.children {
+ // print_crit_types(&c);
+ // crit &= c.byte_size != -1
+ // }
+ // if crit {
+ // println!("{}", tt.type_string);
+ // }
+ // }
+ if let Some(tree) = &typetree.type_tree {
+ println!("{}", tree.type_string);
+ // print_crit_types(tree);
+ // print_types(tree);
+ }
+ // eprintln!("{typetree:#?}");
+
+ // let value = read_value(typetree.type_tree.as_ref().unwrap(), e, &mut cab)?;
+
+ // if let Value::Object { class, .. } = &value {
+ // println!("{class}")
+ // }
+
+ // debug!(
+ // "{}",
+ // serde_json::to_string_pretty(&value.to_json()).unwrap()
+ // )
+ }
+ // eprintln!("{:#?}", file.types);
+
+ Ok(())
+}
diff --git a/exporter/src/bin/gltf.rs b/exporter/src/bin/gltf.rs
new file mode 100644
index 0000000..fb6b72d
--- /dev/null
+++ b/exporter/src/bin/gltf.rs
@@ -0,0 +1,99 @@
+#![feature(array_chunks)]
+use anyhow::anyhow;
+use glam::{Affine3A, Mat4};
+use gltf::Glb;
+use log::warn;
+use std::{borrow::Cow, env::args, fs::File, io::BufReader};
+use unity_tools::{
+ classes::{
+ gameobject::GameObject,
+ mesh_renderer::{MeshRenderer, SkinnedMeshRenderer},
+ transform::Transform,
+ },
+ serialized_file::SerializedFile,
+ 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 cabfile = fs
+ .find_main_file()
+ .ok_or(anyhow!("no CAB file found"))?
+ .to_owned();
+
+ let mut cab = fs.read(&cabfile)?;
+ let mut file = SerializedFile::read(&mut cab)?;
+ let gameobjects = file
+ .objects
+ .iter()
+ .filter(|ob| file.get_object_type_tree(ob).unwrap().type_string == "GameObject")
+ .cloned()
+ .collect::<Vec<_>>();
+
+ // let mut root_tr = Transform::from_value(file.read_object(ob)?)?;
+ // while !root_tr.father.is_null() {
+ // root_tr = root_tr.father.load(&mut file)?;
+ // }
+ // eprintln!("{root_tr:?}");
+
+ let mut root = gltf_json::Root::default();
+
+ for ob in gameobjects {
+ let go = file.read_object(ob)?.parse::<GameObject>()?;
+ for comp in go.components {
+ let ob = comp.load(&mut file)?;
+ let mut global_transform = Affine3A::default();
+ match ob.class_name().unwrap().as_str() {
+ "Transform" => {
+ let mut tr = ob.parse::<Transform>()?;
+ let mut transforms = Vec::new();
+ loop {
+ transforms.push(
+ Mat4::from_translation(tr.local_position)
+ * Mat4::from_scale(tr.local_scale)
+ * Mat4::from_quat(tr.local_rotation),
+ );
+ if tr.father.is_null() {
+ break;
+ } else {
+ tr = tr.father.load(&mut file)?;
+ }
+ }
+ global_transform =
+ Affine3A::from_mat4(transforms.into_iter().reduce(|a, b| a * b).unwrap())
+ }
+ "SkinnedMeshRenderer" => {
+ let mr = ob.parse::<SkinnedMeshRenderer>()?;
+ }
+ "MeshRenderer" => {
+ let mr = ob.parse::<MeshRenderer>()?;
+ }
+ x => warn!("unknown component {x:?}"),
+ }
+ }
+ }
+
+ let json_string = gltf_json::serialize::to_string(&root).expect("Serialization error");
+ let mut json_offset = json_string.len();
+ align_to_multiple_of_four(&mut json_offset);
+ let glb = Glb {
+ header: gltf::binary::Header {
+ magic: *b"glTF",
+ version: 2,
+ length: json_offset as u32,
+ },
+ bin: None,
+ json: Cow::Owned(json_string.into_bytes()),
+ };
+ let writer = std::fs::File::create("triangle.glb").expect("I/O error");
+ glb.to_writer(writer).expect("glTF binary output error");
+
+ Ok(())
+}
+
+fn align_to_multiple_of_four(n: &mut usize) {
+ *n = (*n + 3) & !3;
+}
diff --git a/exporter/src/bin/json.rs b/exporter/src/bin/json.rs
new file mode 100644
index 0000000..dd83de6
--- /dev/null
+++ b/exporter/src/bin/json.rs
@@ -0,0 +1,34 @@
+use std::{
+ env::{args, var},
+ fs::File,
+ io::{BufReader, stdout},
+};
+use unity_tools::{serialized_file::SerializedFile, unityfs::UnityFS};
+
+fn main() -> anyhow::Result<()> {
+ env_logger::init_from_env("LOG");
+ let file = BufReader::new(File::open(args().nth(1).unwrap())?);
+ let mut fs = UnityFS::open(file)?;
+ let filter = args().nth(2);
+ let pretty = var("PRETTY").is_ok();
+
+ let node = fs.find_main_file().unwrap().to_owned();
+ let mut cab = fs.read(&node)?;
+ let mut file = SerializedFile::read(&mut cab)?;
+ for ob in file.objects.clone() {
+ if let Some(f) = &filter {
+ if file.get_object_type_tree(&ob)?.type_string != *f && ob.path_id.to_string() != *f {
+ continue;
+ }
+ }
+ let value = file.read_object(ob)?;
+ if pretty {
+ serde_json::to_writer_pretty(stdout(), &value.to_json()).unwrap();
+ } else {
+ serde_json::to_writer(stdout(), &value.to_json()).unwrap();
+ }
+ println!()
+ }
+
+ Ok(())
+}
diff --git a/exporter/src/bin/meshes.rs b/exporter/src/bin/meshes.rs
new file mode 100644
index 0000000..e3758c4
--- /dev/null
+++ b/exporter/src/bin/meshes.rs
@@ -0,0 +1,59 @@
+#![feature(array_chunks)]
+use anyhow::anyhow;
+use std::{
+ env::args,
+ fs::{File, create_dir_all},
+ io::{BufReader, BufWriter, Write},
+};
+use unity_tools::{
+ classes::mesh::{Mesh, VertexDataChannel},
+ object::parser::FromValue,
+ serialized_file::SerializedFile,
+ 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 i = 0;
+ create_dir_all("/tmp/a").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 mut cab = fs.read(&cabfile)?;
+ let mut file = SerializedFile::read(&mut cab)?;
+ for ob in file.objects.clone() {
+ if file.get_object_type_tree(&ob)?.type_string != "Mesh" {
+ continue;
+ }
+ let value = file.read_object(ob)?;
+ let mesh = Mesh::from_value(value).unwrap();
+ let mut obj = BufWriter::new(File::create(format!(
+ "/tmp/a/{}_{i}.obj",
+ mesh.name.replace("/", "-").replace(".", "-")
+ ))?);
+
+ let (pos_dims, positions) = mesh
+ .vertex_data
+ .read_channel(VertexDataChannel::Position)
+ .unwrap();
+ assert_eq!(pos_dims, 3);
+
+ for [x, y, z] in positions.array_chunks() {
+ writeln!(obj, "v {x} {y} {z}")?;
+ }
+ for [a, b, c] in mesh.read_indecies() {
+ writeln!(obj, "f {} {} {}", a + 1, b + 1, c + 1)?;
+ }
+ i += 1;
+ }
+
+ Ok(())
+}
diff --git a/exporter/src/bin/probe.rs b/exporter/src/bin/probe.rs
new file mode 100644
index 0000000..feca633
--- /dev/null
+++ b/exporter/src/bin/probe.rs
@@ -0,0 +1,21 @@
+use anyhow::Result;
+use std::{env::args, fs::File, io::BufReader};
+use unity_tools::{serialized_file::SerializedFileHeader, unityfs::UnityFS};
+
+fn main() -> Result<()> {
+ let file = BufReader::new(File::open(args().nth(1).unwrap())?);
+ let mut fs = UnityFS::open(file)?;
+
+ let node = fs.find_main_file().unwrap().to_owned();
+ let mut cab = fs.read(&node)?;
+ let ch = SerializedFileHeader::read(&mut cab)?;
+
+ if fs.unity_version.is_ascii() && ch.generator_version.is_ascii() && ch.format < 100 {
+ println!(
+ "{}\t{}\t{}\t{}",
+ fs.file_version, fs.unity_version, ch.format, ch.generator_version
+ );
+ }
+
+ Ok(())
+}
diff --git a/exporter/src/bin/textures.rs b/exporter/src/bin/textures.rs
new file mode 100644
index 0000000..2e077fe
--- /dev/null
+++ b/exporter/src/bin/textures.rs
@@ -0,0 +1,55 @@
+use anyhow::anyhow;
+use log::warn;
+use std::{
+ env::args,
+ fs::{File, create_dir_all},
+ io::BufReader,
+};
+use unity_tools::{
+ classes::texture2d::Texture2D, object::parser::FromValue, serialized_file::SerializedFile,
+ 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/a").unwrap();
+
+ let cabfile = fs
+ .find_main_file()
+ .ok_or(anyhow!("no CAB file found"))?
+ .to_owned();
+
+ let mut cab = fs.read(&cabfile)?;
+ let mut file = SerializedFile::read(&mut cab)?;
+ for ob in file.objects.clone() {
+ if file.get_object_type_tree(&ob)?.type_string != "Texture2D" {
+ continue;
+ }
+ let value = file.read_object(ob)?;
+ let mut texture = Texture2D::from_value(value)?;
+ if texture.image_data.is_empty() {
+ texture.image_data = texture.stream_data.read(&mut fs2)?;
+ }
+ let path = format!(
+ "/tmp/a/{}_{i}.png",
+ texture.name.replace("/", "-").replace(".", "-")
+ );
+ match texture.to_image() {
+ Ok(im) => {
+ if !im.as_rgba32f().is_some() {
+ im.save(&path).unwrap();
+ println!("{path}");
+ }
+ }
+ Err(e) => warn!("{e}"),
+ }
+ i += 1;
+ }
+
+ Ok(())
+}
diff --git a/exporter/src/bin/typegraph.rs b/exporter/src/bin/typegraph.rs
new file mode 100644
index 0000000..ea55e05
--- /dev/null
+++ b/exporter/src/bin/typegraph.rs
@@ -0,0 +1,124 @@
+#![feature(random)]
+use std::{
+ collections::{BTreeMap, BTreeSet},
+ env::args,
+ fs::File,
+ io::BufReader,
+};
+use unity_tools::{
+ serialized_file::{SerializedFile, TypeTreeNode},
+ unityfs::UnityFS,
+};
+
+fn main() -> anyhow::Result<()> {
+ env_logger::init_from_env("LOG");
+ let file = BufReader::new(File::open(args().nth(1).unwrap())?);
+ let mut fs = UnityFS::open(file)?;
+ let filter_prims = args().any(|a| a == "no_primitives");
+
+ let mut edges = BTreeSet::new();
+ let node = fs.find_main_file().unwrap().to_owned();
+ let mut cab = fs.read(&node)?;
+ let file = SerializedFile::read(&mut cab)?;
+
+ for ob in file.objects {
+ let typetree = if ob.type_id < 0 {
+ unimplemented!()
+ } else {
+ &file.types[ob.type_id as usize]
+ };
+ fn print_types(
+ edges: &mut BTreeSet<(String, String)>,
+ filter_prims: bool,
+ tt: TypeTreeNode,
+ ) {
+ for c in tt.children {
+ let mut c = vec![c];
+ loop {
+ let mut nc = Vec::new();
+ let mut f = false;
+ for mut c in c {
+ if let Some(inner) = c.type_string.strip_prefix("PPtr<") {
+ c.type_string = inner.strip_suffix(">").unwrap().to_owned();
+ f = true;
+ } else if matches!(
+ c.type_string.as_str(),
+ "Array" | "pair" | "map" | "vector"
+ ) {
+ nc.extend(c.children);
+ f = true
+ } else {
+ nc.push(c);
+ };
+ }
+ c = nc;
+ if !f {
+ break;
+ }
+ }
+ for c in c {
+ if filter_prims && is_primitive(&c.type_string) {
+ continue;
+ }
+ edges.insert((tt.type_string.to_owned(), c.type_string.to_owned()));
+ print_types(edges, filter_prims, c);
+ }
+ }
+ }
+
+ if let Some(tree) = &typetree.type_tree {
+ print_types(&mut edges, filter_prims, tree.clone());
+ }
+ }
+ let nodes = edges
+ .iter()
+ .flat_map(|(k, v)| [k, v])
+ .collect::<BTreeSet<_>>();
+ let ids = nodes
+ .into_iter()
+ .enumerate()
+ .map(|(i, n)| (n, i))
+ .collect::<BTreeMap<_, _>>();
+
+ println!("digraph {{");
+ for (name, id) in &ids {
+ println!("t{id} [label={name:?}]");
+ }
+ for (a, b) in &edges {
+ println!("t{} -> t{}", ids[a], ids[b]);
+ }
+ println!("}}");
+
+ Ok(())
+}
+
+fn is_primitive(s: &str) -> bool {
+ matches!(
+ s,
+ "Type*"
+ | "int"
+ | "unsigned int"
+ | "UInt8"
+ | "UInt16"
+ | "UInt32"
+ | "UInt64"
+ | "SInt8"
+ | "SInt16"
+ | "SInt32"
+ | "SInt64"
+ | "bool"
+ | "float"
+ | "string"
+ | "float3"
+ | "float4"
+ | "float2"
+ | "Vector2f"
+ | "Vector3f"
+ | "Vector4f"
+ | "Matrix4x4f"
+ | "ColorRGBA"
+ | "Rectf"
+ | "Quaternionf"
+ | "xform"
+ )
+}
diff --git a/exporter/src/bin/yaml.rs b/exporter/src/bin/yaml.rs
new file mode 100644
index 0000000..4ef8933
--- /dev/null
+++ b/exporter/src/bin/yaml.rs
@@ -0,0 +1,50 @@
+use serde_yml::Value;
+use std::{
+ env::args,
+ fs::File,
+ io::{BufReader, stdout},
+};
+use unity_tools::{classes::HValue, serialized_file::SerializedFile, unityfs::UnityFS};
+
+fn main() -> anyhow::Result<()> {
+ env_logger::init_from_env("LOG");
+ let file = BufReader::new(File::open(args().nth(1).unwrap())?);
+ let mut fs = UnityFS::open(file)?;
+ let filter = args().nth(2);
+
+ let node = fs.find_main_file().unwrap().to_owned();
+ let mut cab = fs.read(&node)?;
+
+ let mut file = SerializedFile::read(&mut cab)?;
+ for ob in file.objects.clone() {
+ if let Some(f) = &filter {
+ if file.get_object_type_tree(&ob)?.type_string != *f && ob.path_id.to_string() != *f {
+ continue;
+ }
+ }
+ let value = file.read_object(ob)?;
+ let hvalue = HValue::from_value(value)?;
+
+ let mut hvalue = serde_yml::to_value(hvalue)?;
+ trim_large_arrays(&mut hvalue);
+
+ serde_yml::to_writer(stdout(), &hvalue).unwrap();
+ println!()
+ }
+
+ Ok(())
+}
+
+fn trim_large_arrays(v: &mut Value) {
+ match v {
+ Value::Sequence(values) => {
+ values.iter_mut().for_each(trim_large_arrays);
+ while values.len() > 32 {
+ values.pop();
+ }
+ }
+ Value::Mapping(mapping) => mapping.map.values_mut().for_each(trim_large_arrays),
+ Value::Tagged(tagged_value) => trim_large_arrays(&mut tagged_value.value),
+ _ => (),
+ }
+}
diff --git a/exporter/src/main.rs b/exporter/src/main.rs
new file mode 100644
index 0000000..e7a11a9
--- /dev/null
+++ b/exporter/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}