aboutsummaryrefslogtreecommitdiff
path: root/src/bin/typegraph.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-03-10 20:45:18 +0100
committermetamuffin <metamuffin@disroot.org>2025-03-10 20:45:18 +0100
commit30bf5e07e52142a154a5660574213e59e0363ada (patch)
treea6a619a033269ab76650a820826255acafaa9b6c /src/bin/typegraph.rs
parent42a5916cf742779d016eeefd1c59efbdfab64feb (diff)
downloadunity-tools-30bf5e07e52142a154a5660574213e59e0363ada.tar
unity-tools-30bf5e07e52142a154a5660574213e59e0363ada.tar.bz2
unity-tools-30bf5e07e52142a154a5660574213e59e0363ada.tar.zst
type graph
Diffstat (limited to 'src/bin/typegraph.rs')
-rw-r--r--src/bin/typegraph.rs123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/bin/typegraph.rs b/src/bin/typegraph.rs
new file mode 100644
index 0000000..79c096b
--- /dev/null
+++ b/src/bin/typegraph.rs
@@ -0,0 +1,123 @@
+#![feature(random)]
+use std::{
+ collections::{BTreeMap, BTreeSet},
+ env::args,
+ fs::File,
+ io::BufReader,
+};
+use unity_tools::{
+ serialized_file::{TypeTreeNode, 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())?);
+ let mut fs = UnityFS::open(file)?;
+ let filter_prims = args().any(|a| a == "no_primitives");
+
+ let mut edges = BTreeSet::new();
+ for node in fs.nodes().to_vec() {
+ if node.name.ends_with(".resource") || node.name.ends_with(".resS") {
+ continue;
+ }
+ let mut cab = fs.read(&node)?;
+ let file = read_serialized_file(&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") {
+ 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"
+ | "vector"
+ | "string"
+ | "float3"
+ | "float4"
+ | "float2"
+ | "Vector2f"
+ | "Vector3f"
+ | "Vector4f"
+ | "Quaternionf"
+ | "xform"
+ )
+}