Search Unity

Bug Player prefabs not spawning in non-host/client side

Discussion in 'Netcode for GameObjects' started by thelaughingzasshu, Feb 7, 2024.

  1. thelaughingzasshu

    thelaughingzasshu

    Joined:
    Jan 1, 2024
    Posts:
    12
    When I load the arena scene, only the player prefab of the host player will spawn, while the client player prefab totally does not spawn at all. Below is the relevant code of the object in charge of spawning the player characters.

    Code (CSharp):
    1. public class PlayerLoader : NetworkBehaviour
    2. {
    3.     // public TextMeshProUGUI chara;
    4.     [SerializeField] GameObject[] goats;
    5.     private bool gameStart = false;
    6.  
    7.     [ServerRpc(RequireOwnership = false)]
    8.     public void SpawnPlayerServerRpc(ulong clientId, int prefabId, ServerRpcParams serverRpcParams = default)
    9.     {
    10.         //if (!IsServer) GetComponent<NetworkObject>().SpawnWithOwnership(NetworkManager.Singleton.LocalClientId);
    11.         GameObject newPlayer;
    12.         newPlayer = Instantiate(goats[prefabId]);
    13.         Debug.Log("Spawned");
    14.         NetworkObject netObj = newPlayer.GetComponent<NetworkObject>();
    15.         netObj.SpawnWithOwnership(clientId, true);
    16.     }
    17.  
    18.     public override void OnNetworkSpawn()
    19.     {
    20.        
    21.     }
    22.  
    23.     // Start is called before the first frame update
    24.     void Start()
    25.     {
    26.         GetComponent<NetworkObject>().SpawnWithOwnership(OwnerClientId);      
    27.         int id = PlayerPrefs.GetInt("ButtonParameter", -1);
    28.         Debug.Log(id);
    29.         SpawnPlayerServerRpc(OwnerClientId, id);
    30.         PlayerPrefs.DeleteKey("ButtonParameter");
    31.     }
    32. }
    I noticed that the debug logs for both Start() and SpawnPlayerServerRpc() did not even show up for the non-host/client player, which means the game completely ignored these instructions! I'm not really sure how to approach this problem aside from that. Any help would be greatly appreciated!
     
  2. NoelStephens_Unity

    NoelStephens_Unity

    Unity Technologies

    Joined:
    Feb 12, 2022
    Posts:
    258
    I made modifications with the assumption that PlayerLoader was on an in-scene placed NetworkObject.
    If that is the case, then this adjustment should work:
    Code (CSharp):
    1. /// <summary>
    2. /// I am assuming this component sits on an an in-scene placed NetworkObject.
    3. /// </summary>
    4. public class PlayerLoader : NetworkBehaviour
    5. {
    6.     // public TextMeshProUGUI chara;
    7.     [SerializeField] GameObject[] goats;
    8.     private bool gameStart = false;
    9.  
    10.     [ServerRpc(RequireOwnership = false)]
    11.     public void SpawnPlayerServerRpc(int prefabId, ServerRpcParams serverRpcParams = default)
    12.     {
    13.         var newPlayer = Instantiate(goats[prefabId]);
    14.         var netObj = newPlayer.GetComponent<NetworkObject>();
    15.  
    16.         // Use the ServerRpcParams.Receive to know who the sender is of an Rpc.
    17.         //netObj.SpawnWithOwnership(clientId, true);
    18.  
    19.         // As long as this component is on an in-scene placed NetworkObject, then
    20.         // each player as they connect should invoke the OnNetworkSpawn which will invoke
    21.         // this SpawnPlayerServerRpc. Use the client id of the client who sent the Rpc as the owner id.
    22.         netObj.SpawnWithOwnership(serverRpcParams.Receive.SenderClientId, true);
    23.         Debug.Log($"[Client-{serverRpcParams.Receive.SenderClientId}] Spawned as prefab index-{prefabId} ({newPlayer.name}) on server the side.");
    24.     }
    25.  
    26.     public override void OnNetworkSpawn()
    27.     {
    28.         int id = PlayerPrefs.GetInt("ButtonParameter", -1);
    29.         Debug.Log($"[Client-{NetworkManager.LocalClientId}] Chose to spawn as the {goats[id].name} (index {id}).");
    30.         SpawnPlayerServerRpc(id);
    31.         PlayerPrefs.DeleteKey("ButtonParameter");
    32.     }
    33. }
    If PlayerLoader is not on an in-scene placed NetworkObject, then let me know and describe how the associated NetworkObject is spawned.

    If it is an in-scene placed NetworkObject, then what is happening is the Start method is being invoked prior to OnNetworkSpawn. RPCs cannot be invoked prior to spawning the associated NetworkObject.

    Let me know if this resolves your issue?
     
  3. thelaughingzasshu

    thelaughingzasshu

    Joined:
    Jan 1, 2024
    Posts:
    12
    I got it to work, thank you! Initially it didn't work but I realized in another script I used SceneManager to move from the menu scene to the arena scene where the player prefab loader was located instead of NetworkManager.Singleton.SceneManager and I also put that before NetworkManager.Singleton.StartHost()/StartClient() when it should have been put after. Combined with your code I finally solved the issue. :)
     
    NoelStephens_Unity likes this.
  4. NoelStephens_Unity

    NoelStephens_Unity

    Unity Technologies

    Joined:
    Feb 12, 2022
    Posts:
    258
    Awesome!
    Happy netcoding!
     
    thelaughingzasshu likes this.