Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Issue with clientnetworktransform and character controller (colliders not syncing but transform does

Discussion in 'Netcode for GameObjects' started by KadynCBR, Apr 15, 2022.

  1. KadynCBR

    KadynCBR

    Joined:
    Sep 19, 2015
    Posts:
    2
    A little stumped here if someone has any ideas it would be helpful.
    I am using a charactercontroller with ClientNetworkTransform

    and it seems my character controller's collider isn't moving from its spawn position(??)
    The graphics and object itself seems to be moving correctly when examining on two editors.
    but there's this like "invisible collider" where the players start when loaded in.

    It feels like the character controllers collider isn't being updated but the object transforms are? im not too sure where to even begin with this because this invisible collider doesn't show up in hierarchy it seems.

    For whatever help it might be in conveying my problem..,

    Started with Player 0 (right side).
    Logged in with player 1 ("in air")
    moved player 0 from its original position (beneath player 1)
    then was able to jump on player 0's collider since it remained at its spawn point.
     
  2. KadynCBR

    KadynCBR

    Joined:
    Sep 19, 2015
    Posts:
    2
    Code (CSharp):
    1.   public override void OnNetworkSpawn()
    2.   {
    3.     base.OnNetworkSpawn();
    4.     enabled = IsClient;
    5.     if (!IsOwner)
    6.     {
    7.       enabled = false;
    8.       return;
    9.     }
    10.  
    11.     mycontroller = GetComponent<CharacterController>();
    12.   }
    More on this, after looking at the client driven bitsize example and seeing that it also used a character controller and was set up pretty closely to my own setup, I added the code above to my own character controller and this seems to have solved the issue mentioned above.

    I'm new to network so could someone help me gain some understanding as to why this is the case?
    Disabling the playercontroller script for people who aren't owners allows them to be updated solely by the server?
     
  3. CosmoM

    CosmoM

    Joined:
    Oct 31, 2015
    Posts:
    204
    Any script that is not explicitly disabled on some clients will run on all clients, no matter who the owner is – which is not what you want, typically, for a player controller or anything that listens for input.
     
  4. beyondtheuniverse609

    beyondtheuniverse609

    Joined:
    Jan 10, 2022
    Posts:
    1
    Same issue with me.. the component like just spawned at spawning position but doesnt move whenever the transform is moving. so i dont quite sure
     
  5. NoelStephens_Unity

    NoelStephens_Unity

    Unity Technologies

    Joined:
    Feb 12, 2022
    Posts:
    252
    In order to understand why this issue is happening there are two concepts you need to contemplate:

    • Authority: The instance that drives/dictates the motion of the character/object. Effectively, the authority is the "input" of the object's motion (relative to all non-authority instances) and the local render view of the authority could also be viewed as the "output"/result of the motion.
    • Non-Authority: The instances that mirror the authority instance (by receiving state updates). Effectively, the non-authority instances are nothing more than the "output" of the authority's motion.
    So, in the context of the CharacterController you only need to think about what a CharacterController effectively does: (Typically)Based on the input provided by the player, it translates that to the motion (output) of the "character" (object) while also handling collisions and such.

    If you think about non-authoritative instances, since they are the "output" (result) of the authority's "input"... it would make sense that you would not want non-authoritative instances to have their relative (local) instance of the CharacterController active as that would fight with the input being sent by the authority and applied locally by NetworkTransform.

    You could try a simple test (single player) where you write a script that simple moves the transform of a GameObject in a circle while also having a CharacterController component (attached to the same GameObject) that is invoking Move or SimpleMove based on local keyboard input...the end result will be that the CharacterConroller will not "behave as expected" (under most circumstances) because the transform is being modified by both your script directly moving the transform in a circle and by CharacterController applying changes to the transform based on the Move or SimpleMove invocations driven by keyboard input.

    It can be initially confusing at first, but you can simplify the complexity by just thinking of the context:
    "Which instance do you want driving the CharacterController?"

    If the local player is driving the CharacterController:
    • Enable the CharacterController on the owner instance and disable it on the rest of the non-owner instances.
    • Since the owner is driving input, you want an "owner authoritative" motion model (i.e. ClientNetworkTransform) that sends the end result of the input (i.e. the output being the changes to the transform) to all non-authoritative instances.
    If the server is driving the CharacterController:
    For AI and/or you might be sending player input to the server via RPCs.
    • Enable the CharacterController on the server instance and disable it on the client instance(s).
      • The caveat (if players are sending input via RPCs) is when running a Host (that is both server and client ) it will still be enabled.
    • Since the server is driving input, you want a "server authoritative" motion model (i.e. just NetworkTransform) that sends the end result of the input (i.e. the output being the changes to the transform) to all remote client instances.

    Hopefully the above will help shed some light on why this block of script...

    Code (CSharp):
    1.   public override void OnNetworkSpawn()
    2.   {
    3.     base.OnNetworkSpawn();
    4.     enabled = IsClient;
    5.     if (!IsOwner)
    6.     {
    7.       enabled = false;
    8.       return;
    9.     }
    10.     mycontroller = GetComponent<CharacterController>();
    11.   }
    ...works when using an "Local player driven CharacterController using an owner authoritative motion model". It just disables the CharacterController on non-authoritative (i.e. non-owner) instances.