11using System ;
22using UnityEngine ;
33using UnityEditor ;
4- using UnityEditor . Rendering ;
54using System . Collections . Generic ;
65using System . Runtime . CompilerServices ;
6+ using System . Reflection ;
7+ using System . ComponentModel ;
8+ using System . Linq ;
79
810public static class AssetMetadataUtility
911{
10- static IList < Type > allCustomAssetMetadataTypes ;
12+ static HashSet < Type > disallowMultipleMetadataLookup ;
13+ static Dictionary < Type , Type [ ] > restrictedTypesLookup ;
14+ static Dictionary < Type , ( string displayName , string menuPath ) > metadataNames ;
15+ static List < Type > allCustomAssetMetadataTypes ;
1116
12- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
13- static void Initialize ( )
17+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
18+ static void EnsureInitialized ( )
1419 {
1520 if ( allCustomAssetMetadataTypes != null )
1621 return ;
1722
18- allCustomAssetMetadataTypes = TypeCache . GetTypesDerivedFrom < CustomAssetMetadata > ( ) ;
23+ var metadataTypes = TypeCache . GetTypesDerivedFrom < CustomAssetMetadata > ( ) ;
24+ metadataNames = new Dictionary < Type , ( string displayName , string menuPath ) > ( metadataTypes . Count ) ;
25+ allCustomAssetMetadataTypes = metadataTypes . ToList ( ) ;
26+ restrictedTypesLookup = new Dictionary < Type , Type [ ] > ( ) ;
27+ disallowMultipleMetadataLookup = new HashSet < Type > ( ) ;
28+ foreach ( var metadataType in metadataTypes )
29+ {
30+ string displayName = null ;
31+ string menuName = null ;
32+
33+ var displayNameAttribute = metadataType . GetCustomAttribute < DisplayNameAttribute > ( ) ;
34+ if ( displayNameAttribute != null )
35+ {
36+ displayName = displayNameAttribute . DisplayName ;
37+ }
38+
39+ var addMetadataMenuAttribute = metadataType . GetCustomAttribute < AddMetadataMenuAttribute > ( ) ;
40+ if ( addMetadataMenuAttribute != null )
41+ {
42+ menuName = addMetadataMenuAttribute . MetadataMenu . Replace ( '\\ ' , '/' ) ;
43+ }
44+
45+ if ( displayName == null && menuName != null )
46+ {
47+ int index = menuName . LastIndexOf ( '/' ) ;
48+ displayName = ( index == - 1 ) ? menuName : menuName . Substring ( index + 1 ) ;
49+ }
50+
51+ if ( displayName == null )
52+ {
53+ displayName = ObjectNames . NicifyVariableName ( metadataType . Name ) ;
54+ }
55+
56+ if ( menuName == null && displayName != null )
57+ {
58+ menuName = displayName ;
59+ }
60+
61+ metadataNames [ metadataType ] = ( displayName , menuName ) ;
62+ var disallowMultipleCustomAssetMetadataAttribute = metadataType . GetCustomAttribute < DisallowMultipleCustomAssetMetadataAttribute > ( ) ;
63+ if ( disallowMultipleCustomAssetMetadataAttribute != null )
64+ {
65+ disallowMultipleMetadataLookup . Add ( metadataType ) ;
66+ }
67+ var restrictMetadataAssetTypesAttribute = metadataType . GetCustomAttribute < RestrictMetadataAssetTypesAttribute > ( ) ;
68+ if ( restrictMetadataAssetTypesAttribute != null )
69+ {
70+ restrictedTypesLookup [ metadataType ] = restrictMetadataAssetTypesAttribute . Types ;
71+ }
72+ }
1973 }
2074
2175 public static bool HaveMetadataTypes
2276 {
2377 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
2478 get
2579 {
26- Initialize ( ) ;
27- return AllMetadataTypes . Count > 0 ;
80+ EnsureInitialized ( ) ;
81+ return allCustomAssetMetadataTypes . Count > 0 ;
2882 }
2983 }
3084
31- public static IList < Type > AllMetadataTypes
85+ public static List < Type > AllMetadataTypes
3286 {
3387 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
3488 get
3589 {
36- Initialize ( ) ;
90+ EnsureInitialized ( ) ;
3791 return allCustomAssetMetadataTypes ;
3892 }
39- }
93+ }
94+
95+ public static string GetDisplayName ( Type metadataType )
96+ {
97+ if ( metadataType == null )
98+ return null ;
99+ EnsureInitialized ( ) ;
100+ if ( metadataNames . TryGetValue ( metadataType , out var value ) )
101+ return value . displayName ;
102+ return ObjectNames . NicifyVariableName ( metadataType . Name ) ;
103+ }
40104
41- public static void GetAll ( UnityEngine . Object target , List < CustomAssetMetadata > metadata )
105+ public static string GetMenuName ( Type metadataType )
106+ {
107+ if ( metadataType == null )
108+ return null ;
109+ EnsureInitialized ( ) ;
110+ if ( metadataNames . TryGetValue ( metadataType , out var value ) )
111+ return value . menuPath ;
112+ return ObjectNames . NicifyVariableName ( metadataType . Name ) ;
113+ }
114+
115+ public static void GetAll ( UnityEngine . Object target , List < CustomAssetMetadata > metadata )
42116 {
43117 var assetPath = AssetDatabase . GetAssetPath ( target ) ;
44118 if ( assetPath == null ||
@@ -57,30 +131,56 @@ public static void GetAll(UnityEngine.Object target, List<CustomAssetMetadata> m
57131
58132 public static CustomAssetMetadata Add ( UnityEngine . Object target , Type type )
59133 {
60- var assetPath = AssetDatabase . GetAssetPath ( target ) ;
61- if ( assetPath == null )
134+ if ( ! CanAddMetadataType ( target , type ) )
62135 return null ;
63-
64- // TODO: could try to make non unity assets work by putting a file next to it?
65136
66- var instance = ScriptableObject . CreateInstance ( type ) ;
137+ var assetPath = AssetDatabase . GetAssetPath ( target ) ;
138+ if ( string . IsNullOrWhiteSpace ( assetPath ) )
139+ {
140+ Debug . LogError ( "AssetMetadataUtility.Add: Could not find asset path for target" , target ) ;
141+ return null ;
142+ }
143+
144+ // TODO: could try to make non unity assets work by putting a file next to it?
145+
146+ var instance = ScriptableObject . CreateInstance ( type ) ;
67147 instance . hideFlags = HideFlags . HideInHierarchy ;
68148 if ( instance is CustomAssetMetadata assetMetadata )
69149 {
70- assetMetadata . name = type . Name ;
71- assetMetadata . asset = target ;
72- AssetDatabase . AddObjectToAsset ( assetMetadata , target ) ;
73- AssetDatabase . SetMainObject ( target , assetPath ) ;
150+ assetMetadata . name = type . Name ;
151+ assetMetadata . reference = target ;
152+ AssetDatabase . AddObjectToAsset ( assetMetadata , assetPath ) ;
74153 AssetDatabase . ImportAsset ( assetPath ) ;
75154 AssetDatabase . Refresh ( ) ;
76155 return assetMetadata ;
77156 }
78157
79158 UnityEngine . Object . DestroyImmediate ( instance ) ;
80159 return null ;
81- }
160+ }
161+
162+ public static bool CanAddMetadataType ( UnityEngine . Object target , Type type )
163+ {
164+ if ( ReferenceEquals ( target , null ) || target == null )
165+ return false ;
166+ if ( disallowMultipleMetadataLookup . Contains ( type ) )
167+ {
168+ if ( MetadataLookup . HasMetadataOfType ( target , type ) )
169+ return false ;
170+ }
171+ if ( ! restrictedTypesLookup . TryGetValue ( type , out var restrictedTypes ) )
172+ return true ;
82173
83- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
174+ var targetType = target . GetType ( ) ;
175+ foreach ( var restrictedType in restrictedTypes )
176+ {
177+ if ( restrictedType == targetType )
178+ return true ;
179+ }
180+ return false ;
181+ }
182+
183+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
84184 public static CustomAssetMetadata Add < Metadata > ( UnityEngine . Object target )
85185 where Metadata : CustomAssetMetadata
86186 {
@@ -90,6 +190,9 @@ public static CustomAssetMetadata Add<Metadata>(UnityEngine.Object target)
90190 public static void Destroy < Metadata > ( Metadata metadata )
91191 where Metadata : CustomAssetMetadata
92192 {
193+ if ( metadata == null )
194+ return ;
195+
93196 var assetPath = AssetDatabase . GetAssetPath ( metadata ) ;
94197 if ( assetPath == null )
95198 return ;
0 commit comments