Search Unity

Assets [WIP] Odin Inspector & Serializer Looking for Feedback

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

  1. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    Yes, it would make sense for FoldoutGroup to respect the "Foldout By Default" setting, we'll make sure to fix that. We could also add an overload to the FoldoutGroup if someone wanted to override the setting for special cases.

    Remembering what is expanded/collapsed in the inspector is something we are working on as well. I can't promise it will make it into the next patch, (which should be coming out soon). But definitely the one after that.
     
    Owlglass_Moot likes this.
  2. Joe64

    Joe64

    Joined:
    Jun 13, 2012
    Posts:
    9
    Hi,

    just started using Odin and it looks very promising.
    I like your enthusiasm about your project.

    But I've found a problem with dictionaries.
    This code throws exceptions with Odin:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using Sirenix.OdinInspector;
    4. using Sirenix.Serialization;
    5.  
    6. public struct ValStruct
    7. {
    8.     public int anInt;
    9. }
    10.  
    11. public class OdinDictionaryTest : MonoBehaviour
    12. {
    13.     [OdinSerialize] [ShowInInspector]
    14.     public Dictionary<int, ValStruct> testDict = new Dictionary<int, ValStruct>();
    15.  
    16.     ValStruct val = new ValStruct();
    17.  
    18.     void Awake()
    19.     {
    20.         val.anInt = 1;
    21.  
    22.         testDict.Add(2, val);
    23.         testDict.Add(3, val);
    24.         testDict.Add(9, val);
    25.     }
    26. }
    27.  
    Size is 3 but only first key is drawn.

    The following exception was thrown when drawing property testDict with the following chain of property value drawers:
    PropertyContextMenuDrawer<Dictionary<int, ValStruct>>, ReferenceDrawer<Dictionary<int, ValStruct>>, FixUnityNullDrawer<Dictionary<int, ValStruct>>, ReferencePathConflictDrawer<Dictionary<int, ValStruct>>, ReferenceValueConflictDrawer<Dictionary<int, ValStruct>>, NullableReferenceDrawer<Dictionary<int, ValStruct>>, DictionaryDrawer<Dictionary<int, ValStruct>, int, ValStruct>.
    UnityEngine.Debug:Log(Object)
    Sirenix.OdinInspector.Editor.InspectorUtilities:DrawProperty(InspectorProperty, GUIContent) (at C:/Users/Bjarke/Desktop/Projects/Sirenix Development Framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/InspectorUtilities.cs:375)
    Sirenix.OdinInspector.Editor.InspectorUtilities:DrawProperty(InspectorProperty) (at C:/Users/Bjarke/Desktop/Projects/Sirenix Development Framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/InspectorUtilities.cs:312)
    Sirenix.OdinInspector.Editor.InspectorUtilities:DrawPropertiesInTree(PropertyTree) (at C:/Users/Bjarke/Desktop/Projects/Sirenix Development Framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/InspectorUtilities.cs:290)
    Sirenix.OdinInspector.Editor.PropertyTree:Draw(Boolean) (at C:/Users/Bjarke/Desktop/Projects/Sirenix Development Framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Core/PropertyTree.cs:143)
    Sirenix.OdinInspector.Editor.OdinEditor:OnInspectorGUI() (at C:/Users/Bjarke/Desktop/Projects/Sirenix Development Framework/Sirenix Solution/Sirenix.OdinInspector.Editor/Drawers/OdinEditor.cs:183)
    UnityEditor.DockArea:OnGUI()

    And besides that, I vote also for adding custom types as dictionary keys, at least enum and struct/class with primitive types.
     
  3. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    I've been trying and failing to reproduce this with your example code. We fixed a few bugs with dictionaries in this next patch 1.0.2.0 which is currently going through approval in the asset store, so it looks like this one is resolved.

    Edit: As for more dictionary key types, we're definitely going to be adding more as soon as we have the time to work on that.

    Edit 2: Correction, I worked out how to replicate this error. I was a little confused, as I couldn't recall making any changes which might have fixed it. However, I played around with it a bit more and managed to find it - it has been fixed now. The issue will be resolved in the next patch.

    Meanwhile, if you want to show dictionaries in the inspector, you can inherit your class from SerializedMonoBehaviour or a similar Odin-serialized class. That will make the dictionary render correctly.

    I should also note that, if you don't inherit from SerializedMonoBehaviour or a similar class, using [OdinSerialize] on your field will not cause it to be serialized - which is why you found yourself having to use [ShowInInspector] to make the dictionary show up. The dictionary in your example would not be saved as part of the scene or asset that it's in, but would reset every time there's a reload.

    We've added a warning in the new patch to tell people when they're using [OdinSerialize] incorrectly.
     
    Last edited: Jun 5, 2017
  4. Joe64

    Joe64

    Joined:
    Jun 13, 2012
    Posts:
    9
    Hi Tor-Vestergaard,

    ok, good. Thanks for checking and for the clarifications :).
     
  5. jeremedia

    jeremedia

    Joined:
    Apr 21, 2015
    Posts:
    63
    Is it possible to use Odin to serialize and deserialize at runtime?
     
  6. szevvy

    szevvy

    Joined:
    Jan 7, 2013
    Posts:
    7
    Hi guys,

    Is it possible to entirely disable the serialization part of Odin? We're loving the inspector, but don't require the custom serialization at all, and it's currently causing an issue where our application doesn't compile under XCode - IL2CPP seems to be generating invalid c++ from the Odin code.
     
  7. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    It is! If you instantiate any component derived from a specially serialized class such as SerializedMonoBehaviour, Odin's serialization will run in your build in its optimized binary format mode to make sure the component is instantiated correctly with all its data.

    If you wish to use Odin's serialization manually from your own code, you can use the SerializationUtility and UnitySerializationUtility classes, which respectively provide a series of easy utilities for serializing objects of any kind, and for serializing Unity objects specifically.

    We should probably add a section about this in the manual.

    If you delete the "link.xml" file at the "Sirenix/Assemblies" path, the IL2CPP converter's code stripper should entirely strip Odin's serialization system if you're not using it (remember to delete the demo scenes and scripts, as they reference the serialization system). If that doesn't prove to be enough, you should simply be able to delete the "Sirenix.Serialization" files (.dll, .mdb and .pdb) from the "NoEditor" and "NoEmitNoEditor" folders at the same path. If those assemblies are deleted, Odin's serialization will not be included in any builds, and you will get compiler errors if you try to build with any references to Odin's serialization system. Note that if you do this, you should still delete the link.xml file, as its contents will cause the code stripping to fail when those assemblies are deleted.

    Eventually, we plan to provide a proper installer, where you can select whether you want the serialization support or not, and it will configure your project correctly. For now, this is how you'll have to do it, though perhaps we could add a button somewhere that will perform these actions and remove the serialization for you.

    Finally, while this should hopefully resolve your issue, Odin should ideally compile correctly under XCode. Would you mind giving us some more details about how the XCode compile fails exactly, so we can try to fix that? Other IL2CPP compiles, such as compiling Odin to WebGL, work just fine, so this issue is probably specific to XCode in particular.
     
    mons00n likes this.
  8. NeonTanto

    NeonTanto

    Joined:
    Jun 19, 2013
    Posts:
    156
    Odin look very promised, but I have few questions:
    1. Can I handle changes in colections (add, remove, change object)?
    2. How your serializer handle references for non UnityEngine.Object classes?
    3. Can I write custom editors with using of Odin api?
     
    Last edited: Jun 7, 2017
  9. SuneT

    SuneT

    Joined:
    Feb 29, 2016
    Posts:
    41
    Good news, everyone! Odin v. 1.0.2.1 is out, and it brings a bunch of fixes and even some new features ;)

    Fixes:
    • Formatter emitting now works when targeting the experimental .NET 4.6 platform in Unity 2017.1. This fixes the MethodAccessExceptions that people were getting when the build platform was Standalone or Android with the experimental .NET 4.6 runtime.
    • Fixed issue where object fields would not accept drag and dropping values. You can now drag values into non-Unity object fields - for example, you can now drag assets that implement a certain interface into a field of that interface type.
    • TypeExtensions.SetMemberValue now works on property infos. This was causing all prefab value modifications to properties to become lost or null.
    • Made editor recompilation more robust to type and file load exceptions during inspection of old assemblies with invalid assembly references - these exceptions will now result in an automatic recompile (if this is enabled) which should correct the given assembly references at once.
    • Fixed case where a UnityPropertyValueEntry failing to find its corresponding Unity property would cause a null reference exception to be thrown.
    • AssetsOnly attribute now also excludes scene objects in the object picker when the value is null.
    • ReferenceDrawer no longer forces GUI.enabled to be true.
    • ColorPallete and Enum changes now properly trigger ValidateInput.
    • Color32 now works when only backed by Odin serialization.
    • SirenixEditorFields.MinMaxSlider now respects EditorGUI.showMixedValue.
    • EditorGUI.showMixedValue is now handled per child property.
    • Fixed case where declaring dictionaries with unsupported key types would result in errors when updating a property tree.
    • The context menu item "Set to null" now correctly appears for properties of interface types.
    • Reference object picker is now shown for UnityObject values which are in properties with a base type which is an interface.
    • Fixed a potential bug where the LabelText could end up showing the wrong label.
    • Fixed a bug where multiselection could break the boolean drawer and end up changing the value if there was a value conflict.
    • Fixed cases where AnimationCurves and Gradients would cause errors in the inspector and fail to draw properly.
    • Fixed issue where BoxGroup.ShowLabel was not respected.
    • Fixed case during build-time deserialization of a prefab instance in a scene that is being loaded for being built, where Odin would fail to detect available prefab data due to prefab already having been serialized into build-time data formats. The prefab instance would attempt to deserialize from its own data instead, but that data would sometimes be corrupt, since this is build time and it's a prefab instance and prefab instances don't exist in builds.
    • SplitCamelCase no longer splits all caps.
    • InfoBoxAttribute now works properly with multiple info boxes.
    • Fixed a bug where the wrong label would sometimes be used in the [LabelText] attribute.
    • Using [ShowInInspector] on dictionaries that are on non-Odin-serialized types now works properly.

    Changes:
    • Most attribute which had some kind of string member reference now use StringMemberHelper instead. Original member references have been marked as obsolete.
    • Title attribute has been overhauled to look better, and now has options for subtitle and for a horizontal separator line.
    • UnitySerializationUtility now caches memory streams used, which should result in far less garbage allocated each time an object is serialized.
    • Changed deserialization behaviour in the editor to be able to handle data serialized in build mode. This is a possible fix for a case where Odin-serialized data would sometimes disappear randomly when building and/or exiting play mode.
    • Changed UnityObjectDrawer priority to (0, 0, 0.25) to prevent it from ever overriding a user's vanilla Unity PropertyDrawer by default.
    • Changed IPropertyValueEntry.ValueIsDictionary to ValueIsValidDictionary. Additionally, it is now only true if the Dictionary's key type is a valid key type in the inspector.
    • LabelText attribute is no longer applied to list elements.
    • Lots of changes to demo scenes.
    • AssetLists now only scans for objects within the path specified, if any. This will drastically reduce the time it takes to scan for all relevant assets in large projects.
    • Button and ButtonGroup now use mini button GUI style.
    • SirenixEditorGUI.InfoBox no longer gets a control ID.
    • EnumToggleButtons makes multiple rows of buttons when horizontal space is needed.
    • Polished the spacing between elements a bit more.
    • DetailedInfoBox now shows its foldout icon on the right side of the message box, instead of the bottom.

    Added:
    • When first learning to use the Odin Inspector, it is common for people to misunderstand the OdinSerialize attribute, and use it in places where it does not achive the deceired goal. We now show a warning message in the inspector if we detect any potential cases such as that. The warning message can be disabled in 'Window > Odin Inspector > Preferences > Serialization'.
    • Added OdinEditorWindow, which you can inherit from to easily create Odin-supported editor windows using the same attribute syntax that you use for components and scriptable objects.
    • The Title attribute has now gotten an optional horizontal line separator along with a subtitle. You can now also specify the alignment of the title.
    • Added StringMemberHelper class, which will find a string member field, property or method to get a string from if the given path starts with a $. Otherwise it'll use the given string.
    • Added IPropertyValueCollection.ForceMarkDirty.
    • Added new InlineButton attribute.
    • Added PropertyContextContainer.Get with an out parameter for the context, and a bool return value for initialization.
    • Added an overload to the FoldoutGroup where you can specify whether or not the foldout should start expanded or collapsed.

    UPGRADE NOTES:
    • Import new package.
    • Delete Sirenix/Assemblies/Editor/GeneratedOdinEditors.dll after upgrading, which will cause it to regenerate an updated version of itself if you have this behaviour enabled. The old .dll may cause a multitude of Mono.Cecil type lookup errors to be generated in the console. (These messages are harmless, but annoying.)
     
  10. jeremedia

    jeremedia

    Joined:
    Apr 21, 2015
    Posts:
    63
    Awesome! Thank you for the response. I've been using Odin since the release as it directly addresses several of the challenges presented by my entirely procedural VR project.
    Could you provide a brief example of how you'd suggest using Odin to save and load runtime generated data? I'd imagine such an example would be of great use to other current and potential Odin users. All of my objects inherit from SerializedMonoBehaviour or SerializedScriptableObject.
     
    WendelinReich likes this.
  11. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    I'm uncertain what you mean by "handle" exactly, but you can be notified whenever a list changes using the [OnValueChanged] attribute, or you can "handle" changes by validating them and confirming they are correct, using the [ValidateInput] attribute.

    Non-Unity references are always stored "per-object" - that is, if you have a component which contains a graph data structure with nodes that reference each other a lot, all of these references will be stored and reproduced correctly. If two different components are referencing the same values, that won't work and they will become different references when the components are deserialized, unless you do something like implement Microsoft's IObjectReference interface manually and use that to implement a singleton-like pattern.

    You can! Among others, the GUIHelper and SirenixEditorGUI classes provide a wide array of utilities and methods for drawing nice-looking editor UIs, and Odin is itself made using these classes. If you want to know how something specific is drawn, you can find the drawer in the provided source code and see how it uses the API to draw.

    The serialization system is very flexible, so there are a lot of ways you might go about this. However, the most straightforward would probably be to just use the serialization system in the simplest fashion. Suppose you make a class containing the data you wish to save:

    Code (CSharp):
    1. public class MyData
    2. {
    3.     // You can put anything in here to be saved
    4. }
    Now, you can use the serialization to convert instances of this class to an array of bytes, which you can then save to disk, and load up later to be converted back into MyData instances.

    Code (CSharp):
    1. // Save data
    2. {
    3.     MyData data = new MyData(); // Data to be saved, fetch this from somewhere or initialize it or whatever
    4.  
    5.     // Binary format is fast, but not humanly readable. Json is very slow, but is a text format that can be read by humans when you save it to a file.
    6.     DataFormat format = DataFormat.Binary;
    7.     //DataFormat format = DataFormat.JSON;
    8.  
    9.     // Serialize value to bytes
    10.     byte[] bytes = SerializationUtility.SerializeValue(data, format);
    11.  
    12.     // Write bytes to a file
    13.     File.WriteAllBytes("some/file/path/somefile.data", bytes);
    14. }
    15.  
    16. // Load data
    17. {
    18.     byte[] bytes = File.ReadAllBytes("some/file/path/somefile.data");
    19.  
    20.     // Make sure we deserialize with the same format that we serialized! This is very important.
    21.     DataFormat format = DataFormat.Binary;
    22.     //DataFormat format = DataFormat.JSON;
    23.  
    24.     // Deserialize the data from the stored bytes
    25.     MyData data = SerializationUtility.DeserializeValue<MyData>(bytes, format);
    26. }
    Note that this will not support saving and loading Unity objects (if you have references to Unity objects in MyData, you will have warnings logged in your console), like GameObjects, Components/Behaviours, or ScriptableObjects. We do not support serializing these to bytes in the above fashion, but only extend Unity's own serialization for such objects (through SerializedMonoBehaviour, SerializedScriptableObject, etc) whenever they are saved by Unity itself.
     
    Last edited: Jun 8, 2017
  12. NeonTanto

    NeonTanto

    Joined:
    Jun 19, 2013
    Posts:
    156
    @Tor-Vestergaard thx for answers! Sorry for my english. Its my "read-only" language.
     
    Tor-Vestergaard likes this.
  13. bwheatley

    bwheatley

    Joined:
    Jun 23, 2012
    Posts:
    45
    Is there a way to default a collapsible grouping to start closed? I'm trying to convert some of my custom editors to just being Odin.

    Thanks ;)
     
  14. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    Yo!

    Yup you set the default behaviour in Odin preferences window (Window > Odin Inspector > Preferences > Drawer > General). "Expand Foldout By Default"

    You can also use the FoldoutGroup with the new overload we've added in the latest patch where you can override the default initial state.

    Code (CSharp):
    1. [HideLabel, FoldoutGroup("Some Field", expanded: true)]
    2. public MyStruct SomeField;
    The HideLabel prevents it from showing the default foldout label.

    This solution uses a group attribute, which we currently only allow one of per property. So if it's already using a group for other purposes you would need to make your own attribute for now:

    It could look something like this:

    Usage:
    Code (CSharp):
    1. [Foldout(false)]
    2. public int Collapsed;
    3.  
    4. [Foldout(true)]
    5. public int Expanded;
    Attribute:
    Code (CSharp):
    1.  
    2. public class FoldoutAttribute : Attribute
    3. {
    4.     public readonly bool Expanded;
    5.  
    6.     public FoldoutAttribute(bool expanded)
    7.     {
    8.         this.Expanded = expanded;
    9.     }
    10. }
    Drawer:
    Code (CSharp):
    1. [OdinDrawer]
    2. [DrawerPriority(DrawerPriorityLevel.WrapperPriority)]
    3. public class FoldoutAttributeDrawer : OdinAttributeDrawer<FoldoutAttribute>
    4. {
    5.     protected override void DrawPropertyLayout(InspectorProperty property, FoldoutAttribute attribute, GUIContent label)
    6.     {
    7.         var expanded = property.Context.Get(this, "IsExpanded", attribute.Expanded);
    8.  
    9.         SirenixEditorGUI.BeginBox();
    10.         SirenixEditorGUI.BeginBoxHeader();
    11.         expanded.Value = SirenixEditorGUI.Foldout(expanded.Value, label);
    12.         SirenixEditorGUI.EndBoxHeader();
    13.         if (SirenixEditorGUI.BeginFadeGroup(expanded, expanded.Value, GeneralDrawerConfig.Instance.GUIFoldoutAnimationDuration))
    14.         {
    15.             this.CallNextDrawer(property, label: null);
    16.         }
    17.         SirenixEditorGUI.EndFadeGroup();
    18.         SirenixEditorGUI.EndBox();
    19.     }
    20. }
     
    Last edited: Jun 9, 2017
  15. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Bought this in a heartbeat SOLELY for the ability to work with dictionaries!

    Still digging through things, but quick question. Does it have the ability to allow for proper C# Properties rather than Unity's horrible policy of public fields? Currently I use Candelight for that, but wondering if it is built into Odin so I don't need to use two different assets.
     
    bjarkeck likes this.
  16. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    For sure! Here is the general idea of how you would achieve something similar to Property Backing Field / Candlelight in Odin:

    This example will work fine for structs, primitive types, and UnityEngine.Object types.
    Code (CSharp):
    1. public class MyComponent : MonoBehaviour
    2. {
    3.     [SerializeField, HideInInspector]
    4.     private int evenNumber;
    5.  
    6.     [ShowInInspector]
    7.     public int EvenNumber
    8.     {
    9.         get { return this.evenNumber; }
    10.         set { this.evenNumber = value + value % 2; }
    11.     }
    12.  
    13.     [SerializeField, HideInInspector]
    14.     private Texture someSquareTexture;
    15.  
    16.     [ShowInInspector]
    17.     public Texture SomeSquareTexture
    18.     {
    19.         get { return this.someSquareTexture; }
    20.         set
    21.         {
    22.             if (value != null && value.width == value.height)
    23.             {
    24.                 this.someSquareTexture = value;
    25.             }
    26.         }
    27.     }
    28. }
    However, there is a small hiccup when it comes to reference types that are not UnityEngine.Object types. Whenever Odin sees a reference type property, which value has already been drawn by another property. Odin will draw that same value, as it was initially drawn by the first property/field with all of the attirbutes specified from that first property (but wrapped in a collapsed box (drawn by the reference drawer) to prevent self-referencing infinite draw loops).

    So if the first property/field was drawn, with a [HideInInspector] (which doesn't exclude the property from our property tree) The second time that value will be drawn, it would be drawn with the [HideInInspector] attribute again. So the value would never be shown.

    But you can easily get around this as well by using the [ExcludeDataFromInspector] attribute, which will tell Odin to completely ignore a property/field in the inspector.

    Code (CSharp):
    1. public class MyComponent : MonoBehaviour
    2. {
    3.     [SerializeField, ExcludeDataFromInspector] // ExcludeDataFromInspector instead of HideInInspector
    4.     private int[] intArray = new int[10];
    5.  
    6.     [ShowInInspector]
    7.     public int[] IntArray
    8.     {
    9.         get { return this.intArray; }
    10.         set
    11.         {
    12.             Debug.Log("Array was resized from " + this.intArray.Length + " to " + value.Length);
    13.             this.intArray = value;
    14.         }
    15.     }
    16. }
    Another example case for this:
    Code (CSharp):
    1. public class MyComponent : SerializedMonoBehaviour
    2. {
    3.     [SerializeField, ExcludeDataFromInspector] // ExcludeDataFromInspector instead of HideInInspector
    4.     private MyClass myClass;
    5.  
    6.     [ShowInInspector]
    7.     public MyClass MyClass
    8.     {
    9.         get { return this.myClass; }
    10.         set
    11.         {
    12.             this.myClass = value;
    13.  
    14.             // MyClass does not have the [System.Serializable] attribute which means Unity will not be serializing the class.
    15.             // But since we in this example are inheriting from SerializedMonoBehaviour, Odin will serialize it.
    16.             // ... Which means null support, making this example valid!
    17.             if (value != null)
    18.             {
    19.                 value.Init(this);
    20.             }
    21.         }
    22.     }
    23. }
    24.  
    25. public class MyClass
    26. {
    27.     [SerializeField, HideInInspector]
    28.     private MyComponent myComponent;
    29.  
    30.     [SerializeField]
    31.     private string SomeField;
    32.  
    33.     public void Init(MyComponent myComponent)
    34.     {
    35.         this.myComponent = myComponent;
    36.     }
    37. }
     
    Last edited: Jun 10, 2017
  17. UnityRocksAlt

    UnityRocksAlt

    Joined:
    Dec 28, 2015
    Posts:
    157
    Hi,

    Will you please add a feature that executes function as long as the button is held down in the editor. When the button is released, the execution stops.

    Thanks
     
  18. zzzzzz789

    zzzzzz789

    Joined:
    Dec 21, 2013
    Posts:
    22
    Hi, Odin is amazing. Thank you for making this.

    I am encountering this issue with iOS Builds:
    Where this is a snippet of the code I am using which works in Editor, but seems to throw off in iOS builds:
    Code (CSharp):
    1. public class UISetLayoutElementConfig : SerializedMonoBehaviour
    2. {
    3.     [OdinSerialize]
    4.     public Dictionary<int, UILayoutConfig> layoutConfigs;
    5.  
    6.     [Serializable]
    7.     public class UILayoutConfig
    8.     {
    9.         [HorizontalGroup("minW")]
    10.         public bool minWidth;
    11.         [HorizontalGroup("minW")]
    12.         [HideLabel]
    13.         [ShowIf("minWidth")]
    14.         public float minWidthFloat;
    15.     }
    16. }
    Any help?
     
  19. UnityRocksAlt

    UnityRocksAlt

    Joined:
    Dec 28, 2015
    Posts:
    157
    How do I add a button, and then below it add a title and buttons below the title. lol.PNG
    Here, the buttons "1" and "2" should be below add to tile, and the entire thing "Add to tile" along with buttons "1" and "2" should be below "Reset Original Buttons". Like this:

    Reset Original Size (Button)
    Add to title (Title)
    1(Button) 2(Button)

    But that does not happen.
     
  20. UnityRocksAlt

    UnityRocksAlt

    Joined:
    Dec 28, 2015
    Posts:
    157
    Also, is there a way to suppress this warning:

    [WARNING]
    Invalid drawer declaration 'UnityPropertyDrawer<NamedMonoBehaviourDrawer, NamedMonoBehaviour>'; you cannot use an abstract class 'NamedMonoBehaviour' as the drawn value type. Use a generic drawer with a constraint for that abstract class instead.
    UnityEngine.Debug:LogError(Object)
    Sirenix.OdinInspector.Editor.DrawerLocator:DrawerIsValid(Type, Type&) (at C:/Users/Bjarke/Desktop/Projects/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/DrawerLocator.cs:740)
    Sirenix.OdinInspector.Editor.<>c:<.cctor>b__17_16(Type) (at C:/Users/Bjarke/Desktop/Projects/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/DrawerLocator.cs:155)
    System.Linq.Enumerable:ToList(IEnumerable`1)
    Sirenix.OdinInspector.Editor.DrawerLocator:.cctor() (at C:/Users/Bjarke/Desktop/Projects/Sirenix/Sirenix Solution/Sirenix.OdinInspector.Editor/Misc/DrawerLocator.cs:148)
    UnityEditor.EditorAssemblies:processInitializeOnLoadAttributes()
    [/WARNING]
     
  21. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    Huh, that is odd. After some playing around, I've actually managed to replicate this issue on WebGL, which indicates that it is a general issue with IL2CPP. From studying the logs, it appears that some code is being stripped which ought not have been stripped, and so an incorrect deserialization protocol is being run on the serialized data as the correct formatter could not be instantiated due to the stripped code. So it seems that we currently have an issue with dictionary serialization on IL2CPP builds (which includes iOS). I'll be looking into resolving this promptly so we can push a patch with a fix.

    Meanwhile, I'm afraid I can't do anything but apologize for the inconvenience, and tell you that to avoid the error, you should avoid serializing dictionaries in IL2CPP builds.

    We'll add a [RepeatButton] attribute to our todo list of small features to add whenever the opportunity presents itself. Meanwhile, you could do it yourself using the [OnInspectorGUI] attribute:

    Code (CSharp):
    1. [OnInspectorGUI]
    2. private void DrawButtonGUI()
    3. {
    4.     if (GUILayout.RepeatButton("Button name"))
    5.     {
    6.         // Do whatever you need to do when the button is held down
    7.     }
    8. }
    I'm afraid there currently isn't a way to mix a vertically-layouted title and a button group such as you're trying to. However, you can use property ordering to ensure that your buttons appear in the correct order. Keep in mind that groups by default appear before all other elements, regardless of their order of declaration. You'll have to set the property order of your group to make it appear after other members. See the "Ordering" section in the Design with Attributes page of our manual for details.

    There isn't currently a way to disable this warning, but I'll make sure to disable it for that one specific case you have there, which we hadn't considered could occur. Meanwhile, you can change your drawer to an Odin drawer instead, and avoid the warning that way:

    Code (CSharp):
    1. [OdinDrawer]
    2. public class NamedMonoBehaviourDrawer<T> : OdinValueDrawer<T> where T : NamedMonoBehaviour
    3. {
    4.     protected override void DrawPropertyLayout(IPropertyValueEntry<T> entry, GUIContent label)
    5.     {
    6.         // Do whatever you normally do to draw your value here
    7.         // Through the entry parameter, you have access to all the data you need
    8.     }
    9. }
     
    Last edited: Jun 12, 2017
  22. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    To give an update on this, I've managed to locate and resolve the issue in a fairly roundabout way. The error was caused by some very weird code stripping behaviour - even though the entire serialization assembly is marked to be left fully preserved and untouched by the code stripping, apparently there are some things which it still strips regardless. I've now added some explicit (albeit totally pointless otherwise) code calls to the various wrongly-stripped constructors in question (this issue could have affected Odin-serialized collections of all sorts), and now things seem to work perfectly.

    This fix will be included in the next patch. If having this issue resolved is very critical for you, you can PM me your mail, and I'll send you a recent build with the fix included.
     
    zzzzzz789 likes this.
  23. UnityRocksAlt

    UnityRocksAlt

    Joined:
    Dec 28, 2015
    Posts:
    157
    Thanks for quick replies, the company who built this is great and DevDog is a publisher that continuosly updates. I was careful not to buy a asset where the user randomly loses support.
     
    bjarkeck likes this.
  24. zzzzzz789

    zzzzzz789

    Joined:
    Dec 21, 2013
    Posts:
    22
    Thanks so much! Your support is amazing, I am fine waiting for the next patch.
     
    Tor-Vestergaard likes this.
  25. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    Just picked this up to give it a spin. This already looked pretty close feature-wise to Advanced Inspector (which is also great!), but I really liked the serialization and validation features this has. I've got a pretty complicated project that's heavily integrated with Advanced Inspector, so I'm currently in the process of migrating attributes over.

    So, having said that, there are a few attributes in Advanced Inspector that don't have Odin counterparts yet (which I expected going in). However, the documentation on the website for making custom drawers isn't in yet, so I'm hoping I can get some pointers.

    Namely, the one I'm stuck on right now, is a Tag list attribute. Advanced Inspector has the TextField attribute which handles this, but basically I'm looking for an attribute that I can stick on a string (or a list of strings) to give a nice tag selection dropdown (e.g. rather than display a string entry field, it would use EditorGUI.TagField instead).

    I'm pretty used to writing editor code, but the way that Odin handles some of this stuff is pretty different. Any tips that can point me in the right direction?

    Thanks!
     
  26. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    It's quite straightforward to add new attribute drawers. I am currently in the middle of writing the Drawers in Depth section of the manual, and it shouldn't take too long now before it's up. Meanwhile, here is the code for an attribute drawer that draws a string as a tag field:

    Code (CSharp):
    1. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
    2. public class TagFieldAttribute : Attribute
    3. {
    4. }
    5.  
    6. // In an editor folder somewhere
    7. [OdinDrawer] // Cause the drawer to be registered
    8. public class TagFieldAttributeDrawer : OdinAttributeDrawer<TagFieldAttribute, string> // Draw for tag field attributes on string members
    9. {
    10.     protected override void DrawPropertyLayout(IPropertyValueEntry<string> entry, TagFieldAttribute attribute, GUIContent label)
    11.     {
    12.         // SmartValue automatically handles things like multiselection, etc
    13.         entry.SmartValue = label != null ? EditorGUILayout.TagField(label, entry.SmartValue)
    14.                                          : EditorGUILayout.TagField(entry.SmartValue);
    15.     }
    16. }
    It would be used like this:

    Code (CSharp):
    1. [TagField]
    2. public string someTag;
    As you can see, it's rather simple. Odin also lets you use generic parameters as TValue arguments to the OdinValueDrawer and OdinAttributeDrawer generic types. All possible C# generic constraints are supported - drawers in Odin are always strongly typed, so this is how you make drawers for "a class and all derived classes", for example.

    Code (CSharp):
    1. [OdinDrawer]
    2. public class SomeAttributeDrawer<T> : OdinAttributeDrawer<SomeAttribute, T> where T : ISomeInterface, new() // Use this drawer for members with the SomeAttribute on them, which contain types that implement the ISomeInterface interface, and which have a public parameterless constructor.
    3. {
    4.     protected override void DrawPropertyLayout(IPropertyValueEntry<T> entry, SomeAttribute attribute, GUIContent label)
    5.     {
    6.         // Do some drawing here for T - or perform some wrapping code
    7.         // If you wish, call the next drawer in line, which will usually cause the value of type T to be drawn "normally" inside your wrapping code, depending on which other drawers apply
    8.         this.CallNextDrawer(entry);
    9.     }
    10. }
    Hopefully that helps and casts a bit of light on how the system works, and is enough to last you until the manual section is done :)

    If you have any further questions, though, please don't hesitate to ask.
     
  27. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    Nice, thanks a lot! I'll take a better look at this tomorrow. I've got some other attributes that I'll be making counterparts for, so this'll come in handy.

    Glad to hear the docs are coming soon-ish as well -- I'm sure they'll help out quite a bit.

    Thanks again! This should be enough to get me started.
     
  28. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    Another quick question: is it possible to combine TabGroup and any of the other groups (i.e. FoldoutGroup or BoxGroup)?

    Basically I was trying to organize my inspector into tabs, but maintain the Foldout and Box grouping for the data contained in each tab. Right now, it looks like only one works (whichever attribute is defined first). I'm not sure if that's by design, or if I'm doing something wrong (it seems like it should work, so maybe it's just me?).
     
  29. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    Currently you can't put the same member in multiple different groups on the same level. This is coming as it's a popular request, but for now you'll have to make a storage type and then put the other groups into that. For example:

    Code (CSharp):
    1. public struct SomeFoldoutData
    2. {
    3.     [FoldoutGroup("Foldout")]
    4.     public int someField;
    5.  
    6.     [FoldoutGroup("Foldout")]
    7.     public string someString;
    8.  
    9.     [BoxGroup("Box")]
    10.     public string someString2;
    11.  
    12.     [BoxGroup("Box")]
    13.     public string someString3;
    14.     // etc
    15. }
    16.  
    17. [TabGroup]
    18. public SomeFoldoutData data; // Foldout group in tab group
    Edit: Additionally, you can also look at the solution presented here, which is another method of achieving "groups within groups" right now.
     
    Last edited: Jun 14, 2017
  30. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    Ah. That's disappointing (especially since I was almost done migrating!).

    Having a container class isn't really viable as that would A.) change code everywhere and B.) break currently-serialized data.

    The OnInspectorGUI looks like it might work, but it'll make a bit of a mess with having to manually order everything. I can definitely do that, but you mentioned that groups-within-groups is coming. To that end, is it coming soon-ish (i.e. a few weeks or less) or is it more of a long-term type of thing? If it's coming relatively soon, I'd rather just wait on that than go and clutter up my classes with the OnInspectorGUI workaround.

    Thanks for the quick reply! Aside from this I'm digging Odin (and I'm starting to get the hang of doing Inspectors the "Odin way").
     
  31. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    Definitely within the next 2-3 weeks. IE, if it doesn't make the next patch, it will most definitely make the patch after that. To this we do have to add the approximately 5 days that Unity tends to take to approve a patch before it goes live on the asset store, though.
     
  32. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    Alright, awesome. I'll just hold out for that patch, then, and not worry about it for the time being.

    One other thing I've noticed is that the Dictionary drawer is really...clunky? Like, it takes up a ton of space, especially when you start nesting Dictionaries in Dictionaries (i.e. having a Dictionary be a value for a Dictionary). Two or three levels deep there and you start getting a super messy and pretty unusable inspector, especially as many of the field areas start shrinking. I use Dictionaries somewhat frequently, so this is hitting me pretty hard.

    I was thinking that, as a way to save space, it might help to make the foldout label area the actual key field. (Or a label that can toggle to a text field when clicked, so you can still edit keys). This would help in two ways: it would give the foldouts a better, more descriptive name (right now it's the type name) and it would allow you to get rid of the whole Key panel (which would help immensely with horizontal space).

    Hopefully that makes sense. Odin's pretty beautiful out-of-the-box, so the Dictionary inspector kind of stuck out like a sore thumb. :)
     
  33. Froghuto

    Froghuto

    Joined:
    Oct 4, 2012
    Posts:
    61
    Is there a way to disable the add/remove buttons for Lists/Dictionaries? I would like to handle adding/removing items with custom logic, so the user should not be able to remove/add items through the normal inspector interface.
     
  34. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    I totally agree - and love the suggestion, I will add it in there as an option so you can choose between a foldout vs one line, It'll be there in the next patch.

    Currently, this is only possible with lists and arrays by using the ListDrawerSettings attribute.

    Code (CSharp):
    1.     [ListDrawerSettings(OnTitleBarGUI = "AddListElement", IsReadOnly = true)]
    2.     public List<int> SomeList;
    3.  
    4.     private void AddListElement()
    5.     {
    6.         if (SirenixEditorGUI.ToolbarButton(EditorIcons.Plus))
    7.         {
    8.             this.SomeList.Add(this.SomeList.Count + 1);
    9.         }
    10.     }
    11.  
    There is currently no way to remove the existing add button other than marking the list read-only as I did in the example above, but that will also prevent people from dragging and removing items from the list. I'll make sure to add in a "ShowAddButton" option to the ListDrawerSettings attribute for the next patch, I think it would make good sense to have that for cases like this.

    But as a dirty, dirty hack (and I mean really dirty) you could do something like this for now:

    Code (CSharp):
    1.  
    2.     [ListDrawerSettings(OnTitleBarGUI = "AddListElement")]
    3.     public List<int> SomeList;
    4.  
    5.     private void AddListElement()
    6.     {
    7.         // TODO: Replace this dirty hack when the next version of Odin comes out with:
    8.         // [ListDrawerSettings(OnTitleBarGUI = "AddListElement", ShowAddButton = false)]
    9.         // and
    10.         // if (SirenixEditorGUI.ToolbarButton(EditorIcons.Plus))
    11.         // {
    12.         //     ...
    13.         // }
    14.  
    15.         // If we are hovering the mouse over the add button for the list, which was drawn right before this method got called.
    16.         if (GUIHelper.GetCurrentLayoutRect().AlignRight(23).Contains(Event.current.mousePosition)) // As a side node, we can't use GUILayoutUtility.GetLastRect() because it only returns a valid value in repaint events).
    17.         {
    18.             // Then this means that there is a chance that a mouse-down event was fired on it (which we can't know for sure, but it is likely).
    19.             // Lets interrupt that mouse-down event, and make the button belive it is not being pressed.
    20.             if (Event.current.type == EventType.Used)
    21.             {
    22.                 GUIUtility.hotControl = 0;
    23.             }
    24.  
    25.             // But we know better!
    26.             if (Event.current.type == EventType.MouseUp)
    27.             {
    28.                 this.SomeList.Add(this.SomeList.Count + 1);
    29.                 Event.current.Use();
    30.             }
    31.         }
    32.     }
     
    Last edited: Jun 15, 2017
    Froghuto likes this.
  35. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    Awesome, can't wait to see it. Thanks for being so open to suggestions!
     
  36. adsilcott

    adsilcott

    Joined:
    Aug 30, 2014
    Posts:
    55
    I'm writing a custom property drawer to insure that the object selector displays types that are derived from an abstract class SequenceNode:

    Code (CSharp):
    1. [CustomPropertyDrawer(typeof(SequenceNode))]
    2. public class SequenceNodePropertyDrawer : PropertyDrawer
    3. {
    4.     public override void OnGUI(Rect _position, SerializedProperty _property, GUIContent _label)
    5.     {
    6.         EditorGUI.BeginChangeCheck();
    7.  
    8.         Object value = EditorGUI.ObjectField(_position, "Sequence", _property.objectReferenceValue, typeof(SequenceNode), false);
    9.  
    10.         if (EditorGUI.EndChangeCheck() )
    11.             _property.objectReferenceValue = value;
    12.     }
    13. }
    It works fine but I'm getting this error:
    Invalid drawer declaration 'UnityPropertyDrawer<SequenceNodePropertyDrawer, SequenceNode>'; you cannot use an abstract class 'SequenceNode' as the drawn value type. Use a generic drawer with a constraint for that abstract class instead.

    I saw a similar error posted here. I tried writing an OdinDrawer but I don't know how to call the Editor.GUI.ObjectField from that.

    Edit:
    This code only works when the property is being displayed in a custom editor, which works in this case, but I'll probably go with a different solution in the long run, so you can disregard this.
     
    Last edited: Jun 15, 2017
  37. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    So, couple of things I am running into.

    1. Odin seems to be constantly recompiling its DLLs and otherwise modifying some of its own files. This is playing havok with Git. It also seems to be slowing things down when I move in and out of Unity. Is there an option to disable this?
    2. I am still learning to use Odin, so this might just be user error. But I LOVE the inline editing ability thing that lets me create items on the fly. However I have items that contains lists of interfaces and those don't seem to work in the inline editor?
    3. I have a custom color thing that is basically a color stored as a string in the #FFFFF format but in the inspector I want it to be a color picker. Now I had previously done this using built in Unity stuff, but some installing Odin that has not been working. How can I rebuild that for Odin?
     
  38. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    There are a couple of files which often change in Odin.

    Whenever you add, remove or rename a new script which requires a custom editor, Odin will automatically recompile the GeneratedOdinEditoes.dll located in the Sirenix/Assemblies/Editor folder. This will trigger an extra recompile step, not much we can do about that, that is the price we pay for not creating a custom editor ourselves. However, this shouldn't happen when you simply make changes to a script. But there is no need for the generated odin editor file to be part of the version control, as it will regenerate as needed. More about this in the getting started guide:

    http://sirenix.net/odininspector/manual/introduction/getting-started
    (You can actually safely ignore the entire Sirenix/Assemblies/Editor folder)

    You can, of course, disable automatic editor compilation in "Window > Odin Inspector > Preferences > Editor Types", but then you will need to trigger it manually everytime you create a new file, and want to use Odin's features.

    Many of Odin's preferences is stored in a ScriptableObjects and are project-based, this means that if you play around Odin preferences window this will cause the scriptable objects to change as well.

    But everything else should remain the same.
    So you mean something like this right?
    Code (CSharp):
    1.  
    2.     [InlineEditor]
    3.     public ISomeInterface[] Test;
    This works for me, but it actually displays an error where it shouldn't. So thanks, hope it was the same error you've got :)

    Hmm, something like this?:
    Code (CSharp):
    1.  
    2. public class MyComponent : SerializedMonoBehaviour
    3. {
    4.     [HideInInspector]
    5.     public string MyHexColor;
    6.  
    7.     [ShowInInspector]
    8.     public Color MyColor
    9.     {
    10.         get
    11.         {
    12.             Color color;
    13.             ColorUtility.TryParseHtmlString(this.MyHexColor, out color);
    14.             return color;
    15.         }
    16.         set
    17.         {
    18.             this.MyHexColor = "#" + ColorUtility.ToHtmlStringRGB(value);
    19.         }
    20.     }
    21. }
    You could also easily create your own attribute for it, here is how you would do it usin Odin:

    Usage:
    Code (CSharp):
    1. public class MyComponent : SerializedMonoBehaviour
    2. {
    3.     [HexColor]
    4.     public string MyHexColor;
    5. }
    Attribute:
    Code (CSharp):
    1. public class HexColorAttribute : Attribute
    2. {
    3.  
    4. }
    Drawer (Located in an Editor folder, or wrapped inside #if UNITY_EDITOR):
    Code (CSharp):
    1.  
    2. [OdinDrawer]
    3. public class HexColorAttributeDrawer : OdinAttributeDrawer<HexColorAttribute, string>
    4. {
    5.     protected override void DrawPropertyLayout(IPropertyValueEntry<string> entry, HexColorAttribute attribute, GUIContent label)
    6.     {
    7.         Color color;
    8.         ColorUtility.TryParseHtmlString(entry.SmartValue, out color);
    9.         color = label == null ? EditorGUILayout.ColorField(color) : EditorGUILayout.ColorField(label, color);
    10.         entry.SmartValue = "#" + ColorUtility.ToHtmlStringRGBA(color);
    11.     }
    12. }
     
    Last edited: Jun 16, 2017
  39. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    This is what we have at the moment:
    Code (CSharp):
    1.  
    2.     public List<IVehicleStage> Stages;
    3.  
    With this, I can add List items, but the item added is just an empty IVehicleStage item, with no properties or anything. What I would expect is when clicking, the pop up would let me select a concrete class that implements the interface.

    I tried adding [InlineEditor] and then just got an error saying InlineEditorAttribute can not be put on property Stages of type List<IVehicleStage>
     
  40. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    Are your classes that are implementing the IVehicleStage by any chance internal or are they inheriting from MonoBahaviour or such? If that is the case our current instance creator window, will not locate it. But regular classes and such should work fine:
    interface.png

    Even tho components won't show up in the instance creator window, they can still be dragged from the hiearchy or project window and into the object field.

    We are working on a new and improved instance creator which can handle much more, but that is a couple of patches away.

    Edit: Forgot to mention that the latest public build also have a bug where the instance creator window won't locate structs that implement an interface. This is fixed in the next upcoming patch.
     
  41. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Yes they are SerializedMonoBehaviour :(
     
  42. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    Then your only option currently is to press the Add button, add a null value, and drag the desired object which or has something that contains the interface into the object field, Sorry! This will be better in the future, but the new instance picker window is a few patches away still.
     
  43. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Don't be sorry. In hindsight it makes sense and I think the fault lies not with Odin but with our design :)
     
  44. jwvanderbeck

    jwvanderbeck

    Joined:
    Dec 4, 2014
    Posts:
    825
    Hi,

    I see mention of the DLL in the docs, but there are tons of PDBs that keep having their metadata updated, for example:

    Assets/Plugins/Sirenix/Assemblies/NoEditor/Sirenix.Utilities.pdb.meta
    Assets/Plugins/Sirenix/Assemblies/NoEmitAndNoEditor/Sirenix.Serialization.pdb.meta
    Assets/Plugins/Sirenix/Assemblies/NoEmitAndNoEditor/Sirenix.Utilities.pdb.meta
    Assets/Plugins/Sirenix/Assemblies/Sirenix.OdinInspector.Attributes.pdb.meta
    Assets/Plugins/Sirenix/Assemblies/Sirenix.OdinInspector.Editor.pdb.meta
    Assets/Plugins/Sirenix/Assemblies/Sirenix.Serialization.Config.pdb.meta
    Assets/Plugins/Sirenix/Assemblies/Sirenix.Serialization.pdb.meta
    Assets/Plugins/Sirenix/Assemblies/Sirenix.Utilities.Editor.pdb.meta
    Assets/Plugins/Sirenix/Assemblies/Sirenix.Utilities.pdb.meta

    Are all these PDBs being rebuilt? Can I safely ignore them and their meta files?
     
  45. bjarkeck

    bjarkeck

    Joined:
    Oct 26, 2014
    Posts:
    301
    That is strange, I wonder what is triggering unity to regenerate the meta files? But yes you can safely ignore all *.pdb.meta files.
     
  46. LootlabGames

    LootlabGames

    Joined:
    Nov 21, 2014
    Posts:
    343
    Solved: I just had to modify the editor types.

    I am having problems with Odin.

    After I import the package I get these warnings/errors:

    Warnings:
    1)The following 4 errors occurred while compiling a generated assembly at 'G:/My Projects/MyProject/Assets/Plugins/Sirenix/Assemblies/Editor/GeneratedOdinEditors.dll':
    2) ( You can view the faulty source code files at the path 'G:\My Projects\MyProject/Temp/CodeGeneration-951f0578-1ea3-44ab-9a57-f50f7c93cadf/'. They will remain until Unity is restarted. )

    Errors:
    1) G:\My Projects\MyProject/Temp/CodeGeneration-951f0578-1ea3-44ab-9a57-f50f7c93cadf/CompiledEditorContainer.cs(62,110): error CS1031: Type expected
    2) G:\My Projects\MyProject/Temp/CodeGeneration-951f0578-1ea3-44ab-9a57-f50f7c93cadf/Drawers.cs(359,81): error CS1031: Type expected
    3) G:\My Projects\MyProject/Temp/CodeGeneration-951f0578-1ea3-44ab-9a57-f50f7c93cadf/Drawers.cs(362,73): error CS1525: Unexpected symbol `Cursor_Editor'
    4) G:\My Projects\MyProject/Temp/CodeGeneration-951f0578-1ea3-44ab-9a57-f50f7c93cadf/Drawers.cs(9005,0): error CS1525: Unexpected symbol `}'

    Please let me know how to proceed.
     
    Last edited: Jun 16, 2017
  47. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    We had a similar issue recently. Sometimes, types exist in user assemblies that do not have valid C# type names. Therefore, when Odin tries to create editors for them, the invalid type names will cause compiler errors. In the next patch that we're going to be putting out, we've implemented new logic that checks all generated type names against the official C# specification's requirements for type identifiers - that should resolve these kinds of issues for good.

    Good to hear that you found the solution yourself, though.
     
  48. Tor-Vestergaard

    Tor-Vestergaard

    Joined:
    Mar 20, 2013
    Posts:
    188
    To provide an update on this, we just finished this feature today, so it's going to be in the next patch. We're not sure when exactly we're going to submit that patch as we have a few other things coming up for it as well, but it's quite likely going to be within the next week or so, as we want it to be ready before Unity Unite in Amsterdam on the 27th.

    You can now put groups within other groups. Additionally, groups will by default be placed where their first declared member otherwise would have been placed. For example, this code:

    Code (CSharp):
    1. public class MyMonoBehaviour : MonoBehaviour
    2. {
    3.     [TabGroup("MyTabGroup", "Tab A")]
    4.     public string A;
    5.  
    6.     [TabGroup("MyTabGroup", "Tab B")]
    7.     public string B;
    8.  
    9.     [BoxGroup("MyTabGroup/Tab B/MyBoxGroup")]
    10.     public string C;
    11.  
    12.     [BoxGroup("MyTabGroup/Tab B/MyBoxGroup")]
    13.     public string D;
    14.  
    15.     [TabGroup("MyTabGroup", "Tab B")]
    16.     public string E;
    17. }
    Results in this editor:
     
  49. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    Very nice! I was expecting it to be nested attributes (i.e. [TabGroup] for the tab and [BoxGroup] for the box in the tab) but the string path idea is interesting. Can't wait to play around with it and get more of my inspectors migrated! :)
     
  50. jeremedia

    jeremedia

    Joined:
    Apr 21, 2015
    Posts:
    63
    Awesome. Thank you!!