Parenting basics, sync set parenting

Hi guys, i’m new on coherence and i like the possibilities to create an online game all alone, but i’m stuck with basic things that even the tutorials let me struggle with…

I have 2 examples of bad behavior i did not manage to resolve, here is the first one :




image

This is the code from the first tutorialproject, only that i added a possibility to parent it to a plot, if this one is close enough. but when a remote client pick it back, its still parented to the plot

1 Like

The second one is still in the parenting topic, but on another project :


this is an input manager on every client, there is one and only one cloringBlock in the world, it has a coherenceSync script has well and i’m trying to get authority and parent it to my player on input :




image

image
its working, but why i sometimes have to press twice to parent it correctly on bot client and server, and only on the first connection
the code should take authority and parent in one input, but sometimes, it just takes authority and dont trigger the parenting (do input2 )

Hi @tinytauren, and welcome to the forums! (fun nickname btw, is it WoW related?)

In general, I think the root cause of your issues is how you deal with authority. Authority is a central concept in networking, not just in coherence but in all frameworks. Objects always exist in multiple copies on each Client or server, and it’s crucial that only whoever has authority on it performs actions over it!

For instance, in your first post:

I can clearly see from this image that the Crate is not authoritative on this client, due to the empty coherence icon and obviously the name of the object starting with [network].

And in the code, you don’t do any authority check (CoherenceSync.hasStateAuthority()) before parenting it.

Is it possible that it’s what’s happening here?
Feel free to include more code in your posts, so we can have more context.

As a side comment, I would recommend watching this video about authority:
https://www.youtube.com/watch?v=Ql2w10nJl80

Another resource specifically on parenting is this: Parenting network entities | SDK 1.2 | Unity Multiplayer SDK Documentation | coherence

On the second question, it’s hard to debug without seeing the whole code. Can you paste the entire classes? (using the code tag)

I can also see your network entity has Authority Transfer set to “Request”, but then you commented some key methods like StateAuthorityRequested and maybe more. You can maybe try setting it to “Steal” to start with, to run your tests. The various modes are explained here.

Hey thanks for the reply ! my nickame coming directly from WoW like you said !
i cleaned up the code to be as readable as possible : this in the color input, in the player prefab :
image

using Coherence.Toolkit;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerColorBlockInput : MonoBehaviour
{
    [SerializeField] CoherenceSync m_Sync;
    [SerializeField] InputActionReference m_ColorInputRef; 


    private void OnEnable()
    {
        m_ColorInputRef.asset.Enable();
        m_ColorInputRef.action.performed += ParentingTheBlock; 
    }
    private void OnDisable()
    {
        m_ColorInputRef.action.performed -= ParentingTheBlock;

    }
    private void ParentingTheBlock(InputAction.CallbackContext context)
    {
        FindObjectOfType<ColoringBlock>().OnParentingValidate += ValidatingParenting; 
        FindObjectOfType<ColoringBlock>().TryingToParentTheBlock();
    }

    private void ValidatingParenting(bool obj)
    {
        FindObjectOfType<ColoringBlock>().OnParentingValidate -= ValidatingParenting; 
        FindObjectOfType<ColoringBlock>().ParentingAction(transform.parent);
    }

    
}

that’s it for the input , here is the block :

using Coherence;
using Coherence.Connection;
using Coherence.Toolkit;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;

using UnityEngine;
using UnityEngine.InputSystem;


public class ColoringBlock : MonoBehaviour
{
    CoherenceSync m_Sync;
    CoherenceBridge m_Bridge;
    [SerializeField]  public float m_Value = 12f;

    [SerializeField] public Material[] m_Materials;
   

    [SerializeField]public  TextMeshProUGUI m_Text;

    [SerializeField] InputActionReference m_InputAction;


    /// about parenting 

    public event Action<bool> OnParentingValidate;

    bool m_IsAuthRequested = false;
    public Transform m_PlayerInputTransform; 

    private void Awake()
    {

        m_Sync = GetComponent<CoherenceSync>();
        m_Bridge = FindObjectOfType<CoherenceBridge>();
    }

