using UnityEngine; using Mirror; public class CharacterMovement : NetworkBehaviour { Animator animator; int isWalkingHash; int isRunningHash; PlayerInput input; Vector2 currentMovement; bool movementPressed; bool runPressed; // track last sent state to avoid network spam bool lastSentWalking; bool lastSentRunning; void Awake() { input = new PlayerInput(); input.CharacterControls.Movement.performed += ctx => { currentMovement = ctx.ReadValue(); movementPressed = currentMovement.x != 0 || currentMovement.y != 0; }; input.CharacterControls.Run.performed += ctx => runPressed = ctx.ReadValueAsButton(); } void Start() { animator = GetComponent(); isWalkingHash = Animator.StringToHash("isWalking"); isRunningHash = Animator.StringToHash("isRunning"); } // Only the local player should drive input/movement void Update() { if (!isLocalPlayer) return; HandleMovement(); HandleRotation(); } void HandleRotation() { Vector3 currentPosition = transform.position; Vector3 newPosition = new Vector3(currentMovement.x, 0, currentMovement.y); Vector3 positionToLookAt = currentPosition + newPosition; transform.LookAt(positionToLookAt); } void HandleMovement() { bool isRunning = animator.GetBool(isRunningHash); bool isWalking = animator.GetBool(isWalkingHash); if (movementPressed && !isWalking) { animator.SetBool(isWalkingHash, true); isWalking = true; } if (!movementPressed && isWalking) { animator.SetBool(isWalkingHash, false); isWalking = false; } if ((movementPressed && runPressed) && !isRunning) { animator.SetBool(isRunningHash, true); isRunning = true; } if ((!movementPressed || !runPressed) && isRunning) { animator.SetBool(isRunningHash, false); isRunning = false; } // send animator state to server only when changed if (isWalking != lastSentWalking || isRunning != lastSentRunning) { lastSentWalking = isWalking; lastSentRunning = isRunning; CmdSendAnimationState(isWalking, isRunning); } // movement translation (local) // keep your movement application here (velocity, CharacterController, Rigidbody.ApplyForce, etc.) // Example simple translation (adjust speed as needed): float speed = isRunning ? 6f : 3f; Vector3 move = new Vector3(currentMovement.x, 0, currentMovement.y) * speed * Time.deltaTime; transform.position += move; } public override void OnStartLocalPlayer() { Debug.Log("Local player started: " + netId); input.CharacterControls.Enable(); } public override void OnStopLocalPlayer() { input.CharacterControls.Disable(); } // Called on the server when client issues the command [Command] void CmdSendAnimationState(bool walking, bool running) { // update server-side animator if present if (animator == null) animator = GetComponent(); if (animator != null) { animator.SetBool(isWalkingHash, walking); animator.SetBool(isRunningHash, running); } // broadcast to all clients RpcUpdateAnimationState(walking, running); } // Executed on all clients to apply animator changes [ClientRpc] void RpcUpdateAnimationState(bool walking, bool running) { if (animator == null) animator = GetComponent(); if (animator == null) return; animator.SetBool(isWalkingHash, walking); animator.SetBool(isRunningHash, running); } }