Authority transfer not consistent

I’m on Coherence 1.1.4, using rooms, this is on Unity 2023.2 at the moment. This behavior seems to be the same between Editor and WebGL.

I have fairly empty scene with a ball that is a sphere collider and rigid body, I have 2 player type characters. I have it setup so that when a trigger happens a force is applied to the ball.

I have things setup close to the physics example, when user A first logs into the room they have authority and the ball behaves and reacts as expected. When User B enters the room and tries to kick the ball it behaves erratically. I see authority bounce between the two and then stay with User A. I’m…not sure what I’m missing here.

Relevant Code:

This is the monobehavior on the ball:

private CoherenceSync _sync;
        private Rigidbody _rigidbody;
        private Collider _collider;

        [Sync] public bool isBeingKicked = false;

        private void Awake()
        {
            _collider = GetComponent<Collider>();
            _rigidbody = GetComponent<Rigidbody>();
            _sync = GetComponent<CoherenceSync>();
        }

        private void OnEnable()
        {
            _sync.OnAuthorityRequested += OnAuthorityRequested;
        }

        private void OnDisable()
        {
            _sync.OnAuthorityRequested -= OnAuthorityRequested;
        }
        
        private bool OnAuthorityRequested(ClientID requesterid, AuthorityType authoritytype, CoherenceSync sync)
        {
            return !isBeingKicked;
        }

        public void RequestAuthority(UnityAction callback)
        {
            if (_sync.HasStateAuthority)
            {
                callback();
            }
            else
            {
                isBeingKicked = true;
                _sync.OnStateAuthority.AddListener(callback);
                _sync.RequestAuthority(AuthorityType.Full);
            }
        }

        public void RemoveListeners(UnityAction callback)
        {
            isBeingKicked = false;
            _sync.OnStateAuthority.RemoveListener(callback);
        }

And then this is on the player:

private void OnTriggerEnter(Collider other)
        {
            if (other.CompareTag("Ball"))
            {
                if (other.TryGetComponent(out _ball))
                {
                    _collidedRigidBody = other.GetComponent<Rigidbody>();
                    _ball.RequestAuthority(OnStateAuthority);
                }
            }
        }
        
        private void OnStateAuthority()
        {
            KickCollider();
            _ball.RemoveListeners(OnStateAuthority);
            _ball = null; 
            _collidedRigidBody = null;
        }
        
        private void KickCollider()
        {
            if (_collidedRigidBody != null)
            {
                var direction = (transform.position - _collidedRigidBody.transform.position).normalized;
                    
                _collidedRigidBody.AddForce(direction * multiplier, ForceMode.Impulse);
            }
        }

And this is the coherence sync settings I have on the ball prefab:

Any help to make this smooth would be appreciated.

Hello Michael!

Looking at your code, I might have an idea whats happening, I’ll try to explain:

  1. The OnTriggerEnter from the player doesn’t check if you have authority over the player. I feel like its important that this trigger only runs for authority players, that might be why authority keeps bouncing between them. Keep a reference to the CoherenceSync from your player and add a _coherenceSync.HasStateAuthority to the check right next to the “Ball” tag comparison.

  2. Another thing I see which might have undefined behaviour, is in the first script, in the RequestAuthority method, you are setting isBeingKicked to true when you DON’T have authority over the ball, this is not allowed and coherence will most likely override that value. Remember that even if you’re requesting authority, this is not instant, it takes time for this request to travel to the RS and be processed. isBeingKicked should only be set to true in the KickCollider method.

Hope this helps and thank you for trying coherence out

By the way, remember that when you don’t have authority over the ball, is important that the rigidbody is kinematic, so Unity physics don’t mess with coherence updates.

You can let coherence handle that automatically by going to the Configure window => Components tab and checking the RigidBody configuration there.

Setting kinematic seems to have cleaned up things quite a bit, thank you for the reply. The collision script on the player should only be on for the local player. I set that component to be disabled for any avatars instantiated by coherence. Unless you think I should have that check either way?

Generally setting a component to be disabled protects you from undesired effects, but not with collision events. They will trigger anyway even if the component is disabled, so that is probably part of the picture of why you see so much glitching.

So yeah, either check for authority on the Sync, or check for the component’s enabled:

private void OnTriggerEnter(Collider other)
{
    if (enabled && other.CompareTag("Ball"))
    {
        // Do things
    }
}

PS: I also had to go and double-check whether the physics events were fired with a disabled component :laughing: Apparently the Unity docs used to mention it specifically, but the new page doesn’t! Come on, Unity!