   /// <summary>
   /// this is my personal guide to understand how it works
   /// </summary>
    private void OnEnable()
    {
        m_Bridge.onConnected.AddListener(Connection);
        m_Bridge.onLiveQuerySynced.AddListener(OnSync);
        m_InputAction.asset.Enable();
        m_InputAction.action.performed += MyAction;


        //parenting 

        m_Sync.OnAuthorityRequested += DoAuthorityRequest;
        m_Sync.OnStateAuthority.AddListener(StatingAuthority); 
        
        
    }

    

    private void OnDisable()
    {
        m_Bridge.onConnected.RemoveListener(Connection);
        m_Bridge.onLiveQuerySynced.RemoveListener(OnSync);
        m_InputAction.action.performed -= MyAction;

        // parenting 

        m_Sync.OnAuthorityRequested -= DoAuthorityRequest;
        m_Sync.OnStateAuthority.RemoveListener(StatingAuthority);

    }

    #region UpdatingValuesWithCommands

    private void MyAction(InputAction.CallbackContext context)
    {
        
        m_Value = UnityEngine.Random.Range(0, 100);

        if (m_Sync.HasStateAuthority)
        {
            UpdateRequest(m_Value);
        }
        else
        {

            m_Sync.SendCommand<ColoringBlock>(nameof(UpdateRequest), MessageTarget.AuthorityOnly, m_Value) ;

        }


    }
    public void UpdateRequest(float value)
    {
        print("Update Request");
        UpdatingBlock(value);
        m_Sync.SendCommand<ColoringBlock>(nameof(UpdatingBlock), MessageTarget.Other, value);
    }
    public void SyncRequest()
    {
        
        m_Sync.SendCommand<ColoringBlock>(nameof(UpdatingBlock), MessageTarget.Other, m_Value);
    }

    /// <summary>
    /// this function must be called locally with the right value on every clients
    /// </summary>
    /// <param name="newValue"></param>
    public void UpdatingBlock(float newValue)
    {
        m_Value = newValue; 
        m_Text.text = newValue.ToString();
        
    }

    private void OnSync(CoherenceBridge arg0)
    {
        //ask for the authority of the block to update everyone with its parameters (if serverside, should ask the simulator)
        m_Sync.SendCommand<ColoringBlock>(nameof(SyncRequest), MessageTarget.AuthorityOnly);

    }

   
    /// <summary>
    /// put a random value locally on the box, the color is supposed to be desync, the number is supposed to be sync
    /// </summary>
    private void Connection(CoherenceBridge con)
    {
        m_Value = UnityEngine.Random.Range(0, 100);
        m_Text.text = m_Value.ToString();
        int randomValue = UnityEngine.Random.Range(0, m_Materials.Length-1);
        GetComponent<Renderer>().material = m_Materials[randomValue]; 
    }

    #endregion
    /// Concerning the forum question 
    /// 

    internal void TryingToParentTheBlock()
    {
        if (m_Sync.HasStateAuthority)
        {
            ParentingTheBlock();
        }
        else
        {
            m_IsAuthRequested = true;
            m_Sync.RequestAuthority(AuthorityType.Full); 

        }

    }

    void ParentingTheBlock()
    {
        OnParentingValidate?.Invoke(true); 
    }

    internal void ParentingAction(Transform parentTransform)
    {
        transform.SetParent(parentTransform, false);
        transform.localPosition = Vector3.zero; 
    }

    private bool DoAuthorityRequest(ClientID requesterID, AuthorityType authorityType, CoherenceSync sync)
    {
        //no checks here, just validating 
        return true; 
    }
    private void StatingAuthority()
    {
        if (m_IsAuthRequested)
        {
            m_IsAuthRequested = false;
            ParentingTheBlock(); 
        }
    }

}

please ignore the UpdateValue region

image

as i try in game, i directly take control of the authority but the cube stay parented to the remote player, if i press again, the cube is rightfully parented to my player

thanks a lot !

is the coherence node needed ? i tried with it, still desync but differently(worse)

the test is done on local replication server, is there something with delays too fast ?

yes, i’m still on it

Hey @tinytauren,

your code looks correct, and it definitely seems like something is not right on our end. We are currently looking into it, thank you for reporting this.

And to answer your question: CoherenceNode is not needed in your case because you are parenting the cube directly under a CoherenceSync. If you parented it in more deep layers under a GameObject who doesn’t have a CoherenceSync component (but one of it’s ancestors has), then you need CoherenceNode for that to work.

2 Likes