mod assembly;
mod generator;
mod template;
pub use assembly::{AssemblyTypeTreeGenerator, Loader};
pub use rabex::UnityVersion;
pub use rabex::typetree::TypeTreeNode;
use template::TemplateField;
const ALIGN_FLAG: i32 = 0x4000;
pub(crate) fn assemble(children: Vec<TemplateField>, type_name: &str) -> TypeTreeNode {
let base = TemplateField {
name: "Base".to_string(),
ty: type_name.to_string(),
aligned: false,
children,
};
let mut root = build_node(&base);
root.m_ByteSize = -1;
root
}
fn build_node(field: &TemplateField) -> TypeTreeNode {
let children: Vec<TypeTreeNode> = field.children.iter().map(build_node).collect();
let mut node = TypeTreeNode {
m_Type: field.ty.clone(),
m_Name: field.name.clone(),
m_MetaFlag: Some(if field.aligned { ALIGN_FLAG } else { 0 }),
children,
..Default::default()
};
node.m_ByteSize = byte_size(&node);
if node.m_Type == "Array" {
node.m_TypeFlags = 1;
node.m_MetaFlag = Some(if array_element_aligned(&node) { ALIGN_FLAG } else { 0 });
}
node
}
fn array_element_aligned(array_node: &TypeTreeNode) -> bool {
array_node
.children
.iter()
.find(|c| c.m_Name == "data")
.is_some_and(|data| matches!(data.classify(), rabex::typetree::TypetreeNodeKind::String) || is_pod_value_type(data))
}
fn is_pod_value_type(node: &TypeTreeNode) -> bool {
use rabex::typetree::TypetreeNodeKind::*;
match node.classify() {
Bool | U8 | U16 | U32 | U64 | I8 | I16 | I32 | I64 | Float | Double | Char => true,
Struct => {
!node.m_Type.starts_with("PPtr")
&& node.m_ByteSize > 0
&& node.m_ByteSize % 4 == 0
&& node.children.iter().all(is_pod_value_type)
}
_ => false,
}
}
fn byte_size(node: &TypeTreeNode) -> i32 {
use rabex::typetree::TypetreeNodeKind::*;
match node.classify() {
Bool | U8 | I8 | Char => 1,
U16 | I16 => 2,
U32 | I32 | Float => 4,
U64 | I64 | Double => 8,
String | Map | Array | Untyped => -1,
_ => {
let mut total = 0i32;
for c in &node.children {
if c.m_ByteSize < 0 {
return -1;
}
total += c.m_ByteSize;
}
total
}
}
}