Odin Inspector Version 3.0.9

Changes

  • Made LinqExtensions.ToHashSet extension methods warning-level obsolete, as they are causing naming conflict issues in Unity 2021.2+ and will be removed in the future. Internally, all of Odin's usage of these extensions has been removed.

Fixes

  • Fixed case where a nullable value's drawers would be called by the NullableReferenceDrawer if the value is null and the value is drawn with [InlineProperty] - the NullableReferenceDrawer will not pass on the call for null values, as it is when there is no [InlineProperty] on it.
  • Fixed case where a nullable value's drawers would not be called by the NullableReferenceDrawer if the value is drawn with [InlineProperty] and without [HideLabel]
  • Fixed case where Odin attempting to load a broken validation config asset during batch mode execution of Unity with the -quit argument set would cause Unity to freeze. Instead, an error is now logged to the console warning about what happened, and the attempt to load the asset is abandoned.
  • Fixed case where the TypeFilter attribute would never invoke the constructor of instantiated types when they are picked. Constructors should now be invoked, when a parameterless/default constructor is available.
  • Fixed compiler errors in Odin Validator and in Odin Inspector's source mode installation in Unity 2021.2.0b8+
  • Fixed IndexOutOfRange exception that could occur in the PrefabModificationHandler when inspecting prefab instances.
  • Fixed issue where styles in the OdinActivationWindow would not be initialized by Unity and become null.
  • Fixed slight spacing issue after nullable values drawn with [InlineProperty]
  • The OdinMenuTree.AddAssetAtPath, AddAllAssetsAtPath and AddAllAssetsAtPathCombined extension methods now supports providing asset paths that starts with "Packages/" as well, thus enabling them to work for assets that exist in packages.

Odin Inspector Version 3.0.8

Features

  • License Management for Enterprise

    Starting with version 3.0.8 of Odin Enterprise, License Management can be enabled in the new Downloads page when you download an enterprise build of Odin for your organization. This optional feature lets you more easily manage and get an overview of your organization's seat usage. Learn more here.

Additions

  • Added EnumTypeUtilities and cleaned up EnumSelector.
  • Added Left aligned grey label style to SirenixGUIStyles.
  • Exposed EnableAutomaticHeightAdjustment for OdinEditorWindows.

Fixes

  • Fixed runtime crash when emitting fast getter for static properties via EmitUtilities in Unity 2021.2. This would cause Unity to crash when, for example, using the static inspector to view any class with static properties.
  • Fixed case where, if a prefix label was drawn before an Odin-drawn Unity object field or preview field for a null/destroyed Unity object value, the prefix label would be disabled regardless of the disabled state of the drawn field.
  • When a member of a HorizontalGroup becomes invisible, it will now no longer claim any layout space at all.

Odin Serializer fixes

  • Fixed case where, when a BinaryDataReader enters a struct node, the currently peeked entry name would be null instead of the correct name.

Odin Inspector Version 3.0.7

Optimization

  • Optimized the locating of UnityEngine.Object and Editor types in InspectorTypeDrawingConfigDrawer when initializing Odin's editors. This should slightly reduce Odin's impact on reload times in very large projects, but smaller projects are unlikely to notice much of a difference as the impact should already be quite small.

Additions

  • Added DictionaryDrawerSettings.KeyColumnWidth, which controls the default key column width of the drawn dictionary. The default value of KeyColumnWidth is 130.
  • Added a clarifying note to the ChildGameObjectsOnly example in the attribute overview to state that it cannot be displayed in the overview, but copying it to a component script will cause it to display correctly.

Changes

  • A dictionary's key column width is now a persistent value, meaning if you change the column width by dragging it, it will remain where you put it across selections and reloads.
  • The key column width of dictionaries now allows 30 pixels as its minimum width instead of 90.

Fixes

  • Fixed case where, if you search a collection and remove an element while the search is being displayed, index out of range exceptions would start being thrown and the collection drawer would partially break.
  • Fixed harmless logged error message when opening the type selector popup in the Serialization Debugger window on Linux.
  • Fixed issue in the new StringSlice added in 3.0.6 where StringSlice.GetHashCode() would not give consistent results for slices of a length that is a multiple of 8 minus 1, IE, 7, 15, 23 and so on. This would result in invalid property lookups whenever a member name with one of those string lengths was used, primarily noticeable by for example Odin-serialized AnimationCurves failing to draw properly and giving an error message for such cases.
  • The Preferences window will now display the correct version of Odin Inspector at the bottom of the left-hand menu.
  • Dictionary and GUITable columns can now be dragged when GUI.enabled is false, IE, for example when the ReadOnly attribute is applied.

Odin Serializer fixes

  • Fixed AmbiguousMatchException being thrown by AssemblyImportSettingsUtilities in Unity 2021.2.

Odin Inspector Version 3.0.6

