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.3 has arrived! Read about it here.
    Dismiss Notice
  3. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

[RELEASED] Odin Inspector & Serializer - The Ultimate Workflow Tool ★★★★★

Discussion in 'Assets and Asset Store' started by jorisshh, Jun 15, 2017.

  1. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    156
    This is a known issue, and is related to limitations regarding 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. Sorry about this.
     
  2. Abuthar

    Abuthar

    Joined:
    Jul 12, 2014
    Posts:
    64
    Trying to figure out the serialization in Odin. I'd like to save Classes, which monobehaviour cannot do. However i can't figure out how to actually go from this:

    Code (CSharp):
    1.     public void SaveData()
    2.     {
    3.            
    4.             BinaryFormatter bf = new BinaryFormatter();
    5.             FileStream file = File.Create((System.IO.Path.GetDirectoryName(Application.persistentDataPath) + "file01.dat"));
    6.             SaveIndex index = new SaveIndex();
    7.  
    8.             index._lightData = lightData;
    9.  
    10.             bf.Serialize(file, index);
    11.             file.Close();
    12.     }
    to what odin is supposed to do. Is there a video or examples??
     
  3. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    Hey Abuthar,

    Normally you would just inherit from SerializedMonoBehaviour instead of MonoBehaviour or SerializedScriptableObject instead of ScriptableObject etc, and then Odin will take care of everything that Unity can't serialize.

    There are a lot of examples here:
    http://sirenix.net/odininspector/faq/30/why-is-odin-not-serializing-or-showing-my-field-or-property

    You can also use Odin much like you would use the BinaryFormatter, like in your example. We do have a lot of utilities that makes it a little more convinient though, more on that here:
    http://sirenix.net/odininspector/fa...t-inheriting-from-serializedmonobehaviour-etc
     
  4. Abuthar

    Abuthar

    Joined:
    Jul 12, 2014
    Posts:
    64
    So my serializable class which i want to add to multiple objects and collect into an array 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.  
    Now I am using Unity's binary formatter to save and load. And that script 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. 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.  
    However, on trying to save i get this error:

    SerializationException: Type Sirenix.OdinInspector.SerializedMonoBehaviour in assembly Sirenix.Serialization, Version=1.0.5.1, Culture=neutral, PublicKeyToken=null is not marked as serializable.
    System.Runtime.Serialization.FormatterServices.GetSerializableMembers (System.Type type, StreamingContext context) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Runtime.Serialization/FormatterServices.cs:101)...

    It's super long, but that's the beginning of it. I'm assuming I am doing something wrong? I don't come from a Programming background so I might not be seeing the obvious.
     
  5. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    156
    Hi, I replied to your other post here. Hope it helps explain what's going on!
     
  6. Abuthar

    Abuthar

    Joined:
    Jul 12, 2014
    Posts:
    64
    Thanks! I figured it out without using Odin, I was able to serialize an array of classes full of variables with no problem! :)
     
    bjarkeck likes this.
  7. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    432
    Hi there! I met a problem with Odin serializing Lists
    When I got a list of my own class which contains an enum variable in it.
    The odin serialized list can not let me choose the enum properly.
    When the list got more than one element, no matter which element's enum I manipulate, it changes the next element's enum value.

    It does not appear with unity's list drawer.
     
  8. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    156
    This sounds like a bug that we're aware of, but that we have yet to be able to reproduce, because nobody who's had it has been able to send us example code that reproduces the problem. Can you send us a code snippet that we can paste in and test with, to reproduce the problem?
     
  9. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    432
    Sure, I'll try to simplify my code and send you a sample.

    Edit: Sent you a PM with sample codes.
     
    Last edited: Oct 24, 2017
  10. JoeFernaldSG

    JoeFernaldSG

    Joined:
    Apr 3, 2017
    Posts:
    9
    Hello,

    I'm in the process of trying to re-write one of our more complicated custom inspectors and replacing it with Odin. After an initial implementation pass I've got a few questions I'd like to ask.

    1) Our current custom inspector accesses data contained with in a scriptable object in order to populate a list of floats and an animation curve in a game objects inspector. How would one go about using Odin to do something similar?

    2) There is one behavior in our custom inspector that I have yet to see a solution for in Odin. Our custom inspector has a list of elements in it, these elements can be edited one at a time (like changing their name or setting offsets) or they can all be selected and you can change the offsets on all objects in the list using the same data entry box. Is there any way to reproduce similar behavior in Odin?

    3) The ListDrawerSettings allows you to show a label for each object in the list such as Item 1. Is there any way to do this with the [TableList] attribute? I tried using the list drawer settings but they had no effect.

    4) Is there a way to use the GUIColor option to essentially just color the Fold Out Group header in the inspector? When I set the color it seems to do it for everything in the fold out group and doesn't effect the header at all.

    5) Is there any way to display an Array or List<> as Tabs? Think about having a list of sprites or some such where each list element is in another tab, and shows you the public/serialized variables on those game objects in the tab.

    6) I'm having a little bit of difficulty with the InlineEditor attribute. I've got a class that contains a GameObject, this game object has a mesh renderer (it is essentailly a sprite) on it and I was trying to get a small preview of what the sprite looked like to show up.

    This is the code:

    [System.Serializable]
    public class SpriteData
    {
    [SerializeField, InlineEditor(InlineEditorModes.SmallPreview)]
    private GameObject SpritePrefab;

    [SerializeField]
    private string Name;

    [SerializeField]
    private int TopStrength;

    [SerializeField]
    private int BottomStrength;

    [SerializeField]
    private int NumberToPreload;
    }

    public class MyMonoBehaviour: MonoBehaviour
    {
    [SerializeField, TabGroup("Sprites"), TableList]
    private List<SpriteData> sprites = new List<SpriteData>();
    }

    Unfortunately the result I'm getting is not what I expected to see: Inspector.png SpritePrefab.png
     
  11. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    156
    This is one of those questions with an infinity of answers that are variations of "yes", and I'm not sure which applies better without a more detailed example of exactly what you want or need.

    Essentially, though, it sounds like you need to either use an [OnInspectorGUI] method to contain the logic that populates a shown property or field with the data to display, or an [InlineEditor] for the ScriptableObjects themselves to display the data in them.

    This isn't a thing Odin does out of the box, but it wouldn't actually be that hard to create a drawer that does it, once you become familiar with the basics of Odin's drawing and property system. I thought this was a really sweet idea, so I actually gave it a shot. I've tested it a bit, and it actually seems to work quite well, I think!

    Here's the code for the drawer - you can of course tweak it as you like:

    Code (CSharp):
    1. using System;
    2.  
    3. #if UNITY_EDITOR
    4.  
    5. using UnityEngine;
    6. using System.Linq;
    7. using Sirenix.OdinInspector;
    8. using System.Collections.Generic;
    9. using Sirenix.OdinInspector.Editor;
    10. using Sirenix.Utilities.Editor;
    11.  
    12. #endif
    13.  
    14. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    15. public class MultiEditableListAttribute : Attribute
    16. {
    17. }
    18.  
    19. #if UNITY_EDITOR
    20.  
    21. [OdinDrawer]
    22. public class MultiEditableListAttributeDrawer<TList, TElement> : OdinAttributeDrawer<MultiEditableListAttribute, TList>
    23.     where TList : IList<TElement>
    24. {
    25.     private class ValueContainer
    26.     {
    27.         [ShowInInspector]
    28.         public TElement Element;
    29.     }
    30.  
    31.     private class Context
    32.     {
    33.         public GUIContent Label;
    34.         public LocalPersistentContext<bool> IsVisible;
    35.         public PropertyTree Tree;
    36.         public bool CreateNewTree = true;
    37.     }
    38.  
    39.     protected override void DrawPropertyLayout(IPropertyValueEntry<TList> entry, MultiEditableListAttribute attribute, GUIContent label)
    40.     {
    41.         PropertyContext<Context> context = entry.Context.Get(this, "context", (Context)null);
    42.  
    43.         if (context.Value == null)
    44.         {
    45.             context.Value = new Context()
    46.             {
    47.                 IsVisible = entry.Context.GetPersistent<bool>(this, "IsVisible", false),
    48.                 Label = label == null ? new GUIContent("Multi-edit") : new GUIContent("Multi-edit " + label.text)
    49.             };
    50.  
    51.             // Whenever the list or something in it changes, we must recreate the property tree
    52.  
    53.             Action<int> onListChanged = (_) =>
    54.             {
    55.                 context.Value.Tree = null;
    56.                 context.Value.CreateNewTree = true;
    57.             };
    58.  
    59.             entry.OnValueChanged += onListChanged;
    60.             entry.OnChildValueChanged += onListChanged;
    61.         }
    62.  
    63.         SirenixEditorGUI.BeginBox();
    64.         {
    65.             SirenixEditorGUI.BeginBoxHeader();
    66.             context.Value.IsVisible.Value = SirenixEditorGUI.Foldout(context.Value.IsVisible.Value, context.Value.Label);
    67.             SirenixEditorGUI.EndBoxHeader();
    68.  
    69.             if (SirenixEditorGUI.BeginFadeGroup(context, context.Value.IsVisible.Value))
    70.             {
    71.                 if (context.Value.Tree == null && context.Value.CreateNewTree)
    72.                 {
    73.                     ValueContainer[] valuesToMultiEdit = entry.SmartValue
    74.                         .Where<TElement>(n => !object.ReferenceEquals(n, null))
    75.                         .Distinct()
    76.                         .Select(n => new ValueContainer() { Element = n })
    77.                         .ToArray();
    78.  
    79.                     if (valuesToMultiEdit.Length == 0)
    80.                     {
    81.                         context.Value.CreateNewTree = false;
    82.                     }
    83.                     else
    84.                     {
    85.                         context.Value.Tree = PropertyTree.Create(valuesToMultiEdit);
    86.  
    87.                         context.Value.Tree.OnPropertyValueChanged += (prop, _) =>
    88.                         {
    89.                             string path = prop.Path;
    90.  
    91.                             if (prop.Parent == null)
    92.                             {
    93.                                 path = "";
    94.                             }
    95.                             else if (prop.Path.StartsWith("Element."))
    96.                             {
    97.                                 path = path.Substring(prop.Path.IndexOf('.'));
    98.                             }
    99.  
    100.                             for (int i = 0; i < entry.Property.Children.Count; i++)
    101.                             {
    102.                                 var actualProperty = entry.Property.Tree.GetPropertyAtPath(entry.Property.Children[i].Path + path);
    103.  
    104.                                 if (actualProperty != null && actualProperty.ValueEntry != null)
    105.                                 {
    106.                                     for (int j = 0; j < actualProperty.ValueEntry.ValueCount; j++)
    107.                                     {
    108.                                         try
    109.                                         {
    110.                                             actualProperty.ValueEntry.WeakValues[j] = prop.ValueEntry.WeakValues[j];
    111.                                         }
    112.                                         catch { } // Ignore cast exceptions - only change what we can
    113.                                     }
    114.                                 }
    115.                             }
    116.                         };
    117.                     }
    118.                 }
    119.  
    120.                 if (context.Value.Tree == null)
    121.                 {
    122.                     GUIHelper.PushGUIEnabled(false);
    123.                     GUILayout.Label("No elements to edit");
    124.                     GUIHelper.PopGUIEnabled();
    125.                 }
    126.                 else
    127.                 {
    128.                     InspectorUtilities.BeginDrawPropertyTree(context.Value.Tree, withUndo: false);
    129.  
    130.                     var elementProp = context.Value.Tree.GetPropertyAtPath("Element");
    131.  
    132.                     for (int i = 0; i < elementProp.Children.Count; i++)
    133.                     {
    134.                         elementProp.Children[i].Draw();
    135.                     }
    136.  
    137.                     InspectorUtilities.EndDrawPropertyTree(context.Value.Tree);
    138.                 }
    139.             }
    140.             SirenixEditorGUI.EndFadeGroup();
    141.         }
    142.         SirenixEditorGUI.EndBox();
    143.  
    144.         // Draw the actual list
    145.         this.CallNextDrawer(entry, label);
    146.     }
    147. }
    148.  
    149. #endif
    NOTE: You'll need to upgrade to the newly released Odin 1.0.5.2 in order to get the new PropertyTree.OnPropertyValueChanged event, which this drawer uses.

    With that in your project, you can just add [MultiEditableList] to any list of yours, and it becomes multi-editable, like so:

    [​IMG]

    If you have any questions about how it works, feel free to hop in on Discord and ask away!

    I'm afraid this isn't possible at the moment - we'll need to do a pass over [TableList] at some point and bring it up to the standards of the regular list drawer. For now, you'll have to use, for example, a string field placed first in the order as the "label" of that element, which is almost as good (if you want name labels - if you want indices, I'm afraid you're out of luck for now)!

    I'm afraid there isn't, right now. Probably later in Odin 1.1 with the upgraded property/attribute system, this will become more easily possible. What you *can* do is check out the source for the current FoldoutGroup (FoldoutGroupAttribute.cs and FoldoutGroupAttributeDrawer.cs), and based on that create a new ColoredFoldoutGroup that can take a color as a group argument.

    There isn't strictly a way of doing this directly, however what you can do is use [ListDrawerSettings(NumberOfItemsPerPage = 1)] so that the list paging only shows one element per page - essentially achieving the same effect.

    GameObjects don't currently show up in the InlineEditor previews, unless they have a graphical preview that Unity can draw. Most GameObjects with graphics and meshes will get a preview graphic, but not all - it depends on whether the GameObject gets a preview at the bottom of the inspector if you select it, as that's what Odin draws there.

    We don't currently pull out all the components and render a full inspector for a GameObject, though possibly we'll do that in the future if it can be done in a way that isn't super painful and/or super hacky and unreliable - so far, we haven't figured one out.

    Experimenting with your example, most often it's the case that the GameObject has no preview graphic (as in your screenshots). However, when there is a graphic, it seems that the layouting is messed up a bit, and you have to expand the column quite a bit to view the full preview. We'll have to look into that - I'll put it on our todo list.

    I hope all of that was at least a little helpful!
     
    Last edited: Oct 27, 2017
    JoeFernaldSG likes this.
  12. MoribitoMT

    MoribitoMT

    Joined:
    Jun 1, 2013
    Posts:
    141
    Such a great tool, however needs to be matured more, some feature still lacks behind AdvancedInspector.

    I use this kind of tools mainly analyze inside of my collections.

    For example, here AdvancedInspector can achieve. In this example I can go into my lists see their list elements and even go deeper into list objects ( monobehaviour or not ). I also had problems with Dictionaries, those not even appeared in my inspector with Odin.

    AdvancedInspector ( I can do very deep analysing )
    TimedEventsManaager ( MonoBehaviour )
    - CountDownStampsList ( List collection )
    -- CountDownStamp ( Non-Monobehaviour class )
    -- CountDownStamp ( Non-Monobehaviour class )
    -- CountDownStamp ( Non-Monobehaviour class )
    -- CountDownStamp ( Non-Monobehaviour class )
    -- etc..
    Screen Shot 2017-10-29 at 16.53.46.png
     
  13. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    156
    I will admit, I'm uncertain what exactly you are missing in Odin. All of what you describe, and what you show in the screenshot, as far as I can tell, is perfectly possible in Odin. Could you perhaps clarify a little further what exactly you think Odin is missing?

    As for the dictionaries now always showing up, that would be a distinction of when Odin is serializing something, versus when Unity is serializing something. By default, Odin doesn't serialize the things that Unity serializes, and the serialization of a member is always decided at the "root level" of the component, so if your dictionary is nested inside a class that's being serialized by Unity instead of Odin, then it won't show up, as it's not being serialized. You can see this FAQ answer for more details on when something is serialized by Odin versus Unity.
     
    MoribitoMT likes this.
  14. Westy661

    Westy661

    Joined:
    Sep 13, 2015
    Posts:
    11
    Hi guys!
    I recently purchased Odin, and still learning how to use it. I think its really great, but i have a few unsolved problems. Can you guys help in them?

    - Firstly, i would like to expand a list when the user clicks on a custom button i just created. My problem is, that i cant find a way to get the reference for the ListDrawerSettings decorator on my list.

    - I would like to have a little space before the first and after the last element of a list. I guess the solution will be connected to "OnBeginListElementGUI", but i cant find any SirenixEditorGUI method to insert spacing.

    #Update: as i found out a lot about the asset i changed my question multiple times. Sorry for that. :)

    Thank you vey much in advance,
    Peter
     
    Last edited: Oct 31, 2017
    bjarkeck likes this.
  15. Enoch

    Enoch

    Joined:
    Mar 19, 2013
    Posts:
    170
    Is there a way to display a color picker in Odin that does HDR? I seem to be having trouble when I mix the unity ColorUsageAttribute with Odin. When the attribute is applied I can no longer edit the colors (the HDR color picker comes up but it doesn't change the value)?

    Update: I got around this by adding the [DrawWithUnity] attribute.
     
    Last edited: Oct 31, 2017
    bjarkeck likes this.
  16. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    Hey Peter, no worries :)

    You can't currently (easily) hook into the internal variables of the list-drawer such as whether or not the list it is expanded. But you could just add a ShowIf attribute, and reference a boolean member which you have control over. And regarding the added space, you are on the right track! We don't have a Space in SirenixEditorGUI because Unity already has one in GUILayout, so you can just use that.

    Putting it all together it could look something like this. The PropertyOrders and Begin/End foldout is just a suggestion that may give you some inspiration. hope that helps.

    Code (CSharp):
    1.     public bool showList = false;
    2.  
    3.     [ShowIf("showList"), PropertyOrder(1)]
    4.     [ListDrawerSettings(OnBeginListElementGUI = "DrawSpace", OnEndListElementGUI = "DrawSpace", Expanded = true)]
    5.     public List<GameObject> someList;
    6.  
    7.     [OnInspectorGUI, PropertyOrder(0)]
    8.     private void BeginFoldout()
    9.     {
    10.         SirenixEditorGUI.BeginBox();
    11.         SirenixEditorGUI.BeginBoxHeader();
    12.         this.showList = SirenixEditorGUI.Foldout(this.showList, "Show List");
    13.         SirenixEditorGUI.EndBoxHeader();
    14.         SirenixEditorGUI.BeginFadeGroup(this, this.showList);
    15.     }
    16.  
    17.     [OnInspectorGUI, PropertyOrder(2)]
    18.     private void EndFoldout()
    19.     {
    20.         SirenixEditorGUI.EndFadeGroup();
    21.         SirenixEditorGUI.EndBox();
    22.     }
    23.  
    24.     private void DrawSpace(int index)
    25.     {
    26.         GUILayout.Space(20);
    27.     }
     
  17. Westy661

    Westy661

    Joined:
    Sep 13, 2015
    Posts:
    11
    Thank you very much for your answer!

    Your solution for the foldout expand creates two headers for my list (one because of the foldout, and one for the list itself), which clusters a view a bit, so i decided to wait for future releases, and hope the function will find a way in sometime. The idea on the other hand teached me a lot about the creative use of Odin, so thank you very much for your answer, and the time you invested in it.

    I for some reason tought that GUILayout.Space can be only used in editor code, but i guess at the end Odin hooks into unitys editor system, so i can use any vanila unity editor functionalities. :)
     
  18. Westy661

    Westy661

    Joined:
    Sep 13, 2015
    Posts:
    11
    I would like to ask one more question.

    Im looking for an autofilter search bar component, not unlike your polymorphic item picker.
    As far as i can tell Odin does not have this feature, and i want to write a custom drawer to implement that.

    Can you guys point me to the right direction where to start it?

    Here is the detailed solution i'am loking for:

    [IntelligentSearchBar("GetAllItems", "itemName", "itemCategory")]
    public Item selectedItem;

    public IntelligentSearchBar(List<T> itemsToFilter, string propertyToDisplay, string propertyToFilter);
    [...]

    The searchbar should work as the following:
    - It would be a one line textbox, with a magnfying glass on the right side
    - When i start to type it would show (under the text field like google quick search) the "propertyToDisplay" property of every itemsToFilter list member.
    - After i typed something, it would filter the list by comparing "propertyToFilter" to the text i typed (with contains)
    - When i click on an item, selectedItem would be set to that item, and the textbox would display selectedItem.propertyToDisplay

    In this exampe the lsit would be filtered by category, but the output would be the name of each item in the filtered category (or categories). A more simple case would be "itemName" in the propertyToFilter field, in which case it would be a simple intelligent search for a field.
     
  19. Stef_Morojna

    Stef_Morojna

    Joined:
    Apr 15, 2015
    Posts:
    280
    Is it possible to serialize static variables? (I hope the answer isn't somewhere really obius, and I just didn't find it)

    Also is it possible to disable the sprite that Odin uses for the icons? my entire select sprite menu is full of them.
     
    Last edited: Nov 4, 2017
  20. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    Cool idea! I'm very curious as to what you end up with :)

    We have a similar WIP attribute, I think it's called SelectList, or ToggleList - something like that. It works much like the ValueDropDown attribute, but instead of a dropdown it's a box you can search for items in etc, much like you described.. It maybe look like the like the AssetList attribute currently does, but instead of it being only for assets, it would only be for whatever you provide it with. We've been wanting this for a long time now.

    Have you seen our drawer section in our manual, and the drawer example demo scenes? I think that would be the best place to start, making an attribute drawer. I would also suggest unzipping the source-code and take a the drawers there. You are also more than welcome to join us on Discord, if you want some help or tips that requires a bit of back and forth :)

    Yes you can, but you would need to trigger the serialization and deserialization manually from somewhere. http://sirenix.net/odininspector/fa...t-inheriting-from-serializedmonobehaviour-etc

    If you want to just show a static value in the inspector, you can use a property with and put a ShowInInspector on it: http://sirenix.net/odininspector/faq/41/how-can-i-show-static-fields-and-properties-in-the-inspector

    Not currently I'm afraid, but we'll make sure to embed the png file into the Sirenix.Utilities.Editor.dll and get rid of the asset completely, that way it won't show up and bother you in the future :)
     
    Last edited: Nov 4, 2017
    Westy661 likes this.
  21. Korindian

    Korindian

    Joined:
    Jun 25, 2013
    Posts:
    322
    Hi, I'm not able to right-click on color fields to copy colors. Here is the long console error (Note that the smiley faces are because of the colon and D characters adjacent to each other):


    InvalidCastException: Specified cast is not valid.
    Sirenix.OdinInspector.Editor.Drawers.ColorDrawer.PopulateGenericMenu[T] (Sirenix.OdinInspector.Editor.IPropertyValueEntry`1[TValue] entry, UnityEditor.GenericMenu genericMenu) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/ColorDrawer.cs:72)
    Sirenix.OdinInspector.Editor.Drawers.Color32Drawer.Sirenix.OdinInspector.Editor.IDefinesGenericMenuItems.PopulateGenericMenu (Sirenix.OdinInspector.Editor.InspectorProperty property, UnityEditor.GenericMenu genericMenu) (at <dc3c6ee119b9421cb4cd3cb0032203ee>:0)
    Sirenix.OdinInspector.Editor.InspectorProperty.PopulateGenericMenu (UnityEditor.GenericMenu genericMenu) (at <dc3c6ee119b9421cb4cd3cb0032203ee>:0)
    Sirenix.OdinInspector.Editor.Drawers.PropertyContextMenuDrawer`1[T].DrawPropertyLayout (Sirenix.OdinInspector.Editor.IPropertyValueEntry`1[TValue] entry, UnityEngine.GUIContent label) (at <dc3c6ee119b9421cb4cd3cb0032203ee>:0)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1[T].DrawProperty (Sirenix.OdinInspector.Editor.IPropertyValueEntry`1[TValue] entry, UnityEngine.GUIContent label) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1[T].DrawPropertyImplementation (Sirenix.OdinInspector.Editor.InspectorProperty property, UnityEngine.GUIContent label) (at <dc3c6ee119b9421cb4cd3cb0032203ee>:0)
    Sirenix.OdinInspector.Editor.OdinDrawer.DrawProperty (Sirenix.OdinInspector.Editor.InspectorProperty property, UnityEngine.GUIContent label) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.InspectorUtilities.DrawProperty (Sirenix.OdinInspector.Editor.InspectorProperty property, UnityEngine.GUIContent label) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:601)
    Rethrow as OdinPropertyException: This error occurred while being drawn by Odin.
    Odin Property Path: allScenarios.$0.settings.skybox.nebulaRipples1Tint
    Odin Drawer Chain: PropertyContextMenuDrawer<Color32>, LabelWidthAttributeDrawer, TooltipAttributeDrawer, PrimitiveValueConflictDrawer<Color32>, Color32Drawer, CompositeDrawer.
    UnityEngine.Debug:LogException(Exception)
    Sirenix.OdinInspector.Editor.InspectorUtilities:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:601)
    Sirenix.OdinInspector.Editor.InspectorUtilities:DrawProperty(InspectorProperty) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:527)
    Sirenix.OdinInspector.Editor.Drawers.CompositeDrawer:DrawPropertyImplementation(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/ListDrawer.cs:308)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.NullableReferenceDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.ReferenceValueConflictDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Misc Drawers/PropertyContextMenuDrawer.cs:302)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.ReferencePathConflictDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Misc Drawers/PropertyContextMenuDrawer.cs:249)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.HeaderAttributeDrawer:DrawPropertyLayout(InspectorProperty, HeaderAttribute, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Group Drawers/HorizontalGroupAttributeDrawer.cs:62)
    Sirenix.OdinInspector.Editor.OdinAttributeDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:103)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(IPropertyValueEntry, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.FixUnityNullDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.ReferenceDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(IPropertyValueEntry, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.PropertyContextMenuDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.InspectorUtilities:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:601)
    Sirenix.OdinInspector.Editor.InspectorUtilities:DrawProperty(InspectorProperty) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:527)
    Sirenix.OdinInspector.Editor.Drawers.CompositeDrawer:DrawPropertyImplementation(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/ListDrawer.cs:308)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.NullableReferenceDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.ReferenceValueConflictDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Misc Drawers/PropertyContextMenuDrawer.cs:302)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.ReferencePathConflictDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Misc Drawers/PropertyContextMenuDrawer.cs:249)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.SpaceAttributeDrawer:DrawPropertyLayout(InspectorProperty, SpaceAttribute, GUIContent)
    Sirenix.OdinInspector.Editor.OdinAttributeDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:103)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(IPropertyValueEntry, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.FixUnityNullDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.ReferenceDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(IPropertyValueEntry, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.PropertyContextMenuDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.InspectorUtilities:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:601)
    Sirenix.OdinInspector.Editor.InspectorUtilities:DrawProperty(InspectorProperty) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:527)
    Sirenix.OdinInspector.Editor.Drawers.CompositeDrawer:DrawPropertyImplementation(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/ListDrawer.cs:308)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.NullableReferenceDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawPropertyImplementation(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(InspectorProperty, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:283)
    Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(InspectorProperty, GUIContent)
    Sirenix.OdinInspector.Editor.Drawers.ReferenceValueConflictDrawer`1:DrawPropertyLayout(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Misc Drawers/PropertyContextMenuDrawer.cs:302)
    Sirenix.OdinInspector.Editor.OdinValueDrawer`1:DrawProperty(IPropertyValueEntry`1, GUIContent) (at C:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Infos/InspectorPropertyInfo.cs:1065)
    Sirenix.O<message truncated>
     
  22. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    Thanks, I assume you are using a Color32 right? This is fixed in the next patch.
     
  23. Korindian

    Korindian

    Joined:
    Jun 25, 2013
    Posts:
    322
    Yes, Color32. Thanks!
     
  24. slimshader

    slimshader

    Joined:
    Jun 11, 2013
    Posts:
    95
    Hey, fantastic asset! I have a problem tho: I am trying to create custom Editor Window with persistent settings via GlobalConfig<>. I would like this custom window to embed that GlobalConfig (so that settings can be edited directly in that windows and not in separate Inspector of GlobalConfig derivative). Something along:
    Code (CSharp):
    1.     [InlineEditor(InlineEditorModes.GUIOnly)]
    2.     public EditorConfig Settings;
    3.  
    4.     void OnEnable()
    5.     {
    6.       Settings = EditorConfig.Instance;
    7.     }
    8.  
    9.     // where EditorConfig : GlobalConfig<EditorConfig>
    Unfortunately this does not persist changes across Unity runs and even weirder, editing via InlineEditor marks the scene as edited :/ Please advise

    EDIT: Unity 2017.2, .NET 4.6 mode
     
    Last edited: Nov 6, 2017
  25. ben_unity409

    ben_unity409

    Joined:
    Nov 6, 2017
    Posts:
    1
    Hey, I'm displaying some data using BeginDrawPropertyTree() and EndDrawPropertyTree():

    Code (CSharp):
    1.     [InlineEditor(InlineEditorModes.GUIOnly)]
    2.             InspectorUtilities.BeginDrawPropertyTree(SerializedLevel, false);
    3.             SerializedLevel.GetPropertyAtPath("Cutscenes").Children[SelectedCutsceneIndex].Draw();
    4.             InspectorUtilities.EndDrawPropertyTree(SerializedLevel);
    5.  
    The actual cutscene being drawn is very small -- some dictionaries and lists, <1kb of data -- but it takes about 100ms to update every OnGUI(), which means 100ms between keystrokes, which is pretty hard to use. The profiler says about half the time is taken in BeginDrawPropertyTree(), with another ~7% in EndDrawPropertyTree().

    upload_2017-11-6_10-33-4.png

    How can I improve this workflow? (Can I make property trees out of branches of my level's property tree? Are there switches I can flip?)
     
  26. Silverlode

    Silverlode

    Joined:
    Apr 9, 2013
    Posts:
    35
    Is it possible for Odin to draw represent a list of objects in a 2D view? Imagine I have a class (perhaps a scriptable object) that has:

    public class Monster : ScriptableObject
    {
    public int level;
    public int damage;
    public int XpWhenKilled;
    public string name;
    public string description;
    public int speed;
    public int lootQuality;
    }

    And I want to visualize a List<Monster> in the inspector, such that its easy to compare one monster to another, so every row is a monster and every column a field of the Monster class (level, damage, etc). A bit like a crude spreadsheet.

    If this is possible, could you give me some points where to start? I couldn't find an example this, so perhaps it can't be done?
     
  27. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    This is strange. And does the changes persist if you select the scriptable object in the project window, and modifying the values in the inspector? GlobalConfig is not being serialized by Odin, so If not, it could be because you are showing some values that are not actually being serialized at all? More info here: http://sirenix.net/odininspector/faq/30/why-is-odin-not-serializing-or-showing-my-field-or-property
     
  28. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    Hey Ben,

    Not sure what is meant by the InlineEditor attribute from your example. But the rest of the code looks good to me. But the property tree is made for the not only the Cutscenes property, so even though you're only drawing the Cutscenes, Odin is updating all of the properties for the SerializedLevel property target. So if that is huge, that could be it. It's a longshot, but if that is the case, you could try and create the property tree for the only the Cutscenes property, and then just draw the entire tree, you will probably just need to call SetDirty yourself on the scriptable object when something is changed, as Odin, in that case, don't have any knowledge of it. Another possibility is that the PropertyTree.Create is called every frame, which we've seen people do a couple of times. It should only be created once and cached somewhere.

    Hope some of it helps.
     
  29. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    Like this? - not that it's the ideal way to render the table, but you get the idea :)
    f.png
    (There is no particular reason that SomeMonoBehaviour is a SerializedMonoBehaviour btw)

    If Monster is a ScriptableObject, it becomes a little more difficult, since it would be rendered as an object field. But it's possible to get around that as well, it would just require some typing, let me know if you want pointers for that as well :)
     
    slimshader likes this.
  30. Barabicus

    Barabicus

    Joined:
    Jun 5, 2013
    Posts:
    133
    Hey, I'm trying to create an attribute drawer to easily style a main title for several scripts I've been writing. Basically just draw something based on a string. I've been doing something like this which works well

    Code (CSharp):
    1.         [PropertyOrder(-10), OnInspectorGUI]
    2.         private void OnInspectorGUI()
    3.         {
    4.             CTEditorUtility.DrawInspectorTitle("Unit Attributes");
    5.         }
    But I was thinking of creating an attribute to really minimize it. So it would essentially have the same drawing logic as above but I could just easily do

    Code (CSharp):
    1. [MainHeaderTitle]
    2. private string Title => "Unit Attributes";
    The problem is, it just won't show. I can add the ShowInInspector attribute but it doesn't really work quite the way I want it. It appears disabled. Also seems to have a greater property order by default? I'm not sure it will just always appear towards the bottom of the inspector where seralized fields appear towards the top.

    I can do this which works exactly as I want it

    Code (CSharp):
    1. [MainHeaderTitle]
    2. public string Title = "Unit Attributes";
    But it just doesn't seem right to seralize something that is only required for the Unity Editor. Also I'm trying to learn and get a better idea of how Odin works so I'd be interested in how this could be accomplished regardless.

    Oh I should also point out I don't want the actual string to be shown in a label field, rather to replace it completely with my own drawing logic.

    This is what I'm currently using as a drawer for sake of demonstration. I commented out call next drawer so the actual string field won't be shown. I don't know if this is considered bad practice however.

    Code (CSharp):
    1.     [OdinDrawer]
    2.     public class CTTitleAttributeDrawer : OdinAttributeDrawer<CTTitleAttribute, string>
    3.     {    
    4.         protected override void DrawPropertyLayout(IPropertyValueEntry<string> entry, CTTitleAttribute attribute, GUIContent label)
    5.         {        
    6.             var titleText = entry.SmartValue;
    7.  
    8.             CTEditorUtility.DrawInspectorTitle(titleText);
    9.  
    10.             // Continue the drawer chain.
    11.            // this.CallNextDrawer(entry, label);
    12.         }
    13.     }
    Any help would be really appreciated! :)
     
  31. SeanPalmer

    SeanPalmer

    Joined:
    May 30, 2015
    Posts:
    2
    Is there a way to prevent the resizing of an array (or any collection) while still allowing its elements to be altered?

    I'd love to learn that there is some sort of [FixedLengthList] attribute that I don't know about.

    Btw this tool is amazing and thank you so much for making it!
     
    Last edited: Nov 14, 2017
  32. indie_dev85

    indie_dev85

    Joined:
    Mar 7, 2014
    Posts:
    26
    After Updating to 1.0.5.3 i am facing some serious issues.

    I have a class referencing serializedMonobehaviour, a Dictionary<enum,class A objects> of serialized classes A with structure shown below saved by 1.0.5.

    [Serialized]
    class A
    {
    Dictionary < Enum, class B object>
    }
    Now as soon as i made any change to the scene and save it , boom all the entries in the A dictionaries are gone.This issue is NOT happening when using 1.0.5, but its causing issues when adding dictionary entries using enum as key.

    Kindly let me know why i am facing these issues on 2017.1.2f1 using Odin 1.0.5.3.

    Thanks
     
    Last edited: Nov 10, 2017
  33. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    156
    Hi, and sorry for the late reply. So much is going on, sometimes we forget to check back on the forum every day!

    You need to make sure that CTTitleAttribute inherits from ShowInInspector. I realize this may not be perfect, but for now it's the only way to cause your attribute to force the member to show up. We'll extend this in Odin 1.1, but for now, it's how it has to be.

    As for the GUI appearing disabled, it is because what you do there is a shortform for declaring a readonly property, and Odin disabled the GUI for readonly properties, so they can't be modified. Essentially, you can just force the GUI to be enabled anyways - like so:

    Code (CSharp):
    1. [OdinDrawer]
    2. public class CTTitleAttributeDrawer : OdinAttributeDrawer<CTTitleAttribute, string>
    3. {  
    4.     protected override void DrawPropertyLayout(IPropertyValueEntry<string> entry, CTTitleAttribute attribute, GUIContent label)
    5.     {      
    6.         var titleText = entry.SmartValue;
    7.  
    8.         GUIHelper.PushGUIEnabled(true);
    9.         CTEditorUtility.DrawInspectorTitle(titleText);
    10.         GUIHelper.PopGUIEnabled();
    11.  
    12.         // Continue the drawer chain.
    13.         // this.CallNextDrawer(entry, label);
    14.     }
    15. }
    Finally, not calling the next drawer in the chain is perfectly acceptable practice. That is, in fact, how you override the drawing. If you call the next drawer, you are instead "wrapping" the drawing of the property.

    Hope that helps!

    Not currently, but this isn't a bad idea - we'll add it to our UX todo list!

    I'm afraid that, after much trying, I've proven completely unable to replicate this. Dictionaries of all variants with enum keys or keys of any other type seem to persist perfectly fine. Can you please provide some code and steps to reproduce this issue?
     
  34. Barabicus

    Barabicus

    Joined:
    Jun 5, 2013
    Posts:
    133
    Hey that works perfect! Thanks for your response clears a lot of things up :)
     
  35. SeanPalmer

    SeanPalmer

    Joined:
    May 30, 2015
    Posts:
    2
    Well this is awkward; I edited my original post while you were responding to it... oops.
    I'll move the edit here for visibility:
    __________________
    I've come across a few more problems that I can't find answers to.

    I'm trying to use a [Button] to add elements to a list in the inspector. It seems to work at first, but the elements added by the button disappear upon saving or playing the scene. Elements added with traditional methods work fine. Edit: Nevermind, I reset the component and the button is working fine now.

    Also, is there a way to customize drag and drop behavior to allow types other than the type of the field? For example, if I had a float field "mass," I could specify that Rigidbody components could be dragged into it, and that '"mass" would be assigned the Rigidbody's mass value.

    Lastly I noticed a few bugs:

    The "Forums" link in the footer of your websites links to the old WIP forum post.
    If you rightclick on a list and set it to null Unity crashes.
    __________________
    Thanks for replying to my first post :)
     
    Last edited: Nov 15, 2017
    bjarkeck likes this.
  36. Wobbix

    Wobbix

    Joined:
    Sep 24, 2017
    Posts:
    1
    Forgive me if this has been answered elsewhere in thread, but if you do a search for all references of dictionary and dictionaries, you DO get the entire post. You say that dictionary keys are limited to primitives, guids and enums, but the value can be anything. Can ODIN properly display nested dictionaries, where a key maps to a dictionary that would then have its own key value pair, and, if so, does this behave similarly to what is seen in the introduction video, just with an extra level of nesting, or would one need to specifically inspect the inner dictionary to get such a display?
     
    bjarkeck likes this.
  37. Zymes

    Zymes

    Joined:
    Feb 8, 2017
    Posts:
    95
  38. Don-Gray

    Don-Gray

    Joined:
    Mar 18, 2009
    Posts:
    2,238
    I don't code, will this be of any benefit to me?
     
    bjarkeck likes this.
  39. aidesigner

    aidesigner

    Joined:
    May 2, 2012
    Posts:
    108
    Thank you for the excellent product and documentation (Potential customer).

    -For editor functionality do you only need to inherit from SerializedMonoBehaviour for the classes that contain types not serialized by Unity? Without this inheritance I assume dictionaries, auto properties, and interfaces will not show up in the editor?

    -I do not understand why you ever want Odin serialization inside of a build? Does Odin provide some type of save game functionality that uses Odin serialization? Alternatively is it done solely for the Editor features (i.e. dictionaries/interfaces) and therefore forced to have it in the builds?

    -The lack of Windows store support seems like a big deal. Even if I do plan for windows store build now, it is unwise to pick a utility that eliminates an entire platform. You touch on your window store road-map on this post, but what is the challenge and can it be solved?
     
    Last edited: Nov 16, 2017
    bjarkeck likes this.
  40. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    Pretty cool idea. You could quickly achieve this by using the CustomValueDrawer, and the new DropZoneUtilities class we introduced recently.

    Code (CSharp):
    1. public class SomeMonoBehaviour : MonoBehaviour
    2. {
    3.     [CustomValueDrawer("DrawMassField")]
    4.     public float Mass;
    5.  
    6.     private static float DrawMassField(float value, GUIContent label)
    7.     {
    8.         value = SirenixEditorFields.FloatField(label, value);
    9.         var rect = GUILayoutUtility.GetLastRect();
    10.         var rigidBody = DragAndDropUtilities.DropZone<Rigidbody>(rect, null);
    11.         if (rigidBody)
    12.         {
    13.             value = rigidBody.mass;
    14.         }
    15.  
    16.         return value;
    17.     }
    18. }
    Alternatively, if you wanted to do this sort of thing a lot you could create an attribute drawer with wrapper priority. It could look something like this.

    Usage:
    Code (CSharp):
    1. public class SomeMonoBehaviour : MonoBehaviour
    2. {
    3.     [DropZone(typeof(Rigidbody), "mass")]
    4.     public float Mass;
    5. }

    Attribute and Drawer:

    Code (CSharp):
    1. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
    2. public class DropZoneAttribute : Attribute
    3. {
    4.     public readonly Type Type;
    5.     public readonly string Member;
    6.  
    7.     public DropZoneAttribute(Type type, string member)
    8.     {
    9.         this.Type = type;
    10.         this.Member = member;
    11.     }
    12. }
    13.  
    14. [OdinDrawer]
    15. [DrawerPriority(DrawerPriorityLevel.WrapperPriority)]
    16. public class DropZoneAttributeDrawer : OdinAttributeDrawer<DropZoneAttribute>
    17. {
    18.     protected override void DrawPropertyLayout(InspectorProperty property, DropZoneAttribute attribute, GUIContent label)
    19.     {
    20.         this.CallNextDrawer(property, label);
    21.  
    22.         var value = DragAndDropUtilities.DropZone(property.LastDrawnValueRect, null, attribute.Type);
    23.         if (value != null)
    24.         {
    25.             string error;
    26.             MemberInfo memberInfo = value.GetType()
    27.                 .FindMember()
    28.                 .IsNamed(attribute.Member)
    29.                 .HasNoParameters()
    30.                 .HasReturnType(property.ValueEntry.BaseValueType, true)
    31.                 .IsInstance()
    32.                 .GetMember(out error);
    33.  
    34.             if (error != null)
    35.             {
    36.                 Debug.LogError(error);
    37.             }
    38.             else
    39.             {
    40.                 property.ValueEntry.WeakSmartValue = memberInfo.GetMemberValue(value);
    41.             }
    42.         }
    43.     }
    44. }

    Good catch, we'll have that fixed. Thanks a lot :)
     
    Last edited: Nov 17, 2017
  41. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    Hey Wobbix,

    It's true that in the beginning Odin was limited to only draw dictionaries with certain key-types. But that is no longer the case. Those limitations are now only present when using dictionaries with prefab-modifications. And yes, nested dictionaries is not a problem either. It would just draw it like you would expect, no special behavior there :)
     
    Last edited: Nov 17, 2017
  42. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    I would say so, if I've understood it correctly. I can think of countless cool ways to solve that problem with Odin.

    Here is one, where I've simply added the TableList attribute to the list of waypoints, and some properties to display the operation members inside the Waypoint class. The data structure is the same.

    test.png

    Another solution would be to just have the dictionary serialized and shown in the inspector with Odin.all you would need to do then is remove the list, inherit from SerializedMonoBehaviour and put SerializeField on the dictionary member. An whola :)

    Hope that helps.
     
  43. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    If there is no programmers involved, or/and everything is done with visual-scripting, then currently not a whole lot to be honest. You will notice a lot of small improvements like lists have suddenly become a lot better, right-clicking things now has a lot more options. But if you have a programmer on your team it quickly becomes a huge deal, for everyone involved. You'll start loving your programmer even more for making your life easy. And he'll be super motivated by it, and work twice as fast! At least :D
     
    Last edited: Nov 17, 2017
    Don-Gray likes this.
  44. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    All attributes and everything works right out of the bat, without inheriting from any special class. And you can always force a dictionary to be shown in the inspector using the [ShowInInspector] attribute. But simply displaying a dictionary in the inspector and being able to manipulate the data, is not enough to actually bring that data into your game, because Unity wont serialize it! The values will be lost as soon as you hit play, because Unity don't serialize dictionaries, properties, interfaces, generic types, etc...

    You could use other serilization systems such as the microsoft's BinaryFormatter, but it has no support for data containing Unity types, and you won't get the power of prefab-modifications. That is why you need some code in your game, that knows how load (and save) those data types Unity can't.

    Odin's serialization system is in fact compatible with windows store if you use IL2CPP as the scripting backed. Read more here: http://sirenix.net/odininspector/faq/16/does-the-serialization-support-windows-store-and-uwp

    And if you enable EditorOnly mode and don't need the serialization, then you have nothing to worry about. Nothing will be included in your build. Only a small assembly on a couple of kb's containing the attributes so that your game can compile.

    Hope that clears things up, and thanks for asking :)
     
  45. AmbroiseRabier

    AmbroiseRabier

    Joined:
    Dec 4, 2016
    Posts:
    12
    Hello folks,
    I'm trying to restrict a Serialized field values.I would allow reference from your own GameObject or one of your children GameObject. Is there a proper way to do it with Odin ? I like a display like the image bellow, I like to filter what is displayed (and authorized) for the SerializedField.
    upload_2017-11-17_16-43-54.png

    upload_2017-11-17_16-43-24.png


    I've tough of AssetList (but this one do not work with scene objects :( ), DropDown (work, but you lose the ability to double click goto reference since it's a dropdown), and ValidateInput (I would prefer an AssetList to choose from, so I don't even let the possibility of an error).

    Any help is welcome.

    (PS: context is i'm doing a uNet project, and when isLocalPlayer is true I need to enable some specific components, of the same gameobject)
     
  46. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    108
    Yeah we are working on an AssetList like attribute for objects of any type and any location, but it's still WIP and has been for a while, so we don't really have a solution for your exact use-case right now. But I was about to suggest ValidateInput, because that lets you still use Unity's object picker window. It could look something like:

    Code (CSharp):
    1.     [SerializeField, SceneObjectsOnly, ValidateInput("IsValidObject")]
    2.     private GameObject _someSceneObject;
    3.  
    4.     private bool IsValidObject(GameObject value)
    5.     {
    6.         if (value == null)
    7.         {
    8.             return true;
    9.         }
    10.  
    11.         bool isChildOfSelf = this.GetComponentsInChildren<Transform>()
    12.             .Select(x => x.gameObject)
    13.             .Contains(value);
    14.  
    15.         if (isChildOfSelf)
    16.         {
    17.             return false;
    18.         }
    19.  
    20.         return true;
    21.     }
    And if it's not too many objects the user can choose from then you could also give it an [InlineButton("SelectObject")] and make a GenericMenu and populate that with the desired objects. from the scene. Will that suffice maybe?
     
  47. AmbroiseRabier

    AmbroiseRabier

    Joined:
    Dec 4, 2016
    Posts:
    12
    Thanks for your reply Bjarkeck! I lack of experience with editor scripting for now, so I'll take the first proposition with ValidateInput, I appreciate the example, haven't tough of allowing null value.
    It's probably not possible, but I'll still ask in case. Would it be possible to make my custom attribute inheriting ValidateInput, to make an "ValidateIsChildren" attribute ? (trying to make my code more DRY)
     
  48. Westy661

    Westy661

    Joined:
    Sep 13, 2015
    Posts:
    11
    Hi guys!
    I just found a potential bug:
    [OnValueChanged("refreshGrid")] attribute on Vector3 fields only triggers when i am manipulating the coordinates with mouse scroll. When im clicking on the field and use my keyboard to change the value, it does not trigger. :)
     
    bjarkeck likes this.
  49. ugen_oak

    ugen_oak

    Joined:
    Oct 18, 2016
    Posts:
    6
    I'm having an issue with a [ValueDropdown], and I'm having trouble figuring out why.

    Code (CSharp):
    1. [ValueDropdown(nameof(RightMemberExpressions))]
    2. [OnValueChanged("LogRight")]
    3. public MemberExpression right;
    4.  
    5. public ValueDropdownList<MemberExpression> RightMemberExpressions()
    6. {
    7.     ValueDropdownList<MemberExpression> targetExpressions = new ValueDropdownList<MemberExpression>();
    8.     //
    9.     // targetExpressions gets populated in here
    10.     //
    11.     return targetExpressions;
    12. }
    13.  
    14. public void LogRight()
    15. {
    16. }
    The dropdown looks correct in every way, except none of the choices I make are sticking. I added the [OnValueChanged] attribute to try to see if the field was actually being set, and it looks like it is - but it is immediately being reset to its default value (which for some reason is showing as "None" in the dropdown rather than the value that's being set).

    odinvaluedropdown01.PNG

    In fact, it is constantly updating the value with the first choice from the dropdown. You can see in the screenshot below that I made a selection of Player.Label, and LogRight() was called twice before it was reset.

    odinvaluedropdown02.PNG

    The stack traces for both are below. I've bolded the line where things seem to diverge.
    Not sure that it has anything to do with it, but I'm using the .NET 4.6 API.
     
  50. alpdogan

    alpdogan

    Joined:
    May 8, 2015
    Posts:
    4
    Hello,
    I have a simple question:

    Is Odin capable of validating referenced prefabs too while validating scene?