简体   繁体   中英

Unity Networking | Authority issue - players can move but not shoot independently

I am making a multiplayer game using Unet. Currently, the players can move independently (ie, if user one presses d, then character one will move right if user two presses d then character two will move right) - however, both players shoot 'through' the host.

My movement code is inside the PlayerUnit script. It has one !isLocalPlayer check at the top, in the Update() method. This check is performed before the script detects for user inputs (ie, w, s, mouse1, etc.).

This all works fine when the correct key is pressed; the proper action is performed. Eg:

if (Input.GetKeyDown(up))
    Jump();

Shooting works in a slightly different way as it involves a different script.

When mouse1 is pressed, the Shoot() method in PlayerUnit is called. This, in turn, uses a Command inside the PlayerUnit script to call a ClientRpc in a separate WeaponMaster script, which calls the Fire() coroutine.

In PlayerUnit:

private void Shoot ()
{   
    //WeaponMaster.wM.Shoot();
    CmdShoot();

}

[Command]
void CmdShoot ()
{
    WeaponMaster.wM.RpcShoot();
}

In WeaponMaster:

[ClientRpc]
public void RpcShoot ()
{
    if (ammo != 0)
    {
        if (isAutomatic == true)
        {
            keepFiring = true;
            StartCoroutine(Fire());
        }

        if (isAutomatic == false && noQuickFire == true)
           StartCoroutine(Fire());
    }
}

WeaponMaster has one !isLocalPlayer check as well, once again in the Update() method.

When debugging, I know that playerTwo 's (client) Shoot() method is being called, but playerOne 's RpcShoot is being executed. Everything works fine when playerOne shoots - hence the problem of both players shooting 'through' the host.

All the scripts are on the same object with one NetworkIdentity component.

I'm convinced the problem is just a missing authority check - but I've tried adding !isLocalPlayer tests in the various methods to no avail.

As said my guess is that a Singleton pattern in WeaponMaster.wM is not a good approach here since you get the wrong reference and since everything goes through the server might simply always get the same reference no matter who called CmdShoot .


You should rather store each players own WeaponMaster reference and go through it like in PlayerUnit

// Already reference this via the inspector (drag&drop)
[SerializeField] private WeaponMaster weaponMaster;

// or as fallback get it on runtime
private void Awake()
{
    if(!weaponMaster) weaponMaster = GetComponent<WeaponMaster>();
}

public void Shoot ()
{  
    if(!isLocalPlayer) return;

    CmdShoot();
}

[Command]
private void CmdShoot ()
{
    RpcShoot();
}

// Personally in general I would leave any RPC
// as close to the method calling it
// as possible for better maintainability
[ClientRpc]
private void RpcShoot ()
{
    weaponMaster.Shoot();
}

and accordingly in WeaponMaster

public void Shoot()
{
    if (ammo == 0) return;

    if (isAutomatic)
    {
        keepFiring = true;
        StartCoroutine(Fire());
    }
    else if (!isAutomatic && noQuickFire)
        StartCoroutine(Fire());
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM