Search Unity

  1. Curious about what's going to be in 2020.1? Have a look at the 2020.1 beta blog post.
    Dismiss Notice
  2. Want to see 2020.1b in action? Sign up for our Beta 2020.1 Overview Webinar on April 20th for a live presentation from our evangelists and a Q&A session with guests from R&D.
    Dismiss Notice
  3. Interested in giving us feedback? Join our online research interviews on a broad range of topics and share your insights with us.
    Dismiss Notice
  4. New Unity Live Help updates. Check them out here!

    Dismiss Notice

SerializeReference Attribute?

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

  1. Elringus

    Elringus

    Joined:
    Oct 3, 2012
    Posts:
    501
    Can someone please clarify the following: if a member (a custom serializable type) of a ScriptableObject asset is serialized by reference, should the non-serializable members persist values between editor play mode sessions? Like, imagine the following ScriptableObject:

    Code (CSharp):
    1. public class Container : ScriptableObject
    2. {
    3.     [SerializeReference]
    4.     public List<Item> Items;
    5. }
    And `Item` as follows:

    Code (CSharp):
    1. [System.Serializable]
    2. public class Item
    3. {
    4.     public string Value { get; set; } = null;
    5. }
    I've thought, that `Value` property of `Item` could never be serialized and persist values, as the properties can't be serialized by Unity, but in practice `Value` actually persist any value that is assigned to it at play mode; eg, on first play it has `null`, then I assign to it during play mode, exit play mode, enter play mode again and it still has the value assigned previously during play mode.

    I've made a reproduciton project and sent a bug request (Case: 1213759), but got a response, that this behavior is by design. I'm really confused now, as this breaks all the rules Unity previously had for serialization. Will really appreciate if someone form the devs team could clarify this. @alex-abreu-unity @LeonhardP @karl_jones @jasonm_unity3d @superpig
     
  2. elseforty

    elseforty

    Joined:
    Apr 3, 2018
    Posts:
    198
    kyuskoj likes this.
  3. kyuskoj

    kyuskoj

    Joined:
    Aug 28, 2013
    Posts:
    31
    Hi. I have 2 questions.

    1. Empty class(no field) instances in [SerializeReference] field are not deserialized and it becomes null when I back from prefab mode. Is this by design?

    I pushed a dummy data to make it work.
    Code (CSharp):
    1.  
    2. [Serializable] public class StartFsmCommand : ICommand
    3. {
    4.     [HideInInspector] public int dummy;
    5.  
    6.     public void Execute(object target) {};
    7.     public void Undo(object target) {};
    8. }

    2. [SerializeReference] attribute serializes a custom class which has no [Serializable] attribute. Is it intended?
     
    Last edited: Feb 7, 2020
    Hyp-X likes this.
  4. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    1,901
  5. NWHCoding

    NWHCoding

    Joined:
    Jul 12, 2012
    Posts:
    942
    I am glad to see that 2019.3.1f1 fixed [SerializeReference] list using wrong PropertyDrawer for its elements.

    The issue that was introduced is:
    - Editor is extremely slow when drawing a ReorderableList that has [SerializeReference] attribute.
    - Game mode is not usable when ReorderableList above is visible in the inspector window.

    This was not an issue in 2019.3.0f6 and no code was changed in the meantime.
    Should I submit a bug report or is this a known issue?

    Also, here are deep profiler results (performance is bad when moving an element but also when doing nothing):
    upload_2020-2-13_11-41-21.png

    It seems that DoList() takes a lot of time.
    Here is what is being drawn:
    upload_2020-2-13_11-42-34.png

    And a video:


    Worked perfectly smoothly in previous version and the rest of the inspector works great - only the reorderable list causes massive slowdowns.

    EDIT: Even with one element in the list with a bool and float field it is still noticeably slow.

    EDIT2: Submitted this as a bug, case: 1219277

    EDIT3: Non-SerializeReference list performance is normal. <= Ignore that, it is also much slower than before and shows lag when more elements are added.
     
    Last edited: Feb 14, 2020
    TextusGames likes this.
  6. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    297
    Prefab instance bug.

    Instances of prefab
    are not serializing the type of field with serialized reference attributes. (the field is not marked as an override)
    After entering play mode the field type reverts back to type that is assigned in the prefab.
    It does, however, serialize changes made inside child fields ( if field type of instance is the same as in prefab). ( But after change made and the field was marked as an override, It still is not saved and after entering playmode reverts back to prefab field type).

    Noticeably clicking apply all overrides applies overrides to prefab as expected.

    @LeonhardP Is this a known bug?

    Edited.
    It appears it is a known limitation.
    https://forum.unity.com/threads/can...ereference-fields-in-prefab-instances.776669/

    It is kind of a shame because you use polimorfism to override behaviours. And prefab instance can be overriden too, but they are sadly not compatible for now.

    Edited.
    I was hoping may be prefab variants can override type of serialized reference atribute. But it still resets back..
     
    Last edited: Feb 14, 2020
    kyuskoj, phobos2077 and NWHCoding like this.
  7. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    297
    Nasty renaming bug...

    Renaming used child type will set all your fields of parent type with serialized reference to null. And console will be throwing errors like this " Unknown managed type referenced: [AmimalWorld].Bird ".

    Renaming child class back does not restores data. So renaming a child class that was used at least in one field will loose all your data even in fields there it was not used....

    How are we supposed to rename child types that are used in fields with [SerializeReference]?
    How do you plan to support child class renaming?

    @LeonhardP Is this a known bug?
     
    Last edited: Feb 14, 2020
  8. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    297
    I have a very extreme slow down of inspector even if one field(with SerializeREference attribute) is presented in deeply nested class that is in arrays (and the array is not marked as a serialized reference just one field in youngest child class).
    It is so slow even for 10 elements, that the unfolding variable can take 5 seconds.
    In (2019.3.1f1).

    Edited.
    I can confirm that this is a regression in 2019.3.1.f1 from 2019.3.0.f6.
    In 2019.3.0.f6 inspector is not slow at all.
     
    Last edited: Feb 16, 2020
  9. NWHCoding

    NWHCoding

    Joined:
    Jul 12, 2012
    Posts:
    942
    ReorderableList for normal, non-SerializeReference lists, became extremely slow for me.

    The release of my asset hinges on this and Unity has been promising to fix SerializeReference for quite some time. I am starting to worry that they are out of their depth with SerializeReference in general - or at least out of testing personnel.
     
  10. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    297
    Since the [SerializeRference] is far from production-ready we need a thread for feedback.
    2019.3 beta thread is in the archive and not immediately visible for new users.
    Can someone move this thread into 2020.1 alpha/beta (since it is not archived and visible)?
    And old and new users can continue to gather feedback on this exiting feature.

    @alex-abreu-unity @LeonhardP @karl_jones @jasonm_unity3d @superpig
     
    kyuskoj and SonicBloomEric like this.
  11. NWHCoding

    NWHCoding

    Joined:
    Jul 12, 2012
    Posts:
    942
    No fixes for ReorderableList OR SerializeReference in 2019.3.2f1. Anyone from Unity even attempting to fix this?
    I have an asset about two weeks from release and reworking it to not use [SerializeReference] seems to be the only option at the moment as I have lost faith in Unity team to actually implement something properly. Will 2019 LTS have the fix maybe?
     
    kyuskoj likes this.
  12. NWHCoding

    NWHCoding

    Joined:
    Jul 12, 2012
    Posts:
    942
    One more issue:
    When using [SerializeAttribute] list with public MonoBehavior (could also be other types, have not tested) field that has [NonSerializable] attribute, that field will get reset to initial value (null) each time a value in the inspector is changed.
    So if you set the value at Start() during play mode changing any other value in the inspector will reset the [NonSerializable] fields.

    Edit: All non-serialized fields will get reset as if Play() was just pressed each time any value in the inspector is changed. Only the public fields retain their values.
     
  13. NWHCoding

    NWHCoding

    Joined:
    Jul 12, 2012
    Posts:
    942
    I have compiled current list of issues with SerializeReference.

    Current issues:
    • Performance of lists (especially ReorderableList) since 2019.3.2f is awful. No such issue with version before.
    • Adding element to a SerializeReference list through editor to a prefab instance will not make it dirty and it is impossible to mark it dirty in any way.
    • [NonSerialized] and private fields will get reset to default value each time a field is modified inside the inspector for that object.
    • If using ReorderableList to draw the SerializeReference list when order of elements is changed message saying that "Undo.RegisterCompleteObjectUndo" is required (which I am using) and mentioning that the type tree has changed pop up. The issue that the message is generated from the internal code so no trace is available.
    • Dragging elements inside ReorderableList for [SerializeReference] List will improperly size the background Rect for the dragged object to the size of the current position in the list. Meaning that element 1 is 50 pixels high and element 2 is 300 pixels high, when swapping the position of those two element 1 will be 300 pixels high while being dragged over element 2's position and element 2 will be 50 pixels high.
     
    SirIntruder, TextusGames and Hyp-X like this.
  14. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    297
    Also renaming issue.
    Renaming class that is used in field with serialized reference attribute will throw errors and set all fields of same type (even there it was not currently assigned) to null this will lead to loose of data.
     
    Last edited: Feb 23, 2020
    NWHCoding likes this.
  15. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    1,901
    Some updates on the issues:

    We have a fix for this issue in the pipeline. It's currently being reviewed so it will hopefully not be much longer.

    This is a known issue and the devs are working on it. No ETA for a fix at this point.

    This is a known issue and the team is working on a solution. I don't have an ETA for a fix here. The issue was previously discussed in this thread.

    The unknown issues:

    We didn't have a bug logged for this but I can see that you already submitted a report. Thanks for that! If it gets verified as a bug, it will show up on the issue tracker here.

    We have nothing logged for this issue AFAIK. It would great if you could submit a report for this as well, ideally with a minimal reproduction project.

    Same as the above. A bug report would be appreciated. Please share the issue IDs in this thread if you submit reports for these cases. That makes it easier to follow up on them.
     
    Last edited: Feb 26, 2020
    TextusGames likes this.
  16. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    364
    I recently attempted to use serialized reference on a project I'm developing. I've found that when you use the SerializeReference tag on a list of non-templated elements and that list is populated with derived elements which are templated then the editor crashes every time you inspect the list. This crash happens even if you use a custom inspector drawer which doesn't attempt to display the list of elements in any way.

    The same crash happened when I replaced the base class with an interface. There appears to be no way that I can use the SerializedRefrence tag on a list of non-templated base types and fill it with templated elements.
     
    Last edited: Feb 26, 2020
  17. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    696
    To be clear, by "templated" do you mean C# generics?
     
  18. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    297
    Regression is very severe. 50 elments of a collection with serialized reference make working with inspector impossible it freezes about 5 seconds on every action. (It can possibly be as slow with just 50 separate fields with serialized reference attributes.)
    What was not the case in 2019.3.0f6.
    It is clearly a regression that was introduced in 2019.3.1f1 and is really the one that comletely denies using this feature.

    Also i somehow can not open the link. (
    The page you were looking for doesn't exist.
    You may have mistyped the address or the page may have moved.)
     
  19. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    1,901
    The page doesn't exist because the issue hasn't been verified yet. As I said, the link will start to work if that happens.
     
    TextusGames likes this.
  20. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    364
    Yes that's right. Thank you.
     
  21. SonicBloomEric

    SonicBloomEric

    Joined:
    Sep 11, 2014
    Posts:
    696
    According to @karl_jones:

    It looks like support may be coming later this year...
     
    karl_jones likes this.
  22. karl_jones

    karl_jones

    Unity Technologies

    Joined:
    May 5, 2015
    Posts:
    3,764
    Its in 2020.1 alpha now

    Scripting: The serializer can now serialize fields of generic types (e.g. MyClass<int> someField) directly; it is no longer necessary to derive a concrete subclass from a generic type in order to serialize it.

    Note: SerializeReference does not support generic serialization at the moment, you will still need to use concrete classes when using SerializeReference.
     
    Last edited: Mar 3, 2020
    SonicBloomEric likes this.
  23. Trinary

    Trinary

    Joined:
    Jul 26, 2013
    Posts:
    364
    Hmm.. in that case perhaps it should throw an exception rather than crashing the editor.
     
  24. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    297
    Is this a known issue that then you create one element in list with serialize reference attribute then increase number of elements. This elements will refer to the same object and if you change values of one element all of them will be changed.
    With is not expected, buggy behaviour.

    Is this a bug? I hope that is.
     
  25. jasonatkaruna

    jasonatkaruna

    Joined:
    Feb 26, 2019
    Posts:
    53
    The usual behavior of adding items to a list in the unity inspector is to duplicate the previous element. I'm betting the behavior is the same, and since the duplication is by reference and not by value, this is why they refer to the same object.
     
  26. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    297
    Then you increase the number of elements of the list you do not want it to be duplicated by reference. But the thing you get is that you have a list of just one object that can be changed to just one field I guess, what is the purpose of the list in that case.
    I do not think that duplicating by reference in inspector is desirable.
     
    jasonatkaruna likes this.
  27. MadWatch

    MadWatch

    Joined:
    May 26, 2016
    Posts:
    30
    Same issue here (with Unity 2019.3.4f1). My code looks like this:

    Code (CSharp):
    1. public class Graph : Root, ISerializationCallbackReceiver
    2. {
    3.   [HideInInspector] [SerializeReference] private List<Node> mNodes;
    4.  
    5.   public void OnBeforeSerialize()
    6.   {
    7.     // ... some stuff here...
    8.   }
    9.  
    10.   public void OnAfterDeserialize()
    11.   {
    12.     // Here mNodes contains the correct number of elements but they are all null
    13.   }
    14. }
    When OnAfterDeserialize() is called the node list contains only null references. However the nodes are deserialized properly at a later point. Could this be a bug that OnAfterDeserialize() is called before deserializing the references?
     
  28. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    1,901
    This is a known issue: https://issuetracker.unity3d.com/product/unity/issues/guid/1216813/
    It's currently being investigated.
     
  29. Ghat-Smith

    Ghat-Smith

    Joined:
    Aug 16, 2016
    Posts:
    18
    I saw that problem too, and did a bug report two weeks ago. I got this answer in FogBugz :

    "We successfully reproduced this issue and have determined that it is by design. We have had similar case reports in the past and the developers have been asked about this problem, their response was that, although this behavior might be undesirable, there are times when it is."

    Like you, I can't find any case where this behaviour can be desirable by default... It can't be a good design, unless you give a way to chose if an element is a reference to another element or not, and especially give the possibility to chose which one.

    Also, I noticed that if your script have multiple lists of SerializeReference of the same type, when you add an element to a list, it's creating a reference to the first created (or first found ?) element of the same type, even if it's from another list. So you can end with multiple lists sharing one same object reference.
     
    TextusGames likes this.
  30. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    297
    I am really pity about that poor designer who is working in such big company and designs such things. Then I increase the size of collection I want to increase the size of it no more than what. I do not want it to be magical copy by reference without any indication( especially than usual list are duplicated by value). It seems for me that they are just do not want to spend resources on changing collection size increase logic in inspector.
    For copy by reference there should be another menu command.
     
    kyuskoj likes this.
  31. jasonatkaruna

    jasonatkaruna

    Joined:
    Feb 26, 2019
    Posts:
    53
    I sympathize with you. I think in general, the
    [SerializeReference]
    attribute doesn't have a good default inspector drawer. Whenever I want to edit it, it's usually through code or my own, custom inspectors, similar to what you built with the
    [SerializeReferenceButton]
    attribute (which is pretty sweet btw).
     
    kyuskoj and TextusGames like this.
  32. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    417
    Hey, so I recently came upon this and it's a very great and promising feature.
    I've implemented it in a dialogue system where steps can have requirements and results, which are defined like this:

    Code (CSharp):
    1.     [Serializable]
    2.     public abstract class EffectResult
    3.     {
    4.         public abstract void Execute();
    5.     }
    6.     public class EffectResult_Flag : EffectResult
    7.     {
    8.         public AssetReference Flag { get { return _flag; } }
    9.         public bool Value { get { return _value; } }
    10.         [SerializeField] private AssetReference _flag;
    11.         [SerializeField] private bool _value;
    12.  
    13.         public override void Execute()
    14.         {
    15.             GlobalFlags.Flags[Flag.Asset.name] = Value;
    16.         }
    17.     }
    18.  
    And then simply create a List<EffectResult> in a ScriptableObject and mark this as SerializeReference.
    This all seems to work fine in the Editor, after I wrote a custom property drawer for stuff like this I can properly instantiate and serialize elements into this list.
    However, when I then try to access that list in another object at runtime I get an empty list.
    Am I doing something wrong? The rest of the ScriptableObject containing this list loads in perfectly fine.
     
  33. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    417
    Disregard this, I was being stupid and didn't rewrite my getter to return the correct list. Everything's fine, problem existed between keyboard and seat ;)
     
  34. EyeMD

    EyeMD

    Joined:
    Feb 28, 2015
    Posts:
    7
    I wrote a Dialogue system with branching/tree data structure - Characters have List<Conversation>, conversations are List<Statements or Questions> and Statement/Question inherit from base class of node. Also doing something similar with a Quest system.
    I'm using BinaryFormatter to save/load data - my main issue now is serializing all of this data.
    I'm looking into using ISerializationSurrogate as well as ISerializationCallBackReciever.
    Although relatively new to Serialization, I understand the [SerializeReference] attribute allows serialization of nulls, but more importantly to me, polymorphism and c# object references.
    I'm still researching the best way to go about this - any thoughts on how I can use [SerializeReference] to streamline serializing branching tree data structure in pseudocode? Thanks,
     
    Last edited: Mar 30, 2020 at 5:38 AM
  35. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    417
    I've recently overhauled my own Dialogue system to use this tech as well :)
    Perhaps I can provide some inspiration.
    My Dialogue class contains flat collections of DialogueStep and DialogueChoice classes, which reference each other through indexes (for now): so a DialogueStep (DS1) references 2 Choices (DC1 and DC2) which both have a reference to two new steps DS2 and DS3.
    With the SerializeReference attribute, I can replace those index references with Object References instead. As long as I keep the actual source objects within those flat collections (for editing safety, so breaking a connection between a step and a choice by nulling it won't actually delete the object).
    As an added bonus, I managed to use SerializeReference to save out a Polymorphic Requirement class allowing me to enable/disable Dialogue Choices based on the current game state (does the player possess an item? etc.)
     
  36. jasonatkaruna

    jasonatkaruna

    Joined:
    Feb 26, 2019
    Posts:
    53

    Keep in mind that the references are local to that UnityEngine.Object, so your tree can't be spread out across multiple MonoBehaviours or ScriptableObjects.

    The SerializeReference attribute doesn't have an in-editor drawer for instantiating new objects, but it will show you what's already there. You'll likely want to instantiate the tree and set it up with an editor script rather than through the inspector.

    If you want a tree like structure that isn't local to a UnityEngine.Object, you'll have to use ScriptableObjects. These still support polymorphism--they just have to derive from the same scriptableobject base class.
     
  37. Yandalf

    Yandalf

    Joined:
    Feb 11, 2014
    Posts:
    417
    Yeah, that's an important caveat there!
    Don't expect references to work across multiple UnityObjects (and if I'm understanding the documentation right it doesn't serialize UnityObjects either. Other classes are fine).

    I did write a property drawer myself to combat this problem, actually! If you have a variable that you want serialized this way I added a little attribute which gets drawn as a type dropdown on the inspector, and it instantiates a new object to be stored in that value when used.
    All the code for that can be found here with an example!

    Edit: I forgot the code I posted there did not include the attribute I mentioned. That was added later and has never been put online. It shouldn't be difficult to implement yourself though :)
     
    jasonatkaruna likes this.
  38. jasonatkaruna

    jasonatkaruna

    Joined:
    Feb 26, 2019
    Posts:
    53

    Haha I wrote my own too! https://upm-packages.dev/-/web/detail/com.jasonboukheir.unity-editor-extensions

    It's basically the same thing as yours but with an object picker type drawer instead of an enum dropdown.

    I really think Unity should implement their own since I know of at least 3 different solutions to the same problem.
     
    Yandalf likes this.
  39. EyeMD

    EyeMD

    Joined:
    Feb 28, 2015
    Posts:
    7
    Awesome, thank you so much, very helpful.

    Once again, still figuring out serialization, this is slightly removed from [SerializeReference] but - when a class loaded/deserialized, there is a new instance of that object with identical field members created right?

    Let's say I have a plain old c# class that is serializable. Its constructor calls when I create it. I then serialize it and save it to the hardrive. After I remove references to it, I can see that the original instances Destructor is called. Then, when I load and deserialize and return this new instance, I'm able to call methods on it and access its data - but its constructor is never called.

    Feel like I'm missing something here - when a class is deserialized a new instance (identical to what was originally serialized) is created, but why is the constructor not being called? Thanks again,
     
  40. EyeMD

    EyeMD

    Joined:
    Feb 28, 2015
    Posts:
    7
    Thinking about it more, it makes sense to me now - after the class is deserialized it is introduced back into the game. But its not created anew, so it makes sense that the constructor isn't being called. Save/load is working for my dialogue and quest progression, Thanks again
     
unityunity