Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

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

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

  1. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Ah, I think I see. The inspector will automatically construct object instances for you unless there is not a default constructor or the inspector reaches a certain depth.

    I've created a new attribute, InspectorNotDefaultConstructed, that will handle this workflow. To use it, change NodeChoice to

    Code (csharp):
    1. public struct NodeChoice {
    2.     public string text;
    3.  
    4.     [InspectorNotDefaultConstructed]
    5.     public DialogNode nextNode;
    6. }
    This attribute requires the latest master build. Send me a PM and I'll send you a copy of it.
     
  2. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I'd suggest just calling into FI so that it will do this stuff for you -- no need to rewrite it. (Get a property editor chain via PropertyEditor.Get(typeof(EventTrigger), null) and then you can get the property editor with the .First attribute, ie, `PropertyEditor.Get(typeof(EventTrigger), null).FirstEditor.Edit(...), .GetElementHeight(...)`

    I'd take a look at the Modules/Collections/Editor if you want to see how to create the Rotorz adaptors -- though I wouldn't recommended it.

    Note: Here's the current IList<T> Rotorz adaptor:

    Code (csharp):
    1. public class ListAdaptor<T> : IReorderableListAdaptor {
    2.     public delegate float ItemHeight(T item, fiGraphMetadataChild metadata);
    3.     public delegate T ItemDrawer(Rect position, T item, fiGraphMetadataChild metadata);
    4.  
    5.     private ItemHeight _itemHeight;
    6.     private ItemDrawer _itemDrawer;
    7.     private fiGraphMetadata _metadata;
    8.     private IList<T> _list;
    9.  
    10.     private static T DefaultItemGenerator() {
    11.         return default(T);
    12.     }
    13.  
    14.     /// <param name="list">The list which can be reordered.</param>
    15.     /// <param name="itemDrawer">Callback to draw list item.</param>
    16.     /// <param name="itemHeight">Height of list item in pixels.</param>
    17.     public ListAdaptor(IList<T> list, ItemDrawer itemDrawer, ItemHeight itemHeight, fiGraphMetadata metadata) {
    18.         _metadata = metadata;
    19.         _list = list;
    20.         _itemDrawer = itemDrawer;
    21.         _itemHeight = itemHeight;
    22.     }
    23.  
    24.     public int Count {
    25.         get { return _list.Count; }
    26.     }
    27.     public virtual bool CanDrag(int index) {
    28.         return true;
    29.     }
    30.     public virtual bool CanRemove(int index) {
    31.         return true;
    32.     }
    33.     public void Add() {
    34.         T item = DefaultItemGenerator();
    35.         _list.Add(item);
    36.     }
    37.     public void Insert(int index) {
    38.         Add();
    39.  
    40.         // shift elements forwards
    41.         for (int i = _list.Count - 1; i > index; --i) {
    42.             _list[i] = _list[i - 1];
    43.             _metadata.SetChild(i, _metadata.Enter(i - 1).Metadata);
    44.         }
    45.  
    46.         // update the reference at index
    47.         _list[index] = default(T);
    48.         _metadata.SetChild(index, new fiGraphMetadata());
    49.     }
    50.  
    51.     public void Duplicate(int index) {
    52.         T current = _list[index];
    53.         Insert(index);
    54.         _list[index] = current;
    55.     }
    56.     public void Remove(int index) {
    57.         // shift elements back
    58.         for (int i = index; i < _list.Count - 1; ++i) {
    59.             _list[i] = _list[i + 1];
    60.             _metadata.SetChild(i, _metadata.Enter(i + 1).Metadata);
    61.         }
    62.  
    63.         // pop the last element
    64.         _list.RemoveAt(_list.Count - 1);
    65.     }
    66.     public void Move(int sourceIndex, int destIndex) {
    67.         if (destIndex > sourceIndex)
    68.             --destIndex;
    69.  
    70.         T item = _list[sourceIndex];
    71.         fiGraphMetadata itemMetadata = _metadata.Enter(sourceIndex).Metadata;
    72.  
    73.         Remove(sourceIndex);
    74.         Insert(destIndex);
    75.  
    76.         _list[destIndex] = item;
    77.         _metadata.SetChild(destIndex, itemMetadata);
    78.     }
    79.  
    80.     public void Clear() {
    81.         _list.Clear();
    82.     }
    83.  
    84.     public virtual void DrawItem(Rect position, int index) {
    85.         // Rotorz seems to sometimes give an index of -1, not sure why.
    86.         if (index < 0) {
    87.             return;
    88.         }
    89.  
    90.         _list[index] = _itemDrawer(position, _list[index], _metadata.Enter(index));
    91.     }
    92.     public virtual float GetItemHeight(int index) {
    93.         return _itemHeight(_list[index], _metadata.Enter(index));
    94.     }
    95. }
     
  3. combatdave1

    combatdave1

    Joined:
    Dec 17, 2014
    Posts:
    11
    Removing the default constructor and only providing one with arguments has fixed that for now, cheers :)

    I am having one more problem, though - I'm trying to create a custom EditorWindow to allow me to view my tree in a more visual way, with links being drawn etc. To start with, I'm modifying each node's Position variable as I drag it round. I can see that the inspector is changing, but the DialogSequence object clearly doesn't think that it is dirty - no matter how much I save the project, my changes disappear when I enter/leave play mode. If I modify the Position variable from the inspector, though, these changes persist properly.

    I have found the "SaveState" method on BaseScriptableObject, but this isn't doing what I want. Is this what I should be using? If so, I think I might have found a bug in it. I'm using the exact same code as before (albeit with the default constructor removed). On top of that, I have a custom EditorWindow class which will be drawing all the nodes. To allow me to do this better, I have a NodeVisual class which inherits from nothing and just deals with drawing an individual node. When it opens, my EditorWindow creates one NodeVisual for each Node in my DialogSequence (this is the BaseScriptableObject). The NodeVisual instance handles the drawing and dragging of the node it references - it reads and sets Node.Position. This works fine, and my DialogSequence updates in the inspector to display the correct position values for each Node. At this point, I went through the following process of testing:

    1. Switch from edit to play mode in Unity. This loses all the position changes I've done, presumably because FI doesn't know that the objects which my DialogSequence instance references have changed, and therefore isn't getting itself marked as dirty. So, to fix that I added a "Save" button which calls SaveState on the DialogSequence instance we are editing.

    2. Try to fix the problem before and press my "Save" button. If I switch from edit to play mode, my changes now persist. The problem with this, though, is that when SaveState is called, I am ending up with some weird references. It seems like my DialogSequence gets new copies of all the Nodes it contains, which means that my NodeVisuals are still referencing the old Node instances which the DialogSequence no longer knows about. As such, any changes done will never be persisted - the Nodes which are being modified are now nothing to do with my DialogSequence instance.

    3. To try to fix *that* problem, I added a "Load" button. Pressing this calls RestoreState on my DialogSequence instance, then clears the EditorWindow's list of NodeVisuals and recreates them from the Nodes in the DialogSequence. This works! If I press "Save" and then "Load", my data is persisted and I can continue editing.

    4. Having to press "Load" after "Save" is unintuitive and not what I want from this window. So, I just called my Load function right after I call my Save function. This doesn't work. My guess is that it might be due to the serialization being done on a separate thread, and as such my RestoreState is being called before the SaveState has actually done the serialization.

    The real problem to me seems to be in step 2, with new instances of my Node class being created when I call SaveState. A workaround for that would be easy if it wasn't for the apparent asynchronous which popped up in step 4. Do you have any ideas on if this is a bug or if it's something stupid I'm doing? The alternative, I think, would be to have my NodeVisual class somehow draw the FullInspector inspector (despite for the Node it references despite Node not inheriting from anything) which might correctly inform the DialogSequence that something has changed. Is that possible?

    I can zip up my project if you'd like - I've kept this in a small standalone project purely for testing that I can do what I need to do, so it's not too bloated.

    Cheers again for the help.
     
  4. Dolmen007

    Dolmen007

    Joined:
    Nov 25, 2012
    Posts:
    18
    Thanks for you help sient, but I must admit that I'm completely lost.
    All I want is when you select an item in the serialized enum Event Action, my "InstanciateModel" method is called and the list appears and show the array. I dont know if it is necessary to use CustomBehaviorEditor.
     
  5. stevethorne

    stevethorne

    Joined:
    Apr 8, 2013
    Posts:
    16
    Error recovery sounds great! Would love to see that fully functional.

    The int serialization is much simpler and faster which is why i was confused as to why it defaulted to string serialization and only used the int when an attribute was added.
     
  6. Redtail87

    Redtail87

    Joined:
    Jul 17, 2013
    Posts:
    125
    Hey, I am trying out the demo and can not seem to get properties to work correctly. They show up in the editor fine, but the setter gets called every frame in both editor and play mode. Am I doing something wrong?

    I just have this script attached to a cube in an empty scene

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using FullInspector;
    4.  
    5. public class Player : BaseBehavior
    6. {
    7.     private int _speed;
    8.     public int speed
    9.     {
    10.         get
    11.         {
    12.             return _speed;
    13.         }
    14.        
    15.         set
    16.         {
    17.             _speed = value;
    18.             Debug.Log("Changing Speed to " + value);
    19.         }
    20.     }
    21. }
    22.  
    Thanks.
     
  7. Dolmen007

    Dolmen007

    Joined:
    Nov 25, 2012
    Posts:
    18
    I understand that it is useless to rewrite the list behavior, but I don't understand how call FI in my CustomBehaviorEditor script to show my array and also things that I don't want to change from base behavior.
     
  8. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Is there a way to get the FullInspector inspector within an Editor Window? For example, this shows the default Unity inspector for a component instead of the FullInspector version:
    Code (csharp):
    1. EditorGUILayout.PropertyField(serializedObject.FindProperty("MyThing"));
     
    rakkarage likes this.
  9. Dolmen007

    Dolmen007

    Joined:
    Nov 25, 2012
    Posts:
    18
    So I finally succeed to show my models array with the code you send me.
    Code (CSharp):
    1. behavior.Model = PropertyEditor.Get(typeof(ModelBaseArray[]), null).FirstEditor.Edit<ModelBaseArray[]>(Layout.GetSectionRect("Models", rect), new GUIContent("Model(s)"), behavior.Model, metaDataChild);
    But there is maybe something wrong with height because GUI is showing like this :
     
  10. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Can you send me the project? This should work without any issues by properly wrapping the PropertyEditor calls with change checks and the like. I can take a look at it to see the issue.
     
  11. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    The height issue can be solved by adding the result of

    Code (csharp):
    1. PropertyEditor.Get(typeof(ModelBaseArray[]), null).FirstEditor.GetElementHeight(newGUIContent("Model(s)"), behavior.Model, metaDataChild)
    to the GetElementHeight override.

    I can take a closer look if you send me the actual EventTrigger class itself. Let me know if you need more assistance.
     
    rakkarage likes this.
  12. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Ints are less stable - if you reorder items within the enum, then the int value will deserialize as something else. The int is serialized when we have a flags enum because the flags enum is designed to support multiple values, whereas a regular enum only supports one value.
     
  13. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    This is a bug fixed in 2.4 or 2.5, I don't recall which. Setters are now only called when the value actually changes.
     
  14. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Yep - you have to get the actual object reference though (I have some code that does this for the fiValue property editor; I'll be happy to send it to you in the form of the fiValue editor). After you have the object reference, you can use the typical PropertyEditor.Get(obj.GetType()).Edit / GetElementHeight workflow.

    You can convert any IPropertyEditor / IBehaviorEditor control to use the Layout code with this helper

    Code (csharp):
    1.  
    2.             float height = editor.GetHeight(element);
    3.             Rect region = EditorGUILayout.GetControlRect(false, height);
    4.             if (Event.current.type != EventType.Layout) {
    5.                 editor.Edit(region, element);
    6.             }
    7.  
     
  15. Redtail87

    Redtail87

    Joined:
    Jul 17, 2013
    Posts:
    125
    Ah ok, the current trial is 2.3.1, could I get an updated one please?
     
  16. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I'll be pushing out a new build to the asset store soon. I plan on updating the trial to 2.5 at that time (probably tonight or tomorrow).
     
  17. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I've just pushed out 2.5 to the asset store review team. It should hopefully be available for update soon. I've been working on a new set of docs (you can preview them here) as well for this release.

    I've updated the trial to 2.5 (available here or via the link on the front page of this topic).

    !! The price of Full Inspector is changing to $65. Get it now at $25 for a 62% discount!
     
  18. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Ah, I forgot to mention the changelog. Here it is! There are likely a number of smaller fixes / polish items missing.

    This release also includes a number of internal changes that will be used in the next release - for example, in the next version it will be easy to use FI as a DLL (which will greatly reduce compile times for a base installation of just FI).

    For v2.5

    ** Important **
    - Only auto-properties are displayed and serialized by default now

    New:
    - Added fiValue{T}, which allows perfect Full Inspector integration into any project *without* deriving from BaseBehavior.
    - Added serializer migration utility which assists with changing serialization data between serializers.
    - Animation support can now be toggled in fiSettings (with EnableAnimation).
    - Full Inspector now tracks versions and will prompt you to do a clean import from 2.4.
    - Added an "About Window" with quick links to some common Full Inspector utilities.
    - Added [InspectorShowIf], which allows for conditional field/property/button display in the inspector.
    - Added [InspectorDropdownName], which allows you to customize the name a type appears as in the abstract type dropdown selector.
    - Added [InspectorCollectionRotorzFlags], which allows complete customization of the flags that are sent to Rotorz for list editing.
    - Added [InspectorNotDefaultConstructed], which prevents default construction of the given field/property.
    - Support treating methods with all default parameters as no parameter methods.
    - Collections are now paged when they have more than a certain number of elements. This can be customized with the [InspectorCollectionPager] attribute.
    - You can now easily customize settings by writing a class that extends from `fiSettingsProcessor`.

    Changes:
    - Default label width now matches Unity.
    - Edit/GetHeight are now statically exposed on DefaultBehaviorEditor.
    - Reset is no longer automatically invoked when adding a behavior to an object.
    - Add support for runtime types in SerializationHelpers.
    - Full Inspector generated code will now be placed in a directory named `fiSettings.RootDirectory + "_Generated"`.
    - [Limits] has been promoted to the core namespace as [InspectorRange]
    - SharedInstance can now take an extra generic argument for the serializer to use.
    - [InspectorDatabaseEditor] now works with arrays.
    - Exceptions are now logged using Debug.LogException, which makes it much easier to navigate to the exception source.
    - Added exception logging for BehaviorEditor and PropertyEditor constructors.
    - Removed all default parameters so that MonoDevelop correctly builds Full Inspector
    - Made serializer detection significantly more robust
    - You no longer need to mark modified objects with SetDirty; they will be automatically serialized (assuming they were initially serialized).
    - The static inspector can now be opened with `Alt-I`.

    Fixes:
    - Fixed internal exception when a property accessor with a struct return type threw an exception.
    - Correctly set GUI.changed when creating new object instances.
    - Fixed return type for OnWillDeleteAsset callback.
    - Fixed a Unity deserialization race when entering play mode in the editor.
    - Fixed Rotorz rendering when Unity is in a Linear colorspace
    - Fixed serialization on BaseBehavior for unsigned types and signed shorts.
    - Fixed saving in Unity 4.6.1+ versions.
    - Fixed metadata leak causing an excessive number of metadata objects to exist in a long-running scene (though they are cleaned up after entering/exiting Unity)
    - Fixed fiRuntimeReflectionUtility.GetRuntimeAssemblies() in WebPlayer
     
  19. Saxi

    Saxi

    Joined:
    Jun 28, 2013
    Posts:
    381
    On your site it says Protobuf is alpha/beta, is that still the case?

    I own the json.net asset, is that faster than using the built in one to FullInspector?

    If you use FullInspector, does that replace all of Unity's serialization? Or does Unity still serialize things internally for different parts of the project?

    How much reflection is in the asset? I am very concerned about performance as I primarily target mobile, and try to keep as optimal as possible.
     
  20. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    protobuf-net is alpha/beta and will probably always be so simply because of the way the AOT works: it involves running a decompiler on the assembly so that it can be correctly used inside of Unity's build process.

    Full Serializer is likely slower than Json.NET (I haven't done benchmarks though - I don't know) but Full Serializer "just works", whereas Json.NET has issues with a number of different things like Dictionaries with keys that are not primitive types. Unity's serializer is used when possible but it usually is not applicable.

    Core FI doesn't use too much reflection (one set per member variable per instance) but the serializer may use quite a bit more. The only perf impact is going to be on Awake() in the runtime - after that FI has no impact.
     
  21. Korindian

    Korindian

    Joined:
    Jun 25, 2013
    Posts:
    584
    Hi sient,

    I'm a somewhat novice programmer, and have been eyeing FI2 for a long time, especially for having properties, dictionaries, statics, and interfaces viewable/editable in the inspector. Everytime I'm about to pull the trigger, I hesitate because I don't want to have all my scripts dependent on an asset in case support drops with a later Unity release. However, I took a test drive with your 2.5 trial and really like what I see, so I've already added it to my Asset Store cart and will be buying very soon. I just hope you will always continue your great support as much as you're able.

    Some questions/observations:

    1) Aren't structs already serialized by Unity since one of the latest releases?

    2) If I just use FullSerializer, set it as default and remove the other serializers, I can just derive from BaseBehavior and don't need to type out BaseBehavior<FullSerializerSerializer>, correct?

    3) According to your docs, if I use Awake(), I must do:
    Code (CSharp):
    1. protected override void Awake()
    2. {
    3.     base.Awake();
    4. }
    wherever I use Awake(), correct?

    4) In your FullSerializer examples, if I attach the script "SampleFullSerializerUnityTypes" to a GameObject, I get a bunch of NullReferenceExceptions in the console. I'm using Unity 5 beta 18.

    5) I'm not seeing an fiSettings.cs as mentioned in the guide. Has it been removed for 2.5?

    6) I think I would have preferred automatic serialization of properties with implemented getter and setter logic without having to write [SerializeField] each time, but I understand you changed it due to user feedback.

    Great work, and looking forward to 2.5's approval!
     
  22. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    1) Yep - structs are now natively supported by Unity. The images/etc are out of date and I can't seem to find a way to change the forum title. I'll likely investigate that again sometime soon.

    2) Yep - that will do the trick. Full Serializer will also work across everything and it is what I use myself.

    3) Correct. Hopefully I'll be able to get that removed at some point in the future if you're using Full Serializer (not possible with other serializers as they do not handle running off the main thread properly -- ie, you cannot use == against two UnityEngine.Object references; you have to make sure to use ReferenceEquals, etc)

    4) Strange, I'll take a look at that in the next day or so. Can you post the error message?

    5) Yep, settings has changed in 2.5 so that settings can be saved across FI upgrades. There will be some more documentation on how to customize settings in the upcoming docs but feel free to post again if you want a description now.

    6) Sorry about that! Only auto-properties is the less surprising behavior and significantly reduces the chance of running into issue #96.

    Let me know if you have any other questions.

    Thanks!
     
  23. Saxi

    Saxi

    Joined:
    Jun 28, 2013
    Posts:
    381
    What is the difference than the JSON.NET included with Full Serializer, and JSON.NET from the Asset Store?

    I'm trying to test serializing a game object with Full Serializer, what am I doing wrong?

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using FullInspector;
    4. using FullSerializer;
    5.  
    6. public class SerializeMe : BaseBehavior {
    7.  
    8.     private static fsSerializer _serializer = new fsSerializer();
    9.  
    10.     // Use this for initialization
    11.     void Start () {
    12.         fsData data;
    13.  
    14.         _serializer.TrySerialize(typeof(GameObject), gameObject, out data);
    15.  
    16.         Debug.Log(fsJsonPrinter.CompressedJson(data));
    17.    
    18.     }
    19.    
    20.     // Update is called once per frame
    21.     void Update () {
    22.    
    23.     }
    24. }
    25.  
    26.  
     
  24. Korindian

    Korindian

    Joined:
    Jun 25, 2013
    Posts:
    584
    Hi Sient,

    Here are the 2 error messages. The first is a warning, the second is an error, and they keep slowly filling up the console when I add the script "SampleFullSerializerUnityTypes" to an empty GameObject.

    Can't add script behaviour . The script needs to derive from MonoBehaviour!
    UnityEngine.GameObject:AddComponent()
    FullInspector.Modules.GenericPropertyDrawerPropertyEditor`2:GetContainer(fiGraphMetadata)
    FullInspector.Modules.GenericPropertyDrawerPropertyEditor`2:GetElementHeight(GUIContent, T, fiGraphMetadata)
    FullInspector.PropertyEditor`1:FullInspector.IPropertyEditorEditAPI.GetElementHeight(GUIContent, Object, fiGraphMetadata)
    FullInspector.PropertyEditorExtensions:GetElementHeight(IPropertyEditor, GUIContent, Object, fiGraphMetadataChild)
    FullInspector.Internal.fiEditorGUI:EditPropertyHeightDirect(InspectedProperty, Object, fiGraphMetadataChild)
    FullInspector.Internal.fiEditorGUI:EditPropertyHeight(Object, InspectedProperty, fiGraphMetadataChild)
    FullInspector.Internal.ReflectedPropertyEditor:GetElementHeight(GUIContent, Object, fiGraphMetadata)
    FullInspector.PropertyEditorExtensions:GetElementHeight(IPropertyEditor, GUIContent, Object, fiGraphMetadataChild)
    FullInspector.Internal.fiEditorGUI:EditPropertyHeightDirect(InspectedProperty, Object, fiGraphMetadataChild)
    FullInspector.Internal.fiEditorGUI:EditPropertyHeight(Object, InspectedProperty, fiGraphMetadataChild)
    FullInspector.Internal.ReflectedPropertyEditor:GetElementHeight(GUIContent, Object, fiGraphMetadata)
    FullInspector.PropertyEditorExtensions:GetElementHeight(IPropertyEditor, GUIContent, Object, fiGraphMetadataChild)
    FullInspector.DefaultBehaviorEditor:OnGetHeight(Object, fiGraphMetadata)
    FullInspector.BehaviorEditor`1:GetHeight(Object)
    FullInspector.IBehaviorEditorExtensions:EditWithGUILayout(IBehaviorEditor, Object)
    FullInspector.FullInspectorCommonSerializedObjectEditor:ShowInspectorForSerializedObject(Object)
    FullInspector.FullInspectorCommonSerializedObjectEditor:OnInspectorGUI()
    UnityEditor.DockArea:OnGUI()

    NullReferenceException: (null)
    UnityEditor.SerializedObject..ctor (UnityEngine.Object obj) (at C:/buildslave/unity/build/artifacts/generated/common/editor/SerializedPropertyBindings.gen.cs:66)
    FullInspector.Modules.GenericPropertyDrawerPropertyEditor`2[TContainer,T].GetContainer (FullInspector.fiGraphMetadata metadata)
    FullInspector.Modules.GenericPropertyDrawerPropertyEditor`2[TContainer,T].GetElementHeight (UnityEngine.GUIContent label, .T element, FullInspector.fiGraphMetadata metadata)
    FullInspector.PropertyEditor`1[TElement].FullInspector.IPropertyEditorEditAPI.GetElementHeight (UnityEngine.GUIContent label, System.Object element, FullInspector.fiGraphMetadata metadata)
    FullInspector.PropertyEditorExtensions.GetElementHeight[Object] (IPropertyEditor editor, UnityEngine.GUIContent label, System.Object element, fiGraphMetadataChild metadata)
    FullInspector.Internal.fiEditorGUI.EditPropertyHeightDirect (FullInspector.InspectedProperty property, System.Object propertyValue, fiGraphMetadataChild metadataChild)
    FullInspector.Internal.fiEditorGUI.EditPropertyHeight (System.Object container, FullInspector.InspectedProperty property, fiGraphMetadataChild metadata)
    FullInspector.Internal.ReflectedPropertyEditor.GetElementHeight (UnityEngine.GUIContent label, System.Object element, FullInspector.fiGraphMetadata metadata)
    FullInspector.PropertyEditorExtensions.GetElementHeight[Object] (IPropertyEditor editor, UnityEngine.GUIContent label, System.Object element, fiGraphMetadataChild metadata)
    FullInspector.Internal.fiEditorGUI.EditPropertyHeightDirect (FullInspector.InspectedProperty property, System.Object propertyValue, fiGraphMetadataChild metadataChild)
    FullInspector.Internal.fiEditorGUI.EditPropertyHeight (System.Object container, FullInspector.InspectedProperty property, fiGraphMetadataChild metadata)
    FullInspector.Internal.ReflectedPropertyEditor.GetElementHeight (UnityEngine.GUIContent label, System.Object element, FullInspector.fiGraphMetadata metadata)
    FullInspector.PropertyEditorExtensions.GetElementHeight[Object] (IPropertyEditor editor, UnityEngine.GUIContent label, UnityEngine.Object element, fiGraphMetadataChild metadata)
    FullInspector.DefaultBehaviorEditor.OnGetHeight (UnityEngine.Object behavior, FullInspector.fiGraphMetadata metadata)
    FullInspector.BehaviorEditor`1[TBehavior].GetHeight (UnityEngine.Object behavior)
    FullInspector.IBehaviorEditorExtensions.EditWithGUILayout[Object] (IBehaviorEditor editor, UnityEngine.Object element)
    FullInspector.FullInspectorCommonSerializedObjectEditor.ShowInspectorForSerializedObject (UnityEngine.Object target)
    FullInspector.FullInspectorCommonSerializedObjectEditor.OnInspectorGUI ()
    UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor editor, Int32 editorIndex, Boolean forceDirty, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect, Boolean eyeDropperDirty) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1132)
    UnityEditor.DockArea:OnGUI()

    As far as settings are concerned, I just wanted access to the metadata one which remembers whether items are folded or unfolded in the inspector.

    Bought FI2 earlier, but am using the 2.5 trial until the Asset Store approves 2.5. Thanks for the fast response!
     
  25. combatdave1

    combatdave1

    Joined:
    Dec 17, 2014
    Posts:
    11
    Hey,

    I have worked around the problem by removing my instanced NodeVisual class and just using static drawing methods which operate on whatever is in my Node list. I can still send the project over if you'd like?
     
  26. combatdave1

    combatdave1

    Joined:
    Dec 17, 2014
    Posts:
    11
    I'm currently trying to do exactly this. Is there some full example code for how to make this work from an EditorWindow without having a SerializedObject or SerializedProperty?

    Edit: Worked it out. Here's how to do it:

    Code (csharp):
    1.  
    2.                 var md = fiGraphMetadata.GetGlobal(window.EditingSequence); // window.EditingSequence is my BaseScriptableObject
    3.                 PropertyEditor.Get(typeof(SimpleSpeechEffect), null).FirstEditor.EditWithGUILayout(new GUIContent("Effect"), node.effect as SimpleSpeechEffect, md.Enter("something"));
    4.                // node.effect is what I want to edit, it's type is SimpleSpeechEffect. Not sure what I am supposed to put in "md.Enter" though...
    5.  
    If there's some place where I can provide good documentation as I'm working through these things, it would be good to know.
     
    Last edited: Jan 8, 2015
  27. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    The Json.NET version included with Full Inspector does not support AOT builds; it's pretty much the vanilla source code just with references to non-Unity things stripped - Json.NET for Unity (from the asset store) has been extensively customized so that it can support AOT builds and various platforms.

    For your example code, Full Serializer doesn't really support straight-up serialization of GameObjects. It's pretty tricky; as a result, Full Inspector (for every serializer) delegates all UnityEngine.Object serialization to Unity (for various reasons like prefab support etc).
     
  28. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    It looks like the error messages are caused because FI is deployed as a DLL. I'll have to try and find a fix for that (DLL deploy is a feature I'd like to introduce in 2.6, but there are a few gotchas like this one that need to be fixed first).

    2.5 is now live in the asset store so you can start using that version instead of the trial - this will fix the errors you are seeing with the sample.

    Regarding settings, please see this help document.
     
  29. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I'm still working on updating the docs for PropertyEditor / BehaviorEditor / a few other things, but you can hit "Suggest an Edit" to correct / contribute an item to the docs if you'd like (see this page for an example with the suggest an edit button).

    You may want to consider using BehaviorEditor.Get instead of PropertyEditor.Get for BaseScriptableObject derived types.

    For md.Enter, you should put something that will remain constant for the given edit tree - I typically go with either the property name (so "effect" for the property node.effect) or the index of the item if it is in a collection.

    If you'd like more comprehensive help, feel free to send me some sample code that I can take a look at.
     
  30. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    As a heads up everyone, 2.5 is now live! Make sure to update!
     
  31. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Is there a way to use fiValue or something else to get a property (not field) to show up in a MonoBehaviour without deriving from BaseBehavior?

    Also, when using PropertyEditor.Get, can I pass a custom attribute in along with the type? I'm guessing that's what the ICustomAttributeProvider argument is for, but I'm not sure how to convert an attribute into that.
     
    Last edited: Jan 9, 2015
  32. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    Ok. Got 2.5 from asset store.
    And here is one thing.
    It seems that Paging Collection Editor hides last element.

    Edit:
    Fixed that quickly.
    In BaseCollectionPropertyEditor.cs adjusted these lines
    line 380
    Code (CSharp):
    1. GUI.Label(rect_OfCountLabel, " of " + (collection.Count));
    line 392
    Code (CSharp):
    1. EditorGUI.BeginDisabledGroup(!(pageMetadata.PageEndIndex < collection.Count));
    line 416
    Code (CSharp):
    1. if (delta > (collectionCount - pageMetadata.PageEndIndex))
    2.                 delta = collectionCount - pageMetadata.PageEndIndex;
    line 425
    Code (CSharp):
    1.  
    2. //warning here value can hit out of range.
    3. if (value > max) value = max;
    Tested. No errors. Collections displayed as expected.
    Even with zero elements
     
    Last edited: Jan 9, 2015
  33. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    In PageAdaptor.cs
    line 17
    Code (CSharp):
    1. public int Count {
    2.             get {
    3.                 return _endIndex - _startIndex;
    4.             }
    5.         }
    I dont understand. If we have one element in collection so _startIndex and _endIndex point to the same value Count will return zero. And here Count will always return -1 of actual collection length.
     
  34. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    Here is my quick code for Swap fuctionality in InspectorDatabaseEditor

    In InspectorDatabaseEditorAttribute.cs modify these lines
    line 37
    Code (CSharp):
    1. new fiHorizontalLayout(new fiLayoutHeight(18)) {
    2.                         2,
    3.                         {"SwapBack", 60},
    4.                         2,
    5.                         "Back",
    6.                         2,
    7.                         "Forward",
    8.                         2,
    9.                         {"SwapForward", 60},
    10.                         2,
    11.                         { "Delete", 25 }
    12.                     }
    Add two functions, it will handle button pressed events
    Code (CSharp):
    1.  
    2. //add these functions somewhere. I added after ChangeEditedElement
    3.         private static void SwapForward(ref IList<T> list)
    4.         {
    5.             var metadata = fiGlobalMetadata.Get<InspectorDatabaseEditorMetadata>(list);
    6.             int index = metadata.CurrentIndex;
    7.             if (index < list.Count - 1) {
    8.                 var temp = list[index];
    9.                 list[index] = list[index + 1];
    10.                 list[index + 1] = temp;
    11.             }
    12.         }
    13.         private static void SwapBack(ref IList<T> list)
    14.         {
    15.             var metadata = fiGlobalMetadata.Get<InspectorDatabaseEditorMetadata>(list);
    16.             int index = metadata.CurrentIndex;
    17.             if (index > 0) {
    18.                 var temp = list[index];
    19.                 list[index] = list[index - 1];
    20.                 list[index - 1] = temp;
    21.             }
    22.         }
    Modify DrawHeader
    Code (CSharp):
    1. private Rect DrawHeader(Rect region, GUIContent label, ref IList<T> list)
    2.         {
    3.             var labelRect = Header.GetSectionRect("Label", region);
    4.             var backRect = Header.GetSectionRect("Back", region);
    5.             var forwardRect = Header.GetSectionRect("Forward", region);
    6.             var delRect = Header.GetSectionRect("Delete", region);
    7.             var boxedRect = Header.GetSectionRect("BoxedArea", region);
    8.             var swapBackRect = Header.GetSectionRect("SwapBack", region);
    9.             var swapForwardRect = Header.GetSectionRect("SwapForward", region);
    10.             region = RectTools.MoveDown(region, Header.Height);
    11.  
    12.             GUI.Box(boxedRect, GUIContent.none);
    13.  
    14.             label = AddEditingInformation(label, list);
    15.             if (list.Count == 0) {
    16.                 EditorGUI.LabelField(labelRect, label);
    17.             } else {
    18.                 SetIndex(list, EditorGUI.IntSlider(labelRect, label, CurrentIndex(list), 0,
    19.                     list.Count - 1));
    20.             }
    21.  
    22.             GUI.color = new Color(150, 0, 0);
    23.             EditorGUI.BeginDisabledGroup(!CanDelete(list));
    24.             if (GUI.Button(delRect, "X")) {
    25.                 RemoveEditedElement(ref list);
    26.             }
    27.             EditorGUI.EndDisabledGroup();
    28.             GUI.color = Color.white;
    29.  
    30.             EditorGUI.BeginDisabledGroup(!CanGoBack(list));
    31.             //added code here
    32.             if (GUI.Button(swapBackRect, "<Swap")) {
    33.                 SwapBack(ref list);
    34.             }
    35.             if (GUI.Button(backRect, "<<")) {
    36.                 ChangeEditedElement(ref list, -1);
    37.             }
    38.             EditorGUI.EndDisabledGroup();
    39.  
    40.             //added code here
    41.             bool nextAdd = GetNextButtonOperation(list) == NextButtonOperation.Add;
    42.             EditorGUI.BeginDisabledGroup(nextAdd);
    43.             if (GUI.Button(swapForwardRect, "Swap>")) {
    44.                 SwapForward(ref list);
    45.             }
    46.             EditorGUI.EndDisabledGroup();
    47.  
    48.             string nextLabel = ">>";
    49.             //modified here
    50.             if (nextAdd) {
    51.                 GUI.color = Color.green;
    52.                 nextLabel = "Add";
    53.             }
    54.             if (GUI.Button(forwardRect, nextLabel)) {
    55.                 ChangeEditedElement(ref list, 1);
    56.             }
    57.             GUI.color = Color.white;
    58.  
    59.             return region;
    60.         }
    This code is not that pretty.
    Tested. Works for me.
    By the way InspectorDatabase is great.
     
  35. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Sorry, not really. fiValue<T> is designed to serialize using Unity's serialization system (plus callbacks inside of the fiValue itself) so the MonoBehavior cannot be touched - which means no properties for values stored outside of fiValue (but the T type value can store properties which will be serialized/inspected as you expect by Full Inspector).

    For PropertyEditor.Get, the ICustomAttributeProvider is typically a MemberInfo instance (such as FieldInfo, PropertyInfo, etc) that contains a set of attributes. If you're inspecting a FieldInfo instance, then the call would look something like this:

    Code (csharp):
    1. PropertyEditor.Get(fieldInfo.FieldType, fieldInfo)
     
  36. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Thanks! I'll look into seeing if these fixes are needed with the change discussed below.

    Ah, I think you're correct here. I've changed it so that count returns _endIndex - _startIndex + 1. This alone fixes the last item not being viewable. I'll also have to allow for the _startIndex to equal the _endIndex.


    I'll look into getting this integrated. Thanks! It's a nice addition. Have you also considered using [InspectorCollectionPager(AlwaysShow=True)]?
     
  37. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    Already using it quite often. It makes collection something between DatabaseEditor and standard View.
    Very useful.
    By the way. As you can see on screenshot, I added panel on Database element content.(one GUI.Box, nothing special)
    This helps to distinguish Database element content from other inspector fields that come right after collection.
    Without it Element visually merges with other fields so I cannot find where it ends

    FI is so versatile
    In my current project Im using great collection support and serialization
    I still had no chance to look at new features like Facade, SharedInstance, fiValue.
     
    Last edited: Jan 9, 2015
  38. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Ah, good idea with the box. I've implemented it with a small 3 pixel margin around the actual body content as well.

    I'm happy to hear that you're happy with FI :)
     
  39. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    Great. Waiting for official patch. Thanks you.
     
  40. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    Another tiny mod I want to share
    InspectorRange is quite handy but at glance you cannot tell what is what


    It can be modified, so it will look as Unity version of Range


    InspectorRangeAttributeEditor.cs
    Code (CSharp):
    1.  
    2. //line 06:  Change ReplaceOthers to true
    3. [CustomAttributePropertyEditor(typeof(InspectorRangeAttribute), ReplaceOthers = true)]
    4.  
    5. //line 12: Replace GUI.HorizontalSlider with EditorGUI.Slider
    6. protected override TElement Edit(Rect region, GUIContent label, TElement element, InspectorRangeAttribute attribute, fiGraphMetadata metadata)
    7.     {
    8.         return Cast<TElement>(EditorGUI.Slider(region, label, Cast<float>(element), attribute.Min, attribute.Max));
    9.     }
    10.  
     
  41. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    Also you can make Range to have stepped behavior
    For example you can make value increase by 5 while dragging slider

    Create Attribute
    Code (CSharp):
    1. public class InspectorStepRangeAttribute : System.Attribute
    2. {
    3.     public float Min;
    4.     public float Max;
    5.     public float Step = 1f;
    6.  
    7.     public InspectorStepRangeAttribute(float min, float max, float step)
    8.     {
    9.         Min = min;
    10.         Max = max;
    11.         Step = step;
    12.         //your own limit value. This prevents division by zero
    13.         if (Step < 0.01) Step = 0.01f;
    14.     }
    15. }
    Clone InspectorRangeAttributeEditor as InspectorStepRangeAttributeEditor
    Change every InspectorRangeAttribute to InspectorStepRangeAttribute
    Change one line in Edit
    Code (CSharp):
    1.  
    2. protected override TElement Edit(Rect region, GUIContent label, TElement element, InspectorStepRangeAttribute attribute, fiGraphMetadata metadata)
    3. {
    4.         return Cast<TElement>((int)(EditorGUI.Slider(region, label, Cast<float>(element), attribute.Min, attribute.Max) / attribute.Step) * attribute.Step);
    5. }
    6.  
    Works for me
     
    Last edited: Jan 11, 2015
  42. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Thanks! I like this change. I've integrated them into the next release and have also unified the stepping into the original editor.

    Here is the new InspectorRangeAttribute:

    Code (csharp):
    1. using System;
    2.  
    3. namespace FullInspector {
    4.     [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    5.     public sealed class InspectorRangeAttribute : Attribute {
    6.         /// <summary>
    7.         /// The minimum value.
    8.         /// </summary>
    9.         public float Min;
    10.  
    11.         /// <summary>
    12.         /// The maximum value.
    13.         /// </summary>
    14.         public float Max;
    15.  
    16.         /// <summary>
    17.         /// The step to use. This is optional.
    18.         /// </summary>
    19.         public float Step = float.NaN;
    20.  
    21.         public InspectorRangeAttribute(float min, float max) {
    22.             Min = min;
    23.             Max = max;
    24.         }
    25.     }
    26. }
    and here is the InspectorRangeAttributeEditor

    Code (csharp):
    1. using System;
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. namespace FullInspector.Modules.InspectorRange {
    6.     [CustomAttributePropertyEditor(typeof(InspectorRangeAttribute), ReplaceOthers = true)]
    7.     public class InspectorRangeAttributeEditor<TElement> : AttributePropertyEditor<TElement, InspectorRangeAttribute> {
    8.         private static T Cast<T>(object o) {
    9.             return (T)Convert.ChangeType(o, typeof(T));
    10.         }
    11.  
    12.         protected override TElement Edit(Rect region, GUIContent label, TElement element, InspectorRangeAttribute attribute, fiGraphMetadata metadata) {
    13.             if (float.IsNaN(attribute.Step) == false) {
    14.                 if (attribute.Step <= 0) {
    15.                     Debug.LogWarning(attribute.Step + " is not a valid step. It must be greater than 0.");
    16.                     attribute.Step = float.NaN;
    17.                 }
    18.             }
    19.  
    20.             if (float.IsNaN(attribute.Step) == false) {
    21.                 return Cast<TElement>((int)(EditorGUI.Slider(region, label, Cast<float>(element), attribute.Min, attribute.Max) / attribute.Step) * attribute.Step);
    22.             }
    23.  
    24.             return Cast<TElement>(EditorGUI.Slider(region, label, Cast<float>(element), attribute.Min, attribute.Max));
    25.         }
    26.  
    27.         protected override float GetElementHeight(GUIContent label, TElement element, InspectorRangeAttribute attribute, fiGraphMetadata metadata) {
    28.             return EditorStyles.label.CalcHeight(label, 100);
    29.         }
    30.  
    31.         public override bool CanEdit(Type type) {
    32.             return type == typeof(int) || type == typeof(double) || type == typeof(float) || type == typeof(decimal);
    33.         }
    34.     }
    35. }
    Here is example usage:

    Code (csharp):
    1.  
    2. [InspectorRange(0, 10)]
    3. public float a;
    4.  
    5. [InspectorRange(0, 10, Step = .5f)]
    6. public float b;
    7.  
    upload_2015-1-11_13-36-54.png
     
  43. psxcode

    psxcode

    Joined:
    Jan 26, 2014
    Posts:
    26
    Great! Waiting for patch release
     
  44. NoradZero

    NoradZero

    Joined:
    Apr 24, 2014
    Posts:
    95
    Yeah, i will be waiting for the official patch release aswell. I have couple of problems with the upgrade. I am starting from 2.4. Is there anything special to know when you upgrade ?
     
  45. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    What issues are you having? I've written a few upgrade notes here.

    I've added a number of things to 2.5 that should make future upgrades easier (like separating out all generated files into FullInspector2_Generated, enabling settings customization w/o touching fiSettings.cs, etc)
     
  46. NoradZero

    NoradZero

    Joined:
    Apr 24, 2014
    Posts:
    95
    Well, was getting errors with unity saying it can't get properties and my objects was somehow broken.. But i overwritten with my backup after so i can't remember. I will look at your upgrade notes first and try to update it and get back there if there any problems. Thanks!
     
  47. NoradZero

    NoradZero

    Joined:
    Apr 24, 2014
    Posts:
    95
    Im getting this error. Also upgrading seem to somehow broke 2d toolkit sprite mesh filter on my prefabs.

    ArgumentException: failed to convert parameters
    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:192)
    System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Reflection/MethodBase.cs:115)
    FullInspector.InspectedProperty.Write (System.Object context, System.Object value) (at Assets/FullInspector2/Core/Utility/InspectedProperty.cs:150)
    UnityEngine.Debug:LogException(Exception)
    FullInspector.InspectedProperty:Write(Object, Object) (at Assets/FullInspector2/Core/Utility/InspectedProperty.cs:158)
    FullInspector.Internal.BehaviorSerializationHelpers:RestoreState(ISerializedObject) (at Assets/FullInspector2/Core/BehaviorSerializationHelpers.cs:190)
    FullInspector.BaseBehavior`1:RestoreState() (at Assets/FullInspector2/Core/BaseBehavior.cs:55)
    FullInspector.BehaviorEditor`1:CheckForPrefabChanges(Object) (at Assets/FullInspector2/Core/Editor/IBehaviorEditor.cs:141)
    FullInspector.BehaviorEditor`1:GetHeight(Object) (at Assets/FullInspector2/Core/Editor/IBehaviorEditor.cs:87)
    FullInspector.IBehaviorEditorExtensions:EditWithGUILayout(IBehaviorEditor, Object) (at Assets/FullInspector2/Core/Editor/IBehaviorEditorExtensions.cs:19)
    FullInspector.FullInspectorCommonSerializedObjectEditor:ShowInspectorForSerializedObject(Object) (at Assets/FullInspector2/Core/Editor/FullInspectorCommonSerializedObjectEditor.cs:152)
    FullInspector.FullInspectorCommonSerializedObjectEditor:OnInspectorGUI() (at Assets/FullInspector2/Core/Editor/FullInspectorCommonSerializedObjectEditor.cs:172)
    UnityEditor.DockArea:OnGUI()
     
  48. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Are you able to send me a build so I can repro the issue? The stack trace doesn't give me enough information to debug it. Are you able to continue the import process or does this completely stop it? Did you delete the FullInspector2 folder before importing?
     
  49. combatdave1

    combatdave1

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

    Can FullInspector serialize weakreferences correctly?

    Thanks
     
  50. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I've added an issue here. I fully anticipate this being supported in 2.6.

    WeakReference is probably going to have bad serializer support just because it's a more esoteric type - Full Serializer will support it, however.