Memory Leaks when calling Runner.RegisterUniqueObjects() in a custom INetworkSceneObjectProvider
Hello !
I tried creating a custom INetworkSceneObjectProvider to sync everything when I load and unload scenes.
But when I try to load a new level with this system, the application crashes when I call Runner.RegisterUniqueObjects() but ONLY for the host. I checked the content passed in and it is exactly the same content I passed in on the clients. 😱
I know, for sure, that my LevelData and its callbacks work locally (and on the clients), so I should be able to call correctly Runner.InvokeSceneLoadStart() and Runner.InvokeSceneLoadDone() when I start loading and when I receive the finish callback. It seems like it is working correctly on clients. 🤔
I was using lots of coroutines, I suspected that it may be the source of my problem, that is why I moved every important calls in the update method. But it did change nothing 😥
I also had a question about the Initialize() method, I am not really sure if I am supposed to call Runner.InvokeSceneLoadStart() and Runner.InvokeSceneLoadDone() when filling my lists, but since it was not done in the provided base classes, I did not.
Here is my class, you have to call LoadLevel() and passing in a LevelData to load a level :
using Fusion; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; namespace MOtter.Network { public class NetworkedSceneManager : Fusion.Behaviour, INetworkSceneObjectProvider { private Dictionary<Guid, NetworkObject> m_sceneNetworkedObjects = new Dictionary<Guid, NetworkObject>(); private List<SceneRef> m_currentScenes = new List<SceneRef>(); private bool m_isLoading = false; public NetworkRunner Runner { get; private set; } #region Cache Values for calls in update() private bool m_initializationAsked = false; private bool m_loadLevelAsked = false; private LevelData.LevelData m_levelToLoad = null; private bool m_onLevelLoadedAsked = false; #endregion #region Called by Fusion public void Initialize(NetworkRunner runner) { Runner = runner; Debug.LogError("Initializing asked"); m_initializationAsked = true; } public bool IsReady(NetworkRunner runner) { Assert.Check(Runner == runner); return !m_isLoading; } public void Shutdown(NetworkRunner runner) { Assert.Check(Runner == runner); m_sceneNetworkedObjects.Clear(); m_currentScenes.Clear(); m_isLoading = false; Runner = null; } public bool TryResolveSceneObject(NetworkRunner runner, Guid objectGuid, out NetworkObject instance) { Assert.Check(Runner == runner); return m_sceneNetworkedObjects.TryGetValue(objectGuid, out instance); } #endregion private void Update() { if(m_initializationAsked) { Debug.LogError("Initializing"); FetchSceneRefsAndNetworkedObjects(); m_initializationAsked = false; } if(m_loadLevelAsked) { Debug.LogError("LoadLevel"); m_isLoading = true; m_levelToLoad.OnLoadingEnded += OnLoadingEnded; Runner.InvokeSceneLoadStart(); m_levelToLoad.LoadLevel(); m_loadLevelAsked = false; } if(m_onLevelLoadedAsked) { Debug.LogError("On Level Loaded treatment"); FetchSceneRefsAndNetworkedObjects(); RegisterNetObjects(); Runner.InvokeSceneLoadDone(); m_isLoading = false; m_onLevelLoaded?.Invoke(); m_onLevelLoaded = null; m_onLevelLoadedAsked = false; } } #region Actions private Action m_onLevelLoaded = null; public void LoadLevel(LevelData.LevelData p_levelData, Action a_onLevelLoaded = null) { Debug.LogError("LoadLevel asked"); m_onLevelLoaded = a_onLevelLoaded; m_levelToLoad = p_levelData; m_loadLevelAsked = true; } #endregion private void OnLoadingEnded(LevelData.LevelData p_levelData) { Debug.LogError("OnLevelLoaded treatment asked"); p_levelData.OnLoadingEnded -= OnLoadingEnded; m_onLevelLoadedAsked = true; } #region Utils private void FetchSceneRefsAndNetworkedObjects() { // Fetching SceneRefs m_currentScenes.Clear(); for(int i = 0; i < SceneManager.sceneCount; ++i) { Debug.Log("Scene "+SceneManager.GetSceneAt(i).name+" avec index : "+SceneManager.GetSceneAt(i).buildIndex); m_currentScenes.Add(SceneManager.GetSceneAt(i).buildIndex); } // Fetching Networked Objects m_sceneNetworkedObjects.Clear(); var allNetworkedObjects = FindObjectsOfType<NetworkObject>(); for(int i = 0; i < allNetworkedObjects.Length; ++i) { m_sceneNetworkedObjects.Add(allNetworkedObjects[i].NetworkGuid, allNetworkedObjects[i]); } } private void RegisterNetObjects() { // This makes the host crash when trying to load a level Debug.LogError("This makes the host crash when trying to load a level"); if (m_sceneNetworkedObjects.Values.Count > 0) { Runner.RegisterUniqueObjects(m_sceneNetworkedObjects.Values); } } #endregion } }