Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Clients Rigidbodies aren't moving on Server

Discussion in 'Netcode for GameObjects' started by Faysou, Jun 13, 2023.

  1. Faysou

    Faysou

    Joined:
    Feb 22, 2021
    Posts:
    12
    Hello everyone,
    I am making a ClientPrediction using this tutorial : Unity Netcode For Gameobject - Client Prediction - YouTube.
    Everything is working correctly, but my players aren't moving server side.
    What I can tell you is that my problem is specific to rigidbodies : replacing m_Rigidbody.velocity = ... by Transform.Translate(...) is working on both sides. So the server is correctly receiving infos, but it is blocked.

    Here is my class for moving :
    Code (CSharp):
    1. using Unity.Netcode;
    2. using UnityEngine;
    3.  
    4. public class PlayerMovementPredictive : NetworkBehaviour
    5. {
    6.     [SerializeField] private int defaultSpeed;
    7.  
    8.     [SerializeField] private Transform turret;
    9.  
    10.     [SerializeField] private Mesh debugMesh;
    11.  
    12.     private Rigidbody m_Rigidbody;
    13.     private PlayerInputs m_PlayerInputs;
    14.     private Camera m_MainCamera;
    15.  
    16.     private bool m_IsMousePresent;
    17.  
    18.     private Vector3 m_LookTarget;
    19.     private float m_Speed;
    20.  
    21.  
    22.  
    23.     private int m_Tick;
    24.     private const float TickRate = 1f / 60f;
    25.     private float m_TickDeltaTime;
    26.  
    27.     private const int BufferSize = 1024;
    28.  
    29.     private readonly InputState[] m_InputStates = new InputState[BufferSize];
    30.     private readonly TransformState[] m_TransformStates = new TransformState[BufferSize];
    31.  
    32.     private readonly NetworkVariable<TransformState> m_ServerTransformState = new();
    33.     private TransformState m_PreviousTransformState;
    34.  
    35.     public override void OnNetworkSpawn()
    36.     {
    37.         base.OnNetworkSpawn();
    38.         m_Rigidbody = GetComponent<Rigidbody>();
    39.         m_PlayerInputs = GetComponent<PlayerInputs>();
    40.         m_MainCamera = Camera.main;
    41.      
    42.         m_IsMousePresent = Input.mousePresent;
    43.         m_Speed = defaultSpeed;
    44.  
    45.         m_ServerTransformState.OnValueChanged += OnServerStateChanged;
    46.     }
    47.  
    48.     private void OnServerStateChanged(TransformState previousValue, TransformState newValue)
    49.     {
    50.         m_PreviousTransformState = previousValue;
    51.     }
    52.  
    53.     private void Update()
    54.     {
    55.         var moveInput = m_PlayerInputs.PlayerControls.Player.Move.ReadValue<Vector2>();
    56.         UpdateLookTarget();
    57.      
    58.         if (IsClient && IsLocalPlayer)
    59.         {
    60.             ProcessLocalPlayerMovement(moveInput, m_LookTarget);
    61.         }
    62.         else
    63.         {
    64.             ProcessSimulatedPlayerMovement();
    65.         }
    66.     }
    67.  
    68.     private void UpdateLookTarget()
    69.     {
    70.         if (m_IsMousePresent)
    71.         {
    72.             var ray = m_MainCamera.ScreenPointToRay(m_PlayerInputs.PlayerControls.Player.Look.ReadValue<Vector2>());
    73.          
    74.             if (Physics.Raycast(ray, out var hit, 100000, 1 <<  9))
    75.             {
    76.                 m_LookTarget = new Vector3(hit.point.x, 0, hit.point.z);
    77.             }
    78.         }
    79.         else
    80.         {
    81.             var tmpLook = m_PlayerInputs.PlayerControls.Player.Look.ReadValue<Vector2>();
    82.             if (tmpLook.x is not 0 || tmpLook.y is not 0)
    83.             {
    84.                 m_LookTarget = new Vector3(tmpLook.x, 0, tmpLook.y);
    85.             }
    86.         }
    87.     }
    88.  
    89.     private void ProcessLocalPlayerMovement(Vector2 moveInput, Vector3 lookTarget)
    90.     {
    91.         m_TickDeltaTime += Time.deltaTime;
    92.  
    93.         if (m_TickDeltaTime > TickRate)
    94.         {
    95.             var bufferIndex = m_Tick % BufferSize;
    96.  
    97.             if (!IsServer)
    98.             {
    99.                 MoveWithTickServerRpc(m_Tick, moveInput, lookTarget);
    100.                 Move(moveInput);
    101.                 Look(lookTarget);
    102.             }
    103.             else
    104.             {
    105.                 Move(moveInput);
    106.                 Look(lookTarget);
    107.              
    108.                 var state = new TransformState()
    109.                 {
    110.                     Tick = m_Tick,
    111.                     Position = transform.position,
    112.                     Rotation = transform.rotation,
    113.                     TurretRotation = turret.rotation,
    114.                     IsMoving = true
    115.                 };
    116.  
    117.                 m_ServerTransformState.Value = state;
    118.             }
    119.  
    120.             var inputState = new InputState()
    121.             {
    122.                 Tick = m_Tick,
    123.                 MoveInput = moveInput,
    124.                 LookTarget = lookTarget,
    125.             };
    126.          
    127.             var transformState = new TransformState()
    128.             {
    129.                 Tick = m_Tick,
    130.                 Position = transform.position,
    131.                 Rotation = transform.rotation,
    132.                 TurretRotation = turret.rotation,
    133.                 IsMoving = true
    134.             };
    135.          
    136.             m_InputStates[bufferIndex] = inputState;
    137.             m_TransformStates[bufferIndex] = transformState;
    138.          
    139.             m_TickDeltaTime -= TickRate;
    140.             if (m_Tick is BufferSize)
    141.             {
    142.                 m_Tick = 0;
    143.             }
    144.             else
    145.             {
    146.                 m_Tick += 1;
    147.             }
    148.         }
    149.     }
    150.  
    151.     [ServerRpc]
    152.     private void MoveWithTickServerRpc(int tick, Vector2 moveInput, Vector3 lookTarget)
    153.     {
    154.         Move(moveInput);
    155.         Look(lookTarget);
    156.  
    157.         var transformState = new TransformState()
    158.         {
    159.             Tick = tick,
    160.             Position = transform.position,
    161.             Rotation = transform.rotation,
    162.             TurretRotation = turret.rotation,
    163.             IsMoving = true
    164.         };
    165.  
    166.         m_ServerTransformState.Value = transformState;
    167.     }
    168.  
    169.     private void ProcessSimulatedPlayerMovement()
    170.     {
    171.         m_TickDeltaTime += Time.deltaTime;
    172.  
    173.         if (m_TickDeltaTime > TickRate)
    174.         {
    175.             if (m_ServerTransformState.Value is not null && m_ServerTransformState.Value.IsMoving)
    176.             {
    177.                 transform.position = m_ServerTransformState.Value.Position;
    178.                 transform.rotation = m_ServerTransformState.Value.Rotation;
    179.                 turret.rotation = m_ServerTransformState.Value.TurretRotation;
    180.             }
    181.          
    182.             m_TickDeltaTime -= TickRate;
    183.             if (m_Tick is BufferSize)
    184.             {
    185.                 m_Tick = 0;
    186.             }
    187.             else
    188.             {
    189.                 m_Tick += 1;
    190.             }
    191.         }
    192.     }
    193.  
    194.     private void Move(Vector2 moveInput)
    195.     {
    196.         moveInput = Vector2.ClampMagnitude(moveInput, 1);
    197.         var moveVector = new Vector3(moveInput.x, 0, moveInput.y);
    198.      
    199.         if (moveVector != Vector3.zero)
    200.         {
    201.             m_Rigidbody.velocity = moveVector * m_Speed;
    202.             transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(moveVector), 0.1f);
    203.         }
    204.         else
    205.         {
    206.             m_Rigidbody.velocity = Vector3.Slerp(m_Rigidbody.velocity, Vector3.zero, 0.1f);
    207.         }
    208.     }
    209.  
    210.     private void Look(Vector3 lookTarget)
    211.     {
    212.         if (lookTarget == Vector3.zero)
    213.             return;
    214.      
    215.         if (m_IsMousePresent)
    216.         {
    217.             lookTarget -= transform.position;
    218.         }
    219.      
    220.         lookTarget.y = 0;
    221.         turret.rotation = Quaternion.LookRotation(lookTarget);
    222.     }
    223.  
    224.     private void OnDrawGizmos()
    225.     {
    226.         if (m_ServerTransformState.Value is not null)
    227.         {
    228.             Gizmos.color = Color.magenta;
    229.             Gizmos.DrawMesh(debugMesh, m_ServerTransformState.Value.Position, m_ServerTransformState.Value.Rotation);
    230.         }
    231.     }
    232. }
    Also my player's components :
    upload_2023-6-13_4-41-0.png

    I am using Unity 2022.3.1f1 and NGO 1.4.0

    Thank you !
     
  2. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    426
  3. Faysou

    Faysou

    Joined:
    Feb 22, 2021
    Posts:
    12
    Ok now that my minds are more clear and it's not 4am I can say that disabling transform.position = m_ServerTransformState.Value.Position; (line 177) fixed the problem at the cost of... syncing.

    I believe I am doing something in the wrong order, I will try to find the issue but any help is appreciated ^^

    Also if you spot something that is not "good practice" I would love to hear about ;
     
  4. Faysou

    Faysou

    Joined:
    Feb 22, 2021
    Posts:
    12
    Hi Riku,
    I did try it, but with my setup I want to be the only master in syncing the transform so that is why I removed network transform and networking rigidbody, I still have them on my non-predictive player prefab.

    I found the issue atleast ! After some guessing I can say that ProcessSimulatedPlayerMovement() is interferring with the
    MoveWithTickServerRpc() and that is why my character happen to be "lock" on place on the server-side.

    Can you try to spot my mistake T_T ? It is in the "order" of the logic, I will try to find a fix aswell and keep you updated ;)

    Thank you for you time
     
  5. Faysou

    Faysou

    Joined:
    Feb 22, 2021
    Posts:
    12
    Ok I think I found out why, rigidbody.velocity is set over time compared to transform.translate, so I think my
    ProcessLocalPlayerMovement is stopping player velocity or something like that
     
  6. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    426
    Thanks for sharing! I see you're also writing to m_ServerTransformState.Value in both the RPC and the ProcessSimulatedPlayerMovement(), so you could have race conditions there
     
    Faysou likes this.
  7. Faysou

    Faysou

    Joined:
    Feb 22, 2021
    Posts:
    12
    OKAY,
    It's silly to do ProcessSimulatedPlayerMovement() in Update() if you're the server, it'll undo the move you made haha, it took me a while to figure out that was what you were saying Riku xD

    Thank you once again ^^
     
  8. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    426
    hehe, happy to see you found that helpful :D