Search Unity

Updating Rigidbody Constraints across Host and Clients

Discussion in 'Netcode for GameObjects' started by blakelwinser, Nov 14, 2022.

  1. blakelwinser

    blakelwinser

    Joined:
    Jan 17, 2020
    Posts:
    4
    I'm trying to create a way for a player to freeze another player when a raycast hits the target player. Currently I am using ClientNetworkTransform and I am freezing the targets by using Rigidbody.Constrains.FreezeAll.

    If the host is tagged by a client, the host will be frozen and cannot move. If the host tags a connected client however the client will be be marked as frozen in my logging but will not actually get frozen and can still continue moving around.

    Code (CSharp):
    1.  
    2.     [ServerRpc]
    3.     public void UpdateTeamServerRpc(ulong clientId)
    4.     {
    5.         var taggedClient = NetworkManager.Singleton.ConnectedClients[clientId].PlayerObject.GetComponent<Freeze>();
    6.  
    7.         if (taggedClient != null) //Avoid disconnect errors
    8.         {
    9.             UpdatePlayerStateServerRpc(PlayerState.Tagged);
    10.             taggedClient.rb.constraints = RigidbodyConstraints.FreezeAll;
    11.  
    12. //Doesn't Sync with Client. Host can only be frozen by client.
    13. //I think the fix is to make the NetworkTransform server authorative and not client based.
    14.  
    15.         }
    16.  
    17.         UpdateTeamClientRpc(new ClientRpcParams
    18.         {
    19.             Send = new ClientRpcSendParams
    20.             {
    21.                 TargetClientIds = new ulong[] { clientId }
    22.             }
    23.         });
    24.     }
    25.  
    26.     [ClientRpc]
    27.     public void UpdateTeamClientRpc(ClientRpcParams clientRpcParams = default)
    28.     {
    29.         if (IsOwner) return;
    30.         Debug.Log("Player got tagged");
    31.     }
    As you can see in my comments I think this could be due to me using ClientNetworkTransform but I am unsure, If anyone's wondering I am also simply calling UpdateTeamServerRpc when the player clicks Mouse0 in the FixedUpdate method.
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,998
    Physics is simulated on the server only and the client Rigidbodies are set to kinematic if you use the NetworkRigidbody script (and if wouldn't use it, physics would not be synchronized between clients). So if you set any client's rigidbody to frozen it will not have any effect, with the exception of the host.

    You need to set the frozen flag on the server-side rigidbody of the client that you want to freeze. However, this conflicts with you using ClientNetworkTransform because the client has authority over movement. Therefore you still have to send an RPC to the clients so they won't change their transform (eg due to user input) while being frozen.
     
    blakelwinser likes this.
  3. blakelwinser

    blakelwinser

    Joined:
    Jan 17, 2020
    Posts:
    4
    Right ok, so for testing I simply made a ClientRpc that disables the client playermovement script but the client is still able to move around.

    Code (CSharp):
    1.     [ClientRpc]
    2.     public void UpdateMovementClientRpc(ClientRpcParams clientRpcParams = default)
    3.     {
    4.         if (IsOwner) return;
    5.  
    6.         GetComponent<PlayerMovement>().enabled = false;
    7.         Debug.Log("Player movement disabled");
    8.     }
    When executing this from a client, I can see in my console that I am logging "player movement disabled" and when inspecting the client in the Hierarchy, the movement script is disabled. I suspect I am doing something wrong with the RPC's.
     
  4. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,998
    UpdateMovementClientRpc is called from the server targeting a specific clientId?

    Are you sure you are performing client-authoritative movement? Maybe this is somehow setup incorrectly and movement is actually done on the server (or both client and server).

    You should also check if PlayerMovement.enabled suffices to stop updating the transform. If you use new Input system and PlayerMovement handles input events directly, it will still receive those events and processes them despite the script being disabled. This is why I prefer to have a script that receives input events, and keeps a struct of needed input values (Vector2 and bool mostly) for other scripts to use every Update.
     
  5. blakelwinser

    blakelwinser

    Joined:
    Jan 17, 2020
    Posts:
    4
    Sorry the code makes it look confusing, No my PlayerMovement is all handled through the Client Network Transform component. The above code example is simply to disable said movement script, I would assume if the PlayerMovement script is disabled on the client the movement would no longer function as my inputs are defined within the said movement script.

    I believe I may be calling the RPC's wrong possibly, would you happen to have an example of how I would disable a script on a specific client?
     
    Last edited: Nov 17, 2022
  6. blakelwinser

    blakelwinser

    Joined:
    Jan 17, 2020
    Posts:
    4
    So I have done some experimenting and I am still confused as to why for whatever reason my Client's do not get updated like the host does.

    I changed my Tag script to grab a new networked variable which is created in my PlayerMovement script that is synced to the player move speed. When a player gets tagged, in my case using a raycast the movement gets set to 0. On the host this works fine, if a client tags the host the host cannot move but if its the other way around the client can still do whatever with no changes.

    I must be handling how Client's get updated incorrectly or something, I'm completely stuck at this point unfortunately.

    Code (CSharp):
    1.     private void InitTag()
    2.     {
    3.         RaycastHit hit;
    4.  
    5.         int layerMask = LayerMask.GetMask("Player");
    6.  
    7.         if(Physics.Raycast(cam.transform.position, cam.transform.forward, out hit, minTagDistance, layerMask))
    8.         {
    9.             Debug.DrawRay(cam.transform.position, cam.transform.forward * minTagDistance, Color.red); //Hitting something = red
    10.  
    11.             var playerHit = hit.transform.GetComponent<NetworkObject>();
    12.             if (playerHit != null)
    13.             {
    14.                 UpdateTeamServerRpc(playerHit.OwnerClientId);
    15.             }
    16.         }
    17.         else
    18.         {
    19.             Debug.DrawRay(cam.transform.position, cam.transform.forward * minTagDistance, Color.blue); //Not hitting something = blue
    20.         }
    21.     }
    22.  
    23. [ServerRpc]
    24.     public void UpdateTeamServerRpc(ulong clientId)
    25.     {
    26.         var taggedClient = NetworkManager.Singleton.ConnectedClients[clientId].PlayerObject.GetComponent<TagPunch>();
    27.  
    28.         if (taggedClient != null) //Avoid disconnect errors
    29.         {
    30.             UpdatePlayerStateServerRpc(PlayerState.Tagged);          
    31.             taggedClient.GetComponent<PlayerMovement>()._netMovementSpeed.Value = 0;
    32.             Debug.Log("ServerRpc: Player got tagged");
    33.         }
    34.  
    35.         UpdateTeamClientRpc(new ClientRpcParams
    36.         {
    37.             Send = new ClientRpcSendParams
    38.             {
    39.                 TargetClientIds = new ulong[] { clientId }
    40.             }
    41.         });
    42.     }
    43.  
    44.     [ClientRpc]
    45.     public void UpdateTeamClientRpc(ClientRpcParams clientRpcParams = default)
    46.     {
    47.         if (IsOwner) return;
    48.         Debug.Log("ClientRpc: Player got tagged");
    49.     }