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

Question ClientRpc not reaching all clients?

Discussion in 'Netcode for GameObjects' started by SuphaMahn, Jan 16, 2023.

  1. SuphaMahn

    SuphaMahn

    Joined:
    May 31, 2011
    Posts:
    7
    I have a physics based bullet which is handled on the server. When a player is hit I want to send a message to the player which has been hit. I'm using the code below. When the PlayerHitClientRpc is run it only reaches the server (client id 0). Is there something wrong with my code/logic or could the problem lie somewhere else?

    Code (CSharp):
    1. void FixedUpdate()
    2.     {
    3.         if (collisionCheck)
    4.         {
    5.  
    6.             if (IsServer)
    7.             {
    8.                 RaycastHit hit;
    9.                 if (Physics.Linecast(lastpos, tf.position, out hit, layersToHit))
    10.                 {
    11.                     if (hit.transform.GetComponent<NetworkObject>())
    12.                     {
    13.                         PlayerHitClientRpc(hit.transform.GetComponent<NetworkObject>().OwnerClientId, damagePotential);
    14.                     }
    15.  
    16.                     gameObject.GetComponent<NetworkObject>().Despawn();
    17.                 }
    18.                 else
    19.                 {
    20.                     lastpos = tf.position;
    21.                 }
    22.             }
    23.         }
    24.     }
    25.  
    26.     [ClientRpc]
    27.     private void PlayerHitClientRpc(ulong id, float dmg)
    28.     {
    29.         print("Owner client ID: " + OwnerClientId + ", ID: " + id);
    30.         if (OwnerClientId == id)
    31.         {
    32.             GetComponent<PlayerHealth>().TakeDamage(dmg);
    33.         }
    34.     }
     
  2. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    Hi @SuphaMahn , to send the RPC to a specific client you should use the ClientRpcSendParams parameter, see the example here. Moreover, I'd recommend that you make your health server-authoritative through a syncvar, otherwise clients will be able to cheat the TakeDamage() method.
     
  3. SuphaMahn

    SuphaMahn

    Joined:
    May 31, 2011
    Posts:
    7
    Hi, and thank you for the tip regarding moving my health management. I will implement that later. For now I just want to make sure the hit is communicated to the player. I changed my code so that the clientRpc method targets a specific client but it's not working. My updated code:

    Code (CSharp):
    1. void FixedUpdate()
    2.     {
    3.         if (collisionCheck)
    4.         {
    5.             if (IsServer)
    6.             {
    7.                 RaycastHit hit;
    8.                 if (Physics.Linecast(lastpos, tf.position, out hit, layersToHit))
    9.                 {
    10.                     if (hit.transform.GetComponent<NetworkObject>())
    11.                     {
    12.                         ClientRpcParams clientRpcParams = new ClientRpcParams
    13.                         {
    14.                             Send = new ClientRpcSendParams
    15.                             {
    16.                                 TargetClientIds = new ulong[] { hit.transform.GetComponent<NetworkObject>().OwnerClientId }
    17.                             }
    18.                         };
    19.  
    20.                         PlayerHitClientRpc( damagePotential, clientRpcParams);
    21.                     }
    22.                     GameObject go = Instantiate(explosionPrefab, hit.point, Quaternion.LookRotation(hit.normal));
    23.                     go.GetComponent<NetworkObject>().Spawn();
    24.  
    25.                     gameObject.GetComponent<NetworkObject>().Despawn();
    26.                 }
    27.                 else
    28.                 {
    29.                     lastpos = tf.position;
    30.                 }
    31.             }
    32.         }
    33.     }
    34.  
    35.     [ClientRpc]
    36.     private void PlayerHitClientRpc(float dmg, ClientRpcParams clientID)
    37.     {
    38.         GetComponent<PlayerHealth>().TakeDamage(dmg);
    39.     }
     
  4. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    What's "not working", exactly?

    Is the method called on all lcients or is it not called at all?

    What version of Netcode For GameObjects are you using?
     
  5. SuphaMahn

    SuphaMahn

    Joined:
    May 31, 2011
    Posts:
    7
    Sorry for the vagueness. Not working as in no clients are reached. Even when sent directly to the client the method TakeDamage is not executed. The client doesn't receive the clientRpc call. Same problem as when I sent the clientRpc call to all clients. I used Netcode 1.1.0 but today I updated to 1.2.0. No changes.

    I'm using Client Network Transform on the player objects. Could that be a problem?
     
  6. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    Nope, but I re-read your original post and noticed that you said the host receives the RPC. Are you sure the clients are actually owners of their players? Otherwise OwnerClientId will always return the host.
     
  7. SuphaMahn

    SuphaMahn

    Joined:
    May 31, 2011
    Posts:
    7
    I think so. I have implemented some checks of their OwnerClientId before registering the hit and sending the clientRpc call. It shows the right id number when the bullet hits. My updated code is below. (Did some changes to the code and the objects). The "receiving damage" message refuses to appear, but the "was hit" message shows the right OwnerClientId.

    ..or am I misunderstanding something when you say "actually owners of their players"?

    Code (CSharp):
    1. void FixedUpdate()
    2.     {
    3.         if (collisionCheck)
    4.         {
    5.             if (!IsServer)
    6.             {
    7.                 return;
    8.             }
    9.  
    10.             RaycastHit hit;
    11.             if (Physics.Linecast(lastpos, tf.position, out hit, layersToHit))
    12.             {
    13.                 if (hit.transform.GetComponentInParent<NetworkObject>())
    14.                 {
    15.                     print("Client: " + hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId.ToString() + " was hit");
    16.                     ClientRpcParams clientRpcParams = new ClientRpcParams
    17.                     {
    18.                         Send = new ClientRpcSendParams
    19.                         {
    20.                             TargetClientIds = new ulong[] { hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId }
    21.                         }
    22.                     };
    23.  
    24.                     PlayerHitClientRpc( damagePotential, clientRpcParams);
    25.                 }
    26.                 GameObject go = Instantiate(explosionPrefab, hit.point, Quaternion.LookRotation(hit.normal));
    27.                 go.GetComponent<NetworkObject>().Spawn();
    28.  
    29.                 gameObject.GetComponent<NetworkObject>().Despawn();
    30.             }
    31.             else
    32.             {
    33.                 lastpos = tf.position;
    34.             }
    35.         }
    36.     }
    37.  
    38.     [ClientRpc]
    39.     private void PlayerHitClientRpc(float dmg, ClientRpcParams clientID)
    40.     {
    41.         print(clientID + " receiving damage");
    42.         GetComponent<PlayerHealth>().TakeDamage(dmg);
    43.     }
     
  8. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    Let's try to find the root cause, @SuphaMahn :

    Does the message appear if you comment out line 29?

    Code (CSharp):
    1.                 gameObject.GetComponent<NetworkObject>().Despawn();
    2.  
    If it does not, can you try sending th RPC to all clients instead of just to the one that was hit?
     
  9. SuphaMahn

    SuphaMahn

    Joined:
    May 31, 2011
    Posts:
    7
    I tried commenting out the line but the message still didn't appear.

    I then changed it back to a ClientRpc call without parameters. Same as before, the host is reached but no other clients. Example of output in console:

    upload_2023-1-19_16-59-49.png

    Client 1 should also be receiving the ClientRpc call now.

    Code (CSharp):
    1. void FixedUpdate()
    2.     {
    3.         if (collisionCheck)
    4.         {
    5.             if (!IsServer)
    6.             {
    7.                 return;
    8.             }
    9.  
    10.             RaycastHit hit;
    11.             if (Physics.Linecast(lastpos, tf.position, out hit, layersToHit))
    12.             {
    13.                 if (hit.transform.GetComponentInParent<NetworkObject>())
    14.                 {
    15.                     print("Client: " + hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId.ToString() + " was hit");
    16.                     PlayerHitClientRpc( damagePotential);
    17.                 }
    18.                 GameObject go = Instantiate(explosionPrefab, hit.point, Quaternion.LookRotation(hit.normal));
    19.                 go.GetComponent<NetworkObject>().Spawn();
    20.  
    21.                 gameObject.GetComponent<NetworkObject>().Despawn();
    22.             }
    23.             else
    24.             {
    25.                 lastpos = tf.position;
    26.             }
    27.         }
    28.     }
    29.  
    30.     [ClientRpc]
    31.     private void PlayerHitClientRpc(float dmg)
    32.     {
    33.         print("Client: " + GetComponentInParent<NetworkObject>().OwnerClientId.ToString() + " receiving ClientRpc call");
    34.     }
     
  10. BlackBoxGaming

    BlackBoxGaming

    Joined:
    Mar 25, 2020
    Posts:
    10
    Same problem. Also i implemented the relay to set same ipv4 and port but still same problem.
     
  11. Music_Corner

    Music_Corner

    Joined:
    Mar 8, 2020
    Posts:
    22
    Similar issue here. Client rpc is called only for non owner players. Owner player never recieves client rpc for some reason
     
  12. NoelStephens_Unity

    NoelStephens_Unity

    Unity Technologies

    Joined:
    Feb 12, 2022
    Posts:
    252
    I would highly recommend updating to NGO v1.7.1 to make sure you are not experiencing an issue that has since been fixed.

    I would also try using this adjustment to your assignment of the owner client identifier in the ClientRpcSendParams:

    Code (CSharp):
    1.             print("Client: " + hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId.ToString() + " was hit");
    2.             ClientRpcParams clientRpcParams = new ClientRpcParams
    3.             {
    4.                 Send = new ClientRpcSendParams
    5.                 {
    6.                     TargetClientIds = new List<ulong>(){ hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId }
    7.                 }
    8.             };
    9.  
    10.             PlayerHitClientRpc(damagePotential, clientRpcParams);
    Let me know if the client receives the RPC?