Search Unity

  1. We're looking for feedback on Unity Starter Kits! Let us know what you’d like.
    Dismiss Notice
  2. Unity 2017.2 beta is now available for download.
    Dismiss Notice
  3. Unity 2017.1 is now released.
    Dismiss Notice
  4. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  5. Check out all the fixes for 5.6 on the patch releases page.
    Dismiss Notice
  6. Help us improve the editor usability and artist workflows. Join our discussion to provide your feedback.
    Dismiss Notice

Serialization Best Practices - Megapost

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

  1. WiedemannD

    WiedemannD

    Joined:
    Mar 4, 2015
    Posts:
    16
    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:
    154
    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:
    67
    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:
    113
    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:
    2,622
    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,201
    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. shame

    shame

    Joined:
    Jun 25, 2012
    Posts:
    130
    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,201
    Why you don't save your ScriptableObject on disk?
     
  9. shame

    shame

    Joined:
    Jun 25, 2012
    Posts:
    130
    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:
    9,607
    Are you absolutely sure that the file name exactly matches the class name? That was my problem when I had a similar issue.
     
    shame likes this.
  11. shame

    shame

    Joined:
    Jun 25, 2012
    Posts:
    130
    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
    angrypenguin likes this.
  12. RDeluxe

    RDeluxe

    Joined:
    Sep 29, 2013
    Posts:
    61
    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.
     
  13. Antondoe

    Antondoe

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