Sync doors across server in Unity multiplayer game using Mirror

I’m trying to synchronize doors across the server for a multiplayer game using Unity and Mirror. The doors currently do synchronize across the server, however I do have a couple problems:

**If player 1 points at door 1 and player 2 at door 2, and one of the players presses OpenDoorKey, both doors will open.

If player 1 and player 2 point at door 1, and one of the players presses OpenDoorKey, the door will open and immediately close again.
**
Since I’m using raycasts in my door script, it should have to do with that. I have no idea how to fix this. Here’s the code:

  private void Update()
    {
        if (isClient)
        {
            if (SceneManager.GetActiveScene().name == "Game")
            {
                crosshair = CrossHair.instance.crosshairImage;
            }

            RaycastHit hit;
            Vector3 fwd = playerCamera.TransformDirection(Vector3.forward);

            int mask = 1 << LayerMask.NameToLayer(excludeLayerName) | doorLayer.value;

            if (Physics.Raycast(playerCamera.position, fwd, out hit, rayLength, mask))
            {
                if (hit.collider.CompareTag(doorTag))
                {
                    if (!doOnce)
                    {
                        CrosshairChange(true);
                    }

                    isCrosshairActive = true;
                    doOnce = true;

                    if (Input.GetKeyDown(openDoorKey))
                    {
                        doorIdentity = hit.collider.GetComponent<NetworkIdentity>();
                        CmdDoorController(doorIdentity);
                    }
                }
            }
            else
            {
                if (isCrosshairActive)
                {
                    CrosshairChange(false);
                    doOnce = false;
                }
            }
        }
    }

    [Command(requiresAuthority = false)]
    private void CmdDoorController(NetworkIdentity doorIdentity)
    {
        var doorController = doorIdentity.GetComponent<DoorController>();
        if (doorController != null)
        {
            doorController.PlayAnimation();
        }
    }

Just like you can see in the code, I assign the doorIdentity variable locally only if openDoorKey is pressed, thinking this would make it work, which it didn’t.

If you need anything else, please do ask. Thanks in advance.

I would avoid using the RayCast in that fashion and just use a trigger on the door so when the player gets close to the door it becomes aware of the player =or= the player becomes aware of the door.
You can accomplish this like (rough/general concept):

  • The player enters the trigger on the door and an OnTriggerEnter method defined within a NetworkBehaviour (DoorNetworkBehaviour) component on the door is invoked.
    • You can use a “Player” tag to filter out other things entering the trigger (create a TagHandle in the DoorNetworkBehaviour’s Awake method and check against that within the OnTriggerEnter method…if the object causing the trigger event isn’t a player then just exit early).
  • Upon a player triggering the DoorNetworkBehaviour.OnTriggerEnter method, add additional script to get a PlayerNetworkBehaviour component, attached to the player, and invoke an Rpc (i.e. PlayerNearDoorRpc)
  • The PlayerNearDoorRpc should have a NetworkBehaviourReference parameter so when the DoorNetworkBehaviour invokes the PlayerNearDoorRpc it passes a reference of itself.
  • Upon the PlayerNetworkBehaviour processing the PlayerNearDoorRpc it would set a private/local DoorNetworkBehaviour property that is checked when the player tries to “open a door”.
    • Once the PlayerNetworkBehaviour’s local DoorNetworkBehaviour is valid (i.e. not null), then if you want to make sure the player is actually “looking at/focused on” the handle before being able to try to open it (as well as have some form of visual queue appear) then you could do a Raycast and/or a less processor intensive approach would be to just check the transform’s forward vector relative to a vector from the handle to the player (i.e. dot product).
  • If the player presses a key to open the door, then you can check to see what door the player is close to (if any), checks to see if the door is locked or unlocked, and if the door is locked check to see if the player has the key to the door…and if so then unlock/open the door.
    • The DoorNetworkBehaviour should also have an OpenDoorRpc that will set the status of the door (i.e. opened, closed, locked, unlocked).
    • The OpenDoorRpc would get invoked by the PlayerNetworkBehaviour.
    • Upon processing the OpenDoorRpc, the DoorNetworkBehaviour would set a local NetworkVariable that holds the state of the door so the locked/unlocked or opened/closed status of the door is updated.
    • All instances of the Door should update their state when the NetworkVariable of the DoorNetworkBehaviour changes. Upon the state being updated, any visuals can be applied on each instance.
    • If the player exits the trigger (i.e. OnTriggerExit), then you could use a similar pattern where the DoorNetworkBehaviour tells the PlayerNetworkBehaviour that the player is no longer near it.

This avoids the expensive continual Raycast and is more event driven based on a player’s proximity of the door and should help avoid running into issues where you might end up getting multiple hits when raycasting.

Let me know if this helps?