Additions

  • Added bool IncludeInactive parameter to the ChildGameObjectsOnly attribute, determining whether inactive children should be considered when finding valid child values.
  • Added CopyValues bool to ValueDropdown, which is true by default and controls whether the value dropdown should set copied values or set the original references it was given.
  • Added DirtyOnClick parameter to the Button attribute, which controls whether the button should mark its context dirty or not when it is clicked.
  • Added four new color preference values in the Preferences > General > Collections tab that can be used to change the default color of even and odd list elements in the dark and light skin.
  • Added ListDrawerSettings.ElementColor which is a resolved string that can be used to control the color of each individual element in the list. The resolved string has the extra named values "int index" and "Color defaultColor" available, which are respectively the element index and the color that would normally be used for that element.
  • Added OdinPropertyResolver.IsCollection as a fast path replacement for checking `ChildResolver is ICollectionResolver`. We now recommend using this instead of checking for the interface, as they are functionally equivalent.
  • Added Sirenix.Utilities.Editor.StringSlice, a new type for accelerating working with substrings without requiring new string allocations, for use with the property system particularly as regards to accelerating the process of looking properties up by path and making such queries allocation free when the property already exists. While it is true that modern C# versions contain types like Span<T> and Range for exactly this purpose, Odin also supports older environments that do not have these features, so we have made our own version suitable for our needs.
  • Added a new virtual method OdinPropertyResolver.ChildNameToIndex(ref StringSlice name), which is the new main method used by the property system to look up child properties by their name. The method's default implementation simply calls OdinPropertyResolver.ChildNameToIndex(string name), but it is the new recommended practice to implement actual resolution logic in this method and have OdinPropertyResolver.ChildNameToIndex(string name) call it, as this will improve the overall path lookup performance of the property system.

Optimization

  • Completely changed how Unity prefab instance PropertyModifications are registered for properties in the PropertyTree. Viewing prefab instances with very large numbers of modifications in the inspector should now be much faster and scale far better with the number of modifications on the prefab instance. Note that performance is still likely to be rather chunky for prefab instances with very large numbers of modifications, as while Odin's side of the code is now fairly fast, the calls we are making to the Unity API itself are still very costly. We hope this will only be the first half of the changes we are making to address issue #733, though further optimizations are less certain to be viable to implement.
  • PropertyTree.GetPropertyAtPath, PropertyTree.GetPropertyAtUnityPath and PropertyTree.GetPropertyAtPrefabModificationPath now use the new StringSlice for their lookups. This means that the performance looking a property up by any of its paths has improved by 2x-3x, and the garbage allocation of such calls has been reduced to 0, as long as the property that is looked up already exists.
  • All of Odin's pre-existing PropertyResolvers have been modified to use StringSlice-based lookups instead of string lookups, reducing allocations and increasing basic path lookup speed slightly. For custom-built resolvers, this should be as simple as changing any Dictionary<string, InspectorPropertyInfo> cache lookups can be changed to use StringSlice or StringSlice.PreHashed as keys instead.

Changes

  • Attribute expressions given the short identifier "Color" will now always prefer to interpret that as meaning "UnityEngine.Color" even if there are many types named Color available in the project.
  • Slightly increased the default even/odd list element color contrast in the dark skin of Unity to make the distinction between list elements more clear.
  • The Unity.Entities support module's version has been incremented to 1.0.1.0, as its resolvers have been changed to use StringSlice.

Fixes

  • Editor Only Mode toggling now also disables the Sirenix.OdinInspector.CompatibilityLayer assembly definition, and keeps the .meta files with any moved scripts instead of deleting .meta files and letting Unity generate new ones.
  • Fixed case where copying a struct would copy its values by reference by default, instead of deep copying it. This behaviour has been changed to deep copying by default.
  • Fixed case where PropertyTree.OnUndoRedoPerformed would incorrectly stop being invoked after a new selection happens in the inspector.
  • Fixed case where PropertyTrees would "leak" and not be able to be collected by the GC unless a new selection happens in the inspector, even after they are disposed. (Note that it is still very important to dispose PropertyTree instances once you are done with them, or they will leak and remain in memory forever.)
  • Fixed compile errors in Odin source mode from type name collisions introduced by Unity adding a UnityEditor.SerializationUtility type in 2021.2.
  • Fixed error where OdinPropertyResolver.HasChildCountConflict and OdinPropertyResolver.MaxChildCountSeen would contain incorrect, un-updated values if OdinPropertyResolver.ChildCount has not been gotten yet for that frame/tree update ID. This fixes an issue where, sometimes, reverting the list/array length modification of a list/array on a prefab instance would wipe all modifications in that list, instead of only modifications on all added list/array elements that were removed by the operation.
  • Fixed invalid errors being logged when changing values of a Unity-serialized dictionary in a prefab instance.
  • Fixed issue where Odin's enum dropdown would throw InvalidCastExceptions for non-int enums that don't have a None/0 value defined.
  • Fixed issue where running a validation scan while the editor is in batch mode would throw drawer-related exceptions if the validation scan triggered property state changes through attributes such as ShowIf or HideIf.
  • Fixed issue where TypeFilter could not create instances of types that had no public parameterless constructors.
  • Fixed issue where TypeFilter could would set values of null instead of creating proper instances when creating values for types which would not be serialized by Unity.
  • Fixed regression introduced in 3.0.3 where [InlineEditor] on a GameObject would be incapable of rendering a preview but would instead display a message box as if the full inspector rendering was always requested. Now the message box is only displayed if the InlineEditor is not set to render a preview.
  • The compiler-level restrictions on where the Button attribute be applied have been removed, such that it can also be used with composite attributes and so on.
  • The InlineEditor attribute drawer now catches exceptions thrown when it's being disposed and is destroying its editor instances.
  • ValidateInputAttribute.MemberName has been turned into a wrapper property for the Condition member so as not to break legacy code using that member, and noted as obsolete in the documentation instead of only being marked with the Obsolete attribute.

Odin Project Validator fixes

  • Fixed case where the On Build automatic validation hook would not run properly when the project was being built via Unity Cloud Build.
  • Fixed the Odin Validator package containing a default OdinValidationConfig asset that would override the settings that users had in their validation config.

Odin Serializer fixes

  • Fixed issue where, when serializing a Stack<T> that contains in an element somewhere a reference to another Stack<T> of the same generic variant type, an IndexOutOfRangeException would be thrown if you're lucky, and corrupt data would be written if you're unlucky.
  • Corrected FormatterLocator.cs's assembly iteration to use the Assembly.SafeIsDefined extension method instead of Assembly.IsDefined, ensuring Odin won't throw errors if assemblies with invalid attribute declarations are loaded.

