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. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Huh, okay. I don't think changing BaseBehavior to/from a regular class would change anything, but maybe it corrupted some data. I'm currently downloading 5.1.1f1 and will test it out.
     
  2. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @sient ,

    Many thanks. I've gone for the full product anyway as so many other uses but will now read in to the above and give this all some more thought. Thanks for coming back with such a comprehensive response.
     
  3. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @sient,

    I am using the following code I found on Unity forums and re-jigging it to FI:-

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [System.Serializable]
    4. public class Weapon
    5. {
    6.     [SerializeField]
    7.     public string weaponName;
    8.     [SerializeField]
    9.     public int damage;
    10.  
    11.     public Weapon (string name, int dmg)
    12.     {
    13.         weaponName = name;
    14.         damage = dmg;
    15.     }
    16. }
    17. ------------------------------------------------------------------------------
    18. using UnityEngine;
    19. using UnityEditor;
    20. using System.Collections;
    21. using System;
    22.  
    23. public class WeaponDatabaseEditor : EditorWindow
    24. {
    25.     private enum State
    26.     {
    27.         BLANK,
    28.         EDIT,
    29.         ADD
    30.     }
    31.    
    32.     private State state;
    33.     private int selectedWeapon;
    34.     private string newWeaponName;
    35.     private int newWeaponDamage;
    36.    
    37.     private const string DATABASE_PATH = @"Assets/Database/weaponDB.asset";
    38.    
    39.     private WeaponDatabase weapons;
    40.     private Vector2 _scrollPos;
    41.    
    42.     [MenuItem("BZA/Database/Weapon Database %#w")]
    43.     public static void Init ()
    44.     {
    45.         WeaponDatabaseEditor window = EditorWindow.GetWindow<WeaponDatabaseEditor> ();
    46.         window.minSize = new Vector2 (800, 400);
    47.         window.Show ();
    48.     }
    49.    
    50.     void OnEnable ()
    51.     {
    52.         if (weapons == null)
    53.             LoadDatabase ();
    54.        
    55.         state = State.BLANK;
    56.     }
    57.    
    58.     void OnGUI ()
    59.     {
    60.         EditorGUILayout.BeginHorizontal (GUILayout.ExpandWidth (true));
    61.         DisplayListArea ();
    62.         DisplayMainArea ();
    63.         EditorGUILayout.EndHorizontal ();
    64.     }
    65.    
    66.     void LoadDatabase ()
    67.     {
    68.         weapons = (WeaponDatabase)AssetDatabase.LoadAssetAtPath (DATABASE_PATH, typeof(WeaponDatabase));
    69.        
    70.         if (weapons == null)
    71.             CreateDatabase ();
    72.     }
    73.    
    74.     void CreateDatabase ()
    75.     {
    76.         weapons = ScriptableObject.CreateInstance<WeaponDatabase> ();
    77.         AssetDatabase.CreateAsset (weapons, DATABASE_PATH);
    78.         AssetDatabase.SaveAssets ();
    79.         AssetDatabase.Refresh ();
    80.     }
    81.    
    82.     void DisplayListArea ()
    83.     {
    84.         EditorGUILayout.BeginVertical (GUILayout.Width (250));
    85.         EditorGUILayout.Space ();
    86.        
    87.         _scrollPos = EditorGUILayout.BeginScrollView (_scrollPos, "box", GUILayout.ExpandHeight (true));
    88.        
    89.         for (int cnt = 0; cnt < weapons.COUNT; cnt++) {
    90.             EditorGUILayout.BeginHorizontal ();
    91.             if (GUILayout.Button ("-", GUILayout.Width (25))) {
    92.                 weapons.RemoveAt (cnt);
    93.                 weapons.SortAlphabeticallyAtoZ ();
    94.                 EditorUtility.SetDirty (weapons);
    95.                 state = State.BLANK;
    96.                 return;
    97.             }
    98.            
    99.             if (GUILayout.Button (weapons.Weapon (cnt).weaponName, "box", GUILayout.ExpandWidth (true))) {
    100.                 selectedWeapon = cnt;
    101.                 state = State.EDIT;
    102.             }
    103.            
    104.             EditorGUILayout.EndHorizontal ();
    105.         }
    106.        
    107.         EditorGUILayout.EndScrollView ();
    108.        
    109.         EditorGUILayout.BeginHorizontal (GUILayout.ExpandWidth (true));
    110.         EditorGUILayout.LabelField ("Weapons: " + weapons.COUNT, GUILayout.Width (100));
    111.        
    112.         if (GUILayout.Button ("New Weapon"))
    113.             state = State.ADD;
    114.        
    115.         EditorGUILayout.EndHorizontal ();
    116.         EditorGUILayout.Space ();
    117.         EditorGUILayout.EndVertical ();
    118.     }
    119.    
    120.     void DisplayMainArea ()
    121.     {
    122.         EditorGUILayout.BeginVertical (GUILayout.ExpandWidth (true));
    123.         EditorGUILayout.Space ();
    124.        
    125.         switch (state) {
    126.         case State.ADD:
    127.             DisplayAddMainArea ();
    128.             break;
    129.         case State.EDIT:
    130.             DisplayEditMainArea ();
    131.             break;
    132.         default:
    133.             DisplayBlankMainArea ();
    134.             break;
    135.         }
    136.        
    137.         EditorGUILayout.Space ();
    138.         EditorGUILayout.EndVertical ();
    139.     }
    140.    
    141.     void DisplayBlankMainArea ()
    142.     {
    143.         EditorGUILayout.LabelField (
    144.             "There are 3 things that can be displayed here.\n" +
    145.             "1) Weapon info for editing\n" +
    146.             "2) Black fields for adding a new weapon\n" +
    147.             "3) Blank Area",
    148.             GUILayout.ExpandHeight (true));
    149.     }
    150.    
    151.     void DisplayEditMainArea ()
    152.     {
    153.         weapons.Weapon (selectedWeapon).weaponName = EditorGUILayout.TextField (new GUIContent ("Name: "), weapons.Weapon (selectedWeapon).weaponName);
    154.         weapons.Weapon (selectedWeapon).damage = int.Parse (EditorGUILayout.TextField (new GUIContent ("Damage: "), weapons.Weapon (selectedWeapon).damage.ToString ()));
    155.        
    156.         EditorGUILayout.Space ();
    157.        
    158.         if (GUILayout.Button ("Done", GUILayout.Width (100))) {
    159.             weapons.SortAlphabeticallyAtoZ ();
    160.             EditorUtility.SetDirty (weapons);
    161.             state = State.BLANK;
    162.         }
    163.     }
    164.    
    165.     void DisplayAddMainArea ()
    166.     {
    167.         newWeaponName = EditorGUILayout.TextField (new GUIContent ("Name: "), newWeaponName);
    168.         newWeaponDamage = Convert.ToInt32 (EditorGUILayout.TextField (new GUIContent ("Damage: "), newWeaponDamage.ToString ()));
    169.        
    170.         EditorGUILayout.Space ();
    171.        
    172.         if (GUILayout.Button ("Done", GUILayout.Width (100))) {
    173.             weapons.Add (new Weapon (newWeaponName, newWeaponDamage));
    174.             weapons.SortAlphabeticallyAtoZ ();
    175.            
    176.             newWeaponName = string.Empty;
    177.             newWeaponDamage = 0;
    178.             EditorUtility.SetDirty (weapons);
    179.             state = State.BLANK;
    180.         }
    181.     }
    182. }
    183. -----------------------------------------------------------------------------------------------------
    184.  
    185. using UnityEngine;
    186. using System.Collections;
    187. using System.Collections.Generic;
    188. using System.Linq;
    189.  
    190. public class WeaponDatabase : ScriptableObject
    191. {
    192.     [SerializeField]
    193.     private List<Weapon>
    194.         database;
    195.    
    196.     void OnEnable ()
    197.     {
    198.         if (database == null)
    199.             database = new List<Weapon> ();
    200.     }
    201.    
    202.     public void Add (Weapon weapon)
    203.     {
    204.         database.Add (weapon);
    205.     }
    206.    
    207.     public void Remove (Weapon weapon)
    208.     {
    209.         database.Remove (weapon);
    210.     }
    211.    
    212.     public void RemoveAt (int index)
    213.     {
    214.         database.RemoveAt (index);
    215.     }
    216.    
    217.     public int COUNT {
    218.         get { return database.Count; }
    219.     }
    220.    
    221.     //.ElementAt() requires the System.Linq
    222.     public Weapon Weapon (int index)
    223.     {
    224.         return database.ElementAt (index);
    225.     }
    226.    
    227.     public void SortAlphabeticallyAtoZ ()
    228.     {
    229.         database.Sort ((x, y) => string.Compare (x.weaponName, y.weaponName));
    230.     }
    231. }
    232.  
    233.  
     
  4. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Sure, integrating FI here is pretty easy. For example, let's add a dictionary item to weapon.



    Change Weapon to

    Code (csharp):
    1. [Serializable]
    2. public class Weapon : BaseObject {
    3.     public string weaponName;
    4.     public int damage;
    5.     public Dictionary<string, string> myData;
    6.  
    7.     public Weapon(string name, int dmg) {
    8.         weaponName = name;
    9.         damage = dmg;
    10.         myData = new Dictionary<string, string>();
    11.     }
    12. }
    and in DisplayEditMainArea, add

    Code (csharp):
    1. weapons.Weapon(selectedWeapon).myData = DoEdit(new GUIContent("myData"), weapons.Weapon(selectedWeapon).myData);
    To make animation smooth, in WeaponDatabaseEditor.OnEnable, add
    Code (csharp):
    1.  
    2. fiEditorUtility.RepaintableEditorWindows.Add(this);
    3.  
    We also used this utility method (add it somewhere in WeaponDatabaseEditor)
    Code (csharp):
    1. private static fiGraphMetadata _metadataRoot = new fiGraphMetadata();
    2. private static T DoEdit<T>(GUIContent label, T element) {
    3.     return PropertyEditor.Get(typeof(T), null).FirstEditor.EditWithGUILayout(label, element, _metadataRoot.Enter(label.text));
    4. }

    All together, the file looks likes:

    Code (csharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using UnityEngine;
    5. using UnityEditor;
    6. using FullInspector;
    7. using FullInspector.Internal;
    8.  
    9. [Serializable]
    10. public class Weapon : BaseObject {
    11.     public string weaponName;
    12.     public int damage;
    13.     public Dictionary<string, string> myData;
    14.  
    15.     public Weapon(string name, int dmg) {
    16.         weaponName = name;
    17.         damage = dmg;
    18.         myData = new Dictionary<string, string>();
    19.     }
    20. }
    21.  
    22. public class WeaponDatabaseEditor : EditorWindow {
    23.     private enum State {
    24.         BLANK,
    25.         EDIT,
    26.         ADD
    27.     }
    28.  
    29.     private State state;
    30.     private int selectedWeapon;
    31.     private string newWeaponName;
    32.     private int newWeaponDamage;
    33.  
    34.     private const string DATABASE_PATH = @"Assets/weaponDB.asset";
    35.  
    36.     private WeaponDatabase weapons;
    37.     private Vector2 _scrollPos;
    38.  
    39.     [MenuItem("BZA/Database/Weapon Database %#w")]
    40.     public static void Init() {
    41.         WeaponDatabaseEditor window = EditorWindow.GetWindow<WeaponDatabaseEditor>();
    42.         window.minSize = new Vector2(800, 400);
    43.         window.Show();
    44.     }
    45.  
    46.     void OnEnable() {
    47.         if (weapons == null)
    48.             LoadDatabase();
    49.  
    50.         state = State.BLANK;
    51.         fiEditorUtility.RepaintableEditorWindows.Add(this);
    52.     }
    53.  
    54.     void OnGUI() {
    55.         EditorGUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
    56.         DisplayListArea();
    57.         DisplayMainArea();
    58.         EditorGUILayout.EndHorizontal();
    59.     }
    60.  
    61.     void LoadDatabase() {
    62.         weapons = (WeaponDatabase)AssetDatabase.LoadAssetAtPath(DATABASE_PATH, typeof(WeaponDatabase));
    63.  
    64.         if (weapons == null)
    65.             CreateDatabase();
    66.     }
    67.  
    68.     void CreateDatabase() {
    69.         weapons = ScriptableObject.CreateInstance<WeaponDatabase>();
    70.         AssetDatabase.CreateAsset(weapons, DATABASE_PATH);
    71.         AssetDatabase.SaveAssets();
    72.         AssetDatabase.Refresh();
    73.     }
    74.  
    75.     void DisplayListArea() {
    76.         EditorGUILayout.BeginVertical(GUILayout.Width(250));
    77.         EditorGUILayout.Space();
    78.  
    79.         _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos, "box", GUILayout.ExpandHeight(true));
    80.  
    81.         for (int cnt = 0; cnt < weapons.COUNT; cnt++) {
    82.             EditorGUILayout.BeginHorizontal();
    83.             if (GUILayout.Button("-", GUILayout.Width(25))) {
    84.                 weapons.RemoveAt(cnt);
    85.                 weapons.SortAlphabeticallyAtoZ();
    86.                 EditorUtility.SetDirty(weapons);
    87.                 state = State.BLANK;
    88.                 return;
    89.             }
    90.  
    91.             if (GUILayout.Button(weapons.Weapon(cnt).weaponName, "box", GUILayout.ExpandWidth(true))) {
    92.                 selectedWeapon = cnt;
    93.                 state = State.EDIT;
    94.             }
    95.  
    96.             EditorGUILayout.EndHorizontal();
    97.         }
    98.  
    99.         EditorGUILayout.EndScrollView();
    100.  
    101.         EditorGUILayout.BeginHorizontal(GUILayout.ExpandWidth(true));
    102.         EditorGUILayout.LabelField("Weapons: " + weapons.COUNT, GUILayout.Width(100));
    103.  
    104.         if (GUILayout.Button("New Weapon"))
    105.             state = State.ADD;
    106.  
    107.         EditorGUILayout.EndHorizontal();
    108.         EditorGUILayout.Space();
    109.         EditorGUILayout.EndVertical();
    110.     }
    111.  
    112.     void DisplayMainArea() {
    113.         EditorGUILayout.BeginVertical(GUILayout.ExpandWidth(true));
    114.         EditorGUILayout.Space();
    115.  
    116.         switch (state) {
    117.             case State.ADD:
    118.                 DisplayAddMainArea();
    119.                 break;
    120.             case State.EDIT:
    121.                 DisplayEditMainArea();
    122.                 break;
    123.             default:
    124.                 DisplayBlankMainArea();
    125.                 break;
    126.         }
    127.  
    128.         EditorGUILayout.Space();
    129.         EditorGUILayout.EndVertical();
    130.     }
    131.  
    132.     void DisplayBlankMainArea() {
    133.         EditorGUILayout.LabelField(
    134.             "There are 3 things that can be displayed here.\n" +
    135.             "1) Weapon info for editing\n" +
    136.             "2) Black fields for adding a new weapon\n" +
    137.             "3) Blank Area",
    138.             GUILayout.ExpandHeight(true));
    139.     }
    140.  
    141.     private static fiGraphMetadata _metadataRoot = new fiGraphMetadata();
    142.     private static T DoEdit<T>(GUIContent label, T element) {
    143.         return PropertyEditor.Get(typeof(T), null).FirstEditor.EditWithGUILayout(label, element, _metadataRoot.Enter(label.text));
    144.     }
    145.  
    146.     void DisplayEditMainArea() {
    147.         weapons.Weapon(selectedWeapon).weaponName = EditorGUILayout.TextField(new GUIContent("Name: "), weapons.Weapon(selectedWeapon).weaponName);
    148.         weapons.Weapon(selectedWeapon).damage = int.Parse(EditorGUILayout.TextField(new GUIContent("Damage: "), weapons.Weapon(selectedWeapon).damage.ToString()));
    149.         weapons.Weapon(selectedWeapon).myData = DoEdit(new GUIContent("myData"), weapons.Weapon(selectedWeapon).myData);
    150.  
    151.         EditorGUILayout.Space();
    152.  
    153.         if (GUILayout.Button("Done", GUILayout.Width(100))) {
    154.             weapons.SortAlphabeticallyAtoZ();
    155.             EditorUtility.SetDirty(weapons);
    156.             state = State.BLANK;
    157.         }
    158.     }
    159.  
    160.     void DisplayAddMainArea() {
    161.         newWeaponName = EditorGUILayout.TextField(new GUIContent("Name: "), newWeaponName);
    162.         newWeaponDamage = Convert.ToInt32(EditorGUILayout.TextField(new GUIContent("Damage: "), newWeaponDamage.ToString()));
    163.  
    164.         EditorGUILayout.Space();
    165.  
    166.         if (GUILayout.Button("Done", GUILayout.Width(100))) {
    167.             weapons.Add(new Weapon(newWeaponName, newWeaponDamage));
    168.             weapons.SortAlphabeticallyAtoZ();
    169.  
    170.             newWeaponName = string.Empty;
    171.             newWeaponDamage = 0;
    172.             EditorUtility.SetDirty(weapons);
    173.             state = State.BLANK;
    174.         }
    175.     }
    176. }
    177.  
    178. public class WeaponDatabase : ScriptableObject {
    179.     [SerializeField]
    180.     private List<Weapon>
    181.         database;
    182.  
    183.     void OnEnable() {
    184.         if (database == null)
    185.             database = new List<Weapon>();
    186.     }
    187.  
    188.     public void Add(Weapon weapon) {
    189.         database.Add(weapon);
    190.     }
    191.  
    192.     public void Remove(Weapon weapon) {
    193.         database.Remove(weapon);
    194.     }
    195.  
    196.     public void RemoveAt(int index) {
    197.         database.RemoveAt(index);
    198.     }
    199.  
    200.     public int COUNT {
    201.         get { return database.Count; }
    202.     }
    203.  
    204.     //.ElementAt() requires the System.Linq
    205.     public Weapon Weapon(int index) {
    206.         return database.ElementAt(index);
    207.     }
    208.  
    209.     public void SortAlphabeticallyAtoZ() {
    210.         database.Sort((x, y) => string.Compare(x.weaponName, y.weaponName));
    211.     }
    212. }
     
  5. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I'm unable to reproduce this on 5.1.1f1. Can you send me a repro project?
     
  6. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @ sient - excellent - thanks!
     
  7. Ghopper21

    Ghopper21

    Joined:
    Aug 24, 2012
    Posts:
    170
    Hi there. I'm having problems with the free trial version.

    With Unity 5.1.0f3:
    • New project & scene
    • Import the trial version package
    • When Serializer Manager window pops up, select default and wait until it's green
    • Import the samples package
    • Create empty game object
    • On empty game object, Add Component > Full Inspector Samples > Binary Formatter > Dictionaries
    Get following trace:
    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. 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)
    3. Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
    4. 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:232)
    5. 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)
    6. FullInspector.Rotorz.ReorderableList.Internal.RotorzGUIHelper+<>c__DisplayClass4.<.cctor>b__0 ()
    7. FullInspector.Rotorz.ReorderableList.ReorderableListControl.PrepareState (Int32 controlID, IReorderableListAdaptor adaptor)
    8. FullInspector.Rotorz.ReorderableList.ReorderableListControl.Draw (Rect position, Int32 controlID, IReorderableListAdaptor adaptor, FullInspector.Rotorz.ReorderableList.DrawEmptyAbsolute drawEmpty)
    9. FullInspector.Rotorz.ReorderableList.ReorderableListControl.DrawControlFromState (Rect position, IReorderableListAdaptor adaptor, FullInspector.Rotorz.ReorderableList.DrawEmptyAbsolute drawEmpty, ReorderableListFlags flags)
    10. FullInspector.Rotorz.ReorderableList.ReorderableListGUI.DoListFieldAbsolute (Rect position, IReorderableListAdaptor adaptor, FullInspector.Rotorz.ReorderableList.DrawEmptyAbsolute drawEmpty, ReorderableListFlags flags)
    11. FullInspector.Rotorz.ReorderableList.ReorderableListGUI.ListFieldAbsolute (Rect position, IReorderableListAdaptor adaptor, FullInspector.Rotorz.ReorderableList.DrawEmptyAbsolute drawEmpty, ReorderableListFlags flags)
    12. FullInspector.Internal.BaseCollectionPropertyEditor`4[System.Collections.Generic.Dictionary`2[System.String,System.String],System.Collections.Generic.IDictionary`2[System.String,System.String],System.Collections.Generic.KeyValuePair`2[System.String,System.String],System.String].DoEdit (Rect region, UnityEngine.GUIContent label, IDictionary`2& collection, FullInspector.fiGraphMetadata metadata, IReorderableListAdaptor adaptor)
    13. FullInspector.Internal.BaseCollectionPropertyEditor`4[System.Collections.Generic.Dictionary`2[System.String,System.String],System.Collections.Generic.IDictionary`2[System.String,System.String],System.Collections.Generic.KeyValuePair`2[System.String,System.String],System.String].Edit (Rect region, UnityEngine.GUIContent label, IDictionary`2 collection, FullInspector.fiGraphMetadata metadata)
    14. FullInspector.PropertyEditor`1[System.Collections.Generic.IDictionary`2[System.String,System.String]].FullInspector.IPropertyEditorEditAPI.Edit (Rect region, UnityEngine.GUIContent label, System.Object element, FullInspector.fiGraphMetadata metadata)
    15. FullInspector.PropertyEditorExtensions.DoEdit2[Object] (IPropertyEditorEditAPI api, Rect region, UnityEngine.GUIContent label, System.Object element, FullInspector.fiGraphMetadata metadata)
    16. FullInspector.PropertyEditorExtensions.DoEdit[Object] (IPropertyEditorEditAPI api, Rect region, UnityEngine.GUIContent label, System.Object element, FullInspector.fiGraphMetadata metadata)
    17. FullInspector.PropertyEditorExtensions.Edit[Object] (IPropertyEditor editor, Rect region, UnityEngine.GUIContent label, System.Object element, fiGraphMetadataChild metadata)
    18. FullInspector.Internal.fiEditorGUI.EditPropertyDirect (Rect region, FullInspector.InspectedProperty property, System.Object propertyValue, fiGraphMetadataChild metadataChild, System.Object context)
    19. FullInspector.Internal.fiEditorGUI.EditProperty (Rect region, System.Object container, FullInspector.InspectedProperty property, fiGraphMetadataChild metadata)
    20. FullInspector.Internal.ReflectedPropertyEditor.EditProperty (UnityEngine.Rect& region, System.Object element, FullInspector.InspectedProperty property, FullInspector.fiGraphMetadata metadata)
    21. FullInspector.Internal.ReflectedPropertyEditor.EditPropertiesButtons (Rect region, System.Object element, FullInspector.fiGraphMetadata metadata)
    22. FullInspector.Internal.ReflectedPropertyEditor.Edit (Rect region, UnityEngine.GUIContent label, System.Object element, FullInspector.fiGraphMetadata metadata)
    23. FullInspector.PropertyEditorExtensions.DoEdit2[Object] (IPropertyEditorEditAPI api, Rect region, UnityEngine.GUIContent label, UnityEngine.Object element, FullInspector.fiGraphMetadata metadata)
    24. FullInspector.PropertyEditorExtensions.DoEdit[Object] (IPropertyEditorEditAPI api, Rect region, UnityEngine.GUIContent label, UnityEngine.Object element, FullInspector.fiGraphMetadata metadata)
    25. FullInspector.PropertyEditorExtensions.Edit[Object] (IPropertyEditor editor, Rect region, UnityEngine.GUIContent label, UnityEngine.Object element, fiGraphMetadataChild metadata)
    26. FullInspector.DefaultBehaviorEditor.OnEdit (Rect rect, UnityEngine.Object behavior, FullInspector.fiGraphMetadata metadata)
    27. FullInspector.BehaviorEditor`1[TBehavior].Edit (Rect rect, UnityEngine.Object behavior)
    28. FullInspector.IBehaviorEditorExtensions.EditWithGUILayout[Object] (IBehaviorEditor editor, UnityEngine.Object element)
    29. FullInspector.FullInspectorCommonSerializedObjectEditor.ShowInspectorForSerializedObject (UnityEngine.Object target)
    30. FullInspector.FullInspectorCommonSerializedObjectEditor.OnInspectorGUI ()
    31. UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor editor, Int32 editorIndex, Boolean forceDirty, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect, Boolean eyeDropperDirty) (at /Users/builduser/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1162)
    32. UnityEditor.DockArea:OnGUI()
    33.  
     
  8. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Okay, thanks. I'll push out an updated trial in the next few days. For the time being, I've sent you a PM.
     
  9. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Hi everyone! I've pushed out 2.6.2 to the asset store which is primarily a bug-fix release (it should be available this upcoming week; I'll make another post when it is accepted). Please find the changelog below; one notable new feature is drag and drop support for lists. 2.6.2 also fixes a huge performance regression, so the FI editors should be nice and snappy once more.

    In 2.6.2, only FullSerializer and Json.NET are imported by default. The other two officially supported serializers (protobuf-net and BinaryFormatter) are available as unitypackage files in FullInspector2/Serializers - they are just not imported by default.

    As always, I'd recommend backing up before updating. Make sure to delete the FullInspector2 folder (but not FullInspector2_Generated) before updating for best results.

    For future development, I'm planning to continue to focus on quality. The next release will be 2.7, which will include a refactored attribute property editors system; based on my current designs, there will be some API breakage inside of property editors. This refactoring will also enable (finally!) multiple object editing, which I'd like to land in 2.8.

    Here's the changelog for 2.6.2:

    New:
    - Added IsCollapsedByDefault to InspectorCollectionShowItemDropdownAttribute.
    - Added InspectorKeyWidthAttribute, which (for example), allows you to modify the width of the keys inside of a dictionary.
    - Added Insert button to [InspectorDatabaseEditor] (thanks to psxcode!)
    - Added drag&drop support for UnityObject derive types on reorderable lists.
    - Added BaseNetworkBehavior (you will have to regenerate FullInspector2_Generated to use the non-generic version).
    - Added OnEditorActivate and OnEditorDeactivate callbacks to BehaviorEditors.
    - Added [InspectorHideIf], which is the opposite of [InspectorShowIf].

    Changes:
    - IPropertyEditor type cast failures are easier to read.
    - KeyedCollection{T} is now properly supported.
    - Added a warning message when a PropertyDrawer integration fails because the type is not marked [Serializable].

    Fixes:
    - Fixed visual glitch when inserting an element above/below another element in an array or a list.
    - Fixed prefab utility in certain scenarios.
    - Fixed IsUnity4 returning true for Unity 5 (fixes multithreaded serialization).
    - Fixed large performance regression in editors (only for Unity 5).
    - Fixed EditorWindow.title deprecation warning in Unity 5.
    - Record undo states less often, which leads to better in-editor perf.
    - Fixed nested BaseObject instances not showing up in the inspector.
    - Fixed using an array of BaseObject instances.
    - Cleaned up import warnings from Visual Studio Code.
    - Fixed WinRT builds.
    - Fixed protobuf serializer.
    - Fixed type property editor in Unity 5.
     
  10. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I've also pushed out an update to the trial - it is now set to the latest version, 2.6.2.
     
  11. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    Hi sient,

    I tried the latest version (2.6.2) which you sent me. I wanted to use DLL files instead of source code and consulted the INSTRUCTIONS.md inside the FullInspector-DLL Builder.zip:

    This documentation seems to be wrong. There is no "FullInspector2/PrecompiledDLLs.unitypackage". However I found the DLLs inside the zip file.

    When I copied them into my project and then deleted the Core and Modules folders, no class derived from BaseBehaviour is displayed in the inspector (only the title line of these components are displayed. but no field).
    When I click on one of those components I get an error:

    Are there any further steps required to get the DLLs running?
     
  12. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    That's strange. I'll get those instructions fixed (you did the right thing - I just include the DLLs inside of "DLLs" now). But you definitely shouldn't be getting those errors; you may get a message like the following once:

    Code (csharp):
    1.  
    2. Created new backup persistent storage object at Assets/FullInspector2_Generated/fiBackupStorage.prefab; this should only happen once. Please report a bug if it keeps on occurring.
    3. UnityEngine.Debug:Log(Object, Object)
    4. FullInspector.BackupService.fiPrefabManager:get_Storage()
    5. FullInspector.BackupService.fiStorageManager:HasBackups(CommonBaseBehavior)
    6. FullInspector.FullInspectorCommonSerializedObjectEditor:ShowBackupButton(Object)
    7. FullInspector.FullInspectorCommonSerializedObjectEditor:OnInspectorGUI()
    8. UnityEditor.DockArea:OnGUI()
    9.  
    What version of Unity are you running? Does restarting Unity fix the issue? Did you delete FI2/Core and FI2/Modules?
     
  13. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    Thanks, the new version you sent me worked (Unity 5.1.1f1).

    Now we can move on to the next little problem ;)

    I have the following classes:
    Code (csharp):
    1.  
    2. [Serializable]
    3. public abstract class ValueProvider<T>
    4. { }
    5.  
    6. [Serializable]
    7. public class StaticValue<T> : ValueProvider<T>
    8. { }
    9.  
    10. [Serializable]
    11. public class FilterSearchData<T> : ValueProvider<T>
    12.   where T : IData
    13. { }
    And in some BaseBehaviour I have a member:
    Code (csharp):
    1. public ValueProvider<string> MyString;
    Now when I select the type of MyString in the inspector, I can select StaticValue<string> as well as FilterSearchData<string>. The latter one shouldn't be possible since the type string doesn't implement my interface IData.

    (BTW: Another thing on my wishlist: don't display variables of classes which are not marked with SerializeAttribute - or - even better: mark them in the inspector somehow... I often forget to tag them and wonder why my settings aren't saved)
     
  14. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Ah, sorry - the generic inheritance selection logic doesn't support generic parameters (I was really happy when I even got it to work! ha). The generic selection logic is probably the second most complex reflection (after the property editor creation/matching - that is really gnarly logic) and I'm not sure all of the precise rules in play that determine if a type satisfies a generic constraint. If you select the invalid type what happens? Does an instance get allocated?

    For the serialization data, by default things should only be displayed if they are serialized by FI - but this is not the case for [fiInspectorOnly]. What's your setup look like? I'll try to think of something to make it better, but I don't have any ideas off the top of my head.
     
  15. Illusive-S

    Illusive-S

    Joined:
    Sep 19, 2013
    Posts:
    8
    I was wondering how to call a default PropertyEditor
    I am trying to do a BehaviorEditor with a list in there and make changes to an object based on the changes to the list.
    I have no idea how to draw the damn thing
    And regarding the changing part, is OnEdit called whenever the change to the editor is made? So it would be a perfect place to put a code like that right?
     
  16. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    Does anyone have advice on how to smoothly update FullInspector when there is an update in the asset store? The problem is that if I delete the existing FullInspector folder and import a new version, my existing scripts that use things like "BaseObject" will fail to compile because that class no longer exists. It only exists after you choose your default serializer in FullInspector and it creates those classes. But it's a Catch 22, Unity can't pop up the window letting you choose a default serializer until everything compiles correctly. So far I've had to delete Full Inspector, then comment out / change all code in the project that uses it, then import the new version, then select the Full Serializer, then go back and change everything back to how it was originally using the Full Insepctor classes. It's quite a pain. Is there an easier way?
     
    Deleted User likes this.
  17. Deleted User

    Deleted User

    Guest

    Before I used to just delete the FullInspector2 folder and leave the _Generated one alone but for this new version it's not working. I did what you did: change all classes to work without FI2, then Unity generated the window, then made my classes use FI 2 again. It would be nice if there was an easier way or a set of instructions on how to update FI cleanly.
     
  18. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    Just bough FI, SERIOUSLY loving it so far. So nice to be able to use interfaces and generics without even thinking about what restrictions unity may or may not have.

    I am running into the issue mentioned here though: http://forum.unity3d.com/threads/fu...enerics-interfaces.224270/page-5#post-1737849

    I want to be able to operate on an object just after it's constructed via the inspector. Just wondering if there has been any changes since then, some callback you can hook into to reference an object after it's been constructed?
     
  19. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    @makeshiftwings & @supremegrandruler: Instead of changing all your code it should be possible to just create a file "BaseBehavior" (with "o" not "ou"):
    Code (csharp):
    1. namespace FullInspector
    2. {
    3.     public class BaseBehavior : MonoBehaviour { protected virtual void Awake() { } }
    4. }
    Delete or rename the class for BaseBehavior in the FullInspector_Generated folder.
    this should be enough to let your code compile.

    However: it is still a very annoying workaround.

    @Sarkahn: All public (and all non-public members marked with [FullInspector.ShowInInspector][SerializeField]) can be defined in the inspector window. Full Inspector deserializes your settings for the objekt and sets them right after the object is constucted.
    If you want something like a Start() Method inside non-MonoBehaviour objects: this is not possible out of the box. What you can do is calling Initialization methods inside the Start() Method of the BaseBehavior which contains your object.
     
  20. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    Let me show you an example of what I want to do
    Code (csharp):
    1.  
    2. //Attribute
    3. public class OnAddCallback : Attribute
    4. {
    5.     Delegate del_;
    6.     string methodName_;
    7.     object instance_;
    8.  
    9.     public OnAddCallback( string methodName )
    10.     {
    11.         methodName_ = methodName;
    12.     }
    13.  
    14.     public void Bind<T>( object instance )
    15.     {
    16.         instance_ = instance;
    17.         del_ = Delegate.CreateDelegate(typeof(Action<T>), instance, instance.GetType().GetMethod(methodName_));
    18.     }
    19.  
    20.     void OnAdd<T>(T obj)
    21.     {
    22.         ((Action<T>)del_).Invoke(obj);
    23.     }
    24. }
    25.  
    26. // In my containing class
    27. [OnAddCallback("HandleAdd")
    28. List<IItem> items_;
    29.  
    30. void HandleAdd( Item item )
    31. {
    32.     // Do stuff to my item when it's created in the inspector
    33. }
    34.  
    Is something like this possible?
     
    Last edited: Jul 16, 2015
  21. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    I think I tried something similar last time and it didn't work, because after you choose your default serializer it needs to actually compile to finalize the process, but it won't be able to compile because you'll get an error about multiple definitions of BaseBehavior.

    My recommendation to make importing easier would be to include "FullInspectorGenerated" in the actual asset package using the default FullSerializer, and then let the user change it to a different serializer if he wants using the window.
     
  22. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    @Sarkahn: Not sure if there is a way to get your approach working. Probably sient can give you a better answer.

    However I have another little cosmetic problem...

    I have two classes A and B where B inherits A.
    Now I have a public member from the type A.
    I know that A is always enough and the user would never need to select B in the inspector.

    So I searched and found this:
    Sounds like exactly what I want.
    But it doesn't seem to work. The drop down is still shown :(
     
  23. sanpats

    sanpats

    Joined:
    Aug 24, 2011
    Posts:
    343
    In the Guide, it was stated that Full Inspector's File Serialization won't work on UnityEngine.Object references. Does that mean I can't do a file serialization for my BaseBehavior derived class in entirety, but need to serialize member by member of that class? ( because BaseBehavior also derived from UnityEngine.Object)
     
  24. Ghopper21

    Ghopper21

    Joined:
    Aug 24, 2012
    Posts:
    170
    Hi there, I'm getting the following two obsolete API warnings (with the full and latest version of FullInspector2):
     
  25. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @sient ,

    I don't suppose you could post some sample code for me re how I might use Full Inspector and the editor (with OnGUI buttons) to save out fields to say SimpleSQL (I can deal with the SimpleSQL specific code) as a new row in a sqlite table... outside runtime - so executing in editor, if you see what I mean?
     
  26. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    To call the default property editor, use PropertyEditor.Get(typeof(someType), null).FirstEditor.Edit and/or GetElementHeight.

    OnEdit is called whenever Unity wants to draw an editor GUI. You can use EditorGUI.changed to detect when there has been a change to the object.
     
  27. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Delete FullInspector2 (not FullInspector2_Generated) and import the new package. It may also be easier to import FI into an empty project, exit Unity, and copy+paste the files into your real project. Unfortunately Unity's package manager doesn't work well enough to just do a blanket import on top of an existing installation.

    I'll get some written, thanks! Sometime's its hard to figure out what needs to be documented and what doesn't.
     
    Deleted User likes this.
  28. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602

    This workflow will be enabled by the attribute editor rewrite, which is going to be in the next release (though I don't have a timeline yet). There currently isn't a good way to do this because the PropertyEditors have zero knowledge about the "parent" object that the currently edited object belongs to.
     
  29. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    That's the plan for 2.7 :). Json.NET used to be the default serializer and I didn't want to just suddenly switch people over to FullSerializer. It should be import compatible, except when the Json.NET pipeline is customized. I'm also planning on rewriting the metadata logic around the serializer packages to be much more robust, as right now it likes to cause compile errors.
     
  30. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Would you mind sending a code example for how you're trying to use it? Thanks!
     
  31. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Right, it will throw an exception. The file serialization system immediately sends the object to the selected serializer, whereas for BaseBehavior serialization FI has a mini-serializer that sends only the relevant fields/properties to the serializer (separately).
     
  32. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Not sure what's going on there, I'll take a look. I think you also pushed an issue to GitHub - I'll post updates there.
     
  33. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Sorry, I'm not quite sure I understand. I'm going to write up some docs for embedding FI (basically use PropertyEditor.Get(typeof(sometype), null).FirstEditor.Edit/GetElementHeight) since multiple people have asked (I'll post the link when they're written - I'm going to do it next), but for actually integrating into SimpleSQL I'm not familiar with the APIs/library.
     
  34. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @sient,

    That would be great anyway. . I'm looking to input values in to variables in the inspector or an editor and then using a button or two in the inspector/editor save all that in to a row of a sqlite file table (using orm simplesql but I can take care of that code on the ongui button code I think)...
     
  35. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Yep, still working on it. Just got a new computer :), but Visual Studio is taking a long time to download...
     
  36. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    If you could include some ongui button code with it that would be great...
     
  37. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Here are the docs for how to embed FI.

    What do you mean?
     
  38. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    So I'm thinking of the inspector and using that outside runtime perhaps to store to rows in the sqlite table by pressing an button ongui in the inspector...
     
  39. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    I have these classes:
    Code (csharp):
    1. [Serializable]
    2. public class A
    3. { }
    4.  
    5. [Serializable]
    6. public class B : A
    7. { }
    8.  
    9. public class Test : BaseBehavior
    10. {
    11.   [FullInspector.InspectorSkipInheritance]
    12.   public A myVariable;
    13.  
    14. }
    when I add a Test component to a game object I get the following result:


    The funny thing is: when I select B the selection drop down disappears.

    So probably I do not understand the attribute correctly.
    What I tried to achieve is: The variable should always be of type A and not of any derived class. And I never want to see that dropdown.
     
  40. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I think something like this should work if I understand correctly.

    Code (csharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4. using FullInspector;
    5.  
    6. [Serializable]
    7. public class MyType : BaseObject {
    8.     public Dictionary<int, int> dict;
    9. }
    10.  
    Code (csharp):
    1.  
    2. using FullInspector;
    3. using FullInspector.Internal;
    4. using UnityEngine;
    5. using UnityEditor;
    6.  
    7. public class EmbedDemo : EditorWindow {
    8.     [MenuItem("Test/Embedded FI Editor")]
    9.     private static void Create() {
    10.         GetWindow<EmbedDemo>();
    11.     }
    12.  
    13.     [SerializeField]
    14.     private MyType instance;
    15.     private fiGraphMetadata metadata = new fiGraphMetadata();
    16.  
    17.     protected void OnEnable() {
    18.         // This will make animation smooth.
    19.         fiEditorUtility.RepaintableEditorWindows.Add(this);
    20.     }
    21.  
    22.     private void DoLoad() {
    23.         instance = /* ... */;
    24.     }
    25.     private void DoSave() {
    26.         /* save instance */
    27.     }
    28.  
    29.     protected void OnGUI() {
    30.         var editor = PropertyEditor.Get(typeof(MyType), null);
    31.  
    32.         if (EditorGUILayout.Button("Save")) DoSave();
    33.         if (EditorGUILayout.Button("Load")) DoLoad();
    34.  
    35.         // For convenience, FI defines an `EditWithGUILayout` method that just wraps
    36.         //  the calls to `GetElementHeight` and `Edit`.
    37.         if (instance != null) {
    38.             instance = editor.FirstEditor.EditWithGUILayout(null, instance, metadata.Enter("Hi"));
    39.         }
    40.     }
    41. }
    42.  
     
  41. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Strange, I don't know why this broke. Anyways, change line 12 of FullInspector2\Modules\Attributes\Editor\InspectorSkipInheritanceAttributeEditor.cs to

    Code (csharp):
    1.  
    2. return PropertyEditor.Get(element.GetType(), null).SkipUntilNot(typeof(AbstractTypePropertyEditor));
    3.  
     
  42. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    I've finally pushed out the docs on the attributes! Check them out here.
     
  43. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,215
    @sient,
    Excellent, thanks once again for your help.
     
  44. Ghopper21

    Ghopper21

    Joined:
    Aug 24, 2012
    Posts:
    170
    Awesome, thanks!
     
  45. sanpats

    sanpats

    Joined:
    Aug 24, 2011
    Posts:
    343
    For Unity 5.2.0b3, there is a warning that Application.isLoadingLevel "This property is deprecated, please use LoadLevelAsync to detect if a specific scene is currently loading." in fiSerializationManager.cs line 116. Can you fix it or tell me how to fix it?
     
  46. sz-Bit-Barons

    sz-Bit-Barons

    Joined:
    Nov 12, 2013
    Posts:
    150
    Hmmm... I tried to make a build for iOS again today with IL2CPP...

    The scene is loaded but at the very beginning I receive the following exception:
    Now I wonder if the FullSerializer simply doesn't work or if it is my code...
    If it is my code it probably doesn't work cause I have a class anywhere which doesn't have a default constructor.
    And if this is the case I probably just can write a default constructor to get it working right? Can it be private?
     
  47. Illusive-S

    Illusive-S

    Joined:
    Sep 19, 2013
    Posts:
    8
    Edit requires GUIContent parameter, where from should i get it is a parameter on edit in PropertyEditor but not on BehaviorEditor.
    also i got the error
    Please use BehaviorEditor (not ProperytEditor) for Army on editor TestEditor
    First of all there is a typo :p
    Second of all, why is there such an error? When should i use behavior and when property editor
     
  48. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    That's not good, since LoadLevelAsync definitely does not expose the same amount of information. Try commenting it out, it was there to work around a Unity bug - maybe it has been fixed in Unity 5.
     
  49. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    This looks like a stripping bug on Unity's end. Can you either add "new FullInspector.FullSerializerSerializer()" somewhere to your project or add a stripping annotation to tell Unity to not strip the type? Thanks
     
  50. sient

    sient

    Joined:
    Aug 9, 2013
    Posts:
    602
    Can you post a code sample? The label is whatever you want it to be, probably the name of the field/property you're editing, or something more descriptive, etc. Can you post a code sample with what your confused on?

    Thanks, I've fixed the type and made the message more clear. You use BehaviorEditor whenever you write an editor for a type which derives from UnityEngine.Object. BehaviorEditor enables the inline object editor and it also makes the upcoming attribute editor system possible.