Search Unity

  1. Check out the Unite LA keynote for updates on the Visual Effect Editor, the FPS Sample, ECS, Unity for Film and more! Watch it now!
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  4. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  5. 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. candycat

    candycat

    Joined:
    Jun 5, 2014
    Posts:
    29
    Bug report. After upgrading to 2.0, ListDrawerSettings(IsReadOnly = true) didn't work.
     
  2. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    624
    Hi,
    my code looks like this:
    upload_2018-8-22_14-21-30.png

    Then in the editor it looks like this:
    upload_2018-8-22_14-21-53.png
     
  3. kobyle

    kobyle

    Joined:
    Feb 23, 2015
    Posts:
    86
    Hello,

    I have 5 TabGroups, and I want to select one of them on Selection change through custom code, how can I do that?

    Thanks!
    Koby
     
  4. DespairBear

    DespairBear

    Joined:
    Nov 1, 2013
    Posts:
    174
    Hey I was looking at using this to develop a Unity editor extension for the asset store. Is this currently possible or is there licensing issues with doing so?
     
  5. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    456
    I often get this error when compiling my code, it's not that big a deal but I think it's caused by Odin.

    A PreviewRenderUtility was not clean up properly before assembly reloading which lead to leaking this scene in the Editor. This can be caused by not calling Cleanup() during the OnDisable of an Editor or an EditorWindow.
    UnityEditor.PreviewRenderUtility:Finalize()
     
  6. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    456
    I would like to make my member fields be togglable. But not through a normal Odin Toggle.
    It should be on the same line, just like in the Post-Process package of Unity.
    How can I achieve this?

    Here's a gif to show the behaviour:
    https://i.imgur.com/lpVNCce.gifv
     

    Attached Files:

    Last edited: Aug 25, 2018
  7. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    937
    When I update Odin should I remove the asset first and then download and import the new one?
    or should i just import on top of it?
     
  8. dantonel

    dantonel

    Joined:
    Dec 7, 2015
    Posts:
    8
    Is there something special I have to do to get Odin to properly serialize strongly-typed enum classes like this one:
    Code (CSharp):
    1.     [System.Serializable]
    2.     public class TypeTest
    3.     {
    4.         public static readonly TypeTest A = new TypeTest();
    5.         public static readonly TypeTest B = new TypeTest();
    6.         public static readonly TypeTest C = new TypeTest();
    7.     }
    8.  
    Whenever I create a TypeTest variable in a script and give it a ValueDropdown, I can select the values, but they never get remembered when I enter play mode.
     
  9. Harekelas

    Harekelas

    Joined:
    Feb 3, 2015
    Posts:
    624
    Hi, I've met an issue with dragging elements in a list with derived class

    I've created several classes derived from a base class and declared a list of the base class in a serialized monobehavior.
    And edit the class type and properties in the editor.
    Then I found a bug when dragging and deleting the elements: when elements should move in the list, I found the properties of the same adjacent elements does not move.
    For example:
    upload_2018-8-30_10-8-45.png
    Pay attention to the 27th element's properties, I'll delete the 26th element.
    upload_2018-8-30_10-11-37.png
    The 26th element changed to the ToLookAtItemTask as it should be, but the 27th element kept the original properties where it should be the properties moved upwards from the 28th element.
    This is hurting my workflow for I need to rearrange the order of the elements.
     
  10. Kripll

    Kripll

    Joined:
    Jan 20, 2017
    Posts:
    7
    Hey. Do you have solutions so that when you remove an item from the list, so that you can call your function?
     
  11. dantone1

    dantone1

    Joined:
    Jun 2, 2017
    Posts:
    3
    Also, is there a version of ValueDropdownAttribute/ValueDropdownItem/ValueDropdownList that allows me to use a callback to generate the item that should be added when an element in the dropdown is clicked?

    Edit: Just revisited this myself and discovered the IValueDropdownItem interface, and found that if I simply create my own class that implements that interface, I can use it to do exactly what I need.
     
    Last edited: Sep 7, 2018
  12. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    320
    Hello,

    Is there a way to draw another object's properties from within a drawer?
    In other words, I have a object (lets call it ObjectA) that has a field that is a reference to another object (Object B).

    If I have a drawer for ObjectA, can I draw a field that in ObjectB?

    The reason for this is that I have a sort of "parent system", in which objects can "parent" others... and for each field, I allow the object to override the parent's value. I want to make it so when the field is not overridden, it shows a disabled field that displays the parent's value.

    Here's a very messy example of what I have now:


    Thanks :)
     
    FredTuna likes this.
  13. joshcamas

    joshcamas

    Joined:
    Jun 16, 2017
    Posts:
    320
    For some reason, when I serialize a class using SerializeValue, fields marked with "System.NonSerialized" still end up being serialized. Why is this?
     
  14. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    951
    Just wonder if Odin yet supports you being able to create graph/nodes based editors?
     
  15. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    937
    Why is everyone's questions not being answered?
     
  16. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    951
    To be fair should probably have put the question on discord.... ;) But now I've put it here...
     
  17. slimshader

    slimshader

    Joined:
    Jun 11, 2013
    Posts:
    109
    Hey, just updated Unity to 2018.3 Beta and getting a lot of those:

    Code (CSharp):
    1. MissingMethodException: UnityEngine.Object UnityEditor.PrefabUtility.GetCorrespondingObjectFromSource(UnityEngine.Object)
    2. Sirenix.OdinInspector.Editor.PropertyTree`1[T]..ctor (UI.Xml.XmlElement[] targets, UnityEditor.SerializedObject serializedObject) (at <3c01eaab89c14020b3768bdc5f54b1bb>:0)
    3. System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    4. Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation.
    5. System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    6. System.Reflection.MonoCMethod.DoInvoke (System.Object obj, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    7. System.Reflection.MonoCMethod.Invoke (System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    8. System.RuntimeType.CreateInstanceImpl (System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes, System.Threading.StackCrawlMark& stackMark) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    9. System.Activator.CreateInstance (System.Type type, System.Reflection.BindingFlags bindingAttr, System.Reflection.Binder binder, System.Object[] args, System.Globalization.CultureInfo culture, System.Object[] activationAttributes) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    10. System.Activator.CreateInstance (System.Type type, System.Object[] args) (at <ac823e2bb42b41bda67924a45a0173c3>:0)
    11. Sirenix.OdinInspector.Editor.PropertyTree.Create (System.Collections.IList targets, UnityEditor.SerializedObject serializedObject) (at D:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/MaxValueAttributeDrawer.cs:39)
    12. Sirenix.OdinInspector.Editor.PropertyTree.Create (UnityEditor.SerializedObject serializedObject) (at D:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/ToggleLeftAttributeDrawer.cs:25)
    13. Sirenix.OdinInspector.Editor.OdinEditor.get_Tree () (at <3c01eaab89c14020b3768bdc5f54b1bb>:0)
    14. Sirenix.OdinInspector.Editor.OdinEditor.DrawOdinInspector () (at <3c01eaab89c14020b3768bdc5f54b1bb>:0)
    15. Sirenix.OdinInspector.Editor.OdinEditor.OnInspectorGUI () (at D:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Value Entries/PropertyValueEntry.cs:173)
    16. UnityEditor.InspectorWindow.DoOnInspectorGUI (System.Boolean rebuildOptimizedGUIBlock, UnityEditor.Editor editor, System.Boolean wasVisible, UnityEngine.Rect& contentRect) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1599)
    17. UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
    18.  
     
  18. grimmy

    grimmy

    Joined:
    Feb 2, 2009
    Posts:
    393
    Anyone know how I can add buttons where the red boxes (That I added with photoshop) are in my ListDrawer...? Thanks
    upload_2018-9-14_8-24-56.png

    Also, how would I change the colour of just one of the labels? For example change the 9:18 to green.

    Oh, and how do I set the background color of a table row?

    ..and how do I change the color of a label.

    Cheers
     
    Last edited: Sep 14, 2018
  19. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    555
    Hi there

    Is there an ETA on nested prefabs support now that the 2018.3 beta has dropped?
     
  20. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
    @Prodigga We just released a patch which provides better support for 2018.3 beta, we'll have patch notes up tomorrow. We're still working on getting nested prefabs to work well, and still no ETA on that, unfortunately. But we'll give an update on the roadmap once we know more.

    @grimmy Check out the ListDrawerSettings attribute, from there you can hook into BeginDrawListElement, and EndDrawListElement, there should be an example in the demo scene, and i belive there is one in the online documentation as well. You could potentially also make a drawer for your list element type, and only have it be applied to list elements. Hope that helps!

    @Shadowing We're not as active in here sorry, but we try to direct our users to sirenix.net/support our issue-tracker and our Discord server where we're providing support and answering questions on a daily basis, and the community in there is super helpful as well.

    I'm going to leave this in here again for people to see :)

    Discord
    I would highly recommend you guys joining our Discord ;) We're much more active in there, and if we're not around, then there's a lot of other active and helpful people who're often willing to help.

    Isssue-Tracker
    If you have an issue that you don't want us to forget about, this is the place! If we see a blocking-issue, we'll prioritize it highly, and often do sweeps where we just go through open issues. Feature requests are also more than welcome in here.

    Sirenix.net/support
    If your question or inquiry is more suited for an email, this is the place! Here we also answer all messages!
     
    Last edited: Sep 17, 2018
  21. ratking

    ratking

    Joined:
    Feb 24, 2010
    Posts:
    177
    Appokalopps and bjarkeck like this.
  22. Alex_May

    Alex_May

    Joined:
    Dec 29, 2013
    Posts:
    132
    Does anyone know why the MenuEditorWindow doesn't use the OdinValueDrawer for a menu item's type? Or how to get it so it does
     
  23. mybreeze

    mybreeze

    Joined:
    Nov 12, 2016
    Posts:
    10
    How To Show Scriptable Object As Window Editor Like This?



    upload_2018-10-10_17-13-19.png
     
  24. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
  25. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
    They were made before we introduced the performance optimizations to Odin's PropertyTrees, so back then it was out of the question to even consider it, but even though we could have considered it if we were to make them today, I think we would have done the same way as we did. OdinMenuItems are simple and Odins PropertyTrees, has to account for a lot of various cases unrelated to the use case of OdinMenuItems, so by drawing them manually, we can get a lot more performance out of them, and also design to be good at what they're supposed to do.

    Hope that makes sense, why do you ask, do you have a use-case which you found difficulty implementing with them?
     
  26. Alex_May

    Alex_May

    Joined:
    Dec 29, 2013
    Posts:
    132
    It is just strange that when I add my classes to the menu, the default inspector draws instead of the value drawer. If I contain the class inside another class, the value drawer works, but it's a sad feeling to have a class within another class just for that purpose.
     
  27. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    357
    Seeing the following WARNING in 2018.3b7

    [18:27:17:902] Unable to find style 'IN Popup' in skin 'DarkSkin' repaint
    Code (CSharp):
    1. UnityEngine.GUIStyle:op_Implicit(String)
    2. Sirenix.Utilities.Editor.SirenixEditorFields:DrawSlideKnob(Rect, Int32) (at F:/Sirenix/Sirenix Solution/Sirenix.Utilities.Editor/GUI/SirenixEditorFields.cs:5712)
    3. Sirenix.Utilities.Editor.SirenixEditorFields:FloatField(Rect, GUIContent, Single, GUIStyle) (at F:/Sirenix/Sirenix Solution/Sirenix.Utilities.Editor/GUI/SirenixEditorFields.cs:2048)
    4. Sirenix.Utilities.Editor.SirenixEditorFields:FloatField(GUIContent, Single, GUIStyle, GUILayoutOption[]) (at F:/Sirenix/Sirenix Solution/Sirenix.Utilities.Editor/GUI/SirenixEditorFields.cs:2099)
    5. Sirenix.Utilities.Editor.SirenixEditorFields:FloatField(GUIContent, Single, GUILayoutOption[]) (at F:/Sirenix/Sirenix Solution/Sirenix.Utilities.Editor/GUI/SirenixEditorFields.cs:2111)
    6. Sirenix.OdinInspector.Editor.Drawers.SingleDrawer:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/UnityObjectDrawer.cs:97)
    7. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    8. Sirenix.OdinInspector.Editor.Drawers.PrimitiveValueConflictDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/AssetListAttributeDrawer.cs:463)
    9. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    10. Sirenix.OdinInspector.Editor.Drawers.PropertyContextMenuDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/OnValueChangedAttributeDrawer.cs:73)
    11. Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:82)
    12. Sirenix.OdinInspector.Editor.InspectorProperty:Draw(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Examples/Attributes/TitleGroupExamples.cs:25)
    13. Sirenix.OdinInspector.Editor.InspectorUtilities:DrawPropertiesInTree(PropertyTree) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:209)
    14. Sirenix.OdinInspector.Editor.PropertyTree:Draw(Boolean) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Misc Drawers/DefaultMethodDrawer.cs:207)
    15. Sirenix.OdinInspector.Editor.OdinEditor:DrawTree() (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Value Entries/PropertyValueEntry.cs:173)
    16. Sirenix.OdinInspector.Editor.OdinEditor:DrawOdinInspector() (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Value Entries/PropertyValueEntry.cs:200)
    17. Sirenix.OdinInspector.Editor.OdinEditor:OnInspectorGUI()
    18. UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
     
    luispedrofonseca and bjarkeck like this.
  28. NeXeS

    NeXeS

    Joined:
    Jul 12, 2012
    Posts:
    2
    Hey bjarkeck,

    I recently purchased Odin, and I was wondering what would have to change, or if it is even possible, to use public properties instead of public variables throughout the above code?

    Thanks,
    -NeXeS
     
  29. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
    Hey NeXeS, :)

    Yeah, you can easily do that, just change the public variable to a private field and the SerializeField and HideInInspector attributes. Then add in the property and put [ShowInInspector] on that. That way everything done in the editor will go through getters and setters of the property.

    Did that answer your question?
     
  30. Kadaiyen

    Kadaiyen

    Joined:
    Jul 16, 2012
    Posts:
    13
    I've noticed that the [HideReferenceObjectPicker] attribute doesn't seem to apply to the values of a dictionary serialized w/ odin - is there a workaround to hide the object picker for dictionary values?
     
  31. Barabicus

    Barabicus

    Joined:
    Jun 5, 2013
    Posts:
    149
    Hey,
    I just upgraded a project of mine to 2018.3.0b8 and I instantly noticed that material inspectors are extremely slow. Several seconds to change a value in my case (which as you can imagine makes simple things like choosing a color or adjusting a value very difficult if you scale it up or down). After playing around with it a bit I found it was Odin affecting it. The lag also seems to scale based on project size as well. I understand Unity 2018.3 is in beta so I don't expect a fix to this so soon but I'm just curious if you're aware of this problem and if there is any fix planned on the horizon.
     
  32. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
    With the latest version of Odin, you can put the [HideReferenceObjectPicker] attribute (and all attributes for that matter) on top of the class itself, and it'll be a applied for all members of that type, including dictionaries. Does this work?

    Alternatively you can take a look at AttributeProcessors, there is an example in the Attribute Processor demo - available form the getting started guide found in "Tools > Odin Inspector > Getting Started" where it shows you how you can inject attribute into dictionaries.

    Hope that helps!
     
  33. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
    Thanks! Wasn't aware of this one, interesting that it seems to scale based on project-size. Will have a look soon, hope it's something that is reproducible.
     
  34. NeXeS

    NeXeS

    Joined:
    Jul 12, 2012
    Posts:
    2
    Hi bjarkeck,

    It did answer my question, and for the most part, it works as long as the "References" are public field variables. If they are declared as properties, something I can only describe as "weird" happens. Here is the code I am trying to get to work.

    Code (CSharp):
    1.  
    2. public class SomeMonoBehaviour : MonoBehaviour
    3. {
    4.     public FloatReference test2;
    5. }
    6.  
    7. /// <summary>
    8. /// TODO The variable reference drawer.
    9. /// </summary>
    10. /// <typeparam name="TReference">
    11. /// </typeparam>
    12. /// <typeparam name="TVariable">
    13. /// </typeparam>
    14. /// <typeparam name="TValue">
    15. /// </typeparam>
    16. [OdinDrawer]
    17. public class VariableReferenceDrawer<TReference, TVariable, TValue> : OdinValueDrawer<TReference>
    18.     where TReference : VariableReference<TValue, TVariable>
    19.     where TVariable : ScriptableObjectVariable<TValue>
    20. {
    21.     /// <summary>
    22.     /// TODO The draw property layout.
    23.     /// </summary>
    24.     /// <param name="entry">
    25.     /// TODO The entry.
    26.     /// </param>
    27.     /// <param name="label">
    28.     /// TODO The label.
    29.     /// </param>
    30.     protected override void DrawPropertyLayout(IPropertyValueEntry<TReference> entry, GUIContent label)
    31.     {
    32.         TReference value = entry.SmartValue;
    33.  
    34.         GUILayout.BeginVertical();
    35.         {
    36.             var btnRect = GUIHelper.GetCurrentLayoutRect();
    37.             btnRect.width = EditorGUIUtility.labelWidth;
    38.             btnRect = btnRect.AlignRight(18);
    39.             btnRect.y += 4;
    40.  
    41.             if (GUI.Button(btnRect, GUIContent.none, "PaneOptions"))
    42.             {
    43.                 var menu = new GenericMenu();
    44.                 menu.AddItem(new GUIContent("Constant"), value.UseConstant, () => value.UseConstant = true);
    45.                 menu.AddItem(new GUIContent("Variable"), !value.UseConstant, () => value.UseConstant = false);
    46.                 menu.ShowAsContext();
    47.             }
    48.  
    49.             EditorGUIUtility.AddCursorRect(btnRect, MouseCursor.Arrow);
    50.  
    51.             if (value.UseConstant)
    52.             {
    53.                 entry.Property.Children["ConstantValue"].Draw(label);
    54.             }
    55.             else
    56.             {
    57.                 entry.Property.Children["Variable"].Draw(label);
    58.             }
    59.         }
    60.  
    61.         GUILayout.EndVertical();
    62.     }
    63. }
    64.  
    65. /// <summary>
    66. /// TODO The float variable.
    67. /// </summary>
    68. [CreateAssetMenu(fileName = "FloatVariable", menuName = "Scriptable Object Variables/Float")]
    69. public class FloatVariable : ScriptableObjectVariable<Single>
    70. {
    71. }
    72.  
    73. /// <summary>
    74. /// TODO The float reference.
    75. /// </summary>
    76. [Serializable]
    77. public class FloatReference : VariableReference<Single, FloatVariable>
    78. {
    79.     /// <summary>
    80.     /// TODO The op_ implicit.
    81.     /// </summary>
    82.     /// <param name="reference">
    83.     /// TODO The reference.
    84.     /// </param>
    85.     /// <returns>
    86.     /// </returns>
    87.     public static implicit operator Single(FloatReference reference)
    88.     {
    89.         return reference.Value;
    90.     }
    91. }
    92.  
    93. /// <summary>
    94. /// TODO The scriptable object variable.
    95. /// </summary>
    96. /// <typeparam name="T">
    97. /// </typeparam>
    98. public abstract class ScriptableObjectVariable<T> : ScriptableObject
    99. {
    100.     /// <summary>
    101.     ///        The developer's comments state.
    102.     /// </summary>
    103.     [HideInInspector,
    104.      SerializeField]
    105.     private String _commentsDeveloper;
    106.  
    107.     /// <summary>
    108.     ///        Gets or sets the developer's comments.
    109.     /// </summary>
    110.     /// <returns>
    111.     ///        The developer's comments.
    112.     /// </returns>
    113.     [LabelText("Developer Comments"),
    114.      MultiLineProperty(10),
    115.      PropertyOrder(1),
    116.      PropertyTooltip("The developer's comments for the variable."),
    117.      ShowInInspector]
    118.     public virtual String CommentsDeveloper
    119.     {
    120.         get { return _commentsDeveloper; }
    121.         set { SetCommentsDeveloper(value); }
    122.     }
    123.  
    124.     /// <summary>
    125.     ///        Sets the developer's comments to the value of <paramref name="commentsDeveloper"/>.
    126.     /// </summary>
    127.     /// <param name="commentsDeveloper">
    128.     ///        The <see cref="T:System.String"/> value that represents the developer's comments.
    129.     /// </param>
    130.     /// <returns>This <see cref="T:.ScriptableObjectVariable"/>.</returns>
    131.     public virtual ScriptableObjectVariable<T> SetCommentsDeveloper(String commentsDeveloper)
    132.     {
    133.         _commentsDeveloper = commentsDeveloper;
    134.  
    135.         return this;
    136.     }
    137.  
    138.     /// <summary>
    139.     ///        Describe the property state.
    140.     /// </summary>
    141.     [HideInInspector,
    142.      SerializeField]
    143.     private T _value;
    144.  
    145.     /// <summary>
    146.     ///        Gets or sets describe the property.
    147.     /// </summary>
    148.     /// <returns>
    149.     ///        Describe the property.
    150.     /// </returns>
    151.     [LabelText("$name"),
    152.      PropertyOrder(0),
    153.      PropertyTooltip("The value of the variable."),
    154.      ShowInInspector]
    155.     public virtual T Value
    156.     {
    157.         get { return _value; }
    158.         set { SetValue(value); }
    159.     }
    160.  
    161.     /// <summary>
    162.     ///        Sets describe the property to the value of <paramref name="value"/>.
    163.     /// </summary>
    164.     /// <param name="value">
    165.     ///        The <see cref="T:T"/> value that represents describe the property.
    166.     /// </param>
    167.     /// <returns>This <see cref="T:.ScriptableObjectVariable"/>.</returns>
    168.     public virtual ScriptableObjectVariable<T> SetValue(T value)
    169.     {
    170.         _value = value;
    171.  
    172.         return this;
    173.     }
    174.  
    175.     /// <summary>
    176.     ///        Sets describe the property to the value of <paramref name="value"/>.
    177.     /// </summary>
    178.     /// <param name="value">
    179.     ///        The <see cref="T:T"/> value that represents describe the property.
    180.     /// </param>
    181.     /// <returns>This <see cref="T:.ScriptableObjectVariable"/>.</returns>
    182.     public virtual ScriptableObjectVariable<T> SetValue(ScriptableObjectVariable<T> value)
    183.     {
    184.         _value = value.Value;
    185.  
    186.         return this;
    187.     }
    188.  
    189. }
    190.  
    191. /// <summary>
    192. /// TODO The variable reference.
    193. /// </summary>
    194. /// <typeparam name="TValue">
    195. /// </typeparam>
    196. /// <typeparam name="TVariable">
    197. /// </typeparam>
    198. public abstract class VariableReference<TValue, TVariable>
    199.     where TVariable : ScriptableObjectVariable<TValue>
    200. {
    201.     /// <summary>Initializes a new instance of the <see cref="T:System.Object" /> class.</summary>
    202.     protected VariableReference()
    203.     {
    204.     }
    205.  
    206.     /// <summary>Initializes a new instance of the <see cref="T:System.Object" /> class.</summary>
    207.     protected VariableReference(TValue value)
    208.     {
    209.         _useConstant = true;
    210.         _constantValue = value;
    211.     }
    212.  
    213.     /// <summary>
    214.     ///        Describe the property state.
    215.     /// </summary>
    216.     [SerializeField]
    217.     private Boolean _useConstant;
    218.  
    219.     /// <summary>
    220.     ///        Gets or sets describe the property.
    221.     /// </summary>
    222.     /// <returns>
    223.     ///        Describe the property.
    224.     /// </returns>
    225.     [ShowInInspector]
    226.     public virtual Boolean UseConstant
    227.     {
    228.         get { return _useConstant; }
    229.         set { SetUseConstant(value); }
    230.     }
    231.  
    232.     /// <summary>
    233.     ///        Sets describe the property to the value of <paramref name="useConstant"/>.
    234.     /// </summary>
    235.     /// <param name="useConstant">
    236.     ///        The <see cref="T:System.Boolean"/> value that represents describe the property.
    237.     /// </param>
    238.     /// <returns>This <see cref="T:.VariableReference"/>.</returns>
    239.     public virtual VariableReference<TValue, TVariable> SetUseConstant(Boolean useConstant)
    240.     {
    241.         _useConstant = useConstant;
    242.  
    243.         return this;
    244.     }
    245.  
    246.     /// <summary>
    247.     ///        Describe the property state.
    248.     /// </summary>
    249.     [SerializeField]
    250.     private TValue _constantValue;
    251.  
    252.     /// <summary>
    253.     ///        Gets or sets describe the property.
    254.     /// </summary>
    255.     /// <returns>
    256.     ///        Describe the property.
    257.     /// </returns>
    258.     [ShowInInspector]
    259.     public virtual TValue ConstantValue
    260.     {
    261.         get { return _constantValue; }
    262.         set { SetConstantValue(value); }
    263.     }
    264.  
    265.     /// <summary>
    266.     ///        Sets describe the property to the value of <paramref name="constantValue"/>.
    267.     /// </summary>
    268.     /// <param name="constantValue">
    269.     ///        The <see cref="T:TValue"/> value that represents describe the property.
    270.     /// </param>
    271.     /// <returns>This <see cref="T:.VariableReference"/>.</returns>
    272.     public virtual VariableReference<TValue, TVariable> SetConstantValue(TValue constantValue)
    273.     {
    274.         _constantValue = constantValue;
    275.  
    276.         return this;
    277.     }
    278.  
    279.     /// <summary>
    280.     ///        Describe the property state.
    281.     /// </summary>
    282.     [SerializeField]
    283.     private TVariable _variable;
    284.  
    285.     /// <summary>
    286.     ///        Gets or sets describe the property.
    287.     /// </summary>
    288.     /// <returns>
    289.     ///        Describe the property.
    290.     /// </returns>
    291.     [ShowInInspector,
    292.      SuffixLabel("$GetValueString", true)]
    293.     public virtual TVariable Variable
    294.     {
    295.         get { return _variable; }
    296.         set { SetVariable(value); }
    297.     }
    298.  
    299.     /// <summary>
    300.     ///        Sets describe the property to the value of <paramref name="variable"/>.
    301.     /// </summary>
    302.     /// <param name="variable">
    303.     ///        The <see cref="T:TVariable"/> value that represents describe the property.
    304.     /// </param>
    305.     /// <returns>This <see cref="T:.VariableReference"/>.</returns>
    306.     public virtual VariableReference<TValue, TVariable> SetVariable(TVariable variable)
    307.     {
    308.         _variable = variable;
    309.  
    310.         return this;
    311.     }
    312.  
    313.     /// <summary>
    314.     /// Gets the value.
    315.     /// </summary>
    316.     public TValue Value
    317.     {
    318.         get { return !UseConstant && Variable ? Variable.Value : ConstantValue; }
    319.     }
    320.  
    321.     /// <summary>
    322.     /// TODO The get value string.
    323.     /// </summary>
    324.     /// <returns>
    325.     /// The <see cref="string"/>.
    326.     /// </returns>
    327.     [UsedImplicitly]
    328.     private String GetValueString()
    329.     {
    330.         return Variable.Value.ToString() + "         ";
    331.     }
    332. }
    Can you tell me where I am going wrong?

    Thanks,
    NeXeS
     
  35. Barabicus

    Barabicus

    Joined:
    Jun 5, 2013
    Posts:
    149
    Hey,
    Sorry okay so it seems maybe I might have been a bit hasty posting this. Basically what happened was I have a really large project and some smaller ones. I played around with backups of the smaller ones until I removed something that fixed it. Which was Odin. So when I add Odin to a empty project it gets noticeably slower. I figured maybe it was something to do with the amount of materials in the project so I tried generating 10,000 and it didn't scale. I decided to create a backup of my large project and test it with that. It just took awhile to copy and paste so I wasn't quick in doing that initially. Having just removed Odin there on the large project the lag is still the same, removing it had no affect at all.

    I'm not really quite sure what is causing it or why Odin has an affect on other projects but removing it doesn't seem to do anything in my large project. Maybe Odin and other plugins interact with something that causes this in Unity 2018.3. Maybe its a combination of things I'll look into it a bit more and see if anything interesting turns up.
     
    bjarkeck likes this.
  36. luispedrofonseca

    luispedrofonseca

    Joined:
    Aug 29, 2012
    Posts:
    702
    Someone already mentioned it before, but there was no answer, so here it goes again. I'm getting the following warning on Unity 2018.3.0b8:

    Code (csharp):
    1.  
    2. Unable to find style 'IN Popup' in skin 'DarkSkin' repaint
    3. UnityEngine.GUIStyle:op_Implicit(String)
    4. Sirenix.Utilities.Editor.SirenixEditorFields:DrawSlideKnob(Rect, Int32) (at F:/Sirenix/Sirenix Solution/Sirenix.Utilities.Editor/GUI/SirenixEditorFields.cs:5712)
    5. Sirenix.Utilities.Editor.SirenixEditorFields:IntField(Rect, GUIContent, Int32, GUIStyle) (at F:/Sirenix/Sirenix Solution/Sirenix.Utilities.Editor/GUI/SirenixEditorFields.cs:809)
    6. Sirenix.Utilities.Editor.SirenixEditorFields:IntField(GUIContent, Int32, GUIStyle, GUILayoutOption[]) (at F:/Sirenix/Sirenix Solution/Sirenix.Utilities.Editor/GUI/SirenixEditorFields.cs:860)
    7. Sirenix.Utilities.Editor.SirenixEditorFields:IntField(GUIContent, Int32, GUILayoutOption[]) (at F:/Sirenix/Sirenix Solution/Sirenix.Utilities.Editor/GUI/SirenixEditorFields.cs:872)
    8. Sirenix.OdinInspector.Editor.Drawers.Int32Drawer:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Misc Drawers/PropertyContextMenuDrawer.cs:247)
    9. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    10. Sirenix.OdinInspector.Editor.Drawers.PrimitiveValueConflictDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/AssetListAttributeDrawer.cs:463)
    11. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    12. Sirenix.OdinInspector.Editor.Drawers.PropertyContextMenuDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/OnValueChangedAttributeDrawer.cs:73)
    13. Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:82)
    14. Sirenix.OdinInspector.Editor.InspectorProperty:Draw(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Examples/Attributes/TitleGroupExamples.cs:25)
    15. Sirenix.OdinInspector.Editor.Drawers.CompositeDrawer:DrawPropertyLayout(GUIContent)
    16. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    17. Sirenix.OdinInspector.Editor.Drawers.NullableReferenceDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/QuaternionDrawer.cs:59)
    18. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    19. Sirenix.OdinInspector.Editor.Drawers.ReferenceValueConflictDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/ValueDropdownAttributeDrawer.cs:433)
    20. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    21. Sirenix.OdinInspector.Editor.Drawers.ReferencePathConflictDrawer`1:DrawPropertyLayout(GUIContent)
    22. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    23. Sirenix.OdinInspector.Editor.Drawers.FixUnityNullDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/SerializedPropertyUtilities.cs:30)
    24. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    25. Sirenix.OdinInspector.Editor.Drawers.ReferenceDrawer`1:DrawPropertyLayout(GUIContent)
    26. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    27. Sirenix.OdinInspector.Editor.Drawers.PropertyContextMenuDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/OnValueChangedAttributeDrawer.cs:73)
    28. Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:82)
    29. Sirenix.OdinInspector.Editor.InspectorProperty:Draw(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Examples/Attributes/TitleGroupExamples.cs:25)
    30. Sirenix.OdinInspector.Editor.Drawers.CollectionDrawer`1:DrawItem(InspectorProperty, DragHandle, Int32) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/ColorDrawer.cs:90)
    31. Sirenix.OdinInspector.Editor.Drawers.CollectionDrawer`1:DrawItems() (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/ColorDrawer.cs:77)
    32. Sirenix.OdinInspector.Editor.Drawers.CollectionDrawer`1:DrawPropertyLayout(GUIContent)
    33. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    34. Sirenix.OdinInspector.Editor.Drawers.NullableReferenceDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Value Drawers/QuaternionDrawer.cs:59)
    35. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    36. Sirenix.OdinInspector.Editor.Drawers.ReferenceValueConflictDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/ValueDropdownAttributeDrawer.cs:433)
    37. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    38. Sirenix.OdinInspector.Editor.Drawers.ReferencePathConflictDrawer`1:DrawPropertyLayout(GUIContent)
    39. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    40. Sirenix.OdinInspector.Editor.Drawers.FixUnityNullDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/SerializedPropertyUtilities.cs:30)
    41. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    42. Sirenix.OdinInspector.Editor.Drawers.ReferenceDrawer`1:DrawPropertyLayout(GUIContent)
    43. Sirenix.OdinInspector.Editor.OdinDrawer:CallNextDrawer(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:133)
    44. Sirenix.OdinInspector.Editor.Drawers.PropertyContextMenuDrawer`1:DrawPropertyLayout(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Attribute Drawers/OnValueChangedAttributeDrawer.cs:73)
    45. Sirenix.OdinInspector.Editor.OdinDrawer:DrawProperty(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:82)
    46. Sirenix.OdinInspector.Editor.InspectorProperty:Draw(GUIContent) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Examples/Attributes/TitleGroupExamples.cs:25)
    47. Sirenix.OdinInspector.Editor.InspectorUtilities:DrawPropertiesInTree(PropertyTree) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Utilities/PersistentContext/PersistentContextCache.cs:209)
    48. Sirenix.OdinInspector.Editor.PropertyTree:Draw(Boolean) (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/Misc Drawers/DefaultMethodDrawer.cs:207)
    49. Sirenix.OdinInspector.Editor.OdinEditor:DrawTree() (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Value Entries/PropertyValueEntry.cs:173)
    50. Sirenix.OdinInspector.Editor.OdinEditor:DrawOdinInspector() (at F:/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/Value Entries/PropertyValueEntry.cs:200)
    51. Sirenix.OdinInspector.Editor.OdinEditor:OnInspectorGUI()
    52. UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
    53.  
    54.  
     
  37. Kadaiyen

    Kadaiyen

    Joined:
    Jul 16, 2012
    Posts:
    13
    It didn't! But then I upgraded from v1.x to v2.x and it did :D

    Thanks!
     
    bjarkeck likes this.
  38. Kadaiyen

    Kadaiyen

    Joined:
    Jul 16, 2012
    Posts:
    13
    While I'm here, quick additional question: when selecting a dictionary type using the object reference picker to create a new instance, I'm offered both the Dictionary<T1, T2> type and something like SerializedDictionary<T1, T2>. Don't think that's a type I've made, is that something you guys are doing? Is the Dictionary<T1, T2> type for some reason not serialized?
     
  39. SpyrosUn

    SpyrosUn

    Joined:
    Nov 20, 2016
    Posts:
    16
    Hi there, thanks for Odin, it's great !

    I have a scriptableObject with a 10x10 2d array. I am creating the data needed to populate that array via python and I am wondering if there is an easy way to copy paste this 2d array into the very nice looking 2d array that Odin creates in the Editor. Any ideas ? Thanks !
     
  40. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
    Thanks guys, It has been fixed and we'll submit the patch shortly. It'll be in the 2.0.10 patch.
     
  41. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
    Just imported Odin in 2018.3 and you're right. Just having Odin in the project makes the Material editors slower, curious if you find out what it is that makes it scale. Pretty sure it has nothing to do with Odin directly (Non of our code ever touches material editors). It must be something really strange.
     
  42. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
    Looks like it scales with the number of managed types in any given project. The stack frame for any given frame in the Material Inspector looks like this:

    Code (CSharp):
    1. DrawEditor()
    2. DrawHeader()
    3. OnHeaderIconGUI()
    4. AssetPreview.GetAssetPreview()
    5. // And here comes the interesting part.
    6. Editor.CreateEditor()
    So GetAssetPreview decides to create an editor to generate a preview, Editor.CreateEditor then enumerates a ton of assemblies in order to search for the appropriate editor, and this happens every frame, so the more types in the app domain, the more lag. I think Unity has a bug somewhere, it's likely something isn't cached correctly, or a dictionary lookup has gone wrong somewhere along the road. We should report this bug to Unity :)
     
  43. Barabicus

    Barabicus

    Joined:
    Jun 5, 2013
    Posts:
    149
    Yes I think you're right this is definitely something to do with Unity. I've also found a lot more plugins affect than just Odin. I'm glad you were able to figure out more than I was though! this has been very annoying to deal with.
     
  44. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    221
    You could make a temporary fix by making a custom editor that extends Unitys MaterialEditor and then override the DrawHeader method and manually draw the shader-selector dropdown.
     
  45. SpyrosUn

    SpyrosUn

    Joined:
    Nov 20, 2016
    Posts:
    16
    Anyone with a similar issue I mentioned above ? How do you guys import large 2d arrays(
    TableMatrix). For, say, 10x10 arrays ?
    ?
     
  46. Barabicus

    Barabicus

    Joined:
    Jun 5, 2013
    Posts:
    149
    Oh good idea I'll try doing this! appreciate the tip!
     
  47. Kadaiyen

    Kadaiyen

    Joined:
    Jul 16, 2012
    Posts:
    13
    Fun question: if I'm drawing a Dictionary<enum, enum2> with a custom OdinValueDrawer, how might I go about drawing the header & content in the same style as the default odin collection? (the big boxy header, with the dark box background for content)

    Just trying to keep things consistent. :)

    Thanks, and Odin has been awesome!