Skip to main content

unity_assetdb/
class_id.rs

1//! Unity built-in class IDs we encounter in `Assets/`.
2//!
3//! Source: <https://docs.unity3d.com/Manual/ClassIDReference.html>.
4//! Only assets that can be top-level entries or sub-assets in a project are
5//! enumerated; runtime-only types (Camera, Light, …) live in components, not
6//! the asset DB. Magic numbers stay confined to this file per project rule.
7
8use bincode::{Decode, Encode};
9
10/// Unity asset class IDs. `repr(u32)` — most fit in u16, but a few
11/// post-2018 types (SpriteAtlas, LightingSettings) use 30-bit IDs.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)]
13#[repr(u32)]
14pub enum ClassId {
15    Material = 21,
16    Texture2D = 28,
17    Mesh = 43,
18    Shader = 48,
19    TextAsset = 49,
20    AnimationClip = 74,
21    AudioClip = 83,
22    Cubemap = 89,
23    AnimatorController = 91,
24    Font = 128,
25    PhysicMaterial = 134,
26    PhysicsMaterial2D = 62,
27    MonoBehaviour = 114,
28    MonoScript = 115,
29    Texture3D = 117,
30    RenderTexture = 84,
31    Sprite = 213,
32    SpriteAtlas = 687078895,
33    LightingSettings = 850595691,
34    NavMeshData = 238,
35    TerrainData = 156,
36    Avatar = 90,
37    AvatarMask = 1011,
38    AnimatorOverrideController = 221,
39    AudioMixerController = 244,
40    Prefab = 1001,
41    PrefabImporter = 1002,
42    SceneAsset = 1032,
43    LightingDataAsset = 1120,
44    AssemblyDefinitionAsset = 1153,
45    AssemblyDefinitionReferenceAsset = 1374,
46    GameObject = 1,
47    Transform = 4,
48    RectTransform = 224,
49}
50
51impl ClassId {
52    /// Lookup by raw u32 class ID — None if we don't enumerate it.
53    /// Bake-time fallback when we encounter a class ID not in the table.
54    pub fn from_raw(raw: u32) -> Option<Self> {
55        // Match by listing every supported variant. Compiler-checked that
56        // we cover what we declared above; raw values not listed return None.
57        Some(match raw {
58            1 => Self::GameObject,
59            4 => Self::Transform,
60            21 => Self::Material,
61            28 => Self::Texture2D,
62            43 => Self::Mesh,
63            48 => Self::Shader,
64            49 => Self::TextAsset,
65            62 => Self::PhysicsMaterial2D,
66            74 => Self::AnimationClip,
67            83 => Self::AudioClip,
68            84 => Self::RenderTexture,
69            89 => Self::Cubemap,
70            90 => Self::Avatar,
71            91 => Self::AnimatorController,
72            114 => Self::MonoBehaviour,
73            115 => Self::MonoScript,
74            117 => Self::Texture3D,
75            128 => Self::Font,
76            134 => Self::PhysicMaterial,
77            156 => Self::TerrainData,
78            213 => Self::Sprite,
79            221 => Self::AnimatorOverrideController,
80            224 => Self::RectTransform,
81            238 => Self::NavMeshData,
82            244 => Self::AudioMixerController,
83            1001 => Self::Prefab,
84            1002 => Self::PrefabImporter,
85            1011 => Self::AvatarMask,
86            1032 => Self::SceneAsset,
87            1120 => Self::LightingDataAsset,
88            1153 => Self::AssemblyDefinitionAsset,
89            1374 => Self::AssemblyDefinitionReferenceAsset,
90            687078895 => Self::SpriteAtlas,
91            850595691 => Self::LightingSettings,
92            _ => return None,
93        })
94    }
95
96    /// Stable name string — what gets written to TSV legacy / debug output.
97    pub fn name(self) -> &'static str {
98        match self {
99            Self::GameObject => "GameObject",
100            Self::Transform => "Transform",
101            Self::Material => "Material",
102            Self::Texture2D => "Texture2D",
103            Self::Mesh => "Mesh",
104            Self::Shader => "Shader",
105            Self::TextAsset => "TextAsset",
106            Self::PhysicsMaterial2D => "PhysicsMaterial2D",
107            Self::AnimationClip => "AnimationClip",
108            Self::AudioClip => "AudioClip",
109            Self::RenderTexture => "RenderTexture",
110            Self::Cubemap => "Cubemap",
111            Self::Avatar => "Avatar",
112            Self::AnimatorController => "AnimatorController",
113            Self::MonoBehaviour => "MonoBehaviour",
114            Self::MonoScript => "MonoScript",
115            Self::Texture3D => "Texture3D",
116            Self::Font => "Font",
117            Self::PhysicMaterial => "PhysicMaterial",
118            Self::TerrainData => "TerrainData",
119            Self::Sprite => "Sprite",
120            Self::AnimatorOverrideController => "AnimatorOverrideController",
121            Self::AudioMixerController => "AudioMixerController",
122            Self::RectTransform => "RectTransform",
123            Self::NavMeshData => "NavMeshData",
124            Self::Prefab => "Prefab",
125            Self::PrefabImporter => "PrefabImporter",
126            Self::AvatarMask => "AvatarMask",
127            Self::SceneAsset => "SceneAsset",
128            Self::LightingDataAsset => "LightingDataAsset",
129            Self::AssemblyDefinitionAsset => "AssemblyDefinitionAsset",
130            Self::AssemblyDefinitionReferenceAsset => "AssemblyDefinitionReferenceAsset",
131            Self::SpriteAtlas => "SpriteAtlas",
132            Self::LightingSettings => "LightingSettings",
133        }
134    }
135
136    /// Canonical sub-object fileID Unity assigns to a single embedded
137    /// asset of this class. Encoding: `class_id × 100_000`. Stays in
138    /// this module per the project's "no magic numbers" rule (file
139    /// header).
140    pub fn canonical_subobject_fid(self) -> i64 {
141        (self as i64) * 100_000
142    }
143}
144
145/// File-extension → top-level ClassId. None means the asset isn't typed
146/// purely from extension (e.g. `.asset` requires peeking the YAML).
147pub fn class_from_ext(ext: &str) -> Option<ClassId> {
148    Some(match ext {
149        "prefab" => ClassId::Prefab,
150        "controller" => ClassId::AnimatorController,
151        "overrideController" => ClassId::AnimatorOverrideController,
152        "mat" => ClassId::Material,
153        "anim" => ClassId::AnimationClip,
154        "shader" => ClassId::Shader,
155        "physicMaterial" => ClassId::PhysicMaterial,
156        "physicsMaterial2D" => ClassId::PhysicsMaterial2D,
157        "mask" => ClassId::AvatarMask,
158        "spriteatlas" | "spriteatlasv2" => ClassId::SpriteAtlas,
159        "unity" => ClassId::SceneAsset,
160        "asmdef" => ClassId::AssemblyDefinitionAsset,
161        "asmref" => ClassId::AssemblyDefinitionReferenceAsset,
162        "cs" => ClassId::MonoScript,
163        // Texture-ish — Unity treats these as Texture2D top-level.
164        "png" | "jpg" | "jpeg" | "tga" | "psd" | "tif" | "tiff" | "bmp" | "exr" | "hdr" | "gif"
165        | "iff" | "pict" => ClassId::Texture2D,
166        "ttf" | "otf" => ClassId::Font,
167        "wav" | "mp3" | "ogg" | "aif" | "aiff" | "flac" => ClassId::AudioClip,
168        "txt" | "json" | "xml" | "csv" | "yaml" | "html" | "htm" | "bytes" => ClassId::TextAsset,
169        _ => return None,
170    })
171}
172
173#[cfg(test)]
174mod tests {
175    use super::*;
176
177    #[test]
178    fn from_raw_known() {
179        assert_eq!(ClassId::from_raw(213), Some(ClassId::Sprite));
180        assert_eq!(ClassId::from_raw(1001), Some(ClassId::Prefab));
181        assert_eq!(ClassId::from_raw(114), Some(ClassId::MonoBehaviour));
182    }
183
184    #[test]
185    fn from_raw_unknown() {
186        assert_eq!(ClassId::from_raw(999_999), None);
187    }
188
189    #[test]
190    fn ext_dispatch() {
191        assert_eq!(class_from_ext("prefab"), Some(ClassId::Prefab));
192        assert_eq!(class_from_ext("png"), Some(ClassId::Texture2D));
193        assert_eq!(class_from_ext("asset"), None); // YAML-peek required
194    }
195}