Odin Inspector Version 3.0.5

Additions

  • Added dedicated download for educational version of Odin.
  • Added SirenixEditorGUI.ToolbarToggle overload that takes a Texture.
  • Added ShowIf resolved string parameter to the InlineButton attribute that controls whether it should be shown or not.
  • Added ActionResolver.GetFromContext(ref ActionResolverContext context) and ValueResolver.GetFromContext(ref ValueResolverContext context) methods that let you manually pass in a pre-configured context to the resolver systems, since the values in the context such as SyncRefParametersWithNamedValues can change how resolution happens. Also added ActionResolverContext.CreateDefault and ValueResolverContext.CreateDefault to make it easier to create proper default-configured contexts to be passed into these new APIs.
  • Added ActionResolverContext.IsResolved and ValueResolverContext.IsResolved, which will be true after the context has been resolved.

Changes

  • ActionResolverContext.ResolvedString, ActionResolverContext.SyncRefParametersWithNamedValues, ValueResolverContext.ResolvedString, ValueResolverContext.SyncRefParametersWithNamedValues and ValueResolverContext.ResultType can no longer be changed after the context has been resolved. If you were using SyncRefParametersWithNamedValues the old way where it was set after the context had been resolved, you now instead need to create a default context using ActionResolverContext.CreateDefault or ValueResolverContext.CreateDefault and then set SyncRefParametersWithNamedValues to true before before calling ActionResolver.GetFromContext(ref ActionResolverContext context) or ValueResolver.GetFromContext(ref ValueResolverContext context) to get resolver. The tutorials have been updated to reflect this change.

Fixes

  • Fixed case where the AssetSelector would act as if it was on an element in a list, despite that not being the case.
  • The AssetSelector attribute drawer now only targets UnityEngine.Object types.
  • The Searchable attribute now also works on normal types drawn without a label.
  • Fixed case where methods referenced by ValidateInput would cause errors if the referenced method had a string parameter named property.
  • ActionResolvers and ValueResolvers can now no longer match named values to method parameters if those parameters cannot both be converted from *and* to the named value type. Before we only checked that they could be convert from the named value type to the parameter type. Now we check the other way as well.
  • Odin's ActionResolver and StateUpdater locators now correctly handle invalid/broken assemblies when scanning all loaded assemblies for relevant type registrations, rather than choke on said assemblies.
  • Custom context menu items added using the CustomContextMenu now work with Undo and dirty the containing asset/scene if any value changes are made during the callback.
  • Fixed an issue where opening GenericSelectors or EnumSelectors on Linux (such as via changing enum values or opening value dropdowns), multiple errors about pop call mismatches and empty stacks would be logged in the inspector.
  • Odin will now not initialize its editors when the editor is being run in headless or batch mode.
  • Expressions that are empty or consist of only comments are now allowed.
  • The TypeFilter attribute will not trigger special list drawing behaviour if DrawValueNormally is set to true.

Serializer fixes

  • UnitySerializationUtility.GuessIfUnityWillSerialize(MemberInfo member) now correctly guesses that Unity will not serialize readonly fields.

Odin Inspector Version 3.0.4

Improvements

  • Optimized several parts of the property system that turned out to be acting as performance bottlenecks in certain scenarios, particularly large project validation scans. Users who experienced project validation scans becoming slower in 3.0 should now see significant improvements, to the point of matching or in some cases even exceeding 2.1.x validation performance. If some users are still experiencing project validation scans which are far slower than in 2.1.x, please contact us with reproduction steps or detailed profiling data and we will look into it.
  • Added null conditional operator support to attribute expression. This includes support for the following null conditional operations: member access (value?.member), element access (array?[index]), member assignment (value?.member = something), element assignment (array?[index] = something), member invocation (value?.method()), element invocation (array?[index]()). Note that the behaviour of this operator differs slightly from C#; the attribute expression version of the null conditional operator will consider destroyed UnityEngine.Object instances to be null, whereas in "vanilla" C#, it will not.
  • OdinMenuTreeExtensions.SortMenuItemsByName now uses a far better number-aware sorting method, which should give both better sorting results, and better sorting performance.
  • Removed or tweaked various usages of the current SerializedObject instance during inspection, so there are fewer reasons to work with it. Since it is lazy updated by Odin, this means that it will be updated more rarely and trigger fewer serialization calls.

Additions

  • Added StringUtilities.NumberAwareStringCompare method.
  • Added new overloads of OdinMenuTreeExtensions.SortMenuItemsByName for improved control of how sorting should be done.
  • Added "Delete element" context menu item to collection elements.
  • Added InvokeOnInitialize parameter to the OnValueChanged attribute, which will cause the action to be invoked when property initialization runs (IE when the inspector first opens, for instance), as well as when the value is actually changed.
  • Added InspectorProperty.MarkSerializationRootDirty(), which marks the serialization root objects of the property dirty, if any such applicable roots exist and are UnityEngine.Object instances.
  • Added InspectorProperty.MarkSerializationRootDirty(), which marks the serialization root objects of the property dirty, if any such applicable roots exist and are UnityEngine.Object instances.
  • Added a new [DontValidate] attribute which can be put on members to prevent the validation system from running validation on them; they will not show validation messages in the inspector, nor will the project validator scan them.

Changes

  • Removed the Sirenix.Utilities.Cache and Sirenix.Utilities.ICacheNotificationReceiver types. Use the Sirenix.Serialization.Utilities versions of these types instead.
  • The Check for updates window now states what the current version is when the version is up to date.

