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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Cannot sync host and client

Discussion in 'Multiplayer' started by dkalkwarf, Jun 21, 2020.

  1. dkalkwarf

    dkalkwarf

    Joined:
    Mar 29, 2020
    Posts:
    13
    I am trying to get some basic multiplayer working. I am using HLAPI, etc. Yes, I know it has been deprecated.

    I have a Player prefab (Cylinder) to which I added NetworkIdentity and NetworkTransform components. I have a custom NetworkManager where I overrode OnServerAddPlayer. I have set the NetworkManager.playerPrefab to Player. I am using NetworkManagerHUD. I run as a host and connect a client.

    In NetworkManager.OnServerAddPlayer I am setting the Player's color and position to random values. The positions of the players are correct, but the colors on the client side are always gray (RGB = 1,1,1). I assume the positions are correct because NetworkTransform handles that. I do not understand why the colors are not correct.

    I am aware of SyncVar, Commands, etc. and attempted to make that work. I had mixed results. More on that in a moment. My biggest concern is that I do not understand the interplay between host and client. For starters, I do not understand why if I set a property (color) in NetworkManager.OnServerAddPlayer I should have to do anything else, but it seems I do. I know I am missing something about the whole mechanism, but it isn't clicking.

    As mentioned above, I attempted to use SyncVar and a command. Below is one version of the code I tried. This version displays the correct color of the client player, but not the host player. I have tried many variations of assigning the color, calling the command, etc. but cannot get both colors correct.

    At one point I assigned the random color and position in the Player. This worked fine. However, I needed to move this functionality to NetworkManager.OnServerAddPlayer in order to better control other settings. Why one way worked and another doesn't is a mystery to me. I know I am missing something fundamental, but it isn't coming to me.

    Code (CSharp):
    1. public class CustomNetworkManager : NetworkManager
    2. {
    3.     public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
    4.     {
    5.         SetupNewPlayer(conn, playerControllerId);
    6.        
    7.     }
    8.  
    9.     private void SetupNewPlayer(NetworkConnection conn, short playerControllerId)
    10.     {
    11.         GameObject player = Instantiate(playerPrefab);
    12.  
    13.         // random color
    14.         player.GetComponent<MeshRenderer>().material.color =
    15.             new Color(UnityEngine.Random.Range(0.0f, 1.0f),
    16.                       UnityEngine.Random.Range(0.0f, 1.0f),
    17.                       UnityEngine.Random.Range(0.0f, 1.0f));
    18.  
    19.         // random x position
    20.         player.transform.position = new Vector3(player.transform.position.x + UnityEngine.Random.Range(-5.0f, 5.0f),
    21.                                                 player.transform.position.y,
    22.                                                 player.transform.position.z);
    23.        
    24.         NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
    25.     }
    26. }
    27.  
    28.  
    29. public class Player : NetworkBehaviour
    30. {
    31.     [SyncVar]
    32.     private Color color;
    33.     private Material meshMaterial;
    34.  
    35.     void Start()
    36.     {
    37.         meshMaterial = GetComponent<MeshRenderer>().material;
    38.  
    39.         // save the color set in NetworkManager.OnAddServerPlayer
    40.         color = meshMaterial.color;
    41.     }
    42.  
    43.     private void Update()
    44.     {
    45.         CmdUpdateColor(meshMaterial.color);      
    46.         meshMaterial.color = color;      
    47.     }
    48.  
    49.     [Command]
    50.     void CmdUpdateColor(Color newColor)
    51.     {
    52.         color = newColor;
    53.     }
    54. }
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    If you make a change to the object on the server, you need to also make that change on the client if you want to keep them in sync. As you noticed, the NetworkTransform component mostly handles that for you regarding position/rotation. Changing a color though you need a script which does that. You can use a SyncVar, but you'll have to serialize the Color data for the network, since Color itself isn't a supported SyncVar type. Since you're just generating 3 floats to create your new color, you can easily send the 3 floats individually or as a Vector3 (which is little more than just 3 floats), since both of those are supported SyncVar types.

    Supported SyncVar types from the documentation. What is supported for ClientRPC/Command is similar as well.
    https://docs.unity3d.com/Manual/UNetStateSync.html

    As far as the interplay between client and server in general, it is better to think of it as two separate computers running separate instances of the same game which talk to each other, than it is two computers running the same game. This area seems to really mix up a lot of new people to networking with Unet or similar systems. Anything on one instance you want to change, you need a mechanism for telling the other instances to also change the same thing. Some of that is built in, most of it you need to write yourself.

    Best of luck!
     
    Last edited: Jun 23, 2020
  3. dkalkwarf

    dkalkwarf

    Joined:
    Mar 29, 2020
    Posts:
    13
    I appreciate the comments and I have tried a couple of things. However, I am still struggling.

    I simplified my example. My player prefab now is just a cylinder with no script. Therefore, there is no NetworkTransform SyncVar, etc. My NetworkManager remains the same: I am setting a random color and position. The player positions are always correct, but the colors on the client are always gray (1,1,1). If this is because of the serialization issue you mentioned, then I do not understand: I can get the client color to sync with the code in my original post.
     
  4. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    You just need to send the 3 floats to the clients. Don't try to send the color, because serializing the color type isn't supported. The color is made up of 3 float values. Send those 3 float values, and create the color from the 3 floats on the clients. I suggested using a Vector3 to do so, because they are also made up of 3 floats, and the HLAPI has build in support for serializing Vector3's, which would save you a couple lines of code. But if that sounds complicated, just send the 3 floats.
     
  5. dkalkwarf

    dkalkwarf

    Joined:
    Mar 29, 2020
    Posts:
    13
    Sorry, but I do not completely understand. To reiterate, I wish to set a series of player properties in NetworkManager.OnServerAddPlayer. Some of those settings do not get set on the client. The transform.position makes it to the client, but not other properties. As mentioned above, I cannot set the color (not serializable?). I also tried setting the name (string) as well as a custom integer variable. Neither of those make it to the client (they are set on the server side). Why do some the values set in NetworkManager.OnServerAddPlayer make it across the wire to the client but not others?

    I appreciate the help. At this point, things just seem inconsistent with no rhyme or reason.
     
  6. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    In the code you posted, you're just setting the color. So can't even guess why the other things aren't sending.
     
  7. dkalkwarf

    dkalkwarf

    Joined:
    Mar 29, 2020
    Posts:
    13
    My last question summarizes my problem: Why can I set the position in OnServerAddPlayer, but not other values? My code shows I tried to set the color. That color does not make it to the client. Why?
     
  8. dkalkwarf

    dkalkwarf

    Joined:
    Mar 29, 2020
    Posts:
    13
    After much more reading and experimenting I have solved my problem. However, I still do not understand Unity's rationale.

    My solution (suggested and recommended in multiple forum posts) to the problem of initializing clients in OnServerAddPlayer is that the client needs SyncVars for whatever need to be initialized (e.g. color). Those SyncVars may be set in OnServerAddPlayer.

    Position seems to be a special case in that no SyncVar is required. There is some mention of this exception in a couple of forum topics and it is apparently buried in the Unity documentation somewhere.