Search Unity

Custom Inspector for a list of Addressables

Discussion in 'Addressables' started by RecursiveFrog, Oct 28, 2018.

Thread Status:
Not open for further replies.
  1. RecursiveFrog

    RecursiveFrog

    Joined:
    Mar 7, 2011
    Posts:
    350
    Hello, I'm looking forward to using Addressables but I'm having a difficult time understanding how I'm to create a custom inspector for what I need. See the screenshot below for my current setup.

    Things to note:
    1. This is an inspector for a ScriptableObject
    2. The labels are derived from an external data source of equipment, to which I want to associate arbitrary prefabs.
    3. The labels are display names, not actual key values associated with equipment data, and they can change. They are not ideal for hard-coding into the Address field, and neither are the unique IDs since they are not intended to be human friendly.
    4. The search field simply filters the display by label (eg: don't draw the EditorGUILayout.ObjectField if the label doesn't contain the string in the search field)

    What I would want instead, is something like the above except with a way to call EditorGUILayout.AddressReferenceField or something like that, so that I can have an AddressReference for each equipment item. However, I don't see how I'm to add such a field. How can accomplish this?
     

    Attached Files:

  2. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    The AssetReference already uses a custom property drawer. I'm sure it's possible to make that work in your system, but may require massaging our code a little. I'd recommend you open up our code in the package, and most likely copy a lot of that code into your own property drawer.

    -Bill
     
  3. j0s3I0p3z

    j0s3I0p3z

    Joined:
    Sep 10, 2017
    Posts:
    3
    Thread bump. It's been quite a while since this was open and I had the same issue. I am trying to create a custom editor with AddressReferences. Is there anyway to do this with the current API?

    Thanks,
    Jose
     
  4. merpheus

    merpheus

    Joined:
    Mar 5, 2013
    Posts:
    202
    Hey guys, I believe I have come to a solution. Apparently, a dummy Scriptable Object works for this case.
    Code (CSharp):
    1. public class AssetScriptable : ScriptableObject
    2.     {
    3.         public AssetReference Asset;
    4.     }
    Then you can use serializedProperty to get it.
    Code (CSharp):
    1. soInstance = ScriptableObject.CreateInstance<AssetScriptable>();
    2. var serializedObject = new SerializedObject(soInstance);
    3. var property = serializedObject.FindProperty("Asset");
    Then you can use this property to draw it in your VisualElement/Imgui editor

    Code (CSharp):
    1. serializedObject.Update();
    2. EditorGUILayout.PropertyField(property, false);
    3. serializedObject.ApplyModifiedProperties();
    One thing that I couldn't figure out though, I am using IMGUIContainer for this. Because I need to get this value back to my non-serialized object's property. But I'd rather to use a UIElements PropertyField instead. Unfortunately, there is no way to make change check for propertyfield for this, if anyone knows a way to do that, please quote me.
     
    unity_bill likes this.
  5. jerotas

    jerotas

    Joined:
    Sep 4, 2011
    Posts:
    5,572
    I couldn't get this to work in a custom inspector. It does display the popup for Addressable, but if seemingly registers no changes no matter what you click....anyone get it to work properly?
     
    Real_Siege likes this.
  6. Real_Siege

    Real_Siege

    Joined:
    Jan 14, 2020
    Posts:
    1
    Yea on my end I got the dropable UI but it's all grayed out and I cant modify it.

    Nvm turns out I was using a prefab instead I had to load it with Prefabutility.
     
    Last edited: Feb 15, 2020
  7. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    491
    I just tried this solution m3rt32 suggested as well in my project but like jerotas said it doesn't seem to work for AddressableAssets. The popup appears and everything, but it doesn't seem to register any sort of clicks.
    I'm wondering if this has anything to do with GUI HotControls, perhaps? I did some digging into the AssetReferenceDrawer source code and it seems to assign those to the dropdown if I understood things correctly?
     
  8. sand_lantern

    sand_lantern

    Joined:
    Sep 15, 2017
    Posts:
    210
    This is so close to being useful to me. In my case I'm trying to get the addressable in order to fill out some other default information on my object. Something like this:

    Code (CSharp):
    1. SerializedProperty location = serializedObject.FindProperty ("location");
    2. var val = location.objectReferenceValue;
    3. EditorGUILayout.PropertyField (location);
    4. if (val != location.objectReferenceValue)
    5. {
    6.     AssetReference reference = (AssetReference) val;
    7.     serializedObject.FindProperty ("name").stringValue = reference.editorAsset.name;
    8. }
    Unfortunately, I can't cast val to an AssetReference because it doesn't extend Object. As far as I can tell, nothing else seems to match either. They must have some hidden voodoo going on in PropertyField. Has anyone else worked past this barrier?
     
  9. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    586
    @sand_lantern I use this snippet from Space Puppy's tools to get the actual AssetReference.

    AssetReference reference = (AssetReference) EditorHelper.GetTargetObjectOfProperty(property);


    Code (CSharp):
    1. using UnityEditor;
    2. using System.Linq;
    3. using System.Reflection;
    4.  
    5. namespace com.spacepuppyeditor
    6. {
    7.  
    8.     public static class EditorHelper
    9.     {
    10.         /// <summary>
    11.         /// Gets the object the property represents.
    12.         /// </summary>
    13.         /// <param name="prop"></param>
    14.         /// <returns></returns>
    15.         public static object GetTargetObjectOfProperty(SerializedProperty prop)
    16.         {
    17.             var path = prop.propertyPath.Replace(".Array.data[", "[");
    18.             object obj = prop.serializedObject.targetObject;
    19.             var elements = path.Split('.');
    20.             foreach (var element in elements)
    21.             {
    22.                 if (element.Contains("["))
    23.                 {
    24.                     var elementName = element.Substring(0, element.IndexOf("[", System.StringComparison.Ordinal));
    25.                     var index = System.Convert.ToInt32(element.Substring(element.IndexOf("[", System.StringComparison.Ordinal)).Replace("[", "").Replace("]", ""));
    26.                     obj = GetValue_Imp(obj, elementName, index);
    27.                 }
    28.                 else
    29.                 {
    30.                     obj = GetValue_Imp(obj, element);
    31.                 }
    32.             }
    33.             return obj;
    34.         }
    35.  
    36.         /// <summary>
    37.         /// Gets the object that the property is a member of
    38.         /// </summary>
    39.         /// <param name="prop"></param>
    40.         /// <returns></returns>
    41.         public static object GetTargetObjectWithProperty(SerializedProperty prop)
    42.         {
    43.             if (prop == null) return null;
    44.  
    45.             var path = prop.propertyPath.Replace(".Array.data[", "[");
    46.             object obj = prop.serializedObject.targetObject;
    47.             var elements = path.Split('.');
    48.             foreach (var element in elements.Take(elements.Length - 1))
    49.             {
    50.                 if (element.Contains("["))
    51.                 {
    52.                     var elementName = element.Substring(0, element.IndexOf("[", System.StringComparison.Ordinal));
    53.                     var index = System.Convert.ToInt32(element.Substring(element.IndexOf("[", System.StringComparison.Ordinal)).Replace("[", "").Replace("]", ""));
    54.                     obj = GetValue_Imp(obj, elementName, index);
    55.                 }
    56.                 else
    57.                 {
    58.                     obj = GetValue_Imp(obj, element);
    59.                 }
    60.             }
    61.             return obj;
    62.         }
    63.  
    64.         private static object GetValue_Imp(object source, string name)
    65.         {
    66.             if (source == null)
    67.                 return null;
    68.             var type = source.GetType();
    69.  
    70.             while (type != null)
    71.             {
    72.                 var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
    73.                 if (f != null)
    74.                     return f.GetValue(source);
    75.  
    76.                 var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
    77.                 if (p != null)
    78.                     return p.GetValue(source, null);
    79.  
    80.                 type = type.BaseType;
    81.             }
    82.             return null;
    83.         }
    84.  
    85.         private static object GetValue_Imp(object source, string name, int index)
    86.         {
    87.             if (!(GetValue_Imp(source, name) is System.Collections.IEnumerable enumerable)) return null;
    88.             var enm = enumerable.GetEnumerator();
    89.             //while (index-- >= 0)
    90.             //    enm.MoveNext();
    91.             //return enm.Current;
    92.  
    93.             for (int i = 0; i <= index; i++)
    94.             {
    95.                 if (!enm.MoveNext()) return null;
    96.             }
    97.             return enm.Current;
    98.         }
    99.  
    100.     }
    101.  
    102. }
     
    sand_lantern likes this.
Thread Status:
Not open for further replies.