Fixes

  • Fixed case where property system would throw an exception when failing to create an alias property for an inherited member that has been overridden by a new member in a deriving type.
  • The ListDrawerSettings attribute is no longer passed down to collection elements, so putting it on a list of lists or similarly nested collection member will only affect the top-level collection.
  • Fixed error message that Odin's UnityPropertyHandlerUtility would give in Unity 2021.1 stating it could no longer find the m_propertyDrawer member in the UnityEditor.PropertyHandler type. It has been updated to reflected internal changes made to UnityEditor.PropertyHandler in 2021.1.
  • Fixed case where Copy/Pasting values would break when deep copying and pasting the same objects multiple times.
  • The searchable attribute is no longer inherited by a collection's elements when it is placed on a collection member.
  • NullableReferenceDrawer will now give a better error message and not ruin the GUI layout draw stack when a seemingly Unity-serialization-backed member's value is incorrectly null.
  • The RequireComponentValidator will now check whether the required types are actually components before checking for them. If they are not components, they will be bypassed and considered "valid".
  • Fixed OdinEditorWindow.UseScrollView always being set to true when set, regardless of the value passed to the property setter.
  • Fixed ListDrawerSettingsAttribute.CustomRemoveIndexFunction and CustomRemoveElementFunction not working when used with arrays.
  • Fixed another case where the EULA popup window would break by wrongly triggering during a Unity Cloud Build. This is done by checking whether the editor is being run in batch mode.
  • BoxGroup will now actually draw an error message if its label string is resolved and contains errors.
  • Updated UnitySerializationUtility.GuessIfUnityWillSerialize to reflected that generic UnityEngine.Object references are serialized by Unity in 2020.1 and above.
  • Added UnityEngine.AnimationState to the UnitySerializationUtility.GuessIfUnityWillSerialize method's blacklist of types that Unity will not serialize.

Odin Inspector Version 3.0.3

Fixes

  • Fixed list/array and many other drag and drop operations being broken in Unity 2020.2.
  • Removed errant EditorGUI.BeginChangeCheck() without corresponding end check in FilePathAttributeDrawer.
  • Lowered the priority of the UnityObjectRootDrawer to (0, 100, 0), so other drawers like the validation drawer can draw first. This fixes the case where validation messages for a root inspected component instance would not be displayed at the top of the inspector as they should when inspecting that validated object.
  • Attempting to draw a GameObject inline by inspecting it directly, or by using InlineEditor to draw a GameObject value now results in a helpful message with options for inspecting or selecting the GameObject properly.
  • All overloads of SirenixEditorGUI.IconButton now properly pass in the tooltip string they are given to the GUI.Button() call. However, note that this doesn't always mean that Unity's GUI.Button() will decide to make use of the tooltip and display it properly in all cases.

Odin Project Validator

Improvements

  • The validation profile running window can now also display the property path of validation messages, and also shows a relevant asset/scene path for the message in more cases.

Fixes

  • Project validation scans now correctly handle scanning assets and components with missing scripts, and generate helpful error messages in such cases.

Odin Inspector Version 3.0.2

Fixes

  • Corrected Odin's serialization/prefab warning messages to be more current.
  • Fixed another case where it was not safe to call DrawEditor(int index) in an OdinEditorWindow before OnGUI() has been called at least once. The GameManager series of videos should now be more easily followable, since the most common failure cases of the approach it suggests no longer causes any errors.
  • Fixed caching-based issue where group attributes would be both cached *and* mutated by the grouping system. This caused an issue where, if you had a group declared in type A, and then you have types B and C derived from A, each also adding members to the inherited group, then the data from attributes on the members in types B and C would be merged into the cached attribute from A, and thus "cross-contaminate" from B to C and vice-versa. The fix is that a deep copy is now always made for the merged attribute, reverting an optimization made for 3.0. This means that initialization performance in group-heavy inspectors will be slightly worse.
  • Fixed case where properties would not properly update their components if needed, when RefreshSetup() is called on them. Along with the below point, this fixes an issue where validation would not function properly for root values, IE, a validator for a component type would not scan instances of that component.
  • Fixed case changing the component providers of a PropertyTree via SetUpForValidation() or SetUpForIMGUIDrawing() would not cause RefreshSetup() to be invoked on the RootProperty of the tree.
  • Fixed error introduced in 3.0.1, where non-method members marked with OnInspectorInit would be assigned an order of int.MinValue, instead of only method members, as was intended.
  • Fixed issue where no emitted SerializedProperty could ever be created for dictionary key drawing, breaking all backwards compatibility with legacy Unity PropertyDrawers for drawing dictionary key values. This was due to the StrongDictionaryPropertyResolver not redirecting child path queries for its key properties properly. This fixes a known issue with the Peek asset breaking Odin's drawing of all dictionaries with UnityEngine.Object derived keys.
  • Fixed issue where the list of emitted Unity SerializedProperty host objects to be destroyed was not cleared after said objects were destroyed, causing performance to get worse over time in cases where a lot of non-Unity-backed SerializedProperty instances need to be emitted for Unity PropertyDrawer backwards compatibility purposes.
  • Fixed issue where ValueDropdown would not work correctly when placed on a method parameter.
  • Fixed issue where, when using ValidateInput to validate a string, and using an "unnamed" string parameter in the validation method as the first parameter, the resolver would assign the "message" named value instead of the "value" named value to the first parameter. The named value "value" is now always assigned to parameters by type before the "message" named value is.
  • Fixed layouting issue where members marked with the InlineProperty attribute would have incorrect spacing in some cases, missing 2 pixels of spacing at the bottom.
  • Fixed several issues with Odin controls and drawers. This fix affects TextArea, the NullableReferenceDrawer, SirenixEditorFields.PolymorphicObjectField and the PropertyContextMenuDrawer.
  • Fixed the StrongDictionaryPropertyResolver not respecting the "DontApplyToListElements" attribute, and copying invalid attributes to its direct child properties. This fixes a case where ValidateInput and similar attributes placed on dictionaries would result in errors being registered in the Project Validator.
  • Made the EULA popup more resistant to errors when opening in odd situations like a cloud build running in non-headless mode but where all window creation is broken anyways (??).
  • Odin's "Apply value to prefab" context menu item should now work properly again for Unity-serialized prefab values.
  • Odin's "Revert to prefab" context menu items now correctly mark their containing asset/scene as dirty and have their changes registered for Undo.
  • Potential fix for eternal loop in Folder/FilePath attributes when trying to open the file or folder window on missing external storage.
  • Updated the OdinAttributeDrawer docs that were referencing obsolete APIs.
  • ValueEntry.WeakSmartValue/WeakValues now give a better InvalidCastException message when an invalid type is passed in, stating which type was invalid and what the expected type was.

