Search Unity

[Open Source] VFW (135): Drawers. Save System and full exposure

Discussion in 'Assets and Asset Store' started by vexe, Sep 2, 2014.

  1. wao

    wao

    Joined:
    Aug 9, 2014
    Posts:
    10
    That was the first thing i did. You can find lots of useful information's about custom drawers on 1,2 page.
    DictionaryDrawer.cs
    line 27
    Code (CSharp):
    1. private bool perKeyDrawing, perValueDrawing, noFoldout;
    line 222
    Code (CSharp):
    1. if(!noFoldout)
    2. foldouts[entryKey] = gui.Foldout(pairStr, foldouts[entryKey], Layout.sExpandWidth());
    line 229
    Code (CSharp):
    1. if (!foldouts[entryKey] && !noFoldout)
    2. continue;
    line 235
    Code (CSharp):
    1.  using (gui.Horizontal())
    DrawingAttributes.cs
    around line 57
    Code (CSharp):
    1. [DefinesElementDrawing] public class NoFoldout : Attribute { }
    Then just add NoFoldout attribute to your dictionary. This might not be the cleanest way how to do it but it works. If you want to change is just look around the code and try to understand its not that hard.
     
  2. KhaledM

    KhaledM

    Joined:
    Sep 29, 2013
    Posts:
    41
    @vexe First of all I really appreciate your work and time putted in this package,
    I have a question, when overriding a drawer how can I call the default or base drawer, I just want to add button in the bottom of my BetterScriptableObject script.
     
  3. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @KhaledM Thanks for dropping by! If you just want to add a button, you could just write a method in your BetterScriptableObject and mark it with [Show], that will make it visible in the inspector. If you want to always make it appear in the bottom, you could give it a high display order via [DisplayOrder(1000)] See ShowMethodExample and DisplayOrderExample.

    @Xelnath The reason key/value pairs are drawn like this, is because you might have a complex type as a value, say a List or some interface, having the key/value being drawn beside each other, it wouldn't look so nice. That said, most the times we use dictionaries with simple types for key/value, say, string,GameObject or something like that. In that case it would indeed make sense to have them be drawn beside each other. So I think I will add the option to do that, just like SeqOpt.
     
  4. yonstorm

    yonstorm

    Joined:
    Jan 22, 2013
    Posts:
    5
    I just had to drop by and thank you for this amazing framework. Saved me tons of time and has made me able to focus on my own product features rather than the base functionality that I foolishly thought would be supported by unity by default ( interface / generic serialization ).

    During the last few weeks I had implemented some of the behaviour listed here but noticed it seemed like a task that would never end.

    So thank you. Definitely some nerd love to you from here.
     
    baguwka and vexe like this.
  5. bigdaddy

    bigdaddy

    Joined:
    May 24, 2011
    Posts:
    153
    Just got a message back from Unity support regarding the issue with VFW not compiling in IL2CPP. As the test project, I sent them the example project from VFW.

    They say the compilation issue is fixed in 4.6.4p1 but the project will throw an exception in IL2CPP unless the following is added to your link.xml file:
    I would assume that the issue is also fixed in the latest 5 patch or at the latest on the next patch but I don't know for sure.
     
  6. SuperManitu

    SuperManitu

    Joined:
    Mar 4, 2015
    Posts:
    6
    Is it possible to not serialize a property? I got a few with are set through code and it would be nice not to see them every time in the inspector
     
  7. KhaledM

    KhaledM

    Joined:
    Sep 29, 2013
    Posts:
    41
    @SuperManitu just use [DontSerialize] instead of [Serialize]
     
  8. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Fantastic job, thank you very much!
     
  9. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Hey guys, a small update:

    Regarding Vfw, 1.3 - finally on github - is coming very soon which will hopefully address most of the serialization issues you're having, with many improvements on the editor side of things. There's still one deserialization error that I'm trying to fix which occurs rarely I shot a message to the author of FullSerializer asking his input on the problem giving him a replica project. I will update thread with 1.3 release as soon as that bug is fixed.

    Regarding FastSerializer, it's still a wip, need to implement serializing things by reference. I haven't decided yet, but I'm leaning towards making it open-source.

    Regarding the SaveSystem, still a wip too, it's going to be a separate asset (paid) not part of Vfw. It makes use of FastSerializer for fast binary saving/loading.
     
  10. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @SuperManitu if it's a property with side-effects (bodies for the getter/setter) then it's never serialized. If it's an auto-property, then just [DontSerialize] like Khaled mentioned.

    @JuV Thanks for the kind words, means a lot! Nerd love to you back, with metal horns \m/
     
  11. SuperManitu

    SuperManitu

    Joined:
    Mar 4, 2015
    Posts:
    6
    Yeah, thanks, I thought about this, but couldn't find it in the first place :S, everything is working now
     
  12. Pixeye

    Pixeye

    Joined:
    Jul 2, 2011
    Posts:
    195
    Hi @vexe and everyone!

    First of all, huge thanks for your hard work. VFW is something I always looked for : )
    I'm primarily an ios developer ( and started to use your tool in my next game, Dungelot 3) - there are few issues I ran to. They are not critical but make me worry. The main idea of using VFW for me was to create an easy inspector-based class " editor" for quests and dialogs. After implementing all the stuff using VFW I ran to a problem on iphone
    " run out of trampolines of type 2 " - as far as I understood this error caused by using lots of generic methods, interfaces and so on. I just wander how " heavily" can I use VFW for a mobile project? And maybe someone here already encountered memory problems too.

    Second, After adding vfw my unity editor started to use more and more memory. And keep growing till you shut down editor.



    While I'm writing this post , my editor uses 1240 mb already.



    I use dictionary type of <int,T> where T is a custom generic quest node c# class

    Maybe I'm wrong in designing and using VFW? ( Mainly I wanted to hold string id references, enums, simple data and delegates in a container class ), I use your uDelegate to make list of actions ( for example exiting quest dialog, giving reward and so on )

    And last, It was a little bit frustrating for me to use dictionaries or lists of my quest node classes as they are not informative in the inspector ( they looked like element , element , element ) I'm not experienced with making custom editors, but after looking at your code I implemented to VFW in a dirty way text ref



    I founded



    And added



    With some logic to take string variable from custom class and add to the element counter. Could this feature be implemented in new version as I believe many people would like to order lists and dicts elements by string names, or if it already done where can I look for ref and tutorial : )

    Once again, tnx for your work and awesome editor extension.

    Cheers!
     
    Last edited: Apr 13, 2015
  13. KhaledM

    KhaledM

    Joined:
    Sep 29, 2013
    Posts:
    41
    I cannot find the attribute [Popup] for Int or float, even in the example package it is not there
     
  14. Jacktang

    Jacktang

    Joined:
    Jul 6, 2012
    Posts:
    15
    Really cool plugin! Thanks for all the hard work.

    Just one thing I noticed when looking through the code though. The precompiler wrappers around the profiler and log calls.

    #if PROFILE
    Profiler.BeginSample("Serializing: " + member.Name);
    #endif

    Take a look at the Conditional attribute which is a C# language feature for doing exactly what you're doing without requiring you to wrap every single usage of the method. Unity actually already takes care of this for you for the profiler calls. All the profiler calls are annotated with [Conditional("ENABLE_PROFILER")] so if you don't define ENABLE_PROFILER those calls will simply be compiled out by C#. I noticed you also do the same with your Log calls as well. If you just annotate them with [Conditional("DBG")] you'll get the same behaviour telling C# to compile out all of the calls to those methods if DBG is not defined.

    Great work though, I'm sure I will find many cool uses for this plugin.
     
  15. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    So 1.3 is finally out on github! https://github.com/vexe/VFW - (read first page for some notes)

    1.3 should address most the serialization issues most users were having. I also finally addressed the issue of the flickering when transitioning between edit/playmodes. Better undo support, less 3rd party dependencies and overall more polished codebase. Also added a documentation file, still a wip.

    Sorry it took so long but that's what happens when you play Diablo II
     
    Last edited: Apr 14, 2015
    KhaledM likes this.
  16. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @Jacktang thanks, note taken! I know about Conditional but I remember reading an answer saying there's a difference between them which made me go for those wrapper, now I can't remember that answer nor what the difference was, so I'll go for conditional :D
     
  17. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @KhaledM I intentionally removed float/int support from Popup (see HISTORY file) - Just convert your float/int array/list to a string array/list (which is what I was basically doing in the popup drawer)
    Code (csharp):
    1.  
    2. [Popup("GetNumbers")]
    3. public int number;
    4.  
    5. string[] GetNumbers()
    6. {
    7.     int[] numbers = ....;
    8.     return numbers.Select(x => x.ToString()).ToArray();
    9. }
    10.  
    It's OK to use LINQ here assuming GetNumbers is only for editor-use, and it will not be called perframe but only when the drawer is instantiated, or when you click the "U" button to update the popup members.
     
    KhaledM likes this.
  18. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @pixeye Thanks for using my framework!

    I've never seen that error before. Limited usage of generics/interfaces? Lol Unity....
    I can't really recall where I'm 'heavily' using generics/interfaces in the runtime codebase, all the generics and nastiness is in the editor-side (drawers) - The only runtime interface I implement (as of 1.3) is ISerializationCallbackReceiver. Maybe there's some runtime calls to generic methods, such as Memoize, which I tend to use in a couple of areas yes (which holds a Dictionary<K,V> internally to cache things) Unfortunately I don't have a mobile device so I can't really test. Does the error give you any "helpful" information aside from "yo dawg you got too many trampolines, generics n' stuff"?

    I always keep my editor open even when I'm not doing something Unity-related, but haven't experienced the huge memory usage jump that you're showing. Can you please try and import Vfw 1.3 into an empty project and see if the usage is still heavy? (just to narrow down the possible cause, maybe you got other 3rd parties?)

    You could just override ToString in your quest objects, and they should show up as (assuming you returned the quest name) "QuestName (QuestNode)"
     
  19. KhaledM

    KhaledM

    Joined:
    Sep 29, 2013
    Posts:
    41
    @vexe Thanks for your reply and your hard-smart work
    I imported the latest version (1.3) in new empty project using Unity 5.0.1F1, whenever I try to open
    "DrawersInEditorWindowExample" after the window is showed I am getting repeatedly this error:

    "NullReferenceException: Object reference not set to an instance of an object
    System.Reflection.Emit.ILGenerator.Emit (OpCode opcode, System.Reflection.ConstructorInfo con) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection.Emit/ILGenerator.cs:536)
    Vexe.Runtime.Extensions.DRExtensions+ILEmitter.newobj (System.Reflection.ConstructorInfo ctor)
    Vexe.Runtime.Extensions.DRExtensions.GenerateCtor[Object] (System.Type type, System.Type[] paramTypes)
    Vexe.Runtime.Extensions.DRExtensions.DelegateForCtor[Object] (System.Type type, System.Type[] paramTypes)
    Vexe.Runtime.Extensions.TypeExtensions.Instance[BaseGUI] (System.Type type)
    Vexe.Editor.GUIs.BaseGUI.Create (System.Type guiType) (at Assets/Plugins/Editor/Vexe/GUIs/BaseGUI/BaseGUI.cs:180)
    DrawersInEditorWindowExample.OnGUI () (at Assets/VFW Examples/Editor/DrawersInEditorWindowExample.cs:44)
    System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)"

    Thanks again
     
  20. IWEF

    IWEF

    Joined:
    Jan 6, 2015
    Posts:
    3
    Thank you for your awesome work! The issues we had are now fixed!

    Previously we had to disable serialization for objects which are disabled (removed from scene or editor) to prevent serialization to null in sequences.

    A small problem persists if you make a clean git checkout on the project (or git clean -xdf which cleans Library) than references to object in sequences appear as null, but once the game is started they appear again, so it might be a lag of the sequence drawers. After something is cached in Library problem never appears again.
     
  21. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @KhaledM this should fix it.

    @IWEF this is probably another one of those things related to the upgrade from 1.2.9 to 1.3 - Is there any way you could replicate the behaviour after you said it disappeared?
     
    Last edited: Apr 15, 2015
  22. IWEF

    IWEF

    Joined:
    Jan 6, 2015
    Posts:
    3
    As I said after a git clean -xdf the sequence items are visible as null at the editor start.

    Another thing relates to the field/property id which should be unique and persistent, but since the static counter changes from start to start the id in the assets is always updated, which I think is not so good. Using the GetInstanceID() as an id gives much better results...
     
  23. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    It doesn't really matter if it gets reset. The id field it is initialized to -1 and is only assigned a new id when it's -1. It is marked with SerializeField so it should persist.The real problem is that you could start to duplicate Ids on counter reset. I thought about an id pool, where every Id I assign I add to the pool, and then before assigning an Id I check to make sure it's not already assigned. I was previously using Guid, but I thought it is an overkill. I will look into GetInstanceID
     
  24. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Opened up the source of my vRuntime.dll (as some of you requested @kimsama) which had Helpers, Extensions (which are now under Vexe/Runtime/Library) and Types (now combined with the types under Vexe/Runtime/Types) - There's still one dll, that is my Dynamic/Fast Reflection asset.
     
  25. kimsama

    kimsama

    Joined:
    Jan 2, 2009
    Posts:
    166
    Great!
    Thank you for your proceedings.

    Cheers,
     
  26. NCS

    NCS

    Joined:
    Jan 23, 2015
    Posts:
    2
    First off, thank you so much for your amazing work with your VFW.
    I'm a newcomer to Unity, but I do have a programming background. When I first saw some of the oddities of Unity, like being unable to properly use interfaces or properties (especially with the Inspector), I was kind of disappointed I wouldn't be able to code "properly".
    But then I found your framework. I tried it out, and it is really amazing! I works so well and provides so many features I couldn't even hope to implement myself (not without a lot of work, anyway).

    So thank you a lot for your hard work!

    When I tested your framework, I ran into some bugs though.
    1) In your latest version (1.3), in the Inspector of a BetterBehaviour object, if I go to Script and change the selection of Display (and choose Headers or anything), if I select any other object or even just let the Inspector display anything else, it forgets about the selection I have made and resets Display to BoxedMembersArea.

    2) With a normal MonoBehaviour, the Inspector shows a little graph for the UnityEngine.AnimationCurve, which, if you click on it, opens a small window in which you can edit the graph.
    If I want to use the AnimationCurve in a BetterBehaviour object, though, it just shows the standard object type box that shows which type your object is.
    I wanted to know if you don't support the AnimationCurve, or if you just haven't gotten to implement it/ have overlooked it?

    Either way, thank you for your hard work!
     
    vexe likes this.
  27. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @NCS Thanks for the kind words. Glad you found my little framework useful. It looks like someone already made a contribution adding Color32 and AnimationCurve drawers :) - And this should fix the display options issue.
     
  28. NCS

    NCS

    Joined:
    Jan 23, 2015
    Posts:
    2
    Thank you for the really quick fix! ^^
     
  29. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    I'm doing some cleanup, polishing and writing documentation here and there. I would like to hear some feedback on:
    1. What is/are the feature(s) you use the most?
    2. What killer/game-changing/must-have/nice-to-have feature(s) do you think the framework is missing? (Multiobject editing maybe? although I haven't gotten yet a single complain about it so I'm not sure how critical it is. Maybe another is persisting values coming out of playmode into editmode which is nice to have)
    3. What's the thing that frustrates you the most in the framework? (if any :p)
    4. What are some areas you think are weak and could use some improvement? (apart from documentation which is a work in progress) and how do you think it can be improved?
    5. What are some things you think are not very useful (or maybe not for everybody) and thus shouldn't be a part of the framework? (I could argue for example that BetterAnimator might be one, as I really only used it in my game, you might not even be using mecanim...)
     
    Last edited: Apr 22, 2015
  30. ByteSheep

    ByteSheep

    Joined:
    Jan 6, 2012
    Posts:
    20
    I've noticed that when assigning a field in the inspector, unlike with the default MB scripts, Unity doesn't seem to notice the change you made and won't ask you to save the scene when quitting or loading another level.
    The changes won't be kept unless you remember to save the scene on your own - is there any simple solution to this problem?
    A related issue also seems to be that after loading a scene, assigning a field of a BetterBehaviour inspector, and hitting play, if you then edit & save a script in your project (without saving the scene after assigning the field) the reference in the inspector will be lost.
    Or perhaps a simpler way of explaining the scenario; After hitting play and stopping the game again, any changes that were made to BetterBehaviour inspectors after the last scene save, appear to be lost (or reset to last save state) when editing one of your project scripts in Monodevelop.
    This essentially means you have to remember to save your scene every time you want to edit any script in your project, which is quite annoying : (
    Has anyone else encountered this problem? This is the only issue making me hesitant to use this awesome framework on my current project.
    (Currently using Unity 5.0.1f)
     
    Last edited: Apr 23, 2015
    vexe likes this.
  31. james7132

    james7132

    Joined:
    Mar 6, 2015
    Posts:
    166
    @vexe To answer your questions:

    1. The abstract class/interface serializer is a life-saver.
    2. Some ability to work with the existing Animation system (i.e. exposing a serialized field that normally cannot be serialized to the Animation system). Pretty sure this is impossible, but it would amazing to have that. Multiobject editing would also be nice.
    3. The RabbitGUI's fields for normal System.Objects use of the fully qualified type names is a bit... intimidating? Especially when I am making a kit with this framework intended for beginners, it looks rather daunting. Perhaps provide an option for just the type name? or in general, an option for making the GUI less verbose?

    I don't really have an answer for 4-5, it's working pretty good already.
     
    vexe likes this.
  32. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @merry_christmas I can replicate the first issue yes, I'll see what I can do. About the second issue however; I'm still not able to replicate, maybe I'm not understanding you clearly but here's what I tried:

    1- I had a BetterBehaviour class called TestBehaviour1.cs with a single 'Transform' field called 't'
    2- I assign some transform value (X) to 't', and enter playmode
    3- In playmode, I assign 't' a different value (Y), and then edit the same script (adding and removing a public int x; each time) - After the assembly reload and recompilation, 't' still had the value (Y). (it didn't matter if it was a different script)
    4- After exiting playmode, 't' reverts to the value (X) as expected.

    Is that the way to replicate the behavior you're experiencing? If not, please provide clear steps to replicate or even better shoot a video or create a gif showing the process.
     
  33. ByteSheep

    ByteSheep

    Joined:
    Jan 6, 2012
    Posts:
    20
    I think I'll have to create a video ; )
     
  34. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    2- I'm not sure what 'serialized field' are you talking about. Could you elaborate?

    3- System.Object fields (abstracts, interfaces etc pretty much 'any' type that doesn't have a specific drawer assigned to it) are drawn via RecursiveDrawer (which is meant to be a 'fallback' drawer recursively drawing members that our VisibilityLogic say are visible). Here's what I'm using for the display text:

    Code (csharp):
    1.  
    2.   if (isToStringImpl)
    3.       field = value.ToString();
    4.   else
    5.       field = string.Format("{0} ({1})", value.ToString(), value.GetType().GetNiceName());
    6.  
    So if you implement ToString in your object, it will show whatever you return from there. Otherwise it's value.ToString() and then the value nice type name in prens.

    Looking at this now, I see some redundancy as I recently found that if you don't implement ToString it will default to GetType.ToString() so I'm basically displaying the same thing twice.

    So I guess if ToString isn't impelmented only value.GetType().GetNiceName() is enough? or do you suggest something else?

    Generally speaking I will be implementing a 'DisplayAs' attribute to customize how members look (maybe customize both the label and value text)
     
    Last edited: Apr 23, 2015
  35. james7132

    james7132

    Joined:
    Mar 6, 2015
    Posts:
    166
    @vexe: For example, I wanted to serialize under an interface type A, I choose an implementor type B, it creates the object of type B as needed, and the instance of B's members are accessible from the Animation window, or something similar.

    Yeah, the value.GetType().GetNiceName() only,option is good, but perhaps something like value.GetType().GetNiceName().SplitPascalCase() may be better.
     
  36. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @james7132 If I understood you correctly, you want to inspect members from the Animation Window?... why would you want to do that?
     
    Last edited: Apr 23, 2015
  37. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @merry_christmas it seems that the save scene prompt has to do with Unity's SerializedProperty diff system, they can detect if there's a change and... not sure where they prompt for scene save. I'll investigate more, worst case I will implement a diff system, which also helps visualizing values when they differ from prefab.

    So say you have the following:
    Code (csharp):
    1.  
    2. public class Test : MonoBehaviour
    3. {
    4.   public GameObject go;
    5. }
    6.  
    7. [CustomEditor(typeof(Test))]
    8. public class TestEditor : Editor
    9. {
    10.   public override void OnInspectorGUI()
    11.   {
    12.   // using SerializedProperties changing go and switching scene will prompt a save
    13.   serializedObject.Update();
    14.   var go = serializedObject.FindProperty("go");
    15.   EditorGUILayout.PropertyField(go);
    16.   serializedObject.ApplyModifiedProperties();
    17.  
    18.   // this will not prompt a save, even if you check for changes and SetDirty or test or test.gameObject
    19.   //var test = target as Test;
    20.   //EditorGUI.BeginChangeCheck();
    21.   //test.go = EditorGUILayout.ObjectField("Go", test.go, typeof(GameObject), true) as GameObject;
    22.   //if (EditorGUI.EndChangeCheck())
    23.   //  EditorUtility.SetDirty(test);
    24.   }
    25. }
    26.  
    Does anyone have any input about this? Is there a way to tell Unity there's been changes in the scene and so it should display a prompt when switching scenes? SetDirty doesn't seem to do it.. will keep digging.
     
  38. james7132

    james7132

    Joined:
    Mar 6, 2015
    Posts:
    166
    This would allow us to animate by manipulating those members through an animation, which is usually easier than hand writing custom animation code for each object. Or alternatively, it might be possible to call functions as Animation Events.

    I'm pretty sure it's impossible, especially with the current state Unity's animation system is in, but it would definitely be nice.
     
  39. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Ah... I get it. you want to see members of your interface as values that you can change in the Animation window, just like transform.position etc. Yeah that's not gonna happen unless Unity improves their serialization system to support interfaces etc. Or you could write your own animation system backed up by vfw ;p
     
  40. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Hello, I'm currently trying out this asset because I'd like to serialize a gameobject's scripts (for saving and loading purposes). So I have a reference to a BetterBehaviour script on the gameobject, and now I would like to get the SerializationData that supposedly gets created when a BB script is serialized. I seethat the OnBeforeSerialize() function somehow creates this data, but it's stored in the private variable_serializationData, so how can I access it? I guess there's a good reason why this field is private, otherwise I'd just change it to public ;)
     
  41. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Hey @Cherno. There's a public property to access the that data, "BehaviourData" in BetterBehaviours and "ObjectData" in BetterScriptableObjects.

    I suggest you read the FAQ first on github, I explain a bit about what is meant from the serialization system to serve. It is actually more about 'persisting' things than saving them. The serialization data object contains a dictionary-like structure mapping member names in the behaviour to their values (that's easily serialized to a file if you want to) and a list of Unity objects. Whenever the serializer comes across a Unity object, it just adds it to this list,and serializes the index of where that storage took place. Which means, 1- We're not really serializing Unity objects, it's just a hack to let Unity references persist between assembly reloads 2- We're letting Unity handle the serialization of its own objects. That said, it's not as simple as saving that 'serialization data' object to a file and you're done, there's a lot to do to properly save Unity objects. There's no real way to save that list to a file without writing converters, which is what I did in my Fast.Save, which does exactly what you ask for. Save/Load game system. (It was initially a part of Vfw but no longer, it will be a separate package. I demoed it here a while back)

    You could still use the serialization system to serialize (to Stream) anything that isn't related to Unity, so say a Dictionary<int, List<string>>, you can just use the 'Serializer' property in BetterBehaviour and serialize that dictionary to string, and save it to a file or prefs or whatever.
     
  42. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Thanks for the swift reply. I've been spending the better part of the last two weeks on a method to serialize a gameobject with it's components and only about an hour ago decided to hold my own efforts and try out your system.

    I have implemented a robust ID system so gameobject are basically converted to the information needed so they can get instantiated again when a game is loaded; the id and that of it's parent, if any, and floats for position and rotation. It was when it came to serializing scripts (I didn't even bother with non-MonoBehaviour components like Renderers etc.) that things got very difficult for me because my knowledge of GetField, GetType etc. was extremely limited, to say the least. I initially went with simply creating a seperate, serializeable "wrapper" non-MB class for each MB script and copying the values, first by hand field by field, and later by an automated script. However, I didn't want to constantly update my wrapper classes whenever a script has it's variables changed etc. so I tried my hand at converting a MB component into serializable form.

    That's actually the same how way I did it for my approach. I wasn't able to figure out how to go deeper than the initial script's fields, and planned to look into ISurrogates but decided to try my hand at your method first. So effectively, I got the whole gameobject saving & loading down, now I just need a way to serialize those scripts that are on it.
     
  43. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    You need to dig deeper, try to learn about IL and Reflection.Emit, you'll be surprised how powerful it is! You can pretty much automate the process of saving/loading a behaviour's members and emitting the code that does that to a Dll so it can also be used in AOT platforms, plus with 0 reflection cost (all the reflection stuff is done at emit-time)

    This is what I do in my Fast.Serializer (which I use in Fast.Save) - you give it a bunch of types in advance, and it generates the serialization code necessary to serialize those types (given a number of converters) to either a dynamic method or dll. (as seen here) - I got to a point in Fast.Save where all I need to do to add support to different components is to write what fields/properties to serialize in that component! no surrogates/converters/dtos required (as seen here) - only thing is missing in Fast.Serializer is serializing things by reference, I'm not sure how to go about it (I have a vague idea) as this is my first time writing a serializer and I'm not as genius as @sient :D
     
  44. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    Most valuable missing feature is the ability to refresh the editor ui while the game is running when values inside a Dictionary are changed.

    e.g. right now, if I have a Dictionary<string, int> and then change the value of dict["SomeKey"] = 5, the editor will not update as the game engine updates.
     
  45. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Dictionary drawing has always been challenging. I have code that 'should' address that specific issue you've mentioned, but I'm not surprised to hear that it's not working cause the dictionary drawer is a bit hacky. The problem is, you can't just modify the dictionary immediately because let's say the dictionary key is a reference type, then it's not straight forward to add a new key/value entry, cause it's invalid to have a null (which is the default value for reference types) as a dictionary key, and if it's not null, what else are you going to use? a new instance of TKey? what if the key was a MonoBehaviour...? etc. That prompts into relying on a dictionary-like data structure that allows us to initially add null keys and then you manually write the values to the dictionary when you've set your key. (what the 'w' key is for) - initially I went with a 'temp adding' area where you initialize your pair value to whatever you want, and then add it to the dictionary, but that was also slow and inconvenient sometimes... The problem with relying on another data structure to represent the dictionary is that you can't convert back and forth between the two representations perframe, it would generate megabytes of garbage at ease causing horrible performance, that's why I only read/write from/to the actual dictionary if stuff changes.

    It would be a whole lot easier if the dictionary key was restricted to a value type, that way we can read/write the dictionary directly and not worry about null keys. For me, I mostly use ints, enums or sometimes strings in my runtime dictionaries (imo that's the most common use-case) but I can't assume that for other people, this is a framework and so I have to keep in mind the use-cases of others.

    I'm always open for suggestions on dictionary drawers ideas.
     
  46. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    In my case, I am using a simple string key for my dictionary, is there a modification I can privately perform to allow me to use VFW as an inexpensive "watch' box against the dictionary?
     
  47. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    I'm in the midst of some refactoring. I'll send you a quick patch as soon as I'm done.
     
  48. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    @Xelnath try the latest version. DictionaryDrawer now only supports ValueTypes or strings as keys. It's much simpler and less buggy now. No more 'W' button. If the key was an enum, everytime you click the '+' button I would add a unique value so that you don't have to add, modify then add etc. Same for ints, everytime you press I add 0, 1, 2 etc. You'll see what I mean once you use it. I think it's more satisfying. For anyone that uses reference types as keys, there's no reason you couldn't just use an int, as the reference value would just be hashed as GetHashCode which is just an int.

    @james7132 @pixeye I've added options to customize the display/format of members and fields. See DisplayExample.cs

    @merry_christmas I've addressed both your issues. You should have no reason not to use Vfw in your next project :p
     
    Last edited: Apr 27, 2015
  49. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    I've added some documentations in the readme on github about the drawing systems and how to write drawers, if anybody's interested. I've also addressed editor persistency between assembly reloads so there should be no more flickers/gui disappearing/reappearing which was quite annoying.
     
  50. vexe

    vexe

    Joined:
    May 18, 2013
    Posts:
    644
    Guys, just a reminder about custom drawers. Registering/mapping a type to a drawer is now done manually (for very good reasons), if you don't map, your drawer won't be used. Please view RegisterCustomDrawerExample.cs