Using .SetActive() over Unity Network for multiplayer. (Enable weapons on clients)

Hello, I’ve been struggling to get this right. I’ve googled around quite a bit and have found examples of other people using [ClientRpc] to activate objects over a network which I am trying to do but I think I am doing it wrong.

What I am trying to do it activate a weapon on my player and have all other clients see the weapon. All the weapons are attached to the player at once but are deactivated at start. When I want the weapon, I call SetActive() and activate the weapon I want.

Here is my full weaponManager Script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class WeaponsManager : NetworkBehaviour
{
    //The Gameobject holding the weapons
    [SerializeField]
    GameObject weaponHolder;

    //Holds all of the players weapons
    [SerializeField]
    GameObject[] Weapons;
    int weaponNumber = 0; //Used to scroll through weapons in inventory through Weapons Array

    //For now just increase weapons when "1" is pressed
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            weaponNumber++;
            //Apply weapon through out the network
            CmdSwapWeapon();
        }
    }

    //Gives the player Their start Weapon
    private void Start()
    {
        weaponNumber = 0;
        //Apply weapon through out the network
        CmdSwapWeapon();
    }

    [Command]
    void CmdSwapWeapon()
    {
        //Apply it to all other clients
        RpcSwapWeapon();
    }

    [ClientRpc]
    void RpcSwapWeapon()
    {
        //Disable previous weapon
        if (weaponNumber > 0)
            Weapons[weaponNumber - 1].SetActive(false);

        //If weapon Number is greater than all weapons in inventory, set it to 0 for weapon 1
        if (weaponNumber >= Weapons.Length)
        {
            weaponNumber = 0;
        }
        //Set current weapon active
        Weapons[weaponNumber].SetActive(true);
    }
}

If the above is too much, I can split up each method and explain it. Basically all the above script does is on start, it assigns the default weapon.
Than when, “1” is pressed, it swaps to a new weapon and deactivates the last weapon

Here is an image of what the script looks like in the editor102943-weaponmanager.png

The above works on the local player but it does not sync. Please ask if you have any questions.

Assuming that every player has the authority on his playerPrefab.
Assuming that you want a non server-authority model (own players decide themseleves if the weapon switch can be done).

Some things to considerate:

  • You can only send Rpc from the server instance.
  • You can only ask for Cmd from the instance that you have the authority.

With all the assumptions and considerations that is what i would do:

  1. Add the weapon manager script to the player prefab (if it is not done)

  2. on update, check if you are the local player (the script will be running for each player instance, and you only want to affect the player that has the authority in that machine). you can do if(isLocalPlayer) or if(hasAuthority). If you arent just return

  3. From update, call to localSwapWeapon. This function will do what currently is inside your RPC, also that currentWeapon++

  4. Also from update, do the following:

    if(isServer){
    RpcSwap();
    }else{
    CmdSwap();
    }

this will ask all the clients to swap if you are the server, or the sewrver to swap if you are a client

  • RpcSwap will only call localSwap . Making the clients that receive the rpc to update

  • CmdSwap will call localSwap and RpcSwap. Making the host update the changes and distribute them.

  • On top of RpcSwap ask if(isLocalPlayer) and return (because you are receiving back the notification that you started)