Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
174 views
in Technique[技术] by (71.8m points)

c# - Unity Mirror Multiplayer RTS, client ignoring hasAuthority check

I'm working on an RTS game using mirror and ran into an issue. I'm working on auto-attack function for the units. Everything works for the host but not on clients. Any help would be very much appreciated, I've been at it for a few days already.. Help! Or at least point me in right direction here. I will optimize this a bit better later on I just need to understand why it's not working on client. I've also noticed that Client will add itself to enemies list, it seems to be ignoring "hasAuthority" check

It's a bit of a write up so I'll try to make it as understandable as possible.

Unit gets instantiated and this is the script attached to it:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;
using System.Linq;

public class UnitFiring : NetworkBehaviour
{

    [SerializeField] private Targeter targeter = null;
    [SerializeField] private GameObject projectilePrefab = null;
    [SerializeField] private Transform projectileSpawnPoint = null;
    [SerializeField] private float fireRange = 10f;
    [SerializeField] private float fireRate = 1f;
    [SerializeField] private float rotationSpeed = 20f;

    private float lastFireTime;


    //auto attack 
    [SerializeField] private Transform ownAimAtPoint = null;
    [SerializeField] private LayerMask layerMask;
    [SerializeField] private int updateFunctionFrequency = 60; //in frames
        

    [ServerCallback]
        private void Update()
        {
    
            
            if (Time.frameCount % this.updateFunctionFrequency != 0) return;
//runs update every 60 frames
            enemyColliders.RemoveAll(Collider => Collider == null);
    //if enemyCollider List has GameObject that was destroyed or null, it removes it from the list.
            
    
        Targetable target = targeter.GetTarget();
               

        if(target == null) 
        {
            ArrayDetect();
                        
            AttackUnit();
            return;  
        }
         

        if (!CanFireAtTarget()) { return; }

        //look at target
        Quaternion targetRotation =
            Quaternion.LookRotation(target.transform.position - transform.position);

        //Rotate
        transform.rotation = Quaternion.RotateTowards
            (transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);

        if(Time.time > (1 / fireRate) +lastFireTime)
        {
            Quaternion projectileRotation = Quaternion.LookRotation(
                target.GetAimAtPoint().position - projectileSpawnPoint.position);

            GameObject projectileInstance = Instantiate(
                projectilePrefab, projectileSpawnPoint.position, projectileRotation);

          
            NetworkServer.Spawn(projectileInstance, connectionToClient);
            
            
            lastFireTime = Time.time;

        }
    }
    [Client]
    private bool CanFireAtTarget()
    {
        return (targeter.GetTarget().transform.position - transform.position).sqrMagnitude 
            <= fireRange * fireRange;
    }

[SerializeField] private Collider[] colliderArray;
[SerializeField] private List<GameObject> enemyColliders;

Next is the ArrayDetect Function Detect unit with Physics.OverlapSphere, make sure it has the authority and add it to enemyCollider List, I also added layerMask to make sure it's only checking for Units.

[Server]
    private void ArrayDetect()
    {
       colliderArray = Physics.OverlapSphere(ownAimAtPoint.position, fireRange, layerMask);
       
              
       foreach (Collider collider in colliderArray)
        {
           
                Debug.Log("we hit a", collider);

                if (!collider.TryGetComponent<Targetable>(out Targetable potentialTarget))
                {

                    return;

                }


                if (potentialTarget.hasAuthority)
                {

                    return;  //if the hit target is the players, do nothing

                }

                else
                {
                    
                    enemyColliders = enemyColliders.Distinct().ToList();
                    enemyColliders.Add(collider.gameObject);
                    Debug.Log("Found an enemy", potentialTarget);
                }
            
        }
    }

Now AttackUnit Function, it will go thought enemyColliders List and set them as target to attack

[ServerCallback]
private void AttackUnit()
{   

    foreach (GameObject enemy in enemyColliders)
    {
    
        Debug.Log("We got confirmed enemy", enemy);
        //GetComponent<Targeter>().CmdSetTarget(enemy);
        targeter.CmdSetTarget(enemy);
            //attack the enemy

    }    
}

This is Targetable Script, it simply returns AimAtPoint:

public class Targetable : NetworkBehaviour
{
    [SerializeField] private Transform aimAtPoint = null;

    public Transform GetAimAtPoint()
    {
        return aimAtPoint;
    }
}

This is the CmdSetTarget Command in Targeter Script:

[Command]
   public void CmdSetTarget(GameObject targetGameObject)
    {
        if(!targetGameObject.TryGetComponent<Targetable>(out Targetable newTarget)) { return; }
        //if game object does not have a target, return

        target = newTarget;
    }

This is the error I get in the console, but only on the client Units, the host runs as it should:

Trying to send command for object without authority. Targeter.CmdSetTarget

Thanks for taking time to read this

question from:https://stackoverflow.com/questions/65947592/unity-mirror-multiplayer-rts-client-ignoring-hasauthority-check

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...