622 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C#
		
	
	
	
		
		
			
		
	
	
			622 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C#
		
	
	
	
|  | using UnityEngine; | ||
|  | using System.Collections; | ||
|  | using System.Collections.Generic; | ||
|  | using System.Linq; | ||
|  | using System; | ||
|  | using UnityEngine.UI; | ||
|  | using UnityEngine.SceneManagement; | ||
|  | 
 | ||
|  | namespace ES3Internal | ||
|  | { | ||
|  |     [System.Serializable] | ||
|  |     [DisallowMultipleComponent] | ||
|  |     public abstract class ES3ReferenceMgrBase : MonoBehaviour | ||
|  |     { | ||
|  |         internal object _lock = new object(); | ||
|  | 
 | ||
|  |         public const string referencePropertyName = "_ES3Ref"; | ||
|  |         private static ES3ReferenceMgrBase _current = null; | ||
|  |         private static HashSet<ES3ReferenceMgrBase> mgrs = new HashSet<ES3ReferenceMgrBase>(); | ||
|  | #if UNITY_EDITOR | ||
|  |         private const int CollectDependenciesDepth = 5; | ||
|  |         protected static bool isEnteringPlayMode = false; | ||
|  |         static readonly HideFlags[] invalidHideFlags = new HideFlags[] { HideFlags.DontSave, HideFlags.DontSaveInBuild, HideFlags.DontSaveInEditor, HideFlags.HideAndDontSave }; | ||
|  | #endif | ||
|  | 
 | ||
|  |         private static System.Random rng; | ||
|  | 
 | ||
|  |         [HideInInspector] | ||
|  |         public bool openPrefabs = false; // Whether the prefab list should be open in the Editor. | ||
|  | 
 | ||
|  |         public List<ES3Prefab> prefabs = new List<ES3Prefab>(); | ||
|  | 
 | ||
|  |         public static ES3ReferenceMgrBase Current | ||
|  |         { | ||
|  |             get | ||
|  |             { | ||
|  |                 // If the reference manager hasn't been assigned, or we've got a reference to a manager in a different scene which isn't marked as DontDestroyOnLoad, look for this scene's manager. | ||
|  |                 if (_current == null /*|| (_current.gameObject.scene.buildIndex != -1 && _current.gameObject.scene != SceneManager.GetActiveScene())*/) | ||
|  |                 { | ||
|  |                     var scene = SceneManager.GetActiveScene(); | ||
|  |                     var roots = scene.GetRootGameObjects(); | ||
|  |                     ES3ReferenceMgr mgr = null; | ||
|  | 
 | ||
|  |                     // First, look for Easy Save 3 Manager in the top-level. | ||
|  |                     foreach (var root in roots) | ||
|  |                         if (root.name == "Easy Save 3 Manager") | ||
|  |                             mgr = root.GetComponent<ES3ReferenceMgr>(); | ||
|  | 
 | ||
|  |                     // If the user has moved or renamed the Easy Save 3 Manager, we need to perform a deep search. | ||
|  |                     if (mgr == null) | ||
|  |                         foreach (var root in roots) | ||
|  |                             if ((_current = root.GetComponentInChildren<ES3ReferenceMgr>()) != null) | ||
|  |                                 return _current; | ||
|  | 
 | ||
|  |                     mgrs.Add(_current = mgr); | ||
|  |                 } | ||
|  |                 return _current; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool IsInitialised { get { return idRef.Count > 0; } } | ||
|  | 
 | ||
|  |         [SerializeField] | ||
|  |         public ES3IdRefDictionary idRef = new ES3IdRefDictionary(); | ||
|  |         private ES3RefIdDictionary _refId = null; | ||
|  | 
 | ||
|  |         public ES3RefIdDictionary refId | ||
|  |         { | ||
|  |             get | ||
|  |             { | ||
|  |                 if (_refId == null) | ||
|  |                 { | ||
|  |                     _refId = new ES3RefIdDictionary(); | ||
|  |                     // Populate the reverse dictionary with the items from the normal dictionary. | ||
|  |                     foreach (var kvp in idRef) | ||
|  |                         if (kvp.Value != null) | ||
|  |                             _refId[kvp.Value] = kvp.Key; | ||
|  |                 } | ||
|  |                 return _refId; | ||
|  |             } | ||
|  |             set | ||
|  |             { | ||
|  |                 _refId = value; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public ES3GlobalReferences GlobalReferences | ||
|  |         { | ||
|  |             get | ||
|  |             { | ||
|  |                 return ES3GlobalReferences.Instance; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         private void Awake() | ||
|  |         { | ||
|  |             if (_current != null && _current != this) | ||
|  |             { | ||
|  |                 var existing = _current; | ||
|  | 
 | ||
|  |                 /* We intentionally use Current rather than _current here, as _current may contain a reference to a manager in another scene,  | ||
|  |                  * but Current only returns the Manager for the active scene. */ | ||
|  |                 if (Current != null) | ||
|  |                 { | ||
|  |                     existing.Merge(this); | ||
|  |                     if (gameObject.name.Contains("Easy Save 3 Manager")) | ||
|  |                         Destroy(this.gameObject); | ||
|  |                     else | ||
|  |                         Destroy(this); | ||
|  |                     _current = existing; // Undo the call to Current, which may have set it to NULL. | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |                 _current = this; | ||
|  |             mgrs.Add(this); | ||
|  |         } | ||
|  | 
 | ||
|  |         private void OnDestroy() | ||
|  |         { | ||
|  |             mgrs.Remove(this); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Merges two managers, not allowing any clashes of IDs | ||
|  |         public void Merge(ES3ReferenceMgrBase otherMgr) | ||
|  |         { | ||
|  |             foreach (var kvp in otherMgr.idRef) | ||
|  |                 Add(kvp.Value, kvp.Key); | ||
|  |         } | ||
|  | 
 | ||
|  |         public long Get(UnityEngine.Object obj) | ||
|  |         { | ||
|  |             foreach (var mgr in mgrs) | ||
|  |             { | ||
|  |                 if (mgr == null) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 if (obj == null) | ||
|  |                     return -1; | ||
|  |                 long id; | ||
|  |                 if (!mgr.refId.TryGetValue(obj, out id)) | ||
|  |                     return -1; | ||
|  |                 return id; | ||
|  |             } | ||
|  |             return -1; | ||
|  |         } | ||
|  | 
 | ||
|  |         internal UnityEngine.Object Get(long id, Type type, bool suppressWarnings=false) | ||
|  |         { | ||
|  |             foreach (var mgr in mgrs) | ||
|  |             { | ||
|  |                 if (mgr == null) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 if (id == -1) | ||
|  |                     return null; | ||
|  |                 UnityEngine.Object obj; | ||
|  |                 if (!mgr.idRef.TryGetValue(id, out obj)) | ||
|  |                 { | ||
|  |                     if (GlobalReferences != null) | ||
|  |                     { | ||
|  |                         var globalRef = GlobalReferences.Get(id); | ||
|  |                         if (globalRef != null) | ||
|  |                             return globalRef; | ||
|  |                     } | ||
|  | 
 | ||
|  |                     if(type != null) | ||
|  |                         ES3Debug.LogWarning("Reference for " + type + " with ID " + id + " could not be found in Easy Save's reference manager. If you are loading objects dynamically (i.e. objects created at runtime), this warning is expected and can be ignored.", this); | ||
|  |                     else | ||
|  |                         ES3Debug.LogWarning("Reference with ID " + id + " could not be found in Easy Save's reference manager. If you are loading objects dynamically (i.e. objects created at runtime), this warning is expected and can be ignored.", this); | ||
|  |                     return null; | ||
|  |                 } | ||
|  |                 if (obj == null) // If obj has been marked as destroyed but not yet destroyed, don't return it. | ||
|  |                     return null; | ||
|  |                 return obj; | ||
|  |             } | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         public UnityEngine.Object Get(long id, bool suppressWarnings = false) | ||
|  |         { | ||
|  |             return Get(id, null, suppressWarnings); | ||
|  |         } | ||
|  | 
 | ||
|  |         public ES3Prefab GetPrefab(long id, bool suppressWarnings = false) | ||
|  |         { | ||
|  |             foreach (var mgr in mgrs) | ||
|  |             { | ||
|  |                 if (mgr == null) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 foreach (var prefab in mgr.prefabs) | ||
|  |                     if (prefabs != null && prefab.prefabId == id) | ||
|  |                         return prefab; | ||
|  |             } | ||
|  |             if (!suppressWarnings) | ||
|  |                 ES3Debug.LogWarning("Prefab with ID " + id + " could not be found in Easy Save's reference manager. Try pressing the Refresh References button on the ES3ReferenceMgr Component of the Easy Save 3 Manager in your scene.", this); | ||
|  |             return null; | ||
|  |         } | ||
|  | 
 | ||
|  |         public long GetPrefab(ES3Prefab prefabToFind, bool suppressWarnings = false) | ||
|  |         { | ||
|  |             foreach (var mgr in mgrs) | ||
|  |             { | ||
|  |                 if (mgr == null) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 foreach (var prefab in prefabs) | ||
|  |                     if (prefab == prefabToFind) | ||
|  |                         return prefab.prefabId; | ||
|  |             } | ||
|  |             if (!suppressWarnings) | ||
|  |                 ES3Debug.LogWarning("Prefab with name " + prefabToFind.name + " could not be found in Easy Save's reference manager. Try pressing the Refresh References button on the ES3ReferenceMgr Component of the Easy Save 3 Manager in your scene.", prefabToFind); | ||
|  |             return -1; | ||
|  |         } | ||
|  | 
 | ||
|  |         public long Add(UnityEngine.Object obj) | ||
|  |         { | ||
|  |             long id; | ||
|  |             // If it already exists in the list, do nothing. | ||
|  |             if (refId.TryGetValue(obj, out id)) | ||
|  |                 return id; | ||
|  | 
 | ||
|  |             if (GlobalReferences != null) | ||
|  |             { | ||
|  |                 id = GlobalReferences.GetOrAdd(obj); | ||
|  |                 if (id != -1) | ||
|  |                 { | ||
|  |                     Add(obj, id); | ||
|  |                     return id; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             lock (_lock) | ||
|  |             { | ||
|  |                 // Add the reference to the Dictionary. | ||
|  |                 id = GetNewRefID(); | ||
|  |                 return Add(obj, id); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public long Add(UnityEngine.Object obj, long id) | ||
|  |         { | ||
|  |             if (!CanBeSaved(obj)) | ||
|  |                 return -1; | ||
|  | 
 | ||
|  |             // If the ID is -1, auto-generate an ID. | ||
|  |             if (id == -1) | ||
|  |                 id = GetNewRefID(); | ||
|  |             // Add the reference to the Dictionary. | ||
|  |             lock (_lock) | ||
|  |             { | ||
|  |                 idRef[id] = obj; | ||
|  |                 if(obj != null) | ||
|  |                     refId[obj] = id; | ||
|  |             } | ||
|  |             return id; | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool AddPrefab(ES3Prefab prefab) | ||
|  |         { | ||
|  |             if (!prefabs.Contains(prefab)) | ||
|  |             { | ||
|  |                 prefabs.Add(prefab); | ||
|  |                 return true; | ||
|  |             } | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Remove(UnityEngine.Object obj) | ||
|  |         { | ||
|  |             foreach (var mgr in mgrs) | ||
|  |             { | ||
|  |                 if (mgr == null) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 lock (mgr._lock) | ||
|  |                 { | ||
|  |                     mgr.refId.Remove(obj); | ||
|  |                     // There may be multiple references with the same ID, so remove them all. | ||
|  |                     foreach (var item in mgr.idRef.Where(kvp => kvp.Value == obj).ToList()) | ||
|  |                         mgr.idRef.Remove(item.Key); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Remove(long referenceID) | ||
|  |         { | ||
|  |             foreach (var mgr in mgrs) | ||
|  |             { | ||
|  |                 if (mgr == null) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 lock (mgr._lock) | ||
|  |                 { | ||
|  |                     mgr.idRef.Remove(referenceID); | ||
|  |                     // There may be multiple references with the same ID, so remove them all. | ||
|  |                     foreach (var item in mgr.refId.Where(kvp => kvp.Value == referenceID).ToList()) | ||
|  |                         mgr.refId.Remove(item.Key); | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public void RemoveNullOrInvalidValues() | ||
|  |         { | ||
|  |             var nullKeys = idRef.Where(pair => pair.Value == null || !CanBeSaved(pair.Value)) | ||
|  |                                 .Select(pair => pair.Key).ToList(); | ||
|  |             foreach (var key in nullKeys) | ||
|  |                 idRef.Remove(key); | ||
|  | 
 | ||
|  |             if (GlobalReferences != null) | ||
|  |                 GlobalReferences.RemoveInvalidKeys(); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Clear() | ||
|  |         { | ||
|  |             lock (_lock) | ||
|  |             { | ||
|  |                 refId.Clear(); | ||
|  |                 idRef.Clear(); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool Contains(UnityEngine.Object obj) | ||
|  |         { | ||
|  |             return refId.ContainsKey(obj); | ||
|  |         } | ||
|  | 
 | ||
|  |         public bool Contains(long referenceID) | ||
|  |         { | ||
|  |             return idRef.ContainsKey(referenceID); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void ChangeId(long oldId, long newId) | ||
|  |         { | ||
|  |             foreach (var mgr in mgrs) | ||
|  |             { | ||
|  |                 if (mgr == null) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 mgr.idRef.ChangeKey(oldId, newId); | ||
|  |                 // Empty the refId so it has to be refreshed. | ||
|  |                 mgr.refId = null; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         internal static long GetNewRefID() | ||
|  |         { | ||
|  |             if (rng == null) | ||
|  |                 rng = new System.Random(); | ||
|  | 
 | ||
|  |             byte[] buf = new byte[8]; | ||
|  |             rng.NextBytes(buf); | ||
|  |             long longRand = BitConverter.ToInt64(buf, 0); | ||
|  | 
 | ||
|  |             return (System.Math.Abs(longRand % (long.MaxValue - 0)) + 0); | ||
|  |         } | ||
|  | 
 | ||
|  | #if UNITY_EDITOR | ||
|  |         public static HashSet<UnityEngine.Object> CollectDependencies(UnityEngine.Object obj, HashSet<UnityEngine.Object> dependencies = null, int depth = CollectDependenciesDepth) | ||
|  |         { | ||
|  |             return CollectDependencies(new UnityEngine.Object[] { obj }, dependencies, depth); | ||
|  |         } | ||
|  | 
 | ||
|  |         /* | ||
|  |          * Collects all top-level dependencies of an object. | ||
|  |          * For GameObjects, it will traverse all children. | ||
|  |          * For Components or ScriptableObjects, it will get all serialisable UnityEngine.Object fields/properties as dependencies. | ||
|  |          */ | ||
|  |         public static HashSet<UnityEngine.Object> CollectDependencies(UnityEngine.Object[] objs, HashSet<UnityEngine.Object> dependencies = null, int depth = CollectDependenciesDepth) | ||
|  |         { | ||
|  |             if (depth < 0) | ||
|  |                 return dependencies; | ||
|  | 
 | ||
|  |             if (dependencies == null) | ||
|  |                 dependencies = new HashSet<UnityEngine.Object>(); | ||
|  | 
 | ||
|  |             foreach (var obj in objs) | ||
|  |             { | ||
|  |                 if (obj == null) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 var type = obj.GetType(); | ||
|  | 
 | ||
|  |                 // Skip types which don't need processing | ||
|  |                 if (type == typeof(ES3ReferenceMgr) || type == typeof(ES3AutoSaveMgr) || type == typeof(ES3AutoSave) || type == typeof(ES3InspectorInfo)) | ||
|  |                     continue; | ||
|  | 
 | ||
|  |                 // Add the prefab to the manager but don't process it. We'll use this to work out what prefabs to add to the prefabs list later. | ||
|  |                 if (type == typeof(ES3Prefab)) | ||
|  |                 { | ||
|  |                     dependencies.Add(obj); | ||
|  |                     continue; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 // If it's a GameObject, get the GameObject's Components and collect their dependencies. | ||
|  |                 if (type == typeof(GameObject)) | ||
|  |                 { | ||
|  |                     var go = (GameObject)obj; | ||
|  |                     // If we've not already processed this GameObject ... | ||
|  |                     if (dependencies.Add(go)) | ||
|  |                     { | ||
|  |                         // Get the dependencies of each Component in the GameObject. | ||
|  |                         CollectDependencies(go.GetComponents<Component>(), dependencies, depth - 1); | ||
|  |                         // Get the dependencies of each child in the GameObject. | ||
|  |                         foreach (Transform child in go.transform) | ||
|  |                             CollectDependencies(child.gameObject, dependencies, depth); // Don't decrement child, as we consider this a top-level object. | ||
|  |                     } | ||
|  |                 } | ||
|  |                 // Else if it's a Component or ScriptableObject, add the values of any UnityEngine.Object fields as dependencies. | ||
|  |                 else | ||
|  |                     CollectDependenciesFromFields(obj, dependencies, depth - 1); | ||
|  |             } | ||
|  | 
 | ||
|  |             return dependencies; | ||
|  |         } | ||
|  | 
 | ||
|  |         private static void CollectDependenciesFromFields(UnityEngine.Object obj, HashSet<UnityEngine.Object> dependencies, int depth) | ||
|  |         { | ||
|  |             // If we've already collected dependencies for this, do nothing. | ||
|  |             if (!dependencies.Add(obj)) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             if (depth < 0) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             var type = obj.GetType(); | ||
|  | 
 | ||
|  |             if (isEnteringPlayMode && type == typeof(UnityEngine.UI.Text)) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             try | ||
|  |             { | ||
|  |                 // SerializedObject is expensive, so for known classes we manually gather references. | ||
|  | 
 | ||
|  |                 if (type == typeof(Animator) || obj is Transform || type == typeof(CanvasRenderer) || type == typeof(Mesh) || type == typeof(AudioClip) || type == typeof(Rigidbody) || obj is Texture || obj is HorizontalOrVerticalLayoutGroup) | ||
|  |                     return; | ||
|  | 
 | ||
|  |                 if (obj is Graphic) | ||
|  |                 { | ||
|  |                     var m = (Graphic)obj; | ||
|  |                     dependencies.Add(m.material); | ||
|  |                     dependencies.Add(m.defaultMaterial); | ||
|  |                     dependencies.Add(m.mainTexture); | ||
|  | 
 | ||
|  |                     if (type == typeof(Text)) | ||
|  |                     { | ||
|  |                         var text = (Text)obj; | ||
|  |                         dependencies.Add(text.font); | ||
|  |                     } | ||
|  |                     else if (type == typeof(Image)) | ||
|  |                     { | ||
|  |                         var img = (Image)obj; | ||
|  |                         dependencies.Add(img.sprite); | ||
|  |                     } | ||
|  |                     return; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (type == typeof(Mesh)) | ||
|  |                 { | ||
|  |                     if (UnityEditor.AssetDatabase.Contains(obj)) | ||
|  |                         dependencies.Add(obj); | ||
|  |                     return; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (type == typeof(Material)) | ||
|  |                 { | ||
|  |                     dependencies.Add(((Material)obj).shader); | ||
|  |                     return; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (type == typeof(MeshFilter)) | ||
|  |                 { | ||
|  |                     dependencies.Add(((MeshFilter)obj).sharedMesh); | ||
|  |                     return; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (type == typeof(MeshCollider)) | ||
|  |                 { | ||
|  |                     var mc = (MeshCollider)obj; | ||
|  |                     dependencies.Add(mc.sharedMesh); | ||
|  |                     dependencies.Add(mc.sharedMaterial); | ||
|  |                     dependencies.Add(mc.attachedRigidbody); | ||
|  |                     return; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (type == typeof(Camera)) | ||
|  |                 { | ||
|  |                     var c = (Camera)obj; | ||
|  |                     dependencies.Add(c.targetTexture); | ||
|  |                     return; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (type == typeof(SkinnedMeshRenderer)) | ||
|  |                     dependencies.Add(((SkinnedMeshRenderer)obj).sharedMesh); // Don't return. Let this fall through to the if(obj is renderer) call. | ||
|  |                 else if (type == typeof(SpriteRenderer)) | ||
|  |                     dependencies.Add(((SpriteRenderer)obj).sprite); // Don't return. Let this fall through to the if(obj is renderer) call. | ||
|  |                 else if (type == typeof(ParticleSystemRenderer)) | ||
|  |                     dependencies.Add(((ParticleSystemRenderer)obj).mesh); // Don't return. Let this fall through to the if(obj is renderer) call. | ||
|  | 
 | ||
|  |                 if (obj is Renderer) | ||
|  |                 { | ||
|  |                     dependencies.UnionWith(((Renderer)obj).sharedMaterials); | ||
|  |                     return; | ||
|  |                 } | ||
|  |             } | ||
|  |             catch { } | ||
|  | 
 | ||
|  |             var so = new UnityEditor.SerializedObject(obj); | ||
|  |             if (so == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             var property = so.GetIterator(); | ||
|  |             if (property == null) | ||
|  |                 return; | ||
|  | 
 | ||
|  |             // Iterate through each of this object's properties. | ||
|  |             while (property.NextVisible(true)) | ||
|  |             { | ||
|  |                 try | ||
|  |                 { | ||
|  |                     // If it's an array which contains UnityEngine.Objects, add them as dependencies. | ||
|  |                     if (property.isArray) | ||
|  |                     { | ||
|  |                         for (int i = 0; i < property.arraySize; i++) | ||
|  |                         { | ||
|  |                             var element = property.GetArrayElementAtIndex(i); | ||
|  | 
 | ||
|  |                             // If the array contains UnityEngine.Object types, add them to the dependencies. | ||
|  |                             if (element.propertyType == UnityEditor.SerializedPropertyType.ObjectReference) | ||
|  |                             { | ||
|  |                                 var elementValue = element.objectReferenceValue; | ||
|  |                                 var elementType = elementValue.GetType(); | ||
|  | 
 | ||
|  |                                 // If it's a GameObject, use CollectDependencies so that Components are also added. | ||
|  |                                 if (elementType == typeof(GameObject)) | ||
|  |                                     CollectDependencies(elementValue, dependencies, depth - 1); | ||
|  |                                 else | ||
|  |                                     CollectDependenciesFromFields(elementValue, dependencies, depth - 1); | ||
|  |                             } | ||
|  |                             // Otherwise this array does not contain UnityEngine.Object types, so we should stop. | ||
|  |                             else | ||
|  |                                 break; | ||
|  |                         } | ||
|  |                     } | ||
|  |                     // Else if it's a normal UnityEngine.Object field, add it. | ||
|  |                     else if (property.propertyType == UnityEditor.SerializedPropertyType.ObjectReference) | ||
|  |                     { | ||
|  |                         var propertyValue = property.objectReferenceValue; | ||
|  |                         if (propertyValue == null) | ||
|  |                             break; | ||
|  | 
 | ||
|  |                         // If it's a GameObject, use CollectDependencies so that Components are also added. | ||
|  |                         if (propertyValue.GetType() == typeof(GameObject)) | ||
|  |                             CollectDependencies(propertyValue, dependencies, depth - 1); | ||
|  |                         else | ||
|  |                             CollectDependenciesFromFields(propertyValue, dependencies, depth - 1); | ||
|  |                     } | ||
|  |                 } | ||
|  |                 catch { } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         // Called in the Editor when this Component is added. | ||
|  |         private void Reset() | ||
|  |         { | ||
|  |             // Ensure that Component can only be added by going to Assets > Easy Save 3 > Add Manager to Scene. | ||
|  |             if (gameObject.name != "Easy Save 3 Manager") | ||
|  |             { | ||
|  |                 UnityEditor.EditorUtility.DisplayDialog("Cannot add ES3ReferenceMgr directly", "Please go to 'Assets > Easy Save 3 > Add Manager to Scene' to add an Easy Save 3 Manager to your scene.", "Ok"); | ||
|  |                 DestroyImmediate(this); | ||
|  |             } | ||
|  |         } | ||
|  | #endif | ||
|  | 
 | ||
|  |         internal static bool CanBeSaved(UnityEngine.Object obj) | ||
|  |         { | ||
|  | #if UNITY_EDITOR | ||
|  |             if (obj == null) | ||
|  |                 return true; | ||
|  | 
 | ||
|  |             foreach (var flag in invalidHideFlags) | ||
|  |                 if ((obj.hideFlags & flag) != 0 && obj.hideFlags != HideFlags.HideInHierarchy && obj.hideFlags != HideFlags.HideInInspector && obj.hideFlags != HideFlags.NotEditable) | ||
|  |                     if (!(obj is Mesh || obj is Material)) | ||
|  |                         return false; | ||
|  | 
 | ||
|  |             // Exclude the Easy Save 3 Manager, and all components attached to it. | ||
|  |             if (obj.name == "Easy Save 3 Manager") | ||
|  |                 return false; | ||
|  | #endif | ||
|  |             return true; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     [System.Serializable] | ||
|  |     public class ES3IdRefDictionary : ES3SerializableDictionary<long, UnityEngine.Object> | ||
|  |     { | ||
|  |         protected override bool KeysAreEqual(long a, long b) | ||
|  |         { | ||
|  |             return a == b; | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override bool ValuesAreEqual(UnityEngine.Object a, UnityEngine.Object b) | ||
|  |         { | ||
|  |             return a == b; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] | ||
|  |     [System.Serializable] | ||
|  |     public class ES3RefIdDictionary : ES3SerializableDictionary<UnityEngine.Object, long> | ||
|  |     { | ||
|  |         protected override bool KeysAreEqual(UnityEngine.Object a, UnityEngine.Object b) | ||
|  |         { | ||
|  |             return a == b; | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override bool ValuesAreEqual(long a, long b) | ||
|  |         { | ||
|  |             return a == b; | ||
|  |         } | ||
|  |     } | ||
|  | } |