using GameKit.Dependencies.Utilities; using System; using System.Collections.Generic; using UnityEngine.SceneManagement; namespace FishNet.Managing.Scened { /// /// Extensions for SceneLookupData. /// internal static class SceneLookupDataExtensions { /// /// Returns Names from SceneLookupData. /// /// /// public static string[] GetNames(this SceneLookupData[] datas) { string[] names = new string[datas.Length]; for (int i = 0; i < datas.Length; i++) names[i] = datas[i].Name; return names; } /// /// Returns Names from SceneLookupData. /// /// /// public static string[] GetNamesOnly(this SceneLookupData[] datas) { string[] names = new string[datas.Length]; for (int i = 0; i < datas.Length; i++) names[i] = datas[i].NameOnly; return names; } } /// /// Data container for looking up, loading, or unloading a scene. /// public class SceneLookupData : IEquatable { /// /// Handle of the scene. If value is 0, then handle is not used. /// public int Handle; /// /// Name of the scene. /// public string Name = string.Empty; /// /// Returns the scene name without a directory path should one exist. /// public string NameOnly { get { if (string.IsNullOrEmpty(Name)) return string.Empty; string name = System.IO.Path.GetFileName(Name); return RemoveUnityExtension(name); } } /// /// Returns if this data is valid for use. /// Being valid does not mean that the scene exist, rather that there is enough data to try and lookup a scene. /// public bool IsValid => (Name != string.Empty || Handle != 0); #region Const /// /// String to display when scene data is invalid. /// private const string INVALID_SCENE = "One or more scene information entries contain invalid data and have been skipped."; #endregion /// /// /// public SceneLookupData() { } /// /// /// /// Scene to generate from. public SceneLookupData(Scene scene) { Handle = scene.handle; Name = scene.name; } /// /// /// /// Scene name to generate from. public SceneLookupData(string name) { Name = name; } /// /// /// /// Scene handle to generate from. public SceneLookupData(int handle) { Handle = handle; } /// /// /// /// Scene handle to generate from. /// Name to generate from if handle is 0. public SceneLookupData(int handle, string name) { Handle = handle; Name = name; } #region Comparers. public static bool operator ==(SceneLookupData sldA, SceneLookupData sldB) { //One is null while the other is not. if ((sldA is null) != (sldB is null)) return false; /*If here both are either null or have value. */ if (!(sldA is null)) return sldA.Equals(sldB); else if (!(sldB is null)) return sldB.Equals(sldA); //Fall through indicates both are null. return true; } public static bool operator !=(SceneLookupData sldA, SceneLookupData sldB) { //One is null while the other is not. if ((sldA is null) != (sldB is null)) return true; /*If here both are either null or have value. */ if (!(sldA is null)) return !sldA.Equals(sldB); else if (!(sldB is null)) return !sldB.Equals(sldA); //Fall through indicates both are null. return true; } public bool Equals(SceneLookupData sld) { //Comparing instanced against null. if (sld is null) return false; //True if both handles are empty. bool bothHandlesEmpty = ( (this.Handle == 0) && (sld.Handle == 0) ); //If both have handles and they match. if (!bothHandlesEmpty && sld.Handle == this.Handle) return true; //If neither have handles and name matches. else if (bothHandlesEmpty && sld.Name == this.Name) return true; //Fall through. return false; } public override int GetHashCode() { int hashCode = 2053068273; hashCode = hashCode * -1521134295 + Handle.GetHashCode(); hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Name); return hashCode; } public override bool Equals(object obj) { return base.Equals(obj); } public override string ToString() { return $"Name {Name}, Handle {Handle}"; //return base.ToString(); } #endregion #region CreateData. /// /// Returns a new SceneLookupData. /// /// Scene to create from. /// public static SceneLookupData CreateData(Scene scene) => new(scene); /// /// Returns a new SceneLookupData. /// /// Scene name to create from. /// public static SceneLookupData CreateData(string name) => new(name); /// /// Returns a new SceneLookupData. /// /// Scene handle to create from. /// public static SceneLookupData CreateData(int handle) => new(handle); /// /// Returns a SceneLookupData collection. /// /// Scenes to create from. /// public static SceneLookupData[] CreateData(List scenes) => CreateData(scenes.ToArray()); /// /// Returns a SceneLookupData collection. /// /// Scene names to create from. /// public static SceneLookupData[] CreateData(List names) => CreateData(names.ToArray()); /// /// Returns a SceneLookupData collection. /// /// Scene handles to create from. /// public static SceneLookupData[] CreateData(List handles) => CreateData(handles.ToArray()); /// /// Returns a SceneLookupData collection. /// /// Scenes to create from. /// public static SceneLookupData[] CreateData(Scene[] scenes) { bool invalidFound = false; List result = new(); foreach (Scene item in scenes) { if (!item.IsValid()) { invalidFound = true; continue; } result.Add(CreateData(item)); } if (invalidFound) NetworkManagerExtensions.LogWarning(INVALID_SCENE); return result.ToArray(); } /// /// Returns a SceneLookupData collection. /// /// Scene names to create from. /// public static SceneLookupData[] CreateData(string[] names) { SceneLookupData[] result = new SceneLookupData[names.Length]; for (int i = 0; i < result.Length; i++) result[i] = new(names[i]); return ValidateData(result); } /// /// Validates SceneLookupdatas and returns only valid entries. /// public static SceneLookupData[] ValidateData(SceneLookupData data) => ValidateData(new SceneLookupData[] { data }); /// /// Validates SceneLookupdatas and returns only valid entries. /// /// Datas to validate. public static SceneLookupData[] ValidateData(SceneLookupData[] datas) { bool invalidFound = false; List result = CollectionCaches.RetrieveList(); foreach (SceneLookupData item in datas) { if (item.IsValid) { int failingIndex = -1; //Scene name or handle is set, make sure it's not duplicated in datas. for (int i = 0; i < result.Count; i++) { bool nameMatches = (result[i].Name == item.Name); bool handleMatches = (result[i].Handle == item.Handle); //Handle is the same (could be 0 handle). if (handleMatches) { //If handle matches and not default then the same scene was added multiple times. if (item.Handle != 0) failingIndex = i; } //Name is the same. else if (nameMatches) { //If handle and name matches then also fail. if (handleMatches) failingIndex = i; } } if (failingIndex != -1) NetworkManagerExtensions.LogWarning($"Data {item.ToString()} matches {result[failingIndex].ToString()} and has been removed from datas."); else result.Add(item); } else { invalidFound = true; } } SceneLookupData[] returnedValue; if (invalidFound) { NetworkManagerExtensions.LogWarning(INVALID_SCENE); returnedValue = result.ToArray(); } else { returnedValue = datas; } CollectionCaches.Store(result); return returnedValue; } /// /// Returns a SceneLookupData collection. /// /// Scene handles to create from. /// public static SceneLookupData[] CreateData(int[] handles) { bool invalidFound = false; List result = new(); foreach (int item in handles) { if (item == 0) { invalidFound = true; continue; } result.Add(CreateData(item)); } if (invalidFound) NetworkManagerExtensions.LogWarning(INVALID_SCENE); return result.ToArray(); } #endregion /// /// Removes .Unity from text. /// private static string RemoveUnityExtension(string text) { string extension = ".unity"; int extIndex = text.ToLower().IndexOf(extension); if (extIndex != -1 && (text.Length - extIndex) == extension.Length) text = text.Substring(0, extIndex); return text; } /// /// Returns the first scene found using Handle or Name, preferring Handle. /// /// /// True if scene was found by handle. Handle is always checked first. /// True to warn if duplicates are found. public Scene GetScene(out bool foundByHandle, bool warnIfDuplicates = true) { foundByHandle = false; if (Handle == 0 && string.IsNullOrEmpty(NameOnly)) { NetworkManagerExtensions.LogWarning("Scene handle and name is unset; scene cannot be returned."); return default; } Scene result = default; //Lookup my handle. if (Handle != 0) { result = SceneManager.GetScene(Handle); if (result.handle != 0) foundByHandle = true; } //If couldnt find handle try by string. if (!foundByHandle) result = SceneManager.GetScene(NameOnly, null, warnIfDuplicates); return result; } } }