Search Unity

Not understanding SyncVar, Hook and Command

Discussion in 'Multiplayer' started by Bigbeef, Jan 26, 2017.

  1. Bigbeef

    Bigbeef

    Joined:
    Apr 6, 2013
    Posts:
    31
    I'm having a hard time setting up SyncVars and Command functions. I don't quite understand the flow of how this is supposed to work.

    From what I gather, and please correct me at any point if I am wrong, when a variable is tagged [SyncVar], then if it changes on the server, clients should see it changed.

    Clients can't directly change SyncVars. Only the Server can. So if you want a Client to update a SyncVar, you have to use Command attribute on a function. Command functions, tagged with [Command] and the function name starting with Cmd, are functions that when called are executed by the server. So if you want to tell the server, from a client, to change a SyncVar variable, you need to use a Command function, that way the server changes the variable, and then the change will be seen on the clients.

    For some reason I can not get a client to tell the server to change a SyncVar.

    Am I supposed to tag the server controlled object with a server identity and check Server Only?

    Am I supposed attach a client network identity component to the UI Canvas GameObject that has the script I want the players to use?

    Does the client authority object get the Cmd function or do I put that on the Server Authority object's script?

    Right now I have 2 scripts:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.Networking;
    4. using System.Collections;
    5.  
    6. public class Stats : NetworkBehaviour
    7. {
    8.  
    9.     public const int maxHealth = 100;
    10.     public Text healthText;
    11.  
    12.     [SyncVar(hook = "OnChangeHealth")]
    13.     public int currentHealth = maxHealth;
    14.  
    15.  
    16.     public void TakeDamage(int amount)
    17.     {
    18.         if (!isServer)
    19.             return;
    20.  
    21.         currentHealth -= amount;
    22.  
    23.     }
    24.  
    25.     void OnChangeHealth(int health)
    26.     {
    27.         currentHealth = health;
    28.     }
    29. }
    and


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5. using UnityEngine.Networking;
    6.  
    7.  
    8. public class playerHUDController : NetworkBehaviour {
    9.  
    10.  
    11.     public Button basicButton;
    12.  
    13.     public Stats statObject;
    14.  
    15.     void Start () {
    16.      
    17.     }
    18.  
    19.     void Update () {
    20.  
    21.         statObject.healthText.text = statObject.currentHealth.ToString();
    22.     }
    23.  
    24.  
    25.     public void OnBasicButtonSelect()
    26.     {
    27.         statObject.TakeDamage(10);
    28.     }
    29.  
    30.  
    31. }
    When I am on the Host/Client version of the game, I can press the button, and I see the Text on my screen change: 100, 90, 80, etc.

    On a separate execution of the game, I connect as client only, and I can see the changes being made from the Host/Client game when I click the button on the host/client.

    But if I click the button on the client only game, nothing happens. Nothing changes on the screen, and the Host/Client game doesn't change either.

    What am I doing wrong here? It works perfectly on the Host/Client, but on client it does nothing.

    Any assistance would be great. Thank you!
     
    Last edited: Jan 26, 2017
    Zagule, mdrunk and PersianKiller like this.
  2. robochase

    robochase

    Joined:
    Mar 1, 2014
    Posts:
    244
    i don't see your Command function in the code you provided!

    you're close, but you need to do something like this -

    note that you won't see CmdTakeDamage getting called on the client when the client calls it. normally you'd expect an infinite loop here, but nope. it only gets called on the server's copy of this gameobject.

    Code (CSharp):
    1. public void TakeDamage(int value)
    2. {
    3.     if (isServer) {
    4.         currentHealth -= value;
    5.     } else {
    6.         CmdTakeDamage (value);
    7.     }
    8. }
    9.  
    10. [Command]
    11. void CmdTakeDamage(int value)
    12. {
    13.     TakeDamage (value);
    14. }
     
  3. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    [SyncVar] only sync from Server --> Client. They never sync from Client --> Server. However they *can* be changed locally on the client and no errors will be thrown.

    [Command] send information from Client --> Server. It can only be used if the client owns the object and has authority.
    [ClientRPC] are just like command's but send information from Server --> all Client's
    [TargetRPC] is just like ClientRPC, but only sends to 1 client (not all clients)

    Your hook looks correct.

    If you want the client to change the value of the SyncVar then send a Command to the server and then on the server change the value. This new updated value will then be trickled back to all clients and hooks will be called.
     
  4. robochase

    robochase

    Joined:
    Mar 1, 2014
    Posts:
    244
    nice, i didn't know TargetRPC existed. now to go back & optimize.... :D
     
    pjkokane21 likes this.
  5. ludovicb1239

    ludovicb1239

    Joined:
    Sep 12, 2018
    Posts:
    2
    Big thanks !
    I used some of your code to syncronise my position and a bool value.
    I dont know how to change the server or player autority
     
    Last edited: Nov 4, 2019
  6. AdventureproGames

    AdventureproGames

    Joined:
    Feb 4, 2015
    Posts:
    5
    In my experience, SyncVars simply don't work when the change is made on a listen server (Host/Client).

    For anyone else having the problem in the OP, note that if you run two clients and then a server independently, your problem will likely go away. But if one of your clients is also the host, SyncVars won't propagate anywhere else.