Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

Question Respawning Problem with Unity Netcode

Discussion in 'Netcode for GameObjects' started by Suchit_Niranjan, Aug 15, 2023.

  1. Suchit_Niranjan

    Suchit_Niranjan

    Joined:
    Mar 7, 2023
    Posts:
    15
    I've been working on implementing a respawn system using Unity Netcode for my game objects. The respawn process works as expected when the host kills the client, but I'm encountering a problem when the client kills the host. The host respawns correctly, but it floats in the air (because i am spawning it 1f on y axis) on the client and some of the scripts attached to it, such as PlayerMovement, GunSystem, ClientNetworkTransform, and Target, seem to be disabled.

    I've provided relevant code snippets from my Target script and GunSystem script below. The Target script handles health, respawning, and notifying clients about health changes, while the GunSystem script initiates damage to the target through raycasting.

    Target Script:

    Code (CSharp):
    1. [ServerRpc(RequireOwnership = false)]
    2.     public void UpdateHealthServerRpc(float damage, ulong clientId)
    3.     {
    4.         health.Value -= damage;
    5.  
    6.         NotifyHealthChangeClientRpc(damage, new ClientRpcParams{
    7.             Send = new ClientRpcSendParams
    8.             {
    9.                 TargetClientIds = new ulong[] {clientId}
    10.             }
    11.         });
    12.  
    13.         Die(clientId);
    14.     }
    15.  
    16.     public void Die(ulong clientId)
    17.     {
    18.         if(health.Value < 0f)
    19.         {
    20.             Debug.Log("Destroying");
    21.             gameObject.GetComponent<NetworkObject>().Despawn();
    22.            
    23.             StartCoroutine(Delay(5f));
    24.  
    25.             RespawnPlayer(clientId);
    26.         }
    27.     }
    28.  
    29.     public void RespawnPlayer(ulong clientId)
    30.     {
    31.         NetworkObject playerPrefab = Instantiate(NetworkManager.LocalClient.PlayerObject, new Vector3(0f, 1f, 0f), Quaternion.identity);
    32.         playerPrefab.SpawnAsPlayerObject(clientId);
    33.     }
    34.  
    35.     [ClientRpc]
    36.     public void NotifyHealthChangeClientRpc(float damage, ClientRpcParams clientRpcParams = default)
    37.     {
    38.         Debug.Log("Client got damage");
    39.     }
    GunSystem script:
    Code (CSharp):
    1. //RayCast
    2.         if (Physics.Raycast(rayCastOrigin.position, direction, out rayHit, range, whatIsEnemy))
    3.         {
    4.             Debug.Log(rayHit.collider.name);
    5.  
    6.             if (rayHit.collider.CompareTag("Enemy"))
    7.             {
    8.                 var playerHit = rayHit.collider.GetComponent<NetworkObject>();
    9.                 if(playerHit != null)
    10.                 {
    11.                     playerHit.GetComponent<Target>().UpdateHealthServerRpc(damage, playerHit.OwnerClientId);
    12.                 }              
    13.             }
    14.         }
     
  2. Nyphur

    Nyphur

    Joined:
    Jan 29, 2016
    Posts:
    98
    In general you want to avoid destroying and spawning multiplayer objects as much as possible, especially the players as their objects are linked to the NetworkManager's connected client list and that gets messy. It's easier to disable the player's control inputs and visuals and then teleport the player and re-enable everything when they "respawn" instead.

    Be aware that you may run into issues with ownership when teleporting or moving players with clientnetworktransforms in code, and you may run into an issue where the networkrigidbody and networktransform both try to sync locations in the same frame so your teleport gets overwritten. That was a fun one to diagnose.
     
  3. Suchit_Niranjan

    Suchit_Niranjan

    Joined:
    Mar 7, 2023
    Posts:
    15
    Thank you for your guidance! I followed your suggestion and made some changes to the Target script.

    Code (CSharp):
    1. public void Die(ulong clientId)
    2.     {
    3.         if(health.Value < 0f)
    4.         {
    5.             Debug.Log("Destroying");
    6.             //gameObject.GetComponent<NetworkObject>().Despawn();
    7.             NetworkObject playerPrefab = NetworkManager.Singleton.ConnectedClients[clientId].PlayerObject;
    8.             playerPrefab.GetComponent<PlayerMovement>().enabled = false;
    9.             playerPrefab.GetComponent<MeshRenderer>().enabled = false;
    10.             playerPrefab.GetComponent<GunSystem>().enabled = false;
    11.          
    12.             //StartCoroutine(Delay(5f));
    13.  
    14.             RespawnPlayer(clientId);
    15.         }
    16.     }
    17.  
    18.     public void RespawnPlayer(ulong clientId)
    19.     {
    20.         // NetworkObject playerPrefab = Instantiate(NetworkManager.LocalClient.PlayerObject, new Vector3(0f, 1f, 0f), Quaternion.identity);
    21.         // playerPrefab.SpawnAsPlayerObject(clientId);
    22.         NetworkObject playerPrefab = NetworkManager.Singleton.ConnectedClients[clientId].PlayerObject;
    23.         playerPrefab.transform.position = new Vector3(0f, 1f, 0f);
    24.         playerPrefab.GetComponent<MeshRenderer>().enabled = true;
    25.         playerPrefab.GetComponent<PlayerMovement>().enabled = true;
    26.         playerPrefab.GetComponent<GunSystem>().enabled = true;
    27.         playerPrefab.GetComponent<Target>().health.Value = 100f;
    28.  
    29.     }
    However, I encountered an issue related to ClientNetworkTransform and NetworkRigidBody. The client can kill the host successfully, but the host isn't able to kill clients. Although client's health gets restored to 100, but the position doesn't change.
     
    Last edited: Aug 19, 2023
  4. Nyphur

    Nyphur

    Joined:
    Jan 29, 2016
    Posts:
    98
    Could be the bug I described above, it's an issue where the clientnetworktransform and the networkrigidbody both set the position so the change of position gets instantly reverted. Without seeing the rest of your code it'd be hard to diagnose.

    Also, how does the server actually tell the clients that a character has died or respawned? I can see that clients can tell the server via a serverrpc to deal damage to the character, and various scripts then get disabled and re-enabled but this only happens on the server. You need to instead dispatch these events to all clients through a ClientRpc that enables and disables the scripts.