123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- using System.Reflection;
- using SingularityGroup.HotReload.Editor;
- using UnityEditor;
- using UnityEngine;
- [InitializeOnLoad]
- public class InspectorFreezeFix
- {
- // Inspector window getting stuck is fixed by calling UnityEditor.InspectorWindow.RefreshInspectors()
- // Below code subscribes to selection changed callback and calls the method if the inspector is actually stuck
- static InspectorFreezeFix()
- {
- Selection.selectionChanged += OnSelectionChanged;
- }
-
- private static int _lastInitialEditorId;
- private static void OnSelectionChanged() {
- if (!EditorCodePatcher.config.enableInspectorFreezeFix) {
- return;
- }
- try {
- // Most of stuff is internal so we use reflection here
- var inspectorType = typeof(Editor).Assembly.GetType("UnityEditor.InspectorWindow");
- foreach (var inspector in Resources.FindObjectsOfTypeAll(inspectorType)) {
-
- object isLockedValue = inspectorType.GetProperty("isLocked")?.GetValue(inspector);
- if (isLockedValue == null) {
- continue;
- }
-
- // If inspector window is locked deliberately by user (via the lock icon on top-right), we don't need to refresh
- var isLocked = (bool)isLockedValue;
- if (isLocked) {
- continue;
- }
-
- // Inspector getting stuck is due to ActiveEditorTracker of that window getting stuck internally.
- // The tracker starts returning same values from m_Tracker.activeEditors property.
- // (Root of cause of this is out of my reach as the tracker code is mainly native code)
- // We detect that by checking first element of activeEditors array
- // We do the check because we don't want to RefreshInspectors every selection change, RefreshInspectors is expensive
- var tracker = inspectorType.GetField("m_Tracker", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(inspector);
- if (tracker == null) {
- continue;
- }
- var activeEditors = tracker.GetType().GetProperty("activeEditors");
- if (activeEditors == null) {
- continue;
- }
- var editors = (Editor[])activeEditors.GetValue(tracker);
- if (editors.Length == 0) {
- continue;
- }
-
- var first = editors[0].GetInstanceID();
- if (_lastInitialEditorId == first) {
- // This forces the tracker to be rebuilt
- var m = inspectorType.GetMethod("RefreshInspectors", BindingFlags.Static | BindingFlags.NonPublic);
- if (m == null) {
- // support for older versions
- RefreshInspectors(inspectorType);
- } else {
- m.Invoke(null, null);
- }
- }
- _lastInitialEditorId = first;
- // Calling RefreshInspectors once refreshes all the editors
- break;
- }
- } catch {
- // ignore, we don't want to make user experience worse by displaying a warning in this case
- }
- }
- static void RefreshInspectors(System.Type inspectorType) {
- var allInspectorsField = inspectorType.GetField("m_AllInspectors", BindingFlags.NonPublic | BindingFlags.Static);
-
- if (allInspectorsField == null) {
- return;
- }
- var allInspectors = allInspectorsField.GetValue(null) as System.Collections.IEnumerable;
- if (allInspectors == null) {
- return;
- }
-
- foreach (var inspector in allInspectors) {
- var trackerField = FindFieldInHierarchy(inspector.GetType(), "tracker");
- if (trackerField == null) {
- continue;
- }
- var tracker = trackerField.GetValue(inspector);
- var forceRebuildMethod = tracker.GetType().GetMethod("ForceRebuild", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- if (forceRebuildMethod == null) {
-
- continue;
- }
- forceRebuildMethod.Invoke(tracker, null);
- }
- }
- static PropertyInfo FindFieldInHierarchy(System.Type type, string fieldName) {
- PropertyInfo field = null;
- while (type != null && field == null) {
- field = type.GetProperty(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- type = type.BaseType;
- }
- return field;
- }
- }
|