unity_asset_binary/typetree/
types.rs1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct TypeTreeNode {
15 pub type_name: String,
17 pub name: String,
19 pub byte_size: i32,
21 pub index: i32,
23 pub type_flags: i32,
25 pub version: i32,
27 pub meta_flags: i32,
29 pub level: i32,
31 pub type_str_offset: u32,
33 pub name_str_offset: u32,
35 pub ref_type_hash: u64,
37 pub children: Vec<TypeTreeNode>,
39}
40
41impl TypeTreeNode {
42 pub fn new() -> Self {
44 Self {
45 type_name: String::new(),
46 name: String::new(),
47 byte_size: 0,
48 index: 0,
49 type_flags: 0,
50 version: 0,
51 meta_flags: 0,
52 level: 0,
53 type_str_offset: 0,
54 name_str_offset: 0,
55 ref_type_hash: 0,
56 children: Vec::new(),
57 }
58 }
59
60 pub fn with_info(type_name: String, name: String, byte_size: i32) -> Self {
62 Self {
63 type_name,
64 name,
65 byte_size,
66 ..Default::default()
67 }
68 }
69
70 pub fn is_array(&self) -> bool {
72 self.type_name == "Array" || self.type_name.starts_with("vector")
73 }
74
75 pub fn is_aligned(&self) -> bool {
77 (self.meta_flags & 0x4000) != 0
78 }
79
80 pub fn size(&self) -> i32 {
82 self.byte_size
83 }
84
85 pub fn is_primitive(&self) -> bool {
87 matches!(
88 self.type_name.as_str(),
89 "bool"
90 | "char"
91 | "SInt8"
92 | "UInt8"
93 | "SInt16"
94 | "UInt16"
95 | "SInt32"
96 | "UInt32"
97 | "SInt64"
98 | "UInt64"
99 | "float"
100 | "double"
101 | "int"
102 | "string"
103 )
104 }
105
106 pub fn is_string(&self) -> bool {
108 self.type_name == "string"
109 }
110
111 pub fn is_numeric(&self) -> bool {
113 matches!(
114 self.type_name.as_str(),
115 "SInt8"
116 | "UInt8"
117 | "SInt16"
118 | "UInt16"
119 | "SInt32"
120 | "UInt32"
121 | "SInt64"
122 | "UInt64"
123 | "float"
124 | "double"
125 | "int"
126 )
127 }
128
129 pub fn is_boolean(&self) -> bool {
131 self.type_name == "bool"
132 }
133
134 pub fn find_child(&self, name: &str) -> Option<&TypeTreeNode> {
136 self.children.iter().find(|child| child.name == name)
137 }
138
139 pub fn find_child_mut(&mut self, name: &str) -> Option<&mut TypeTreeNode> {
141 self.children.iter_mut().find(|child| child.name == name)
142 }
143
144 pub fn child_names(&self) -> Vec<&str> {
146 self.children
147 .iter()
148 .map(|child| child.name.as_str())
149 .collect()
150 }
151
152 pub fn add_child(&mut self, child: TypeTreeNode) {
154 self.children.push(child);
155 }
156
157 pub fn remove_child(&mut self, name: &str) -> Option<TypeTreeNode> {
159 if let Some(pos) = self.children.iter().position(|child| child.name == name) {
160 Some(self.children.remove(pos))
161 } else {
162 None
163 }
164 }
165
166 pub fn depth(&self) -> i32 {
168 self.level
169 }
170
171 pub fn has_children(&self) -> bool {
173 !self.children.is_empty()
174 }
175
176 pub fn child_count(&self) -> usize {
178 self.children.len()
179 }
180
181 pub fn validate(&self) -> Result<(), String> {
183 if self.type_name.is_empty() {
184 return Err("Type name cannot be empty".to_string());
185 }
186
187 if self.byte_size < -1 {
188 return Err("Invalid byte size".to_string());
189 }
190
191 for (i, child) in self.children.iter().enumerate() {
193 child
194 .validate()
195 .map_err(|e| format!("Child {}: {}", i, e))?;
196 }
197
198 Ok(())
199 }
200}
201
202impl Default for TypeTreeNode {
203 fn default() -> Self {
204 Self::new()
205 }
206}
207
208#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct TypeTree {
214 pub nodes: Vec<TypeTreeNode>,
216 pub string_buffer: Vec<u8>,
218 pub version: u32,
220 pub platform: u32,
222 pub has_type_dependencies: bool,
224}
225
226impl TypeTree {
227 pub fn new() -> Self {
229 Self {
230 nodes: Vec::new(),
231 string_buffer: Vec::new(),
232 version: 0,
233 platform: 0,
234 has_type_dependencies: false,
235 }
236 }
237
238 pub fn with_capacity(capacity: usize) -> Self {
240 Self {
241 nodes: Vec::with_capacity(capacity),
242 string_buffer: Vec::new(),
243 version: 0,
244 platform: 0,
245 has_type_dependencies: false,
246 }
247 }
248
249 pub fn is_empty(&self) -> bool {
251 self.nodes.is_empty()
252 }
253
254 pub fn node_count(&self) -> usize {
256 self.nodes.len()
257 }
258
259 pub fn add_node(&mut self, node: TypeTreeNode) {
261 self.nodes.push(node);
262 }
263
264 pub fn find_node(&self, name: &str) -> Option<&TypeTreeNode> {
266 self.nodes.iter().find(|node| node.name == name)
267 }
268
269 pub fn find_node_mut(&mut self, name: &str) -> Option<&mut TypeTreeNode> {
271 self.nodes.iter_mut().find(|node| node.name == name)
272 }
273
274 pub fn node_names(&self) -> Vec<&str> {
276 self.nodes.iter().map(|node| node.name.as_str()).collect()
277 }
278
279 pub fn clear(&mut self) {
281 self.nodes.clear();
282 self.string_buffer.clear();
283 }
284
285 pub fn get_string(&self, offset: u32) -> Option<String> {
287 if offset as usize >= self.string_buffer.len() {
288 return None;
289 }
290
291 let start = offset as usize;
292 let end = self.string_buffer[start..]
293 .iter()
294 .position(|&b| b == 0)
295 .map(|pos| start + pos)
296 .unwrap_or(self.string_buffer.len());
297
298 String::from_utf8(self.string_buffer[start..end].to_vec()).ok()
299 }
300
301 pub fn add_string(&mut self, s: &str) -> u32 {
303 let offset = self.string_buffer.len() as u32;
304 self.string_buffer.extend_from_slice(s.as_bytes());
305 self.string_buffer.push(0); offset
307 }
308
309 pub fn validate(&self) -> Result<(), String> {
311 if self.nodes.is_empty() {
312 return Err("TypeTree has no nodes".to_string());
313 }
314
315 for (i, node) in self.nodes.iter().enumerate() {
316 node.validate()
317 .map_err(|e| format!("Root node {}: {}", i, e))?;
318 }
319
320 Ok(())
321 }
322
323 pub fn statistics(&self) -> TypeTreeStatistics {
325 let mut stats = (0usize, 0i32, 0usize, 0usize); fn count_nodes(node: &TypeTreeNode, depth: i32, stats: &mut (usize, i32, usize, usize)) {
328 stats.0 += 1; stats.1 = stats.1.max(depth); if node.is_primitive() {
332 stats.2 += 1; }
334 if node.is_array() {
335 stats.3 += 1; }
337
338 for child in &node.children {
339 count_nodes(child, depth + 1, stats);
340 }
341 }
342
343 for node in &self.nodes {
344 count_nodes(node, 0, &mut stats);
345 }
346
347 TypeTreeStatistics {
348 total_nodes: stats.0,
349 root_nodes: self.nodes.len(),
350 max_depth: stats.1,
351 primitive_count: stats.2,
352 array_count: stats.3,
353 string_buffer_size: self.string_buffer.len(),
354 }
355 }
356}
357
358impl Default for TypeTree {
359 fn default() -> Self {
360 Self::new()
361 }
362}
363
364#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct TypeTreeStatistics {
367 pub total_nodes: usize,
368 pub root_nodes: usize,
369 pub max_depth: i32,
370 pub primitive_count: usize,
371 pub array_count: usize,
372 pub string_buffer_size: usize,
373}
374
375#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct TypeInfo {
378 pub class_id: i32,
379 pub class_name: String,
380 pub type_tree: TypeTree,
381 pub script_type_index: Option<i16>,
382 pub script_id: [u8; 16],
383 pub old_type_hash: [u8; 16],
384}
385
386impl TypeInfo {
387 pub fn new(class_id: i32, class_name: String) -> Self {
389 Self {
390 class_id,
391 class_name,
392 type_tree: TypeTree::new(),
393 script_type_index: None,
394 script_id: [0; 16],
395 old_type_hash: [0; 16],
396 }
397 }
398
399 pub fn is_script_type(&self) -> bool {
401 self.script_type_index.is_some()
402 }
403}
404
405#[derive(Debug, Clone, Default)]
407pub struct TypeRegistry {
408 types: HashMap<i32, TypeInfo>,
409}
410
411impl TypeRegistry {
412 pub fn new() -> Self {
414 Self {
415 types: HashMap::new(),
416 }
417 }
418
419 pub fn add_type(&mut self, type_info: TypeInfo) {
421 self.types.insert(type_info.class_id, type_info);
422 }
423
424 pub fn get_type(&self, class_id: i32) -> Option<&TypeInfo> {
426 self.types.get(&class_id)
427 }
428
429 pub fn class_ids(&self) -> Vec<i32> {
431 self.types.keys().copied().collect()
432 }
433
434 pub fn has_type(&self, class_id: i32) -> bool {
436 self.types.contains_key(&class_id)
437 }
438
439 pub fn clear(&mut self) {
441 self.types.clear();
442 }
443
444 pub fn len(&self) -> usize {
446 self.types.len()
447 }
448
449 pub fn is_empty(&self) -> bool {
451 self.types.is_empty()
452 }
453}