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

[SyncVar] Struct Not Synchronizing from Host to Client

Discussion in 'Multiplayer' started by Zullar, Jun 15, 2015.

  1. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    I have a GameObject with attached NetworkIdentity and NetworkBehavior Script (C#)

    I run two instances of the game with a host & client using the built in NetworkManager + NetworkManagerHUD. When the client connects it properly receives the most recent values from the host. However, after the client is connected when I press the key to increment the structure fields they only update on the host, not on the client.

    Does anybody know why the [SyncVar] struct is not updating on the client when it's fields are changed on the host? According to http://docs.unity3d.com/Manual/UNetStateSync.html "SyncVars can be basic types such as integers, strings and floats. They can also be Unity types such as Vector3 and user-defined structs, but updates for struct SyncVars are sent as monolithic updates, not incremental changes if fields within a struct change."

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.Networking; //needed for NetworkBehavior
    5.  
    6. public class TestSyncStruct : NetworkBehaviour
    7. {
    8.     [SyncVar]
    9.     private TestStruct syncStruct;
    10.  
    11.     private void Start()
    12.     {
    13.         if(isServer)
    14.         {
    15.             syncStruct = new TestStruct(1234, "initial string", 1234.5678f);
    16.         }
    17.     }
    18.  
    19.     private void Update()
    20.     {
    21.         if(isServer)
    22.         {
    23.             if(Input.GetKeyDown(KeyCode.Alpha1))
    24.             {
    25.                 syncStruct.myInt += 1;
    26.                 syncStruct.myString = "syncStruct set";
    27.                 syncStruct.myFloat += 1f;
    28.                 Debug.Log("Key 1 Pressed: Server: Increment syncStruct");
    29.             }
    30.         }
    31.     }
    32.  
    33.     private void OnGUI()
    34.     {
    35.         GUI.Label(new Rect(400, 70, 500, 30), "SyncStruct: " + syncStruct.myInt + " " + syncStruct.myString + " " + syncStruct.myFloat);
    36.     }
    37. }
    38.  
    39. public struct TestStruct
    40. {
    41.     public int myInt;
    42.     public string myString;
    43.     public float myFloat;
    44.    
    45.     public TestStruct(int myIntIn, string myStringIn, float myFloatIn) //constructor
    46.     {
    47.         myInt = myIntIn;
    48.         myString = myStringIn;
    49.         myFloat = myFloatIn;
    50.     }
    51. }
    52.  
     
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    SyncVar structs do not incrementally update. if you want incremental updates, make 3 SyncVars.
     
    Zullar likes this.
  3. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    When 1 of the 3 structure fields is changed I believe all 3 fields should be sent to the client which is inneficient. Is this what you mean by structures do not incremetally update?

    But to state my problem another way when I change 1 structure field it doesn't update any of the 3 fields on the client. I have to manually SetDirtyBit ( ) of the structure on the host to get the client to sychronize. In other words changing a [SyncVar] structure's field value does not automatically SetDirtyBit( ) as it does with [SyncVar] int.
     
  4. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    Yes, that is exactly how it works at the moment. If you set syncStruct to a new struct value it would be set dirty, but setting fields within the struct does not set it dirty.

    Using individual SynVars is preferable to using structs.
     
    Zullar likes this.
  5. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Ah. Thanks for the info.
     
  6. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    3,062
    I have a detail question:
    I am updating a component of a Vector3 and set it dirty. Doing this on the host updates the client but the other way round, the host is not being updated. In the NetworkIdentity, I set LocalPlayerAuthority to true.
    Also: Is there a good way to find which bit relates to which SyncVar?
     
  7. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    I am not 100% sure, but I believe SyncVar's only update from server-->client and not from client-->server, even if LocalPlayerAuthority is true. If you want client data replicated to server one way to do this is to use the [Command] attribute. If you want the data replicated from client to server and all other clients then you can use [Command] to set the syncVar on the server, with a hook on the SyncVar to update its value on all clients except the localplayer.
     
  8. LeopardX

    LeopardX

    Joined:
    May 31, 2015
    Posts:
    64
    call me silly but to me it looks like your code will only run on the server.. none of your code executes from client besides the UI stuff, so no updates or things done on the client to sent to the host are done.. is probably why its only working one way, ive actually got a similar problem but im going to make a separate post for that as the design is slightly diferent to what you have done.

    For me im useing [Client] and [Command] methods, but still only works one way at the moment.
     
  9. TehGM

    TehGM

    Joined:
    Nov 15, 2013
    Posts:
    89
    In fact, C# standards say structs should be immutable (only readonly fields).
    Perhaps Unity is slowly trying to get us used to that? ;o
     
  10. aranthel09

    aranthel09

    Joined:
    Jul 17, 2015
    Posts:
    66
    I might be a bit late here, but I'm currently using SyncVars for my variables. However, it says I have too many SyncVars (way more than 32). How am I supposed to deal with that? All my code is oriented on simply stating variables and then [SyncVar] them.
     
  11. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    UNET uses a packed uint32 dirty bit mask for [SyncVars] which limits you to 32 SyncVars per script. I imagine this is unlikely to change anytime soon (or ever). You can however get around this a few ways:
    1: Use multiple scripts on the same object. 2 scripts = 64 SyncVars, 3 scripts = 96 SyncVars, etc.
    2: Use SyncLists (they can hold thousands) and do not count towards the 32 SyncVar limit
    3: Don't use UNET's HLAPI SyncVars and use messages instead (this is what I've done... it has many advantages. it avoids all the UNET bugs and UNET design issues, avoids the 32 SyncVar limit, gives you serialization control)

    After spending a LOT of time with UNET HLAPI SyncVars/SyncLists/Commands/RPC's I'd advise everybody not to use them until they are fixed. There are so many problems at the moment you will spend all your time trying to workaround and bandaid the bugs... just don't use them is my advise. My advise is to use UNET messages instead, they seem to be very robust.
     
    Yhugo98 and MechEthan like this.