ClientRpc not reaching all clients?

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?

void FixedUpdate()
    {
        if (collisionCheck)
        {

            if (IsServer)
            {
                RaycastHit hit;
                if (Physics.Linecast(lastpos, tf.position, out hit, layersToHit))
                {
                    if (hit.transform.GetComponent<NetworkObject>())
                    {
                        PlayerHitClientRpc(hit.transform.GetComponent<NetworkObject>().OwnerClientId, damagePotential);
                    }

                    gameObject.GetComponent<NetworkObject>().Despawn();
                }
                else
                {
                    lastpos = tf.position;
                }
            }
        }
    }

    [ClientRpc]
    private void PlayerHitClientRpc(ulong id, float dmg)
    {
        print("Owner client ID: " + OwnerClientId + ", ID: " + id);
        if (OwnerClientId == id)
        {
            GetComponent<PlayerHealth>().TakeDamage(dmg);
        }
    }

Hi @NorthernLight , 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.

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:

void FixedUpdate()
    {
        if (collisionCheck)
        {
            if (IsServer)
            {
                RaycastHit hit;
                if (Physics.Linecast(lastpos, tf.position, out hit, layersToHit))
                {
                    if (hit.transform.GetComponent<NetworkObject>())
                    {
                        ClientRpcParams clientRpcParams = new ClientRpcParams
                        {
                            Send = new ClientRpcSendParams
                            {
                                TargetClientIds = new ulong[] { hit.transform.GetComponent<NetworkObject>().OwnerClientId }
                            }
                        };

                        PlayerHitClientRpc( damagePotential, clientRpcParams);
                    }
                    GameObject go = Instantiate(explosionPrefab, hit.point, Quaternion.LookRotation(hit.normal));
                    go.GetComponent<NetworkObject>().Spawn();

                    gameObject.GetComponent<NetworkObject>().Despawn();
                }
                else
                {
                    lastpos = tf.position;
                }
            }
        }
    }

    [ClientRpc]
    private void PlayerHitClientRpc(float dmg, ClientRpcParams clientID)
    {
        GetComponent<PlayerHealth>().TakeDamage(dmg);
    }

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?

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?

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.

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”?

void FixedUpdate()
    {
        if (collisionCheck)
        {
            if (!IsServer)
            {
                return;
            }

            RaycastHit hit;
            if (Physics.Linecast(lastpos, tf.position, out hit, layersToHit))
            {
                if (hit.transform.GetComponentInParent<NetworkObject>())
                {
                    print("Client: " + hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId.ToString() + " was hit");
                    ClientRpcParams clientRpcParams = new ClientRpcParams
                    {
                        Send = new ClientRpcSendParams
                        {
                            TargetClientIds = new ulong[] { hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId }
                        }
                    };

                    PlayerHitClientRpc( damagePotential, clientRpcParams);
                }
                GameObject go = Instantiate(explosionPrefab, hit.point, Quaternion.LookRotation(hit.normal));
                go.GetComponent<NetworkObject>().Spawn();

                gameObject.GetComponent<NetworkObject>().Despawn();
            }
            else
            {
                lastpos = tf.position;
            }
        }
    }

    [ClientRpc]
    private void PlayerHitClientRpc(float dmg, ClientRpcParams clientID)
    {
        print(clientID + " receiving damage");
        GetComponent<PlayerHealth>().TakeDamage(dmg);
    }

Let’s try to find the root cause, @NorthernLight :

Does the message appear if you comment out line 29?

                gameObject.GetComponent<NetworkObject>().Despawn();

If it does not, can you try sending th RPC to all clients instead of just to the one that was hit?

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:

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

Client 1 should also be receiving the ClientRpc call now.

void FixedUpdate()
    {
        if (collisionCheck)
        {
            if (!IsServer)
            {
                return;
            }

            RaycastHit hit;
            if (Physics.Linecast(lastpos, tf.position, out hit, layersToHit))
            {
                if (hit.transform.GetComponentInParent<NetworkObject>())
                {
                    print("Client: " + hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId.ToString() + " was hit");
                    PlayerHitClientRpc( damagePotential);
                }
                GameObject go = Instantiate(explosionPrefab, hit.point, Quaternion.LookRotation(hit.normal));
                go.GetComponent<NetworkObject>().Spawn();

                gameObject.GetComponent<NetworkObject>().Despawn();
            }
            else
            {
                lastpos = tf.position;
            }
        }
    }

    [ClientRpc]
    private void PlayerHitClientRpc(float dmg)
    {
        print("Client: " + GetComponentInParent<NetworkObject>().OwnerClientId.ToString() + " receiving ClientRpc call");
    }

Same problem. Also i implemented the relay to set same ipv4 and port but still same problem.

Similar issue here. Client rpc is called only for non owner players. Owner player never recieves client rpc for some reason

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:

            print("Client: " + hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId.ToString() + " was hit");
            ClientRpcParams clientRpcParams = new ClientRpcParams
            {
                Send = new ClientRpcSendParams
                {
                    TargetClientIds = new List<ulong>(){ hit.transform.GetComponentInParent<NetworkObject>().OwnerClientId }
                }
            };

            PlayerHitClientRpc(damagePotential, clientRpcParams);

Let me know if the client receives the RPC?