Client is not allowed to write to this Network Variable!


image

image

I want the character to fall to the ground using the H key, stand up using the J key, and allow another player to help them up. The Host can fall using the H key, and the Client can help them up without any issues. However, the Client cannot fall using the H key, and even if they do fall, the Host cannot help them up, and this error occurs.

Please post code and logs as text in code tags. Images can’t be quoted, edited, searched, and are hard to read.

You also need to specify where in your code the error occurs.

As to the message, it’s what it says: a client tries to change a NetworkVariable’s value who isn’t the owner of the object. Do an IsOwner check to avoid this.

Yes, @CodeSmile is right.
By the way, this error can occur if there are 2 players in the game and you didn’t implement the “isOwner” condition where the player presses the “H” key.

I want a client to change another client’s NetworkVariable.
SetFallDownServerRpc is triggered from another client.
code:

using System.Collections;
using System.Collections.Generic;
using Unity.Netcode;
using Unity.Netcode.Components;
using UnityEngine;
using Cinemachine;
using static UnityEngine.Rendering.DebugUI;
using System;

public class PlayerMovement : NetworkBehaviour
{
    [SerializeField] private Transform CameraRoot;
    [SerializeField] private Transform Camera;
    private float horizontal;
    private float vertical;
    private Rigidbody rb;
    [SerializeField] private float speed =2;
    [SerializeField] private GameObject head;
    private float headUpDown = 0;
    private float headRightLeft = 0;
    [SerializeField] private bool fallDown = false;
    [SerializeField] private MeshRenderer meshRenderer;
    [SerializeField] private Material green;
    [SerializeField] private Material red;
    [SerializeField] private float AirResistance = 0.8f;
    private Animator _animator;
    private bool anim;
    [SerializeField] private float AnimBlendSpeed = 8.9f;
    private int xVelHash;
    private int yVelHash;
    private int zVelHash;
    private int crouchHash;
    private Vector2 currentVelocity;
    private float xRotation;
    private int JumpHash;
    private int FallingHash;
    private int GroundHash;
    [SerializeField] private float Dis2Ground = 0.8f;
    [SerializeField] private LayerMask GroundCheck;
    private bool _Grounded;
    private bool CrouchJump = true;
    [SerializeField] private CinemachineVirtualCamera virtualCamera;
    [SerializeField] private int ownerPriority = 15;
    private bool SlowSpeed = false;
    public bool isMovement = true;
    private NetworkVariable<bool> falldown = new NetworkVariable<bool>(false, NetworkVariableReadPermission.Everyone, NetworkVariableWritePermission.Owner);
    [SerializeField] private CapsuleCollider playerCollider;
    public override void OnNetworkSpawn()
    {
        falldown.OnValueChanged += FallDown;
        if (IsOwner)
        {
            virtualCamera.Priority = ownerPriority;
        }  
    }
   
    private void Start()
    {
        if (!IsOwner) return; 
        //Cursor.lockState = CursorLockMode.Locked;
        //Cursor.visible = false;
        rb = GetComponent<Rigidbody>();
        anim = TryGetComponent<Animator>(out _animator);

        xVelHash = Animator.StringToHash("X_Velocity");
        yVelHash = Animator.StringToHash("Y_Velocity");
        zVelHash = Animator.StringToHash("Z_Velocity");
        JumpHash = Animator.StringToHash("Jump");
        GroundHash = Animator.StringToHash("Grounded");
        FallingHash = Animator.StringToHash("Falling");
        crouchHash = Animator.StringToHash("Crouch");
    }
    private void FixedUpdate()
    {
        if (!IsOwner) return;
        SampleGround();        
        Movement();
        if (isMovement == false) return;
        HandleCrouch();               
    }

    private void Update()
    {
        if (!IsOwner) return;
        if (isMovement == false) return;
             
            if (Input.GetKeyDown(KeyCode.H))
            {
                setFallDownServerRpc(true);
            }
            if (Input.GetKeyDown(KeyCode.J))
            {
                setFallDownServerRpc(false);
            }
   
        HandleJump();
    }
    private void LateUpdate()
    {
        if (!IsOwner) return;        
        Rotation();
    }