Change

  • Added two new buttons to each example in the Attribute Overview, "Copy Component" and "Create Component Script" which will let the user try out the example as a regular Unity component. Many examples were modified to accomodate this.
  • All examples in the Attribute Overview that implicitly require Odin's serialization in order to work now have an extra info box noting this fact.

Unity.Mathematics module

Module version incremented to 1.0.1.0

Fix

  • Fixed issue where installing the "Unity.Mathematics support" module would cause the types "int3" and "uint3" to not have their "Z" values drawn.

Odin Project Validator

Fix

  • Fixed multiline error messages not showing in full in the Project Validator overview. The window might still need to be expanded horizontally to view the full message. Many more UX improvements are coming soon to the Project Validator.
  • Fixed case where Unity would sometimes not load prefab assets correctly when the AssetValidationProfile scans the project, causing some prefab components/assets to be null despite being loaded straight from the AssetDatabase. A different loading approach is now used for prefabs that should reduce our exposure to this asset loading bug.

Odin Serializer

Fix

  • Fixed the case where Json serialized string writing could overrun the buffer when they contained characters that needed to be escaped.

Add

  • Added OdinPrefabSerializationEditorUtility.ApplyPropertyOverride method along with an OdinPrefabSerializationEditorUtility.HasApplyPropertyOverride property.

Odin Inspector Version 3.0.1

Update 3.0 introduces significant performance improvements, and several new foundational features and architecture improvements that will make it easier than ever to work with Odin, and that lay the groundwork for future patches. 3.0 is about the future; it's a major spring cleaning patch where we've gone back through our entire codebase and cleaned up, improved, and re-architected for anticipated future needs.

As such, this is not a patch focused on shiny new features. That being said, we do have a few shiny new features. But before we take a look at them, we want to bring your attention to another important change:

For a long time, the Odin Personal license (formerly named Odin Commercial) has been the only way to buy and use Odin for all customers. Odin Enterprise is a new license that launched with the 3.0 beta, and came with an attendant change in our EULA. In short, Odin Enterprise is now required for any entity using Odin with revenue or funding greater than $200,000 USD in the last 12 months. For more details on the terms and features of Odin Enterprise, as well as our reasoning behind launching it, see our updated pricing page and our blog post about the launch of Odin Enterprise.

Now let's take a look at all the new features and improvements that 3.0 brings!

Modules

Starting the trend of preparing for the future, we've added a modules feature to Odin. Modules are small, conditionally toggleable "bundles" of features that can activate and deactivate themselves based on whether their dependencies are present in the project. They solve a long-standing problem for us, namely how to add support for Unity packages without excessive use of hard-to-maintain reflection code.

To begin with, there won't be a lot of modules, but as time passes and we add support for more and more optional Unity packages, the amount of modules will grow proportionately. 3.0 ships with only two modules: a Unity.Mathematics support module, and an experimental Unity.Entities support module.

Property States

We've added a new State system to properties, accessible through InspectorProperty.State, which manages certain states of properties such as Visible, Expanded and Enabled and makes them accessible by anything. Formerly, the states of properties were inaccessible, usually contained within and managed by the drawers which used those states - for example, whether a property was visible was only controllable and knowable by the ShowIfAttributeDrawer, whereas now property visibility has turned into an actual public, accessible value that other things can react to.

Additionally, to better facilitate drawer-less property validation and in anticipation of eventually moving away from IMGUI drawing to Unity's new UIElements, we have separated the logic that controls and updates states from the drawer system. States should now be primarily controlled by the new StateUpdaters. We have removed many drawers such as ShowIfAttributeDrawer, EnableIfAttributeDrawer, and so on, and reimplemented them as StateUpdaters.

This feature means that groups will now automatically become invisible when all their contained properties become invisible, the Project Validator will not validate hidden properties, and so on.

Improved Attribute Expressions

With Odin 2.1, we brought you the ability to write C#-like expressions in resolved attribute strings by prepending @ to the string, instead of only being able to reference members by name. In Odin 3.0, we're further improving this feature by adding support for assignment operators and a novel, new property query operator.

Assignment Operators

For a long time, attribute expressions have mostly been about somehow getting or creating a value. However, with the new ActionResolvers (see further down), this all changes. Therefore, we've made sure to add support for C#'s assignment operators to Odin's expression compiler.

This covers the operators =, +=, -=, *=, /=, %=, <<=, >>=, &=, |= and ^=.

Property Query Operator

