diff --git a/Editor/Assigner.cs b/Editor/Assigner.cs index 16feeb6..4644716 100644 --- a/Editor/Assigner.cs +++ b/Editor/Assigner.cs @@ -13,6 +13,9 @@ public static class Assigner new ObjectAssigner(), new ComponentArrayAssigner(), new ObjectArrayAssigner(), +#if UNITY_ADDRESSABLES + new AssetReferenceTAssigner(), +#endif }; public static void AssignObjectProperties(SerializedObject obj) @@ -24,6 +27,7 @@ public static void AssignObjectProperties(SerializedObject obj) { Logger.Log($"Assigning property: {property.propertyPath}"); + bool assigned = false; foreach (ISubAssigner assigner in _assigners) { using (new Timer($"Assigner `{assigner.GetType().Name}` for `{property.propertyPath}`")) @@ -31,17 +35,20 @@ public static void AssignObjectProperties(SerializedObject obj) if (assigner.TryAssign(property)) { Logger.Log($"Property `{property.propertyPath}` assigned by {assigner.GetType().Name}"); + assigned = true; break; } } } + //because of AssetReferenceTAssigner this function must be called here. + if (assigned) + obj.ApplyModifiedProperties(); + if (!property.NextVisible(true)) break; } } - - obj.ApplyModifiedProperties(); } } } \ No newline at end of file diff --git a/Editor/Assigners/AssetReferenceTAssigner.cs b/Editor/Assigners/AssetReferenceTAssigner.cs new file mode 100644 index 0000000..c0e9d9b --- /dev/null +++ b/Editor/Assigners/AssetReferenceTAssigner.cs @@ -0,0 +1,80 @@ +#if UNITY_ADDRESSABLES +using System; +using AutoAssigner.Providers; +using UnityEditor; +using UnityEngine.AddressableAssets; + +namespace AutoAssigner.Assigners +{ + public class AssetReferenceTAssigner : ISubAssigner + { + public bool TryAssign(SerializedProperty property) + { + if (property.propertyType != SerializedPropertyType.Generic) + return false; + + if (property.isArray || property.IsArrayElement()) + return false; + + property.GetFieldInfoAndStaticType(out Type fieldType); + + if (!IsAssignableToGenericType(fieldType, typeof(AssetReferenceT<>))) + return false; + + var obj = property.GetObject(); + if (obj is not AssetReference assetRef) + return false; + + if (assetRef.editorAsset != null) + return true; + + var genericType = GetGenericType(fieldType); + if (genericType == null) + return false; + + var targetName = $"{genericType.Name} {property.name}"; + var targetObj = ObjectProvider.GetOne(genericType, targetName); + if (targetObj == null) + targetObj = PrefabProvider.GetOne(genericType, targetName); + + assetRef.SetEditorAsset(targetObj); + assetRef.SetEditorSubObject(targetObj); + + //We must Update SerializedObject to read new values + property.serializedObject.Update(); + + return true; + } + + //It's tricky to detect both AssetReferenceT and AssetReferenceSprite + private bool IsAssignableToGenericType(Type givenType, Type genericType) + { + if (givenType == null || genericType == null) + return false; + + if (givenType.IsGenericType && + genericType.IsAssignableFrom(givenType.GetGenericTypeDefinition())) + return true; + + var baseType = givenType.BaseType; + return IsAssignableToGenericType(baseType, genericType); + } + + //Return Sprite for both AssetReferenceT and AssetReferenceSprite + private Type GetGenericType(Type givenType) + { + if (givenType == null) + return null; + + if (givenType.IsGenericType) + { + var genericArguments = givenType.GetGenericArguments(); + return genericArguments.Length == 0 ? null : genericArguments[0]; + } + + var baseType = givenType.BaseType; + return GetGenericType(baseType); + } + } +} +#endif \ No newline at end of file diff --git a/Editor/Assigners/AssetReferenceTAssigner.cs.meta b/Editor/Assigners/AssetReferenceTAssigner.cs.meta new file mode 100644 index 0000000..4466f93 --- /dev/null +++ b/Editor/Assigners/AssetReferenceTAssigner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1abb1bd52cec4813b7e7517441546e73 +timeCreated: 1718917066 \ No newline at end of file diff --git a/Editor/Assigners/ComponentArrayAssigner.cs b/Editor/Assigners/ComponentArrayAssigner.cs index 716b0d4..30033b4 100644 --- a/Editor/Assigners/ComponentArrayAssigner.cs +++ b/Editor/Assigners/ComponentArrayAssigner.cs @@ -27,7 +27,8 @@ public bool TryAssign(SerializedProperty property) List all; - if (!property.HasPrefabInTheName()) + var isComponent = property.serializedObject.targetObject is Component; + if (!property.HasPrefabInTheName() && isComponent) { var root = (Component)property.serializedObject.targetObject; all = root.GetComponentsInChildren(element, true).ToList(); diff --git a/Editor/Assigners/ComponentAssigner.cs b/Editor/Assigners/ComponentAssigner.cs index 1a17677..953a90d 100644 --- a/Editor/Assigners/ComponentAssigner.cs +++ b/Editor/Assigners/ComponentAssigner.cs @@ -24,7 +24,8 @@ public bool TryAssign(SerializedProperty property) if (property.objectReferenceValue != null) return true; - if (!property.HasPrefabInTheName()) + var isComponent = property.serializedObject.targetObject is Component; + if (!property.HasPrefabInTheName() && isComponent) { var root = (Component)property.serializedObject.targetObject; Component[] children = root.GetComponentsInChildren(fieldType, true); @@ -32,13 +33,12 @@ public bool TryAssign(SerializedProperty property) if (children.Length != 0) { (property.objectReferenceValue, _) = NameProcessor.GetMatching(children, property.GetTargetName()); + if (property.objectReferenceValue != null) + return true; } } - else - { - property.objectReferenceValue = PrefabProvider.GetOne(fieldType, property.GetTargetName()); - } + property.objectReferenceValue = PrefabProvider.GetOne(fieldType, property.GetTargetName()); return true; } } diff --git a/Editor/AutoAssigner.Editor.asmdef b/Editor/AutoAssigner.Editor.asmdef index 6007ee7..124d1a1 100644 --- a/Editor/AutoAssigner.Editor.asmdef +++ b/Editor/AutoAssigner.Editor.asmdef @@ -2,17 +2,26 @@ "name": "AutoAssigner.Editor", "rootNamespace": "AutoAssigner", "references": [ - "AutoAssigner" + "AutoAssigner", + "Unity.Addressables" ], "includePlatforms": [ "Editor" ], "excludePlatforms": [], "allowUnsafeCode": false, - "overrideReferences": true, - "precompiledReferences": [], + "overrideReferences": false, + "precompiledReferences": [ + "" + ], "autoReferenced": true, "defineConstraints": [], - "versionDefines": [], + "versionDefines": [ + { + "name": "com.unity.addressables", + "expression": "", + "define": "UNITY_ADDRESSABLES" + } + ], "noEngineReferences": false } \ No newline at end of file diff --git a/Editor/Providers/PrefabProvider.cs b/Editor/Providers/PrefabProvider.cs index fe2a18f..03b43b3 100644 --- a/Editor/Providers/PrefabProvider.cs +++ b/Editor/Providers/PrefabProvider.cs @@ -48,7 +48,8 @@ public static Component GetOne(Type t, string targetName) (string bestPath, _) = NameProcessor.GetMatching(paths, targetName); - return AssetDatabase.LoadAssetAtPath(bestPath).GetComponent(t); + var prefab = AssetDatabase.LoadAssetAtPath(bestPath); + return prefab != null ? prefab.GetComponent(t) : null; } public static GameObject GetOne(string targetName) diff --git a/Editor/SerializedPropertyExtensions.cs b/Editor/SerializedPropertyExtensions.cs index 902e244..f597ed4 100644 --- a/Editor/SerializedPropertyExtensions.cs +++ b/Editor/SerializedPropertyExtensions.cs @@ -76,5 +76,14 @@ public static bool IsArrayElement(this SerializedProperty property) && property.propertyPath.Contains("[") && property.propertyPath.Contains("]"); } + + public static object GetObject(this SerializedProperty property) + { + object obj = property.serializedObject.targetObject; + string path = property.propertyPath; + BindingFlags bindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + FieldInfo field = obj.GetType().GetField(path, bindings); + return field != null ? field.GetValue(obj) : default(object); + } } } \ No newline at end of file