    private void Movement()
    {
        if (!anim) return;
        if (isMovement == true)
        {
            if (SlowSpeed)
            {
                if (!falldown.Value)
                {
                    if (Input.GetKey(KeyCode.C))
                    {
                        speed = 0.65f;
                        CrouchJump = false;
                    }
                    else
                    {
                        CrouchJump = true;
                        if (Input.GetKey(KeyCode.LeftShift))
                        {
                            speed = 3f;
                        }
                        else
                        {
                            speed = 1;
                        }
                    }
                }
                else
                {
                    speed = 0.60f;
                }
                
            }
            else
            {
                if (!falldown.Value)
                {
                    if (Input.GetKey(KeyCode.C))
                    {
                        speed = 1.25f;
                        CrouchJump = false;
                    }
                    else
                    {
                        CrouchJump = true;
                        if (Input.GetKey(KeyCode.LeftShift))
                        {
                            speed = 6f;
                        }
                        else
                        {

                            speed = 2f;

                        }
                    }
                }
                else
                {
                    speed = 1f;
                }
                
            }
        }
        
        

        

        if (_Grounded) 
        {
            if (isMovement == true)
            {
                currentVelocity.x = Mathf.Lerp(currentVelocity.x, Input.GetAxis("Horizontal") * speed, AnimBlendSpeed * Time.fixedDeltaTime);
                currentVelocity.y = Mathf.Lerp(currentVelocity.y, Input.GetAxis("Vertical") * speed, AnimBlendSpeed * Time.fixedDeltaTime);
            }
            else
            {
                currentVelocity.x = Mathf.Lerp(currentVelocity.x, 0, AnimBlendSpeed * Time.fixedDeltaTime);
                currentVelocity.y = Mathf.Lerp(currentVelocity.y, 0, AnimBlendSpeed * Time.fixedDeltaTime);
            }
                

            var xVelDiffrence = currentVelocity.x - rb.velocity.x;
            var yVelDiffrence = currentVelocity.y - rb.velocity.z;

            rb.AddForce(transform.TransformVector(new Vector3(xVelDiffrence, 0, yVelDiffrence)), ForceMode.VelocityChange);

            _animator.SetFloat(xVelHash, currentVelocity.x);
            _animator.SetFloat(yVelHash, currentVelocity.y);
        }
        else
        {
            rb.AddForce(transform.TransformVector(new Vector3(currentVelocity.x * AirResistance, 0, currentVelocity.y * AirResistance)), ForceMode.VelocityChange);
        }
        
        

        
    }
    
    private void Rotation()
    {
        if (!anim) return;
        if (isMovement == true)
        {
            var Mouse_X = Input.GetAxis("Mouse X");
            var Mouse_Y = Input.GetAxis("Mouse Y");
            xRotation -= Mouse_Y * 160f * Time.smoothDeltaTime;
            xRotation = Mathf.Clamp(xRotation, -70, 40);
            Camera.localRotation = Quaternion.Euler(xRotation, 0, 0);
            rb.MoveRotation(rb.rotation * Quaternion.Euler(0, Mouse_X * 160f * Time.smoothDeltaTime, 0));
        }               
        Camera.position = CameraRoot.position;   
    }

    private void HandleCrouch() => _animator.SetBool(crouchHash, (bool)Input.GetKey(KeyCode.C));

    private void HandleJump()
    {
        if(!anim) return;
        if (!CrouchJump) return;
        if (!Input.GetKeyDown(KeyCode.Space)) return;
        
         _animator.SetTrigger(JumpHash);
        rb.AddForce(rb.velocity.y * Vector3.up, ForceMode.VelocityChange);
        rb.AddForce(200 * Vector3.up, ForceMode.Impulse);
        _animator.ResetTrigger(JumpHash);


    }

    public void JumpAddForce()
    {
        rb.AddForce(rb.velocity.y*Vector3.up ,ForceMode.VelocityChange);
        rb.AddForce(200 * Vector3.up, ForceMode.Impulse);
        _animator.ResetTrigger(JumpHash);
    }

    private void SampleGround()
    {
        if(!anim) return;
        RaycastHit hitInfo;
        if (Physics.Raycast(rb.worldCenterOfMass, Vector3.down, out hitInfo, Dis2Ground + 0.1f))
        {
            _Grounded = true;
            SetAnimatorGrounding();
            return;
        }
        _Grounded = false;
        _animator.SetFloat(zVelHash,rb.velocity.y);
        SetAnimatorGrounding();
        return;
    }

    private void SetAnimatorGrounding()
    {
        _animator.SetBool(FallingHash,!_Grounded);
        _animator.SetBool(GroundHash,_Grounded);

    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.transform.tag == "slow")
        {
            SlowSpeed = true;
        }
        else
        {
            SlowSpeed = false;
        }
    }

    public bool CheckFallDown()
    {
        return falldown.Value;
    }


    [ServerRpc(RequireOwnership = false)]
    public void setFallDownServerRpc(bool value)
    {                      
            falldown.Value = value;     
    }

    private void FallDown(bool previousValue, bool newValue)
    {

        if (newValue)
        {
            playerCollider.center = new Vector3(0, 0.3f, 0.3f);
            playerCollider.radius = 0.4f;
            playerCollider.height = 1.70f;
            playerCollider.direction = 2;
        }
        else
        {
            playerCollider.center = new Vector3(0, 0.89f, 0);
            playerCollider.radius = 0.28f;
            playerCollider.height = 1.79f;
            playerCollider.direction = 1;            
        }       
        _animator.SetBool("FallDown", newValue);
    }
    

    

}

Regarding of the documentation, if you set write permission to “owner”, that means host or server don’t have permission.

When you call “setFallDownServerRpc” method, the server/host try to set the value than you got an that message.

Use clientRPC instead of serverRPC than the owner can change the variable based on received data.

Edit: Also this approach won’t work because every “RPC” works on own NetworkBehavior object.
Thant means Player2 can’t trigger Player1’s RPC because “Update()” has “!IsOwner” condition.

Regarding of the informations, I think, you should change the approach.

Change your RPCs to be this if you want to send an RPC to an owner of the object:

[Rpc(SendTo.Owner)]
void SetFallDownRpc(bool value)
{
    falldown.Value = value;
}

This will use the server/host as the proxy to route the message to the right client (unless the owner is a host then it just goes to the host). You can keep the owner write permissions for your NetworkVariable.

1 Like