Client cannot damage Host

Hello, currently I’m in the Gameplay additions section of the Netcode course. And I’ve noticed that when a client shoots a host his life does not decrease for him neither in script or in the healthbar. What could be the reason for this lag?
I have debugged and noticed that when a client shoots host, in OnTriggerEnter function second if statement is true and it returns out of the method instead of decreasing the health.

Hi there,
The second if statement is to prevent the client from shooting themselves. It’s checking if the projectile owner is the same as the tank it’s colliding with. We use a more robust method to deal with this later using the Physics2D collisions matrix.

Keep in mind, collisions that cause damage are only occurring on the Server. The projectiles in the client instances are only dummy projectiles. So if you debug on the client, you shouldn’t expect to see the damage done there. The health is synced to the clients whenever it is changed on the host.

Sorry, I didn’t fully understand you. I debuged it on the host, to see why the projectiles which client released couldn’t damage the host. And it seems like host recognises those projectiles as his own. It’s pretty weird.

Would you like to share your code for spawning the projectiles? Perhaps their ownership isn’t setting up correctly.

Sure here it is

using System;
using Core.Coins;
using Core.Combat;
using Input;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Serialization;

namespace Core.Player
{
    public class ProjectileLauncher : NetworkBehaviour
    {
        [Header("References")] 
        [SerializeField] private CoinWallet coinWallet;
        [SerializeField] private InputReader inputReader;
        [SerializeField] private Transform projectileSpawnPoint;
        [SerializeField] private GameObject serverProjectilePrefab;
        [SerializeField] private GameObject clientProjectilePrefab;
        [SerializeField] private GameObject muzzleFlash;
        [SerializeField] private Collider2D playerCollider;

        [Header("Settings")] 
        [SerializeField] private float projectileSpeed;
        [SerializeField] private float fireRate;
        [SerializeField] private float muzzleFlashDuration;
        [SerializeField] private int costToFire;

        private bool _isFiring;
        private float _muzzleFlashTimer;
        private float _timer;

        public override void OnNetworkSpawn()
        {
            if (!IsOwner) return;

            inputReader.PrimaryFireEvent += HandlePrimaryFire;
        }

        public override void OnNetworkDespawn()
        {
            if (!IsOwner) return;

            inputReader.PrimaryFireEvent -= HandlePrimaryFire;
        }

        private void Update()
        {
            if (_muzzleFlashTimer > 0f)
            {
                _muzzleFlashTimer -= Time.deltaTime;

                if (_muzzleFlashTimer <= 0f)
                {
                    muzzleFlash.SetActive(false);
                }
            }
            
            if (!IsOwner) return;

            if(_timer > 0) _timer -= Time.deltaTime;
            
            if (!_isFiring) return;

            if (_timer > 0) return;

            if (coinWallet.TotalCoins.Value < costToFire) return;
            
            PrimaryFireServerRpc(projectileSpawnPoint.position, projectileSpawnPoint.up);
            
            SpawnDummyProjectile(projectileSpawnPoint.position, projectileSpawnPoint.up);

            _timer = 1 / fireRate;
        }

        private void HandlePrimaryFire(bool shouldFire)
        {
            _isFiring = shouldFire;
        }

        [ServerRpc]
        private void PrimaryFireServerRpc(Vector3 spawnPos, Vector3 direction)
        {
            if (coinWallet.TotalCoins.Value < costToFire) return;
            
            coinWallet.SpendCoins(costToFire);
            
            GameObject projectileInstance = 
                Instantiate(serverProjectilePrefab, spawnPos, Quaternion.identity);
            
            projectileInstance.transform.up = direction;
            
            Physics2D.IgnoreCollision(playerCollider, projectileInstance.GetComponent<Collider2D>());
            
            if (projectileInstance.TryGetComponent<Rigidbody2D>(out Rigidbody2D rb))
            {
                rb.velocity = rb.transform.up * projectileSpeed;
            }
            
            SpawnDummyProjectileClientRpc(spawnPos, direction);
        }

        [ClientRpc]
        private void SpawnDummyProjectileClientRpc(Vector3 spawnPos, Vector3 direction)
        {
            if(IsOwner) return;
            
            SpawnDummyProjectile(spawnPos, direction);
        }
        
        private void SpawnDummyProjectile(Vector3 spawnPos, Vector3 direction)
        {
            muzzleFlash.SetActive(true);
            _muzzleFlashTimer = muzzleFlashDuration;
            
            GameObject projectileInstance = 
                Instantiate(clientProjectilePrefab, spawnPos, Quaternion.identity);

            projectileInstance.transform.up = direction;
            
            Physics2D.IgnoreCollision(playerCollider, projectileInstance.GetComponent<Collider2D>());

            if (projectileInstance.TryGetComponent<DealDamageOnContact>(out DealDamageOnContact dealDamageOnContact))
            {
                dealDamageOnContact.SetOwner(OwnerClientId);
            }
            
            if (projectileInstance.TryGetComponent<Rigidbody2D>(out Rigidbody2D rb))
            {
                rb.velocity = rb.transform.up * projectileSpeed;
            }
        }
    }
}

At some point we add the line:

if (projectileInstance.TryGetComponent<DealDamageOnContact>(out DealDamageOnContact dealDamage))
{
      dealDamage.SetOwner(OwnerClientId);
}

Right before we SpawnDummProjectile in the PrimaryFireServerRpc method.
It might just be in the next lecture and you haven’t gotten there yet?

In the DealDamageOnContact script:

private ulong ownerClientId;

    public void SetOwner(ulong ownerClientId)
    {
        this.ownerClientId = ownerClientId;
    }

Thanks! That has worked! Looks like I just forgot to add this piece of code there) Thank you very much!)

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms