Add OdinInspector integration

This commit is contained in:
VladV 2022-05-18 09:20:51 +03:00
parent 7d48204c2d
commit fc4da39d75
14 changed files with 278 additions and 6 deletions

8
Editor.Integrations.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e6b289af1e2447f40a294b9fd063474a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8f456555c4d04a27a1ee0166c06cf796
timeCreated: 1652773355

View File

@ -0,0 +1,40 @@
using System;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities.Editor;
using UnityEditor;
using UnityEngine;
namespace TriInspector.Editor.Integrations.Odin
{
[DrawerPriority(0.0, 0.0, 6000.0)]
public class DrawWithTriInspectorDrawer<T> : OdinAttributeDrawer<DrawWithTriInspectorAttribute, T>, IDisposable
{
private TriPropertyTreeForOdin<T> _propertyTree;
protected override void Initialize()
{
base.Initialize();
_propertyTree = new TriPropertyTreeForOdin<T>(ValueEntry);
}
public void Dispose()
{
_propertyTree?.Dispose();
}
protected override void DrawPropertyLayout(GUIContent label)
{
var propertyState = ValueEntry.Property.State;
propertyState.Expanded = SirenixEditorGUI.Foldout(propertyState.Expanded, label);
if (propertyState.Expanded)
{
EditorGUI.indentLevel++;
_propertyTree.Draw();
EditorGUI.indentLevel--;
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ee9c37a0a21643c2a7037a7a159b4355
timeCreated: 1652773581

View File

@ -0,0 +1,23 @@
{
"name": "TriInspector.Editor.Integrations.Odin",
"rootNamespace": "",
"references": [
"TriInspector",
"TriInspector.Editor"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [
""
],
"autoReferenced": false,
"defineConstraints": [
"ODIN_INSPECTOR"
],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 90456d836f7b85c45a469d1f5ee611b1
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,161 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor;
using TriInspector.Elements;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace TriInspector.Editor.Integrations.Odin
{
public class TriPropertyTreeForOdin<T> : ITriPropertyParent, ITriPropertyTree
{
private readonly IPropertyValueEntry<T> _odinValueEntry;
private readonly InspectorProperty _odinProperty;
private readonly IReadOnlyList<TriProperty> _triProperties;
private readonly TriInspectorElement _triInspectorElement;
private readonly SerializedProperty _serializedProperty;
private bool _validationRequired;
public TriPropertyTreeForOdin(IPropertyValueEntry<T> odinValueEntry)
{
_odinValueEntry = odinValueEntry;
_odinProperty = odinValueEntry.Property;
TargetObjectType = _odinProperty.Tree.TargetType;
TargetsCount = _odinProperty.Tree.WeakTargets.Count;
TargetIsPersistent = _odinProperty.Tree.WeakTargets[0] is Object obj &&
obj != null && EditorUtility.IsPersistent(obj);
_serializedProperty = _odinProperty.Tree.GetUnityPropertyForPath(_odinProperty.Path, out _);
UpdateAfterValueModification();
_triProperties = TriTypeDefinition.GetCached(odinValueEntry.TypeOfValue)
.Properties
.Select((propertyDefinition, index) =>
{
var serializedProperty = _serializedProperty.FindPropertyRelative(propertyDefinition.Name);
return new TriProperty(this, this, propertyDefinition, index, serializedProperty);
})
.ToList();
_triInspectorElement = new TriInspectorElement(odinValueEntry.TypeOfValue, _triProperties);
_triInspectorElement.AttachInternal();
_triProperties.ForEach(it => it.Update());
_triProperties.ForEach(it => it.RunValidation());
}
public void Draw()
{
UpdateEmittedScriptableObject();
_triProperties.ForEach(it => it.Update());
if (_validationRequired)
{
_validationRequired = false;
_triProperties.ForEach(it => it.RunValidation());
}
_triInspectorElement.Update();
var width = EditorGUIUtility.currentViewWidth;
var height = _triInspectorElement.GetHeight(width);
var rect = GUILayoutUtility.GetRect(width, height);
_triInspectorElement.OnGUI(rect);
}
public Type TargetObjectType { get; }
public int TargetsCount { get; }
public bool TargetIsPersistent { get; }
public void Dispose()
{
_triInspectorElement?.DetachInternal();
}
public void ForceCreateUndoGroup()
{
_odinProperty.RecordForUndo(forceCompleteObjectUndo: true);
Undo.FlushUndoRecordObjects();
}
public void PrepareForValueModification()
{
var dirty = false;
dirty |= _odinValueEntry.ApplyChanges();
dirty |= _serializedProperty.serializedObject.ApplyModifiedProperties();
dirty |= ApplyEmittedScriptableObject();
if (dirty)
{
_validationRequired = true;
GUIHelper.RequestRepaint();
}
}
public void UpdateAfterValueModification()
{
UpdateEmittedScriptableObject();
_serializedProperty.serializedObject.SetIsDifferentCacheDirty();
_serializedProperty.serializedObject.Update();
_odinProperty.Update();
}
public void RequestRepaint()
{
GUIHelper.RequestRepaint();
}
public object GetValue(int targetIndex)
{
return _odinValueEntry.Values[targetIndex];
}
public void NotifyValueChanged(TriProperty property)
{
ApplyEmittedScriptableObject();
_odinValueEntry.Values.ForceMarkDirty();
}
private void UpdateEmittedScriptableObject()
{
if (_serializedProperty.serializedObject.targetObject is EmittedScriptableObject<T>)
{
var targetObjects = _serializedProperty.serializedObject.targetObjects;
for (var index = 0; index < targetObjects.Length; ++index)
{
((EmittedScriptableObject<T>) targetObjects[index]).SetValue(_odinValueEntry.Values[index]);
}
_serializedProperty.serializedObject.Update();
}
}
private bool ApplyEmittedScriptableObject()
{
var dirty = false;
if (_serializedProperty.serializedObject.targetObject is EmittedScriptableObject<T>)
{
dirty = _serializedProperty.serializedObject.ApplyModifiedPropertiesWithoutUndo();
var targetObjects = _serializedProperty.serializedObject.targetObjects;
for (var index = 0; index < targetObjects.Length; ++index)
{
_odinValueEntry.Values[index] = ((EmittedScriptableObject<T>) targetObjects[index]).GetValue();
}
}
return dirty;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d883d32fb4d94844b172e3a08edbf2b4
timeCreated: 1652774822

3
Editor/AssemblyInfo.cs Normal file
View File

@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("TriInspector.Editor.Integrations.Odin")]

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 31eceb5f41944fc5a4afccb7697d3e61
timeCreated: 1652775741

View File

@ -252,7 +252,7 @@ namespace TriInspector
PropertyTree.PrepareForValueModification(); PropertyTree.PrepareForValueModification();
// record object state for undp // record object state for undp
Undo.FlushUndoRecordObjects(); PropertyTree.ForceCreateUndoGroup();
// set value for all targets // set value for all targets
for (var targetIndex = 0; targetIndex < PropertyTree.TargetsCount; targetIndex++) for (var targetIndex = 0; targetIndex < PropertyTree.TargetsCount; targetIndex++)

View File

@ -104,10 +104,10 @@ namespace TriInspector
_inspectorElement.OnGUI(rect); _inspectorElement.OnGUI(rect);
} }
public void UpdateAfterValueModification() public void ForceCreateUndoGroup()
{ {
SerializedObject.SetIsDifferentCacheDirty(); Undo.RegisterCompleteObjectUndo(TargetObjects, "Inspector");
SerializedObject.Update(); Undo.FlushUndoRecordObjects();
} }
public void PrepareForValueModification() public void PrepareForValueModification()
@ -117,9 +117,12 @@ namespace TriInspector
RequestValidation(); RequestValidation();
RequestRepaint(); RequestRepaint();
} }
}
Undo.RegisterCompleteObjectUndo(TargetObjects, "Inspector"); public void UpdateAfterValueModification()
Undo.FlushUndoRecordObjects(); {
SerializedObject.SetIsDifferentCacheDirty();
SerializedObject.Update();
} }
public void NotifyValueChanged(TriProperty property) public void NotifyValueChanged(TriProperty property)
@ -149,6 +152,7 @@ namespace TriInspector
int TargetsCount { get; } int TargetsCount { get; }
bool TargetIsPersistent { get; } bool TargetIsPersistent { get; }
void ForceCreateUndoGroup();
void PrepareForValueModification(); void PrepareForValueModification();
void UpdateAfterValueModification(); void UpdateAfterValueModification();
void RequestRepaint(); void RequestRepaint();

View File

@ -0,0 +1,11 @@
using System;
using System.Diagnostics;
namespace TriInspector
{
[AttributeUsage(AttributeTargets.Class)]
[Conditional("UNITY_EDITOR")]
public class DrawWithTriInspectorAttribute : Attribute
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 33460afbb365415a9ff9d9379f0cec59
timeCreated: 1652773384