Search Unity

Full Inspector: Inspector and serialization for structs, dicts, generics, interfaces

Discussion in 'Assets and Asset Store' started by sient, Jan 23, 2014.

  1. Maisey

    Maisey

    Joined:
    Feb 17, 2014
    Posts:
    302
    [BUG?]
    When serialising a collection with a custom IEqualityComparer, will the comparer be discarded? Or is it because my collection is constructed with a static comparer? Been looking at this issue for to long now so I can't think straight.

    Code (CSharp):
    1.  
    2. private static readonly IEqualityComparer<IConstraint> s_Comparer = new ReferenceComparer<IConstraint>();
    3. [SerializeField, HideInInspector]
    4. private HashSet<IConstraint> m_Constraints = new HashSet<IConstraint>(s_Comparer);
    5.  
     
  2. avee

    avee

    Joined:
    Feb 14, 2013
    Posts:
    6
    Hi, I think I have found a bug.

    Lets say we have the following code:

    Code (CSharp):
    1.  
    2. public struct something {
    3.     public int a;
    4. }
    5.  
    6. [System.Serializable]
    7. public class Why : BaseBehavior<JsonNetSerializer> {
    8.     public Dictionary<something, int> wtf = newDictionary<something, int>();
    9. }
    10.  
    In my testing I have the following behavior:
    https://www.dropbox.com/s/y0x50aut0c2s7a4/fi2-json-bug.m4v?dl=0

    However, if I change the serializer to FullSerializerSerializer, the problem goes away.

    What seems to be the cause?

    FYI I am using the primitve serialization patch that we discussed earlier in this thread.
     
  3. Maisey

    Maisey

    Joined:
    Feb 17, 2014
    Posts:
    302
    [BUG]
    Sorry for spamming, but found one more thing:

    If I modify a custom script on a gameobject, through a script on another gameobject, the state for the modified object is never serialized.

    For example, if I, in another script on another gameObject, have a reference to an object with the following script, and add a new object to the m_MyObjects-list, this will not be saved if I don't explicitly trigger "Windows->Full Inspector->Developer->Save All".

    Code (CSharp):
    1. public class SaveMe : BaseBehaviour{
    2.       public List<object> m_MyObjects = new List<object>();
    3. }
    EDIT1
    Actually, this happens even if I add stuff to the instance from within itself... Seems to be "SaveState" missing when altering the behaviour from code. Calling "Save All" before play fixes it...
     
    Last edited: Dec 11, 2014
  4. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Sorry, can you send me a more detailed report? Statics will not be serialized into the JSON data so you will lose all static data when deserializing.
     
  5. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Json.NET serializes dictionaries as JSON objects, which means that the keys have to serialize to/from strings. Full Serializer serializes dictionaries as arrays with a {key/value} object, which enables support for your complex key example.
     
  6. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    When modifying objects from code you need to explicitly call SaveState on the object after the modification (FI is lazy about serialization so as to not cause a massive slowdown in the editor).
     
  7. avee

    avee

    Joined:
    Feb 14, 2013
    Posts:
    6
    Thank you for the answer! So is it not possible at all to use JSON serializer for dictionaries with complex key? I'm just curious to know..
     
  8. danien

    danien

    Joined:
    Jun 16, 2009
    Posts:
    71
    I'm having a problem (using the trial version of Full Inspector) where variables for my BaseScriptableObject-derived class don't seem to be getting serialized. Every time I quit and restart Unity after saving both the scene and project, the variables are reset and my values are lost.

    Is there documentation for using BaseScriptableObject? Is there something else I need to do other than deriving my class from it?

    EDIT: I've looked at the Other samples with the Item Database. When I edit data in the ItemDatabaseWorld1 ScriptableObject asset, save scene and project, then quit and restart Unity, the ItemDatabaseWorld1 asset shows the old values instead of the changes I have made. If I add a new item, it is not there after restarting.

    I've also modified the values in the Simple Types (BaseBehavior) component in the Jsonnet sample and the values also revert upon saving and restarting Unity. Basically, I can't seem to get serialization working even in the samples.

    This is on Unity 4.6.1, trial version of Full Inspector.

    Any clues on how I can proceed? Thanks.
     
    Last edited: Dec 15, 2014
  9. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Json.NET docs here say that "When serializing a dictionary the keys of the dictionary are converted to strings and used as the JSON object property names. The string written for a key can be customized by either overriding ToString() for the key type or by implementing a TypeConverter. A TypeConverter will also support converting a custom string back again when deserializing a dictionary."
     
  10. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I want to see if this issue occurs on a non-trial build. I've sent you a PM.
     
  11. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    If running on Unity 4.6.1+ scene saving will likely be broken. Please send me a PM to receive a build that corrects this issue. I expect to have FI 2.5 on the asset store within the next week or two.

    Thanks!
     
  12. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Samples are no longer going to be included in the official release. They can be found here instead.
     
  13. Maisey

    Maisey

    Joined:
    Feb 17, 2014
    Posts:
    302
    Ah okay... I see your point but then again, having "SaveState" all over the place is not very fail-proof. Took me some time to figure out why stuff didn't work, so some kind of generic solution is needed IMO. Doesn't unity keep hashes for monobehaviours? Should be pretty straight forward then to call "Save All" each time CTRL+S is pressed and only serialize changed objects (should be efficient enough if possible).

    Another question: Does "Full Inspector" support any kind of "reference perseverance"? Or do I have to solve this manually? Problem is, I have a few classes with eventhandlers, and the same object instance (memory equal) in different collections will as of now be serialized/deserialized as two different objects (as expected), and when setting up the listeners after deserialiez it will fail down the road. Any suggestions so I can avoid spagetti-code?

    Edit.
    I know Json .NET supports this (both as a global setting, and on a per class/field level), but I'm currently running the default Full Inspector Serializer.
     
    Last edited: Dec 18, 2014
  14. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Ya, I'm going to take a look into this and will try to find a solution. It might not be doable without a big performance hit.

    Yep! You can use fiSharedInstance<T> instead to get an instance that is actually shared across many different objects (it is a significantly easier to use ScriptableObject wrapper).

    Full Serializer should support this just as well as Json.NET -- the core issue is that Full Inspector uses a different serialization context per field/property inside of each behavior.
     
  15. Maisey

    Maisey

    Joined:
    Feb 17, 2014
    Posts:
    302
    Great!

    Alright, got any example on how to use it? And I'm not sure: Did you recommend that I should use fiSharedInstance or ScriptableObject?
    Also, I really needed this for basic System.Object types. Is this not possible?
     
  16. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    You can use fiSharedInstance<T> for this scenario. Here is the documentation. It works with any type, not just those derived from UnityObject.
     
  17. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Good news! Everything appears to work correctly -- you no longer need to mark objects as dirty, so this scenario should just work in 2.5.
     
    Maisey likes this.
  18. Maisey

    Maisey

    Joined:
    Feb 17, 2014
    Posts:
    302
    Awesome!
    Edit.
    Okay, I see how SharedInstance<T> is implemented and unfortunatly this is not what I want. Having to type "obj.Instance.SomeMethod()" is not reasonable at this point (would have to change a lot of code to be very bloated).
    What I really need is the same as JSON .NET got.

    Awesome! :)

    Btw: When is 2.5 scheduled for release?
     
    Last edited: Dec 19, 2014
  19. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Full Serializer automatically preserves object references like Json.NET with preserve object references (this enables support for cyclic object graphs). The issue is that even this object reference preservation will not work because each member on the BaseBehavior type is serialized completely independently. The only way to achieve data sharing between members is thus via UnityObject instances.

    I'm hoping to get 2.5 out before the end of December -- if not, then it'll be early January.
     
  20. Kenner-Stross

    Kenner-Stross

    Joined:
    Sep 7, 2012
    Posts:
    11
    FullInspector has been an absolute godsend for us, but we've run into a problem now that we've begun testing on iOS (this is the same problem that was mentioned by one previous poster):

    ExecutionEngineException: Attempting to JIT compile method 'System.Linq.OrderedEnumerable`1<FullInspector.InspectedMember>:GetEnumerator ()' while running with --aot-only.

    at System.Collections.Generic.List`1[FullInspector.InspectedMember].AddEnumerable (IEnumerable`1 enumerable) [0x00000] in <filename unknown>:0
    at System.Collections.Generic.List`1[FullInspector.InspectedMember].AddRange (IEnumerable`1 collection) [0x00000] in <filename unknown>:0
    at FullInspector.InspectedType..ctor (System.Type type) [0x00000] in <filename unknown>:0
    at FullInspector.InspectedType.Get (System.Type type) [0x00000] in <filename unknown>:0
    at FullInspector.InspectedType..ctor (System.Type type) [0x00000] in <filename unknown>:0
    at FullInspector.InspectedType.Get (System.Type type) [0x00000] in <filename unknown>:0
    at FullInspector.InspectedType..ctor (System.Type type) [0x00000] in <filename unknown>:0
    at FullInspector.InspectedType.Get (System.Type type) [0x00000] in <filename unknown>:0
    at FullInspector.InspectedType.RemoveProperty[IntPtr] (System.String propertyName) [0x00000] in <filename unknown>:0
    at FullInspector.InspectedType.InitializePropertyRemoval () [0x00000] in <filename unknown>:0
    at FullInspector.InspectedType..cctor () [0x00000] in <filename unknown>:0
    Rethrow as TypeInitializationException: An exception was thrown by the type initializer for FullInspector.InspectedType
    at FullInspector.Internal.BehaviorSerializationHelpers.RestoreState[FullSerializerSerializer] (ISerializedObject obj) [0x00000] in <filename unknown>:0
    at FullInspector.BaseBehavior`1[TSerializer].RestoreState () [0x00000] in <filename unknown>:0
    at FullInspector.BaseBehavior`1[TSerializer].Awake () [0x00000] in <filename unknown>:0


    We are using the default FullSerializer in the 2.4 release.

    Has this been fixed in the (hopefully soon-to-be-released) 2.5? I'm curious why this hasn't been coming up more often, as I would certainly imagine that FI2 appears on many iOS games. Hmmm...

    Thanks,
    Kenner
     
  21. Saxi

    Saxi

    Joined:
    Jun 28, 2013
    Posts:
    381
    What type of impact does this have on device, specifically mobile?

    Can you use protobuf-net and have it show up in inspector as well?
     
  22. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Please check your PM's; I've sent you a message with a build that corrects this issue (others deploying on iOS have either sent me an email or posted here) - I meant to submit a 2.4 patch release but I simply got too busy for awhile (I do extra testing before pushing out to the asset store that takes awhile) and 2.5 is almost ready.
     
  23. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Yep, protobuf-net works on Android, but it has issues on AOT platforms like iOS. I include a solution in Full Inspector for AOT platforms but it definitely has rough-edges. Send me a PM if you'd like to try it out. Full Serializer "just works" across every platform and will serialize just about everything (Json.NET serializes most things but not everything, ie, dictionaries with complex keys).

    If you're concerned about performance, you can opt-out of custom serialization by deriving from FullSerializer<NullSerializer> which will give you power of Full Inspector but without serialization support for the various complex types.
     
  24. obula

    obula

    Joined:
    Jan 17, 2012
    Posts:
    4
    Thanks! sient, I will try them.
     
  25. combatdave1

    combatdave1

    Joined:
    Dec 17, 2014
    Posts:
    11
    Hi,

    I'm using the trial of Full Inspector to make sure it meets my needs. I'm currently having difficulty creating a read-only field in a class which inherits from BaseScriptableObject. I'm trying to follow this:

    http://jacobdufault.github.io/fullinspector/assets/docs/custom_property_editors.html

    But it's really not very clear. I assume I need an Attribute Property Editor so I can do something like:

    [ReadOnly]
    public SomeObjectType myObject;

    But even copy-pasting the example code from that page results in errors - CustomAttributePropertyEditor and AttributePropertyEditor apparently don't exist.

    Thanks for any help.
     
  26. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    The docs are targeted at the current release of FI (2.4), whereas the trial is running on an old version (2.3). You can use [InspectorDisabled] instead to create a read-only field/property.
     
  27. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I'm excited to introduce a really cool feature for 2.5: paged collections. It's going to make managing large quantities of data significantly easier.

    Here's a quick demo!

    paged collections.gif

    Whenever a collection reaches a certain length, the paging interface will automatically be displayed. Of course, this interface can be completely disabled if you like (via changing Full Inspector settings) and you can customize how many items the collection must have before the paging interface is displayed. This is additionally configurable on a per-member basis via the new InspectorCollectionPagerAttribute atrribute. Here's an example:

    Code (csharp):
    1.  
    2. public class PagerDemo : BaseBehavior {
    3.     // show the pager after the list has 5 elements
    4.     [InspectorCollectionPager(5)]
    5.     public IObj[] PagerDynamic;
    6.  
    7.     // always show the pager
    8.     [InspectorCollectionPager(AlwaysShow = true)]
    9.     public IObj[] PagerAlwaysShown;
    10.  
    11.     // always hide the pager
    12.     [InspectorCollectionPager(AlwaysHide = true)]
    13.     public IObj[] PagerAlwaysHidden;
    14. }
    15.  
     
    rakkarage likes this.
  28. danien

    danien

    Joined:
    Jun 16, 2009
    Posts:
    71
    Thanks for resolving the serialization issue with Unity 4.6.1, @sient

    I've come across another issue with serialization of C# properties but not sure if it's related.

    If I have a simple property, it works just fine.
    Code (CSharp):
    1. public string Name { get; set; }
    However, if I use custom property getters and setters:
    Code (CSharp):
    1. string _name;
    2. public string Name
    3. {
    4.     get { return _name; }
    5.     set { _name = value; }
    6. }
    FullInspector shows the property in the Inspector and they are editable, but they don't seem to be serialized. If I save the scene/project and reload the scene, the value is set back to an empty string.
     
  29. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    This is an intentional breaking change in 2.5 - auto-properties are automatically displayed and serialized whereas manual properties no longer are. You can show the manual property in the inspector using [ShowInInspector] and you can serialize it via [SerializeField].

    It's strange that the property is showing up in the inspector. I'm unable to reproduce this. Can you post a full sample?
     
  30. danien

    danien

    Joined:
    Jun 16, 2009
    Posts:
    71
    Ah, I didn't realize I needed the SerializeField attribute for manual properties. Thanks.

    The manual property showing up was because I was using FullInspector 2.4 with that (with the change you provided in the PM). It doesn't happen with 2.5RC. Sorry, my bad.
     
  31. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Ah, ok. Thanks
     
  32. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    I have a problem on Unity 4.6.1f1.
    Seems that when FullInspector2.4.2 is imported, Unity cannot save scene, project and prefabs
    When I delete FI, Unity saves scenes as expected

    Edit:
    Tested on fresh new project
    As I import FI unity stops saving
    As I delete Fi unity saves scenes

    Edit:
    Tried with 2.5RC. same results
     
    Last edited: Dec 28, 2014
  33. dkoontz

    dkoontz

    Joined:
    Aug 7, 2009
    Posts:
    198
    Is FI2 compatible with Unity 5? I unzipped the free demo and tried making a simple component with an int and a List<int> and I get the following error. http://imgur.com/kez1mRE
     
  34. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    2.4.2 Scene Save Patch: Download here and import into an existing source-based Full Inspector 2.4.2 installation. Note that this patch will not work on FI 2.5 builds.

    Please check your inbox; I've sent you a new RC that should fix the issue if you want to use the RC; otherwise, please apply the patch above.
     
  35. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Yes, 2.5 (2.4 might, idk) works perfectly in Unity 5.
     
  36. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    Got it. Thank you.
     
  37. combatdave1

    combatdave1

    Joined:
    Dec 17, 2014
    Posts:
    11
    Hi sient,

    Thanks for the support. Is there any easy way to allow my objects to correctly serialize null?

    I'm basically creating a tree, although there can be multiple root nodes and multiple children can point to the same node. To do this, I have a container class and a node class. The Container class inherits from BaseScriptableObject and contains a List<Node> of head nodes. The Node class inherits from nothing, and contains a List<LinkInfo>. LinkInfo is a struct which contains a single reference to another Node (and some other custom data, strings, ints, etc). The Node's List<LinkInfo> will always be populated, but the referenced Nodes inside each individual LinkInfo may or may not be null.

    I'm currently having a problem where on load, a Node deserializes it's List<LinkInfo>, but these LinkInfos then create a new Node rather than correctly leaving their references set to null. That is, if I create a new Container, add a single Node to it, and then add a LinkInfo to the List<LinkInfo> I end up with:

    Container -> head node List<Node> (length 1) -> Node I created -> List<LinkInfo> (length 1) -> Node I didn't ask for (this should be null)

    Do you have any thoughts on the best way to deal with this and correctly have my null references? I assume that I need my Node class to inherit from something, but I'd like to keep them as lightweight as possible.

    Thanks
     
  38. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Can you post the code for the classes? A tree can be defined as simply as this (no need for inheritance, Full Serializer will handle this perfectly, as should the other serializers):

    Code (csharp):
    1.  
    2. public class Tree<T> {
    3.     public T Item;
    4.     public List<Tree<T>> Children;
    5.  
    6.     // etc..., ie
    7.     public Tree<T> Parent;
    8. }
    9.  
    Important: Make sure that Unity does not serialize the given elements, as Unity will automatically populate recursive data structures to a depth of 7 iirc. You can make the type generic, wrap it in a generic holder, or just not add [Serializable].
     
  39. Dolmen007

    Dolmen007

    Joined:
    Nov 25, 2012
    Posts:
    18
    Hello, I just bought FullInspector and the first thing I can say, it is that you made an amazing work so far.:)

    However I have a question about list and arrays for something I try to do.

    I have a script who display an array of derived class from ModelBase, and this array is normally created when you choose an action type with an enum in the inspector.

    But I would like to prevent the user to add, remove or worse rearrange this array in the inspector.
    I see that you implemented Rotorz ReorderableList but how can I use the ReorderableListFlags ?
    I tried with CustomAttribute but I don't understand how I can do what I want.

    My second question is how can I instantiate my array with the right model when the user choose an event type with the enum ?
    I know that I can do that with Unity CustomEditor but I don't know if I can combine this with FullInspector.
    I started to learn Unity Serialisation but it is not so easy.:confused:
     
  40. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I'm just implemented a new attribute for customizing how collections appears (I rewrote the collection code for 2.5 making this *much* easier).

    Here's how to use it:

    Code (csharp):
    1. public class RotorzList : BaseBehavior {
    2.     [InspectorCollectionRotorzFlags(HideAddButton = true, HideRemoveButtons = true, DisableReordering = true)]
    3.     public List<int> myInts;
    4. }
    Here's how it appears:

    upload_2015-1-1_13-3-20.png

    Send me a PM and I'll send you the latest master which includes this attribute.
     
  41. Dolmen007

    Dolmen007

    Joined:
    Nov 25, 2012
    Posts:
    18
    And maybe this could be a good idea to do a UserEcho (userecho.com) like Joachim Holmér did for Shader Forge.
    So we can suggest new things or ideas.

    And about my second question, is this possible to use FullInspector like I was using CustomEditor. Keep FullInspector base, but do things OnInspectorGUI ?
     
    Last edited: Jan 1, 2015
  42. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I use the GitHub Issues page for this.

    Yep, you can write custom PropertyEditors or custom BehaviorEditors (open up Modules/Common/Editor and take a look at some of the files in there for examples of PropertyEditors).
     
  43. stevethorne

    stevethorne

    Joined:
    Apr 8, 2013
    Posts:
    16
    I noticed something today that was causing issues and was wondering why it's done this way.

    If I have an enum serialized in a BaseBehavior<FullSerializer> object and I then remove the value that it's serialized as from the enum, the whole object fails to deserialize. I noticed that it's because of the following lines of code in fsEnumConverter.cs

    Code (CSharp):
    1. if (ArrayContains(Enum.GetNames(storageType), enumValue) == false) {
    2.     return fsFailure.Fail("Cannot find enum name " + enumValue + " on type " + storageType);
    3. }
    Is there any reason as to why it fails if it can't find the value? This means that a programmer can't remove a value after it's used in a serialized object. To fix my issue temporarily, I just set the instance to -1 and return a success.

    While fixing this I also noticed something else. You serialize enums as strings sometimes and as ints/floats sometimes. This seemed strange to me and I was wondering why that is the case. The enums are only serialized as int32s when the enum has the FlagsAttribute.
     
  44. combatdave1

    combatdave1

    Joined:
    Dec 17, 2014
    Posts:
    11

    Here's my code. Container class:

    Code (CSharp):
    1. public class DialogSequence : BaseScriptableObject
    2. {
    3.     public List<DialogNode> headNodes = new List<DialogNode>();
    4.  
    5.     public DialogNode AddHeadNode()
    6.     {
    7.         DialogNode n = new DialogNode();
    8.         n.Initialize(this);
    9.         headNodes.Add(n);
    10.         return n;
    11.     }
    12. }
    Node class, which then contains my "link info" struct.

    Code (CSharp):
    1. public class DialogNode
    2. {
    3.     public struct NodeChoice
    4.     {
    5.         public string text;
    6.         public DialogNode nextNode;
    7.     }
    8.    
    9.     public List<NodeChoice> choices;
    10.    
    11.     public string name;
    12.     public Rect rect;
    13.  
    14.     public void Initialize(DialogSequence owner)
    15.     {
    16.         choices = new List<NodeChoice>(new NodeChoice[4]);
    17.     }
    18. }
    I have a window which deals with creating new DialogNodes and will call Initialize, but I get the same problem just using the inspector too. When I add a new NodeChoice to the "choices" list, the nextNode is populated with an instance of DialogNode.
     
  45. Dolmen007

    Dolmen007

    Joined:
    Nov 25, 2012
    Posts:
    18
    Hello,

    could you post an example of CustomBehaviorEditor ?
    Is that your OnSceneGUI matches to Unity CustomEditor OnInspectorGUI ?

    Code (CSharp):
    1. [CustomBehaviorEditor(typeof(EventTrigger))]
    2. public class EventTriggerEditor : BehaviorEditor<EventTrigger>
    3. {
    4.     protected override void OnEdit(Rect rect, EventTrigger behavior, fiGraphMetadata metadata)
    5.     {
    6.         base.Edit(rect, behavior);
    7.     }
    8.  
    9.     protected override float OnGetHeight(EventTrigger behavior, fiGraphMetadata metadata)
    10.     {
    11.         return base.GetHeight(behavior);
    12.     }
    13.  
    14.     protected override void OnSceneGUI(EventTrigger behavior)
    15.     {
    16.      
    17.     }
    18. }
     
  46. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I'll switch flags over so that they serialize as "Val1, Val2, ..." (issue here). Serializing as an int is simpler which is why it was done that way initially.

    I also plan on adding error recovery (trackable here), but that requires reworking a few things internally (fsFailure, etc). Error recovery means that if one part of the deserializing fails then the rest of the deserialization can still continue.
     
  47. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Sorry, you might have to be more specific with how to reproduce the issue. Everything looks like it is working as expected:

    dialogsequence.gif

    Everything stays the same when I enter/exit play-mode with both Full Serializer and Json.NET.

    Here's the script I used. It's the same as yours except that is derives from BaseBehavior (which won't make a difference -- the serialization logic is identical).

    Code (csharp):
    1. using FullInspector;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class DialogSequence : BaseBehavior<JsonNetSerializer> {
    6.     public List<DialogNode> headNodes = new List<DialogNode>();
    7.  
    8.     public DialogNode AddHeadNode() {
    9.         DialogNode n = new DialogNode();
    10.         n.Initialize(this);
    11.         headNodes.Add(n);
    12.         return n;
    13.     }
    14. }
    15.  
    16. public class DialogNode {
    17.     public struct NodeChoice {
    18.         public string text;
    19.         public DialogNode nextNode;
    20.     }
    21.  
    22.     public List<NodeChoice> choices;
    23.  
    24.     public string name;
    25.     public Rect rect;
    26.  
    27.     public void Initialize(DialogSequence owner) {
    28.         choices = new List<NodeChoice>(new NodeChoice[4]);
    29.     }
    30. }
     
  48. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I'll be happy to show you something more specific if you post the code for EventTrigger, otherwise here's the BehaviorEditor for Transform. The fiLayout code is just another way to manipulate Rect values:

    Code (csharp):
    1. [CustomBehaviorEditor(typeof(Transform))]
    2. public class TransformBehaviorEditor : BehaviorEditor<Transform> {
    3.     private static fiLayout Layout;
    4.  
    5.     static TransformBehaviorEditor() {
    6.         float vecHeight = EditorStyles.label.CalcHeight(GUIContent.none, 0);
    7.         Layout = new fiVerticalLayout {
    8.             { "Position", vecHeight },
    9.             2,
    10.             { "Rotation", vecHeight },
    11.             2,
    12.             { "Scale", vecHeight }
    13.         };
    14.     }
    15.  
    16.     protected override void OnEdit(Rect rect, Transform behavior, fiGraphMetadata metadata) {
    17.         behavior.position = EditorGUI.Vector3Field(Layout.GetSectionRect("Position", rect), "Position", behavior.position);
    18.         behavior.rotation = Quaternion.Euler(EditorGUI.Vector3Field(Layout.GetSectionRect("Rotation", rect), "Rotation", behavior.rotation.eulerAngles));
    19.         behavior.localScale = EditorGUI.Vector3Field(Layout.GetSectionRect("Scale", rect), "Scale", behavior.localScale);
    20.     }
    21.  
    22.     protected override float OnGetHeight(Transform behavior, fiGraphMetadata metadata) {
    23.         return Layout.Height;
    24.     }
    25.  
    26.     protected override void OnSceneGUI(Transform behavior) {
    27.     }
    28. }
     
  49. combatdave1

    combatdave1

    Joined:
    Dec 17, 2014
    Posts:
    11
    Hey again,

    Thanks for the quick support! The issue is actually present in the gif - when you press the "+" on the choices (the third click you do), you can see that the "next node" instantly becomes editable and populated with default values. My desired behaviour is that upon doing the third click in the gif, the "next node" field should be null.

    You can actually see my desired behaviour later in the gif - when you add "deeper" choices (ie go further into the tree), instead of the "next node" field being populated automatically, the field is null and there's a button which gives you the option to create a child.
     
  50. Dolmen007

    Dolmen007

    Joined:
    Nov 25, 2012
    Posts:
    18
    Ok, after some test I wrote this.
    But I still don't understand how using ListField or ListFieldAbsolute from ReorderableListGUI with the param IReorderableListAdapter.

    Code (CSharp):
    1. [CustomBehaviorEditor(typeof(EventTrigger))]
    2. public class EventTriggerEditor : BehaviorEditor<EventTrigger>
    3. {
    4.     private static fiLayout Layout;
    5.     private ActionTypeEnum OldAction;
    6.     private IReorderableListAdaptor adaptor;
    7.  
    8.     static EventTriggerEditor()
    9.     {
    10.         float vecHeight = EditorStyles.label.CalcHeight(GUIContent.none, 0);
    11.         Layout = new fiVerticalLayout {
    12.             { "Event", vecHeight },
    13.             2,
    14.             { "Action", vecHeight },
    15.             2,
    16.             { "ModelTitle", vecHeight },
    17.             2,
    18.             { "ModelArray", vecHeight }
    19.         };
    20.     }
    21.  
    22.     protected override void OnEdit(Rect rect, EventTrigger behavior, fiGraphMetadata metadata)
    23.     {
    24.         behavior.EventType = (EventTypeEnum)EditorGUI.EnumPopup(Layout.GetSectionRect("Event", rect), behavior.EventType.GetType().ToString(), behavior.EventType);
    25.         behavior.Action = (ActionTypeEnum)EditorGUI.EnumPopup(Layout.GetSectionRect("Action", rect), behavior.Action.GetType().ToString(), behavior.Action);
    26.  
    27.         if (behavior.Action != ActionTypeEnum.None)
    28.         {
    29.             if (behavior.Action != OldAction)
    30.             {
    31.                 behavior.Model = this.InstanciateModel(behavior);
    32.  
    33.                 if (behavior.Model != null)
    34.                 {
    35.                     ReorderableListFlags flags = ReorderableListFlags.HideRemoveButtons | ReorderableListFlags.HideAddButton
    36.                         | ReorderableListFlags.DisableReordering | ReorderableListFlags.DisableDuplicateCommand | ReorderableListFlags.DisableContextMenu;
    37.  
    38.                     ReorderableListGUI.Title(Layout.GetSectionRect("ModelTitle", rect), "Model(s)");
    39.  
    40.                     //??? How can I display my list ???
    41.                     //ReorderableListGUI.ListFieldAbsolute(Layout.GetSectionRect("ModelArray", rect), adaptor, flags);
    42.                 }
    43.             }
    44.         }
    45.         else
    46.         {
    47.             if (behavior.Model != null)
    48.             {
    49.                 behavior.Model = null;
    50.                 OldAction = behavior.Action;
    51.             }
    52.         }
    53.  
    54.     }
    55.     protected override float OnGetHeight(EventTrigger behavior, fiGraphMetadata metadata)
    56.     {
    57.         return Layout.Height;
    58.     }
    59.     protected override void OnSceneGUI(EventTrigger behavior)
    60.     {
    61.  
    62.     }
    63.  
    64.     private ModelBaseArray[] InstanciateModel(EventTrigger behavior)
    65.     {
    66.         Type type = typeof(EventManager);
    67.         MethodInfo methodInfo = type.GetMethod(behavior.Action.ToString());
    68.  
    69.         int count = methodInfo.GetParameters().Length;
    70.  
    71.         if (count >= 1)
    72.         {
    73.             ParameterInfo[] parametersArray = methodInfo.GetParameters();
    74.  
    75.             ModelBaseArray[] Model = new ModelBaseArray[parametersArray.Length];
    76.  
    77.             for (int i = 0; i < parametersArray.Length; i++)
    78.             {
    79.                 Type paramType = parametersArray[i].ParameterType;
    80.                 var d = Activator.CreateInstance(paramType);
    81.                 Model[i] = new ModelBaseArray(d as ModelBase);
    82.             }
    83.  
    84.             return Model;
    85.         }
    86.         else
    87.         {
    88.             return null;
    89.         }
    90.     }