The new state system for properties means that it becomes far more meaningful to work directly with properties in attributes. This was possible before by using the builtin $property named expression argument, but it was quite tedious to type. We've added a new operator to expressions for getting the properties of other members in the scope of the expression.

The syntax is #(MemberName), and it evaluates to the InspectorProperty instance that represents the MemberName member.

As the example below demonstrates, these additions to the expression compiler have a powerful synergy with the new state system, letting you create vastly more powerful custom logic in your inspectors than ever before, using only attributes.

// It is generally recommended to use the OnStateUpdate attribute to control the state of properties
[OnStateUpdate("@#(exampleList).State.Expanded = $value.HasFlag(ExampleEnum.UseStringList)")]
public ExampleEnum exampleEnum;

public List exampleList;

[Flags] public enum ExampleEnum { None, UseStringList }

Value and Action Resolvers

Value and Action Resolvers provide a simple API for taking strings and turning them into values or actions, as well as providing helpful, detailed error messages if a bad string is given or the string causes exceptions while being resolved.

With these two new systems, we managed to eliminate every single line of manual reflection code related to resolved strings, throughout all of Odin's drawers, validators and state updaters. This has drastically simplified their implementation.

Value and Action Resolvers don't just make Odin's own attribute implementations more simple, consistent and feature-rich across the board, though - they also make it effortless for users to create their own attributes that use resolved strings.

Five New Attributes

Searchable

You asked (a lot), and we answered! The new Searchable attribute adds a search filter that can search the children of the field or type on which it is applied.

You can put it on types to make the whole type searchable anywhere it appears, put it on members to make the member's contents searchable, put it on lists or arrays to make them searchable, and so on!

This feature has been a long time coming, and we're happy to report that it's finally here. Search can be configured in a variety of ways by passing in parameters to the attribute declaration, and by implementing the ISearchFilterable interface.

Note that this does not currently work when directly applied to dictionaries, though a search field "above" the dictionary will still search the dictionary's properties if it is searching recursively.

OnCollectionChanged

OnCollectionChanged can be put on collections, and provides an event callback when the collection is about to be changed through the inspector, and when the collection has been changed through the inspector. Additionally, it provides a CollectionChangeInfo struct containing information about the exact changes made to the collection. This attribute works for all collections with a collection resolver, amongst them arrays, lists, dictionaries, hashsets, stacks and linked lists.

OnStateUpdate

OnStateUpdate provides an event callback when the property's state should be updated, when the StateUpdaters run on the property instance. This generally happens at least once per frame, and the callback will be invoked even when the property is not visible. This can be used to approximate custom StateUpdaters like [ShowIf] without needing to make entire attributes and StateUpdaters for one-off cases.

OnInspectorInit

The OnInspectorInit attribute takes in an action string as an argument (typically the name of a method to be invoked, or an expression to be executed), and executes that action when the property's drawers are initialized in the inspector. Initialization will happen at least once during the first drawn frame of any given property, but may also happen several times later, most often when the type of a polymorphic property changes and it refreshes its drawer setup and recreates all its children.

OnInspectorDispose

The OnInspectorDispose attribute takes in an action string as an argument (typically the name of a method to be invoked, or an expression to be executed), and executes that action when the property's drawers are disposed in the inspector. Disposing will happen at least once, when the inspector changes selection or the property tree is collected by the garbage collector, but may also happen several times before that, most often when the type of a polymorphic property changes and it refreshes its drawer setup and recreates all its children, disposing of the old setup and children.

3.0 Patch Notes

Features

  • Added a State system to properties, accessible through InspectorProperty.State, which manages certain states of properties such as Visible, Expanded and Enabled and makes them accessible by anything.
  • Added property query syntax and assignment operators to expressions.
  • Added [Searchable] attribute.
  • Added [OnCollectionChanged] attribute.
  • Added [OnStateUpdate] attribute.
  • Added Value Resolvers and Action Resolvers
  • Added a new StateUpdater system; these are type-matched (just like drawers) and attached to a property, and their sole purpose is to receive event invocations and update the property's state. These are all written to exist outside of an IMGUI scope.
  • Added right-click context menu items "Move element to top", "Move element to bottom" and "Move element to index" to all elements of ordered collections, as well as "Insert element here", that creates a new value using the list's value creation logic, and inserts it at the context element's index.
  • Added VisibleIf and AnimateVisibility members to all group attributes; all groups can now directly control their own visibility, without ShowIfGroup and HideIfGroup getting involved anywhere.
  • The validation system has been moved to use the property system as its data backend, instead of using manually implemented reflection.
  • The project validator will now ignore validation of properties that are not visible.

Experimental features

  • We've added a new experimental option in the General drawer preferences called Precompute Type Matching, which will attempt to speed up first-time inspector opening times by using a separate thread to precompute generic type matching for things like drawers, based on a file cache of all matched types from prior domain reloads that is kept in the project Temp folder. This feature should be particularly impactful in those projects that contain very large numbers of custom drawers, processors and resolvers that are causing lag spikes the first time an inspector for a given type is opened with Odin. Please try this out if you'd like, and see if you can notice or measure any difference.

