Skip to content

Commit

Permalink
Build Resources.FindObjectsOfTypeAll bugfix
Browse files Browse the repository at this point in the history
  • Loading branch information
LogicalError committed Oct 30, 2024
1 parent 6bc1626 commit 22de986
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 31 deletions.
53 changes: 40 additions & 13 deletions Editor/Build/MetadataLookupBuild.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
using UnityEditor;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

// This is a bit of a hack, but we need to ensure that our metadata is not stripped on build,
// so at build time we clone them into a temporary resources directory. Afterwards we delete the directory.
// Cloning works since each metadata object holds a reference to the thing it belongs to and we can
// just use the clone at runtime instead.
// so at build time we clone them into a temporary resources directory. Cloning works since
// each metadata object holds a reference to the thing it belongs to and we can just use the
// clone at runtime instead. After we've created the build we delete the directory.
public class MetadataLookupPreprocessBuild : IPreprocessBuildWithReport
{
public int callbackOrder { get { return 0; } }

public static bool HadResourcesDirectory = false;

CustomAssetMetadata CloneCustomAssetMetadata(CustomAssetMetadata assetMetadata, string basePath, ref int index)
{
var clone = UnityEngine.Object.Instantiate(assetMetadata);
var name = $"{assetMetadata.GetInstanceID()}-{index}"; index++;
AssetDatabase.CreateAsset(clone, $"{basePath}/{name}.asset");
return clone;
}

public void OnPreprocessBuild(BuildReport report)
{
const string basePath = "Assets/Resources/" + MetadataLookup.kResourcePath;
Expand All @@ -22,17 +32,34 @@ public void OnPreprocessBuild(BuildReport report)
System.IO.Directory.Delete(basePath, true);
System.IO.Directory.CreateDirectory(basePath);
var list = ScriptableObject.CreateInstance<MetadataLookupAsset>();
var allMetadata = Resources.FindObjectsOfTypeAll<CustomAssetMetadata>();

var allMetadata = new List<CustomAssetMetadata>();

var allPaths = UnityEditor.AssetDatabase.FindAssets($"t:Material"); // TODO: support more than just materials
foreach(var assetPath in allPaths)
{
foreach (var item in UnityEditor.AssetDatabase.LoadAllAssetRepresentationsAtPath(assetPath))
{
if (item is not CustomAssetMetadata metadata)
continue;
allMetadata.Add(metadata);
}
UnityEditor.EditorUtility.UnloadUnusedAssetsImmediate();
}

// This doesn't work since Resources.FindObjectsOfTypeAll only works on
// assets currently loaded into memory.
//allMetadata.AddRange(Resources.FindObjectsOfTypeAll<CustomAssetMetadata>());

int index = 0;
for (int i = 0; i < allMetadata.Length; i++)
{
var clone = UnityEngine.Object.Instantiate(allMetadata[i]);
var name = $"{allMetadata[i].GetInstanceID()}-{index}"; index++;
AssetDatabase.CreateAsset(clone, $"{basePath}/{name}.asset");
allMetadata[i] = clone;
for (int i = 0; i < allMetadata.Count; i++)
{
allMetadata[i] = CloneCustomAssetMetadata(allMetadata[i], basePath, ref index);
}
list.allMetadata = allMetadata;
AssetDatabase.CreateAsset(list, $"{basePath}/{MetadataLookup.kAssetName}.asset");
UnityEditor.EditorUtility.UnloadUnusedAssetsImmediate();

list.allMetadata = allMetadata.ToArray();
AssetDatabase.CreateAsset(list, $"{basePath}/{MetadataLookup.kAssetName}.asset");
AssetDatabase.StopAssetEditing();
}

Expand Down
44 changes: 27 additions & 17 deletions Runtime/Common/MetadataLookup.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@


#if !UNITY_EDITOR
#define UNITY_RUNTIME
#endif
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;

internal static class MetadataLookup
{
public const string kResourcePath = "AssetMetadata";
public const string kResourcePath = "__AssetMetadata";
public const string kAssetName = "list.asset";

readonly static Dictionary<int, List<CustomAssetMetadata>> table = new();
Expand Down Expand Up @@ -110,7 +111,7 @@ internal static bool Register(UnityEngine.LazyLoadReference<UnityEngine.Object>
internal static void Unregister(UnityEngine.LazyLoadReference<UnityEngine.Object> reference, CustomAssetMetadata metadata)
{
if (reference.isBroken || !reference.isSet ||
object.ReferenceEquals(metadata, null))
object.ReferenceEquals(metadata, null))
return;

if (!table.TryGetValue(reference.instanceID, out var metadataList))
Expand All @@ -119,7 +120,7 @@ internal static void Unregister(UnityEngine.LazyLoadReference<UnityEngine.Object
metadataList.Remove(metadata);
if (metadataList.Count == 0)
{
table.Remove(reference.instanceID);
table.Remove(reference.instanceID);
}
}

Expand All @@ -130,32 +131,41 @@ static bool RegisterMetadataForAsset(string assetPath)
return false;

bool foundAny = false;
foreach (var item in UnityEditor.AssetDatabase.LoadAllAssetsAtPath(assetPath))
var subAssets = UnityEditor.AssetDatabase.LoadAllAssetRepresentationsAtPath(assetPath);
foreach (var item in subAssets)
{
if (item is not CustomAssetMetadata metadata)
continue;

foundAny = MetadataLookup.Register(metadata.reference.asset, metadata) || foundAny;
}
UnityEditor.EditorUtility.UnloadUnusedAssetsImmediate();
return foundAny;
}
#endif

static bool GetAllMetadataForAsset(UnityEngine.Object asset, out List<CustomAssetMetadata> result)
{
EnsureInitialized();
if (table.TryGetValue(asset.GetInstanceID(), out result))
return true;
if (asset)
{
EnsureInitialized();
if (table.TryGetValue(asset.GetInstanceID(), out result))
return true;
#if UNITY_EDITOR
if (Application.isEditor)
{
var assetPath = UnityEditor.AssetDatabase.GetAssetPath(asset);
RegisterMetadataForAsset(assetPath);
if (table.TryGetValue(asset.GetInstanceID(), out result))
return true;
}
if (Application.isEditor)
{
var assetPath = UnityEditor.AssetDatabase.GetAssetPath(asset);
if (!RegisterMetadataForAsset(assetPath))
{
result = null;
return false;
}
if (table.TryGetValue(asset.GetInstanceID(), out result))
return true;
}
#endif
result = null;
}
result = null;
return false;
}

Expand Down Expand Up @@ -192,7 +202,7 @@ static void InitializeEditor()
var allMetadata = Resources.FindObjectsOfTypeAll<CustomAssetMetadata>();
foreach (var metadata in allMetadata)
{
if (metadata != null)
if (!metadata)
continue;
var assetPath = UnityEditor.AssetDatabase.GetAssetPath(metadata);
RegisterMetadataForAsset(assetPath);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "com.custom_asset_metadata",
"displayName": "Custom Asset Metadata",
"version": "1.2.1",
"version": "1.2.2",
"unity": "2020.3",
"description": "Adds the ability to store meta data on Assets",
"license": "MIT",
Expand Down

0 comments on commit 22de986

Please sign in to comment.