unity_asset_core/
constants.rs

1//! Constants and type definitions for Unity YAML parsing
2//!
3//! This module contains Unity-specific constants, tags, and type definitions
4//! that are used throughout the parsing process.
5
6use std::collections::HashMap;
7use std::sync::{Arc, RwLock};
8
9/// Unity YAML tag URI
10pub const UNITY_TAG_URI: &str = "tag:unity3d.com,2011:";
11
12/// Unity YAML version
13pub const UNITY_YAML_VERSION: (u32, u32) = (1, 1);
14
15/// Line ending types
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub enum LineEnding {
18    Unix,    // \n
19    Windows, // \r\n
20    Mac,     // \r
21}
22
23impl Default for LineEnding {
24    fn default() -> Self {
25        #[cfg(windows)]
26        return LineEnding::Windows;
27        #[cfg(not(windows))]
28        return LineEnding::Unix;
29    }
30}
31
32impl LineEnding {
33    pub fn as_str(&self) -> &'static str {
34        match self {
35            LineEnding::Unix => "\n",
36            LineEnding::Windows => "\r\n",
37            LineEnding::Mac => "\r",
38        }
39    }
40
41    /// Create LineEnding from string representation
42    pub fn from_string(s: &str) -> Self {
43        match s {
44            "\n" => LineEnding::Unix,
45            "\r\n" => LineEnding::Windows,
46            "\r" => LineEnding::Mac,
47            _ => LineEnding::default(),
48        }
49    }
50}
51
52/// Unity class ID to name mapping
53/// This is a global registry that maps class IDs to class names
54pub struct UnityClassIdMap {
55    map: Arc<RwLock<HashMap<String, String>>>,
56}
57
58impl UnityClassIdMap {
59    pub fn new() -> Self {
60        Self {
61            map: Arc::new(RwLock::new(HashMap::new())),
62        }
63    }
64
65    /// Get or create a class mapping
66    pub fn get_or_create(&self, class_id: &str, class_name: &str) -> String {
67        let key = format!("{}-{}", class_id, class_name);
68
69        // Try to read first
70        if let Ok(map) = self.map.read()
71            && let Some(existing) = map.get(&key)
72        {
73            return existing.clone();
74        }
75
76        // Need to write
77        if let Ok(mut map) = self.map.write() {
78            map.insert(key.clone(), class_name.to_string());
79        }
80
81        class_name.to_string()
82    }
83
84    /// Clear all mappings
85    pub fn clear(&self) {
86        if let Ok(mut map) = self.map.write() {
87            map.clear();
88        }
89    }
90
91    /// Get class name from class ID.
92    pub fn get_class_name(&self, class_id: i32) -> Option<String> {
93        self.get_class_name_str(class_id).map(str::to_string)
94    }
95
96    /// Get class name from class ID without allocating.
97    pub fn get_class_name_str(&self, class_id: i32) -> Option<&'static str> {
98        class_id_name(class_id)
99    }
100}
101
102fn class_id_name(class_id: i32) -> Option<&'static str> {
103    match class_id {
104        // Core Unity objects
105        0 => Some("Object"),
106        1 => Some("GameObject"),
107        2 => Some("Component"),
108        4 => Some("Transform"),
109        8 => Some("Behaviour"),
110
111        // Managers
112        3 => Some("LevelGameManager"),
113        5 => Some("TimeManager"),
114        6 => Some("GlobalGameManager"),
115        9 => Some("GameManager"),
116        11 => Some("AudioManager"),
117        13 => Some("InputManager"),
118
119        // Rendering
120        20 => Some("Camera"),
121        21 => Some("Material"),
122        23 => Some("MeshRenderer"),
123        25 => Some("Renderer"),
124        27 => Some("Texture"),
125        28 => Some("Texture2D"),
126        33 => Some("MeshFilter"),
127        43 => Some("Mesh"),
128        48 => Some("Shader"),
129
130        // Text and Assets
131        49 => Some("TextAsset"),
132        74 => Some("AnimationClip"),
133        83 => Some("AudioClip"),
134        89 => Some("CubemapArray"),
135        90 => Some("Avatar"),
136        91 => Some("AnimatorController"),
137        95 => Some("Animator"),
138        108 => Some("Light"),
139        114 => Some("MonoBehaviour"),
140        115 => Some("MonoScript"),
141        128 => Some("Font"),
142        142 => Some("AssetBundle"),
143        152 => Some("MovieTexture"),
144        184 => Some("RenderTexture"),
145        212 => Some("SpriteRenderer"),
146        213 => Some("Sprite"),
147        1001 => Some("PrefabInstance"),
148
149        // Physics
150        50 => Some("Rigidbody2D"),
151        54 => Some("Rigidbody"),
152        56 => Some("Collider"),
153
154        // Editor / additional types
155        687078895 => Some("SpriteAtlas"),
156
157        _ => None,
158    }
159}
160
161impl Default for UnityClassIdMap {
162    fn default() -> Self {
163        Self::new()
164    }
165}
166
167lazy_static::lazy_static! {
168    /// Global class ID map instance
169    pub static ref GLOBAL_CLASS_ID_MAP: UnityClassIdMap = UnityClassIdMap::new();
170}
171
172/// Common Unity class IDs
173pub mod class_ids {
174    pub const OBJECT: i32 = 0;
175    pub const GAME_OBJECT: i32 = 1;
176    pub const COMPONENT: i32 = 2;
177    pub const BEHAVIOUR: i32 = 8;
178    pub const TRANSFORM: i32 = 4;
179    pub const CAMERA: i32 = 20;
180    pub const MATERIAL: i32 = 21;
181    pub const MESH_RENDERER: i32 = 23;
182    pub const TEXTURE_2D: i32 = 28;
183    pub const MESH: i32 = 43;
184    pub const SHADER: i32 = 48;
185    pub const TEXTURE: i32 = 27;
186    pub const TEXT_ASSET: i32 = 49;
187    pub const ANIMATION_CLIP: i32 = 74;
188    pub const AUDIO_CLIP: i32 = 83;
189    pub const ANIMATOR_CONTROLLER: i32 = 91;
190    pub const MONO_BEHAVIOUR: i32 = 114;
191    pub const MONO_SCRIPT: i32 = 115;
192    pub const ASSET_BUNDLE: i32 = 142;
193    pub const SPRITE_RENDERER: i32 = 212;
194    pub const SPRITE: i32 = 213;
195    pub const PREFAB_INSTANCE: i32 = 1001;
196    pub const SPRITE_ATLAS: i32 = 687078895;
197}
198
199/// Common Unity class names
200pub mod class_names {
201    pub const OBJECT: &str = "Object";
202    pub const GAME_OBJECT: &str = "GameObject";
203    pub const COMPONENT: &str = "Component";
204    pub const TRANSFORM: &str = "Transform";
205    pub const CAMERA: &str = "Camera";
206    pub const MATERIAL: &str = "Material";
207    pub const MESH_RENDERER: &str = "MeshRenderer";
208    pub const TEXTURE_2D: &str = "Texture2D";
209    pub const MESH: &str = "Mesh";
210    pub const SHADER: &str = "Shader";
211    pub const TEXTURE: &str = "Texture";
212    pub const SPRITE: &str = "Sprite";
213    pub const MONO_BEHAVIOUR: &str = "MonoBehaviour";
214    pub const MONO_SCRIPT: &str = "MonoScript";
215    pub const PREFAB_INSTANCE: &str = "PrefabInstance";
216    pub const SPRITE_ATLAS: &str = "SpriteAtlas";
217}
218
219#[cfg(test)]
220mod tests {
221    use super::*;
222
223    #[test]
224    fn test_line_ending() {
225        assert_eq!(LineEnding::Unix.as_str(), "\n");
226        assert_eq!(LineEnding::Windows.as_str(), "\r\n");
227        assert_eq!(LineEnding::Mac.as_str(), "\r");
228    }
229
230    #[test]
231    fn test_common_class_ids() {
232        assert_eq!(class_ids::OBJECT, 0);
233        assert_eq!(class_ids::GAME_OBJECT, 1);
234        assert_eq!(class_ids::COMPONENT, 2);
235        assert_eq!(class_ids::TRANSFORM, 4);
236        assert_eq!(class_ids::BEHAVIOUR, 8);
237        assert_eq!(class_ids::SPRITE_RENDERER, 212);
238        assert_eq!(class_ids::SPRITE, 213);
239
240        assert_eq!(
241            GLOBAL_CLASS_ID_MAP.get_class_name(class_ids::SPRITE),
242            Some("Sprite".to_string())
243        );
244        assert_eq!(
245            GLOBAL_CLASS_ID_MAP.get_class_name(class_ids::SPRITE_RENDERER),
246            Some("SpriteRenderer".to_string())
247        );
248
249        // Defensive: avoid "guess" mappings for unknown IDs.
250        assert_eq!(GLOBAL_CLASS_ID_MAP.get_class_name(256), None);
251        assert_eq!(GLOBAL_CLASS_ID_MAP.get_class_name(512), None);
252        assert_eq!(GLOBAL_CLASS_ID_MAP.get_class_name(768), None);
253    }
254
255    #[test]
256    fn test_class_id_map() {
257        let map = UnityClassIdMap::new();
258        let result = map.get_or_create("1", "GameObject");
259        assert_eq!(result, "GameObject");
260
261        // Should return the same result
262        let result2 = map.get_or_create("1", "GameObject");
263        assert_eq!(result2, "GameObject");
264    }
265}