Performance

  • Major optimization passes have been performed throughout the entire codebase, resulting in a major overall increase in performance. This includes drastically rearchitecting many internal systems; more careful caching of the results of expensive operations; optimizing and limiting the use of .NET's reflection API's; aggressively limiting allocations needed for common operations; algorithmic improvements on priority sorting of drawers, resolvers and processors; changing code hotspots to enable better optimization by the JIT; and much, much more.

    Specific changes made and features affected during this months-long optimization endeavour are far too numerous to list exhaustively, but of particular note is the initialization time of Odin in general and of the property system in particular. Notably, in our benchmarks the majority of CPU time during the initialization of Odin and first-time use of the property system is now being spent by the JIT as it compiles Odin to its final bytecode form.

    To provide an example, switching the validation system to use Odin's properties resulted in project validation scans becoming 10-20 times slower than in 2.1. With the new optimizations, this overhead is reduced to project validation scans that range from being about as fast as before, to about twice as slow at worst, according to our tests - this while running on the far more feature-rich, easy-to-use and extendable property system, as opposed to 2.1's more barebones and spotty validation backend.

Add

  • [OnInspectorGUI] now also uses the action resolver system when placed directly on methods. This means OnInspectorGUI can now have named context values passed as method parameters, such as the InspectorProperty instance that represents the invoked method.
  • [OnInspectorInit] and [OnInspectorDispose] can now be placed directly on methods, and the methods can have named context values passed as parameters, such as the InspectorProperty instance that represents the invoked method.
  • A PropertyTree can now have its target values changed via the SetTargets and SetSerializedObject methods. Along with the new CleanForCachedReuse method on PropertyTree, property trees are now cacheable/reusable. This new feature is used by the Project Validator to speed up scans.
  • The TypeSearchIndex matching rules have now been reimplemented in a new TypeMatcher/TypeMatcherCreator pattern that is more easily optimized for performance, as each matcher can pre-fetch results of expensive reflection calls like type.GetGenericArguments(), such that they only ever have to be made once. This makes first-time/uncached matching several times faster.
  • Added "Duplicate element" menu item to all collection elements.
  • Added "Insert pasted element" context menu item to collection elements, which inserts a pasted element from the clipboard if the clipboard value is compatible.
  • Added an InvokeOnUndoRedo parameter to the OnValueChanged attribute to control whether to perform the action when an undo or redo event occurs via UnityEditor.Undo.undoRedoPerformed.
  • Added an ODIN_INSPECTOR_3 preprocessor directive, to help people transition due to the number of breaking changes made in certain APIs.
  • Added InspectorProperty.IsTreeRoot, which is true if the property is the tree root.
  • Added LabelText member to BoxGroup, to allow overriding the label text of the box without changing the name of the group.
  • Added StateUpdaters, a new system for updating property states that is entirely independent of the concept of drawing. Drawers that implement IOnStateUpdate will no longer be created, initialized and have OnStateUpdate invoked during non-GUI events such as a project validation scan, which was causing issues before with drawers that weren't mean to be initialized outside of a GUI event context.
  • Added support for empty expression strings to actions: the expression string "@" will do nothing, but evaluate to an empty action when resolved by action resolvers.
  • Added the [OnInspectorInit] and [OnInspectorDispose] attributes. TODO: link docs.
  • Added the MethodPropertyResolverCreator, which resolves an action as an invocation of the property method itself, for properties that represent methods or delegates.
  • Added Value And Action Resolvers Example to Custom Drawers demo scene.
  • Added window popup that asks the user to accept the new EULA.
  • PropertyTree.EnumerateTree and InspectorProperty.NextProperty now have an extra bool parameter "visibleOnly" that will cause them to only return visible properties.
  • The static inspector window will now also recursively inspect all members in child properties; this lets you recurse arbitrarily deep into various type reference structures, so be careful with this!
  • Added DisplayParameters member to the Button attribute. If set to false, the button will not display any parameters as inspector values, but will instead be invoked through an ActionResolver or ValueResolver (based on whether it returns a value), giving access to contextual named parameter values like "InspectorProperty property" that can be passed to the button method.
  • The TabGroup drawer now exposes the "CurrentTabName", "CurrentTabIndex" and "TabCount" custom states, which say respectively what the name of the currently open tab is, what the index of the currently open tab is, and how many tabs the tab group contains.
  • Added the NicifyText member to the LabelText attribute. When set to true, the given label text will be nicified before being displayed.
  • Added OdinEditorWindow.EnsureEditorsAreReady() method that ensures editors are ready to be drawn safely.
  • Added ValidationRunner.ValidateObjectRecursively overloads to the Project Validator's ValidationRunner type, that take a root value to validate which is not derived from the UnityEngine.Object type.
  • The AOT support scan will now also scan all addressable assets, if the addressables package is included and being used.

