FR2_SceneCache.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. #if UNITY_2018_3_OR_NEWER
  2. #define SUPPORT_NESTED_PREFAB
  3. #endif
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. using UnityEditor;
  9. using UnityEngine;
  10. using Object = UnityEngine.Object;
  11. #if UNITY_2017_1_OR_NEWER
  12. using UnityEditor.SceneManagement;
  13. using UnityEngine.SceneManagement;
  14. #endif
  15. #if SUPPORT_NESTED_PREFAB
  16. using UnityEditor.Experimental.SceneManagement;
  17. #endif
  18. namespace vietlabs.fr2
  19. {
  20. public class FR2_SceneCache
  21. {
  22. private static FR2_SceneCache _api;
  23. public static Action onReady;
  24. public static bool ready = true;
  25. private Dictionary<Component, HashSet<HashValue>> _cache = new Dictionary<Component, HashSet<HashValue>>();
  26. public int current;
  27. public Dictionary<string, HashSet<Component>> folderCache = new Dictionary<string, HashSet<Component>>();
  28. private List<GameObject> listGO;
  29. //public HashSet<string> prefabDependencies = new HashSet<string>();
  30. public Dictionary<GameObject, HashSet<string>> prefabDependencies =
  31. new Dictionary<GameObject, HashSet<string>>();
  32. public int total;
  33. private IWindow window;
  34. public FR2_SceneCache()
  35. {
  36. #if UNITY_2018_1_OR_NEWER
  37. EditorApplication.hierarchyChanged -= OnSceneChanged;
  38. EditorApplication.hierarchyChanged += OnSceneChanged;
  39. #else
  40. EditorApplication.hierarchyWindowChanged -= OnSceneChanged;
  41. EditorApplication.hierarchyWindowChanged += OnSceneChanged;
  42. #endif
  43. #if UNITY_2018_2_OR_NEWER
  44. EditorSceneManager.activeSceneChangedInEditMode -= OnSceneChanged;
  45. EditorSceneManager.activeSceneChangedInEditMode += OnSceneChanged;
  46. #endif
  47. #if UNITY_2017_1_OR_NEWER
  48. SceneManager.activeSceneChanged -= OnSceneChanged;
  49. SceneManager.activeSceneChanged += OnSceneChanged;
  50. SceneManager.sceneLoaded -= OnSceneChanged;
  51. SceneManager.sceneLoaded += OnSceneChanged;
  52. Undo.postprocessModifications -= OnModify;
  53. Undo.postprocessModifications += OnModify;
  54. #endif
  55. #if SUPPORT_NESTED_PREFAB
  56. PrefabStage.prefabStageOpened -= prefabOnpen;
  57. PrefabStage.prefabStageClosing += prefabClose;
  58. PrefabStage.prefabStageOpened -= prefabOnpen;
  59. PrefabStage.prefabStageClosing += prefabClose;
  60. #endif
  61. }
  62. public static FR2_SceneCache Api
  63. {
  64. get
  65. {
  66. if (_api == null)
  67. {
  68. _api = new FR2_SceneCache();
  69. }
  70. return _api;
  71. }
  72. }
  73. private bool _dirty = true;
  74. public bool Dirty
  75. {
  76. get { return _dirty; }
  77. set { _dirty = value; }
  78. }
  79. public Dictionary<Component, HashSet<HashValue>> cache
  80. {
  81. get
  82. {
  83. if (_cache == null)
  84. {
  85. refreshCache(window);
  86. }
  87. return _cache;
  88. }
  89. }
  90. public void refreshCache(IWindow window)
  91. {
  92. if (window == null)
  93. {
  94. return;
  95. }
  96. // if(!ready) return;
  97. this.window = window;
  98. _cache = new Dictionary<Component, HashSet<HashValue>>();
  99. folderCache = new Dictionary<string, HashSet<Component>>();
  100. prefabDependencies = new Dictionary<GameObject, HashSet<string>>();
  101. ready = false;
  102. List<GameObject> listRootGO = null;
  103. #if SUPPORT_NESTED_PREFAB
  104. if (PrefabStageUtility.GetCurrentPrefabStage() != null)
  105. {
  106. GameObject rootPrefab = PrefabStageUtility.GetCurrentPrefabStage().prefabContentsRoot;
  107. if (rootPrefab != null)
  108. {
  109. listRootGO = new List<GameObject> {rootPrefab};
  110. }
  111. }
  112. #else
  113. #endif
  114. if (listRootGO == null)
  115. {
  116. listGO = FR2_Unity.getAllObjsInCurScene().ToList();
  117. }
  118. else
  119. {
  120. listGO = new List<GameObject>();
  121. foreach (GameObject item in listRootGO)
  122. {
  123. listGO.AddRange(FR2_Unity.getAllChild(item, true));
  124. }
  125. }
  126. total = listGO.Count;
  127. current = 0;
  128. // Debug.Log("refresh cache total " + total);
  129. EditorApplication.update -= OnUpdate;
  130. EditorApplication.update += OnUpdate;
  131. // foreach (var item in FR2_Helper.getAllObjsInCurScene())
  132. // {
  133. // // Debug.Log("object in scene: " + item.name);
  134. // Component[] components = item.GetComponents<Component>();
  135. // foreach (var com in components)
  136. // {
  137. // if(com == null) continue;
  138. // SerializedObject serialized = new SerializedObject(com);
  139. // SerializedProperty it = serialized.GetIterator().Copy();
  140. // while (it.NextVisible(true))
  141. // {
  142. // if (it.propertyType != SerializedPropertyType.ObjectReference) continue;
  143. // if (it.objectReferenceValue == null) continue;
  144. // if(!_cache.ContainsKey(com)) _cache.Add(com, new HashSet<SerializedProperty>());
  145. // if(!_cache[com].Contains(it))
  146. // _cache[com].Add(it.Copy());
  147. // }
  148. // }
  149. // }
  150. Dirty = false;
  151. }
  152. private void OnUpdate()
  153. {
  154. for (var i = 0; i < 5 * FR2_Cache.priority; i++)
  155. {
  156. if (listGO == null || listGO.Count <= 0)
  157. {
  158. //done
  159. // Debug.Log("done");
  160. EditorApplication.update -= OnUpdate;
  161. ready = true;
  162. Dirty = false;
  163. listGO = null;
  164. if (onReady != null)
  165. {
  166. onReady();
  167. }
  168. if (window != null)
  169. {
  170. window.OnSelectionChange();
  171. }
  172. return;
  173. }
  174. int index = listGO.Count - 1;
  175. GameObject go = listGO[index];
  176. if (go == null)
  177. {
  178. continue;
  179. }
  180. string prefabGUID = FR2_Unity.GetPrefabParent(go);
  181. if (!string.IsNullOrEmpty(prefabGUID))
  182. {
  183. Transform parent = go.transform.parent;
  184. while (parent != null)
  185. {
  186. GameObject g = parent.gameObject;
  187. if (!prefabDependencies.ContainsKey(g))
  188. {
  189. prefabDependencies.Add(g, new HashSet<string>());
  190. }
  191. prefabDependencies[g].Add(prefabGUID);
  192. parent = parent.parent;
  193. }
  194. }
  195. Component[] components = go.GetComponents<Component>();
  196. foreach (Component com in components)
  197. {
  198. if (com == null)
  199. {
  200. continue;
  201. }
  202. var serialized = new SerializedObject(com);
  203. SerializedProperty it = serialized.GetIterator().Copy();
  204. while (it.NextVisible(true))
  205. {
  206. if (it.propertyType != SerializedPropertyType.ObjectReference)
  207. {
  208. continue;
  209. }
  210. if (it.objectReferenceValue == null)
  211. {
  212. continue;
  213. }
  214. var isSceneObject = true;
  215. string path = AssetDatabase.GetAssetPath(it.objectReferenceValue);
  216. if (!string.IsNullOrEmpty(path))
  217. {
  218. string dir = Path.GetDirectoryName(path);
  219. if (!string.IsNullOrEmpty(dir))
  220. {
  221. isSceneObject = false;
  222. if (!folderCache.ContainsKey(dir))
  223. {
  224. folderCache.Add(dir, new HashSet<Component>());
  225. }
  226. if (!folderCache[dir].Contains(com))
  227. {
  228. folderCache[dir].Add(com);
  229. }
  230. }
  231. }
  232. if (!_cache.ContainsKey(com))
  233. {
  234. _cache.Add(com, new HashSet<HashValue>());
  235. }
  236. _cache[com].Add(new HashValue
  237. {target = it.objectReferenceValue, isSceneObject = isSceneObject});
  238. // if (!_cache.ContainsKey(com)) _cache.Add(com, new HashSet<SerializedProperty>());
  239. // if (!_cache[com].Contains(it))
  240. // _cache[com].Add(it.Copy());
  241. // string path = AssetDatabase.GetAssetPath(it.objectReferenceValue);
  242. // if (string.IsNullOrEmpty(path)) continue;
  243. // string dir = System.IO.Path.GetDirectoryName(path);
  244. // if (string.IsNullOrEmpty(dir)) continue;
  245. // if (!folderCache.ContainsKey(dir)) folderCache.Add(dir, new HashSet<Component>());
  246. // if (!folderCache[dir].Contains(com))
  247. // folderCache[dir].Add(com);
  248. }
  249. }
  250. listGO.RemoveAt(index);
  251. current++;
  252. }
  253. }
  254. private void OnSceneChanged()
  255. {
  256. if (!Application.isPlaying)
  257. {
  258. Api.refreshCache(window);
  259. return;
  260. }
  261. SetDirty();
  262. }
  263. #if UNITY_2017_1_OR_NEWER
  264. private UndoPropertyModification[] OnModify(UndoPropertyModification[] modifications)
  265. {
  266. for (var i = 0; i < modifications.Length; i++)
  267. {
  268. if (modifications[i].currentValue.objectReference != null)
  269. {
  270. SetDirty();
  271. break;
  272. }
  273. }
  274. return modifications;
  275. }
  276. #endif
  277. public void SetDirty()
  278. {
  279. Dirty = true;
  280. }
  281. public class HashValue
  282. {
  283. public bool isSceneObject;
  284. public Object target;
  285. //public SerializedProperty pro;
  286. // public HashValue(SerializedProperty pro, bool isSceneObject)
  287. // {
  288. // //this.pro = pro;
  289. // this.isSceneObject = isSceneObject;
  290. // }
  291. }
  292. #if SUPPORT_NESTED_PREFAB
  293. private void prefabClose(PrefabStage obj)
  294. {
  295. if (!Application.isPlaying)
  296. {
  297. Api.refreshCache(window);
  298. return;
  299. }
  300. SetDirty();
  301. }
  302. private void prefabOnpen(PrefabStage obj)
  303. {
  304. if (!Application.isPlaying)
  305. {
  306. Api.refreshCache(window);
  307. return;
  308. }
  309. SetDirty();
  310. }
  311. #endif
  312. #if UNITY_2017_1_OR_NEWER
  313. private void OnSceneChanged(Scene scene, LoadSceneMode mode)
  314. {
  315. OnSceneChanged();
  316. }
  317. private void OnSceneChanged(Scene arg0, Scene arg1)
  318. {
  319. OnSceneChanged();
  320. }
  321. #endif
  322. }
  323. }