You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

302 lines
10 KiB

5 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEditor;
  5. using UnityEngine;
  6. using Object = UnityEngine.Object;
  7. #if UNITY_5_3_OR_NEWER
  8. using UnityEngine.SceneManagement;
  9. #endif
  10. namespace Plugins.Isolationist.Editor
  11. {
  12. [InitializeOnLoad]
  13. public static class EditorIsolateCommand
  14. {
  15. private const string ISOLATE_KEY_PREF = "IsolationistKey";
  16. private const string ISOLATE_ALT_PREF = "IsolationistAlt";
  17. private const string ISOLATE_CTRL_PREF = "IsolationistCtrl";
  18. private const string ISOLATE_SHIFT_PREF = "IsolationistShift";
  19. private const string ISOLATE_HIDE_LIGHTS_PREF = "IsolationistHideLights";
  20. private const string ISOLATE_HIDE_CAMERAS_PREF = "IsolationistHideCameras";
  21. private static bool _alt;
  22. private static bool _ctrl;
  23. private static bool _shift;
  24. private static bool _ctrlOrShiftPressed;
  25. private static bool _hideLights;
  26. private static bool _hideCameras;
  27. private static KeyCode _hotkey;
  28. private static GameObject _lastSelection;
  29. private static int _lastSelectionCount;
  30. private static string _shortcutDisplay;
  31. private static List<GameObject> _lastSelectionList;
  32. private static readonly List<Type> _lightTypeList = new List<Type>();
  33. private static readonly List<Type> _cameraTypeList = new List<Type>();
  34. public static void AddLightType(Type type) {
  35. _lightTypeList.Add(type);
  36. }
  37. public static void AddCameraType(Type type) {
  38. _cameraTypeList.Add(type);
  39. }
  40. static EditorIsolateCommand()
  41. {
  42. _alt = EditorPrefs.GetBool(ISOLATE_ALT_PREF, false);
  43. _ctrl = EditorPrefs.GetBool(ISOLATE_CTRL_PREF, false);
  44. _shift = EditorPrefs.GetBool(ISOLATE_SHIFT_PREF, false);
  45. _hotkey = (KeyCode) EditorPrefs.GetInt(ISOLATE_KEY_PREF, (int) KeyCode.I);
  46. _hideLights = EditorPrefs.GetBool(ISOLATE_HIDE_LIGHTS_PREF, true);
  47. _hideCameras = EditorPrefs.GetBool(ISOLATE_HIDE_CAMERAS_PREF, true);
  48. EditorApplication.update += Update;
  49. EditorApplication.playmodeStateChanged += PlaymodeStateChanged;
  50. EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI;
  51. SceneView.onSceneGUIDelegate += OnSceneGUI;
  52. AddCameraType(typeof(Camera));
  53. AddLightType(typeof(Light));
  54. AddLightType(typeof(ReflectionProbe));
  55. }
  56. private static bool IsolateKeyPressed
  57. {
  58. get
  59. {
  60. if (Event.current == null) return false;
  61. if (Event.current.type != EventType.KeyUp) return false;
  62. return Event.current.keyCode == _hotkey && Event.current.alt == _alt && Event.current.control == _ctrl && Event.current.shift == _shift;
  63. }
  64. }
  65. public static string ShortcutDisplay { get { return _shortcutDisplay.IsNullOrEmpty() ? _shortcutDisplay = GetShortcutDisplay() : _shortcutDisplay; } }
  66. private static void Update()
  67. {
  68. if (!IsolateInfo.IsIsolated || _lastSelection == Selection.activeGameObject && _lastSelectionCount == Selection.gameObjects.Length) return;
  69. var selectionList = Selection.gameObjects.ToList();
  70. var newItems = _lastSelectionList == null ? selectionList : selectionList.Except(_lastSelectionList).ToList();
  71. _lastSelection = Selection.activeGameObject;
  72. _lastSelectionCount = Selection.gameObjects.Length;
  73. _lastSelectionList = selectionList;
  74. SelectionChanged(newItems);
  75. }
  76. private static void OnSceneGUI(SceneView sceneView) { OnGUI(); }
  77. private static void HierarchyWindowItemOnGUI(int instanceId, Rect selectionRect)
  78. {
  79. if (!GUI.GetNameOfFocusedControl().IsNullOrEmpty()) return;
  80. OnGUI();
  81. }
  82. private static void OnGUI()
  83. {
  84. _ctrlOrShiftPressed = Event.current.control || Event.current.shift;
  85. if (!IsolateKeyPressed) return;
  86. ToggleIsolate();
  87. Event.current.Use();
  88. }
  89. private static void PlaymodeStateChanged()
  90. {
  91. if (EditorApplication.isPlayingOrWillChangePlaymode) IsolateInfo.Show();
  92. else IsolateInfo.Hide();
  93. }
  94. private static void SelectionChanged(List<GameObject> newItems)
  95. {
  96. if (WasHidden(Selection.activeTransform) && !_ctrlOrShiftPressed)
  97. {
  98. EndIsolation();
  99. return;
  100. }
  101. if (!_ctrlOrShiftPressed) return;
  102. UpdateIsolation(newItems);
  103. }
  104. private static List<GameObject> GetAllGameObjectsToHide() { return IsolateInfo.Instance.FocusObjects.SelectMany<GameObject, GameObject>(GetGameObjectsToHide).Distinct().ToList(); }
  105. [MenuItem("Tools/Toggle Isolate", true)]
  106. public static bool CanToggleIsolate() { return Selection.activeGameObject || IsolateInfo.IsIsolated; }
  107. [MenuItem("Tools/Toggle Isolate")]
  108. public static void ToggleIsolate()
  109. {
  110. if (IsolateInfo.IsIsolated) EndIsolation();
  111. else StartIsolation();
  112. }
  113. private static void StartIsolation()
  114. {
  115. if (IsolateInfo.Instance)
  116. {
  117. Debug.LogWarning("Isolationist: Found previous isolation info. This shouldn't happen. Ending the previous isolation anyway.");
  118. EndIsolation();
  119. }
  120. if (EditorApplication.isPlayingOrWillChangePlaymode) {
  121. Debug.LogWarning("Isolationist: Can't isolate while playing. It'll break stuff!");
  122. return;
  123. }
  124. // Create new IsolateInfo object.
  125. var container = new GameObject("IsolationInfo") {hideFlags = HideFlags.HideInHierarchy};
  126. Undo.RegisterCreatedObjectUndo(container, "Isolate");
  127. IsolateInfo.Instance = container.AddComponent<IsolateInfo>();
  128. var focusList = IsolateInfo.Instance.FocusObjects = Selection.gameObjects.ToList();
  129. if (!_hideLights) _lightTypeList.ForEach(t => focusList.AddRange(Object.FindObjectsOfType(t).Select<Object, GameObject>(ObjectToGO)));
  130. if (!_hideCameras) _cameraTypeList.ForEach(t => focusList.AddRange(Object.FindObjectsOfType(t).Select<Object, GameObject>(ObjectToGO)));
  131. IsolateInfo.Instance.HiddenObjects = GetAllGameObjectsToHide();
  132. if (!IsolateInfo.Instance.HiddenObjects.Any())
  133. {
  134. Object.DestroyImmediate(container);
  135. Debug.LogWarning("Isolationist: Nothing to isolate.");
  136. return;
  137. }
  138. Undo.RecordObjects(IsolateInfo.Instance.HiddenObjects.Cast<Object>().ToArray(), "Isolate");
  139. IsolateInfo.Hide();
  140. }
  141. private static GameObject ObjectToGO(Object obj)
  142. {
  143. Component component = obj as Component;
  144. return component ? component.gameObject : null;
  145. }
  146. private static void UpdateIsolation(List<GameObject> newItems)
  147. {
  148. if (!newItems.Any()) return;
  149. Undo.RecordObject(IsolateInfo.Instance, "Isolate");
  150. Undo.RecordObjects(IsolateInfo.Instance.HiddenObjects.Cast<Object>().ToArray(), "Isolate");
  151. IsolateInfo.Show();
  152. IsolateInfo.Instance.FocusObjects = IsolateInfo.Instance.FocusObjects.Concat(newItems).Distinct().ToList();
  153. var newHiddenObjects = GetAllGameObjectsToHide();
  154. Undo.RecordObjects(newHiddenObjects.Except(IsolateInfo.Instance.HiddenObjects).Cast<Object>().ToArray(), "Isolate");
  155. IsolateInfo.Instance.HiddenObjects = newHiddenObjects;
  156. IsolateInfo.Hide();
  157. }
  158. private static bool WasHidden(Transform t) { return t && !t.gameObject.activeInHierarchy && !t.GetComponent<IsolateInfo>() && !IsolateInfo.Instance.FocusObjects.Any(t.gameObject.IsRelative); }
  159. private static bool CanHide(Transform t)
  160. {
  161. return t && t.gameObject.activeSelf && !t.GetComponent<IsolateInfo>() && !IsolateInfo.Instance.FocusObjects.Any(t.gameObject.IsRelative);
  162. }
  163. private static IEnumerable<GameObject> GetGameObjectsToHide(GameObject keeperGo)
  164. {
  165. if (!keeperGo) return new List<GameObject>();
  166. var keeper = keeperGo.transform;
  167. var transformsToHide = new List<Transform>();
  168. while (keeper.parent)
  169. {
  170. transformsToHide.AddRange(keeper.parent.GetChildren().Where(CanHide));
  171. keeper = keeper.parent;
  172. }
  173. transformsToHide.AddRange(GetRootTransforms().Where(CanHide));
  174. return transformsToHide.Select(t => t.gameObject);
  175. }
  176. [PreferenceItem("Isolationist")]
  177. public static void PreferencesGUI()
  178. {
  179. GUILayout.Label("Shortcut: " + ShortcutDisplay);
  180. _ctrl = EditorGUILayout.Toggle("Ctrl", _ctrl);
  181. _alt = EditorGUILayout.Toggle("Alt", _alt);
  182. _shift = EditorGUILayout.Toggle("Shift", _shift);
  183. _hotkey = (KeyCode) EditorGUILayout.EnumPopup("Shortcut Key", _hotkey);
  184. GUILayout.Label("");
  185. _hideLights = EditorGUILayout.Toggle("Hide Lights", _hideLights);
  186. _hideCameras = EditorGUILayout.Toggle("Hide Cameras", _hideCameras);
  187. if (!GUI.changed) return;
  188. EditorPrefs.SetBool(ISOLATE_CTRL_PREF, _ctrl);
  189. EditorPrefs.SetBool(ISOLATE_ALT_PREF, _alt);
  190. EditorPrefs.SetBool(ISOLATE_SHIFT_PREF, _shift);
  191. EditorPrefs.SetBool(ISOLATE_HIDE_LIGHTS_PREF, _hideLights);
  192. EditorPrefs.SetBool(ISOLATE_HIDE_CAMERAS_PREF, _hideCameras);
  193. EditorPrefs.SetInt(ISOLATE_KEY_PREF, (int) _hotkey);
  194. _shortcutDisplay = GetShortcutDisplay();
  195. }
  196. private static void EndIsolation()
  197. {
  198. if (!IsolateInfo.Instance) return;
  199. if (IsolateInfo.Instance.HiddenObjects != null)
  200. {
  201. Undo.RecordObjects(IsolateInfo.Instance.HiddenObjects.Cast<Object>().ToArray(), "DeIsolate");
  202. IsolateInfo.Show();
  203. }
  204. Undo.DestroyObjectImmediate(IsolateInfo.Instance.gameObject);
  205. }
  206. private static string GetShortcutDisplay()
  207. {
  208. var display = "";
  209. if (_ctrl) display += "Ctrl+";
  210. if (_alt) display += "Alt+";
  211. if (_shift) display += "Shift+";
  212. display += _hotkey;
  213. return display;
  214. }
  215. #region Utils
  216. private static bool IsParent(this Transform parent, Transform transform)
  217. {
  218. while (parent)
  219. {
  220. if (parent == transform) return true;
  221. parent = parent.parent;
  222. }
  223. return false;
  224. }
  225. private static bool IsParent(this GameObject parent, GameObject go) { return parent && go && IsParent(parent.transform, go.transform); }
  226. private static bool IsRelative(this GameObject go1, GameObject go2) { return go2.IsParent(go1) || go1.IsParent(go2); }
  227. private static IEnumerable<Transform> GetChildren(this Transform t)
  228. {
  229. var children = new List<Transform>();
  230. for (var i = 0; i < t.childCount; i++) children.Add(t.GetChild(i));
  231. return children;
  232. }
  233. private static IEnumerable<GameObject> GetRootSceneObjects()
  234. {
  235. #if UNITY_5_3_OR_NEWER
  236. return SceneManager.GetActiveScene().GetRootGameObjects();
  237. #else
  238. var prop = new HierarchyProperty(HierarchyType.GameObjects);
  239. var expanded = new int[0];
  240. while (prop.Next(expanded)) yield return prop.pptrValue as GameObject;
  241. #endif
  242. }
  243. private static IEnumerable<Transform> GetRootTransforms() { return GetRootSceneObjects().Where(go => go).Select(go => go.transform); }
  244. private static bool IsNullOrEmpty(this string str) { return string.IsNullOrEmpty(str); }
  245. #endregion
  246. }
  247. }