Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

SerializeReference Attribute?

Discussion in '2019.3 Beta' started by SonicBloomEric, May 15, 2019.

  1. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    Sorry for the late response, was out on paternity leave.

    example:

    Code (CSharp):
    1.  
    2. [Serializable] class Boo
    3. {
    4.     public int a;
    5. }
    6.  
    7. class Foo : MonoBehaviour
    8. {
    9.     [SerializeReference] public Boo boo;
    10. }
    11.  
    12. void SomeMethodSomewhere( GameObject go )
    13. {
    14.     var foo1 = go.AddComponent(typeof(Foo)) as Foo;
    15.     var foo2 = go.AddComponent(typeof(Foo)) as Foo;
    16.     var boo = new Boo() { a =4 };
    17.  
    18.     foo1.boo = boo;
    19.     foo2.boo = boo;
    20.  
    21.     // At this point, foo1.boo == foo2.boo (same instance)
    22. }
    23.  
    but once the go gets saved and reloaded, if you where to fetch those two components back from the game object into foo1 and foo2, you would have: foo1.boo != foo2.boo

    that is because [SerializeReference] are serialized As Part of the 'root' object , in this case the Foo instances, and so can't be shared between root objects.

    But if Foo had two fields of type Boo, then one instance of Foo could have two fields point to the same Boo instance and that would be preserved during serialization/deserialization.
     
    Last edited: Jul 16, 2019
    Flying_Banana, ftejada and dzamani like this.
  2. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    as of today, there are no plans for it that I am aware of.
     
  3. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41

    yes, just add [SerializeReference] to public List<Animal> animals;
     
    Novack likes this.
  4. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    That sounds a like a bug, please log an issue so that we can track it and resolve it asap. thanks!

    https://unity3d.com/unity/qa/bug-reporting
     
  5. taylank

    taylank

    Joined:
    Nov 3, 2012
    Posts:
    111
    Experiencing the same thing. And the editor crashes every other minute when trying to work with this feature.
     
  6. stopiccot_onthespot

    stopiccot_onthespot

    Joined:
    Oct 1, 2016
    Posts:
    66
    Do you plan guys to add support to serialize template classes without declaring specialized type?
    Code (csharp):
    1. [Serializable]
    2. public class TemplateClass<T>
    3. {
    4.     public T val;
    5. }
    6.  
    7. [Serializable]
    8. public class TemplateClassInt : TemplateClass<int> { }
    9.  
    10. public TemplateClass<int> intClass1;
    11. public TemplateClassInt intClass2;
    intClass1 is not shown in the inspector
     
    Prodigga likes this.
  7. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    At the moment, there are no plans to support generics.
     
  8. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    please log bug reports so that we can address instabilities. thank you.
    https://unity3d.com/unity/qa/bug-reporting
     
  9. FabioFZynga

    FabioFZynga

    Joined:
    Sep 24, 2018
    Posts:
    7
    The doc link is broken, and searching for SerializeReference in the Manual or Scripting API pages for 2019.3 returns no results :/
     
  10. FabioFZynga

    FabioFZynga

    Joined:
    Sep 24, 2018
    Posts:
    7
    This looks beautiful! I've tried it out (exact same code) in Unity 2019.3.0a11, the Trees field appears in the Editor but it is broken! (just shows a list of labels with no ability to add or edit anything) Is that normal?
     
  11. AndrewKaninchen

    AndrewKaninchen

    Joined:
    Oct 30, 2016
    Posts:
    86
    Might I ask why? It really bothers me, as even Unity falls into this trap from time to time. Addressables and UnityEvents, for example, have clunky workarounds because of that. And we know it is possible from a usability standpoint. Odin Serializer is very much capable of working in tandem with Unity's serializer where the second can't, so I can't imagine why Unity's serializer couldn't use a hybrid approach to it, even if using the current way to do it is theoretically impossible. You'd just have to do it a different way wherever it is required.

    Using generics in Unity is a nightmare the way it currently works (as in, it doesn't). In my last project I had to do so many workarounds to be able to serialize everything I needed that in the end I just gave up and refactored everything to go with Odin Serializer so my code could look like it should.
     
  12. stopiccot_onthespot

    stopiccot_onthespot

    Joined:
    Oct 1, 2016
    Posts:
    66
    Such a shame in 2019...
     
    a436t4ataf, starikcetin and Prodigga like this.
  13. LoneWolfGameDevCourse

    LoneWolfGameDevCourse

    Joined:
    Feb 13, 2017
    Posts:
    57
    This usage case is very close to what I am using this for. However, I could not get it to work at first. The elements in m_Trees were serializing references correctly, but the [SerializeReference] fields in the derived classes were not being serialized at all.

    My Node class did not derive from anything, so noticing that in this example the base class was an interface I tried doing that and converting all my references in the derived classes to interface references. Then all the serialization worked as I had hoped!

    Is it really the case that a class can't serialize its own type reference? It's not a problem to add the extra interface but I was wondering why using an interface "middle-man" makes this work.
     
    Last edited: Aug 10, 2019
  14. jasonm_unity3d

    jasonm_unity3d

    Unity Technologies

    Joined:
    Mar 2, 2017
    Posts:
    41
    You are saying that:

    Code (CSharp):
    1.  
    2. class Node
    3. {
    4.   [SerializeReference] public Node left;
    5.   [SerializeReference] public Node right;
    6. }
    7.  
    8. class SpecialNode : Node
    9. {
    10.   [SerializeReference] public object extraData;
    11. }
    12.  
    13. class Tree: MonoBehaviour
    14. {
    15.     [SerializeReference] public Node Root;
    16. }
    17.  
    that a tree with a node of type
    SpecialNode
    does not serialize
    extraData
    , unless interfaces are used to abstract the Node type?

    if that is the case, then it's a bug. please report it so that we can track it and fix it.

    thanks,
    -J
     
  15. LoneWolfGameDevCourse

    LoneWolfGameDevCourse

    Joined:
    Feb 13, 2017
    Posts:
    57
    Actually what I was seeing is that in your example, Root would serialize fine, but left and right would not. I'm not sure about extraData, but it probably would. It only seems to be self-referencing type fields that have the issue. Adding an "INode" interface to the Node class and changing left and right fields to be of INode type would get it to serialize correctly.
     
  16. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    617
    A quick sanity check here: all class definitions in your hierarchy are marked with the [System.Serializable] attribute, yes?
     
  17. LoneWolfGameDevCourse

    LoneWolfGameDevCourse

    Joined:
    Feb 13, 2017
    Posts:
    57
    Here is a concrete example with results.

    With the code set up like:
    Code (CSharp):
    1. public interface IFlowNode { }
    2.  
    3. [System.Serializable]
    4. public class FlowNode : IFlowNode
    5. {
    6.     public FlowNodeId Id;
    7.     public FlowChart Chart;
    8.     public FlowSegment Segment;
    9.     [SerializeReference] public IFlowNode Next;
    10.     [SerializeReference] public IFlowNode Prev;
    11.     public FlowRunMode RunMode;
    12.     public FlowRunClause RunClause;
    13. }
    It serializes the references correctly. Here is the serialized output to the .asset file:

    00000001:
    type: {class: FlowNode, ns: PF.Core, asm: Assembly-CSharp}
    data:
    Id:
    Index: 0
    Revision: 0
    Chart: {fileID: 0}
    Segment: 0
    Next:
    id: 6
    Prev:
    id: 5
    RunMode: 0
    RunClause: 0


    However, with the code set up like:
    Code (CSharp):
    1. [System.Serializable]
    2. public class FlowNode
    3. {
    4.     public FlowNodeId Id;
    5.     public FlowChart Chart;
    6.     public FlowSegment Segment;
    7.     [SerializeReference] public FlowNode Next;
    8.     [SerializeReference] public FlowNode Prev;
    9.     public FlowRunMode RunMode;
    10.     public FlowRunClause RunClause;
    11. }
    The serialized result completely ignores the FlowNode fields:

    00000001:
    type: {class: FlowNode, ns: PF.Core, asm: Assembly-CSharp}
    data:
    Id:
    Index: 0
    Revision: 0
    Chart: {fileID: 0}
    Segment: 0
    RunMode: 0
    RunClause: 0
     
    Last edited: Aug 24, 2019
  18. superpig

    superpig

    Quis aedificabit ipsos aedificatores? Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,194
    Supported in 2020.1.0a2.
     
  19. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    4,486
    Wow! I am waiting for this feature for my personal framework forever. Do you have a time machine which is going forward in time faster than the standard 1 second per second rate? I want to be in 2020 today. :)
     
    Alverik and Prodigga like this.
  20. AndrewKaninchen

    AndrewKaninchen

    Joined:
    Oct 30, 2016
    Posts:
    86
    Nice
     
  21. Peter77

    Peter77

    Joined:
    Jun 12, 2013
    Posts:
    4,102
    That is great! How does this work with custom editors?
     
  22. starikcetin

    starikcetin

    Joined:
    Dec 7, 2017
    Posts:
    245
  23. stopiccot_onthespot

    stopiccot_onthespot

    Joined:
    Oct 1, 2016
    Posts:
    66
    I guess that would be even bigger Unite announcement than nested prefabs)
     
    Alverik and a436t4ataf like this.
  24. kvfreedom

    kvfreedom

    Joined:
    Mar 30, 2015
    Posts:
    16
    If the class name changes, the reference will be lost. Is it possible to store by GUID instead of the class name.
     
    Jes28 likes this.
  25. DoctorShinobi

    DoctorShinobi

    Joined:
    Oct 5, 2012
    Posts:
    86
    Woah. Does it mean this is going to work?
    Code (CSharp):
    1. public UnityEvent<int> eventWithAnInt;
    I have like thirty wrapper classes for UnityEvent since I can't use it directly with template arguments in the inspector.
     
    Last edited: Aug 28, 2019
    Prodigga likes this.
  26. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    771
    I am late to the party but wanted to chime in and say this is excellent news! Kicking goals, Unity serialisation team! :) I assume DoctorShinobi's case would be supported by this? Could we get a confirmation?

    I have similar use cases - a generic class that I need to inherit every time just to specify the type so it is serializable.

    Can the type T be any type, or are there limitations? Would it work fine if T was GameObject, or MonoBehaviour? Or must it be a plain old serializable class?
     
  27. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,434
    I would hazard a guess that if manually specializing it works, then leaving it in its raw generic form will work @Prodigga
     
  28. ObelardO

    ObelardO

    Joined:
    Feb 20, 2015
    Posts:
    2
    Code (CSharp):
    1. Generating diff  of this object for undo because the type tree changed.
    2. This happens if you have used Undo.RecordObject when changing the script property.
    3. Please use Undo.RegisterCompleteObjectUndo
    Everytime when i trying to record object with [SerializeReference] attribute.
     

    Attached Files:

  29. Peter77

    Peter77

    Joined:
    Jun 12, 2013
    Posts:
    4,102
  30. m3rt32

    m3rt32

    Joined:
    Mar 5, 2013
    Posts:
    60
    Is that also mean that, there could be a Dictionary serialization support in 2020.1 ?
     
  31. arkogelul

    arkogelul

    Joined:
    Nov 14, 2016
    Posts:
    100
    Hi all,

    I'm trying to figure out why this thing is that massive. Could someone explain why is it a great thing ?
    I'm kind of new to C# and Unity, but if I can learn something to improve, I'll go for it !
     
  32. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,434
    Probably not, they're quite unrelated issues
     
    m3rt32 and Prodigga like this.
  33. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,330
    It's for when you need to save/load data. If you use OOP features such as inheritance (to store many different Types in the same list, for example) you cannot easily save the data to a file. It will only save the serializable fields (strings, ints, etc) data of the base class and ignore the data from the children. This means you have to make an entirely different "saveable" or simplified version of each class (or use a better serializer system), which is harder when there are references to other things, because you will need a unique ID of some kind.

    It looks like when SerializeReference is bug-free, I will just be able to put it on my class and it will save/load perfectly.

    The best way to see serialized data is by making a ScriptableObject with some public fields, then you can open the asset in notepad, and see the data that was saved as YAML at the bottom.
     
  34. arkogelul

    arkogelul

    Joined:
    Nov 14, 2016
    Posts:
    100
    Thank you for the explanation :)
    It doesn't fully make sense, but it gives me an idea. We didn't tackle the save/load system yet, but I'll definitely check this out. Where can I find further information on the subject ?
     
  35. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    617
    Google is your friend.

    But here are some resources:
    All of the above strongly point out that you cannot type serialized fields using Interfaces, Abstract Classes, or a base class as the current serializer has zero support for it. This is why things like Odin exist and why everyone is so excited that Unity finally added support for some of the missing serialization features.
     
    Alverik, a436t4ataf and arkogelul like this.
  36. Yuri-b

    Yuri-b

    Joined:
    Apr 16, 2017
    Posts:
    1
    I'm experiencing an issue when duplicating/cloning the object. The references of the polymorphic object ([SerializeReference]) that refer to the game object or its components being duplicated are not updated. For instance when I duplicate a game object with a script named Foo that has a property holding the value of type Bar (serialized POCO) and it holds a reference to the game object being duplicated (Foo.bar.gameObject = Foo.gameObject) I end up with two scripts referring to one game object. When object is serialized by value ([SerializedField]) the references to the objects are properly copied/updated.
    I hope this is something that will be changed/fixed in future releases? Otherwise the feature is quite useless.
     
  37. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    3,501
    Please file a bug report so we can make sure this is addressed.
     
  38. Ramobo

    Ramobo

    Joined:
    Dec 26, 2018
    Posts:
    14
    But why? What in the design of the serialization system causes this deal-breaker? For a lot of people, I'm assuming. All that the assumed people and I need out of this feature is to be able to serialize a field that takes a MonoBehaviour that implements a specific interface.
     
    jyfc and JoNax97 like this.
  39. bdovaz

    bdovaz

    Joined:
    Dec 10, 2011
    Posts:
    687
    +1
     
    jyfc likes this.
  40. QFSW

    QFSW

    Joined:
    Mar 24, 2015
    Posts:
    2,434
    If I had to guess, most likely how it instantiates the classes on deserialization; using the method that every other class uses wouldn't work for UnityEngine.Object

    Granted, I don't see why they don't just add a custom factory that uses the AssetDatabase for UnityEngine.Objects, but who knows, there may be something I'm not seeing
     
    Alverik and Ramobo like this.
  41. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    617
    Guessing here, myself, but I think you're basically right. The added complication is that UnityEngine.Object references are properly restored, whereas POCOs are duplicated wherever a single reference was originally shared. To handle this guarantee in the serialization system would likely require additional metadata and, thus, changes to the serialization format itself. I'd be willing to bet that the code to serialize UnityEngine.Objects is both more complex and far deeper in the codebase and isn't something they are interested in touching...
     
    Alverik and QFSW like this.
  42. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    227
    It's for much, much more than that! (hint: the entire Editor is implemented via Serialization. Typically merely clicking things in the Inspector, or selecting objects, will break without correct Serialization).

    ...hence the huge excitement. This takes a lot of code that is correct C#, but bizarrely corrupts/breaks/decouples itself when running in Unity (and at unpredictable moments), and makes it Just Work. The traditional workaround has been to "write lower quality C# code (that avoids using many of the most important features of the C# language, because they break Unity)" or "write huge amounts of complex workarounds / buy complex workarounds from the asset store".
     
    Alverik likes this.
  43. Ludiq

    Ludiq

    Joined:
    Mar 6, 2015
    Posts:
    594
    Piggybacking on this: after a reserialization of foo1, would foo1.boo still point to the same object reference or would it be a new object?

    In other words:

    Code (CSharp):
    1.  
    2. void SomeMethodSomewhere( GameObject go )
    3. {
    4.     var foo = go.AddComponent(typeof(Foo)) as Foo;
    5.     var booBefore = foo.boo;
    6.     // Reserialize foo somehow
    7.     var booAfter = foo.boo;
    8.  
    9.     Debug.Log(booBefore == booAfter); // True or false?
    10. }
    11.  
    If this outputs true, then I have a million other questions. ;):rolleyes:
     
  44. HelloMeow

    HelloMeow

    Joined:
    May 11, 2014
    Posts:
    197
    I'm also a bit disappointed to see that this doesn't let you serialize UnityEngine.Object via their interface.

    UnityEngine.Objects are already serialized by reference. Would it be possible to treat all public/serializable interface fields as a field that can only serialize UnityEngine.Object? The SerializeReference attribute could then be used to differentiate between the intent to serialize POCOs or UnityEngine.Object
     
    sirxeno likes this.
  45. I_Jemin

    I_Jemin

    Joined:
    Jul 31, 2014
    Posts:
    6
    Is there plan to add this feature in Unity 2018.4? I really love and need this but company I working with won't change the unity version :(
     
  46. Peter77

    Peter77

    Joined:
    Jun 12, 2013
    Posts:
    4,102
    Not going to happen, unless they break their own rules:
    https://unity3d.com/unity/qa/lts-releases
     
    Last edited: Oct 1, 2019
    Alverik, superpig and karl_jones like this.
  47. LoneWolfGameDevCourse

    LoneWolfGameDevCourse

    Joined:
    Feb 13, 2017
    Posts:
    57
    So what's the opinion on this? Is this a bug that I should report or is this expected behavior?

     
  48. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    3,501
    Yes please file a bug report.
     
  49. LoneWolfGameDevCourse

    LoneWolfGameDevCourse

    Joined:
    Feb 13, 2017
    Posts:
    57
    Ok just submitted my bug report.

    EDIT: Will post case ID number when emailed to me.
     
    Last edited: Oct 8, 2019 at 4:21 PM
  50. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    658
    @karl_jones So, finally got to use this for some tooling, but unfortunately I very quickly run into an 100% reproducible crash, along with some general oddity. Case 1189933 (@LeonhardP)

    Basically, when serialising an array of polymorphic objects marked with SerializeReference, if one of those objects contains an array stability goes out the window.

    In the most basic form, if I have two objects, the first of which has a primitive field and the second of which has an array field of a primitive, once I add any elements to that array, editing the primitive field crashes the editor 100% of the time.

    Sometimes it will also get in a weird situation where editing the array elements themselves gets incredibly slow and then the editor locks up in a native-side infinite loop. Annoyingly, I stopped being able to reproduce this and lost the call stack of where it gets stuck but it's somewhere related to SerializedProperty::GetStringValue() and it looks like it's copying strings in an infinite loop.
     
    Last edited: Oct 8, 2019 at 7:05 PM
    LeonhardP and karl_jones like this.