Search Unity

Resolved Clien't object does not fall with gravity (Using NetworkTransform + NetworkRigidbody)

Discussion in 'Netcode for GameObjects' started by babaliaris, Jan 27, 2024.

  1. babaliaris

    babaliaris

    Joined:
    Apr 21, 2013
    Posts:
    40
    Let's say a player Network Object with id: 2 spawns in the Server and thus on the client's Computer.
    This object has the following components:
    1) NetworkTransform
    2) NetworkRigidbody
    3) MovementScript
    4) Rigidbody (Kinematic On The Client's Computer)
    5) Capsule Collider
    6) Player Input

    The object falls from gravity as expected in the Server, but on the client, it gets stuck in the air.

    What I expected to happen:
    The object falls on the server because physics is applied to it -> The transform's position on the server changes -> NetworkTransform broadcasts these changes to all the clients, resulting in a kinematic movement. So I should also see the client's instances of that Network Object falling, but instead, they get stuck in the air.

    Why is this happening?

    Do I have to manually simulate a falling velocity by applying a force on the Server?

    Moving the Network Object using forces on the Server Side, the NetworkTransform successfully updates the positions in the clients, resulting in the same movement as well:

    MovementScript:
    Code (CSharp):
    1. using Unity.Netcode;
    2. using UnityEngine;
    3. using UnityEngine.InputSystem;
    4.  
    5. public class PlayerMovementScript : NetworkBehaviour
    6. {
    7.  
    8.     [SerializeField] private float MoveSpeed = 100;
    9.  
    10.     private Vector2 mMoveInput;
    11.     private Rigidbody mRigidbodyRef;
    12.    
    13.  
    14.     // Start is called before the first frame update
    15.     void Start()
    16.     {
    17.         mRigidbodyRef = GetComponent<Rigidbody>();
    18.     }
    19.  
    20.     // Update is called once per frame
    21.     void Update()
    22.     {
    23.     }
    24.  
    25.     void FixedUpdate()
    26.     {
    27.         if (this.IsServer)
    28.         {
    29.             mRigidbodyRef.AddForce( (transform.right * mMoveInput.x + transform.forward * mMoveInput.y) * Time.deltaTime * MoveSpeed );
    30.             Debug.Log($"Applying force to NetworkObject: {this.NetworkObjectId}");
    31.         }
    32.     }
    33.  
    34.  
    35.     public void OnMove(InputAction.CallbackContext ctx)
    36.     {
    37.         if (this.IsOwner)
    38.         {
    39.             Vector2 input = ctx.ReadValue<Vector2>();
    40.             MoveServerRpc(input.x, input.y, this.OwnerClientId);
    41.         }
    42.     }
    43.  
    44.  
    45.     [ServerRpc]
    46.     private void MoveServerRpc(float x, float y, ulong clientID)
    47.     {
    48.         mMoveInput.x = x;
    49.         mMoveInput.y = y;
    50.         Debug.Log("Move ("+x+" , "+y+") " + "Request By: " + clientID);
    51.     }
    52. }
    53.  
     
  2. NoelStephens_Unity

    NoelStephens_Unity

    Unity Technologies

    Joined:
    Feb 12, 2022
    Posts:
    259
    Here is an example of a physics motion model for a player that works in either server or owner authoritative modes.
    I made the default set to a server authority motion model, but you can adjust that by editing the Player prefab's PlayerMovement component's AuhtorityMotionModel property:
    upload_2024-1-27_16-39-53.png

    Use standard input for motion (WASD or Arrows) and the space bar to jump (which launches the player into the air using linear velocity).

    Let me know if this quick example I put together helps you track down your issue?

    Side Note:
    The owner authority motion model is smoother for this kind of thing, so try that out too!;)
     

    Attached Files:

    babaliaris likes this.
  3. babaliaris

    babaliaris

    Joined:
    Apr 21, 2013
    Posts:
    40
    I tested your scene and read the Player Movement Script and I understand what you did. You manually implemented physics sync, which is what I thought I might do.

    The question although remains: Why does the built-in NetworkRigidbody exist? What is its purpose?
     
  4. NoelStephens_Unity

    NoelStephens_Unity

    Unity Technologies

    Joined:
    Feb 12, 2022
    Posts:
    259
    The example provided doesn't synchronize physics, but it does synchronize changes to the transform on the non-kinematic side with any other remote kinematic instance. NetworkRigidbody assures that, depending upon the authoritative motion model you select:
    • Server: All server instances are non-kinematic and all remote client instances are kinematic
    • Owner: All clients'/owners' local instances are non-kinematic and all non-owner instances are kinematic.
    The difference is whether you are sending user/player input to the server or applying the input directly to the local instance. NetworkRigidbody just determines whether an instance is non-kinematic or kinematic relative to whether the NetworkTransform is configured to be using a server or owner authoritative motion model. Without NetworkRigidbody, the example would not work correctly.

    Does this help?
     
    babaliaris likes this.
  5. NoelStephens_Unity

    NoelStephens_Unity

    Unity Technologies

    Joined:
    Feb 12, 2022
    Posts:
    259
    Another way to think of this:

    Server Authoritative:
    With the Server authoritative motion model, you could change ownership several times but the Server's instance is what always applies the linear and angular velocities to the non-kinematic Rigidbody based on the current owner's (client) player's remote input. There will always be some form of latency between the remote input and the changes to the transform. Changes to the transform are 1 full RTT for all clients (except host which is always just 1/2 rtt).

    owner input changes (1/2 rtt)--> server/host applies velocities --> (1/2 rtt) transform changes to all clients (including owner)
    Server Rigidbody ---> Always non-kinematic
    Remote Client(s) Rigidbody --> Always kinematic

    The physics simulation is always running on the Server/Host.



    Owner Authoritative
    With the Owner authoritative motion model, the current Owner's player's input is what is used to apply the linear and angular velocities to the local non-kinematic Rigidbody. Changes to the Owner's local transform are sent to the server that forwards those changes to any other non-owner client. If ownership changes, then the new client Owner is who controls updating all non-owners instances based on that client's local player input. There is no latency between a local player's input and the changes applied to the Rigidbody, there is 1/2 RTT latency between the owner and the server and 1 RTT latency to all remote clients.

    owner transform changes due to applying velocities --> (1/2 rtt) server/host applies locally & forwards changes--> (1/2 rtt) all other non-owner remote clients
    Owner Rigidbody ---> Always non-kinematic
    Non-Owner Rigidbody --> Always kinematic

    The physics simulation is broken up into local owner relative simulations.
     
    Last edited: Jan 28, 2024
    babaliaris likes this.
  6. babaliaris

    babaliaris

    Joined:
    Apr 21, 2013
    Posts:
    40
    I understand. So in the Server Authoritative mode, clients send the input to the server, the server applies physics to its instances and those instances are linked to the client's kinematic instances that are being controlled like puppets.

    The NetworkTransform is the component that implements this connection. Making the server instance the puppeteer and the client instance its puppet.

    While the NetworkRigidbody only makes sure that the client Rigidbody is set to kinematic.
     
    NoelStephens_Unity likes this.