You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CrowdControl/Assets/Plugins/Sirenix/Odin Inspector/Scripts/Editor/FixBrokenUnityObjectWrapper...

208 lines
7.6 KiB
C#

2 months ago
//-----------------------------------------------------------------------
// <copyright file="FixBrokenUnityObjectWrapperDrawer.cs" company="Sirenix IVS">
// Copyright (c) Sirenix IVS. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
#if UNITY_EDITOR && UNITY_2018_3_OR_NEWER
#pragma warning disable
namespace Sirenix.OdinInspector.Editor.Drawers
{
using Sirenix.OdinInspector;
using Sirenix.OdinInspector.Editor;
using Sirenix.Utilities;
using Sirenix.Utilities.Editor;
using System.Linq;
using UnityEditor;
using UnityEngine;
[DrawerPriority(0.001, 0, 0)]
public class FixBrokenUnityObjectWrapperDrawer<T> : OdinValueDrawer<T>, IDefinesGenericMenuItems
where T : UnityEngine.Component
{
private const string AUTO_FIX_PREFS_KEY = "TemporarilyBrokenUnityObjectWrapperDrawer.autoFix";
private bool isBroken = false;
private T realWrapperInstance;
private bool allowSceneViewObjects;
private static bool autoFix;
protected override void Initialize()
{
this.allowSceneViewObjects = this.ValueEntry.Property.GetAttribute<AssetsOnlyAttribute>() == null;
autoFix = EditorPrefs.HasKey(AUTO_FIX_PREFS_KEY);
}
protected override void DrawPropertyLayout(GUIContent label)
{
if (!(this.ValueEntry.ValueState == PropertyValueState.NullReference || this.ValueEntry.ValueState == PropertyValueState.ReferenceValueConflict))
{
this.CallNextDrawer(label);
return;
}
if (Event.current.type == EventType.Layout)
{
this.isBroken = false;
var count = this.ValueEntry.ValueCount;
for (int i = 0; i < count; i++)
{
var component = this.ValueEntry.Values[i];
if (ComponentIsBroken(component, ref this.realWrapperInstance))
{
this.isBroken = true;
break;
}
}
if (this.isBroken && autoFix)
{
this.isBroken = false;
for (int i = 0; i < this.ValueEntry.ValueCount; i++)
{
T fixedComponent = null;
if (ComponentIsBroken(this.ValueEntry.Values[i], ref fixedComponent) && fixedComponent)
{
(this.ValueEntry as IValueEntryActualValueSetter<T>).SetActualValue(i, fixedComponent);
}
}
this.ValueEntry.Update();
}
}
if (!this.isBroken)
{
this.CallNextDrawer(label);
return;
}
var rect = EditorGUILayout.GetControlRect(label != null);
var btnRect = rect.AlignRight(20);
var controlRect = rect.SetXMax(btnRect.xMin - 5);
object newInstance = null;
EditorGUI.BeginChangeCheck();
{
if (this.ValueEntry.BaseValueType.IsInterface)
{
newInstance = SirenixEditorFields.PolymorphicObjectField(controlRect,
label,
this.realWrapperInstance,
this.ValueEntry.BaseValueType,
this.allowSceneViewObjects);
}
else
{
newInstance = SirenixEditorFields.UnityObjectField(
controlRect,
label,
this.realWrapperInstance,
this.ValueEntry.BaseValueType,
this.allowSceneViewObjects) as Component;
}
}
if (EditorGUI.EndChangeCheck())
{
this.ValueEntry.WeakSmartValue = newInstance;
}
if (GUI.Button(btnRect, " ", EditorStyles.miniButton))
{
var popup = new FixBrokenUnityObjectWrapperPopup(this.ValueEntry);
OdinEditorWindow.InspectObjectInDropDown(popup, 300);
}
if (Event.current.type == EventType.Repaint)
{
GUI.DrawTexture(btnRect, EditorIcons.ConsoleWarnicon, ScaleMode.ScaleToFit);
}
}
private static bool ComponentIsBroken(T component, ref T realInstance)
{
var uObj = component;
var oObj = (object)uObj;
if (oObj != null && uObj == null)
{
var instanceId = uObj.GetInstanceID();
if (AssetDatabase.Contains(instanceId))
{
var path = AssetDatabase.GetAssetPath(instanceId);
var realWrapper = AssetDatabase.LoadAllAssetsAtPath(path).FirstOrDefault(n => n.GetInstanceID() == instanceId) as T;
if (realWrapper)
{
realInstance = realWrapper;
return true;
}
}
}
return false;
}
public void PopulateGenericMenu(InspectorProperty property, GenericMenu genericMenu)
{
if (EditorPrefs.HasKey(AUTO_FIX_PREFS_KEY))
{
genericMenu.AddItem(new GUIContent("Disable auto-fix of broken prefab instance references"), false, (x) =>
{
EditorPrefs.DeleteKey(AUTO_FIX_PREFS_KEY);
autoFix = false;
}, null);
}
}
[TypeInfoBox("This asset reference is temporarily broken until the next reload, because of an error in Unity where the C# wrapper object of a prefab asset is destroyed when changes are made to that prefab asset. This error has been reported to Unity.\n\nMeanwhile, Odin can fix this for you by getting a new, valid wrapper object from the asset database and replacing the broken wrapper instance with the new one.")]
private class FixBrokenUnityObjectWrapperPopup
{
private IPropertyValueEntry<T> valueEntry;
public FixBrokenUnityObjectWrapperPopup(IPropertyValueEntry<T> valueEntry)
{
this.valueEntry = valueEntry;
}
[HorizontalGroup, Button(ButtonSizes.Large)]
public void FixItThisTime()
{
for (int i = 0; i < this.valueEntry.ValueCount; i++)
{
var localI = i;
T fixedComponent = null;
if (ComponentIsBroken(this.valueEntry.Values[i], ref fixedComponent) && fixedComponent)
{
this.valueEntry.Property.Tree.DelayActionUntilRepaint(() =>
{
(this.valueEntry as IValueEntryActualValueSetter<T>).SetActualValue(localI, fixedComponent);
});
}
}
if (GUIHelper.CurrentWindow)
{
EditorApplication.delayCall += GUIHelper.CurrentWindow.Close;
}
}
[HorizontalGroup, Button(ButtonSizes.Large)]
public void FixItAlways()
{
EditorPrefs.SetBool(AUTO_FIX_PREFS_KEY, true);
autoFix = true;
if (GUIHelper.CurrentWindow)
{
EditorApplication.delayCall += GUIHelper.CurrentWindow.Close;
}
}
}
}
}
#endif