diff --git a/com.unity.netcode.gameobjects/Components.meta b/com.unity.netcode.gameobjects/Components.meta
new file mode 100644
index 0000000000..d4eb0dae79
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Components.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8b267eb841a574dc083ac248a95d4443
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs
index 00e7719e4a..741dc16670 100644
--- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkConfig.cs
@@ -342,8 +342,8 @@ public ulong GetConfig(bool cache = true)
{
var sortedDictionary = Prefabs.NetworkPrefabOverrideLinks.OrderBy(x => x.Key);
foreach (var sortedEntry in sortedDictionary)
-
{
+ Debug.Log($"[NetworkConfig] - GetConfig - [{sortedEntry.Key}={sortedEntry.Value.Prefab}]");
writer.WriteValueSafe(sortedEntry.Key);
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs
index 6e801f5b61..e438426758 100644
--- a/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Configuration/NetworkPrefabs.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Text;
+using TrollKing.Core;
using UnityEngine;
namespace Unity.Netcode
@@ -13,6 +14,8 @@ namespace Unity.Netcode
[Serializable]
public class NetworkPrefabs
{
+ private static readonly NetworkLogScope k_Log = new NetworkLogScope(nameof(NetworkPrefabs));
+
///
/// Edit-time scripted object containing a list of NetworkPrefabs.
///
@@ -52,6 +55,7 @@ public class NetworkPrefabs
private void AddTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
{
+ k_Log.Debug(() => $"NetworkPrefabs AddTriggeredByNetworkPrefabList [networkPrefab={networkPrefab}]");
if (AddPrefabRegistration(networkPrefab))
{
// Don't add this to m_RuntimeAddedPrefabs
@@ -62,6 +66,7 @@ private void AddTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
private void RemoveTriggeredByNetworkPrefabList(NetworkPrefab networkPrefab)
{
+ k_Log.Debug(() => $"NetworkPrefabs RemoveTriggeredByNetworkPrefabList [networkPrefab={networkPrefab}]");
m_Prefabs.Remove(networkPrefab);
}
@@ -93,6 +98,7 @@ internal void Shutdown()
/// When true, logs warnings about invalid prefabs that are removed during initialization
public void Initialize(bool warnInvalid = true)
{
+ k_Log.Debug(() => $"NetworkPrefabs Initialize [warnInvalid={warnInvalid}]");
m_Prefabs.Clear();
foreach (var list in NetworkPrefabsLists)
{
@@ -111,6 +117,8 @@ public void Initialize(bool warnInvalid = true)
{
foreach (var networkPrefab in list.PrefabList)
{
+ var netObj = networkPrefab.Prefab.GetComponent();
+ k_Log.Debug(() => $"NetworkPrefabs Add networkPrefab [networkPrefab={networkPrefab}] [prefab={networkPrefab.Prefab}] [prefabHash={netObj.PrefabIdHash}] [globalHash={netObj.GlobalObjectIdHash}]");
prefabs.Add(networkPrefab);
}
}
@@ -288,9 +296,19 @@ private bool AddPrefabRegistration(NetworkPrefab networkPrefab)
{
return false;
}
+
+ var netObj = networkPrefab.Prefab.GetComponent();
+ if (netObj)
+ {
+ k_Log.Debug(() => $"NetworkPrefabs AddPrefabRegistration [prefab={networkPrefab.Prefab.name}] [networkPrefab={networkPrefab}] [hash={netObj.PrefabIdHash}] [global={netObj.GlobalObjectIdHash}]");
+ }
+
+
+
// Safeguard validation check since this method is called from outside of NetworkConfig and we can't control what's passed in.
if (!networkPrefab.Validate())
{
+ Debug.LogError($"NetworkPrefabs AddPrefabRegistration INVALID [networkPrefab={networkPrefab}]");
return false;
}
@@ -303,7 +321,7 @@ private bool AddPrefabRegistration(NetworkPrefab networkPrefab)
var networkObject = networkPrefab.Prefab.GetComponent();
// This should never happen, but in the case it somehow does log an error and remove the duplicate entry
- Debug.LogError($"{nameof(NetworkPrefab)} ({networkObject.name}) has a duplicate {nameof(NetworkObject.GlobalObjectIdHash)} source entry value of: {source}!");
+ Debug.LogError($"NetworkPrefabs {nameof(NetworkPrefab)} ({networkObject.name}) has a duplicate {nameof(NetworkObject.GlobalObjectIdHash)} source entry value of: {source}!");
return false;
}
@@ -311,6 +329,7 @@ private bool AddPrefabRegistration(NetworkPrefab networkPrefab)
if (networkPrefab.Override == NetworkPrefabOverride.None)
{
NetworkPrefabOverrideLinks.Add(source, networkPrefab);
+ k_Log.Debug(() => $"NetworkPrefabs AddPrefabRegistration NetworkPrefabOverrideLinks [prefab={networkPrefab.Prefab.name}] [source={source}] [networkPrefab={networkPrefab}]");
return true;
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkLogScope.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkLogScope.cs
new file mode 100644
index 0000000000..458c21c899
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkLogScope.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace TrollKing.Core
+{
+ public enum NetworkLoggingLevel
+ {
+ Debug,
+ Info,
+ Warn,
+ Error,
+ Exception,
+ None
+ }
+
+ public class NetworkLogScope
+ {
+ private readonly string m_LoggerName;
+ private readonly NetworkLoggingLevel m_Level = NetworkLoggingLevel.Info;
+
+ public NetworkLogScope(string logName, NetworkLoggingLevel logLevel = NetworkLoggingLevel.Info)
+ {
+ m_LoggerName = logName;
+ m_Level = logLevel;
+ }
+
+ public NetworkLoggingLevel GetLevel()
+ {
+ return m_Level;
+ }
+
+ public void Log(Func stringProvider, NetworkLoggingLevel logLevel = NetworkLoggingLevel.Info)
+ {
+ if (logLevel >= m_Level)
+ {
+ string logString = stringProvider.Invoke();
+ DateTime time = DateTime.Now;
+ var shortTime = time.ToString("T");
+
+ switch (logLevel)
+ {
+ case NetworkLoggingLevel.Debug:
+ UnityEngine.Debug.Log($"[{shortTime}][DEBUG][{m_LoggerName}] {logString}");
+ break;
+ case NetworkLoggingLevel.Info:
+ UnityEngine.Debug.Log($"[{shortTime}][INFO][{m_LoggerName}] {logString}");
+ break;
+ case NetworkLoggingLevel.Warn:
+ UnityEngine.Debug.LogWarning($"[{shortTime}][WARN][{m_LoggerName}] {logString}");
+ break;
+ case NetworkLoggingLevel.Error:
+ UnityEngine.Debug.LogError($"[{shortTime}][ERROR][{m_LoggerName}] {logString}");
+ break;
+ case NetworkLoggingLevel.Exception:
+ UnityEngine.Debug.LogError($"[{shortTime}][EXCEPTION][{m_LoggerName}] {logString}");
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(logLevel), logLevel, null);
+ }
+ }
+ }
+
+ public void Debug(Func logString)
+ {
+ Log(logString, NetworkLoggingLevel.Debug);
+ }
+
+ public void Info(Func logString)
+ {
+ Log(logString, NetworkLoggingLevel.Info);
+ }
+
+ public void Warning(Func logString)
+ {
+ Log(logString, NetworkLoggingLevel.Warn);
+ }
+
+ public void LogWarning(Func logString)
+ {
+ Log(logString, NetworkLoggingLevel.Warn);
+ }
+
+ public void Error(Func logString)
+ {
+ Log(logString, NetworkLoggingLevel.Error);
+ }
+
+ public void LogError(Func logString)
+ {
+ Log(logString, NetworkLoggingLevel.Error);
+ }
+
+ public void LogException(Exception e)
+ {
+ UnityEngine.Debug.LogException(e);
+ }
+
+ public void LogError(Exception e)
+ {
+ UnityEngine.Debug.LogError($"[{m_LoggerName}] {e}");
+ UnityEngine.Debug.LogException(e);
+ }
+ }
+
+ public static class NetworkGameObjectUtility
+ {
+ private static readonly NetworkLogScope Log = new NetworkLogScope(nameof(NetworkGameObjectUtility));
+
+ private static string NetworkGetScenePathRecursive(Transform go, string path)
+ {
+ if (go.parent == null)
+ {
+ return $"{go.gameObject.scene.name}:{go.name}:{path}";
+ }
+
+ return NetworkGetScenePathRecursive(go.parent, $"{go.name}:{path}");
+ }
+
+ // Depth first, we are going all the way down each leg
+ public static void NetworkGetAllHierarchyChildrenRecursive(this GameObject source, ref Queue queue)
+ {
+ if (source == null)
+ {
+ return;
+ }
+
+ int children = source.transform.childCount;
+ for (int i = 0; i < children; i++)
+ {
+ var child = source.transform.GetChild(i);
+ var go = child.gameObject;
+ Log.Debug(() => $"AddingHierarchyChild {go}");
+ queue.Enqueue(go);
+ NetworkGetAllHierarchyChildrenRecursive(go, ref queue);
+ }
+ }
+
+ public static Queue NetworkGetAllHierarchyChildren(this GameObject root)
+ {
+ var retVal = new Queue();
+ if (root == null)
+ {
+ return retVal;
+ }
+ Log.Debug(() => $"AddingHierarchyParent {root}");
+ retVal.Enqueue(root);
+ root.NetworkGetAllHierarchyChildrenRecursive(ref retVal);
+ return retVal;
+ }
+
+ public static string NetworkGetScenePath(this GameObject go)
+ {
+ return NetworkGetScenePath(go.transform);
+ }
+
+ public static string NetworkGetScenePath(this Transform go)
+ {
+ return NetworkGetScenePathRecursive(go, "");
+ }
+
+ public static string NetworkGetSceneName(this GameObject go)
+ {
+ return go.scene.name;
+ }
+
+ public static bool NetworkTryGetComponentInParent(this GameObject go, out T comp)
+ {
+ var parent = go.transform;
+ while (parent != null && parent.parent != parent)
+ {
+ if (parent.TryGetComponent(out comp))
+ {
+ return true;
+ }
+ parent = parent.parent;
+ }
+
+ comp = default;
+ return false;
+ }
+ }
+}
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkLogScope.cs.meta b/com.unity.netcode.gameobjects/Runtime/Core/NetworkLogScope.cs.meta
new file mode 100644
index 0000000000..ea3fdf85eb
--- /dev/null
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkLogScope.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 3b83aae632414713b8843141e3cea71b
+timeCreated: 1695872236
\ No newline at end of file
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
index f0e388d72e..4838aae9e1 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
@@ -1090,7 +1090,7 @@ public int MaximumFragmentedMessageSize
get => MessageManager.FragmentedMessageMaxSize;
}
- internal void Initialize(bool server)
+ public virtual void Initialize(bool server)
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
if (!DisableNotOptimizedSerializedType)
diff --git a/com.unity.netcode.gameobjects/Runtime/Core/NetworkUpdateLoop.cs b/com.unity.netcode.gameobjects/Runtime/Core/NetworkUpdateLoop.cs
index 5f60e748be..ea1f8856b2 100644
--- a/com.unity.netcode.gameobjects/Runtime/Core/NetworkUpdateLoop.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Core/NetworkUpdateLoop.cs
@@ -61,6 +61,7 @@ public enum NetworkUpdateStage : byte
PostScriptLateUpdate = 8,
///
/// Updated after the Monobehaviour.LateUpdate for all components is invoked
+ /// and all rendering is complete
///
PostLateUpdate = 7
}
@@ -74,12 +75,24 @@ public static class NetworkUpdateLoop
private static Dictionary s_UpdateSystem_Arrays;
private const int k_UpdateSystem_InitialArrayCapacity = 1024;
+ private static NetworkUpdateStage[] _CACHED_ENUM = null;
+
+ public static NetworkUpdateStage[] GetNetworkUpdateStageEnumValues()
+ {
+ if (_CACHED_ENUM == null)
+ {
+ _CACHED_ENUM = (NetworkUpdateStage[])Enum.GetValues(typeof(NetworkUpdateStage));
+ }
+
+ return _CACHED_ENUM;
+ }
+
static NetworkUpdateLoop()
{
s_UpdateSystem_Sets = new Dictionary>();
s_UpdateSystem_Arrays = new Dictionary();
- foreach (NetworkUpdateStage updateStage in Enum.GetValues(typeof(NetworkUpdateStage)))
+ foreach (NetworkUpdateStage updateStage in GetNetworkUpdateStageEnumValues())
{
s_UpdateSystem_Sets.Add(updateStage, new HashSet());
s_UpdateSystem_Arrays.Add(updateStage, new INetworkUpdateSystem[k_UpdateSystem_InitialArrayCapacity]);
@@ -92,7 +105,7 @@ static NetworkUpdateLoop()
/// The implementation to register for all network updates
public static void RegisterAllNetworkUpdates(this INetworkUpdateSystem updateSystem)
{
- foreach (NetworkUpdateStage updateStage in Enum.GetValues(typeof(NetworkUpdateStage)))
+ foreach (NetworkUpdateStage updateStage in GetNetworkUpdateStageEnumValues())
{
RegisterNetworkUpdate(updateSystem, updateStage);
}
@@ -136,7 +149,7 @@ public static void RegisterNetworkUpdate(this INetworkUpdateSystem updateSystem,
/// The implementation to deregister from all network updates
public static void UnregisterAllNetworkUpdates(this INetworkUpdateSystem updateSystem)
{
- foreach (NetworkUpdateStage updateStage in Enum.GetValues(typeof(NetworkUpdateStage)))
+ foreach (NetworkUpdateStage updateStage in GetNetworkUpdateStageEnumValues())
{
UnregisterNetworkUpdate(updateSystem, updateStage);
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionRequestMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionRequestMessage.cs
index 11aa4f35bc..465ec4648d 100644
--- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionRequestMessage.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/ConnectionRequestMessage.cs
@@ -143,7 +143,7 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
{
if (NetworkLog.CurrentLogLevel <= LogLevel.Normal)
{
- NetworkLog.LogWarning($"{nameof(NetworkConfig)} mismatch. The configuration between the server and client does not match");
+ NetworkLog.LogWarning($"{nameof(NetworkConfig)} mismatch. IncomingHash=[{ConfigHash}] OurHash=[{networkManager.NetworkConfig.GetConfig()}] The configuration between the server and client does not match");
}
networkManager.DisconnectClient(context.SenderId);
diff --git a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/NetworkVariableDeltaMessage.cs b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/NetworkVariableDeltaMessage.cs
index 8db084cd7d..e8d976faf8 100644
--- a/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/NetworkVariableDeltaMessage.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Messaging/Messages/NetworkVariableDeltaMessage.cs
@@ -188,6 +188,7 @@ public void Serialize(FastBufferWriter writer, int targetVersion)
var startingSize = writer.Length;
var networkVariable = NetworkBehaviour.NetworkVariableFields[i];
+
var shouldWrite = networkVariable.IsDirty() &&
networkVariable.CanClientRead(TargetClientId) &&
(networkManager.IsServer || networkVariable.CanClientWrite(networkManager.LocalClientId)) &&
diff --git a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs
index 97fbeabc72..b2f26296aa 100644
--- a/com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs
+++ b/com.unity.netcode.gameobjects/Runtime/NetworkVariable/Collections/NetworkList.cs
@@ -580,7 +580,8 @@ public void RemoveAt(int index)
// check write permissions
if (!CanClientWrite(m_NetworkManager.LocalClientId))
{
- throw new InvalidOperationException("Client is not allowed to write to this NetworkList");
+ LogWritePermissionError();
+ return;
}
var value = m_List[index];
diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs
index 01bdff807f..2340327262 100644
--- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs
+++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/DefaultSceneManagerHandler.cs
@@ -1,6 +1,10 @@
using System;
using System.Collections.Generic;
+using TrollKing.Core;
using UnityEngine;
+using UnityEngine.AddressableAssets;
+using UnityEngine.ResourceManagement.AsyncOperations;
+using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
@@ -11,6 +15,8 @@ namespace Unity.Netcode
///
internal class DefaultSceneManagerHandler : ISceneManagerHandler
{
+ private static NetworkLogScope s_Log = new NetworkLogScope(nameof(DefaultSceneManagerHandler));
+
private Scene m_InvalidScene = new Scene();
internal struct SceneEntry
@@ -22,18 +28,55 @@ internal struct SceneEntry
internal Dictionary> SceneNameToSceneHandles = new Dictionary>();
- public AsyncOperation LoadSceneAsync(string sceneName, LoadSceneMode loadSceneMode, SceneEventProgress sceneEventProgress)
+ public AsyncOperationHandle LoadSceneAsync(string sceneName, LoadSceneMode loadSceneMode, SceneEventProgress sceneEventProgress)
{
- var operation = SceneManager.LoadSceneAsync(sceneName, loadSceneMode);
- sceneEventProgress.SetAsyncOperation(operation);
+ s_Log.Info(() => $"Loading scene '{sceneName}'...");
+ AsyncOperationHandle operation = default;
+ if (loadSceneMode == LoadSceneMode.Single)
+ {
+ operation = Addressables.LoadSceneAsync(sceneName, LoadSceneMode.Additive, false);
+ // Handle the async load
+ operation.Completed += handle =>
+ {
+ var sceneInstance = handle.Result;
+ var current = SceneManager.GetActiveScene();
+ var async = sceneInstance.ActivateAsync();
+ async.completed += asyncOperation =>
+ {
+ var scene = sceneInstance.Scene;
+ SceneManager.SetActiveScene(scene);
+ SceneManager.UnloadSceneAsync(current);
+ };
+
+ };
+ sceneEventProgress.SetAsyncOperation(operation);
+ }
+ else
+ {
+ operation = Addressables.LoadSceneAsync(sceneName, loadSceneMode);
+ sceneEventProgress.SetAsyncOperation(operation);
+ }
+
return operation;
}
- public AsyncOperation UnloadSceneAsync(Scene scene, SceneEventProgress sceneEventProgress)
+ public AsyncOperationHandle UnloadSceneAsync(NetworkSceneManager.SceneData scene, SceneEventProgress sceneEventProgress)
{
- var operation = SceneManager.UnloadSceneAsync(scene);
- sceneEventProgress.SetAsyncOperation(operation);
- return operation;
+ if (scene.SceneInstance.HasValue)
+ {
+ var operation = Addressables.UnloadSceneAsync(scene.SceneInstance.Value);
+ sceneEventProgress.SetAsyncOperation(operation);
+ return operation;
+ }
+ else
+ {
+ s_Log.Error(() => $"Unloaded a scene that wasn't loaded with addressables '{scene.SceneInstance}'");
+ var unloadOp = SceneManager.UnloadSceneAsync(scene.SceneReference);
+ AsyncOperationHandle operation = default;
+ sceneEventProgress.SetAsyncOperation(operation);
+ return operation;
+ }
+
}
///
@@ -168,8 +211,9 @@ public Scene GetSceneFromLoadedScenes(string sceneName, NetworkManager networkMa
/// same application instance is still running, the same scenes are still loaded on the client, and
/// upon reconnecting the client doesn't have to unload the scenes and then reload them)
///
- public void PopulateLoadedScenes(ref Dictionary scenesLoaded, NetworkManager networkManager)
+ public void PopulateLoadedScenes(ref Dictionary scenesLoaded, NetworkManager networkManager)
{
+ Debug.LogError($"PopulateLoadedScenes START");
SceneNameToSceneHandles.Clear();
var sceneCount = SceneManager.sceneCount;
for (int i = 0; i < sceneCount; i++)
@@ -190,7 +234,7 @@ public void PopulateLoadedScenes(ref Dictionary scenesLoaded, Networ
SceneNameToSceneHandles[scene.name].Add(scene.handle, sceneEntry);
if (!scenesLoaded.ContainsKey(scene.handle))
{
- scenesLoaded.Add(scene.handle, scene);
+ scenesLoaded.Add(scene.handle, new NetworkSceneManager.SceneData(null, scene));
}
}
else
@@ -198,6 +242,7 @@ public void PopulateLoadedScenes(ref Dictionary scenesLoaded, Networ
throw new Exception($"[Duplicate Handle] Scene {scene.name} already has scene handle {scene.handle} registered!");
}
}
+ Debug.LogError($"PopulateLoadedScenes END");
}
private List m_ScenesToUnload = new List();
@@ -373,7 +418,7 @@ public void SetClientSynchronizationMode(ref NetworkManager networkManager, Load
// If the scene is not already in the ScenesLoaded list, then add it
if (!sceneManager.ScenesLoaded.ContainsKey(scene.handle))
{
- sceneManager.ScenesLoaded.Add(scene.handle, scene);
+ sceneManager.ScenesLoaded.Add(scene.handle, new NetworkSceneManager.SceneData(null, scene));
}
}
}
diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/ISceneManagerHandler.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/ISceneManagerHandler.cs
index 9cd3ed1ac8..9f52e28da6 100644
--- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/ISceneManagerHandler.cs
+++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/ISceneManagerHandler.cs
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using UnityEngine;
+using UnityEngine.ResourceManagement.AsyncOperations;
+using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
namespace Unity.Netcode
@@ -8,13 +10,13 @@ namespace Unity.Netcode
/// Used to override the LoadSceneAsync and UnloadSceneAsync methods called
/// within the NetworkSceneManager.
///
- internal interface ISceneManagerHandler
+ public interface ISceneManagerHandler
{
- AsyncOperation LoadSceneAsync(string sceneName, LoadSceneMode loadSceneMode, SceneEventProgress sceneEventProgress);
+ AsyncOperationHandle LoadSceneAsync(string sceneAssetKey, LoadSceneMode loadSceneMode, SceneEventProgress sceneEventProgress);
- AsyncOperation UnloadSceneAsync(Scene scene, SceneEventProgress sceneEventProgress);
+ AsyncOperationHandle UnloadSceneAsync(NetworkSceneManager.SceneData scene, SceneEventProgress sceneEventProgress);
- void PopulateLoadedScenes(ref Dictionary scenesLoaded, NetworkManager networkManager = null);
+ void PopulateLoadedScenes(ref Dictionary scenesLoaded, NetworkManager networkManager = null);
Scene GetSceneFromLoadedScenes(string sceneName, NetworkManager networkManager = null);
bool DoesSceneHaveUnassignedEntry(string sceneName, NetworkManager networkManager = null);
diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs
index 331d5ff112..975b065953 100644
--- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/NetworkSceneManager.cs
@@ -1,9 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using TrollKing.Core;
using Unity.Collections;
using UnityEngine;
+using UnityEngine.AddressableAssets;
+using UnityEngine.Profiling;
+using UnityEngine.ResourceManagement.AsyncOperations;
+using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
+using Object = UnityEngine.Object;
namespace Unity.Netcode
@@ -27,7 +33,7 @@ public class SceneEvent
///
///
///
- public AsyncOperation AsyncOperation;
+ public AsyncOperationHandle AsyncOperation;
///
/// Will always be set to the current
@@ -131,6 +137,8 @@ public class SceneEvent
///
public class NetworkSceneManager : IDisposable
{
+ private static readonly NetworkLogScope Log = new NetworkLogScope(nameof(NetworkSceneManager));
+
private const NetworkDelivery k_DeliveryType = NetworkDelivery.ReliableFragmentedSequenced;
internal const int InvalidSceneNameOrPath = -1;
@@ -181,7 +189,7 @@ public class NetworkSceneManager : IDisposable
/// name of the scene being processed
/// the LoadSceneMode mode for the scene being loaded
/// the associated that can be used for scene loading progress
- public delegate void OnLoadDelegateHandler(ulong clientId, string sceneName, LoadSceneMode loadSceneMode, AsyncOperation asyncOperation);
+ public delegate void OnLoadDelegateHandler(ulong clientId, string sceneName, LoadSceneMode loadSceneMode, AsyncOperationHandle asyncOperation);
///
/// Delegate declaration for the OnUnload event.
@@ -191,7 +199,7 @@ public class NetworkSceneManager : IDisposable
/// the client that is processing this event (the server will receive all of these events for every client and itself)
/// name of the scene being processed
/// the associated that can be used for scene unloading progress
- public delegate void OnUnloadDelegateHandler(ulong clientId, string sceneName, AsyncOperation asyncOperation);
+ public delegate void OnUnloadDelegateHandler(ulong clientId, string sceneName, AsyncOperationHandle asyncOperation);
///
/// Delegate declaration for the OnSynchronize event.
@@ -394,7 +402,7 @@ public bool ActiveSceneSynchronizationEnabled
///
/// The SceneManagerHandler implementation
///
- internal ISceneManagerHandler SceneManagerHandler = new DefaultSceneManagerHandler();
+ public ISceneManagerHandler SceneManagerHandler = new DefaultSceneManagerHandler();
internal readonly Dictionary SceneEventProgressTracking = new Dictionary();
@@ -413,6 +421,17 @@ public bool ActiveSceneSynchronizationEnabled
///
internal Scene SceneBeingSynchronized;
+ public class SceneData
+ {
+ public SceneData(SceneInstance? instance, Scene reference)
+ {
+ SceneReference = reference;
+ SceneInstance = instance;
+ }
+ public Scene SceneReference;
+ public SceneInstance? SceneInstance;
+ }
+
///
/// Used to track which scenes are currently loaded
/// We store the scenes as [SceneHandle][Scene] in order to handle the loading and unloading of the same scene additively
@@ -421,7 +440,7 @@ public bool ActiveSceneSynchronizationEnabled
/// The client links the server scene handle to the client local scene handle upon a scene being loaded
///
///
- internal Dictionary ScenesLoaded = new Dictionary();
+ public Dictionary ScenesLoaded = new Dictionary();
///
/// Returns the currently loaded scenes that are synchronized with the session owner or server depending upon the selected
@@ -432,7 +451,7 @@ public bool ActiveSceneSynchronizationEnabled
/// synchronized remotely. This can be useful when using scene validation and excluding certain scenes from being synchronized.
///
/// List of the known synchronized scenes
- public List GetSynchronizedScenes()
+ public List GetSynchronizedScenes()
{
return ScenesLoaded.Values.ToList();
}
@@ -454,6 +473,7 @@ internal bool UpdateServerClientSceneHandle(int serverHandle, int clientHandle,
{
if (!ServerSceneHandleToClientSceneHandle.ContainsKey(serverHandle))
{
+ Log.Debug(() => $"Adding Server Scene Handle {clientHandle} {localScene.name}");
ServerSceneHandleToClientSceneHandle.Add(serverHandle, clientHandle);
}
else if (!IsRestoringSession)
@@ -463,6 +483,7 @@ internal bool UpdateServerClientSceneHandle(int serverHandle, int clientHandle,
if (!ClientSceneHandleToServerSceneHandle.ContainsKey(clientHandle))
{
+ Log.Debug(() => $"Adding Client Scene Handle {clientHandle} {localScene.name}");
ClientSceneHandleToServerSceneHandle.Add(clientHandle, serverHandle);
}
else if (!IsRestoringSession)
@@ -473,7 +494,7 @@ internal bool UpdateServerClientSceneHandle(int serverHandle, int clientHandle,
// It is "Ok" if this already has an entry
if (!ScenesLoaded.ContainsKey(clientHandle))
{
- ScenesLoaded.Add(clientHandle, localScene);
+ ScenesLoaded.Add(clientHandle, new SceneData(null, localScene));
}
return true;
@@ -487,6 +508,7 @@ internal bool RemoveServerClientSceneHandle(int serverHandle, int clientHandle)
{
if (ServerSceneHandleToClientSceneHandle.ContainsKey(serverHandle))
{
+ Log.Debug(() => $"Remove ServerSceneHandleToClientSceneHandle {clientHandle} {serverHandle}");
ServerSceneHandleToClientSceneHandle.Remove(serverHandle);
}
else
@@ -496,6 +518,7 @@ internal bool RemoveServerClientSceneHandle(int serverHandle, int clientHandle)
if (ClientSceneHandleToServerSceneHandle.ContainsKey(clientHandle))
{
+ Log.Debug(() => $"Remove ClientSceneHandleToServerSceneHandle {clientHandle} {serverHandle}");
ClientSceneHandleToServerSceneHandle.Remove(clientHandle);
}
else
@@ -505,6 +528,7 @@ internal bool RemoveServerClientSceneHandle(int serverHandle, int clientHandle)
if (ScenesLoaded.ContainsKey(clientHandle))
{
+ Log.Debug(() => $"Remove ScenesLoaded {clientHandle} {serverHandle}");
ScenesLoaded.Remove(clientHandle);
}
else
@@ -515,16 +539,6 @@ internal bool RemoveServerClientSceneHandle(int serverHandle, int clientHandle)
return true;
}
- ///
- /// Hash to build index lookup table
- ///
- internal Dictionary HashToBuildIndex = new Dictionary();
-
- ///
- /// Build index to hash lookup table
- ///
- internal Dictionary BuildIndexToHash = new Dictionary();
-
///
/// The Condition: While a scene is asynchronously loaded in single loading scene mode, if any new NetworkObjects are spawned
/// they need to be moved into the do not destroy temporary scene
@@ -540,10 +554,12 @@ internal bool RemoveServerClientSceneHandle(int serverHandle, int clientHandle)
///
internal Dictionary SceneEventDataStore;
- internal readonly NetworkManager NetworkManager;
+ internal Dictionary ScenePathsBySceneName;
+
+ private NetworkManager NetworkManager { get; }
// Keep track of this scene until the NetworkSceneManager is destroyed.
- internal Scene DontDestroyOnLoadScene;
+ public Scene DontDestroyOnLoadScene;
///
/// This setting changes how clients handle scene loading when initially synchronizing with the server.
@@ -558,7 +574,7 @@ internal bool RemoveServerClientSceneHandle(int serverHandle, int clientHandle)
/// and, if is
/// set, callback(s).
///
- public LoadSceneMode ClientSynchronizationMode { get; internal set; }
+ public LoadSceneMode ClientSynchronizationMode { get; set; }
///
/// When true, the messages will be turned off
@@ -663,104 +679,6 @@ internal bool ShouldDeferCreateObject()
return (synchronizeEventDetected && ClientSynchronizationMode == LoadSceneMode.Single) || (!synchronizeEventDetected && loadingEventDetected);
}
- ///
- /// Gets the scene name from full path to the scene
- ///
- internal string GetSceneNameFromPath(string scenePath)
- {
- var begin = scenePath.LastIndexOf("/", StringComparison.Ordinal) + 1;
- var end = scenePath.LastIndexOf(".", StringComparison.Ordinal);
- return scenePath.Substring(begin, end - begin);
- }
-
- ///
- /// Generates the hash values and associated tables
- /// for the scenes in build list
- ///
- internal void GenerateScenesInBuild()
- {
- // TODO 2023: We could support addressable or asset bundle scenes by
- // adding a method that would allow users to add scenes to this.
- // The method would be server-side only and require an additional SceneEventType
- // that would be used to notify clients of the added scene. This might need
- // to include information about the addressable or asset bundle (i.e. address to load assets)
- HashToBuildIndex.Clear();
- BuildIndexToHash.Clear();
- for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++)
- {
- var scenePath = SceneUtility.GetScenePathByBuildIndex(i);
- var hash = XXHash.Hash32(scenePath);
- var buildIndex = SceneUtility.GetBuildIndexByScenePath(scenePath);
-
- // In the rare-case scenario where a programmatically generated build has duplicate
- // scene entries, we will log an error and skip the entry
- if (!HashToBuildIndex.ContainsKey(hash))
- {
- HashToBuildIndex.Add(hash, buildIndex);
- BuildIndexToHash.Add(buildIndex, hash);
- }
- else
- {
- Debug.LogError($"{nameof(NetworkSceneManager)} is skipping duplicate scene path entry {scenePath}. Make sure your scenes in build list does not contain duplicates!");
- }
- }
- }
-
- ///
- /// Gets the scene name from a hash value generated from the full scene path
- ///
- internal string SceneNameFromHash(uint sceneHash)
- {
- // In the event there is no scene associated with the scene event then just return "No Scene"
- // This can happen during unit tests when clients first connect and the only scene loaded is the
- // unit test scene (which is ignored by default) that results in a scene event that has no associated
- // scene. Under this specific special case, we just return "No Scene".
- if (sceneHash == 0)
- {
- return "No Scene";
- }
- return GetSceneNameFromPath(ScenePathFromHash(sceneHash));
- }
-
- ///
- /// Gets the full scene path from a hash value
- ///
- internal string ScenePathFromHash(uint sceneHash)
- {
- if (HashToBuildIndex.ContainsKey(sceneHash))
- {
- return SceneUtility.GetScenePathByBuildIndex(HashToBuildIndex[sceneHash]);
- }
- else
- {
- throw new Exception($"Scene Hash {sceneHash} does not exist in the {nameof(HashToBuildIndex)} table! Verify that all scenes requiring" +
- $" server to client synchronization are in the scenes in build list.");
- }
- }
-
- ///
- /// Gets the associated hash value for the scene name or path
- ///
- internal uint SceneHashFromNameOrPath(string sceneNameOrPath)
- {
- var buildIndex = SceneUtility.GetBuildIndexByScenePath(sceneNameOrPath);
- if (buildIndex >= 0)
- {
- if (BuildIndexToHash.ContainsKey(buildIndex))
- {
- return BuildIndexToHash[buildIndex];
- }
- else
- {
- throw new Exception($"Scene '{sceneNameOrPath}' has a build index of {buildIndex} that does not exist in the {nameof(BuildIndexToHash)} table!");
- }
- }
- else
- {
- throw new Exception($"Scene '{sceneNameOrPath}' couldn't be loaded because it has not been added to the build settings scenes in build list.");
- }
- }
-
///
/// When set to true, this will disable the console warnings about
/// a scene being invalidated.
@@ -801,9 +719,6 @@ internal NetworkSceneManager(NetworkManager networkManager)
NetworkManager = networkManager;
SceneEventDataStore = new Dictionary();
- // Generates the scene name to hash value
- GenerateScenesInBuild();
-
// Since NetworkManager is now always migrated to the DDOL we will use this to get the DDOL scene
DontDestroyOnLoadScene = networkManager.gameObject.scene;
@@ -816,7 +731,7 @@ internal NetworkSceneManager(NetworkManager networkManager)
for (int i = 0; i < SceneManager.sceneCount; i++)
{
var loadedScene = SceneManager.GetSceneAt(i);
- ScenesLoaded.Add(loadedScene.handle, loadedScene);
+ ScenesLoaded.Add(loadedScene.handle, new SceneData(null, loadedScene));
}
SceneManagerHandler.PopulateLoadedScenes(ref ScenesLoaded, NetworkManager);
}
@@ -868,21 +783,17 @@ private void SceneManager_ActiveSceneChanged(Scene current, Scene next)
}
}
- // If the scene's build index is in the hash table
- if (BuildIndexToHash.ContainsKey(next.buildIndex))
+ // Notify clients of the change in active scene
+ var sceneEvent = BeginSceneEvent();
+ sceneEvent.SceneEventType = SceneEventType.ActiveSceneChanged;
+ sceneEvent.ActiveSceneAsset = next.name;
+ var sessionOwner = NetworkManager.ServerClientId;
+ if (NetworkManager.DistributedAuthorityMode)
{
- // Notify clients of the change in active scene
- var sceneEvent = BeginSceneEvent();
- sceneEvent.SceneEventType = SceneEventType.ActiveSceneChanged;
- sceneEvent.ActiveSceneHash = BuildIndexToHash[next.buildIndex];
- var sessionOwner = NetworkManager.ServerClientId;
- if (NetworkManager.DistributedAuthorityMode)
- {
- sessionOwner = NetworkManager.CurrentSessionOwner;
- }
- SendSceneEventData(sceneEvent.SceneEventId, NetworkManager.ConnectedClientsIds.Where(c => c != sessionOwner).ToArray());
- EndSceneEvent(sceneEvent.SceneEventId);
+ sessionOwner = NetworkManager.CurrentSessionOwner;
}
+ SendSceneEventData(sceneEvent.SceneEventId, NetworkManager.ConnectedClientsIds.Where(c => c != sessionOwner).ToArray());
+ EndSceneEvent(sceneEvent.SceneEventId);
}
///
@@ -893,34 +804,28 @@ private void SceneManager_ActiveSceneChanged(Scene current, Scene next)
/// index into ScenesInBuild
/// LoadSceneMode the scene is going to be loaded
/// true (Valid) or false (Invalid)
- internal bool ValidateSceneBeforeLoading(uint sceneHash, LoadSceneMode loadSceneMode)
+ internal bool ValidateSceneBeforeLoading(string sceneName, LoadSceneMode loadSceneMode)
{
- var sceneName = SceneNameFromHash(sceneHash);
- var sceneIndex = SceneUtility.GetBuildIndexByScenePath(sceneName);
- return ValidateSceneBeforeLoading(sceneIndex, sceneName, loadSceneMode);
- }
+ Log.Debug(() => $"ValidateSceneBeforeLoading {sceneName} {loadSceneMode}");
+ return true;
- ///
- /// Overloaded version that is invoked by and .
- /// This specifically is to allow runtime generated scenes to be excluded by the server during synchronization.
- ///
- internal bool ValidateSceneBeforeLoading(int sceneIndex, string sceneName, LoadSceneMode loadSceneMode)
- {
- var validated = true;
- if (VerifySceneBeforeLoading != null)
- {
- validated = VerifySceneBeforeLoading.Invoke(sceneIndex, sceneName, loadSceneMode);
- }
- if (!validated && !m_DisableValidationWarningMessages)
- {
- var serverHostorClient = "Client";
- if (HasSceneAuthority())
- {
- serverHostorClient = NetworkManager.DistributedAuthorityMode ? "Session Owner" : NetworkManager.IsHost ? "Host" : "Server";
- }
- Debug.LogWarning($"Scene {sceneName} of Scenes in Build Index {sceneIndex} being loaded in {loadSceneMode} mode failed validation on the {serverHostorClient}!");
- }
- return validated;
+ // var validated = true;
+ // var sceneIndex = SceneUtility.GetBuildIndexByScenePath(sceneName);
+ // if (VerifySceneBeforeLoading != null)
+ // {
+ // validated = VerifySceneBeforeLoading.Invoke(sceneIndex, sceneName, loadSceneMode);
+ // }
+ // if (!validated && !m_DisableValidationWarningMessages)
+ // {
+ // var serverHostorClient = "Client";
+ // if (NetworkManager.IsServer)
+ // {
+ // serverHostorClient = NetworkManager.IsHost ? "Host" : "Server";
+ // }
+ //
+ // Debug.LogWarning($"Scene {sceneName} of Scenes in Build Index {sceneIndex} being loaded in {loadSceneMode} mode failed validation on the {serverHostorClient}!");
+ // }
+ // return validated;
}
///
@@ -953,7 +858,7 @@ internal Scene GetAndAddNewlyLoadedSceneByName(string sceneName)
{
if (!ScenesLoaded.ContainsKey(sceneLoaded.handle))
{
- ScenesLoaded.Add(sceneLoaded.handle, sceneLoaded);
+ ScenesLoaded.Add(sceneLoaded.handle, new SceneData(null, sceneLoaded));
SceneManagerHandler.StartTrackingScene(sceneLoaded, true, NetworkManager);
return sceneLoaded;
}
@@ -987,7 +892,7 @@ internal void SetTheSceneBeingSynchronized(int serverSceneHandle)
}
// Get the scene currently being synchronized
- SceneBeingSynchronized = ScenesLoaded.ContainsKey(clientSceneHandle) ? ScenesLoaded[clientSceneHandle] : new Scene();
+ SceneBeingSynchronized = ScenesLoaded.ContainsKey(clientSceneHandle) ? ScenesLoaded[clientSceneHandle].SceneReference : new Scene();
if (!SceneBeingSynchronized.IsValid() || !SceneBeingSynchronized.isLoaded)
{
@@ -1066,7 +971,7 @@ private void SendSceneEventData(uint sceneEventId, ulong[] targetClientIds)
EventData = sceneEvent,
};
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, NetworkManager.ServerClientId);
- NetworkManager.NetworkMetrics.TrackSceneEventSent(NetworkManager.ServerClientId, (uint)sceneEvent.SceneEventType, SceneNameFromHash(sceneEvent.SceneHash), size);
+ NetworkManager.NetworkMetrics.TrackSceneEventSent(NetworkManager.ServerClientId, (uint)sceneEvent.SceneEventType, sceneEvent.SceneAsset, size);
}
foreach (var clientId in targetClientIds)
{
@@ -1076,24 +981,19 @@ private void SendSceneEventData(uint sceneEventId, ulong[] targetClientIds)
EventData = sceneEvent,
};
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, NetworkManager.ServerClientId);
- NetworkManager.NetworkMetrics.TrackSceneEventSent(clientId, (uint)sceneEvent.SceneEventType, SceneNameFromHash(sceneEvent.SceneHash), size);
+ NetworkManager.NetworkMetrics.TrackSceneEventSent(clientId, (uint)sceneEvent.SceneEventType, sceneEvent.SceneAsset, size);
}
}
else
{
- // Send to each individual client to assure only the in-scene placed NetworkObjects being observed by the client
- // is serialized
- foreach (var clientId in targetClientIds)
+ var message = new SceneEventMessage
{
- sceneEvent.TargetClientId = clientId;
- var message = new SceneEventMessage
- {
- EventData = sceneEvent,
- };
- var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, clientId);
- NetworkManager.NetworkMetrics.TrackSceneEventSent(clientId, (uint)sceneEvent.SceneEventType, SceneNameFromHash(sceneEvent.SceneHash), size);
- }
+ EventData = sceneEvent,
+ };
+ var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, targetClientIds);
+ NetworkManager.NetworkMetrics.TrackSceneEventSent(targetClientIds, (uint)SceneEventDataStore[sceneEventId].SceneEventType, sceneEvent.SceneAsset, size);
}
+
}
///
@@ -1175,16 +1075,53 @@ private SceneEventProgress ValidateSceneEvent(string sceneName, bool isUnloading
return new SceneEventProgress(null, SceneEventProgressStatus.SceneEventInProgress);
}
- // Return invalid scene name status if the scene name is invalid
- if (SceneUtility.GetBuildIndexByScenePath(sceneName) == InvalidSceneNameOrPath)
+ // // Return invalid scene name status if the scene name is invalid
+ // if (SceneUtility.GetBuildIndexByScenePath(sceneName) == InvalidSceneNameOrPath)
+ // {
+ // Debug.LogError($"Scene '{sceneName}' couldn't be loaded because it has not been added to the build settings scenes in build list.");
+ // return new SceneEventProgress(null, SceneEventProgressStatus.InvalidSceneName);
+ // }
+ var locatorInfo = Addressables.GetLocatorInfo(sceneName);
+
+ var resourceLocationAsync = Addressables.LoadResourceLocationsAsync(sceneName);
+ resourceLocationAsync.WaitForCompletion();
+ if (resourceLocationAsync.Status == AsyncOperationStatus.Succeeded)
{
- Debug.LogError($"Scene '{sceneName}' couldn't be loaded because it has not been added to the build settings scenes in build list.");
- return new SceneEventProgress(null, SceneEventProgressStatus.InvalidSceneName);
+ if (resourceLocationAsync.Result.Count >= 1)
+ {
+ var location = resourceLocationAsync.Result[0];
+ var provider = location.ProviderId;
+ if (!provider.Contains("Scene"))
+ {
+ Debug.LogWarning($"Provider is not a scene provider! {provider}");
+ }
+
+ var resourceType = location.ResourceType;
+ if (resourceType != typeof(SceneInstance))
+ {
+ throw new Exception($"Scene is not of the SceneInstance type! {resourceType}");
+ }
+ if (location.HasDependencies)
+ {
+ // Has dependencies!
+ // download something?
+ // no! this is just a verification method
+ }
+
+ if (location.PrimaryKey != sceneName)
+ {
+ throw new Exception($"Scene is not primary key of the scene name! {location.PrimaryKey} {sceneName}");
+ }
+ }
+ }
+ else
+ {
+ throw new Exception($"Scene '{sceneName}' couldn't be loaded for its resource location.");
}
var sceneEventProgress = new SceneEventProgress(NetworkManager)
{
- SceneHash = SceneHashFromNameOrPath(sceneName)
+ SceneName = sceneName
};
SceneEventProgressTracking.Add(sceneEventProgress.Guid, sceneEventProgress);
@@ -1207,7 +1144,7 @@ private bool OnSceneEventProgressCompleted(SceneEventProgress sceneEventProgress
var clientsThatCompleted = sceneEventProgress.GetClientsWithStatus(true);
var clientsThatTimedOut = sceneEventProgress.GetClientsWithStatus(false);
sceneEventData.SceneEventProgressId = sceneEventProgress.Guid;
- sceneEventData.SceneHash = sceneEventProgress.SceneHash;
+ sceneEventData.SceneAsset = sceneEventProgress.SceneName;
sceneEventData.SceneEventType = sceneEventProgress.SceneEventType;
sceneEventData.ClientsCompleted = clientsThatCompleted;
sceneEventData.LoadSceneMode = sceneEventProgress.LoadSceneMode;
@@ -1228,7 +1165,7 @@ private bool OnSceneEventProgressCompleted(SceneEventProgress sceneEventProgress
NetworkManager.NetworkMetrics.TrackSceneEventSent(
NetworkManager.ConnectedClientsIds,
(uint)sceneEventProgress.SceneEventType,
- SceneNameFromHash(sceneEventProgress.SceneHash),
+ sceneEventProgress.SceneName,
size);
}
@@ -1236,7 +1173,7 @@ private bool OnSceneEventProgressCompleted(SceneEventProgress sceneEventProgress
OnSceneEvent?.Invoke(new SceneEvent()
{
SceneEventType = sceneEventProgress.SceneEventType,
- SceneName = SceneNameFromHash(sceneEventProgress.SceneHash),
+ SceneName = sceneEventProgress.SceneName,
ClientId = NetworkManager.CurrentSessionOwner,
LoadSceneMode = sceneEventProgress.LoadSceneMode,
ClientsThatCompleted = clientsThatCompleted,
@@ -1245,11 +1182,11 @@ private bool OnSceneEventProgressCompleted(SceneEventProgress sceneEventProgress
if (sceneEventData.SceneEventType == SceneEventType.LoadEventCompleted)
{
- OnLoadEventCompleted?.Invoke(SceneNameFromHash(sceneEventProgress.SceneHash), sceneEventProgress.LoadSceneMode, sceneEventData.ClientsCompleted, sceneEventData.ClientsTimedOut);
+ OnLoadEventCompleted?.Invoke(sceneEventProgress.SceneName, sceneEventProgress.LoadSceneMode, sceneEventData.ClientsCompleted, sceneEventData.ClientsTimedOut);
}
else
{
- OnUnloadEventCompleted?.Invoke(SceneNameFromHash(sceneEventProgress.SceneHash), sceneEventProgress.LoadSceneMode, sceneEventData.ClientsCompleted, sceneEventData.ClientsTimedOut);
+ OnUnloadEventCompleted?.Invoke(sceneEventProgress.SceneName, sceneEventProgress.LoadSceneMode, sceneEventData.ClientsCompleted, sceneEventData.ClientsTimedOut);
}
EndSceneEvent(sceneEventData.SceneEventId);
@@ -1304,7 +1241,7 @@ public SceneEventProgressStatus UnloadScene(Scene scene)
var sceneEventData = BeginSceneEvent();
sceneEventData.SceneEventProgressId = sceneEventProgress.Guid;
sceneEventData.SceneEventType = SceneEventType.Unload;
- sceneEventData.SceneHash = SceneHashFromNameOrPath(sceneName);
+ sceneEventData.SceneAsset = sceneName;
sceneEventData.LoadSceneMode = LoadSceneMode.Additive; // The only scenes unloaded are scenes that were additively loaded
sceneEventData.SceneHandle = sceneHandle;
@@ -1316,11 +1253,19 @@ public SceneEventProgressStatus UnloadScene(Scene scene)
if (!RemoveServerClientSceneHandle(sceneEventData.SceneHandle, scene.handle))
{
- Debug.LogError($"Failed to remove {SceneNameFromHash(sceneEventData.SceneHash)} scene handles [Server ({sceneEventData.SceneHandle})][Local({scene.handle})]");
+ Debug.LogError($"Failed to remove {sceneEventData.SceneAsset} scene handles [Server ({sceneEventData.SceneHandle})][Local({scene.handle})]");
}
- var sceneUnload = SceneManagerHandler.UnloadSceneAsync(scene, sceneEventProgress);
-
+ AsyncOperationHandle sceneUnload;
+ if (ScenesLoaded[sceneHandle].SceneInstance.HasValue)
+ {
+ sceneUnload = SceneManagerHandler.UnloadSceneAsync(ScenesLoaded[sceneHandle], sceneEventProgress);
+ }
+ else
+ {
+ throw new Exception("Fuuuuck");
+ sceneUnload = default;
+ }
// Notify local server that a scene is going to be unloaded
OnSceneEvent?.Invoke(new SceneEvent()
{
@@ -1344,7 +1289,7 @@ public SceneEventProgressStatus UnloadScene(Scene scene)
private void OnClientUnloadScene(uint sceneEventId)
{
var sceneEventData = SceneEventDataStore[sceneEventId];
- var sceneName = SceneNameFromHash(sceneEventData.SceneHash);
+ var sceneName = sceneEventData.SceneAsset;
if (!ServerSceneHandleToClientSceneHandle.ContainsKey(sceneEventData.SceneHandle))
{
@@ -1368,7 +1313,7 @@ private void OnClientUnloadScene(uint sceneEventId)
// should be migrated temporarily into the DDOL, once the scene is unloaded they will be migrated into the
// currently active scene.
var networkManager = NetworkManager;
- SceneManagerHandler.MoveObjectsFromSceneToDontDestroyOnLoad(ref networkManager, scene);
+ SceneManagerHandler.MoveObjectsFromSceneToDontDestroyOnLoad(ref networkManager, scene.SceneReference);
m_IsSceneEventActive = true;
var sceneEventProgress = new SceneEventProgress(NetworkManager)
{
@@ -1381,8 +1326,16 @@ private void OnClientUnloadScene(uint sceneEventId)
SceneEventProgressTracking.Add(sceneEventData.SceneEventProgressId, sceneEventProgress);
}
- var sceneUnload = SceneManagerHandler.UnloadSceneAsync(scene, sceneEventProgress);
-
+ AsyncOperationHandle sceneUnload;
+ if (ScenesLoaded[sceneHandle].SceneInstance.HasValue)
+ {
+ sceneUnload = SceneManagerHandler.UnloadSceneAsync(ScenesLoaded[sceneHandle], sceneEventProgress);
+ }
+ else
+ {
+ throw new Exception("Fuuuuck");
+ sceneUnload = default;
+ }
SceneManagerHandler.StopTrackingScene(sceneHandle, sceneName, NetworkManager);
// Remove our server to scene handle lookup
@@ -1409,7 +1362,7 @@ private void OnClientUnloadScene(uint sceneEventId)
/// Server and Client:
/// Invoked when an additively loaded scene is unloaded
///
- private void OnSceneUnloaded(uint sceneEventId)
+ private void OnSceneUnloaded(uint sceneEventId, string sceneName)
{
// If we are shutdown or about to shutdown, then ignore this event
if (!NetworkManager.IsListening || NetworkManager.ShutdownInProgress)
@@ -1451,11 +1404,11 @@ private void OnSceneUnloaded(uint sceneEventId)
{
SceneEventType = sceneEventData.SceneEventType,
LoadSceneMode = sceneEventData.LoadSceneMode,
- SceneName = SceneNameFromHash(sceneEventData.SceneHash),
+ SceneName = sceneEventData.SceneAsset,
ClientId = NetworkManager.LocalClientId,
});
- OnUnloadComplete?.Invoke(NetworkManager.LocalClientId, SceneNameFromHash(sceneEventData.SceneHash));
+ OnUnloadComplete?.Invoke(NetworkManager.LocalClientId, sceneEventData.SceneAsset);
if (!HasSceneAuthority())
{
@@ -1469,14 +1422,14 @@ private void OnSceneUnloaded(uint sceneEventId)
// current instance is the DAHost.
var target = NetworkManager.DAHost ? NetworkManager.CurrentSessionOwner : NetworkManager.ServerClientId;
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, target);
- NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, SceneNameFromHash(sceneEventData.SceneHash), size);
+ NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, sceneEventData.SceneAsset, size);
}
EndSceneEvent(sceneEventId);
// This scene event is now considered "complete"
m_IsSceneEventActive = false;
}
- private void EmptySceneUnloadedOperation(uint sceneEventId)
+ private void EmptySceneUnloadedOperation(uint sceneEventId, string sceneName)
{
// Do nothing (this is a stub call since it is only used to flush all additively loaded scenes)
}
@@ -1494,7 +1447,7 @@ internal void UnloadAdditivelyLoadedScenes(uint sceneEventId)
foreach (var keyHandleEntry in ScenesLoaded)
{
// Validate the scene as well as ignore the DDOL (which will have a negative buildIndex)
- if (currentActiveScene.name != keyHandleEntry.Value.name && keyHandleEntry.Value.buildIndex >= 0)
+ if (currentActiveScene.name != keyHandleEntry.Value.SceneReference.name && keyHandleEntry.Value.SceneReference != DontDestroyOnLoadScene)
{
var sceneEventProgress = new SceneEventProgress(NetworkManager)
{
@@ -1502,16 +1455,17 @@ internal void UnloadAdditivelyLoadedScenes(uint sceneEventId)
OnSceneEventCompleted = EmptySceneUnloadedOperation
};
- if (ClientSceneHandleToServerSceneHandle.ContainsKey(keyHandleEntry.Value.handle))
+ if (ClientSceneHandleToServerSceneHandle.TryGetValue(keyHandleEntry.Value.SceneReference.handle, out var serverSceneHandle))
{
- var serverSceneHandle = ClientSceneHandleToServerSceneHandle[keyHandleEntry.Value.handle];
ServerSceneHandleToClientSceneHandle.Remove(serverSceneHandle);
}
- ClientSceneHandleToServerSceneHandle.Remove(keyHandleEntry.Value.handle);
+ Log.Debug(() => $"Remove ClientSceneHandleToServerSceneHandle {keyHandleEntry.Value.SceneReference.handle}");
+ ClientSceneHandleToServerSceneHandle.Remove(keyHandleEntry.Value.SceneReference.handle);
var sceneUnload = SceneManagerHandler.UnloadSceneAsync(keyHandleEntry.Value, sceneEventProgress);
- SceneUnloadEventHandler.RegisterScene(this, keyHandleEntry.Value, LoadSceneMode.Additive, sceneUnload);
+ SceneUnloadEventHandler.RegisterScene(this, keyHandleEntry.Value.SceneReference, LoadSceneMode.Additive, sceneUnload);
+
}
}
// clear out our scenes loaded list
@@ -1519,6 +1473,94 @@ internal void UnloadAdditivelyLoadedScenes(uint sceneEventId)
SceneManagerHandler.ClearSceneTracking(NetworkManager);
}
+ public SceneEventProgress LoadAddressableScene(AssetReference sceneReference, LoadSceneMode loadSceneMode)
+ {
+ var resourceAsync = Addressables.LoadResourceLocationsAsync(sceneReference);
+ resourceAsync.WaitForCompletion();
+
+ var sceneName = "";
+
+ if (resourceAsync.Status == AsyncOperationStatus.Succeeded)
+ {
+ var sceneKey = resourceAsync.Result[0].PrimaryKey;
+ sceneName = sceneKey;
+ }
+ else
+ {
+ throw new Exception($"Failed to load scene from resource {resourceAsync.OperationException}");
+ }
+
+ var sceneEventProgress = ValidateSceneEventLoading(sceneName);
+ if (sceneEventProgress.Status != SceneEventProgressStatus.Started)
+ {
+ return sceneEventProgress;
+ }
+
+ // This will be the message we send to everyone when this scene event sceneEventProgress is complete
+ sceneEventProgress.SceneEventType = SceneEventType.LoadEventCompleted;
+ sceneEventProgress.LoadSceneMode = loadSceneMode;
+
+ var sceneEventData = BeginSceneEvent();
+
+ // Now set up the current scene event
+ sceneEventData.SceneEventProgressId = sceneEventProgress.Guid;
+ sceneEventData.SceneEventType = SceneEventType.Load;
+ sceneEventData.SceneAsset = sceneName;
+ sceneEventData.LoadSceneMode = loadSceneMode;
+ var sceneEventId = sceneEventData.SceneEventId;
+ // This both checks to make sure the scene is valid and if not resets the active scene event
+ m_IsSceneEventActive = ValidateSceneBeforeLoading(sceneEventData.SceneAsset, loadSceneMode);
+ if (!m_IsSceneEventActive)
+ {
+ EndSceneEvent(sceneEventId);
+ sceneEventProgress.Status = SceneEventProgressStatus.SceneFailedVerification;
+ return sceneEventProgress;
+ }
+
+ if (sceneEventData.LoadSceneMode == LoadSceneMode.Single)
+ {
+ // Destroy current scene objects before switching.
+ NetworkManager.SpawnManager.ServerDestroySpawnedSceneObjects();
+
+ // Preserve the objects that should not be destroyed during the scene event
+ MoveObjectsToDontDestroyOnLoad();
+
+ // Now Unload all currently additively loaded scenes
+ UnloadAdditivelyLoadedScenes(sceneEventId);
+
+ // Register the active scene for unload scene event notifications
+ SceneUnloadEventHandler.RegisterScene(this, SceneManager.GetActiveScene(), LoadSceneMode.Single);
+ }
+
+ // Now start loading the scene
+ sceneEventProgress.SceneEventId = sceneEventId;
+ sceneEventProgress.OnSceneEventCompleted = OnSceneLoaded;
+ var sceneLoad = SceneManagerHandler.LoadSceneAsync(sceneName, loadSceneMode, sceneEventProgress);
+
+ // Notify the local server that a scene loading event has begun
+ OnSceneEvent?.Invoke(new SceneEvent()
+ {
+ AsyncOperation = sceneLoad,
+ SceneEventType = sceneEventData.SceneEventType,
+ LoadSceneMode = sceneEventData.LoadSceneMode,
+ SceneName = sceneName,
+ ClientId = NetworkManager.ServerClientId
+ });
+
+ OnLoad?.Invoke(NetworkManager.ServerClientId, sceneName, sceneEventData.LoadSceneMode, sceneLoad);
+
+ //Return our scene progress instance
+ return sceneEventProgress;
+ }
+
+
+ private static Dictionary s_ResourceLocationsBySceneName = new();
+
+ public bool PrepareToLoadScene(string sceneName, Action loaded)
+ {
+ return false;
+ }
+
///
/// Server side:
/// Loads the scene name in either additive or single loading mode.
@@ -1527,12 +1569,23 @@ internal void UnloadAdditivelyLoadedScenes(uint sceneEventId)
/// the name of the scene to be loaded
/// how the scene will be loaded (single or additive mode)
/// ( means it was successful)
- public SceneEventProgressStatus LoadScene(string sceneName, LoadSceneMode loadSceneMode)
+ public SceneEventProgress LoadScene(string sceneName, LoadSceneMode loadSceneMode)
{
+ // Debug.Log($"[NetworkSceneManager] LoadScene sceneName={sceneName}");
+ if (!s_ResourceLocationsBySceneName.TryGetValue(sceneName, out var found))
+ {
+ var resourceLocationAsync = Addressables.LoadResourceLocationsAsync(sceneName);
+ if (!resourceLocationAsync.IsValid())
+ {
+ return null;
+ }
+ }
+
+ // Debug.Log($"[NetworkSceneManager] LoadScene Finished LoadResources sceneName={sceneName}");
var sceneEventProgress = ValidateSceneEventLoading(sceneName);
if (sceneEventProgress.Status != SceneEventProgressStatus.Started)
{
- return sceneEventProgress.Status;
+ return sceneEventProgress;
}
// This will be the message we send to everyone when this scene event sceneEventProgress is complete
@@ -1544,15 +1597,15 @@ public SceneEventProgressStatus LoadScene(string sceneName, LoadSceneMode loadSc
// Now set up the current scene event
sceneEventData.SceneEventProgressId = sceneEventProgress.Guid;
sceneEventData.SceneEventType = SceneEventType.Load;
- sceneEventData.SceneHash = SceneHashFromNameOrPath(sceneName);
+ sceneEventData.SceneAsset = sceneName;
sceneEventData.LoadSceneMode = loadSceneMode;
var sceneEventId = sceneEventData.SceneEventId;
// This both checks to make sure the scene is valid and if not resets the active scene event
- m_IsSceneEventActive = ValidateSceneBeforeLoading(sceneEventData.SceneHash, loadSceneMode);
+ m_IsSceneEventActive = ValidateSceneBeforeLoading(sceneEventData.SceneAsset, loadSceneMode);
if (!m_IsSceneEventActive)
{
EndSceneEvent(sceneEventId);
- return SceneEventProgressStatus.SceneFailedVerification;
+ return new SceneEventProgress(NetworkManager.Singleton, SceneEventProgressStatus.SceneFailedVerification);
}
if (sceneEventData.LoadSceneMode == LoadSceneMode.Single)
@@ -1580,8 +1633,9 @@ public SceneEventProgressStatus LoadScene(string sceneName, LoadSceneMode loadSc
// Now start loading the scene
sceneEventProgress.SceneEventId = sceneEventId;
sceneEventProgress.OnSceneEventCompleted = OnSceneLoaded;
+ // Debug.Log($"[NetworkSceneManager] BEGIN SceneManagerHandler.LoadSceneAsync sceneName={sceneName} loadSceneMode={loadSceneMode}");
var sceneLoad = SceneManagerHandler.LoadSceneAsync(sceneName, loadSceneMode, sceneEventProgress);
-
+ // Debug.Log($"[NetworkSceneManager] END SceneManagerHandler.LoadSceneAsync sceneName={sceneName} loadSceneMode={loadSceneMode}");
// Notify the local server that a scene loading event has begun
OnSceneEvent?.Invoke(new SceneEvent()
{
@@ -1594,7 +1648,7 @@ public SceneEventProgressStatus LoadScene(string sceneName, LoadSceneMode loadSc
OnLoad?.Invoke(NetworkManager.LocalClientId, sceneName, sceneEventData.LoadSceneMode, sceneLoad);
//Return our scene progress instance
- return sceneEventProgress.Status;
+ return sceneEventProgress;
}
///
@@ -1605,7 +1659,7 @@ internal class SceneUnloadEventHandler
{
private static Dictionary> s_Instances = new Dictionary>();
- internal static void RegisterScene(NetworkSceneManager networkSceneManager, Scene scene, LoadSceneMode loadSceneMode, AsyncOperation asyncOperation = null)
+ internal static void RegisterScene(NetworkSceneManager networkSceneManager, Scene scene, LoadSceneMode loadSceneMode, AsyncOperationHandle asyncOperation = default)
{
var networkManager = networkSceneManager.NetworkManager;
if (!s_Instances.ContainsKey(networkManager))
@@ -1650,7 +1704,7 @@ internal static void Shutdown()
}
private NetworkSceneManager m_NetworkSceneManager;
- private AsyncOperation m_AsyncOperation;
+ private AsyncOperationHandle m_AsyncOperation;
private LoadSceneMode m_LoadSceneMode;
private ulong m_ClientId;
private Scene m_Scene;
@@ -1683,7 +1737,7 @@ private void SceneUnloaded(Scene scene)
}
}
- private SceneUnloadEventHandler(NetworkSceneManager networkSceneManager, Scene scene, ulong clientId, LoadSceneMode loadSceneMode, AsyncOperation asyncOperation = null)
+ private SceneUnloadEventHandler(NetworkSceneManager networkSceneManager, Scene scene, ulong clientId, LoadSceneMode loadSceneMode, AsyncOperationHandle asyncOperation = default)
{
m_LoadSceneMode = loadSceneMode;
m_AsyncOperation = asyncOperation;
@@ -1701,7 +1755,7 @@ private SceneUnloadEventHandler(NetworkSceneManager networkSceneManager, Scene s
ClientId = clientId
});
- m_NetworkSceneManager.OnUnload?.Invoke(networkSceneManager.NetworkManager.LocalClientId, m_Scene.name, null);
+ m_NetworkSceneManager.OnUnload?.Invoke(networkSceneManager.NetworkManager.LocalClientId, m_Scene.name, default);
}
}
@@ -1713,10 +1767,10 @@ private SceneUnloadEventHandler(NetworkSceneManager networkSceneManager, Scene s
private void OnClientSceneLoadingEvent(uint sceneEventId)
{
var sceneEventData = SceneEventDataStore[sceneEventId];
- var sceneName = SceneNameFromHash(sceneEventData.SceneHash);
+ var sceneName = sceneEventData.SceneAsset;
// Run scene validation before loading a scene
- if (!ValidateSceneBeforeLoading(sceneEventData.SceneHash, sceneEventData.LoadSceneMode))
+ if (!ValidateSceneBeforeLoading(sceneEventData.SceneAsset, sceneEventData.LoadSceneMode))
{
EndSceneEvent(sceneEventId);
return;
@@ -1774,7 +1828,7 @@ private void OnClientSceneLoadingEvent(uint sceneEventId)
/// Client and Server:
/// Generic on scene loaded callback method to be called upon a scene loading
///
- private void OnSceneLoaded(uint sceneEventId)
+ private void OnSceneLoaded(uint sceneEventId, string loadedSceneName)
{
// If we are shutdown or about to shutdown, then ignore this event
if (!NetworkManager.IsListening || NetworkManager.ShutdownInProgress)
@@ -1784,11 +1838,12 @@ private void OnSceneLoaded(uint sceneEventId)
}
var sceneEventData = SceneEventDataStore[sceneEventId];
- var nextScene = GetAndAddNewlyLoadedSceneByName(SceneNameFromHash(sceneEventData.SceneHash));
- if (!nextScene.isLoaded || !nextScene.IsValid())
+ var nextScene = GetAndAddNewlyLoadedSceneByName(loadedSceneName);
+ if (!nextScene.IsValid())
{
throw new Exception($"Failed to find valid scene internal Unity.Netcode for {nameof(GameObject)}s error!");
}
+ // If we async loaded a single scene, the active will activate it
if (sceneEventData.LoadSceneMode == LoadSceneMode.Single)
{
@@ -1820,6 +1875,8 @@ private void OnSceneLoaded(uint sceneEventId)
}
}
+ Log.Debug(() => "OnSceneLoaded");
+
//Get all NetworkObjects loaded by the scene
PopulateScenePlacedObjects(nextScene);
@@ -1861,6 +1918,8 @@ private void OnSceneLoaded(uint sceneEventId)
///
private void OnSessionOwnerLoadedScene(uint sceneEventId, Scene scene)
{
+ // Debug.Log($"NetworkSceneManager - OnServerLoadedScene eventId:{sceneEventId} scene:{scene.name}");
+
var sceneEventData = SceneEventDataStore[sceneEventId];
// Register in-scene placed NetworkObjects with spawn manager
foreach (var keyValuePairByGlobalObjectIdHash in ScenePlacedObjects)
@@ -1910,12 +1969,12 @@ private void OnSessionOwnerLoadedScene(uint sceneEventId, Scene scene)
{
SceneEventType = sceneEventData.SceneEventType,
LoadSceneMode = sceneEventData.LoadSceneMode,
- SceneName = SceneNameFromHash(sceneEventData.SceneHash),
- ClientId = NetworkManager.LocalClientId,
+ SceneName = sceneEventData.SceneAsset,
+ ClientId = NetworkManager.ServerClientId,
Scene = scene,
});
- OnLoadComplete?.Invoke(NetworkManager.LocalClientId, SceneNameFromHash(sceneEventData.SceneHash), sceneEventData.LoadSceneMode);
+ OnLoadComplete?.Invoke(NetworkManager.ServerClientId, sceneEventData.SceneAsset, sceneEventData.LoadSceneMode);
//Second, only if we are a host do we want register having loaded for the associated SceneEventProgress
if (SceneEventProgressTracking.ContainsKey(sceneEventData.SceneEventProgressId) && NetworkManager.IsClient)
@@ -1946,7 +2005,7 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene)
};
var target = NetworkManager.DAHost ? NetworkManager.CurrentSessionOwner : NetworkManager.ServerClientId;
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, target);
- NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, SceneNameFromHash(sceneEventData.SceneHash), size);
+ NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, sceneEventData.SceneAsset, size);
}
else
{
@@ -1969,12 +2028,12 @@ private void OnClientLoadedScene(uint sceneEventId, Scene scene)
{
SceneEventType = SceneEventType.LoadComplete,
LoadSceneMode = sceneEventData.LoadSceneMode,
- SceneName = SceneNameFromHash(sceneEventData.SceneHash),
+ SceneName = sceneEventData.SceneAsset,
ClientId = NetworkManager.LocalClientId,
Scene = scene,
});
- OnLoadComplete?.Invoke(NetworkManager.LocalClientId, SceneNameFromHash(sceneEventData.SceneHash), sceneEventData.LoadSceneMode);
+ OnLoadComplete?.Invoke(NetworkManager.LocalClientId, sceneEventData.SceneAsset, sceneEventData.LoadSceneMode);
EndSceneEvent(sceneEventId);
}
@@ -2036,10 +2095,10 @@ internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingServic
sceneEventData.LoadSceneMode = ClientSynchronizationMode;
var activeScene = SceneManager.GetActiveScene();
sceneEventData.SceneEventType = SceneEventType.Synchronize;
- if (BuildIndexToHash.ContainsKey(activeScene.buildIndex))
- {
- sceneEventData.ActiveSceneHash = BuildIndexToHash[activeScene.buildIndex];
- }
+ // if (BuildIndexToHash.ContainsKey(activeScene.buildIndex))
+ // {
+ // sceneEventData.ActiveSceneHash = BuildIndexToHash[activeScene.buildIndex];
+ // }
// Organize how (and when) we serialize our NetworkObjects
for (int i = 0; i < SceneManager.sceneCount; i++)
@@ -2053,6 +2112,7 @@ internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingServic
continue;
}
+ var sceneHash = scene.name;
if (scene == DontDestroyOnLoadScene)
{
continue;
@@ -2062,11 +2122,11 @@ internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingServic
// If we are the base scene, then we set the root scene index;
if (activeScene == scene)
{
- if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, sceneEventData.LoadSceneMode))
+ if (!ValidateSceneBeforeLoading(sceneHash, sceneEventData.LoadSceneMode))
{
continue;
}
- sceneEventData.SceneHash = SceneHashFromNameOrPath(scene.path);
+ sceneEventData.SceneAsset = scene.name;
// If we are just a normal client, then always use the server scene handle
if (NetworkManager.DistributedAuthorityMode)
@@ -2079,7 +2139,7 @@ internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingServic
sceneEventData.SceneHandle = scene.handle;
}
}
- else if (!ValidateSceneBeforeLoading(scene.buildIndex, scene.name, LoadSceneMode.Additive))
+ else if (!ValidateSceneBeforeLoading(sceneHash, LoadSceneMode.Additive))
{
continue;
}
@@ -2087,11 +2147,11 @@ internal void SynchronizeNetworkObjects(ulong clientId, bool synchronizingServic
// If we are just a normal client and in distributed authority mode, then always use the known server scene handle
if (NetworkManager.DistributedAuthorityMode && !NetworkManager.DAHost)
{
- sceneEventData.AddSceneToSynchronize(SceneHashFromNameOrPath(scene.path), ClientSceneHandleToServerSceneHandle[scene.handle]);
+ sceneEventData.AddSceneToSynchronize(sceneHash, ClientSceneHandleToServerSceneHandle[scene.handle]);
}
else
{
- sceneEventData.AddSceneToSynchronize(SceneHashFromNameOrPath(scene.path), scene.handle);
+ sceneEventData.AddSceneToSynchronize(sceneHash, scene.handle);
}
}
@@ -2136,17 +2196,17 @@ private void OnClientBeginSync(uint sceneEventId)
var sceneEventData = SceneEventDataStore[sceneEventId];
var sceneHash = sceneEventData.GetNextSceneSynchronizationHash();
var sceneHandle = sceneEventData.GetNextSceneSynchronizationHandle();
- var sceneName = SceneNameFromHash(sceneHash);
+ var sceneName = sceneHash;
var activeScene = SceneManager.GetActiveScene();
- var loadSceneMode = sceneHash == sceneEventData.SceneHash ? sceneEventData.LoadSceneMode : LoadSceneMode.Additive;
+ var loadSceneMode = sceneHash == sceneEventData.SceneAsset ? sceneEventData.LoadSceneMode : LoadSceneMode.Additive;
// Store the sceneHandle and hash
sceneEventData.NetworkSceneHandle = sceneHandle;
- sceneEventData.ClientSceneHash = sceneHash;
+ sceneEventData.SceneAsset = sceneHash;
// If this is the beginning of the synchronization event, then send client a notification that synchronization has begun
- if (sceneHash == sceneEventData.SceneHash)
+ if (sceneHash == sceneEventData.SceneAsset)
{
OnSceneEvent?.Invoke(new SceneEvent()
{
@@ -2168,14 +2228,14 @@ private void OnClientBeginSync(uint sceneEventId)
return;
}
- var sceneLoad = (AsyncOperation)null;
+ var sceneLoad = (AsyncOperationHandle)default;
// Determines if the client has the scene to be loaded already loaded, if so will return true and the client will skip loading this scene
// For ClientSynchronizationMode LoadSceneMode.Single, we pass in whether the scene being loaded is the first/primary active scene and if it is already loaded
// it should pass through to post load processing (ClientLoadedSynchronization).
// For ClientSynchronizationMode LoadSceneMode.Additive, if the scene is already loaded or the active scene is the scene to be loaded (does not require it to
// be the initial primary scene) then go ahead and pass through to post load processing (ClientLoadedSynchronization).
- var shouldPassThrough = SceneManagerHandler.ClientShouldPassThrough(sceneName, sceneHash == sceneEventData.SceneHash, ClientSynchronizationMode, NetworkManager);
+ var shouldPassThrough = SceneManagerHandler.ClientShouldPassThrough(sceneName, sceneName == sceneEventData.SceneAsset, ClientSynchronizationMode, NetworkManager);
if (!shouldPassThrough)
{
@@ -2185,7 +2245,9 @@ private void OnClientBeginSync(uint sceneEventId)
SceneEventId = sceneEventId,
OnSceneEventCompleted = ClientLoadedSynchronization
};
+ // Debug.Log($"[NetworkSceneManager] OnClientBeginSync BEGIN SceneManagerHandler.LoadSceneAsync sceneName={sceneName} loadSceneMode={loadSceneMode}");
sceneLoad = SceneManagerHandler.LoadSceneAsync(sceneName, loadSceneMode, sceneEventProgress);
+ // Debug.Log($"[NetworkSceneManager] OnClientBeginSync END SceneManagerHandler.LoadSceneAsync sceneName={sceneName} loadSceneMode={loadSceneMode}");
// Notify local client that a scene load has begun
OnSceneEvent?.Invoke(new SceneEvent()
@@ -2202,7 +2264,7 @@ private void OnClientBeginSync(uint sceneEventId)
else
{
// If so, then pass through
- ClientLoadedSynchronization(sceneEventId);
+ ClientLoadedSynchronization(sceneEventId, sceneName);
}
}
@@ -2211,10 +2273,9 @@ private void OnClientBeginSync(uint sceneEventId)
/// This handles all of the in-scene and dynamically spawned NetworkObject synchronization
///
/// Netcode scene index that was loaded
- private void ClientLoadedSynchronization(uint sceneEventId)
+ private void ClientLoadedSynchronization(uint sceneEventId, string sceneName)
{
var sceneEventData = SceneEventDataStore[sceneEventId];
- var sceneName = SceneNameFromHash(sceneEventData.ClientSceneHash);
var nextScene = SceneManagerHandler.GetSceneFromLoadedScenes(sceneName, NetworkManager);
if (!nextScene.IsValid())
{
@@ -2226,7 +2287,7 @@ private void ClientLoadedSynchronization(uint sceneEventId)
throw new Exception($"Failed to find valid scene internal Unity.Netcode for {nameof(GameObject)}s error!");
}
- var loadSceneMode = (sceneEventData.ClientSceneHash == sceneEventData.SceneHash ? sceneEventData.LoadSceneMode : LoadSceneMode.Additive);
+ var loadSceneMode = (sceneEventData.ClientSceneName == sceneEventData.SceneAsset ? sceneEventData.LoadSceneMode : LoadSceneMode.Additive);
// For now, during a synchronization event, we will make the first scene the "base/master" scene that denotes a "complete scene switch"
if (loadSceneMode == LoadSceneMode.Single)
@@ -2241,6 +2302,8 @@ private void ClientLoadedSynchronization(uint sceneEventId)
throw new Exception($"Server Scene Handle ({sceneEventData.SceneHandle}) already exist! Happened during scene load of {nextScene.name} with Client Handle ({nextScene.handle})");
}
+ Log.Debug(() => $"ClientLoadedSynchronization sceneName={sceneName}");
+
// Apply all in-scene placed NetworkObjects loaded by the scene
PopulateScenePlacedObjects(nextScene, false);
@@ -2248,7 +2311,7 @@ private void ClientLoadedSynchronization(uint sceneEventId)
var responseSceneEventData = BeginSceneEvent();
responseSceneEventData.LoadSceneMode = loadSceneMode;
responseSceneEventData.SceneEventType = SceneEventType.LoadComplete;
- responseSceneEventData.SceneHash = sceneEventData.ClientSceneHash;
+ responseSceneEventData.SceneAsset = sceneEventData.ClientSceneName;
var target = NetworkManager.ServerClientId;
if (NetworkManager.DistributedAuthorityMode)
@@ -2308,12 +2371,12 @@ private void SynchronizeNetworkObjectScene()
if (ScenesLoaded.ContainsKey(networkObject.SceneOriginHandle))
{
var scene = ScenesLoaded[networkObject.SceneOriginHandle];
- if (scene == DontDestroyOnLoadScene)
+ if (scene.SceneReference == DontDestroyOnLoadScene)
{
Debug.Log($"{networkObject.gameObject.name} migrating into DDOL!");
}
- SceneManager.MoveGameObjectToScene(networkObject.gameObject, scene);
+ SceneManager.MoveGameObjectToScene(networkObject.gameObject, scene.SceneReference);
}
else if (NetworkManager.LogLevel <= LogLevel.Normal)
{
@@ -2337,13 +2400,10 @@ private void HandleClientSceneEvent(uint sceneEventId)
{
case SceneEventType.ActiveSceneChanged:
{
- if (HashToBuildIndex.ContainsKey(sceneEventData.ActiveSceneHash))
+ var scene = SceneManager.GetSceneByName(sceneEventData.ClientSceneName);
+ if (scene.isLoaded)
{
- var scene = SceneManager.GetSceneByBuildIndex(HashToBuildIndex[sceneEventData.ActiveSceneHash]);
- if (scene.isLoaded)
- {
- SceneManager.SetActiveScene(scene);
- }
+ SceneManager.SetActiveScene(scene);
}
EndSceneEvent(sceneEventId);
break;
@@ -2371,17 +2431,16 @@ private void HandleClientSceneEvent(uint sceneEventId)
}
else
{
+ Log.Debug(() => $"SceneEventType.Synchronize sceneName={sceneEventData.ClientSceneName}");
+
// Include anything in the DDOL scene
PopulateScenePlacedObjects(DontDestroyOnLoadScene, false);
// If needed, set the currently active scene
- if (HashToBuildIndex.ContainsKey(sceneEventData.ActiveSceneHash))
+ var targetActiveScene = SceneManager.GetSceneByName(sceneEventData.ClientSceneName);
+ if (targetActiveScene.isLoaded && targetActiveScene.handle != SceneManager.GetActiveScene().handle)
{
- var targetActiveScene = SceneManager.GetSceneByBuildIndex(HashToBuildIndex[sceneEventData.ActiveSceneHash]);
- if (targetActiveScene.isLoaded && targetActiveScene.handle != SceneManager.GetActiveScene().handle)
- {
- SceneManager.SetActiveScene(targetActiveScene);
- }
+ SceneManager.SetActiveScene(targetActiveScene);
}
// Spawn and Synchronize all NetworkObjects
@@ -2412,7 +2471,7 @@ private void HandleClientSceneEvent(uint sceneEventId)
};
var target = NetworkManager.DAHost ? NetworkManager.CurrentSessionOwner : NetworkManager.ServerClientId;
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, target);
- NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, SceneNameFromHash(sceneEventData.SceneHash), size);
+ NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, sceneEventData.SceneAsset, size);
}
}
else
@@ -2425,7 +2484,7 @@ private void HandleClientSceneEvent(uint sceneEventId)
};
var target = NetworkManager.DAHost ? NetworkManager.CurrentSessionOwner : NetworkManager.ServerClientId;
var size = NetworkManager.ConnectionManager.SendMessage(ref message, k_DeliveryType, target);
- NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, SceneNameFromHash(sceneEventData.SceneHash), size);
+ NetworkManager.NetworkMetrics.TrackSceneEventSent(target, (uint)sceneEventData.SceneEventType, sceneEventData.SceneAsset, size);
}
}
else
@@ -2506,7 +2565,7 @@ private void HandleClientSceneEvent(uint sceneEventId)
{
SceneEventType = sceneEventData.SceneEventType,
LoadSceneMode = sceneEventData.LoadSceneMode,
- SceneName = SceneNameFromHash(sceneEventData.SceneHash),
+ SceneName = sceneEventData.SceneAsset,
ClientId = NetworkManager.ServerClientId,
ClientsThatCompleted = sceneEventData.ClientsCompleted,
ClientsThatTimedOut = sceneEventData.ClientsTimedOut,
@@ -2514,11 +2573,11 @@ private void HandleClientSceneEvent(uint sceneEventId)
if (sceneEventData.SceneEventType == SceneEventType.LoadEventCompleted)
{
- OnLoadEventCompleted?.Invoke(SceneNameFromHash(sceneEventData.SceneHash), sceneEventData.LoadSceneMode, sceneEventData.ClientsCompleted, sceneEventData.ClientsTimedOut);
+ OnLoadEventCompleted?.Invoke(sceneEventData.SceneAsset, sceneEventData.LoadSceneMode, sceneEventData.ClientsCompleted, sceneEventData.ClientsTimedOut);
}
else
{
- OnUnloadEventCompleted?.Invoke(SceneNameFromHash(sceneEventData.SceneHash), sceneEventData.LoadSceneMode, sceneEventData.ClientsCompleted, sceneEventData.ClientsTimedOut);
+ OnUnloadEventCompleted?.Invoke(sceneEventData.SceneAsset, sceneEventData.LoadSceneMode, sceneEventData.ClientsCompleted, sceneEventData.ClientsTimedOut);
}
EndSceneEvent(sceneEventId);
@@ -2549,11 +2608,11 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId)
{
SceneEventType = sceneEventData.SceneEventType,
LoadSceneMode = sceneEventData.LoadSceneMode,
- SceneName = SceneNameFromHash(sceneEventData.SceneHash),
+ SceneName = sceneEventData.SceneAsset,
ClientId = clientId
});
- OnLoadComplete?.Invoke(clientId, SceneNameFromHash(sceneEventData.SceneHash), sceneEventData.LoadSceneMode);
+ OnLoadComplete?.Invoke(clientId, sceneEventData.SceneAsset, sceneEventData.LoadSceneMode);
if (SceneEventProgressTracking.ContainsKey(sceneEventData.SceneEventProgressId))
{
@@ -2573,11 +2632,11 @@ private void HandleSessionOwnerEvent(uint sceneEventId, ulong clientId)
{
SceneEventType = sceneEventData.SceneEventType,
LoadSceneMode = sceneEventData.LoadSceneMode,
- SceneName = SceneNameFromHash(sceneEventData.SceneHash),
+ SceneName = sceneEventData.SceneAsset,
ClientId = clientId
});
- OnUnloadComplete?.Invoke(clientId, SceneNameFromHash(sceneEventData.SceneHash));
+ OnUnloadComplete?.Invoke(clientId, sceneEventData.SceneAsset);
EndSceneEvent(sceneEventId);
break;
@@ -2772,7 +2831,7 @@ internal void HandleSceneEvent(ulong clientId, FastBufferReader reader)
}
NetworkManager.NetworkMetrics.TrackSceneEventReceived(
- clientId, (uint)sceneEventData.SceneEventType, SceneNameFromHash(sceneEventData.SceneHash), reader.Length);
+ clientId, (uint)sceneEventData.SceneEventType, sceneEventData.SceneAsset, reader.Length);
if (sceneEventData.IsSceneEventClientSide())
{
@@ -2839,11 +2898,23 @@ internal void MoveObjectsToDontDestroyOnLoad()
// Only move dynamically spawned NetworkObjects with no parent as the children will follow
if (networkObject.gameObject.transform.parent == null && networkObject.IsSceneObject != null && !networkObject.IsSceneObject.Value)
{
- UnityEngine.Object.DontDestroyOnLoad(networkObject.gameObject);
- // When temporarily migrating to the DDOL, adjust the network and origin scene handles so no messages are generated
- // about objects being moved to a new scene.
- networkObject.NetworkSceneHandle = ClientSceneHandleToServerSceneHandle[networkObject.gameObject.scene.handle];
- networkObject.SceneOriginHandle = networkObject.gameObject.scene.handle;
+ try
+ {
+ Object.DontDestroyOnLoad(networkObject.gameObject);
+ // When temporarily migrating to the DDOL, adjust the network and origin scene handles so no messages are generated
+ // about objects being moved to a new scene.
+ networkObject.NetworkSceneHandle = ClientSceneHandleToServerSceneHandle[networkObject.gameObject.scene.handle];
+ networkObject.SceneOriginHandle = networkObject.gameObject.scene.handle;
+ }
+ catch (Exception e)
+ {
+ string allEntities = "";
+ foreach (var kvp in ClientSceneHandleToServerSceneHandle)
+ {
+ allEntities += $"{kvp.Key}={kvp.Value},";
+ }
+ Log.Error(() => $"Failed to move object={networkObject} to DDOL [{allEntities}] e={e}");
+ }
}
}
else if (networkObject.HasAuthority)
@@ -2865,6 +2936,7 @@ internal void MoveObjectsToDontDestroyOnLoad()
///
internal void PopulateScenePlacedObjects(Scene sceneToFilterBy, bool clearScenePlacedObjects = true)
{
+ Log.Debug(() => $"PopulateScenePlacedObjects Scene={sceneToFilterBy.name} clearScenePlacedObjects={clearScenePlacedObjects}");
if (clearScenePlacedObjects)
{
ScenePlacedObjects.Clear();
@@ -2884,6 +2956,7 @@ internal void PopulateScenePlacedObjects(Scene sceneToFilterBy, bool clearSceneP
{
var globalObjectIdHash = networkObjectInstance.GlobalObjectIdHash;
var sceneHandle = networkObjectInstance.gameObject.scene.handle;
+ Log.Debug(() => $"PopulateScenePlacedObjects object={networkObjectInstance.gameObject} sceneHandle={sceneHandle} hash={globalObjectIdHash}");
// We check to make sure the NetworkManager instance is the same one to be "NetcodeIntegrationTestHelpers" compatible and filter the list on a per scene basis (for additive scenes)
if (networkObjectInstance.IsSceneObject != false && (networkObjectInstance.NetworkManager == NetworkManager ||
networkObjectInstance.NetworkManagerOwner == null) && sceneHandle == sceneToFilterBy.handle)
@@ -2899,9 +2972,11 @@ internal void PopulateScenePlacedObjects(Scene sceneToFilterBy, bool clearSceneP
}
else
{
+ Log.Error(() => $"Duplicate hash ids from object={ScenePlacedObjects[globalObjectIdHash][sceneHandle].gameObject.NetworkGetScenePath()}");
var exitingEntryName = ScenePlacedObjects[globalObjectIdHash][sceneHandle] != null ? ScenePlacedObjects[globalObjectIdHash][sceneHandle].name : "Null Entry";
- throw new Exception($"{networkObjectInstance.name} tried to registered with {nameof(ScenePlacedObjects)} which already contains " +
+ string expStr = ($"{networkObjectInstance.name} tried to registered with {nameof(ScenePlacedObjects)} which already contains " +
$"the same {nameof(NetworkObject.GlobalObjectIdHash)} value {globalObjectIdHash} for {exitingEntryName}!");
+ Log.Error(() => expStr);
}
}
}
@@ -3029,7 +3104,7 @@ internal void NotifyNetworkObjectSceneChanged(NetworkObject networkObject)
/// or invoked by when a client finishes
/// synchronization.
///
- internal void MigrateNetworkObjectsIntoScenes()
+ public void MigrateNetworkObjectsIntoScenes()
{
try
{
@@ -3049,9 +3124,9 @@ internal void MigrateNetworkObjectsIntoScenes()
var scene = ScenesLoaded[clientSceneHandle];
foreach (var networkObject in ownerEntry.Value)
{
- SceneManager.MoveGameObjectToScene(networkObject.gameObject, scene);
+ SceneManager.MoveGameObjectToScene(networkObject.gameObject, scene.SceneReference);
networkObject.NetworkSceneHandle = sceneEntry.Key;
- networkObject.SceneOriginHandle = scene.handle;
+ networkObject.SceneOriginHandle = scene.SceneReference.handle;
}
}
}
@@ -3280,7 +3355,7 @@ public List GetSceneMapping(MapTypes mapType)
{
foreach (var entry in ServerSceneHandleToClientSceneHandle)
{
- var scene = ScenesLoaded[entry.Value];
+ var scene = ScenesLoaded[entry.Value].SceneReference;
var sceneIsPresent = scene.IsValid() && scene.isLoaded;
var sceneMap = new SceneMap()
{
@@ -3299,7 +3374,7 @@ public List GetSceneMapping(MapTypes mapType)
{
foreach (var entry in ClientSceneHandleToServerSceneHandle)
{
- var scene = ScenesLoaded[entry.Key];
+ var scene = ScenesLoaded[entry.Key].SceneReference;
var sceneIsPresent = scene.IsValid() && scene.isLoaded;
var sceneMap = new SceneMap()
{
diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs
index 943f54aff2..d0eff4ee43 100644
--- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs
+++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventData.cs
@@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using Unity.Collections;
+using UnityEngine;
using UnityEngine.SceneManagement;
namespace Unity.Netcode
@@ -105,12 +106,12 @@ internal class SceneEventData : IDisposable
internal ForceNetworkSerializeByMemcpy SceneEventProgressId;
internal uint SceneEventId;
- internal uint ActiveSceneHash;
- internal uint SceneHash;
+ internal string ActiveSceneAsset;
+ internal string SceneAsset;
internal int SceneHandle;
// Used by the client during synchronization
- internal uint ClientSceneHash;
+ internal string ClientSceneName;
internal int NetworkSceneHandle;
/// Only used for scene events, this assures permissions when writing
@@ -150,7 +151,7 @@ internal class SceneEventData : IDisposable
internal List ClientsCompleted;
internal List ClientsTimedOut;
- internal Queue ScenesToSynchronize;
+ internal Queue ScenesToSynchronize;
internal Queue SceneHandlesToSynchronize;
internal LoadSceneMode ClientSynchronizationMode;
@@ -170,7 +171,7 @@ internal class SceneEventData : IDisposable
///
///
///
- internal void AddSceneToSynchronize(uint sceneHash, int sceneHandle)
+ internal void AddSceneToSynchronize(string sceneHash, int sceneHandle)
{
ScenesToSynchronize.Enqueue(sceneHash);
SceneHandlesToSynchronize.Enqueue((uint)sceneHandle);
@@ -181,7 +182,7 @@ internal void AddSceneToSynchronize(uint sceneHash, int sceneHandle)
/// Gets the next scene hash to be loaded for approval and/or late joining
///
///
- internal uint GetNextSceneSynchronizationHash()
+ internal string GetNextSceneSynchronizationHash()
{
return ScenesToSynchronize.Dequeue();
}
@@ -232,7 +233,7 @@ internal void InitializeForSynch()
if (ScenesToSynchronize == null)
{
- ScenesToSynchronize = new Queue();
+ ScenesToSynchronize = new Queue();
}
else
{
@@ -491,7 +492,7 @@ internal void Serialize(FastBufferWriter writer)
if (SceneEventType == SceneEventType.ActiveSceneChanged)
{
- writer.WriteValueSafe(ActiveSceneHash);
+ writer.WriteValueSafe(ActiveSceneAsset);
return;
}
@@ -515,15 +516,21 @@ internal void Serialize(FastBufferWriter writer)
}
// Write the scene index and handle
- writer.WriteValueSafe(SceneHash);
+ var sceneName = SceneAsset ?? "";
+ writer.WriteValueSafe(sceneName);
writer.WriteValueSafe(SceneHandle);
switch (SceneEventType)
{
case SceneEventType.Synchronize:
{
- writer.WriteValueSafe(ActiveSceneHash);
+ if (ActiveSceneAsset == null)
+ {
+ Debug.LogError($"Synchronizing - ActiveSceneAsset but it hasn't been initialized yet");
+ ActiveSceneAsset = "";
+ }
+ writer.WriteValueSafe(ActiveSceneAsset);
WriteSceneSynchronizationData(writer);
if (EnableSerializationLogs)
@@ -582,7 +589,13 @@ internal void WriteSceneSynchronizationData(FastBufferWriter writer)
builder.AppendLine($"[Write][Synchronize-Start][WPos: {writer.Position}] Begin:");
}
// Write the scenes we want to load, in the order we want to load them
- writer.WriteValueSafe(ScenesToSynchronize.ToArray());
+ var valArray = ScenesToSynchronize.ToArray();
+ writer.WriteValueSafe(valArray.Length);
+ foreach (var v in valArray)
+ {
+ writer.WriteValueSafe(v);
+ }
+
writer.WriteValueSafe(SceneHandlesToSynchronize.ToArray());
// Store our current position in the stream to come back and say how much data we have written
var positionStart = writer.Position;
@@ -737,7 +750,7 @@ internal void Deserialize(FastBufferReader reader)
if (SceneEventType == SceneEventType.ActiveSceneChanged)
{
- reader.ReadValueSafe(out ActiveSceneHash);
+ reader.ReadValueSafe(out ActiveSceneAsset);
return;
}
@@ -767,14 +780,14 @@ internal void Deserialize(FastBufferReader reader)
reader.ReadValueSafe(out ClientSynchronizationMode);
}
- reader.ReadValueSafe(out SceneHash);
+ reader.ReadValueSafe(out SceneAsset);
reader.ReadValueSafe(out SceneHandle);
switch (SceneEventType)
{
case SceneEventType.Synchronize:
{
- reader.ReadValueSafe(out ActiveSceneHash);
+ reader.ReadValueSafe(out ActiveSceneAsset);
if (EnableSerializationLogs)
{
LogArray(reader.ToArray(), 0, reader.Length);
@@ -824,9 +837,15 @@ internal void Deserialize(FastBufferReader reader)
internal void CopySceneSynchronizationData(FastBufferReader reader)
{
m_NetworkObjectsSync.Clear();
- reader.ReadValueSafe(out uint[] scenesToSynchronize);
+ reader.ReadValueSafe(out int sceneCount);
+ ScenesToSynchronize = new Queue();
+ for (int i = 0; i < sceneCount; i++)
+ {
+ reader.ReadValueSafe(out string s);
+ ScenesToSynchronize.Enqueue(s);
+ }
+
reader.ReadValueSafe(out uint[] sceneHandlesToSynchronize);
- ScenesToSynchronize = new Queue(scenesToSynchronize);
SceneHandlesToSynchronize = new Queue(sceneHandlesToSynchronize);
// is not packed!
diff --git a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventProgress.cs b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventProgress.cs
index e9b52a218e..5b1858b362 100644
--- a/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventProgress.cs
+++ b/com.unity.netcode.gameobjects/Runtime/SceneManagement/SceneEventProgress.cs
@@ -1,7 +1,11 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Threading.Tasks;
+using TrollKing.Core;
using UnityEngine;
+using UnityEngine.ResourceManagement.AsyncOperations;
+using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
using AsyncOperation = UnityEngine.AsyncOperation;
@@ -65,8 +69,10 @@ public enum SceneEventProgressStatus
/// Server side only:
/// This tracks the progress of clients during a load or unload scene event
///
- internal class SceneEventProgress
+ public class SceneEventProgress
{
+ private static NetworkLogScope Log = new NetworkLogScope(nameof(SceneEventProgress));
+
///
/// List of clientIds of those clients that is done loading the scene.
///
@@ -81,14 +87,14 @@ internal class SceneEventProgress
///
/// Delegate type for when the switch scene progress is completed. Either by all clients done loading the scene or by time out.
///
- internal delegate bool OnCompletedDelegate(SceneEventProgress sceneEventProgress);
+ public delegate bool OnCompletedDelegate(SceneEventProgress sceneEventProgress);
///
/// The callback invoked when the switch scene progress is completed. Either by all clients done loading the scene or by time out.
///
- internal OnCompletedDelegate OnComplete;
+ public OnCompletedDelegate OnComplete;
- internal Action OnSceneEventCompleted;
+ public Action OnSceneEventCompleted;
///
/// This will make sure that we only have timed out if we never completed
@@ -101,17 +107,17 @@ internal bool HasTimedOut()
///
/// The hash value generated from the full scene path
///
- internal uint SceneHash { get; set; }
+ internal string SceneName { get; set; }
internal Guid Guid { get; } = Guid.NewGuid();
internal uint SceneEventId;
private Coroutine m_TimeOutCoroutine;
- private AsyncOperation m_AsyncOperation;
+ private AsyncOperationHandle m_AsyncOperation;
private NetworkManager m_NetworkManager { get; }
- internal SceneEventProgressStatus Status { get; set; }
+ public SceneEventProgressStatus Status { get; set; }
internal SceneEventType SceneEventType { get; set; }
@@ -124,7 +130,7 @@ internal List GetClientsWithStatus(bool completedSceneEvent)
{
// If we are the host, then add the host-client to the list
// of clients that completed if the AsyncOperation is done.
- if (m_NetworkManager.IsHost && m_AsyncOperation.isDone)
+ if (m_NetworkManager.IsHost && m_AsyncOperation.IsDone)
{
clients.Add(m_NetworkManager.LocalClientId);
}
@@ -143,7 +149,7 @@ internal List GetClientsWithStatus(bool completedSceneEvent)
// If we are the host, then add the host-client to the list
// of clients that did not complete if the AsyncOperation is
// not done.
- if (m_NetworkManager.IsHost && !m_AsyncOperation.isDone)
+ if (m_NetworkManager.IsHost && !m_AsyncOperation.IsDone)
{
clients.Add(m_NetworkManager.LocalClientId);
}
@@ -254,22 +260,65 @@ private bool HasFinished()
// Note: Integration tests process scene loading through a queue
// and the AsyncOperation could not be assigned for several
// network tick periods. Return false if that is the case.
- return m_AsyncOperation == null ? false : m_AsyncOperation.isDone;
+
+ // If we're async loading a scene that we tell not to activate, we need to check that the downstream scene has been activated before calling out
+ var initialValid = m_AsyncOperation.IsValid() && m_AsyncOperation.IsDone;
+ if (initialValid)
+ {
+ var res = m_AsyncOperation.Result;
+ return res.Scene.isLoaded;
+ }
+
+ return false;
+ }
+
+ public AsyncOperationHandle GetHandle()
+ {
+ return m_AsyncOperation;
}
///
/// Sets the AsyncOperation for the scene load/unload event
///
- internal void SetAsyncOperation(AsyncOperation asyncOperation)
+ public void SetAsyncOperation(AsyncOperationHandle asyncOperation)
{
+ if (!asyncOperation.IsValid())
+ {
+ Log.Error(() => $"Async Operation handle is invalid!");
+ return;
+ }
+
+ // Debug.Log($"[SceneEventProgress] SetAsyncOperation ");
m_AsyncOperation = asyncOperation;
- m_AsyncOperation.completed += new Action(asyncOp2 =>
+ m_AsyncOperation.Completed += new Action>(asyncOp2 =>
{
// Don't invoke the callback if the network session is disconnected
// during a SceneEventProgress
- if (IsNetworkSessionActive())
+ if (asyncOp2.Status == AsyncOperationStatus.Succeeded)
+ {
+ var sceneInstance = asyncOp2.Result;
+ if (!sceneInstance.Scene.isLoaded)
+ {
+ var asyncLoad = sceneInstance.ActivateAsync();
+ asyncLoad.completed += operation =>
+ {
+ if (IsNetworkSessionActive())
+ {
+ OnSceneEventCompleted?.Invoke(SceneEventId, asyncOp2.Result.Scene.name);
+ }
+ };
+ }
+ else
+ {
+ if (IsNetworkSessionActive())
+ {
+ OnSceneEventCompleted?.Invoke(SceneEventId, asyncOp2.Result.Scene.name);
+ }
+ }
+ }
+ else
{
- OnSceneEventCompleted?.Invoke(SceneEventId);
+ Debug.LogError($"Failed to load async scene: {asyncOp2.OperationException}");
}
// Go ahead and try finishing even if the network session is terminated/terminating
diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs
index fe0dd270e9..3b39eb8938 100644
--- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkPrefabHandler.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using TrollKing.Core;
using UnityEngine;
namespace Unity.Netcode
@@ -50,6 +51,8 @@ public interface INetworkPrefabInstanceHandler
///
public class NetworkPrefabHandler
{
+ private static readonly NetworkLogScope k_Log = new NetworkLogScope(nameof(NetworkPrefabHandler));
+
private NetworkManager m_NetworkManager;
///
@@ -315,7 +318,12 @@ public GameObject GetNetworkPrefabOverride(GameObject gameObject)
case NetworkPrefabOverride.Hash:
case NetworkPrefabOverride.Prefab:
{
- return m_NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks[networkObject.GlobalObjectIdHash].OverridingTargetPrefab;
+ var res = m_NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks[networkObject.GlobalObjectIdHash].OverridingTargetPrefab;
+ k_Log.Debug(() => $"NetworkPrefabHandler GetNetworkPrefabOverride [gameObject={gameObject.name}] [networkPrefab={networkObject.GlobalObjectIdHash}]" +
+ $"[overrideType={m_NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks[networkObject.GlobalObjectIdHash].Override}]" +
+ $"[overrideObj={m_NetworkManager.NetworkConfig.Prefabs.NetworkPrefabOverrideLinks[networkObject.GlobalObjectIdHash].OverridingTargetPrefab}]");
+
+ return res;
}
}
}
@@ -360,12 +368,18 @@ public void AddNetworkPrefab(GameObject prefab)
var networkPrefab = new NetworkPrefab { Prefab = prefab };
bool added = m_NetworkManager.NetworkConfig.Prefabs.Add(networkPrefab);
+ k_Log.Debug(() => $"NetworkPrefabHandler AddNetworkPrefab prefab={prefab.name} hash={networkObject.GlobalObjectIdHash}");
if (m_NetworkManager.IsListening && added)
{
m_NetworkManager.DeferredMessageManager.ProcessTriggers(IDeferredNetworkMessageManager.TriggerType.OnAddPrefab, networkObject.GlobalObjectIdHash);
}
}
+ public IReadOnlyList GetPrefabs()
+ {
+ return m_NetworkManager.NetworkConfig.Prefabs.Prefabs;
+ }
+
///
/// Remove a prefab from the prefab list.
/// As with AddNetworkPrefab, this is specific to the client it's called on -
@@ -406,6 +420,7 @@ internal void RegisterPlayerPrefab()
//In the event there is no NetworkPrefab entry (i.e. no override for default player prefab)
if (!networkConfig.Prefabs.NetworkPrefabOverrideLinks.ContainsKey(playerPrefabNetworkObject.GlobalObjectIdHash))
{
+ k_Log.Debug(() => $"[NetworkPrefabHandler] RegisterPlayerPrefab - PlayerPrefab={networkConfig.PlayerPrefab.name} hash={playerPrefabNetworkObject.GlobalObjectIdHash}");
//Then add a new entry for the player prefab
AddNetworkPrefab(networkConfig.PlayerPrefab);
}
diff --git a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs
index 19227c82ba..86a116ee0d 100644
--- a/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs
+++ b/com.unity.netcode.gameobjects/Runtime/Spawning/NetworkSpawnManager.cs
@@ -4,6 +4,7 @@
using System.Linq;
using System.Text;
using UnityEngine;
+using TrollKing.Core;
namespace Unity.Netcode
{
@@ -12,6 +13,7 @@ namespace Unity.Netcode
///
public class NetworkSpawnManager
{
+ private static readonly NetworkLogScope Log = new NetworkLogScope(nameof(NetworkSpawnManager));
// Stores the objects that need to be shown at end-of-frame
internal Dictionary> ObjectsToShowToClient = new Dictionary>();
@@ -1512,12 +1514,14 @@ internal void ServerSpawnSceneObjectsOnStartSweep()
}
}
+ Log.Info(() => "ServerSpawnSceneObjectsOnStartSweep");
+
// Since we are spawing in-scene placed NetworkObjects for already loaded scenes,
// we need to add any in-scene placed NetworkObject to our tracking table
var clearFirst = true;
foreach (var sceneLoaded in NetworkManager.SceneManager.ScenesLoaded)
{
- NetworkManager.SceneManager.PopulateScenePlacedObjects(sceneLoaded.Value, clearFirst);
+ NetworkManager.SceneManager.PopulateScenePlacedObjects(sceneLoaded.Value.SceneReference, clearFirst);
clearFirst = false;
}
diff --git a/com.unity.netcode.gameobjects/Runtime/com.unity.netcode.runtime.asmdef b/com.unity.netcode.gameobjects/Runtime/com.unity.netcode.runtime.asmdef
index d68a562768..ba65fbd7f2 100644
--- a/com.unity.netcode.gameobjects/Runtime/com.unity.netcode.runtime.asmdef
+++ b/com.unity.netcode.gameobjects/Runtime/com.unity.netcode.runtime.asmdef
@@ -13,7 +13,9 @@
"Unity.Networking.Transport",
"Unity.Collections",
"Unity.Burst",
- "Unity.Mathematics"
+ "Unity.Mathematics",
+ "Unity.ResourceManager",
+ "Unity.Addressables"
],
"includePlatforms": [],
"excludePlatforms": [],
diff --git a/com.unity.netcode.gameobjects/Samples~/Bootstrap/Prefabs/BootstrapPlayer.prefab b/com.unity.netcode.gameobjects/Samples~/Bootstrap/Prefabs/BootstrapPlayer.prefab
index 5b7b44713f..34fd335d94 100644
--- a/com.unity.netcode.gameobjects/Samples~/Bootstrap/Prefabs/BootstrapPlayer.prefab
+++ b/com.unity.netcode.gameobjects/Samples~/Bootstrap/Prefabs/BootstrapPlayer.prefab
@@ -29,12 +29,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3439633038736912633}
+ serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
- m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &3439633038736913157
MeshFilter:
@@ -55,11 +56,15 @@ MeshRenderer:
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
+ m_RayTracingAccelStructBuildFlagsOverride: 0
+ m_RayTracingAccelStructBuildFlags: 1
+ m_SmallMeshCulling: 1
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
@@ -93,9 +98,17 @@ SphereCollider:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3439633038736912633}
m_Material: {fileID: 0}
+ m_IncludeLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ m_ExcludeLayers:
+ serializedVersion: 2
+ m_Bits: 0
+ m_LayerOverridePriority: 0
m_IsTrigger: 0
+ m_ProvidesContacts: 0
m_Enabled: 1
- serializedVersion: 2
+ serializedVersion: 3
m_Radius: 0.5
m_Center: {x: 0, y: 0, z: 0}
--- !u!114 &3439633038736912634
@@ -110,8 +123,12 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
- GlobalObjectIdHash: 951099334
+ GlobalObjectIdHash: 2131729030
AlwaysReplicateAsRoot: 0
+ SynchronizeTransform: 1
+ ActiveSceneSynchronization: 0
+ SceneMigrationSynchronization: 1
+ SpawnWithObservers: 1
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
--- !u!114 &2776227185612554462
@@ -138,9 +155,12 @@ MonoBehaviour:
PositionThreshold: 0
RotAngleThreshold: 0
ScaleThreshold: 0
+ UseQuaternionSynchronization: 0
+ UseQuaternionCompression: 0
+ UseHalfFloatPrecision: 0
InLocalSpace: 0
Interpolate: 1
- FixedSendsPerSecond: 30
+ SlerpPosition: 0
--- !u!114 &6046305264893698362
MonoBehaviour:
m_ObjectHideFlags: 0
diff --git a/com.unity.netcode.gameobjects/TestHelpers/Runtime/IntegrationTestSceneHandler.cs b/com.unity.netcode.gameobjects/TestHelpers/Runtime/IntegrationTestSceneHandler.cs
index a023bc1d65..a97454a5d3 100644
--- a/com.unity.netcode.gameobjects/TestHelpers/Runtime/IntegrationTestSceneHandler.cs
+++ b/com.unity.netcode.gameobjects/TestHelpers/Runtime/IntegrationTestSceneHandler.cs
@@ -3,6 +3,9 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
+using UnityEngine.AddressableAssets;
+using UnityEngine.ResourceManagement.AsyncOperations;
+using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
@@ -59,7 +62,7 @@ public enum JobTypes
}
public JobTypes JobType;
public string SceneName;
- public Scene Scene;
+ public SceneInstance Scene;
public SceneEventProgress SceneEventProgress;
public IntegrationTestSceneHandler IntegrationTestSceneHandler;
}
@@ -118,7 +121,8 @@ internal static IEnumerator ProcessLoadingSceneJob(QueuedSceneJob queuedSceneJob
SceneManager.sceneLoaded += SceneManager_sceneLoaded;
// We always load additively for all scenes during integration tests
- var asyncOperation = SceneManager.LoadSceneAsync(queuedSceneJob.SceneName, LoadSceneMode.Additive);
+ var asyncOperation = Addressables.LoadSceneAsync(queuedSceneJob.SceneName, LoadSceneMode.Additive);
+
queuedSceneJob.SceneEventProgress.SetAsyncOperation(asyncOperation);
// Wait for it to finish
@@ -208,9 +212,9 @@ internal static IEnumerator ProcessUnloadingSceneJob(QueuedSceneJob queuedSceneJ
}
SceneManager.sceneUnloaded += SceneManager_sceneUnloaded;
- if (queuedSceneJob.Scene.IsValid() && queuedSceneJob.Scene.isLoaded && !queuedSceneJob.Scene.name.Contains(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName))
+ if (queuedSceneJob.Scene.Scene.IsValid() && queuedSceneJob.Scene.Scene.isLoaded && !queuedSceneJob.Scene.Scene.name.Contains(NetcodeIntegrationTestHelpers.FirstPartOfTestRunnerSceneName))
{
- var asyncOperation = SceneManager.UnloadSceneAsync(queuedSceneJob.Scene);
+ var asyncOperation = Addressables.UnloadSceneAsync(queuedSceneJob.Scene);
queuedSceneJob.SceneEventProgress.SetAsyncOperation(asyncOperation);
}
else
@@ -230,7 +234,7 @@ internal static IEnumerator ProcessUnloadingSceneJob(QueuedSceneJob queuedSceneJ
///
private static void SceneManager_sceneUnloaded(Scene scene)
{
- if (CurrentQueuedSceneJob.JobType != QueuedSceneJob.JobTypes.Completed && CurrentQueuedSceneJob.Scene.name == scene.name)
+ if (CurrentQueuedSceneJob.JobType != QueuedSceneJob.JobTypes.Completed && CurrentQueuedSceneJob.Scene.Scene.name == scene.name)
{
SceneManager.sceneUnloaded -= SceneManager_sceneUnloaded;
@@ -280,15 +284,15 @@ private void AddJobToQueue(QueuedSceneJob queuedSceneJob)
///
/// Server always loads like it normally would
///
- public AsyncOperation GenericLoadSceneAsync(string sceneName, LoadSceneMode loadSceneMode, SceneEventProgress sceneEventProgress)
+ public AsyncOperationHandle GenericLoadSceneAsync(string sceneName, LoadSceneMode loadSceneMode, SceneEventProgress sceneEventProgress)
{
m_ServerSceneBeingLoaded = sceneName;
if (NetcodeIntegrationTest.IsRunning)
{
SceneManager.sceneLoaded += Sever_SceneLoaded;
}
- var operation = SceneManager.LoadSceneAsync(sceneName, loadSceneMode);
- sceneEventProgress.SetAsyncOperation(operation);
+ var operation = Addressables.LoadSceneAsync(sceneName, loadSceneMode);
+ // sceneEventProgress.SetAsyncOperation(operation);
return operation;
}
@@ -304,42 +308,42 @@ private void Sever_SceneLoaded(Scene scene, LoadSceneMode arg1)
///
/// Server always unloads like it normally would
///
- public AsyncOperation GenericUnloadSceneAsync(Scene scene, SceneEventProgress sceneEventProgress)
+ public AsyncOperationHandle GenericUnloadSceneAsync(SceneInstance scene, SceneEventProgress sceneEventProgress)
{
- var operation = SceneManager.UnloadSceneAsync(scene);
+ var operation = Addressables.UnloadSceneAsync(scene);
sceneEventProgress.SetAsyncOperation(operation);
return operation;
}
- public AsyncOperation LoadSceneAsync(string sceneName, LoadSceneMode loadSceneMode, SceneEventProgress sceneEventProgress)
+ public AsyncOperationHandle LoadSceneAsync(string sceneAssetKey, LoadSceneMode loadSceneMode, SceneEventProgress sceneEventProgress)
{
// Server and non NetcodeIntegrationTest tests use the generic load scene method
if (!NetcodeIntegrationTest.IsRunning)
{
- return GenericLoadSceneAsync(sceneName, loadSceneMode, sceneEventProgress);
+ return GenericLoadSceneAsync(sceneAssetKey, loadSceneMode, sceneEventProgress);
}
else // NetcodeIntegrationTest Clients always get added to the jobs queue
{
- AddJobToQueue(new QueuedSceneJob() { IntegrationTestSceneHandler = this, SceneName = sceneName, SceneEventProgress = sceneEventProgress, JobType = QueuedSceneJob.JobTypes.Loading });
+ AddJobToQueue(new QueuedSceneJob() { IntegrationTestSceneHandler = this, SceneName = sceneAssetKey, SceneEventProgress = sceneEventProgress, JobType = QueuedSceneJob.JobTypes.Loading });
}
- return null;
+ return default;
}
- public AsyncOperation UnloadSceneAsync(Scene scene, SceneEventProgress sceneEventProgress)
+ public AsyncOperationHandle UnloadSceneAsync(NetworkSceneManager.SceneData scene, SceneEventProgress sceneEventProgress)
{
// Server and non NetcodeIntegrationTest tests use the generic unload scene method
if (!NetcodeIntegrationTest.IsRunning)
{
- return GenericUnloadSceneAsync(scene, sceneEventProgress);
+ return GenericUnloadSceneAsync(scene.SceneInstance.Value, sceneEventProgress);
}
else // NetcodeIntegrationTest Clients always get added to the jobs queue
{
- AddJobToQueue(new QueuedSceneJob() { IntegrationTestSceneHandler = this, Scene = scene, SceneEventProgress = sceneEventProgress, JobType = QueuedSceneJob.JobTypes.Unloading });
+ AddJobToQueue(new QueuedSceneJob() { IntegrationTestSceneHandler = this, Scene = scene.SceneInstance.Value, SceneEventProgress = sceneEventProgress, JobType = QueuedSceneJob.JobTypes.Unloading });
}
// This is OK to return a "nothing" AsyncOperation since we are simulating client loading
- return null;
+ return default;
}
///
@@ -381,7 +385,7 @@ internal Scene GetAndAddNewlyLoadedSceneByName(string sceneName)
{
continue;
}
- NetworkManager.SceneManager.ScenesLoaded.Add(sceneLoaded.handle, sceneLoaded);
+ NetworkManager.SceneManager.ScenesLoaded.Add(sceneLoaded.handle, new NetworkSceneManager.SceneData(null, sceneLoaded));
StartTrackingScene(sceneLoaded, true, NetworkManager);
return sceneLoaded;
}
@@ -594,7 +598,7 @@ public Scene GetSceneFromLoadedScenes(string sceneName, NetworkManager networkMa
return m_InvalidScene;
}
- public void PopulateLoadedScenes(ref Dictionary scenesLoaded, NetworkManager networkManager)
+ public void PopulateLoadedScenes(ref Dictionary scenesLoaded, NetworkManager networkManager)
{
if (!SceneNameToSceneHandles.ContainsKey(networkManager))
{
@@ -632,7 +636,7 @@ public void PopulateLoadedScenes(ref Dictionary scenesLoaded, Networ
SceneNameToSceneHandles[networkManager][scene.name].Add(scene.handle, sceneEntry);
if (!scenesLoaded.ContainsKey(scene.handle))
{
- scenesLoaded.Add(scene.handle, scene);
+ scenesLoaded.Add(scene.handle, new NetworkSceneManager.SceneData(null, scene));
}
}
else
@@ -861,7 +865,7 @@ public void SetClientSynchronizationMode(ref NetworkManager networkManager, Load
if (!sceneManager.ScenesLoaded.ContainsKey(scene.handle))
{
StartTrackingScene(scene, true, networkManager);
- sceneManager.ScenesLoaded.Add(scene.handle, scene);
+ sceneManager.ScenesLoaded.Add(scene.handle, new NetworkSceneManager.SceneData(null, scene));
}
}
}
diff --git a/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTestHelpers.cs b/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTestHelpers.cs
index 2f5f975ecd..789ef2d494 100644
--- a/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTestHelpers.cs
+++ b/com.unity.netcode.gameobjects/TestHelpers/Runtime/NetcodeIntegrationTestHelpers.cs
@@ -421,7 +421,7 @@ private static void SceneManagerValidationAndTestRunnerInitialization(NetworkMan
// with the clients.
if (!networkManager.SceneManager.ScenesLoaded.ContainsKey(scene.handle))
{
- networkManager.SceneManager.ScenesLoaded.Add(scene.handle, scene);
+ networkManager.SceneManager.ScenesLoaded.Add(scene.handle, new NetworkSceneManager.SceneData(null, scene));
}
// In distributed authority we need to check if this scene is already added
if (networkManager.DistributedAuthorityMode)
diff --git a/com.unity.netcode.gameobjects/TestHelpers/Runtime/com.unity.netcode.testhelpers.runtime.asmdef b/com.unity.netcode.gameobjects/TestHelpers/Runtime/com.unity.netcode.testhelpers.runtime.asmdef
index 2fb107c79f..14fad83862 100644
--- a/com.unity.netcode.gameobjects/TestHelpers/Runtime/com.unity.netcode.testhelpers.runtime.asmdef
+++ b/com.unity.netcode.gameobjects/TestHelpers/Runtime/com.unity.netcode.testhelpers.runtime.asmdef
@@ -6,7 +6,9 @@
"Unity.Multiplayer.MetricTypes",
"Unity.Multiplayer.NetStats",
"Unity.Multiplayer.Tools.MetricTypes",
- "Unity.Multiplayer.Tools.NetStats"
+ "Unity.Multiplayer.Tools.NetStats",
+ "Unity.ResourceManager",
+ "Unity.Addressables"
],
"optionalUnityReferences": [
"TestAssemblies"
diff --git a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs
index eb2ed8a18d..2403402701 100644
--- a/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs
+++ b/com.unity.netcode.gameobjects/Tests/Editor/Messaging/MessageCorruptionTests.cs
@@ -90,11 +90,16 @@ public unsafe void Send(ulong clientId, NetworkDelivery delivery, FastBufferWrit
break;
}
case TypeOfCorruption.CorruptBytes:
- batchData.Seek(batchData.Length - 2);
- var currentByte = batchData.GetUnsafePtr()[0];
- batchData.WriteByteSafe((byte)(currentByte == 0 ? 1 : 0));
- MessageQueue.Add(batchData.ToArray());
- break;
+ {
+ batchData.Seek(batchData.Length - 4);
+ for (int i = 0; i < 4; i++)
+ {
+ var currentByte = batchData.GetUnsafePtr()[i];
+ batchData.WriteByteSafe((byte)(currentByte == 0 ? 1 : 0));
+ MessageQueue.Add(batchData.ToArray());
+ }
+ break;
+ }
case TypeOfCorruption.Truncated:
batchData.Truncate(batchData.Length - 1);
MessageQueue.Add(batchData.ToArray());
diff --git a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributedAuthorityCodecTests.cs b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributedAuthorityCodecTests.cs
index af69df9aa8..2a89327bc4 100644
--- a/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributedAuthorityCodecTests.cs
+++ b/com.unity.netcode.gameobjects/Tests/Runtime/DistributedAuthority/DistributedAuthorityCodecTests.cs
@@ -347,7 +347,7 @@ public IEnumerator SceneEventMessageLoad()
SceneEventType = SceneEventType.Load,
LoadSceneMode = LoadSceneMode.Single,
SceneEventProgressId = Guid.NewGuid(),
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
};
@@ -373,7 +373,7 @@ public IEnumerator SceneEventMessageLoadWithObjects()
SceneEventType = SceneEventType.Load,
LoadSceneMode = LoadSceneMode.Single,
SceneEventProgressId = Guid.NewGuid(),
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
};
@@ -393,7 +393,7 @@ public IEnumerator SceneEventMessageUnload()
SceneEventType = SceneEventType.Unload,
LoadSceneMode = LoadSceneMode.Single,
SceneEventProgressId = Guid.NewGuid(),
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
};
@@ -413,7 +413,7 @@ public IEnumerator SceneEventMessageLoadComplete()
SceneEventType = SceneEventType.LoadComplete,
LoadSceneMode = LoadSceneMode.Single,
SceneEventProgressId = Guid.NewGuid(),
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
};
@@ -433,7 +433,7 @@ public IEnumerator SceneEventMessageUnloadComplete()
SceneEventType = SceneEventType.UnloadComplete,
LoadSceneMode = LoadSceneMode.Single,
SceneEventProgressId = Guid.NewGuid(),
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
};
@@ -453,7 +453,7 @@ public IEnumerator SceneEventMessageLoadCompleted()
SceneEventType = SceneEventType.LoadEventCompleted,
LoadSceneMode = LoadSceneMode.Single,
SceneEventProgressId = Guid.NewGuid(),
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
ClientsCompleted = new List() { k_ClientId },
ClientsTimedOut = new List() { 123456789 },
@@ -475,7 +475,7 @@ public IEnumerator SceneEventMessageUnloadLoadCompleted()
SceneEventType = SceneEventType.UnloadEventCompleted,
LoadSceneMode = LoadSceneMode.Single,
SceneEventProgressId = Guid.NewGuid(),
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
ClientsCompleted = new List() { k_ClientId },
ClientsTimedOut = new List() { 123456789 },
@@ -497,11 +497,11 @@ public IEnumerator SceneEventMessageSynchronize()
SceneEventType = SceneEventType.Synchronize,
LoadSceneMode = LoadSceneMode.Single,
ClientSynchronizationMode = LoadSceneMode.Single,
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
- ScenesToSynchronize = new Queue()
+ ScenesToSynchronize = new Queue()
};
- eventData.ScenesToSynchronize.Enqueue(101);
+ eventData.ScenesToSynchronize.Enqueue("SomeRandomSceneName2");
eventData.SceneHandlesToSynchronize = new Queue();
eventData.SceneHandlesToSynchronize.Enqueue(202);
@@ -522,7 +522,7 @@ public IEnumerator SceneEventMessageReSynchronize()
SceneEventType = SceneEventType.ReSynchronize,
LoadSceneMode = LoadSceneMode.Single,
ClientSynchronizationMode = LoadSceneMode.Single,
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
};
@@ -542,7 +542,7 @@ public IEnumerator SceneEventMessageSynchronizeComplete()
SceneEventType = SceneEventType.ReSynchronize,
LoadSceneMode = LoadSceneMode.Single,
ClientSynchronizationMode = LoadSceneMode.Single,
- SceneHash = XXHash.Hash32("SomeRandomSceneName"),
+ SceneAsset = "SomeRandomSceneName",
SceneHandle = 23456,
};
@@ -560,7 +560,7 @@ public IEnumerator SceneEventMessageActiveSceneChanged()
var eventData = new SceneEventData(Client)
{
SceneEventType = SceneEventType.ActiveSceneChanged,
- ActiveSceneHash = XXHash.Hash32("ActiveScene")
+ ActiveSceneAsset = "SomeRandomSceneName"
};
var message = new SceneEventMessage()
diff --git a/minimalproject/ProjectSettings/MemorySettings.asset b/minimalproject/ProjectSettings/MemorySettings.asset
new file mode 100644
index 0000000000..5b5facecac
--- /dev/null
+++ b/minimalproject/ProjectSettings/MemorySettings.asset
@@ -0,0 +1,35 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!387306366 &1
+MemorySettings:
+ m_ObjectHideFlags: 0
+ m_EditorMemorySettings:
+ m_MainAllocatorBlockSize: -1
+ m_ThreadAllocatorBlockSize: -1
+ m_MainGfxBlockSize: -1
+ m_ThreadGfxBlockSize: -1
+ m_CacheBlockSize: -1
+ m_TypetreeBlockSize: -1
+ m_ProfilerBlockSize: -1
+ m_ProfilerEditorBlockSize: -1
+ m_BucketAllocatorGranularity: -1
+ m_BucketAllocatorBucketsCount: -1
+ m_BucketAllocatorBlockSize: -1
+ m_BucketAllocatorBlockCount: -1
+ m_ProfilerBucketAllocatorGranularity: -1
+ m_ProfilerBucketAllocatorBucketsCount: -1
+ m_ProfilerBucketAllocatorBlockSize: -1
+ m_ProfilerBucketAllocatorBlockCount: -1
+ m_TempAllocatorSizeMain: -1
+ m_JobTempAllocatorBlockSize: -1
+ m_BackgroundJobTempAllocatorBlockSize: -1
+ m_JobTempAllocatorReducedBlockSize: -1
+ m_TempAllocatorSizeGIBakingWorker: -1
+ m_TempAllocatorSizeNavMeshWorker: -1
+ m_TempAllocatorSizeAudioWorker: -1
+ m_TempAllocatorSizeCloudWorker: -1
+ m_TempAllocatorSizeGfx: -1
+ m_TempAllocatorSizeJobWorker: -1
+ m_TempAllocatorSizeBackgroundWorker: -1
+ m_TempAllocatorSizePreloadManager: -1
+ m_PlatformMemorySettings: {}
diff --git a/minimalproject/ProjectSettings/boot.config b/minimalproject/ProjectSettings/boot.config
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/pvp-exemptions.json b/pvp-exemptions.json
new file mode 100644
index 0000000000..6c53ec94ca
--- /dev/null
+++ b/pvp-exemptions.json
@@ -0,0 +1,2835 @@
+{
+ "per_package": {
+ "com.unity.netcode.gameobjects@1": {
+ "exempts": {
+ "PVP-31-1": {
+ "errors": [
+ "LICENSE.md: license must match regex: ^(?.*?) copyright \\u00a9 \\d+ \\S(.*\\S)?(?:\\r?\\n|$)"
+ ]
+ },
+ "PVP-40-1": {
+ "errors": [
+ "CHANGELOG.md: line 196: header must match regex: ^\\[(?.*)\\]( - (?\\d{4}-\\d{2}-\\d{2}))?$"
+ ]
+ },
+ "PVP-41-1": {
+ "errors": [
+ "CHANGELOG.md: line 9: Unreleased section is not allowed for public release"
+ ]
+ },
+ "PVP-150-1": {
+ "errors": [
+ "Unity.Netcode.Components.AnticipatedNetworkTransform: in list item context (only allowed in block or inline context)",
+ "Unity.Netcode.Components.AnticipatedNetworkTransform: in list item context (only allowed in block or inline context)",
+ "Unity.Netcode.Components.AnticipatedNetworkTransform: void AnticipateMove(Vector3): empty tag",
+ "Unity.Netcode.Components.AnticipatedNetworkTransform: void AnticipateRotate(Quaternion): empty tag",
+ "Unity.Netcode.Components.AnticipatedNetworkTransform: void AnticipateScale(Vector3): empty tag",
+ "Unity.Netcode.Components.AnticipatedNetworkTransform: void AnticipateState(TransformState): empty tag",
+ "Unity.Netcode.Components.AnticipatedNetworkTransform: void Smooth(TransformState, TransformState, float): empty tag",
+ "Unity.Netcode.AnticipatedNetworkVariable: in list item context (only allowed in block or inline context)",
+ "Unity.Netcode.AnticipatedNetworkVariable: in list item context (only allowed in block or inline context)",
+ "Unity.Netcode.AnticipatedNetworkVariable: void Anticipate(T): empty tag",
+ "Unity.Netcode.AnticipatedNetworkVariable: void Smooth(in T, in T, float, AnticipatedNetworkVariable.SmoothDelegate): empty tag",
+ "Unity.Netcode.RuntimeTests.BufferDataValidationComponent: bool IsTestComplete(): empty tag",
+ "Unity.Netcode.BufferedLinearInterpolatorVector3: XML is not well-formed: Missing closing quotation mark for string literal",
+ "Unity.Netcode.BufferSerializer: void SerializeValue(ref NativeArray, Allocator): unexpected ",
+ "Unity.Netcode.BufferSerializer: bool PreCheck(int): empty tag",
+ "Unity.Netcode.BufferSerializer: bool PreCheck(int): empty tag",
+ "Unity.Netcode.BytePacker: in block context; use instead",
+ "Unity.Netcode.ByteUnpacker: in block context; use instead",
+ "Unity.Netcode.ByteUnpacker: void ReadValuePacked(FastBufferReader, out string): empty tag",
+ "Unity.Netcode.FastBufferReader: in block context; use instead",
+ "Unity.Netcode.FastBufferReader: .ctor(NativeArray, Allocator, int, int, Allocator): in block context (only allowed in top-level context)",
+ "Unity.Netcode.FastBufferReader: .ctor(NativeArray, Allocator, int, int, Allocator): empty tag",
+ "Unity.Netcode.FastBufferReader: .ctor(byte*, Allocator, int, int, Allocator): in block context (only allowed in top-level context)",
+ "Unity.Netcode.FastBufferReader: .ctor(byte*, Allocator, int, int, Allocator): empty tag",
+ "Unity.Netcode.FastBufferReader: .ctor(FastBufferWriter, Allocator, int, int, Allocator): in block context (only allowed in top-level context)",
+ "Unity.Netcode.FastBufferReader: .ctor(FastBufferWriter, Allocator, int, int, Allocator): empty tag",
+ "Unity.Netcode.FastBufferReader: .ctor(FastBufferReader, Allocator, int, int, Allocator): in block context (only allowed in top-level context)",
+ "Unity.Netcode.FastBufferReader: .ctor(FastBufferReader, Allocator, int, int, Allocator): empty tag",
+ "Unity.Netcode.FastBufferReader: void ReadNetworkSerializable(out T): empty tag",
+ "Unity.Netcode.FastBufferReader: void ReadNetworkSerializable(out T): empty tag",
+ "Unity.Netcode.FastBufferReader: void ReadNetworkSerializable(out T[]): empty tag",
+ "Unity.Netcode.FastBufferReader: void ReadNetworkSerializable(out NativeArray, Allocator): empty tag",
+ "Unity.Netcode.FastBufferReader: void ReadNetworkSerializableInPlace(ref T): empty tag",
+ "Unity.Netcode.FastBufferReader: void ReadNetworkSerializableInPlace(ref T): empty tag",
+ "Unity.Netcode.FastBufferReader: void ReadPartialValue(out T, int, int): empty tag",
+ "Unity.Netcode.FastBufferReader: void ReadValueSafe(out NativeArray, Allocator): unexpected ",
+ "Unity.Netcode.FastBufferReader: void ReadValueSafeTemp(out NativeArray): unexpected ",
+ "Unity.Netcode.FastBufferWriter: in block context; use instead",
+ "Unity.Netcode.FastBufferWriter: bool TryBeginWriteInternal(int): empty tag",
+ "Unity.Netcode.FastBufferWriter: bool TryBeginWriteInternal(int): empty tag",
+ "Unity.Netcode.FastBufferWriter: bool TryBeginWriteInternal(int): empty tag",
+ "Unity.Netcode.FastBufferWriter: byte[] ToArray(): empty tag",
+ "Unity.Netcode.FastBufferWriter: byte* GetUnsafePtr(): empty tag",
+ "Unity.Netcode.FastBufferWriter: byte* GetUnsafePtrAtCurrentPosition(): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(string, bool): empty tag",
+ "Unity.Netcode.FastBufferWriter: void WriteNetworkSerializable(in T): empty tag",
+ "Unity.Netcode.FastBufferWriter: void WriteNetworkSerializable(T[], int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: void WriteNetworkSerializable(T[], int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: void WriteNetworkSerializable(NativeArray, int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: void WriteNetworkSerializable(NativeArray, int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(T[], int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(T[], int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(NativeArray, int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(NativeArray, int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: void WritePartialValue(T, int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: void WritePartialValue(T, int, int): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(in T, ForStructs): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(in T, ForStructs): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(in T, ForStructs): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(in T): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(in T): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(in T): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(in NativeArray): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(in NativeArray): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(in NativeArray): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(): empty tag",
+ "Unity.Netcode.FastBufferWriter: int GetWriteSize(): empty tag",
+ "Unity.Netcode.FastBufferWriter: void WriteValueSafe(in NativeArray): unexpected ",
+ "Unity.Netcode.ForceNetworkSerializeByMemcpy: empty tag",
+ "Unity.Netcode.GenerateSerializationForGenericParameterAttribute: tag inside ",
+ "Unity.Netcode.GenerateSerializationForGenericParameterAttribute: mixed block and inline content in ; wrap inline content in ",
+ "Unity.Netcode.Components.HalfVector3: XML is not well-formed: End tag 'remarks' does not match the start tag 'ushort'",
+ "Unity.Netcode.Components.HalfVector3: .ctor(Vector3, bool3): unexpected ",
+ "Unity.Netcode.Components.HalfVector4: XML is not well-formed: End tag 'remarks' does not match the start tag 'ushort'",
+ "Unity.Netcode.InvalidParentException: .ctor(string): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.InvalidParentException: .ctor(string): empty tag",
+ "Unity.Netcode.InvalidParentException: .ctor(string, Exception): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.InvalidParentException: .ctor(string, Exception): empty tag",
+ "Unity.Netcode.IReaderWriter: void SerializeValue(ref NativeArray, Allocator): unexpected ",
+ "Unity.Netcode.IReaderWriter: bool PreCheck(int): empty tag",
+ "Unity.Netcode.IReaderWriter: bool PreCheck(int): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTest: void VerboseDebug(string): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTest: void CreateServerAndClients(int): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTest: .ctor(HostOrServer): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTest: void TimeTravel(double, int): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: bool CreateNewClients(int, out NetworkManager[], bool): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: void StopOneClient(NetworkManager, bool): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: void StartOneClient(NetworkManager): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: bool Start(bool, NetworkManager, NetworkManager[], BeforeClientStartCallback): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: IEnumerator WaitForClientConnected(NetworkManager, ResultWrapper, float): unexpected ",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: IEnumerator WaitForClientsConnected(NetworkManager[], ResultWrapper, float): XML is not well-formed: An identifier was expected",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: IEnumerator WaitForClientConnectedToServer(NetworkManager, ResultWrapper, float): unexpected ",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: IEnumerator WaitForClientsConnectedToServer(NetworkManager, int, ResultWrapper, float): unexpected ",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: IEnumerator GetNetworkObjectByRepresentation(ulong, NetworkManager, ResultWrapper, bool, float): unexpected ",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: IEnumerator GetNetworkObjectByRepresentation(Func, NetworkManager, ResultWrapper, bool, float): unexpected ",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: void GetNetworkObjectByRepresentationWithTimeTravel(Func, NetworkManager, ResultWrapper, bool, int): unexpected ",
+ "Unity.Netcode.TestHelpers.Runtime.NetcodeIntegrationTestHelpers: IEnumerator WaitForCondition(Func, ResultWrapper, float, int): unexpected ",
+ "Unity.Netcode.NetworkBehaviour: NetworkObject: text or XML content outside a top-level tag",
+ "Unity.Netcode.NetworkBehaviour: NetworkObject GetNetworkObject(ulong): empty tag",
+ "Unity.Netcode.NetworkBehaviour: NetworkObject GetNetworkObject(ulong): empty tag",
+ "Unity.Netcode.NetworkBehaviour: void OnSynchronize(ref BufferSerializer): unexpected ",
+ "Unity.Netcode.NetworkBehaviourReference: .ctor(NetworkBehaviour): empty tag",
+ "Unity.Netcode.RuntimeTests.NetVarContainer: GameObject CreatePrefabGameObject(NetVarCombinationTypes): empty tag",
+ "Unity.Netcode.NetworkConfig: string ToBase64(): empty tag",
+ "Unity.Netcode.NetworkConfig: ulong GetConfig(bool): empty tag",
+ "Unity.Netcode.NetworkConfig: ulong GetConfig(bool): empty tag",
+ "Unity.Netcode.NetworkConfig: bool CompareConfig(ulong): empty tag",
+ "Unity.Netcode.NetworkConfig: bool CompareConfig(ulong): empty tag",
+ "Unity.Netcode.NetworkList: .ctor(IEnumerable, NetworkVariableReadPermission, NetworkVariableWritePermission): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: .ctor(IEnumerable, NetworkVariableReadPermission, NetworkVariableWritePermission): empty tag",
+ "Unity.Netcode.NetworkList: IEnumerator GetEnumerator(): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: void Add(T): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: void Clear(): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: bool Contains(T): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: bool Remove(T): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: Count: cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: int IndexOf(T): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: void Insert(int, T): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: void RemoveAt(int): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkList: this[int]: cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.NetworkManager: OnServerStopped: unexpected ",
+ "Unity.Netcode.NetworkManager: OnClientStopped: unexpected ",
+ "Unity.Netcode.NetworkManager: void AddNetworkPrefab(GameObject): empty tag",
+ "Unity.Netcode.NetworkManager: void AddNetworkPrefab(GameObject): empty tag",
+ "Unity.Netcode.NetworkManager: void RemoveNetworkPrefab(GameObject): empty tag",
+ "Unity.Netcode.NetworkManager: MaximumTransmissionUnitSize: empty tag",
+ "Unity.Netcode.NetworkManager: MaximumTransmissionUnitSize: unexpected ",
+ "Unity.Netcode.NetworkManager: void SetPeerMTU(ulong, int): empty tag",
+ "Unity.Netcode.NetworkManager: int GetPeerMTU(ulong): empty tag",
+ "Unity.Netcode.NetworkManager: int GetPeerMTU(ulong): empty tag",
+ "Unity.Netcode.NetworkManager: MaximumFragmentedMessageSize: empty tag",
+ "Unity.Netcode.NetworkManager: MaximumFragmentedMessageSize: unexpected ",
+ "Unity.Netcode.TestHelpers.Runtime.NetworkManagerHelper: Guid AddGameNetworkObject(string): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetworkManagerHelper: T AddComponentToObject(Guid): empty tag",
+ "Unity.Netcode.NetworkObject: bool TryRemoveParent(bool): empty tag",
+ "Unity.Netcode.RuntimeTests.NetworkObjectDestroyTests: IEnumerator TestNetworkObjectServerDestroy(): empty tag",
+ "Unity.Netcode.RuntimeTests.NetworkObjectOnSpawnTests: IEnumerator TestOnNetworkSpawnCallbacks(): empty tag",
+ "Unity.Netcode.RuntimeTests.NetworkObjectPropertyTests: void TestPrefabHashIdPropertyIsAPrefab(): empty tag",
+ "Unity.Netcode.RuntimeTests.NetworkObjectPropertyTests: void TestPrefabHashIdPropertyIsAPrefab(): unexpected ",
+ "Unity.Netcode.NetworkObjectReference: .ctor(NetworkObject): empty tag",
+ "Unity.Netcode.NetworkObjectReference: .ctor(GameObject): empty tag",
+ "Unity.Netcode.INetworkPrefabInstanceHandler: NetworkObject Instantiate(ulong, Vector3, Quaternion): empty tag",
+ "Unity.Netcode.NetworkPrefabHandler: bool AddHandler(NetworkObject, INetworkPrefabInstanceHandler): empty tag",
+ "Unity.Netcode.NetworkPrefabHandler: bool AddHandler(uint, INetworkPrefabInstanceHandler): empty tag",
+ "Unity.Netcode.NetworkPrefabHandler: void AddNetworkPrefab(GameObject): empty tag",
+ "Unity.Netcode.NetworkPrefabHandler: void AddNetworkPrefab(GameObject): empty tag",
+ "Unity.Netcode.NetworkPrefabHandler: void RemoveNetworkPrefab(GameObject): empty tag",
+ "Unity.Netcode.NetworkPrefabsList: void Add(NetworkPrefab): empty tag",
+ "Unity.Netcode.NetworkPrefabsList: void Remove(NetworkPrefab): empty tag",
+ "Unity.Netcode.SceneEvent: in block context; use instead",
+ "Unity.Netcode.NetworkSceneManager: void SetClientSynchronizationMode(LoadSceneMode): XML is not well-formed: Expected an end tag for element 'summary'",
+ "Unity.Netcode.NetworkSceneManager: SceneEventProgressStatus UnloadScene(Scene): empty tag",
+ "Unity.Netcode.NetworkSceneManager.SceneEventDelegate: in block context; use instead",
+ "Unity.Netcode.NetworkSceneManager.SceneEventDelegate: empty tag",
+ "Unity.Netcode.NetworkSceneManager.OnLoadDelegateHandler: in block context; use instead",
+ "Unity.Netcode.NetworkSceneManager.OnUnloadDelegateHandler: in block context; use instead",
+ "Unity.Netcode.NetworkSceneManager.OnSynchronizeDelegateHandler: in block context; use instead",
+ "Unity.Netcode.NetworkSceneManager.OnEventCompletedDelegateHandler: in block context; use instead",
+ "Unity.Netcode.NetworkSceneManager.OnLoadCompleteDelegateHandler: in block context; use instead",
+ "Unity.Netcode.NetworkSceneManager.OnUnloadCompleteDelegateHandler: in block context; use instead",
+ "Unity.Netcode.NetworkSceneManager.OnSynchronizeCompleteDelegateHandler: in block context; use instead",
+ "Unity.Netcode.NetworkTime: NetworkTime TimeTicksAgo(int): empty tag",
+ "Unity.Netcode.NetworkTimeSystem: bool Advance(double): empty tag",
+ "Unity.Netcode.RuntimeTests.NetworkTimeSystemTests: IEnumerator PlayerLoopFixedTimeTest(): XML is not well-formed: End tag 'summary' does not match the start tag 'see'",
+ "Unity.Netcode.RuntimeTests.NetworkTimeSystemTests: IEnumerator PlayerLoopTimeTest_WithDifferentTimeScale(float): empty tag",
+ "Unity.Netcode.RuntimeTests.NetworkTimeSystemTests: IEnumerator CorrectAmountTicksTest(): empty tag",
+ "Unity.Netcode.Components.NetworkTransform: void OnSynchronize(ref BufferSerializer): empty tag",
+ "Unity.Netcode.Components.NetworkTransform: void OnSynchronize(ref BufferSerializer): empty tag",
+ "Unity.Netcode.Components.NetworkTransform: void OnSynchronize(ref BufferSerializer): unexpected ",
+ "Unity.Netcode.Components.NetworkTransform: void OnInitialize(ref NetworkVariable): empty tag",
+ "Unity.Netcode.Components.NetworkTransform: void SetState(Vector3?, Quaternion?, Vector3?, bool): empty tag",
+ "Unity.Netcode.Components.NetworkTransform: void SetState(Vector3?, Quaternion?, Vector3?, bool): empty tag",
+ "Unity.Netcode.Components.NetworkTransform: void SetState(Vector3?, Quaternion?, Vector3?, bool): text or XML content outside a top-level tag",
+ "Unity.Netcode.Components.NetworkTransform: void Update(): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.Components.NetworkTransform: void Teleport(Vector3, Quaternion, Vector3): empty tag",
+ "Unity.Netcode.Components.NetworkTransform: void Teleport(Vector3, Quaternion, Vector3): empty tag",
+ "Unity.Netcode.Components.NetworkTransform: void Teleport(Vector3, Quaternion, Vector3): text or XML content outside a top-level tag",
+ "Unity.Netcode.RuntimeTests.NetworkTransformBase: int OnNumberOfClients(): empty tag",
+ "Unity.Netcode.RuntimeTests.NetworkTransformBase: bool AllChildObjectInstancesAreSpawned(): empty tag",
+ "Unity.Netcode.Editor.NetworkTransformEditor: void OnEnable(): cannot auto-inheritdoc (not an override or interface implementation); must specify 'cref'",
+ "Unity.Netcode.RuntimeTests.NetworkTransformPacketLossTests: void NetworkTransformMultipleChangesOverTime(TransformSpace, Axis): XML is not well-formed: An identifier was expected",
+ "Unity.Netcode.RuntimeTests.NetworkTransformTests: void NetworkTransformMultipleChangesOverTime(TransformSpace, OverrideState, Axis): XML is not well-formed: An identifier was expected",
+ "Unity.Netcode.NetworkTransport: in block context; use instead",
+ "Unity.Netcode.NetworkTransport: void Initialize(NetworkManager): suspicious '///' triple-slash inside XmlDoc comment",
+ "Unity.Netcode.NetworkTransport: void Initialize(NetworkManager): text or XML content outside a top-level tag",
+ "Unity.Netcode.NetworkVariableBase: void SetUpdateTraits(NetworkVariableUpdateTraits): empty tag",
+ "Unity.Netcode.NetworkVariableBase: bool ExceedsDirtinessThreshold(): empty tag",
+ "Unity.Netcode.TestHelpers.Runtime.NetworkVariableHelper: XML is not well-formed: End tag 'summary' does not match the start tag 'T'",
+ "Unity.Netcode.UserNetworkVariableSerialization: empty tag",
+ "Unity.Netcode.UserNetworkVariableSerialization.DuplicateValueDelegate: unexpected ",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_UnmanagedByMemcpy(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_UnmanagedByMemcpyArray(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_List(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_HashSet(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_Dictionary(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_Dictionary(): unexpected ",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_UnmanagedINetworkSerializable(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_UnmanagedINetworkSerializableArray(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_ManagedINetworkSerializable(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_FixedString(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeSerializer_FixedStringArray(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeEqualityChecker_ManagedIEquatable(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeEqualityChecker_UnmanagedIEquatable(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeEqualityChecker_UnmanagedIEquatableArray(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeEqualityChecker_List(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeEqualityChecker_HashSet(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeEqualityChecker_Dictionary(): empty tag",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeEqualityChecker_Dictionary(): unexpected ",
+ "Unity.Netcode.NetworkVariableSerializationTypes: void InitializeEqualityChecker_UnmanagedValueEquals(): empty