How do you handle melee combat in Unet?

Hey everyone, so I have a character animation to strike. I want to know how you would handle the Unet side to this equation. Would you keep colliders permanently attached to player’s hands and enable them when they fire the animation or would you spawn them through the server? Would you deal damage through a Trigger or a Rigidbody? How would you go about syncing this through the internet? Thanks everyone. New to combat in Unet.

Feel free to discuss theories with me, you don’t have to write actual code. I’m in need of outside opinions fast, so just dropping a few words will do me a ton of help.

I’m new to it as well. I think you’d:

  • Have the client call a [Command] when they want to attack

  • The [Command] method verifies that the client can attack, and if so does detection

  • Detection can be done using a raycast/spherecast/capsulecast/etc or a sweeptest or just enabling the collider on the server and using OnCollisionEnter and either an if(NetworkServer.active) or a [Server] attribute.

  • Damage is applied using [Server] methods

  • Use a [ClientRpc] method to notify all clients that the player has successfully made an attack and to notify players of the effect of the attack (for example if a player took damage).

You use the [Command] attribute to allow a client to request an action.
You use the [Server] attribute on a method to make it so the method can only be called from the server itself.
You use [ClientRpc] to notify clients of events.

Here’s my detection code for a simple attack using an OverlapSphere. Keep in mind this is my learning project hence the comments and lack of elegance.

[Command]
protected void CmdAttack()
{
    if (!CanAttack) // Check that the player is able to attack
    {
        return;
    }
    // Damage and hit detection
    Collider[] hits = Physics.OverlapSphere(transform.TransformPoint(attackOffset), attackRadius, attackMask);
    foreach (var agent in hits.Select(hit => hit.GetComponent<Agent>()).Where(obj => obj != null).Where(obj => obj != this))
    {
        agent.TakeDamage(attackDamage);
    }
    RpcAttack(); // Notify clients
    attackCooldown = attackDelay;
}

[ClientRpc]
public void RpcAttack()
{
    onAttack.Invoke(); // My animator trigger, sounds, particles, etc are all linked to this from the Inspector
}

[Server] // can only be called from the server (can't command the server to do this)
public void TakeDamage(float damage)
{
    if (!IsImmuneToDamage) // Prevent kicking players while down
    {
        stamina = Mathf.Clamp01(stamina - damage);
        staminaCooldown = staminaRegenDelay;
        DropSmallItems(smallItemDropCount);
        if (stamina == 0f)
        {
            knockdownCooldown = knockdownDuration;
            KnockDown();
        }
    }
}

You wouldn’t want to notify every client about the attack though. Just the clients that are with in range of the player and so would actually care. Sending it to every connected client would just be a waste of Bandwidth.

Wouldn’t that be under the control of a NetworkProximityChecker? You’d have that on your players so they only keep nearby objects loaded.

Edit: Not sure if this would still send messages, though the server/host would be able to tell who was visible to who with NetworkIdentity.m_Observers, which NetworkProximityChecker modifies. I’m not sure if that’s factored in when UNET sends Rpcs.

Not too sure about Unity’s new Networking as I don’t use it. I have my own Custom Network Framework I use. But the way I do it is I have several Areas of Interest. Mobs and Players in one, Houses and large props in another, smaller props in a 3rd. I then use Triggers to find out when one of these objects enter it’s area of interest radius and then start sending updates to the client for that item.