Search Unity

Serialization Best Practices - Megapost

Discussion in 'Scripting' started by Tim-C, Oct 19, 2012.

  1. WiedemannD

    WiedemannD

    Joined:
    Mar 4, 2015
    Posts:
    19
    Well I wouldn't be surprised if you would find some custom solution in the asset store among editor tools, but I haven't looked for it.

    I don't have a tutorial for you. But I once implemented a very simple undo system for a non Unity web app in JS.
    It shouldn't make much of a difference in CS and Unity though:

    - In your editor window create an array or better a list with a certain size (e.g. 50), which will be how many undo steps your undo stack will have.
    - Have some kind of data object, which might just be a KeyValuePair<string, object> (key = name of the property, value = old value of the property before a change happens), or something more complicated if you would want to store several property changes in one undo step (which I think is possible in Unity's undo system).
    If we are talking about several materials in your case the data object would also need to store a reference to the actual material, or you might include some kind of path structure in the key (e.g. key = "nameOfYourMaterial/nameOfTheChangedProperty"), which you would need to parse again when undoing. There are a billion of ways how you could structure this.
    - Have a function – that gets triggered before you change a property – to store the property's old value in a new data object and push it onto your undo stack (if it is already full, old entries will get removed at the end). -> Then perform the actual property value change.
    - Have a Unity menu entry/button in the scene view/button in your editor window or whatever that triggers the undo operation. Interpret your last data object on the stack, apply the corresponding old property value to the referenced material and afterwards remove the data object from the undo stack.

    Further possible extensions:
    - Additionally have a redo stack that gets filled with data objects when performing an undo operation.
    - Create a Unity menu for your undo system to undo/redo also with certain keyboard shortcuts (using CTRL/CMD + Z is probably not the best idea).
    - Extend your data object with a descriptive string that explains what property was changed or whatever you want and show the latest description in your menu.
     
  2. garrido86

    garrido86

    Joined:
    Dec 17, 2013
    Posts:
    233
    Big thanks for that in-depth knowledge! That's pretty much already a Tutorial and will be enough to guide me through creating my own custom undo system.[/QUOTE]
     
  3. AhrenM

    AhrenM

    Joined:
    Aug 30, 2014
    Posts:
    74
    Forgive the cross post, but I dropped this question into a separate thread and it sank without a trace. Thought I'd take one last crack at it here. I'm having what looks like a serialization sequencing issue with a dependency between a pre-compiled assembly and loose source.

    Problem is thus:
    I have two code modules, lets call them A and B.
    A has a dependency on B and A is an Editor extension I want to ship. B is a framework and will always ship loose.

    When A & B are both loose code files (in dev) everything works fine.
    When A is a compiled DLL every everything works fine until I hit an in-editor serialization, either PIE or code re-compile. At that point ScriptableObjects created by code in the DLL go bye-bye.

    I'm not sure at this point exactly what is happening and it's only evident in the compiled version, so that makes it difficult to debug :confused:. It kind of looks like some stage of serialization(de?) is happening when relationship between A.dll and Assembly-CSharp-Editor.dll isn't resolvable, but I'm really guessing here. Unity 5.1

    I've uploaded the project here:
    https://www.dropbox.com/s/ye8wfv3m6jwmw46/uAssist_Test_U5.1.zip?dl=0

    To replicate:
    Window->Forms->Demo1 (100% loose code files)
    Window->uAssist->Window Designer->Create New Form (editor forms in DLL, framework is loose)
    Start PIE.
    Select one of the editor windows

    Once again this problem only manifests when the editor window classes are in a compiled assembly.

    I am really scratching my head on where to even start on this one, so any advice would be most welcome.

    Ahren
     
  4. Gru

    Gru

    Joined:
    Dec 23, 2012
    Posts:
    142
    Maybe this has been mentioned before - I didn't read the whole thread. However, I just wasted an hour debugging and want to share a little nuance, may help somebody, because this is the best resource for ScriptableObjects out there.

    The problem was with some inheritance hierarchy some of my ScriptableObjects were not saved to disk (some were), even if I set dirty flags correctly and everything. Changes were saved on assembly reload and not immediately.

    The problem was that my Class name was not matching my script file name. Not the best practice, but compilers don't complain.

    Also, a little correction from the first page:
    • The field ‘m_SerializedThing’ needs to have the attribute [SerializeField] added to it. What this tells Unity is that it should attempt to serialize this field on assembly reload or similar events.
    I found this not to be necessary in a class that extends EditorWindow, as the examples there show.
     
  5. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    I wonder if anyone can take a look at this thread:
    http://forum.unity3d.com/threads/creating-a-new-texture2d-for-editorwindow.365759/#post-2381150

    Basically, it seems that references to Texture2D objects are lost when exiting playmode. But this only occurs for Textures that are generated in code (e.g: new Texture2D(1, 1) ... ) If the EditorWindow instance references textures from the project, it will work fine.

    Has anyone encountered such behaviour before? Is this expected behaviour ?
     
  6. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    It's "normal", because when exiting playmode, Unity dump the memory and rebuild it. It works fine for anything on CPU memory, like any C# object, but it does not for anything in GPU memory.

    Your best bet is to write that texture to the disk and retrieve it there after a playmode switch.
     
  7. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    227
    General Array Serialization doesn't work for anyone right ? Even the example is broken.
    I managed to make derived ScriptableObjects in list survive the play button, but not Unity3D restart.
    So, seems like JSON is the only way to work around this issue for now.

    Makes me wonder why we still use old version of mono if every single thing gets broken anyway.
     
    Last edited: May 26, 2016
  8. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Why you don't save your ScriptableObject on disk?
     
  9. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    227
    I think it still fails to populate the generic list with child-class scriptableobjects automatically. I just tried it, this led to some weird errors when restarting Unity. "Script can't be loaded" it says in child ScriptableObject inspector.
    And this will lead to a bit dirty project since I need 100-200 of those.
     
  10. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Are you absolutely sure that the file name exactly matches the class name? That was my problem when I had a similar issue.
     
    forcepusher likes this.
  11. forcepusher

    forcepusher

    Joined:
    Jun 25, 2012
    Posts:
    227
    That did it. Thanks man.
    I had to create an extra script that matches the name for each inherited class (I've got like 10 of them). Seems like my project will turn into a mess lol.
    (Whoops, this was already discussed on page 2 of this thread. I missed it.)

    EDIT:
    I decided that this mess is unacceptable. I'm just going to work around all those issues via JSON, Type.GetType() and some reflection
     
    Last edited: May 29, 2016
    Harinezumi and angrypenguin like this.
  12. RDeluxe

    RDeluxe

    Joined:
    Sep 29, 2013
    Posts:
    117
    Well, after a quite long struggle I may be of some help.

    What's missing from this awesome video is how to actually save the assets, without having hundreds of .asset files everywhere.

    The answer is here :


    You have to create your List<> or Array elements (which are ScriptableObject) and add them to the parent thanks to AssetDatabase.AddObjectToAsset(newScriptableObject, parentObject);

    Set the hideflag to HideInHierarchy on your "children" objects and you are good to go. The List in your parent object will reference the assets, but your project folders won't be crowded.

    I successfully managed to put in place a serialized polymorphic List with this method.
     
    phobos2077 likes this.
  13. Antondoe

    Antondoe

    Joined:
    Dec 2, 2014
    Posts:
    1
    Last edited: Aug 10, 2016
  14. kerede

    kerede

    Joined:
    Apr 3, 2013
    Posts:
    9
    I realize this is an old thread, but the Unite video that goes with it is the single most useful resource I've found on this topic. Here's that link again in case you missed it:


    This is many years old at this point, but I'm guessing it's still a good foundation for understanding the editor serialization process. Is there anything fundamental that has changed in the interim? Is there a newer post or Unite video that covers the changes? Thanks!
     
  15. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Nope, even after all those years, Unity serialization is still as disappointing as it was.
     
    Dextozz likes this.
  16. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Well, 2020 now, gonna update it a bit.

    There's support for generics and System.Object serialization.
    There's support for nullable types.
    Haven't used it yet, so I haven't explored the limitation. (Can you nest type in a ScriptableObject?)

    Unity is very slowly getting to a state of "usable" engine.
    We got copy/paste in the inspector in 2019!

    Now just missing half a thousand basic features from the inspector.
    Unity might be good before 2050!
     
  17. ge01f

    ge01f

    Joined:
    Nov 28, 2014
    Posts:
    121
    2020.3.31 -- Im still having Unity throw away data in a MonoBehaviour in the scene that are Enums (ints) and references to other MonoBehaviours components in the scene that arent ephemeral.

    It seems normally that this doesnt happen, but then sometimes it does happen. No idea why, doesnt seem to fit the serialization model. Adding [SerializeField] to all those ints and MonoBehaviour references does nothing to save them. They are already MonoBehaviours, but I tried adding System.Serializable to them just to see if that changed the behavior of losing the references, but no change in behaviour.

    In the editor, the references are there and stable, but on play they are lost and exiting play they are still lost. The Enum is the craziest part, it's just an int, and in every other MonoBehaviour component, I dont lose them, but in one Im having problem with which is a normal MonoBehaviour that doesnt do anything strange (very vanilla), it loses the data.
     
  18. AhrenM

    AhrenM

    Joined:
    Aug 30, 2014
    Posts:
    74
    Ahhh.....I remember this thread.
    Good times..... :)