Change

  • Brought ColorUsage32AttributeDrawer up to modern Odin standards.
  • Brought ColorUsageAttributeDrawer and ColorUsage32AttributeDrawer up to modern Odin standards.
  • Changed the default file name of the Odin 3.0 persistent context cache file, so it doesn't conflict with caches from prior versions of Odin.
  • Changed the hard-coded max size of the persistent context cache to 1GB, though it is really, really not recommended to actually make it that large! :)
  • DefaultOdinPropertyResolverLocator's SearchIndex and GetEmptyResolverInstance members are now public.
  • Deleted all property system APIs that were made obsolete with patch 2.0.
  • FixUnityNullDrawer is now public.
  • Property order has been changed to a float from an int. This change applies to various APIs, and the [PropertyOrder] attribute. This will make it a lot easier to inject properties in between each other in ways you hadn't originally anticipated when setting up your orders, and means you won't have to leave huge order gaps to accommodate unforeseen future changes.
  • Local property contexts (IE, all calls to Property.Context.Get<T>(etc)) have been made fully obsolete, upgraded from the warning-level obsolete they were before. Local drawer fields should be used instead.
  • Removed the Scene Validator which was deprecated a long time ago, and changed relevant examples to use the new validation system instead.
  • Renamed most resolved strings to remove terminology that references members, since all resolved strings are no longer member exclusive, but can also use expressions and any other functionality registered in the value and action resolver system. All old members have been soft-obsoleted.
  • The "root properties" of a PropertyTree now have the actual tree RootProperty (formerly SecretRootProperty) as their parent, instead of null. PropertyTree.Draw() no longer manually draws the children of the tree root property one by one - instead, it merely calls RootProperty.Draw(), meaning that Odin PropertyTrees can now directly inspect and correctly draw types such as lists.
  • The drawer for [ShowDrawerChain] will now also display the path of the property whose drawer chain is being shown.
  • ValueResolvers and ActionResolvers now have an option for logging exceptions that are thrown during invocation, which is set to true by default.
  • Range and PropertyRange attributes are now drawn virtually identically by Odin.
  • EditorOnlyModeConfig and PersistentContextCache are no longer asset-less ScriptableObject-based singletons (via GlobalConfig<T>), but more simple POCO singletons. This change was made because they were causing UnityEngine.Object leaks across domain reloads.
  • GlobalConfigAttribute.UseAsset has been made error-level obsolete, because it was causing object leaking issues and was fundamentally "useless". Use a POCO singleton or a ScriptableSingleton instead.
  • OdinEditorWindow.UpdateEditors() has been changed from private to protected so it can be invoked manually by deriving classes.
  • Turned PreviewFieldAttribute.AlignmentHasValue into a readonly property.
  • Changed the type of the ValidationSetup.Root field from UnityEngine.Object to System.Object, since any type can act as a validation root now.

Fix

  • Added ShowIfGroup and HideIfGroup to the Groups category in the attribute overview.
  • Better unimplemented/bad base.DrawPropertyLayout() call feedback message.
  • Dictionaries should now work property with [LabelText].
  • Exceptions thrown by attribute and property processors are now caught and logged.
  • Fixed case where attributes such as [Range] and [MinValue] would throw exceptions and not work, when applied to Vector2, Vector3 and Vector4's.
  • Fixed case where the TypeExtensions.GetOperatorMethod(Type, Operator, Type, Type) overload would throw an exception when there was an ambiguous operator match.
  • Fixed issue in attribute expressions where assigning a constant null value to a reference type member/collection indexer would require casting the null value to the correct type. Null constants are now implicitly converted to any reference type member/indexer to which they are assigned.
  • Fixed issue where the labels of EnumToggleButtons' selected enum values would not show up in the first ever domain reload in Unity 2019.3+. Issue #671 https://bitbucket.org/sirenix/odin-inspector/issues/671/enum-toggle-buttons-when-selected-have.
  • Fixed the polymorphic star and the MinMaxSlider slider UI being badly sized/placed in the new 2019.3 UI.
  • GUIUtility.ExitGUI() is now called after all button clicks, meaning that button methods that invalidate the GUI state should no longer cause a multitude of exceptions related to layout and other GUI states to be thrown after they're done executing.
  • Odin now by default draws a blue line next to modified prefab values. This can be turned off by toggling the "Show Blue Prefab Value Modified Bar" setting in the General preferences.
  • OdinEditor now also performs extra warmup repaints after it has been cached and reused by Unity, instead of just when it is created and used for the first time.
  • Removed superfluous debugging statements from validation.
  • Soft-obsoleted OdinMenuTree.HandleKeybaordMenuNavigation and added a message to use the property spelled OdinMenuTree.HandleKeyboardMenuNavigation instead.
  • The PropertyTree.GetPropertyAtPath(path) method will now correctly return the root property if given the path '$ROOT'.
  • Fixed error where assigning null to the WeakSmartValue of an alias value entry that aliases a struct value for a base value entry of an interface type implemented by the struct, would result in a null reference exception.
  • The attribute expression compiler will now implicitly cast (and box) enum values to the System.Enum type.
  • The ChildGameObjectOnly attribute now correctly validates and registers incorrect values in the Project Validator.
  • OdinEditorWindow.DrawEditor(int index) and DrawEditorPreview(int index, float height) can now be safely invoked before base.OnGUI() has been called once before. This fixes a common issue people were seeing when tweaking the code examples given in the 3-part "Create THE GameManager" tutorial series on YouTube.
  • Setting a PreviewField attribute's Alignment parameter using the [PreviewField(Alignment = value)] syntax rather than passing the value to the constructor now works properly.
  • Updated UnitySerializationUtility.GuessIfUnityWillSerialize to not consider types defined in System.dll and System.Core.dll as types that Unity might serialize.
  • AOTSupportUtilities.GenerateDLL no longer sets obsolete Linux import settings "StandaloneLinux" and "StandaloneLinuxUniversal" in 2019.2+.
  • Fixed case where the TypeExtensions.GetOperatorMethod(Type, Operator, Type, Type) overload would throw an exception when there was an ambiguous operator match.
  • Switched serializer unaligned read/write support logic to a whitelist instead of a blacklist approach, and ensured the read test only occurs on whitelisted platforms. This fixes a startup crash on PS Vita.
  • Mitigated issue with the AOT scan where scanning resource assets would often break and throw MissingReferenceExceptions when Unity's AssetDatabase v2 was enabled. This appears to be an issue with the resource assets being unloaded/destroyed silently while in use, with the issue more likely to happen on slower hardware. The mitigation is to load resources one at a time by path instead of loading them all at once, thus lessening the risk of assets becoming null during the scan.
  • Fix to HashSet used for deduplication when loading resource assets for AOT scan, to cope with cases where corrupt/bad resources are loaded. It now uses a reference equality comparer to bypass Unity object strangeness.
  • MissingReferenceExceptions are now caught and logged so the scan can continue when AOT scanning resource assets, in case the null check fails/is bad.