Search Unity

Bug NetworkSceneManager.SceneLoad is deserializing spawned objects in the wrong scene

Discussion in 'Netcode for GameObjects' started by adamgryu, May 25, 2023.

  1. adamgryu

    adamgryu

    Joined:
    Mar 1, 2014
    Posts:
    188
    I was getting this exception upon switching scenes:

    Code (CSharp):
    1. NotServerException: Destroy a spawned NetworkObject on a non-host client is not valid. Call Destroy or Despawn on the server/host instead.
    Upon further debugging, I found that the server loads the new scene before the client, and dynamically spawned objects on the server (using the hybrid approach from here) are synchronized with the client before the client has finished loading their scene.

    This causes the objects to spawn into the client's old scene before it has been unloaded. Then as the scene is unloaded (with these newly spawned objects also unloading), this exception is thrown.

    Any ideas about what might be causing this, or how to avoid this?

    EDIT: Here is my spawner class I'm using.
    Code (CSharp):
    1. public class NonPooledDynamicSpawner : NetworkBehaviour {
    2.  
    3.     public GameObject prefabToSpawn;
    4.     public bool destroyWithSpawner;
    5.  
    6.     private NetworkObject spawnedNetworkObject;
    7.     private bool spawned = false;
    8.  
    9.     public override void OnNetworkSpawn() {
    10.         // Only the server spawns, clients will disable this component on their side
    11.         enabled = IsServer;
    12.         if (!enabled || prefabToSpawn == null) {
    13.             return;
    14.         }
    15.  
    16.         Spawn();
    17.     }
    18.  
    19.     private void Spawn() {
    20.         Assert.IsFalse(spawned);
    21.  
    22.         // Instantiate the GameObject Instance
    23.         var prefabInstance = Instantiate(prefabToSpawn);
    24.  
    25.         // Optional, this example applies the spawner's position and rotation to the new instance
    26.         prefabInstance.transform.position = transform.position;
    27.         prefabInstance.transform.rotation = transform.rotation;
    28.  
    29.         // Get the instance's NetworkObject and Spawn
    30.         spawnedNetworkObject = prefabInstance.GetComponent<NetworkObject>();
    31.         spawnedNetworkObject.Spawn(true);
    32.  
    33.         spawned = true;
    34.     }
    35.  
    36.     public override void OnNetworkDespawn() {
    37.         if (IsServer && destroyWithSpawner && spawnedNetworkObject != null && spawnedNetworkObject.IsSpawned) {
    38.             spawnedNetworkObject.Despawn();
    39.         }
    40.         base.OnNetworkDespawn();
    41.     }
    42. }
     
    Last edited: May 25, 2023
  2. Mj-Kkaya

    Mj-Kkaya

    Joined:
    Oct 10, 2017
    Posts:
    179
    Hi @adamgryu,
    If I correctly understand of your problem there is a simple solution.
    Don't call "Spawn()" method in "OnNetworkSpawn()" method. Just listen "NetworkManager.Singleton.SceneManager.OnLoadComplete" event then spawn the object.
    I highly recommend to read you Scene Events.
     
  3. adamgryu

    adamgryu

    Joined:
    Mar 1, 2014
    Posts:
    188
    I have read through the scene documentation - there's a lot to take in so I might have missed a critical detail. It still wasn't able to help me figure out the problem.

    When I was debugging, I saw that OnNetworkSpawn() is called after LoadEventCompleted. So I don't think OnLoadComplete would help since it happens even earlier?

    In this case, the server and clients were ready to load the next scene but hadn't unloaded the prior scene due to the way async loading works with LoadSceneMode.Single (I assume AsyncOperation.allowSceneActivation isn't true yet). Since the server triggers the new scene first, it would load before the clients did and trigger the Spawn() before the clients even got the LoadEventCompleted signal and begun their scene activation.

    I ended up addressing this by having the clients manually ACK the server once some objects in their scene were actually started, and the server delayed the spawning until all the ACKs were received.

    Still, this seems like something the framework handle? Is this expected behavior or did I mess up somewhere?
     
    Last edited: May 26, 2023
  4. Mj-Kkaya

    Mj-Kkaya

    Joined:
    Oct 10, 2017
    Posts:
    179
    Do you use "NetworkManager.Singleton.SceneManager.LoadScene()" method to load the scene?
    Actually I wrote a error post like what you have : My Post
     
  5. TruckerJoe

    TruckerJoe

    Joined:
    Feb 25, 2019
    Posts:
    39
    @adamgryu
    Do you find the reason for that error?
    It sounds, that I have exactly the same problem...