Search Unity

  1. We've closed the job boards. If you're looking for work, or looking to hire check out Unity Connect. You can see more information here.
    Dismiss Notice
  2. Unity 2017.2 is now released.
    Dismiss Notice
  3. The Unity Gear Store is here to help you look great at your next meetup, user group or conference. With all new Unity apparel, stickers and more!
    Dismiss Notice
  4. If you're a macOS 10.13 High Sierra user take be sure to read this before updating Unity.
    Dismiss Notice
  5. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  6. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice
  7. Unity 2017.3 beta is now available for download.
    Dismiss Notice

Assets [WIP] Odin Inspector & Serializer Looking for Feedback

Discussion in 'Works In Progress' started by jorisshh, Feb 22, 2017.

  1. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    150
    You can use OnInspectorGUI and property ordering to achieve this. Essentially, just put a method like this anywhere in your class, and it will draw an info box at the very top of your inspector.

    Code (CSharp):
    1. #if UNITY_EDITOR
    2.     [OnInspectorGUI, PropertyOrder(int.MinValue)]
    3.     private void DrawInfoBox()
    4.     {
    5.         Sirenix.Utilities.Editor.SirenixEditorGUI.InfoMessageBox("Message here");
    6.     }
    7. #endif
     
    zzzzzz789 likes this.
  2. SuneT

    SuneT

    Joined:
    Feb 29, 2016
    Posts:
    41
    A bit of news
    We've decided to turn our own forums at forum.devdog.io to "read-only" and instead switch to our own Discord server.

    The Discord server will allow for faster support and quicker messaging back and forth! ;)

    So if you're experiencing any issues, have feedback, or just want to show-off whatever you've made using any of our tools and hang out with us, come join: https://discord.gg/zjNj5zZ
     
  3. jorisshh

    jorisshh

    Joined:
    Oct 6, 2009
    Posts:
    1,474
    Great news, everyone!

    First of all, Odin is on sale in case you haven't noticed.
    We're going to increase the price after this sale, so Odin will never be cheaper than this (even during future sales).

    And also - Odin is a finalist in the Unity Awards, and we need YOUR help!
    You can go vote for Odin right here: https://awards.unity.com/
     
  4. MaddoScientisto

    MaddoScientisto

    Joined:
    Jan 30, 2015
    Posts:
    62
    Hello, first I got to say that I really like this addon, it quickly became one of my essential assets for any new project of mine.
    So I've been wondering if there's any way to do the following custom editor field with just an attribute:
    m_DefaultSprite = EditorGUILayout.ObjectField("Default Sprite", tile.m_DefaultSprite, typeof(Sprite), false) as Sprite;

    basically showing the sprite field rather than the generic one
     
  5. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    150
    That sounds like it would be something like this:

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. #if UNITY_EDITOR
    5. using Sirenix.OdinInspector.Editor;
    6. using UnityEditor;
    7. #endif
    8.  
    9. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    10. public class DrawSpriteFieldAttribute : Attribute { }
    11.  
    12. #if UNITY_EDITOR
    13. [OdinDrawer]
    14. public class SpriteDrawer : OdinAttributeDrawer<DrawSpriteFieldAttribute, Sprite>
    15. {
    16.     protected override void DrawPropertyLayout(IPropertyValueEntry<Sprite> entry, DrawSpriteFieldAttribute attribute, GUIContent label)
    17.     {
    18.         entry.SmartValue = EditorGUILayout.ObjectField("Default Sprite", entry.SmartValue, typeof(Sprite), false) as Sprite;
    19.     }
    20. }
    21. #endif
    And then you would just put [DrawSpriteField] on your member. It's a little odd that Odin isn't doing that correctly, though - it should. We'll have to look into that. Thanks for the heads up!
     
  6. MaddoScientisto

    MaddoScientisto

    Joined:
    Jan 30, 2015
    Posts:
    62
    Thank you that did the trick, on the plus side now I know how to make attributes for custom things!

    While I'm here another thing: is there a way to expand serialized scriptableobjects instead of editing them in a separate window?

    Also I noticed that all the elements in a BoxGroup are hidden (for instance with ShowIf) the box still shows, is there a way to hide it?
     
    Last edited: Oct 11, 2017
  7. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    150
    If you mean when you have a reference to them, and you want to draw the whole ScriptableObject instead of just the object field, you can use [InlineEditor] for that - draws inspectors for Unity object values inline in the inspector itself. Works on anything - Meshes, Materials, Components, ScriptableObjects, AudioClips, etc.
     
  8. MaddoScientisto

    MaddoScientisto

    Joined:
    Jan 30, 2015
    Posts:
    62
    Very nice! I love this asset more and more! I have more questions but I guess I'll get on the discord and ask there so I don't end up cluttering the thread too much
     
  9. Celtc

    Celtc

    Joined:
    Jan 19, 2014
    Posts:
    4
    Is there any way to serialize Stack<> and Queue<> classes? Thanks! Great asset!

    PD.: When using UnityEvents inside of non monobehaviour classes, I can't get them to be drawn properly (as Unity does).

    Here is my code:

    Code (CSharp):
    1. [SerializeField]
    2. [PropertyOrder(0)]
    3. [DrawWithUnity]
    4. [TabGroup("Events")]
    5. public UnityEvent_GameObject OnSpawn = new UnityEvent_GameObject();
    6.  
    7. [SerializeField]
    8. [PropertyOrder(1)]
    9. [TabGroup("Events")]
    10. public UnityEvent_GameObject OnRecycle = new UnityEvent_GameObject();
    And this is how it gets drawn:

    [​IMG]
     
    Last edited: Oct 13, 2017
  10. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    150
    This is a known issue, and is related to limitations how Unity draws UnityEvents. It's a hard one to fix, and it looks like we're essentially just going to have to make our very own UnityEvent drawer, which I'm afraid is a little bit in the future. For now, you'll have to make sure that your UnityEvents are serialized by Unity, and are in a Component. The next patch does have an improved error message that essentially states this, though.
     
  11. gbarnes

    gbarnes

    Joined:
    Mar 25, 2014
    Posts:
    3
    Hello,

    so far I'm lovin Odin. However I asked myself if it's possible to somehow group togther list elements visually. For Example we have a list of different objects. Objects could be weapons, armor or other stuff. Would it be possible to group elements by their "type" (I'm not speaking of the programming type but some abitrary we would like to specify).

    This would it make easier for designers to maintain a specific subset of the list.
     
  12. vudong

    vudong

    Joined:
    Feb 6, 2015
    Posts:
    29
    [​IMG]
    I lost data!
     
  13. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    98
    Not sure what you mean by you lost data, could you provide a little more information in regards to that?

    But thank you for posting that error message, it should be fixed now. If you will send us an email with your Odin Invoice Nr. (for verification) via our website www.sirenix.net I can send you the hotfix right away. Until then, you can go into Odin preferences and prevent the persistent cache from storing to disk.
     
    Last edited: Oct 17, 2017
  14. Meceka

    Meceka

    Joined:
    Dec 23, 2013
    Posts:
    287
    Hello,
    I am using Odin inspector only for attributes. So I disabled serialization as recommended in manual.
    However, although it's not mentioned in the manual I am adding a "using Sirenix.OdinInspector;" line in my scripts to make attributes work. And I don't know what assemblies I am adding into the build by doing that.
    In the FAQ section, there is this question:
    "Can I use Odin for its editors only, without using the serialization?"
    it claims that
    "The only Odin code that will be included, is the small Sirenix.OdinInspector.Attributes assembly"
    I tried using Sirenix.OdinInspector.Attributes but there isn't such a namespace
    Is my workflow correct by adding "using Sirenix.OdinInspector" to only add attributes to scripts?
    I also tried adding it like this, but the build fails because of attributes,
    #if UNITY_EDITOR
    using Sirenix.OdinInspector;
    #endif
     
  15. Celtc

    Celtc

    Joined:
    Jan 19, 2014
    Posts:
    4
    I'll really looking forward for your UnityEvent drawer. I think is quite a big deal, since lot of games are event driven. And being able to inspect them is invaluable for designers, and even programmers.
     
    Last edited: Oct 20, 2017
  16. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    150
    You should indeed just write "using Sirenix.OdinInspector;" - that includes the attributes, which are declared under that namespace, despite actually being in an assembly named Sirenix.OdinInspector.Attributes. We just thought having to type "using Sirenix.OdinInspector.Attributes;" was a little bit much, so we just declared it under a shorter namespace.
     
  17. Abuthar

    Abuthar

    Joined:
    Jul 12, 2014
    Posts:
    63
    Hey there, i need a little help. Trying to serialize a class with Odin. I keep getting this error:

    Code (CSharp):
    1. SerializationException: Type Sirenix.OdinInspector.SerializedMonoBehaviour in assembly Sirenix.Serialization, Version=1.0.5.1, Culture=neutral, PublicKeyToken=null is not marked as serializable.
    2. System.Runtime.Serialization.FormatterServices.GetSerializableMembers... etc
    my Scripts look like this (I'm using an empty project to figure this out before using in my real project).

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.Runtime.Serialization.Formatters.Binary;
    5. using System.IO;
    6. using System;
    7. using Sirenix.Serialization;
    8. using Sirenix.OdinInspector;
    9.  
    10. public class DataManager : MonoBehaviour
    11. {
    12.     public LightData[] _lightData;
    13.  
    14.     public void SaveProjectData()
    15.     {
    16.  
    17.         BinaryFormatter bf = new BinaryFormatter();
    18.         FileStream file = File.Create((Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/file01.dat"));
    19.         SaveIndex index = new SaveIndex();
    20.  
    21.         index.data = _lightData;
    22.  
    23.         bf.Serialize(file, index);
    24.         file.Close();
    25.         Debug.Log("Saved");
    26.     }
    27.  
    28.     public void LoadProjectData(int targetFile)
    29.     {
    30.         if (File.Exists((Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "file01.dat")))
    31.         {
    32.             BinaryFormatter bf = new BinaryFormatter();
    33.             FileStream file = File.Open((Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "file01.dat"), FileMode.Open);        
    34.             SaveIndex index = (SaveIndex)bf.Deserialize(file);
    35.  
    36.             for(int i = 0; i < index.data.Length; i++)
    37.             {
    38.                 _lightData[i].LoadData(index.data[i]);
    39.                 Debug.Log("Loading Data . . .");
    40.             }
    41.  
    42.             file.Close();
    43.  
    44.         }
    45.         else
    46.         {
    47.             Debug.Log("File is Null");
    48.         }
    49.     }
    50. }
    51.  
    52. [System.Serializable]
    53. public class SaveIndex
    54. {
    55.     public LightData[] data;
    56. }
    57.  
    The serialized file looks like this:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.Runtime.Serialization.Formatters.Binary;
    5. using System.IO;
    6. using System;
    7. using Sirenix.Serialization;
    8. using Sirenix.OdinInspector;
    9.  
    10. [System.Serializable]
    11. public class LightData : SerializedMonoBehaviour
    12. {
    13.     [OdinSerialize]
    14.     public float lightIntensity;
    15.     [OdinSerialize]
    16.     public float lightX;
    17.     [OdinSerialize]
    18.     public float lightY;
    19.     [OdinSerialize]
    20.     public float lightZ;
    21.  
    22.     public void LoadData(LightData reader)
    23.     {
    24.         lightIntensity = reader.lightIntensity;
    25.         lightX = reader.lightX;
    26.         lightY = reader.lightY;
    27.         lightZ = reader.lightZ;
    28.     }
    29.  
    30. }
    31.  
    can anyone tell me what i'm doing wrong??
     
  18. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    150
    I'm afraid there's a few misunderstandings going on in that code!

    Let's take them one at a time:
    1. Using BinaryFormatter doesn't invoke Odin's serialization. Your code isn't actually calling into Odin's serialization anywhere. BinaryFormatter is a built-in class that comes with the runtime that the scripting part of Unity is built on, and doesn't actually have anything to do with how either Odin or Unity do serialization. You can read more about how to actually invoke Odin's serialization here - the link includes an example of how to do essentially what you're trying, only with Odin instead.

    2. You cannot serialize any instance of a type that inherits from UnityEngine.Object to a file, due to how Unity works. Odin's SerializedMonoBehaviour inherits from UnityEngine.MonoBehaviour, which is a component that you put on a GameObject. UnityEngine.MonoBehaviour derives from UnityEngine.Object. So you cannot make any class that you want to serialize to a file inherit from SerializedMonoBehaviour. The SerializationException you're getting, in fact, is exactly because the class is not meant to be used in that way.

      A SerializedMonoBehaviour cannot be serialized from the "outside". How you're supposed to use it, is that you put it on a GameObject as a component, and that component can now be used as any other regular Unity component, except it magically has extra serialization capabilities built in, so it can save and show things that a regular Unity component could not. These serialization capabilities are invoked from deep within Unity's own serialization system, which also has nothing to do with BinaryFormatter.

      In short, SerializedMonoBehaviour is a convenience class for using Odin's serialization in your Unity components in an inspector-friendly way.

    3. You don't actually need Odin to do what you're trying, there. In fact, that code should work perfectly, if you just change "public class LightData : SerializedMonoBehaviour" to "public class LightData" and remove the [OdinSerialize] attributes. The BinaryFormatter class will take your LightData and save/load it just fine on its own, without any involvement from Odin at all.

      If you do want to use Odin to do the serialization instead, see the FAQ link in point 1 for some example code.
    I hope that helps explain the issues you're getting! And of course, if you have any more questions, feel free to ask :)
     
  19. brisingre

    brisingre

    Joined:
    Nov 8, 2009
    Posts:
    252
    A few quick questions:

    1. Can I make a boolean that looks like a button instead of a check box?
    2. Can I inspect a static variable?
    3. Can I make a range that doesn't enforce it's min and max on associated number entry field? That is, the slider goes from, say, 0 to 1, but if you put 2 in the text field it won't change it to 1 unless you mess with the slider.
    And just for fun, a before and after on the first thing I've Odin-ized

    Before:
    upload_2017-11-10_16-12-39.png

    After:
    upload_2017-11-10_16-13-0.png
     
    Last edited: Nov 11, 2017
  20. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    150
    1. Can I make a boolean that looks like a button instead of a check box?

    You can! You just need to create an attribute and a drawer for it:

    Code (CSharp):
    1. // Declare an attribute to use
    2. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    3. public class ButtonBoolAttribute : Attribute
    4. {
    5. }
    6.  
    7. // In an editor script somewhere, declare the drawer
    8. [OdinDrawer]
    9. public class ButtonBoolAttributeDrawer : OdinAttributeDrawer<ButtonBoolAttribute, bool>
    10. {
    11.     protected override void DrawPropertyLayout(IPropertyValueEntry<bool> entry, ButtonBoolAttribute attribute, GUIContent label)
    12.     {
    13.         bool value = entry.SmartValue; // Value in the first selected object
    14.         GUIStyle style = value ? SirenixGUIStyles.ButtonSelected : SirenixGUIStyles.Button;
    15.  
    16.         if (GUILayout.Button(label, style))
    17.         {
    18.             entry.SmartValue = !value;
    19.         }
    20.     }
    21. }
    2. Can I inspect a static variable?

    Currently, not directly. In Odin 1.1, we will add this ability. Meanwhile, what you can do is, essentially, make an instance property that references the static variable:

    Code (CSharp):
    1. private string MyStaticVariable { get { return myStaticVariable; } set { myStaticVariable = value; } }
    3. Can I make a range that doesn't enforce it's min and max on associated number entry field? That is, the slider goes from, say, 0 to 1, but if you put 2 in the text field it won't change it to 1 unless you mess with the slider.

    Yes, you can make your own range attribute with a drawer that is unconstrained:

    Code (CSharp):
    1. // Declare an attribute to use
    2. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    3. public sealed class UnconstrainedRangeAttribute : Attribute
    4. {
    5.     public readonly float Min;
    6.     public readonly float Max;
    7.  
    8.     public UnconstrainedRangeAttribute(float min, float max)
    9.     {
    10.         this.Min = min;
    11.         this.Max = max;
    12.     }
    13. }
    14.  
    15. // In an editor script somewhere, declare the drawer
    16. [OdinDrawer]
    17. public sealed class UnconstrainedRangeAttributeFloatDrawer : OdinAttributeDrawer<UnconstrainedRangeAttribute, float>
    18. {
    19.     /// <summary>
    20.     /// Draws the property.
    21.     /// </summary>
    22.     protected override void DrawPropertyLayout(IPropertyValueEntry<float> entry, UnconstrainedRangeAttribute attribute, GUIContent label)
    23.     {
    24.         entry.SmartValue = label == null ?
    25.             EditorGUILayout.Slider(entry.SmartValue, attribute.Min, attribute.Max) :
    26.             EditorGUILayout.Slider(label, entry.SmartValue, attribute.Min, attribute.Max);
    27.     }
    28. }
     
    brisingre likes this.
  21. brisingre

    brisingre

    Joined:
    Nov 8, 2009
    Posts:
    252
    Thanks for the quick response!

    ButtonBool and the workaround for statics worked perfectly.

    UnconstrainedFloat is giving me problems. The value clamps to max even if I type a larger number in the text field. I made some changes and got something that technically has the functionality I'm looking for, but it's super awkward to use.

    Code (CSharp):
    1. // Declare an attribute to use
    2. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    3. public sealed class UnconstrainedRangeAttribute : Attribute
    4. {
    5.     public readonly float Min;
    6.     public readonly float Max;
    7.  
    8.     public UnconstrainedRangeAttribute(float min, float max)
    9.     {
    10.         this.Min = min;
    11.         this.Max = max;
    12.     }
    13. }
    14.  
    15. // In an editor script somewhere, declare the drawer
    16. [OdinDrawer]
    17. public sealed class UnconstrainedRangeAttributeFloatDrawer : OdinAttributeDrawer<UnconstrainedRangeAttribute, float>
    18. {
    19.     /// <summary>
    20.     /// Draws the property.
    21.     /// </summary>
    22.     protected override void DrawPropertyLayout(IPropertyValueEntry<float> entry, UnconstrainedRangeAttribute attribute, GUIContent label)
    23.     {
    24.         if(entry.SmartValue < attribute.Max)
    25.         {
    26.             entry.SmartValue = label == null ?
    27.                 EditorGUILayout.Slider(entry.SmartValue, attribute.Min, attribute.Max) :
    28.                 EditorGUILayout.Slider(label, entry.SmartValue, attribute.Min, attribute.Max);
    29.  
    30.         }
    31.         else
    32.         {
    33.  
    34.             entry.SmartValue = label == null ?
    35.                 EditorGUILayout.FloatField(entry.SmartValue) :
    36.                 EditorGUILayout.FloatField(label, entry.SmartValue);
    37.         }
    38.     }
    39. }
    40.  
     
  22. brisingre

    brisingre

    Joined:
    Nov 8, 2009
    Posts:
    252
    Odin seems to be stopping me from building for OSX.
    upload_2017-11-25_15-39-14.png
     
  23. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    150
    It looks like you've enabled Odin's Editor Only Mode. When you do so, then, as noted in the description above the button you activate it with, you should delete Odin's demo scripts since they reference code that will no longer be available in builds.
     
  24. brisingre

    brisingre

    Joined:
    Nov 8, 2009
    Posts:
    252
    Thank you!
     
  25. Censureret

    Censureret

    Joined:
    Jan 3, 2017
    Posts:
    92
    Does anyone know how to make a dropdown with Tags using Odin inspector?
     
  26. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    150
    There is no built-in way of doing that in Odin, currently, but you can easily make your own attribute drawer for strings with that behaviour. See our manual for creating custom drawers, and also see the demo scene "2 - Custom Drawers Example" that comes with Odin, to learn how to create custom drawers.