Skip to content

Commit 2ccf70f

Browse files
committed
Improved metadata menu / using LazyLoadReference now in metadata lookup
1 parent ca459ab commit 2ccf70f

28 files changed

+548
-264
lines changed
Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,17 @@
1-
using System;
21
using UnityEngine;
32
using UnityEditor;
43

54
[CustomEditor(typeof(Material)), CanEditMultipleObjects]
65
public class MaterialMetadataEditor : MaterialEditor
76
{
87
MetadataEditor metadataEditor;
9-
10-
public override void OnEnable()
11-
{
12-
base.OnEnable();
13-
metadataEditor = new MetadataEditor(targets);
14-
}
15-
16-
public override void OnDisable()
17-
{
18-
base.OnDisable();
19-
metadataEditor.Dispose();
20-
metadataEditor = null;
21-
}
22-
23-
public override void OnInspectorGUI()
24-
{
8+
public override void OnEnable() { base.OnEnable(); metadataEditor = new MetadataEditor(targets); }
9+
public override void OnDisable() { base.OnDisable(); metadataEditor.Dispose(); metadataEditor = null; }
10+
public override void OnInspectorGUI()
11+
{
2512
base.OnInspectorGUI();
13+
if (!GUI.enabled)
14+
return;
2615
metadataEditor.OnInspectorGUI();
2716
}
28-
}
17+
}

Editor/Build/MetadataLookupBuild.cs

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using UnityEditor;
1+
using UnityEditor;
42
using UnityEditor.Build;
53
using UnityEditor.Build.Reporting;
64
using UnityEngine;
@@ -13,33 +11,6 @@ public class MetadataLookupPreprocessBuild : IPreprocessBuildWithReport
1311
{
1412
public int callbackOrder { get { return 0; } }
1513

16-
public static List<(string, CustomAssetMetadata)> GetAllMetadata<Asset>()
17-
where Asset : UnityEngine.Object
18-
{
19-
// TODO: figure out if there's a more efficient way of doing this??
20-
var guids = AssetDatabase.FindAssets($"t:{typeof(Asset).Name}");
21-
var result = new List<(string, CustomAssetMetadata)>();
22-
for (int i = 0; i < guids.Length; i++)
23-
{
24-
var assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
25-
// Sadly any asset included in a scene file cannot be loaded
26-
if (assetPath.EndsWith(".unity"))
27-
continue;
28-
29-
int index = 0;
30-
foreach (var item in AssetDatabase.LoadAllAssetsAtPath(assetPath))
31-
{
32-
if (item is CustomAssetMetadata metadata && metadata.asset is Asset)
33-
{
34-
var name = $"{guids[i]}-{index}";
35-
result.Add((name, metadata));
36-
index++;
37-
}
38-
}
39-
}
40-
return result;
41-
}
42-
4314
public static bool HadResourcesDirectory = false;
4415

4516
public void OnPreprocessBuild(BuildReport report)
@@ -51,16 +22,17 @@ public void OnPreprocessBuild(BuildReport report)
5122
System.IO.Directory.Delete(basePath, true);
5223
System.IO.Directory.CreateDirectory(basePath);
5324
var list = ScriptableObject.CreateInstance<MetadataLookupAsset>();
54-
var allMetadata = new List<CustomAssetMetadata>();
55-
// TODO: use addressables (if available?) instead to avoid loading every asset into memory
56-
foreach (var (name, metadata) in GetAllMetadata<Material>()) // TODO: figure out a way to efficiently support more types
57-
{
58-
var clone = UnityEngine.Object.Instantiate(metadata);
59-
AssetDatabase.CreateAsset(clone, $"{basePath}/{name}.asset");
60-
allMetadata.Add(clone);
25+
var allMetadata = Resources.FindObjectsOfTypeAll<CustomAssetMetadata>();
26+
int index = 0;
27+
for (int i = 0; i < allMetadata.Length; i++)
28+
{
29+
var clone = UnityEngine.Object.Instantiate(allMetadata[i]);
30+
var name = $"{allMetadata[i].GetInstanceID()}-{index}"; index++;
31+
AssetDatabase.CreateAsset(clone, $"{basePath}/{name}.asset");
32+
allMetadata[i] = clone;
6133
}
62-
list.allMetadata = allMetadata.ToArray();
63-
AssetDatabase.CreateAsset(list, $"{basePath}/{MetadataLookup.kAssetName}.asset");
34+
list.allMetadata = allMetadata;
35+
AssetDatabase.CreateAsset(list, $"{basePath}/{MetadataLookup.kAssetName}.asset");
6436
AssetDatabase.StopAssetEditing();
6537
}
6638

Editor/Common/AssetMetadataUtility.cs

Lines changed: 125 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,118 @@
11
using System;
22
using UnityEngine;
33
using UnityEditor;
4-
using UnityEditor.Rendering;
54
using System.Collections.Generic;
65
using System.Runtime.CompilerServices;
6+
using System.Reflection;
7+
using System.ComponentModel;
8+
using System.Linq;
79

810
public 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

Comments
 (0)