Very simple sync question with Udon# Opening a Door example

I am trying to do very simple scripting so that one object can act as a button to open or close a door.
The logic with Udon# is fairly simple, you just have to link an onInteract event and change the position of a target gameObject. I even did synced the position of the door, and when the master is clicking the button the door opens/close and after a small delay other people in the world can see the door actually opening / closing. Now the difficult question. It seems that only the master can click the button.
If a second player clicks the button the door is not moving at all.
The question is: which is the simples way of making the button move something in the world and everybody can touch the button and see the moving done?
Sorry if this has been already asked before (but I couldnt find a good very simple example explaining such basic interaction), it seems that network events can deal with this, but I am not sure, if that is the only solution. Or if this is there is a video or url explaining how to use this.

So I did the following script and it seems working. I made the target synced via the Inspector.
I wonder if the same might be accomplished by setting some [SyncUdon] wizardry in the transform target. Is this the correct way of doing things, i.e. having the door synced, or everything should be done via networkevents? But in that case how can the other clients know if the door is open or closed?

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;

public class VRC_button_A_matt1 : UdonSharpBehaviour
{
    public Transform target;

    Vector3 aperta = new Vector3(-0.207f, -1.63f, -0.56f);
    Vector3 chiusa = new Vector3(-0.207f, 1.197f, -0.56f);

    void Start()
    {
        Debug.Log("started VRC_button_A_matt1");
        target.localPosition = chiusa;
    }
    public override void Interact()
    {

        Debug.Log("Interacted");
            SendCustomNetworkEvent(NetworkEventTarget.All, "NetworkEventStuff");
        
        
    }
    public void NetworkEventStuff()
    {
        if (target.localPosition == aperta)
        {
            target.localPosition = chiusa;
        }
        else
        {
            target.localPosition = aperta;
        }
        Debug.Log("changing position to " + target.localPosition);
    }

}

Keeping as close to your code as possible. I would add a synced bool variable to the mix to track the state.

public Transform target;

Vector3 aperta = new Vector3(-0.207f, -1.63f, -0.56f);
Vector3 chiusa = new Vector3(-0.207f, 1.197f, -0.56f);

[UdonSynced] public bool IsOpen;

void Start() {
    Debug.Log("started VRC_button_A_matt1");
    target.localPosition = chiusa;
    IsOpen = false;
}
public override void Interact() {

    Debug.Log("Interacted");
    SendCustomNetworkEvent(NetworkEventTarget.All, "NetworkEventStuff");


}
public void NetworkEventStuff() {
    if (IsOpen) {
        target.localPosition = chiusa;
        IsOpen = false;
    } else {
        target.localPosition = aperta;
        IsOpen = true;
    }
    Debug.Log("changing position to " + target.localPosition);
}

I’m not able to test it at the moment, let me know if it doesn’t work.

Thanks @unigold I tested it… It “almost” works.
But there is a serious bug in this, consider this example (I tested it):
a) first user enters and finds the door closed, so they push the button and the door opens.
b) second user enters and since in the start method there is written that the status is the door being closed, they see it closed (while the first can see still it opened)


This is obviously unwanted. After that each push keeps the door synced, but at the beginning each new player find it closed even if it had been opened by others.
I am not able to find myself a simple way to have it open or closed, except the only thing is to have the door with an empty udon behaviour but setting it as synchronized and setting in the start method the isOpen flag to the actual value read from the door coordinates. Do you think this is the correct way for dealing with this? The only doubt I have is that I have read that synced variables are slow and they can arrive after 0.2 seconds, while network messages can be quicker, so it can happen that the message arrive but the usynced flag IsOpen will arrive later?

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;

public class VRC_button_A_matt1 : UdonSharpBehaviour
{
    public Transform Target;
    [UdonSynced] bool IsOpen;

    Vector3 OpenPosition = new Vector3(-0.207f, -1.63f, -0.56f);
    Vector3 ClosePosition = new Vector3(-0.207f, 1.197f, -0.56f);

    void Start()
    {
        Debug.Log("started VRC_button_A_matt1");
        //DELETED target.localPosition = closePosition;
        //GET ACTUAL POSITION OF THE DOOR WHICH IS NOW SYNCED
        IsOpen = Target.localPosition == OpenPosition; 
    }
    public override void Interact()
    {

        Debug.Log("Interacted");
        SendCustomNetworkEvent(NetworkEventTarget.All, "NetworkEventStuff");
        
        
    }
    public void NetworkEventStuff()
    {
        if (IsOpen)
        {
            Target.localPosition = ClosePosition;
            IsOpen = false;
        }
        else
        {
            Target.localPosition = OpenPosition;
            IsOpen = true;
        }
        
        Debug.Log("changing position to " + Target.localPosition);
    }

}

just add update(){} to your code and use that to check the bool, add a local bool as well, if the local bool doesn’t match the synced one, it means you’re out of sync and should update the state on your end.

(update() is a built in unity thing that runs every frame)

Thank you for bringing up my mistake, you’re right that is problematic.

I hope this still serves your purpose, please let me know if it doesn’t, but I’ve written some different code in order to simplify the process.

You could try having 2 different doors, one in the open position, and one in the closed position, then toggle between them.

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;

public class DoorControl : UdonSharpBehaviour {
public GameObject OpenDoor;
public GameObject ClosedDoor;
[UdonSynced] public bool CurrentOpenState;

public override void Interact() {
   SendCustomNetworkEvent(NetworkEventTarget.All, "NetworkEventStuff");
}
public void Start() {
    if (Networking.LocalPlayer.isMaster) {
        CurrentOpenState = false; //if the player is the master (if the player is the first player in the instance) the door will be set to this value
    }
    OpenDoor.SetActive(CurrentOpenState);
    ClosedDoor.SetActive(!CurrentOpenState);
    //should set the current state for players who joined after it was last changed
}
public void NetworkEventStuff() {
    OpenDoor.SetActive(CurrentOpenState); //sets to CurrentOpenState's last set value
    ClosedDoor.SetActive(!CurrentOpenState); //sets it to the opposite of CurrentOpenState's last set value
    CurrentOpenState = !CurrentOpenState; //toggles it to the opposeite state so when the function runs again it sets each door to it's opposite state
}

}

Again, untested in game, please let me know if you find an issue.

edit: not sure why this posts formatting will not work. lol