Search Unity

AssetReferences as serialized private members

Discussion in 'Addressables' started by aferon, Nov 26, 2018.

  1. aferon

    aferon

    Joined:
    Jun 12, 2015
    Posts:
    8
    Hi.
    Just sharing my experience as I just started working with the addressables system.

    I'm making a heavy use of serialized private fields, mostly for encapsulation reasons, such as this.
    Code (CSharp):
    1. [SerializeField] private GameObject m_prefab;
    While this works with AssetReferences, the inspector starts to display blank lines when you go a bit further, such as arrays or lists of AssetReferences, or objects containing AssetReferences. Add inheritance to the objects you want to serialize and you'll also get blank lines.

    I managed to get around these issues with the following patch (applied to version 0.4.8)
    Code (diff):
    1. diff --git a/game/unity_packages/com.unity.addressables@0.4.8-preview/Editor/GUI/AssetReferenceDrawer.cs b/game/unity_packages/com.unity.addressables@0.4.8-preview/Editor/GUI/AssetReferenceDrawer.cs
    2. index 31df0f3e..bd8a457c 100644
    3. --- a/game/unity_packages/com.unity.addressables@0.4.8-preview/Editor/GUI/AssetReferenceDrawer.cs
    4. +++ b/game/unity_packages/com.unity.addressables@0.4.8-preview/Editor/GUI/AssetReferenceDrawer.cs
    5. @@ -1,10 +1,10 @@
    6.  using UnityEngine;
    7. -using System;
    8. +using UnityEngine.AddressableAssets;
    9.  using UnityEditor.IMGUI.Controls;
    10. +using System;
    11.  using System.Collections.Generic;
    12. -using UnityEngine.AddressableAssets;
    13.  using System.Linq;
    14. -using UnityEditor.Graphs;
    15. +using System.Reflection;
    16.  
    17.  namespace UnityEditor.AddressableAssets
    18.  {
    19. @@ -520,7 +520,14 @@ namespace UnityEditor.AddressableAssets
    20.  
    21.              int arrayIndex = splitCounts[depth];
    22.  
    23. -            var newField = targetObject.GetType().GetField(currName);
    24. +            Type objType = targetObject.GetType();
    25. +            FieldInfo newField = null;
    26. +            do
    27. +            {
    28. +                newField = objType.GetField(currName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
    29. +                objType = objType.BaseType;
    30. +            } while(newField == null && objType != null);
    31. +
    32.              var newObj = newField.GetValue(targetObject);
    33.              if (depth == splitName.Count - 1)
    34.              {
    There is two main modifications here.
    • using BindingFlags when calling GetField(). This allows for retrieving private members, most notably allowing private arrays/lists of AssetReferences
    • a loop walking up the inheritance hierarchy, to get serialized private fields declared in parent classes working (BindingFlags.FlattenHierarchy doesn't account for private members)
    This works for displaying and setting stuff in the inspector but hasn't been thoroughly tested.

    Some notes/questions on some points I ran into while working on the above:
    • while arrays work with any AssetReference type (AssetReferenceGameObject, AssetReferenceTexture, ...), lists don't support the specializations. This is due to how SerializedPropertyExtensions.GetActualObjectForSerializedProperty() is called and could probably be solved with reflection on the generics.
    • the "label rewriting" in SerializedPropertyExtensions.GetActualObjectForSerializedProperty() prevents showing custom labels if you're using custom editors which in turn end up displaying AssetReferences.
     
  2. brgishy

    brgishy

    Joined:
    Jul 9, 2013
    Posts:
    31
    I too am running into similar issues.

    1) Private serialized members do not show up
    @spl0k already solved this in a better way than I did, so no need to reiterate.

    2) Arrays of objects that have AssetReference fields do not show up.
    If you create this ScriptableObject you'll be able to repro the bug.

    Code (CSharp):
    1.  
    2. [CreateAssetMenu]
    3. public class Avatars : ScriptableObject
    4. {
    5.     [SerializeField] private Avatar[] avatars;  // List<Avatar> also would not work
    6.  
    7.     [Serializable]
    8.     public class Avatar
    9.     {
    10.         [SerializeField] private AssetReference danceAnimationClip;
    11.         [SerializeField] private AssetReference fallAnimationClip;
    12.         [SerializeField] private AssetReference jumpAnimationClip;
    13.     }
    14. }
    15.  
    The AssetReferenceDrawer.DescendHierarchy detects indices of arrays correctly, but when it encounters an array that is earlier on in the property path, it sends the array recursively down when it should send the object within the array.

    3) Generic Lists are not supported
    If you were to change the "Avatar[] avatars;" to "List<Avatar> avatars;" in the ScriptableObject above, that too would not work.

    Solution to all three bugs
    AssetReferenceDrawer.cs.png

    I haven't fully tested everything, but they seem to be working well. I hope all this info is helpful. I think this new Addressable system is turning out great so far!
     
    Allan-Smith likes this.
  3. james7132

    james7132

    Joined:
    Mar 6, 2015
    Posts:
    166
    This has been one of the biggest blockers from me adopting use of Addressables (that and the actual building of bundles doesn't seem to allow disabling appending the hash to the built bundles, and building bundles during an actual build seems to error out.)

    Not sure why the drawer is implemented in this way when it could have easily been implemented as a regular object field, perhaps with a custom EditorStyle to denote that the field is addressable with a prompt that says "This object is not Addressable, are you sure would want to add it to a bundle?". This has been consistently broken since the initial public release, and there currently exists a large number of ad hoc hacks to solve one edge case over another, when we clearly already have a proper solution already.
     
    taptpci likes this.
  4. brgishy

    brgishy

    Joined:
    Jul 9, 2013
    Posts:
    31
    @unity_bill Should I be submitting these as bugs? If so, where? Through the editor, or is there a better place to file bugs on packages? I'd love to just send you a PR on this sort of thing.

    Thanks in advance!
     
  5. unity_bill

    unity_bill

    Joined:
    Apr 11, 2017
    Posts:
    1,053
    In general, bug reports are fine, but in this case, this is a known bug we already have on our list.

    Thanks for the input and the code sample.
     
  6. Allan-Smith

    Allan-Smith

    Joined:
    Feb 7, 2012
    Posts:
    57
    Thanks for the temp solution @brgishy, working nicely for me. File to edit by the way is AssetReferenceDrawer.cs if anyone needs to know.
     
    brgishy likes this.