using System.Collections; using System.Collections.Generic; using UnityEngine; using ES3Internal; using UnityEngine.SceneManagement; #if UNITY_EDITOR using UnityEditor; using UnityEditor.SceneManagement; using System.Reflection; using System; using System.Linq; #endif #if UNITY_VISUAL_SCRIPTING using Unity.VisualScripting; [IncludeInSettings(true)] #endif public class ES3ReferenceMgr : ES3ReferenceMgrBase { #if UNITY_EDITOR [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void RefreshDependencies(bool isEnteringPlayMode = false) { // Empty the refId so it has to be refreshed. refId = null; ES3ReferenceMgrBase.isEnteringPlayMode = isEnteringPlayMode; // This will get the dependencies for all GameObjects and Components from the active scene. AddDependencies(this.gameObject.scene.GetRootGameObjects()); AddDependenciesFromFolders(); AddPrefabsToManager(); RemoveNullOrInvalidValues(); ES3ReferenceMgrBase.isEnteringPlayMode = false; } [MenuItem("Tools/Easy Save 3/Refresh References for All Scenes", false, 150)] static void RefreshDependenciesInAllScenes() { if (!EditorUtility.DisplayDialog("Refresh references in all scenes", "This will open each scene which is enabled in your Build Settings, refresh each reference manager, and save the scene.\n\nWe recommend making a backup of your project before doing this for the first time.", "Ok", "Cancel", DialogOptOutDecisionType.ForThisMachine, "ES3RefreshAllOptOut")) return; // Get a list of loaded scenes so we know whether we need to close them after refreshing references or not. var loadedScenePaths = new string[SceneManager.sceneCount]; for (int i = 0; i < SceneManager.sceneCount; i++) loadedScenePaths[i] = SceneManager.GetSceneAt(i).path; var scenes = EditorBuildSettings.scenes; var sceneNameList = ""; // We use this so we can display a list of scenes at the end. for (int i = 0; i < scenes.Length; i++) { var buildSettingsScene = scenes[i]; if (!buildSettingsScene.enabled) continue; if (EditorUtility.DisplayCancelableProgressBar("Refreshing references", $"Refreshing references for scene {buildSettingsScene.path}.", i / scenes.Length)) return; var sceneWasOpen = loadedScenePaths.Contains(buildSettingsScene.path); var scene = EditorSceneManager.OpenScene(buildSettingsScene.path, OpenSceneMode.Additive); var mgr = ES3ReferenceMgr.GetManagerFromScene(scene); if (mgr != null) { try { ((ES3ReferenceMgr)mgr).RefreshDependencies(); } catch(Exception e) { ES3Debug.LogError($"Couldn't update references for scene {scene.name} as the following exception occurred:\n\n" + e); } } sceneNameList += $"{scene.name}\n"; // If the scene wasn't originally open, save it and close it. if (!sceneWasOpen) { // Temporarily disable refreshing on save so that it doesn't refresh again. var updateReferencesOnSave = ES3Settings.defaultSettingsScriptableObject.updateReferencesWhenSceneIsSaved; ES3Settings.defaultSettingsScriptableObject.updateReferencesWhenSceneIsSaved = false; EditorSceneManager.SaveScene(scene); EditorSceneManager.CloseScene(scene, true); ES3Settings.defaultSettingsScriptableObject.updateReferencesWhenSceneIsSaved = updateReferencesOnSave; } } EditorUtility.ClearProgressBar(); EditorUtility.DisplayDialog("References refreshed", $"Refrences updated for scenes:\n\n{sceneNameList}", "Ok", DialogOptOutDecisionType.ForThisMachine, "ES3RefreshAllCompleteOptOut"); } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void Optimize() { var dependencies = EditorUtility.CollectDependencies(this.gameObject.scene.GetRootGameObjects().Where(go => go != this.gameObject).ToArray()); var notDependenciesOfScene = new HashSet(); foreach (var kvp in idRef) if (!dependencies.Contains(kvp.Value)) notDependenciesOfScene.Add(kvp.Value); foreach (var obj in notDependenciesOfScene) Remove(obj); } /* Adds all dependencies from this scene to the manager */ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void AddDependencies() { var rootGameObjects = gameObject.scene.GetRootGameObjects(); for (int j = 0; j < rootGameObjects.Length; j++) { var go = rootGameObjects[j]; if (EditorUtility.DisplayCancelableProgressBar("Gathering references", "Populating reference manager with your scene dependencies so they can be saved and loaded by reference.", j / rootGameObjects.Length)) return; AddDependencies(go); } EditorUtility.ClearProgressBar(); } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void AddDependencies(UnityEngine.Object[] objs) { var timeStarted = EditorApplication.timeSinceStartup; var timeout = ES3Settings.defaultSettingsScriptableObject.collectDependenciesTimeout; foreach (var obj in objs) { if (obj == null || obj.name == "Easy Save 3 Manager") continue; foreach (var dependency in EditorUtility.CollectDependencies(new UnityEngine.Object[] { obj })) { if (EditorApplication.timeSinceStartup - timeStarted > timeout) { ES3Debug.LogWarning($"Easy Save cancelled gathering of references for object {obj.name} because it took longer than {timeout} seconds. You can increase the timeout length in Tools > Easy Save 3 > Settings > Reference Gathering Timeout, or adjust the settings so that fewer objects are referenced in your scene."); return; } Add(dependency); if (obj is ES3Prefab prefab) AddPrefabToManager(prefab); } } } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void AddDependenciesFromFolders() { var folders = ES3Settings.defaultSettingsScriptableObject.referenceFolders; // Remove null or empty values. ArrayUtility.Remove(ref folders, ""); ArrayUtility.Remove(ref folders, null); if (folders == null || folders.Length == 0) return; var guids = AssetDatabase.FindAssets("t:Object", folders); foreach (var guid in guids) { var path = AssetDatabase.GUIDToAssetPath(guid); var obj = AssetDatabase.LoadAssetAtPath(path); if(obj != null) AddDependencies(obj); } } /*[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void AddDependenciesLegacy(UnityEngine.Object[] objs) { for (int i = 0; i < objs.Length; i++) { var obj = objs[i]; if (obj.name == "Easy Save 3 Manager") continue; var dependencies = CollectDependenciesLegacy(obj); foreach (var dependency in dependencies) { if (dependency != null) { Add(dependency); // Add the prefab if it's referenced by this scene. if (dependency.GetType() == typeof(ES3Prefab)) AddPrefabToManager((ES3Prefab)dependency); } } } Undo.RecordObject(this, "Update Easy Save 3 Reference List"); }*/ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void AddDependencies(UnityEngine.Object obj) { AddDependencies(new UnityEngine.Object[] { obj }); } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void GeneratePrefabReferences() { AddPrefabsToManager(); foreach (var es3Prefab in prefabs) es3Prefab.GeneratePrefabReferences(); } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public void AddPrefabsToManager() { if (ES3Settings.defaultSettingsScriptableObject.addAllPrefabsToManager) { // Clear any null values. This isn't necessary if we're not adding all prefabs to manager as the list is cleared each time. if (this.prefabs.RemoveAll(item => item == null) > 0) Undo.RecordObject(this, "Update Easy Save 3 Reference List"); foreach (var es3Prefab in Resources.FindObjectsOfTypeAll()) AddPrefabToManager(es3Prefab); } } [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] private void AddPrefabToManager(ES3Prefab es3Prefab) { try { if (es3Prefab != null && EditorUtility.IsPersistent(es3Prefab)) if(AddPrefab(es3Prefab)) Undo.RecordObject(this, "Update Easy Save 3 Reference List"); es3Prefab.GeneratePrefabReferences(); } catch { } } #endif }