using System; using System.Collections.Generic; using System.Globalization; using System.IO; using UnityEditor; using UnityEngine; using Object = UnityEngine.Object; #if UNITY_5_3_OR_NEWER #endif namespace vietlabs.fr2 { // filter, ignore anh huong ket qua thi hien mau do // optimize lag duplicate khi use public class FR2_WindowAll : FR2_WindowBase, IHasCustomMenu { [MenuItem("Window/Find Reference 2")] private static void ShowWindow() { var _window = CreateInstance(); _window.InitIfNeeded(); FR2_Unity.SetWindowTitle(_window, "FR2"); _window.Show(); } [NonSerialized] internal FR2_Bookmark bookmark; [NonSerialized] internal FR2_Selection selection; [NonSerialized] internal FR2_UsedInBuild UsedInBuild; [NonSerialized] internal FR2_DuplicateTree2 Duplicated; [NonSerialized] internal FR2_RefDrawer RefUnUse; [NonSerialized] internal FR2_RefDrawer UsesDrawer; // [Selected Assets] are [USING] (depends on / contains reference to) ---> those assets [NonSerialized] internal FR2_RefDrawer UsedByDrawer; // [Selected Assets] are [USED BY] <---- those assets [NonSerialized] internal FR2_RefDrawer SceneToAssetDrawer; // [Selected GameObjects in current Scene] are [USING] ---> those assets [NonSerialized] internal FR2_RefDrawer RefInScene; // [Selected Assets] are [USED BY] <---- those components in current Scene [NonSerialized] internal FR2_RefDrawer SceneUsesDrawer; // [Selected GameObjects] are [USING] ---> those components / GameObjects in current scene [NonSerialized] internal FR2_RefDrawer RefSceneInScene; // [Selected GameObjects] are [USED BY] <---- those components / GameObjects in current scene internal int level; private Vector2 scrollPos; private string tempGUID; private Object tempObject; protected bool lockSelection { get { return selection != null && selection.isLock; } } private void OnEnable() { Repaint(); } protected void InitIfNeeded() { if (UsesDrawer != null) return; UsesDrawer = new FR2_RefDrawer(this) { messageEmpty = "[Selected Assets] are not [USING] (depends on / contains reference to) any other assets!" }; UsedByDrawer = new FR2_RefDrawer(this) { messageEmpty = "[Selected Assets] are not [USED BY] any other assets!" }; Duplicated = new FR2_DuplicateTree2(this); SceneToAssetDrawer = new FR2_RefDrawer(this) { messageEmpty = "[Selected GameObjects] (in current open scenes) are not [USING] any assets!" }; RefUnUse = new FR2_RefDrawer(this); RefUnUse.groupDrawer.hideGroupIfPossible = true; UsedInBuild = new FR2_UsedInBuild(this); bookmark = new FR2_Bookmark(this); selection = new FR2_Selection(this); SceneUsesDrawer = new FR2_RefDrawer(this) { messageEmpty = "[Selected GameObjects] are not [USING] any other GameObjects in scenes" }; RefInScene = new FR2_RefDrawer(this) { messageEmpty = "[Selected Assets] are not [USED BY] any GameObjects in opening scenes!" }; RefSceneInScene = new FR2_RefDrawer(this) { messageEmpty = "[Selected GameObjects] are not [USED BY] by any GameObjects in opening scenes!" }; #if UNITY_2018_OR_NEWER UnityEditor.SceneManagement.EditorSceneManager.activeSceneChangedInEditMode -= OnSceneChanged; UnityEditor.SceneManagement.EditorSceneManager.activeSceneChangedInEditMode += OnSceneChanged; #elif UNITY_2017_OR_NEWER UnityEditor.SceneManagement.EditorSceneManager.activeSceneChanged -= OnSceneChanged; UnityEditor.SceneManagement.EditorSceneManager.activeSceneChanged += OnSceneChanged; #endif FR2_Cache.onReady -= OnReady; FR2_Cache.onReady += OnReady; FR2_Setting.OnIgnoreChange -= OnIgnoreChanged; FR2_Setting.OnIgnoreChange += OnIgnoreChanged; Repaint(); } #if UNITY_2018_OR_NEWER private void OnSceneChanged(Scene arg0, Scene arg1) { if (IsFocusingFindInScene || IsFocusingSceneToAsset || IsFocusingSceneInScene) { OnSelectionChange(); } } #endif protected void OnIgnoreChanged() { RefUnUse.ResetUnusedAsset(); UsedInBuild.SetDirty(); OnSelectionChange(); } protected void OnCSVClick() { FR2_Ref[] csvSource = null; var drawer = GetAssetDrawer(); if (drawer != null) csvSource = drawer.source; if (IsFocusingUnused && csvSource == null) { csvSource = RefUnUse.source; //if (csvSource != null) Debug.Log("d : " + csvSource.Length); } if (IsFocusingUsedInBuild && csvSource == null) { csvSource = FR2_Ref.FromDict(UsedInBuild.refs); //if (csvSource != null) Debug.Log("e : " + csvSource.Length); } if (IsFocusingDuplicate && csvSource == null) { csvSource = FR2_Ref.FromList(Duplicated.list); //if (csvSource != null) Debug.Log("f : " + csvSource.Length); } FR2_Export.ExportCSV(csvSource); } protected void OnReady() { OnSelectionChange(); } public override void OnSelectionChange() { Repaint(); isNoticeIgnore = false; if (!FR2_Cache.isReady) { return; } if (focusedWindow == null) { return; } if (SceneUsesDrawer == null) { InitIfNeeded(); } if (UsesDrawer == null) { InitIfNeeded(); } if (!lockSelection) { ids = FR2_Unity.Selection_AssetGUIDs; selection.Clear(); //ignore selection on asset when selected any object in scene if (Selection.gameObjects.Length > 0 && !FR2_Unity.IsInAsset(Selection.gameObjects[0])) { ids = new string[0]; selection.AddRange(Selection.gameObjects); } else { selection.AddRange(ids); } level = 0; if (selection.isSelectingAsset) { UsesDrawer.Reset(ids, true); UsedByDrawer.Reset(ids, false); RefInScene.Reset(ids, this as IWindow); } else { RefSceneInScene.ResetSceneInScene(Selection.gameObjects); SceneToAssetDrawer.Reset(Selection.gameObjects, true, true); SceneUsesDrawer.ResetSceneUseSceneObjects(Selection.gameObjects); } // auto disable enable scene / asset if (IsFocusingUses) { sp2.splits[0].visible = !selection.isSelectingAsset; sp2.splits[1].visible = true; sp2.CalculateWeight(); } if (IsFocusingUsedBy) { sp2.splits[0].visible = true; sp2.splits[1].visible = selection.isSelectingAsset; sp2.CalculateWeight(); } } if (IsFocusingGUIDs) { //objs = new Object[ids.Length]; objs = new Dictionary(); var objects = Selection.objects; for (var i = 0; i < objects.Length; i++) { var item = objects[i]; #if UNITY_2018_1_OR_NEWER { var guid = ""; long fileid =-1; try { if(AssetDatabase.TryGetGUIDAndLocalFileIdentifier(item, out guid, out fileid)) { objs.Add(guid+"/"+ fileid, objects[i]); //Debug.Log("guid: " + guid + " fileID: " + fileid); } } catch{} } #else { var path = AssetDatabase.GetAssetPath(item); if (string.IsNullOrEmpty(path)) continue; var guid = AssetDatabase.AssetPathToGUID(path); System.Reflection.PropertyInfo inspectorModeInfo = typeof(SerializedObject).GetProperty("inspectorMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); SerializedObject serializedObject = new SerializedObject(item); inspectorModeInfo.SetValue(serializedObject, InspectorMode.Debug, null); SerializedProperty localIdProp = serializedObject.FindProperty("m_LocalIdentfierInFile"); //note the misspelling! var localId = localIdProp.longValue; if (localId <= 0) { localId = localIdProp.intValue; } if (localId <= 0) { continue; } if (!string.IsNullOrEmpty(guid)) objs.Add(guid + "/" + localId, objects[i]); } #endif } } if (IsFocusingUnused) { RefUnUse.ResetUnusedAsset(); } if (FR2_SceneCache.Api.Dirty && !Application.isPlaying) { FR2_SceneCache.Api.refreshCache(this); } EditorApplication.delayCall -= Repaint; EditorApplication.delayCall += Repaint; } public FR2_SplitView sp1; // container : Selection / sp2 / Bookmark public FR2_SplitView sp2; // Scene / Assets void InitPanes() { sp2 = new FR2_SplitView(this) { isHorz = false, splits = new List() { new FR2_SplitView.Info(){ title = new GUIContent("Scene", FR2_Icon.Scene.image), draw = DrawScene }, new FR2_SplitView.Info(){ title = new GUIContent("Assets", FR2_Icon.Asset.image), draw = DrawAsset }, } }; sp2.CalculateWeight(); sp1 = new FR2_SplitView(this) { isHorz = true, splits = new List() { new FR2_SplitView.Info(){ title = new GUIContent("Selection", FR2_Icon.Selection.image), weight = 0.4f, visible = false, draw = (rect) => selection.Draw(rect) }, new FR2_SplitView.Info(){ draw = (r) => { if (IsFocusingUses || IsFocusingUsedBy) { sp2.Draw(r); } else { DrawTools(r); } } }, new FR2_SplitView.Info(){ title = new GUIContent("Bookmark", FR2_Icon.Favorite.image), weight = 0.4f, visible = false, draw = (rect) => bookmark.Draw(rect) }, } }; sp1.CalculateWeight(); } private FR2_TabView tabs; private FR2_TabView bottomTabs; private FR2_SearchView search; void DrawScene(Rect rect) { FR2_RefDrawer drawer = IsFocusingUses ? (selection.isSelectingAsset ? null : SceneUsesDrawer) : (selection.isSelectingAsset ? RefInScene : RefSceneInScene); if (drawer == null) return; if (!FR2_SceneCache.ready) { var rr = rect; rr.height = 16f; int cur = FR2_SceneCache.Api.current, total = FR2_SceneCache.Api.total; EditorGUI.ProgressBar(rr, cur * 1f / total, string.Format("{0} / {1}", cur, total)); WillRepaint = true; return; } drawer.Draw(rect); var refreshRect = new Rect(rect.xMax-16f, rect.yMin-14f, 18f, 18f); if (GUI2.ColorIconButton(refreshRect, FR2_Icon.Refresh.image, FR2_SceneCache.Api.Dirty ? (Color?)GUI2.lightRed : null)) { FR2_SceneCache.Api.refreshCache(drawer.window); } } FR2_RefDrawer GetAssetDrawer() { if (IsFocusingUses) { return selection.isSelectingAsset ? UsesDrawer : SceneToAssetDrawer; } if (IsFocusingUsedBy) { return selection.isSelectingAsset ? UsedByDrawer : null; } return null; } void DrawAsset(Rect rect) { var drawer = GetAssetDrawer(); if (drawer != null) drawer.Draw(rect); } void DrawSearch() { if (search == null) search = new FR2_SearchView(); search.DrawLayout(); } protected override void OnGUI() { OnGUI2(); } protected bool CheckDrawImport() { if (EditorApplication.isCompiling) { EditorGUILayout.HelpBox("Compiling scripts, please wait!", MessageType.Warning); Repaint(); return false; } if (EditorApplication.isUpdating) { EditorGUILayout.HelpBox("Importing assets, please wait!", MessageType.Warning); Repaint(); return false; } InitIfNeeded(); if (EditorSettings.serializationMode != SerializationMode.ForceText) { EditorGUILayout.HelpBox("FR2 requires serialization mode set to FORCE TEXT!", MessageType.Warning); if (GUILayout.Button("FORCE TEXT")) { EditorSettings.serializationMode = SerializationMode.ForceText; } return false; } if (FR2_Cache.hasCache && !FR2_Cache.CheckSameVersion()) { EditorGUILayout.HelpBox("Incompatible cache version found!!!\nFR2 will need a full refresh and this may take quite some time to finish but you would be able to work normally while the scan works in background!", MessageType.Warning); FR2_Cache.DrawPriorityGUI(); if (GUILayout.Button("Scan project")) { FR2_Cache.DeleteCache(); FR2_Cache.CreateCache(); } return false; } if (!FR2_Cache.isReady) { if (!FR2_Cache.hasCache) { EditorGUILayout.HelpBox( "FR2 cache not found!\nFirst scan may takes quite some time to finish but you would be able to work normally while the scan works in background...", MessageType.Warning); FR2_Cache.DrawPriorityGUI(); if (GUILayout.Button("Scan project")) { FR2_Cache.CreateCache(); Repaint(); } return false; } else { FR2_Cache.DrawPriorityGUI(); } if (!DrawEnable()) { return false; } FR2_Cache api = FR2_Cache.Api; string text = "Refreshing ... " + (int) (api.progress * api.workCount) + " / " + api.workCount; Rect rect = GUILayoutUtility.GetRect(1f, Screen.width, 18f, 18f); EditorGUI.ProgressBar(rect, api.progress, text); Repaint(); return false; } if (!DrawEnable()) { return false; } return true; } protected bool IsFocusingUses { get { return tabs != null && tabs.current == 0; }} protected bool IsFocusingUsedBy { get { return tabs != null && tabs.current == 1; }} protected bool IsFocusingDuplicate { get { return tabs != null && tabs.current == 2; }} protected bool IsFocusingGUIDs { get { return tabs != null && tabs.current == 3; }} protected bool IsFocusingUnused { get { return tabs != null && tabs.current == 4; }} protected bool IsFocusingUsedInBuild { get { return tabs != null && tabs.current == 5; }} void OnTabChange() { if (deleteUnused != null) deleteUnused.hasConfirm = false; if (UsedInBuild != null) UsedInBuild.SetDirty(); } void InitTabs() { tabs = FR2_TabView.Create(this, false, "Uses", "Used By", "Duplicate", "GUIDs", "Unused Assets", "Uses in Build" ); tabs.onTabChange = OnTabChange; tabs.callback = new DrawCallback() { BeforeDraw = ()=> { if (GUI2.ToolbarToggle(ref selection.isLock, selection.isLock ? FR2_Icon.Lock.image : FR2_Icon.Unlock.image, new Vector2(-1, 2), "Lock Selection")) { WillRepaint = true; } }, AfterDraw = () => { //GUILayout.Space(16f); if (GUI2.ToolbarToggle(ref sp1.isHorz, FR2_Icon.Panel.image, Vector2.zero, "Layout")) { sp1.CalculateWeight(); Repaint(); } if (GUI2.ToolbarToggle(ref sp1.splits[0].visible, FR2_Icon.Selection.image, Vector2.zero, "Show / Hide Selection")) { sp1.CalculateWeight(); Repaint(); } if (GUI2.ToolbarToggle(ref sp2.splits[0].visible, FR2_Icon.Scene.image, Vector2.zero, "Show / Hide Scene References")) { sp2.CalculateWeight(); Repaint(); } if (GUI2.ToolbarToggle(ref sp2.splits[1].visible, FR2_Icon.Asset.image, Vector2.zero, "Show / Hide Asset References")) { sp2.CalculateWeight(); Repaint(); } if (GUI2.ToolbarToggle(ref sp1.splits[2].visible, FR2_Icon.Favorite.image, Vector2.zero, "Show / Hide Bookmarks")) { sp1.CalculateWeight(); Repaint(); } } }; } protected bool DrawHeader() { if (tabs == null) InitTabs(); if (bottomTabs == null) { bottomTabs = FR2_TabView.Create(this, true, new GUIContent(FR2_Icon.Setting.image, "Settings"), new GUIContent(FR2_Icon.Ignore.image, "Ignore"), new GUIContent(FR2_Icon.Filter.image, "Filter by Type") ); bottomTabs.current = -1; } tabs.DrawLayout(); return true; } protected bool DrawFooter() { GUILayout.BeginHorizontal(EditorStyles.toolbar); { bottomTabs.DrawLayout(); GUILayout.FlexibleSpace(); DrawAssetViewSettings(); GUILayout.FlexibleSpace(); DrawViewModes(); } GUILayout.EndHorizontal(); return false; } void DrawAssetViewSettings() { var isDisable = !sp2.splits[1].visible; EditorGUI.BeginDisabledGroup(isDisable); { GUI2.ToolbarToggle(ref FR2_Setting.s.displayAssetBundleName, FR2_Icon.AssetBundle.image, Vector2.zero, "Show / Hide Assetbundle Names"); #if UNITY_2017_1_OR_NEWER GUI2.ToolbarToggle(ref FR2_Setting.s.displayAtlasName, FR2_Icon.Atlas.image, Vector2.zero, "Show / Hide Atlas packing tags"); #endif GUI2.ToolbarToggle(ref FR2_Setting.s.showUsedByClassed, FR2_Icon.Material.image, Vector2.zero, "Show / Hide usage icons"); GUI2.ToolbarToggle(ref FR2_Setting.s.displayFileSize, FR2_Icon.Filesize.image, Vector2.zero, "Show / Hide file size"); if (GUILayout.Button("CSV", EditorStyles.toolbarButton)) { OnCSVClick(); } } EditorGUI.EndDisabledGroup(); } void DrawViewModes() { var gMode = FR2_Setting.GroupMode; if (GUI2.EnumPopup(ref gMode, new GUIContent(FR2_Icon.Group.image, "Group by"), EditorStyles.toolbarPopup, GUILayout.Width(80f))) { FR2_Setting.GroupMode = gMode; markDirty(); } GUILayout.Space(16f); var sMode = FR2_Setting.SortMode; if (GUI2.EnumPopup(ref sMode, new GUIContent(FR2_Icon.Sort.image, "Sort by"), EditorStyles.toolbarPopup, GUILayout.Width(50f))) { FR2_Setting.SortMode = sMode; RefreshSort(); } } protected void OnGUI2() { if (!CheckDrawImport()) { return; } if (sp1 == null) InitPanes(); DrawHeader(); sp1.DrawLayout(); DrawSettings(); DrawFooter(); if (WillRepaint) { Repaint(); } } private FR2_DeleteButton deleteUnused; void DrawTools(Rect rect) { if (IsFocusingDuplicate) { rect = GUI2.Padding(rect, 2f, 2f); GUILayout.BeginArea(rect); Duplicated.DrawLayout(); GUILayout.EndArea(); return; } if (IsFocusingUnused) { rect = GUI2.Padding(rect, 2f, 2f); if ((RefUnUse.refs != null && RefUnUse.refs.Count == 0)) { GUILayout.BeginArea(rect); { EditorGUILayout.HelpBox("Wow! So clean!?", MessageType.Info); EditorGUILayout.HelpBox("Your project does not has have any unused assets, or have you just hit DELETE ALL?", MessageType.Info); EditorGUILayout.HelpBox("Your backups are placed at Library/FR2/ just in case you want your assets back!", MessageType.Info); } GUILayout.EndArea(); } else { rect.yMax -= 40f; GUILayout.BeginArea(rect); RefUnUse.DrawLayout(); GUILayout.EndArea(); var toolRect = rect; toolRect.yMin = toolRect.yMax; var lineRect = toolRect; lineRect.height = 1f; GUI2.Rect(lineRect, Color.black, 0.5f); toolRect.xMin += 2f; toolRect.xMax -= 2f; toolRect.height = 40f; if (deleteUnused == null) { deleteUnused = new FR2_DeleteButton() { warningMessage = "It's absolutely safe to delete them all!\nA backup (.unitypackage) will be created so you can import it back later!", deleteLabel = new GUIContent("DELETE ASSETS", FR2_Icon.Delete.image), confirmMessage = "Create backup at Library/FR2/" }; } GUILayout.BeginArea(toolRect); deleteUnused.Draw(()=> { FR2_Unity.BackupAndDeleteAssets(RefUnUse.source); }); GUILayout.EndArea(); } return; } if (IsFocusingUsedInBuild) { UsedInBuild.Draw(rect); return; } if (IsFocusingGUIDs) { rect = GUI2.Padding(rect, 2f, 2f); GUILayout.BeginArea(rect); DrawGUIDs(); GUILayout.EndArea(); return; } } void DrawSettings() { if (bottomTabs.current == -1) return; GUILayout.BeginVertical(GUILayout.Height(100f)); { GUILayout.Space(2f); switch (bottomTabs.current) { case 0: { FR2_Setting.s.DrawSettings(); break; } case 1: { if (AssetType.DrawIgnoreFolder()) { markDirty(); } break; } case 2: { if (AssetType.DrawSearchFilter()) { markDirty(); } break; } } } GUILayout.EndVertical(); var rect = GUILayoutUtility.GetLastRect(); rect.height = 1f; GUI2.Rect(rect, Color.black, 0.4f); } protected void markDirty() { UsedByDrawer.SetDirty(); UsesDrawer.SetDirty(); Duplicated.SetDirty(); SceneToAssetDrawer.SetDirty(); RefUnUse.SetDirty(); RefInScene.SetDirty(); RefSceneInScene.SetDirty(); SceneUsesDrawer.SetDirty(); UsedInBuild.SetDirty(); WillRepaint = true; } protected void RefreshSort() { UsedByDrawer.RefreshSort(); UsesDrawer.RefreshSort(); Duplicated.RefreshSort(); SceneToAssetDrawer.RefreshSort(); RefUnUse.RefreshSort(); UsedInBuild.RefreshSort(); } // public bool isExcludeByFilter; protected bool checkNoticeFilter() { var rsl = false; if (IsFocusingUsedBy && !rsl) { rsl = UsedByDrawer.isExclueAnyItem(); } if (IsFocusingDuplicate) { return Duplicated.isExclueAnyItem(); } if (IsFocusingUses && rsl == false) { rsl = UsesDrawer.isExclueAnyItem(); } //tab use by return rsl; } protected bool checkNoticeIgnore() { bool rsl = isNoticeIgnore; return rsl; } private Dictionary objs; private string[] ids; private void DrawGUIDs() { GUILayout.Label("GUID to Object", EditorStyles.boldLabel); GUILayout.BeginHorizontal(); { string guid = EditorGUILayout.TextField(tempGUID ?? string.Empty); EditorGUILayout.ObjectField(tempObject, typeof(Object), false, GUILayout.Width(120f)); if (GUILayout.Button("Paste", EditorStyles.miniButton, GUILayout.Width(70f))) { guid = EditorGUIUtility.systemCopyBuffer; } if (guid != tempGUID && !string.IsNullOrEmpty(guid)) { tempGUID = guid; tempObject = FR2_Unity.LoadAssetAtPath ( AssetDatabase.GUIDToAssetPath(tempGUID) ); } } GUILayout.EndHorizontal(); GUILayout.Space(10f); if (objs == null)// || ids == null) { return; } //GUILayout.Label("Selection", EditorStyles.boldLabel); //if (ids.Length == objs.Count) { scrollPos = GUILayout.BeginScrollView(scrollPos); { //for (var i = 0; i < ids.Length; i++) foreach (var item in objs) { //if (!objs.ContainsKey(ids[i])) continue; GUILayout.BeginHorizontal(); { //var obj = objs[ids[i]]; var obj = item.Value; EditorGUILayout.ObjectField(obj, typeof(Object), false, GUILayout.Width(150)); string idi = item.Key; GUILayout.TextField(idi, GUILayout.Width(240f)); if (GUILayout.Button("Copy", EditorStyles.miniButton, GUILayout.Width(50f))) { tempObject = obj; //EditorGUIUtility.systemCopyBuffer = tempGUID = item.Key; tempGUID = item.Key; //string guid = ""; //long file = -1; //if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out guid, out file)) //{ // EditorGUIUtility.systemCopyBuffer = tempGUID = idi + "/" + file; // if (!string.IsNullOrEmpty(tempGUID)) // { // tempObject = obj; // } //} } } GUILayout.EndHorizontal(); } } GUILayout.EndScrollView(); } GUILayout.BeginHorizontal(); if (GUILayout.Button("Merge Selection To")) { FR2_Export.MergeDuplicate(tempGUID); } EditorGUILayout.ObjectField(tempObject, typeof(Object), false, GUILayout.Width(120f)); GUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); } } }