Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Client Exception: Server Scene Handle already exists!

Discussion in 'Netcode for GameObjects' started by mariuskleiner, Mar 28, 2023.

  1. mariuskleiner

    mariuskleiner

    Joined:
    Jul 30, 2017
    Posts:
    1
    Hi there!

    I am getting an exception (on the client side) when switching scenes:


    Exception: Server Scene Handle (-128) already exist! Happened during scene load of LoadingScreenScene with Client Handle (-88458)
    Unity.Netcode.NetworkSceneManager.OnSceneLoaded (System.UInt32 sceneEventId) (at Library/PackageCache/com.unity.netcode.gameobjects@1.2.0/Runtime/SceneManagement/NetworkSceneManager.cs:1416)
    Unity.Netcode.SceneEventProgress.<SetAsyncOperation>b__37_0 (UnityEngine.AsyncOperation asyncOp2) (at Library/PackageCache/com.unity.netcode.gameobjects@1.2.0/Runtime/SceneManagement/SceneEventProgress.cs:262)
    UnityEngine.AsyncOperation.InvokeCompletionEvent () (at <ba783288ca164d3099898a8819fcec1c>:0)


    Couldn't find any infos using search and google. Can you hint me to the relevant documentation part?

    Thank you in advance!!!
     
  2. Sleins

    Sleins

    Joined:
    Apr 14, 2023
    Posts:
    7
    I am getting the same erro and for some reason the client with this erro dont start proplely.
     
  3. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
  4. Sleins

    Sleins

    Joined:
    Apr 14, 2023
    Posts:
    7
    hello @RikuTheFuffs-U I am using
    Multiplay Version 1.0.0-pre.10 - April 28, 2023
    Matchmaker Version 1.0.0 - March 24, 2023
    Netcode for GameObjects - Version 1.2.0 - December 09, 2022
    Unity 2021.3.20f1.

    In my project, I am using the base architecture structure used on the unity multiplay sample project.
    From what I could debug so far my server is loading my battle scene correctly but the client logs on to the server before the server loaded the battle scene so the receives one call to load the Bootstrap scene and this call bugs everything on the client because he tries to load his bootstrap what causes the problem to have Server Scene Handle (-128) already exist!. Sometimes in the worst clients, I can see it loading multiple battle scenes at the same time. in one of my tests, my client loaded 3 battle scenes for no reason before unloading two of them, in another I have one loading and maintaining 2 battle scenes one the correct and the other that bugs the project receiving the Server Scene Handle (-128) already exist!.
     
    Last edited: May 22, 2023
  5. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    Thanks for the answer. Not sure if you did changes to the Unity Multiplay Sample Project (do you have a link to the sample?), but I'd recommend to try implementing the switch-logic in a separate project to understand where the issue is, as it can be related to your custom code.
     
  6. Sleins

    Sleins

    Joined:
    Apr 14, 2023
    Posts:
    7
    the sample project. https://github.com/Unity-Technologies/com.unity.services.samples.matchplay

    The project is this one. I have made some changes but most of my changes were outside of the part where I think it is bugging.

    I think I find the solution my client-server connection is stable now.

    The problem is on the class MatchplayNetworkServer and in the Class ServerGameManager on the

    On the server game Manager we have this method:

    Code (CSharp):
    1.  public async Task StartGameServerAsync(GameInfo startingGameInfo)
    2.         {
    3.             Debug.Log($"Starting server with:{startingGameInfo}.");
    4.  
    5.             // The server should respond to query requests irrespective of the server being allocated.
    6.             // Hence, start the handler as soon as we can.
    7.             await m_MultiplayServerQueryService.BeginServerQueryHandler();
    8.  
    9.             try
    10.             {
    11.                 var matchmakerPayload = await GetMatchmakerPayload(k_MultiplayServiceTimeout);
    12.  
    13.                 if (matchmakerPayload != null)
    14.                 {
    15.                     Debug.Log($"Got payload: {matchmakerPayload}");
    16.                     startingGameInfo = PickGameInfo(matchmakerPayload);
    17.  
    18.                     MatchStartedServerQuery(startingGameInfo);
    19.                     await StartBackfill(matchmakerPayload, startingGameInfo);
    20.                     m_NetworkServer.OnPlayerJoined += UserJoinedServer;
    21.                     m_NetworkServer.OnPlayerLeft += UserLeft;
    22.                     m_StartedServices = true;
    23.                 }
    24.                 else
    25.                 {
    26.                     Debug.LogWarning("Getting the Matchmaker Payload timed out, starting with defaults.");
    27.                 }
    28.             }
    29.             catch (Exception ex)
    30.             {
    31.                 Debug.LogWarning($"Something went wrong trying to set up the Services:\n{ex} ");
    32.             }
    33.  
    34.             if (!m_NetworkServer.OpenConnection(m_ServerIP, m_ServerPort, startingGameInfo))
    35.             {
    36.                 Debug.LogError("NetworkServer did not start as expected.");
    37.                 return;
    38.             }
    39.  
    40.             //Changes Map and sets the synched shared variables to the starting info
    41.             m_SynchedServerData = await m_NetworkServer.ConfigureServer(startingGameInfo);
    42.             if (m_SynchedServerData == null)
    43.             {
    44.                 Debug.LogError("Could not find the synchedServerData.");
    45.                 return;
    46.             }
    47.  
    48.             m_SynchedServerData.serverID.Value = m_ServerName;
    49.  
    50.             m_SynchedServerData.map.OnValueChanged += OnServerChangedMap;
    51.             m_SynchedServerData.gameMode.OnValueChanged += OnServerChangedMode;
    52.             //Set the count to connected players
    53.             m_MultiplayServerQueryService.SetPlayerCount((ushort)NetworkServer.PlayerCount);
    54.  
    55.         }
    56.  
    This code is responsible for starting the server Multiplay Server Query Service connecting the clients, Open Connection and start the server. After all that he call the method NetworkServer.ConfigureServer with calls the

    m_NetworkManager.SceneManager.LoadScene(startingGameInfo.ToSceneName, LoadSceneMode.Single);

    The NetworkManager sceneManager load scene is completely unreliable. My client was connecting to the server before he completely load the correct scene and unload the previews scene with the bootstrap scene.

    • To Correct that the first thing I have done is a Scene manager class to receive and handle all the load and unload calls. I called NetworkSceneManager.
    • on my StartGameServerAsync the first thing that I do is to call the NetworkServer.ConfigureServer before everything and I make the server wait for My battle scene to be fully loaded and my bootstrap scene to be fully unloaded even before I open the server connection or start the BeginServerQueryHandler.
    • Another thing is I am not using the NetworkManager.SceneManager.LoadScene(). i chose to use the normal SceneManager.LoadScene because I load the scene before starting the server and only start after the process is fully completed on the server.
    I am adding bellow my code for reference from this methods

    Code (CSharp):
    1.  
    2.             //Changes Map and sets the synched shared variables to the starting info
    3.             bool serverSetup = await networkServer.ConfigureServer(startingGameInfo);
    4.             if (serverSetup == false)
    5.             {
    6.                 Debug.LogError("Could not setup the server");
    7.                 return;
    8.             }
    9.  
    10.             if (!networkServer.OpenConnection(serverIP, serverPort, startingGameInfo))
    11.             {
    12.                 Debug.LogError("NetworkServer did not start as expected.");
    13.                 return;
    14.             }
    15.  
    16.             NetworkSceneManager.Instance.InitNetworkSceneManager();
    17.  
    18.             Debug.Log($"Starting server with:{startingGameInfo}.");
    19.  
    20.             // The server should respond to query requests irrespective of the server being allocated.
    21.             // Hence, start the handler as soon as we can.
    22.             await multiplayServerQueryService.BeginServerQueryHandler();
    23.  
    24.             try
    25.             {
    26.                 var matchmakerPayload = await GetMatchmakerPayload(multiplayServiceTimeout);
    27.  
    28.                 if (matchmakerPayload != null)
    29.                 {
    30.                     Debug.Log($"Got payload: {matchmakerPayload}");
    31.                     startingGameInfo = PickGameInfo(matchmakerPayload);
    32.  
    33.                     MatchStartedServerQuery(startingGameInfo);
    34.                     await StartBackfill(matchmakerPayload, startingGameInfo);
    35.                     networkServer.OnPlayerJoined += UserJoinedServer;
    36.                     networkServer.OnPlayerLeft += UserLeft;
    37.                     startedServices = true;
    38.                 }
    39.                 else
    40.                 {
    41.                     Debug.LogWarning("Getting the Matchmaker Payload timed out, starting with defaults.");
    42.                 }
    43.             }
    44.             catch (Exception ex)
    45.             {
    46.                 Debug.LogWarning($"Something went wrong trying to set up the Services:\n{ex} ");
    47.             }

    Code (CSharp):
    1. var localNetworkedSceneLoaded = false;
    2.  
    3.             //NetworkSceneManager.Instance.LoadNetworkScene(startingGameInfo.ToSceneName, LoadSceneMode.Additive, (ulong clientId, string sceneName, LoadSceneMode sceneMode) =>
    4.             //{
    5.             //    void bootStrapUnloadCompleted()
    6.             //    {
    7.             //        localNetworkedSceneLoaded = true;
    8.             //        NetworkSceneManager.OnBattleSceneLoaded -= bootStrapUnloadCompleted;
    9.             //    }
    10.             //    NetworkSceneManager.OnBattleSceneLoaded += bootStrapUnloadCompleted;
    11.             //});
    12.             NetworkSceneManager.Instance.IsServer = true;
    13.             NetworkSceneManager.Instance.LoadScene(startingGameInfo.ToSceneName, LoadSceneMode.Additive, (Scene sceneName, LoadSceneMode sceneMode) =>
    14.             {
    15.                 void bootStrapUnloadCompleted()
    16.                 {
    17.                     localNetworkedSceneLoaded = true;
    18.                     NetworkSceneManager.OnBattleSceneLoaded -= bootStrapUnloadCompleted;
    19.                 }
    20.                 NetworkSceneManager.OnBattleSceneLoaded += bootStrapUnloadCompleted;
    21.             });
    22.  
    23.             while (!localNetworkedSceneLoaded) await Task.Delay(50);
    24.  
    25.             await Task.Delay(1000);
    26.  
    27.             Debug.Log("Battle scene loading completed");
    28.  
    29.             return true;

    Code (CSharp):
    1. public class NetworkSceneManager : MonoBehaviour
    2.     {
    3.         private bool isServer = false;
    4.  
    5.         public bool IsServer
    6.         {
    7.             get { return isServer; }
    8.             set { isServer = value; }
    9.         }
    10.  
    11.         public static NetworkSceneManager Instance
    12.         {
    13.             get
    14.             {
    15.                 if (networkSceneManager != null) return networkSceneManager;
    16.                 networkSceneManager = FindObjectOfType<NetworkSceneManager>();
    17.                 if (networkSceneManager == null)
    18.                 {
    19.                     Debug.LogError("No NetworkSceneManager in scene, did you run this from the bootStrap scene?");
    20.                     return null;
    21.                 }
    22.  
    23.                 return networkSceneManager;
    24.             }
    25.         }
    26.  
    27.         private Scene previewActiveScene;
    28.  
    29.         public static Action OnBattleSceneLoaded;
    30.  
    31.         private static NetworkSceneManager networkSceneManager;
    32.  
    33.         private NetworkManager networkManager;
    34.         #region properties
    35.         public void Awake()
    36.         {
    37.             networkManager = GetComponent<NetworkManager>();
    38.             SceneManager.sceneLoaded += OnSceneLoaded;
    39.             SceneManager.sceneUnloaded += OnSceneUnloaded;
    40.          
    41.         }
    42.  
    43.         public void InitNetworkSceneManager()
    44.         {
    45.             networkManager.SceneManager.OnLoad += OnSceneNetworkLoaded;
    46.             networkManager.SceneManager.OnUnload += OnSceneNetworkUnloaded;
    47.         }
    48.  
    49.         public void DisposeNetworkSceneManager()
    50.         {
    51.             networkManager.SceneManager.OnLoad -= OnSceneNetworkLoaded;
    52.             networkManager.SceneManager.OnUnload -= OnSceneNetworkUnloaded;
    53.         }
    54.  
    55.         #endregion
    56.         #region privateMethods
    57.         private void OnSceneLoaded(Scene scene,LoadSceneMode loadMode)
    58.         {
    59.             Debug.Log("Loaded Scene: " + scene.name);
    60.             if(IsServer && scene.name == "BattleArena")
    61.             {
    62.                 SceneManager.SetActiveScene(scene);
    63.                 UnloadSceneAsync(0);
    64.             } else if(networkManager.IsClient)
    65.             {
    66.  
    67.             }
    68.         }
    69.  
    70.         private void OnSceneUnloaded(Scene scene)
    71.         {
    72.             Debug.Log("UnLoaded Scene: " + scene.name);
    73.             if (IsServer && scene.name == "BootStrap")
    74.             {
    75.                 OnBattleSceneLoaded?.Invoke();
    76.             }
    77.          
    78.         }
    79.  
    80.         private void OnSceneNetworkLoaded(ulong clientId, string sceneName, LoadSceneMode loadSceneMode, AsyncOperation asyncOperation)
    81.         {
    82.             Debug.Log("Loaded Network Scene: " + sceneName);
    83.         }
    84.  
    85.         private void OnSceneNetworkUnloaded(ulong clientId, string sceneName, AsyncOperation asyncOperation)
    86.         {
    87.             Debug.Log("Unload Network Scene: " + sceneName);
    88.         }
    89.         #endregion
    90.         #region publicMethods
    91.         public void LoadNetworkScene(string sceneName, LoadSceneMode mode = LoadSceneMode.Single, Action<ulong, string, LoadSceneMode> OnCompleteLoading = null)
    92.         {
    93.             Debug.Log("Loading Network Scene: " + sceneName);
    94.             networkManager.SceneManager.LoadScene(sceneName, mode);
    95.             if (OnCompleteLoading != null)
    96.             {
    97.                 networkManager.SceneManager.OnLoadComplete += CreateAndSetSynchedServerData;
    98.  
    99.                 void CreateAndSetSynchedServerData(ulong clientId, string sceneName, LoadSceneMode sceneMode)
    100.                 {
    101.                     if (clientId != networkManager.LocalClientId)
    102.                         return;
    103.  
    104.                     OnCompleteLoading.Invoke(clientId, sceneName, sceneMode);
    105.                     networkManager.SceneManager.OnLoadComplete -= CreateAndSetSynchedServerData;
    106.                 }
    107.  
    108.             }
    109.  
    110.         }
    111.  
    112.         public void LoadScene(string sceneName, LoadSceneMode mode = LoadSceneMode.Single, Action<Scene, LoadSceneMode> OnCompleteLoading = null)
    113.         {
    114.             Debug.Log("Loading Scene: " + sceneName);
    115.             SceneManager.LoadScene(sceneName, mode);
    116.             if(OnCompleteLoading != null) {
    117.  
    118.                 SceneManager.sceneLoaded += CreateAndSetSynchedServerData;
    119.  
    120.                 void CreateAndSetSynchedServerData(Scene scene, LoadSceneMode sceneMode)
    121.                 {
    122.                     OnCompleteLoading.Invoke(scene, sceneMode);
    123.                     SceneManager.sceneLoaded -= CreateAndSetSynchedServerData;
    124.                 }
    125.             }
    126.  
    127.         }
    128.  
    129.         public void UnloadSceneAsync(Scene scene)
    130.         {
    131.             SceneManager.UnloadSceneAsync(scene);
    132.         }
    133.  
    134.         public void UnloadSceneAsync(string sceneName)
    135.         {
    136.             SceneManager.UnloadSceneAsync(sceneName);
    137.         }
    138.  
    139.         public void UnloadSceneAsync(int sceneIndex)
    140.         {
    141.             Debug.Log("unload scene: " + sceneIndex);
    142.             AsyncOperation loadOpt = SceneManager.UnloadSceneAsync(sceneIndex);
    143.  
    144.         }
    145.  
    146.         public Scene GetActiveScene() => SceneManager.GetActiveScene();
    147.         #endregion
    148.     }
     
    nopropsneeded likes this.
  7. jackward84

    jackward84

    Joined:
    Jan 26, 2017
    Posts:
    87
    Also intermittently having this issue.

    Client is in "Tropical Scene", enters a ticket for "Arena Scene", matchmaker accepts and the player starts loading. The player immediately disposes of their current scene and loads up a "Loading Screen" scene.

    Server meanwhile is loading up the arena scene in response to the allocation payload.

    Client connects and the error message mentioned in this thread occurs at random, maybe 1/10 times.

    Best guess is my client is managing to load in the scene before the server is done loading it.

    I don't call ReadyServerForPlayersAsync() at all. It doesn't seem like this does anything, players get matched into the server regardless. In fact, I commented this line out because it was crashing. Should matchmaking tickets be getting fulfilled when the server hasn't said they're ready? If not then what is the point in this method?

    EDIT: I noticed whenever this happens, the client has the scene loaded twice. But the scene is only ever loaded once on the server. There is no client side scene switching code other than opening the "loading screen" which only has a camera, image and music, so I'm at a loss why this scene would get loaded twice. It's also really hard to get this to trigger, given I can go through 10+ matches without it ever triggering.
     
    Last edited: Jun 19, 2023
  8. jackward84

    jackward84

    Joined:
    Jan 26, 2017
    Posts:
    87
    After many hours of debugging I believe I have solved this issue, for my use case at least!

    My server start flow goes something like
    • Bootstrap (loads network, starts the server, etc)
    • Wait for allocation before doing anything else
    • On allocate -> change the map
    I believe the "start the server" vs "wait for allocation" bit is backward here. So clients were able to load in while the server was still on the bootstrap scene waiting for allocation. I explicitly set my clients to ignore server requests to change scene to bootstrap, but that isn't enough.

    To fix this, you can use ConnectionApproval.Pending = true, to temporarily pause the connection attempt (the client will not try to load any scene yet) until your scene has loaded on the server. Note that at this stage you have to begin managing the client connection state because if you change the pending state from true to false, and the client since disconnected, you'll get an exception. So you have to start manually checking if the client is in the NetworkManager's ConnectedClients before changing their Pending status. Unfortunately the connection approval process isn't async so you'll need to either start using dictionaries with the network ID in them, or use something like a coroutine.

    Alternatively, just leave them as pending and let them time out so they'll reconnect.

    I do thoroughly believe this is a bug with NetworkSceneManager. The client should not be trying to load the same scene multiple times when the server only changed their scene once.
     
    Last edited: Jun 20, 2023
    nopropsneeded likes this.
  9. Music_Corner

    Music_Corner

    Joined:
    Mar 8, 2020
    Posts:
    22
    When does it get fixed?!?!?!?!?!
    I started getting this dumb message after switching protocol from dtls to udp and updating unity transport package to fix another NGO bug..........

    UPD I switched back to dtls and it seem to help for some magic reason. Not sure if another bug comes back cause of it (really hope it does not but you know it's unity so...
     
    Last edited: Mar 13, 2024