diff --git a/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs b/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs index 6e3a4554..a84ec970 100644 --- a/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs +++ b/Assets/FishNet/Runtime/Managing/Scened/SceneLookupData.cs @@ -1,4 +1,5 @@ -using GameKit.Dependencies.Utilities; +using FishNet.Utility; +using GameKit.Dependencies.Utilities; using System; using System.Collections.Generic; using UnityEngine.SceneManagement; @@ -24,7 +25,6 @@ public static string[] GetNames(this SceneLookupData[] datas) return names; } - /// /// Returns Names from SceneLookupData. /// @@ -46,13 +46,33 @@ public static string[] GetNamesOnly(this SceneLookupData[] datas) public class SceneLookupData : IEquatable { /// - /// Handle of the scene. If value is 0, then handle is not used. + /// Raw handle of the scene. If value is 0, then handle is not used. /// - public int Handle; + private ulong _rawHandle; + + /// + /// Legacy 32-bit handle view. + /// + public int Handle + { + get => unchecked((int)_rawHandle); + set => _rawHandle = unchecked((uint)value); + } + + /// + /// Raw scene handle value. + /// + public ulong RawHandle + { + get => _rawHandle; + set => _rawHandle = value; + } + /// /// Name of the scene. /// public string Name = string.Empty; + /// /// Returns the scene name without a directory path should one exist. /// @@ -62,16 +82,17 @@ public string NameOnly { 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; + public bool IsValid => Name != string.Empty || RawHandle != 0; #region Const /// @@ -89,7 +110,7 @@ public SceneLookupData() { } /// Scene to generate from. public SceneLookupData(Scene scene) { - Handle = scene.handle; + RawHandle = UnityCompatibility.GetSceneHandleRaw(scene); Name = scene.name; } @@ -109,6 +130,14 @@ public SceneLookupData(int handle) Handle = handle; } + /// + /// + /// Raw scene handle to generate from. + public SceneLookupData(ulong handle) + { + RawHandle = handle; + } + /// /// /// Scene handle to generate from. @@ -119,6 +148,16 @@ public SceneLookupData(int handle, string name) Name = name; } + /// + /// + /// Raw scene handle to generate from. + /// Name to generate from if handle is 0. + public SceneLookupData(ulong handle, string name) + { + RawHandle = handle; + Name = name; + } + #region Comparers. public static bool operator ==(SceneLookupData sldA, SceneLookupData sldB) { @@ -159,10 +198,10 @@ public bool Equals(SceneLookupData sld) return false; // True if both handles are empty. - bool bothHandlesEmpty = Handle == 0 && sld.Handle == 0; + bool bothHandlesEmpty = RawHandle == 0 && sld.RawHandle == 0; // If both have handles and they match. - if (!bothHandlesEmpty && sld.Handle == Handle) + if (!bothHandlesEmpty && sld.RawHandle == RawHandle) return true; // If neither have handles and name matches. else if (bothHandlesEmpty && sld.Name == Name) @@ -175,7 +214,7 @@ public bool Equals(SceneLookupData sld) public override int GetHashCode() { int hashCode = 2053068273; - hashCode = hashCode * -1521134295 + Handle.GetHashCode(); + hashCode = hashCode * -1521134295 + RawHandle.GetHashCode(); hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Name); return hashCode; } @@ -187,7 +226,7 @@ public override bool Equals(object obj) public override string ToString() { - return $"Name {Name}, Handle {Handle}"; + return $"Name {Name}, Handle {RawHandle}"; // return base.ToString(); } #endregion @@ -214,6 +253,13 @@ public override string ToString() /// public static SceneLookupData CreateData(int handle) => new(handle); + /// + /// Returns a new SceneLookupData. + /// + /// Raw scene handle to create from. + /// + public static SceneLookupData CreateData(ulong handle) => new(handle); + /// /// Returns a SceneLookupData collection. /// @@ -235,6 +281,13 @@ public override string ToString() /// public static SceneLookupData[] CreateData(List handles) => CreateData(handles.ToArray()); + /// + /// Returns a SceneLookupData collection. + /// + /// Raw scene handles to create from. + /// + public static SceneLookupData[] CreateData(List handles) => CreateData(handles.ToArray()); + /// /// Returns a SceneLookupData collection. /// @@ -297,12 +350,12 @@ public static SceneLookupData[] ValidateData(SceneLookupData[] datas) for (int i = 0; i < result.Count; i++) { bool nameMatches = result[i].Name == item.Name; - bool handleMatches = result[i].Handle == item.Handle; + bool handleMatches = result[i].RawHandle == item.RawHandle; // 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) + if (item.RawHandle != 0) failingIndex = i; } // Name is the same. @@ -365,6 +418,32 @@ public static SceneLookupData[] CreateData(int[] handles) return result.ToArray(); } + + /// + /// Returns a SceneLookupData collection. + /// + /// Raw scene handles to create from. + /// + public static SceneLookupData[] CreateData(ulong[] handles) + { + bool invalidFound = false; + List result = new(); + foreach (ulong item in handles) + { + if (item == 0) + { + invalidFound = true; + continue; + } + + result.Add(CreateData(item)); + } + + if (invalidFound) + NetworkManagerExtensions.LogWarning(INVALID_SCENE); + + return result.ToArray(); + } #endregion /// @@ -390,7 +469,7 @@ public Scene GetScene(out bool foundByHandle, bool warnIfDuplicates = true) { foundByHandle = false; - if (Handle == 0 && string.IsNullOrEmpty(NameOnly)) + if (RawHandle == 0 && string.IsNullOrEmpty(NameOnly)) { NetworkManagerExtensions.LogWarning("Scene handle and name is unset; scene cannot be returned."); return default; @@ -398,11 +477,11 @@ public Scene GetScene(out bool foundByHandle, bool warnIfDuplicates = true) Scene result = default; - // Lookup my handle. - if (Handle != 0) + // Lookup by handle first. + if (RawHandle != 0) { - result = SceneManager.GetScene(Handle); - if (result.handle != 0) + result = GetSceneByRawHandle(RawHandle); + if (UnityCompatibility.HasValidSceneHandle(result)) foundByHandle = true; } @@ -412,5 +491,21 @@ public Scene GetScene(out bool foundByHandle, bool warnIfDuplicates = true) return result; } + + /// + /// Returns a currently loaded scene by raw scene handle. + /// + private static Scene GetSceneByRawHandle(ulong rawHandle) + { + int count = UnityEngine.SceneManagement.SceneManager.sceneCount; + for (int i = 0; i < count; i++) + { + Scene scene = UnityEngine.SceneManagement.SceneManager.GetSceneAt(i); + if (scene.IsValid() && UnityCompatibility.GetSceneHandleRaw(scene) == rawHandle) + return scene; + } + + return default; + } } } \ No newline at end of file diff --git a/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs b/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs index 6bae7b5c..d53b8378 100644 --- a/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs +++ b/Assets/FishNet/Runtime/Managing/Scened/SceneManager.cs @@ -5,6 +5,7 @@ using FishNet.Object; using FishNet.Serializing.Helping; using FishNet.Transporting; +using FishNet.Utility; using GameKit.Dependencies.Utilities; using GameKit.Dependencies.Utilities.Types; using System; @@ -34,11 +35,11 @@ public class PendingClientSceneLoads /// /// Scene handles which have clients that have not yet confirmed the loading status. /// - private Dictionary> _scenesWithPendingLoads = new(); + private Dictionary> _scenesWithPendingLoads = new(); /// /// Clients with pending loads, and each scene handle pending. /// - private Dictionary> _clientsWithPendingLoads = new(); + private Dictionary> _clientsWithPendingLoads = new(); /// /// Clients which have been sent the initial scene load with no scenes specified. /// @@ -49,11 +50,11 @@ public class PendingClientSceneLoads /// /// Adds a pending load for a client. /// - public void AddClientToScene(NetworkConnection connection, int sceneHandle) + public void AddClientToScene(NetworkConnection connection, ulong sceneHandle) { /* The client has 1 or more pending loads already. See * if the specified scene is already pending. */ - if (_clientsWithPendingLoads.TryGetValueIL2CPP(connection, out List sceneList)) + if (_clientsWithPendingLoads.TryGetValueIL2CPP(connection, out List sceneList)) { //Scene is already marked for the connection. if (sceneList.Contains(sceneHandle)) @@ -81,14 +82,14 @@ public void AddClientToScene(NetworkConnection connection, int sceneHandle) /// Removes a client from all pending loads. /// Scene handles which no longer have clients pending loads. - internal List RemoveClientFromAllScenes(NetworkConnection conn) + internal List RemoveClientFromAllScenes(NetworkConnection conn) { - List emptyScenes = new(); + List emptyScenes = new(); - if (!_clientsWithPendingLoads.TryGetValueIL2CPP(conn, out List sceneList)) + if (!_clientsWithPendingLoads.TryGetValueIL2CPP(conn, out List sceneList)) return emptyScenes; - foreach (int sceneHandle in sceneList) + foreach (ulong sceneHandle in sceneList) { /* If the scene is in the clients list then it should * be in scenesWithPendingLoads. This is a safety check but @@ -113,7 +114,7 @@ internal List RemoveClientFromAllScenes(NetworkConnection conn) /// Becomes true if the scene which the connection is being removed from has no more pending loads. /// True if the client had the specified scene as pending. - internal bool RemoveClientFromScene(NetworkConnection conn, int sceneHandle, out bool sceneHasNoPendingLoads) + internal bool RemoveClientFromScene(NetworkConnection conn, ulong sceneHandle, out bool sceneHasNoPendingLoads) { // The scene has does not have any pending clients. if (!_scenesWithPendingLoads.TryGetValueIL2CPP(sceneHandle, out HashSet connectionsLoadingScene)) @@ -136,7 +137,7 @@ internal bool RemoveClientFromScene(NetworkConnection conn, int sceneHandle, out /* If client does not have any pending loads then * there is nothing to remove, which means the requested * scene still has clients in it. */ - if (!_clientsWithPendingLoads.TryGetValueIL2CPP(conn, out List sceneList)) + if (!_clientsWithPendingLoads.TryGetValueIL2CPP(conn, out List sceneList)) { sceneHasNoPendingLoads = false; return false; @@ -176,7 +177,7 @@ internal bool RemoveClientFromScene(NetworkConnection conn, int sceneHandle, out /// /// Returns if a scene has any number of clients still pending load. /// - internal bool HasSceneAnyPendingLoads(int sceneHandle) => _scenesWithPendingLoads.TryGetValueIL2CPP(sceneHandle, out _); + internal bool HasSceneAnyPendingLoads(ulong sceneHandle) => _scenesWithPendingLoads.TryGetValueIL2CPP(sceneHandle, out _); /// /// Clears all information. @@ -576,7 +577,7 @@ void SendEmptyBroadcast() }; foreach (SceneLookupData lookupData in sceneLookupData) - _pendingClientSceneLoads.AddClientToScene(connection, lookupData.Handle); + _pendingClientSceneLoads.AddClientToScene(connection, lookupData.RawHandle); connection.Broadcast(msg, requireAuthenticated: true); } @@ -635,7 +636,7 @@ private void ClientDisconnected(NetworkConnection conn) /* True if SceneConnections has no more connections * in its scene, as well if the scene checked is in * has no other clients pending load confirmation. */ - bool isSceneNowEmpty = removed && hs.Count == 0 && !_pendingClientSceneLoads.HasSceneAnyPendingLoads(scene.handle); + bool isSceneNowEmpty = removed && hs.Count == 0 && !_pendingClientSceneLoads.HasSceneAnyPendingLoads(UnityCompatibility.GetSceneHandleRaw(scene)); //True if not a global scene and not in scenes to be manually unloaded. bool notGlobalAndNotManualUnload = !IsGlobalScene(scene) && !_manualUnloadScenes.Contains(scene); @@ -691,9 +692,9 @@ private void OnClientLoadedScenes(NetworkConnection conn, ClientScenesLoadedBroa foreach (SceneLookupData item in msg.SceneLookupDatas) { //Make sure the sceneId is pending. - if (!_pendingClientSceneLoads.RemoveClientFromScene(conn, item.Handle, out _)) + if (!_pendingClientSceneLoads.RemoveClientFromScene(conn, item.RawHandle, out _)) { - KickClient($"Client {conn.ToString()} sent a scene load response for handle [{item.Handle}], but client was not sent a load for this handle."); + KickClient($"Client {conn.ToString()} sent a scene load response for handle [{item.RawHandle}], but client was not sent a load for this handle."); break; } @@ -1058,7 +1059,7 @@ private IEnumerator __LoadScenes() /* Scene queue data scenes. * All scenes in the scene queue data whether they will be loaded or not. */ List requestedLoadSceneNames = new(); - List requestedLoadSceneHandles = new(); + List requestedLoadSceneHandles = new(); /* Make a null filled array. This will be populated * using loaded scenes, or already loaded (eg cannot be loaded) scenes. */ @@ -1081,7 +1082,7 @@ private IEnumerator __LoadScenes() { requestedLoadSceneNames.Add(s.name); if (byHandle) - requestedLoadSceneHandles.Add(s.handle); + requestedLoadSceneHandles.Add(UnityCompatibility.GetSceneHandleRaw(s)); } if (CanLoadScene(data, lookupData)) @@ -1124,7 +1125,7 @@ private IEnumerator __LoadScenes() } // Connection scenes handles prior to ConnectionScenes being modified. - List connectionScenesHandlesCached = new(); + List connectionScenesHandlesCached = new(); // If replacing scenes. if (replaceScenes != ReplaceOption.None) { @@ -1137,7 +1138,7 @@ private IEnumerator __LoadScenes() { Scene[] sceneConnectionsKeys = SceneConnections.Keys.ToArray(); for (int i = 0; i < sceneConnectionsKeys.Length; i++) - connectionScenesHandlesCached.Add(sceneConnectionsKeys[i].handle); + connectionScenesHandlesCached.Add(UnityCompatibility.GetSceneHandleRaw(sceneConnectionsKeys[i])); // If global then remove all connections from all scenes. if (data.ScopeType == SceneScopeType.Global) @@ -1155,7 +1156,7 @@ private IEnumerator __LoadScenes() else { foreach (Scene s in NetworkManager.ClientManager.Connection.Scenes) - connectionScenesHandlesCached.Add(s.handle); + connectionScenesHandlesCached.Add(UnityCompatibility.GetSceneHandleRaw(s)); } } @@ -1181,7 +1182,7 @@ private IEnumerator __LoadScenes() if (requestedLoadSceneNames.Contains(s.name)) continue; // Same as above but using handles. - if (requestedLoadSceneHandles.Contains(s.handle)) + if (requestedLoadSceneHandles.Contains(UnityCompatibility.GetSceneHandleRaw(s))) continue; /* Cannot unload global scenes. If * replace scenes was used for a global @@ -1193,7 +1194,7 @@ private IEnumerator __LoadScenes() if (_manualUnloadScenes.Contains(s)) continue; - bool inScenesCache = connectionScenesHandlesCached.Contains(s.handle); + bool inScenesCache = connectionScenesHandlesCached.Contains(UnityCompatibility.GetSceneHandleRaw(s)); HashSet conns; bool inScenesCurrent = SceneConnections.ContainsKey(s); // If was in scenes previously but isnt now then no connections reside in the scene. @@ -1328,7 +1329,7 @@ void InvokePercentageChange(int index, float maximumWorth, float currentScenePer /* If the first lookup data contains a handle and the scene * is found for that handle then use that as the moved to scene. * Nobs always move to the first specified scene. */ - if (sceneLoadData.SceneLookupDatas[0].Handle != 0 && !string.IsNullOrEmpty(firstScene.name)) + if (sceneLoadData.SceneLookupDatas[0].RawHandle != 0 && !string.IsNullOrEmpty(firstScene.name)) { firstValidScene = firstScene; } @@ -1503,7 +1504,7 @@ void AddClientPendingLoads(NetworkConnection[] lConns) { SceneLookupData[] slds = msg.QueueData.SceneLoadData.SceneLookupDatas; foreach (SceneLookupData sld in slds) - AddPendingLoad(lConns, sld.Handle); + AddPendingLoad(lConns, sld.RawHandle); } } /* If running as client then send a message @@ -2246,12 +2247,22 @@ public static Scene GetScene(string sceneName, NetworkManager nm = null, bool wa /// /// public static Scene GetScene(int sceneHandle) + { + return GetScene(unchecked((uint)sceneHandle)); + } + + /// + /// Returns a scene by raw handle. + /// + /// + /// + public static Scene GetScene(ulong sceneHandle) { int count = UnitySceneManager.sceneCount; for (int i = 0; i < count; i++) { Scene s = UnitySceneManager.GetSceneAt(i); - if (s.handle == sceneHandle) + if (UnityCompatibility.GetSceneHandleRaw(s) == sceneHandle) return s; } @@ -2354,7 +2365,7 @@ private void RemoveOccupiedScenes(List scenes) { Scene s = scenes[i]; - if (SceneConnections.TryGetValueIL2CPP(s, out _) || _pendingClientSceneLoads.HasSceneAnyPendingLoads(s.handle)) + if (SceneConnections.TryGetValueIL2CPP(s, out _) || _pendingClientSceneLoads.HasSceneAnyPendingLoads(UnityCompatibility.GetSceneHandleRaw(s))) { scenes.RemoveAt(i); i--; @@ -2365,7 +2376,7 @@ private void RemoveOccupiedScenes(List scenes) /// /// Adds a pending load for a connection. /// - private void AddPendingLoad(NetworkConnection[] conns, int sceneHandle) + private void AddPendingLoad(NetworkConnection[] conns, ulong sceneHandle) { foreach (NetworkConnection c in conns) { diff --git a/Assets/FishNet/Runtime/Managing/Scened/UnloadedScene.cs b/Assets/FishNet/Runtime/Managing/Scened/UnloadedScene.cs index 5f89fb49..2fcb0dd4 100644 --- a/Assets/FishNet/Runtime/Managing/Scened/UnloadedScene.cs +++ b/Assets/FishNet/Runtime/Managing/Scened/UnloadedScene.cs @@ -1,19 +1,26 @@ -using UnityEngine.SceneManagement; +using FishNet.Utility; +using UnityEngine.SceneManagement; namespace FishNet.Managing.Scened { public struct UnloadedScene { public readonly string Name; - public readonly int Handle; + public readonly ulong Handle; public UnloadedScene(Scene s) { Name = s.name; - Handle = s.handle; + Handle = UnityCompatibility.GetSceneHandleRaw(s); } public UnloadedScene(string name, int handle) + { + Name = name; + Handle = unchecked((uint)handle); + } + + public UnloadedScene(string name, ulong handle) { Name = name; Handle = handle; @@ -30,7 +37,7 @@ public Scene GetScene() for (int i = 0; i < loadedScenes; i++) { Scene s = UnityEngine.SceneManagement.SceneManager.GetSceneAt(i); - if (s.IsValid() && s.handle == Handle) + if (s.IsValid() && UnityCompatibility.GetSceneHandleRaw(s) == Handle) return s; } diff --git a/Assets/FishNet/Runtime/Observing/NetworkObserver.cs b/Assets/FishNet/Runtime/Observing/NetworkObserver.cs index fd0fb35d..c9a05a48 100644 --- a/Assets/FishNet/Runtime/Observing/NetworkObserver.cs +++ b/Assets/FishNet/Runtime/Observing/NetworkObserver.cs @@ -155,10 +155,12 @@ internal void Deinitialize(bool destroyed) foreach (ObserverCondition item in _observerConditions) { item.Deinitialize(destroyed); - /* Use GetInstanceId to ensure the object is actually - * instantiated. If Id is negative, then it's instantiated - * and not a reference to the original object. */ - if (destroyed && item.GetInstanceID() < 0) + + /* Conditions are replaced with instantiated copies during Initialize. + * Destroy the runtime copies when this observer is being destroyed. + * Do not rely on InstanceID sign because InstanceID is obsolete in Unity 6.5+. + */ + if (destroyed) Destroy(item); } @@ -309,10 +311,10 @@ internal ObserverStateChange RebuildObservers(NetworkConnection connection, bool if (!_initialized) { string goName = gameObject == null ? "Empty" : gameObject.name; - + NetworkManager nm = _networkObject == null ? null : _networkObject.NetworkManager; nm.LogError($"{GetType().Name} is not initialized on NetworkObject [{goName}]. RebuildObservers should not be called. If you are able to reproduce this error consistently please report this issue."); - + return ObserverStateChange.Unchanged; } diff --git a/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs b/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs index f294ae66..7ab92cbe 100644 --- a/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs +++ b/Assets/FishNet/Runtime/Serializing/Helping/Comparers.cs @@ -1,4 +1,5 @@ -using System; +using FishNet.Utility; +using System; using System.Collections.Generic; using UnityEngine.SceneManagement; @@ -10,6 +11,7 @@ public class PublicPropertyComparer /// Compare if T is default. /// public static Func IsDefault { get; set; } + /// /// Compare if T is the same as T2. /// @@ -48,8 +50,11 @@ public bool Equals(Scene a, Scene b) if (!a.IsValid() || !b.IsValid()) return false; - if (a.handle != 0 || b.handle != 0) - return a.handle == b.handle; + ulong aHandle = UnityCompatibility.GetSceneHandleRaw(a); + ulong bHandle = UnityCompatibility.GetSceneHandleRaw(b); + + if (aHandle != 0 || bHandle != 0) + return aHandle == bHandle; return a.name == b.name; } diff --git a/Assets/FishNet/Runtime/Serializing/SceneComparer.cs b/Assets/FishNet/Runtime/Serializing/SceneComparer.cs index d4a4e076..d09b802f 100644 --- a/Assets/FishNet/Runtime/Serializing/SceneComparer.cs +++ b/Assets/FishNet/Runtime/Serializing/SceneComparer.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using FishNet.Utility; +using System.Collections.Generic; using UnityEngine.SceneManagement; namespace FishNet.Serializing.Helping @@ -7,12 +8,12 @@ internal sealed class SceneHandleEqualityComparer : EqualityComparer { public override bool Equals(Scene a, Scene b) { - return a.handle == b.handle; + return UnityCompatibility.GetSceneHandleRaw(a) == UnityCompatibility.GetSceneHandleRaw(b); } public override int GetHashCode(Scene obj) { - return obj.handle; + return UnityCompatibility.GetSceneHandleRaw(obj).GetHashCode(); } } } \ No newline at end of file diff --git a/Assets/FishNet/Runtime/UnityCompatibility.cs b/Assets/FishNet/Runtime/UnityCompatibility.cs new file mode 100644 index 00000000..81f26979 --- /dev/null +++ b/Assets/FishNet/Runtime/UnityCompatibility.cs @@ -0,0 +1,54 @@ +using UnityEngine.SceneManagement; + +namespace FishNet.Utility +{ + /// + /// Compatibility helpers for Unity API changes across supported Unity versions. + /// + public static class UnityCompatibility + { + /// + /// Returns a runtime object identifier using Unity's current object identity API. + /// + public static ulong GetObjectRuntimeId(UnityEngine.Object obj) + { +#if UNITY_6000_5_OR_NEWER + return obj.GetEntityId().GetRawData(); +#else + return unchecked((uint)obj.GetInstanceID()); +#endif + } + + /// + /// Returns a raw scene handle value using Unity's current SceneHandle API. + /// + public static ulong GetSceneHandleRaw(Scene scene) + { +#if UNITY_6000_5_OR_NEWER + return scene.handle.GetRawData(); +#else + return unchecked((uint)(int)scene.handle); +#endif + } + + /// + /// Creates a SceneHandle from raw scene handle data. + /// + public static SceneHandle SceneHandleFromRaw(ulong rawHandle) + { +#if UNITY_6000_5_OR_NEWER + return SceneHandle.FromRawData(rawHandle); +#else + return (SceneHandle)(int)rawHandle; +#endif + } + + /// + /// Returns true if the scene has a non-zero raw handle. + /// + public static bool HasValidSceneHandle(Scene scene) + { + return scene.IsValid() && GetSceneHandleRaw(scene) != 0; + } + } +} \ No newline at end of file diff --git a/Assets/FishNet/Runtime/UnityCompatibility.cs.meta b/Assets/FishNet/Runtime/UnityCompatibility.cs.meta new file mode 100644 index 00000000..897e9ea9 --- /dev/null +++ b/Assets/FishNet/Runtime/UnityCompatibility.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c3a88ed478506c145a5efcd3e7c04fd6 \ No newline at end of file