Search Unity

[Solved] (C#) Only the host correctly changes a [SyncVar]

Discussion in 'Multiplayer' started by Gunging, Apr 24, 2017.

  1. Gunging

    Gunging

    Joined:
    Sep 6, 2016
    Posts:
    139
    Well, I have a bool "charging" that should be active for a player's gameObject in all the computers while the LocalPlayer holds spacebar, the code looks like this:
    Code (CSharp):
    1.  
    2.  
    3. [SyncVar] bool charging;
    4. int ammo;
    5. int chargeSize;
    6.  
    7. void Update() {
    8.       if (charging) { Charge(); }
    9.       if (!isLocalPlayer) {return;}
    10.       FireMechanic();
    11. }
    12.  
    13. void FireMechanic() {
    14.             if (Input.GetKey(KeyCode.Space) && ammo > 0) {
    15.                 chargeSize++; //Irrelevant?
    16.                 ammo--;           //Irrelevant?
    17.                 charging = true;
    18.                 if (allowAmmoRegen) { allowAmmoRegen = false; }
    19.             }
    20.             if (Input.GetKeyUp(KeyCode.Space)) { //When spacebar releases
    21.                 CmdFire(chargeSize);
    22.                 charging = false;
    23.                 chargeSize = 0;
    24.                 allowAmmoRegen = true;
    25.             }
    26. }
    *Charging is irrelevant for CmdFire. It only activates Charge(), which just has a visual effect of some particle systems and stuff, is not altered in any other place of the script.

    After running some Debug.Log()s, I realized only the host sets "charging" to true/false in every computer; The clients only have "charging" as true when needed on their computer, in every other computer it remains false always.

    Thanks in advance.
     
  2. robochase

    robochase

    Joined:
    Mar 1, 2014
    Posts:
    244
    yep, that's how sync vars work - only the server can change their values.

    if you need a client to change a syncvar, it should send a command to the server, passing the new value as a parameter. the server would then update the syncvar in the command.
     
  3. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Yeah SyncVars are only from Server --> Client

    If you want to send data from Client --> Server there are 2 ways
    A: Command
    B: MessageBase

    So to sync a variable from a client to server + other clients it takes 2 steps.
    Step1: Send data from client to server (2 options: Command or MessageBase)
    Step2: Send data from server to all other clients (3 options: SyncVar, ClientRPC, or MessageBase)

    If you decide to use SyncVars it becomes a little tricky because you must ignore the callbacks on the owner that set the value in the firstplace otherwise you'll be fighting with the Server over control of it.

    If you decide to use ClientRPC again the owner of the variable must ignore the message (or alternatively on send it to non-owner clients). Also late-connecting players will not get the latest up-to-date value when they connect.

    I personally use MessageBase. But this gets extremely complicated as well.
     
  4. Gunging

    Gunging

    Joined:
    Sep 6, 2016
    Posts:
    139
    So, you recommend removing the [SyncVar] attribute, and change it instead with, like:
    Code (CSharp):
    1. void FireMechanic() {
    2.             if (Input.GetKey(KeyCode.Space) && ammo > 0) {
    3.                 //charging = true;
    4.                 CmdSetCharging(true);
    5.             }
    6. }
    7.  
    8. [Command] CmdSetCharging(bool value) {
    9.       charging = value;
    10. }
    ?

    Im actually going to try this lol.
     
  5. Gunging

    Gunging

    Joined:
    Sep 6, 2016
    Posts:
    139
    Interesting: The clients set the bool correctly in the host only, the host makes it remain false.
    Let me try something else....

    [EDIT]: Leaving the syncvar attribute still not works :c
     
    Last edited: Apr 24, 2017
  6. robochase

    robochase

    Joined:
    Mar 1, 2014
    Posts:
    244
    try this - note the isServer checks I added. the server can set the sync var directly. non-servers send a command to the server, which then sets the sync var for everyone.

    also I changed your first if (Input.GetKey()) to use GetKeyDown so you're not spamming a command to the server every frame - this is a waste of bandwidth.

    Code (CSharp):
    1.  
    2. [SyncVar] bool charging;
    3. int ammo;
    4. int chargeSize;
    5. void Update() {
    6.       if (charging) { Charge(); }
    7.       if (!isLocalPlayer) {return;}
    8.       FireMechanic();
    9. }
    10. void FireMechanic() {
    11.     if (Input.GetKeyDown(KeyCode.Space) && ammo > 0) {
    12.         chargeSize++; //Irrelevant?
    13.         ammo--;           //Irrelevant?
    14.    
    15.         if (isServer)
    16.         {
    17.             charging = true;
    18.         }
    19.         else
    20.         {
    21.             CmdCharging(true);
    22.         }
    23.  
    24.         if (allowAmmoRegen) { allowAmmoRegen = false; }
    25.     }
    26.     if (Input.GetKeyUp(KeyCode.Space)) { //When spacebar releases
    27.         CmdFire(chargeSize);
    28.    
    29.         if (isServer)
    30.         {
    31.             charging = false;
    32.         }
    33.         else
    34.         {
    35.             CmdCharging(false);
    36.         }
    37.         chargeSize = 0;
    38.         allowAmmoRegen = true;
    39.     }
    40. }
    41.  
    42. [Command]
    43. void CmdCharging(bool isCharging)
    44. {
    45.     // note that this is only called on the server
    46.     charging = isCharging;
    47. }
     
    Basevich likes this.
  7. Gunging

    Gunging

    Joined:
    Sep 6, 2016
    Posts:
    139
    It works, thank you.

    Oh, well, it is supposed to be KeyDown because of what is contained in the irrelevant section of the code in Charging(), In my case instead add.
    Code (CSharp):
    1. if (isServer)
    2. {
    3.       if (!charging) { charging = true; }
    4. }
    5. else
    6. {
    7.       if (!charging) { CmdCharging(true); }
    8. }
    9.  
     
    Basevich likes this.