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

Sync Var Hook Changing Variables, but not calling functions...

Discussion in 'Multiplayer' started by _spacepig_, May 9, 2017.

  1. _spacepig_

    _spacepig_

    Joined:
    Jan 18, 2016
    Posts:
    151
    I'm making a switching weapons script but I can't seem to find anywhere where it tells me how to do this or what I'm doing wrong. It would be a huge help if someone could look at my code and tell me what I'm doing wrong. Sorry if it's messy ive been kinda rushing. Thanks!

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.Networking;
    5. public class WeaponManager : NetworkBehaviour
    6. {
    7.  
    8.     private string WeaponLayerName = "WeaponLayer";
    9.  
    10.  
    11.  
    12.     public int[] equippedWeapons;
    13.  
    14.     [SerializeField]
    15.     private Transform weaponHolder;
    16.  
    17.     [SerializeField]
    18.     private PlayerWeapon primaryWeapon;
    19.  
    20.     [SerializeField]
    21.     private PlayerWeapon secondaryWeapon;
    22.  
    23.     [SerializeField]
    24.     private PlayerWeapon specialWeapon;
    25.  
    26.     [SerializeField]
    27.     private PlayerWeapon MeleeWeapon;
    28.  
    29.     [SyncVar (hook = "SwitchWeaponCallback")]
    30.     private int currentWeaponIndex = 0;
    31.  
    32.     private PlayerWeapon currentWeapon;
    33.     private WeaponGraphics currentGraphics;
    34.     public bool isSwitchingWeapon = false;
    35.  
    36.  
    37.  
    38.     bool canSwitchAgain = true;
    39.  
    40.     private PlayerWeapon weaponToLoad;
    41.  
    42.     private bool firstEquip = true;
    43.  
    44.  
    45.     // Use this for initialization
    46.     void Start()
    47.     {
    48.         //EquipWeapon(equippedWeapons[0]);
    49.         isSwitchingWeapon = false;
    50.     }
    51.  
    52.  
    53.     public PlayerWeapon GetCurrentWeapon()
    54.     {
    55.         return currentWeapon;
    56.  
    57.     }
    58.     public WeaponGraphics GetCurrentGraphics()
    59.     {
    60.  
    61.         return currentGraphics;
    62.  
    63.     }
    64.     public override void OnStartLocalPlayer()
    65.     {
    66.         EquipWeaponStart(currentWeaponIndex);
    67.  
    68.     }
    69.  
    70.     public override void OnStartServer()
    71.     {
    72.         base.OnStartServer();
    73.         firstEquip = true;
    74.         currentWeaponIndex = equippedWeapons[0];
    75.     }
    76.     public void SwitchWeaponCallback(int _weapon)
    77.     {
    78.         print("Changed");
    79.         currentWeaponIndex = _weapon;
    80.         EquipWeapon(currentWeaponIndex);
    81.     }
    82.  
    83.     public override void OnStartClient()
    84.     {
    85.  
    86.         EquipWeaponStart(equippedWeapons[0]);
    87.     }
    88.  
    89.  
    90.  
    91.    
    92.  
    93.  
    94.  
    95.  
    96.     void EquipWeaponStart(int _weapon)
    97.     {
    98.  
    99.        
    100.            
    101.         if (_weapon == currentWeaponIndex) return;
    102.                
    103.            
    104.        
    105.  
    106.         if (firstEquip)
    107.             firstEquip = false;
    108.  
    109.  
    110.  
    111.         gameObject.GetComponent<PlayerShoot>().aiming = false;
    112.  
    113.         StopCoroutine(gameObject.GetComponent<PlayerShoot>().Reload());
    114.  
    115.  
    116.  
    117.  
    118.  
    119.      
    120.         StartCoroutine(DrawTimer(_weapon));
    121.        
    122.     }
    123.  
    124.  
    125.     void EquipWeapon(int _weapon)
    126.     {
    127.         if (_weapon == currentWeaponIndex) return;
    128.         print("switch" + _weapon);
    129.  
    130.      
    131.            // CmdEquipWeapon(_weapon);
    132.             DoEquipWeapon(_weapon);
    133.        
    134.  
    135.     }
    136.  
    137.  
    138.  
    139.  
    140.     IEnumerator DrawTimer(int _weapon)
    141.     {
    142.  
    143.         while (gameObject.GetComponent<PlayerShoot>().fireRateTimer > 0)
    144.         {
    145.             yield return null;
    146.         }
    147.  
    148.         while (isSwitchingWeapon == true)
    149.         {
    150.             yield return null;
    151.         }
    152.         canSwitchAgain = false;
    153.         isSwitchingWeapon = true;
    154.  
    155.         gameObject.GetComponent<Player>().SetAnimationParameter("IsSwitchingWeapon", 3, 0, 0, true, true);
    156.         if (currentWeapon != null)
    157.             yield return new WaitForSeconds(currentWeapon.putAwayTime);
    158.  
    159.         EquipWeapon(_weapon);
    160.         canSwitchAgain = true;
    161.  
    162.         if (currentWeapon != null)
    163.             yield return new WaitForSeconds(currentWeapon.drawTime);
    164.  
    165.         gameObject.GetComponent<Player>().SetAnimationParameter("IsSwitchingWeapon", 3, 0, 0, false, true);
    166.         isSwitchingWeapon = false;
    167.  
    168.  
    169.  
    170.     }
    171.  
    172.  
    173.  
    Code (csharp):
    1.  
    2.  
    3.   void DoEquipWeapon(int _weapon)
    4.     {
    5.  
    6.      
    7.  
    8.  
    9.         currentWeaponIndex = _weapon;
    10.  
    11.         if (currentWeapon != null)
    12.         {
    13.  
    14.             currentWeapon.graphics.SetActive(false);
    15.         }
    16.  
    17.         switch (_weapon)
    18.         {
    19.  
    20.  
    21.             case 0:
    22.                 // no weapon
    23.                 currentWeapon = null;
    24.                 break;
    25.             case 1:
    26.                 // primary
    27.                 currentWeapon = primaryWeapon;
    28.                 break;
    29.             case 2:
    30.                 // secondary
    31.                 currentWeapon = secondaryWeapon;
    32.                 break;
    33.             case 3:
    34.                 // special
    35.                 currentWeapon = specialWeapon;
    36.                 break;
    37.             case 4:
    38.                 // Melee
    39.                 currentWeapon = MeleeWeapon;
    40.                 break;
    41.         }
    42.  
    43.  
    44.  
    45.        
    46.  
    47.         currentGraphics = currentWeapon.graphics.GetComponent<WeaponGraphics>();
    48.  
    49.  
    50.         if (isLocalPlayer)
    51.         {
    52.             Util.SetLayerRecursively(currentWeapon.graphics, LayerMask.NameToLayer(WeaponLayerName));
    53.         }
    54.  
    55.  
    56.  
    57.         currentWeapon.graphics.SetActive(true);
    58.         currentWeapon.spreadFactorSet = currentWeapon.spreadFactor;
    59.         gameObject.GetComponent<Player>().SetAnimationParameter("CurrentWeapon", 2, 0f, currentWeaponIndex, false, true);
    60.         gameObject.GetComponent<PlayerShoot>().fireRateTimer = 0;
    61.         gameObject.GetComponent<PlayerShoot>().aiming = false;
    62.         if (GetComponent<PlayerSetup>().playerUIInstance != null)
    63.         {
    64.  
    65.             GetComponent<PlayerSetup>().playerUIInstance.GetComponent<PlayerUI>().crossHair.SetActive(true);
    66.         }
    67.  
    68.     }
    69.  
    70.   void Update()
    71.     {
    72.         if (!isLocalPlayer)
    73.             return;
    74.  
    75.        
    76.  
    77.  
    78.         if (Input.GetKeyDown("1"))
    79.         {
    80.             EquipWeaponStart(equippedWeapons[0]);
    81.            
    82.         }
    83.         if (Input.GetKeyDown("2"))
    84.         {
    85.              EquipWeaponStart(equippedWeapons[1]);
    86.            
    87.         }
    88.  
    89.         if (Input.GetKeyDown("3"))
    90.         {
    91.              EquipWeaponStart(equippedWeapons[2]);
    92.         }
    93.         if (Input.GetKeyDown("4"))
    94.         {
    95.              EquipWeaponStart(equippedWeapons[3]);
    96.            
    97.         }
    98.     }
    99.  
    100.  
    101.     public void loadAmmoStart()
    102.     {
    103.  
    104.         for (int i = 0; i < equippedWeapons.Length; i++)
    105.         {
    106.             SetAmmo(i);
    107.         }
    108.     }
    109.  
    110.     public void SetAmmo(int _weapon)
    111.     {
    112.  
    113.  
    114.  
    115.         switch (_weapon)
    116.         {
    117.             case 0:
    118.                 // no weapon
    119.                 weaponToLoad = null;
    120.                 break;
    121.             case 1:
    122.                 // primary
    123.                 weaponToLoad = primaryWeapon;
    124.                 break;
    125.             case 2:
    126.                 // secondary
    127.                 weaponToLoad = secondaryWeapon;
    128.                 break;
    129.             case 3:
    130.                 // special
    131.                 weaponToLoad = specialWeapon;
    132.                 break;
    133.             case 4:
    134.                 // Melee
    135.                 weaponToLoad = MeleeWeapon;
    136.                 break;
    137.         }
    138.  
    139.  
    140.         if (weaponToLoad != null)
    141.             weaponToLoad.currentAmmo = weaponToLoad.magazineSize;
    142.  
    143.     }
    144.  
    145.  
    146. }
    147.  
    148.  
    149.  
     
  2. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Is the value of currentWeaponIndex being changed?
    If currentWeaponIndex is being changed is SwitchWeaponCallback being called on the server? Or just not clients?

    The way hooks work is that the new value must also be set within the hook or else the value wont be set on the client(don't ask me why). So...
    currentWeaponIndex = weapon
    should be part of your SwitchWeaponCallback

    Also, SyncVar callbacks are not called during initialization when OnSerialize/Desierialize w/ initialState==true. So if you want the hook called when a client connects you must call it yourself (I do this during Start)
     
  3. _spacepig_

    _spacepig_

    Joined:
    Jan 18, 2016
    Posts:
    151

    It seems the value is set, but the function isnt called
     
  4. unidad2pete

    unidad2pete

    Joined:
    Feb 17, 2017
    Posts:
    22
    A trick working for me, i have a lot of similar problems working with syncvars and rpc cmd functions.

    1- Put empty object in scene (named "TriggerSpawnGameObject" or name you want)
    2- Put InputField in scene, out of screen, not visible to game screen( Name "InputTrigger")
    3- In TriggerSpawnGameObject put new script (Named "ScriptTriggerFunction")

    Code (CSharp):
    1.  
    2.    [SyncVar(hook = "Trigger")]
    3.     public string stringTrigger;
    4.     public InputField inputTrigger;
    5.  
    6.     public void Trigger(string msj)
    7.     {
    8.         inputTrigger.text = msj;
    9.     }
    10.     void Start ()
    11.     {
    12.         inputTrigger = GameObject.Find("InputTrigger").GetComponent<InputField>();
    13.     }
    14.  
    15.     void Update ()
    16.     {
    17.  
    18.     }
    4 - Create new gameObject and registrer how spawned object in server(prefab named "PrefabTrigger")
    5- In prefabTrigger, add new script(named " ScriptGameObjectTrigger")

    Code (CSharp):
    1. v
    2. oid Start ()
    3.     {
    4.         if(isServer)
    5.         {
    6.             GameObject.Find("TriggerSpawnGameObject").GetComponent<ScriptTriggerFunction>().stringTrigger = Random.Range(0, 1000).ToString();
    7.             Destroy(gameObject, 3);
    8.         }
    9.     }
    At this moment we have an object with function to change a syncvar string on server, that make change that value on all clients, and input field on game with new value.
    We can use this gameobject to say all clients do something when any call (Client or server)
    Code (CSharp):
    1. [Command]
    2.     public void CmdSpawnTrigger()
    3.     {
    4.         var go = Instantiate(prefabTrigger);
    5.         NetworkServer.Spawn(go);
    6.     }
    For example, in your script to switch weapons.

    Code (CSharp):
    1. public InputField inputTrigger;
    2.     public override void OnStartLocalPlayer()
    3.     {
    4.         base.OnStartLocalPlayer();
    5.         inputTrigger = GameObject.Find("InputTrigger").GetComponent<InputField>();
    6.         inputTrigger.onValueChanged.AddListener(delegate { FunctionToCall(); });
    7.         //Maybe you need call IEnumerator to wait for sure all data its synchronized, then call
    8.        CmdSpawnTrigger(/* info to share if needed */);
    9.     }
    10.  
    11.     public void FunctionToCall()
    12.     {
    13.         // YourCode
    14.     }
    This is not for sync variables, you say value is set, but function not called.
    When you change any syncvar variable, you can spawn prefabTrigger after change they value.
    Then, after set value, a FunctionToCall its called on all clients, you can get do you want in that function.
    Or you can send info to allplayers on prefabTrigger script.

    Code (CSharp):
    1.  
    2. public int indexWeapon;
    3. public bool onlyTrigger = true;
    4. void Start ()
    5.     {
    6.         if(isServer)
    7.         {
    8.           if(onlyTrigger)
    9. {
    10.             GameObject.Find("TriggerSpawnGameObject").GetComponent<ScriptTriggerFunction>().stringTrigger = Random.Range(0, 1000).ToString();
    11. } else
    12. {
    13.            GameObject.Find("TriggerSpawnGameObject").GetComponent<ScriptTriggerFunction>().stringTrigger = indexweapon.toString();
    14. }
    15. Destroy(gameObject, 3);
    16.         }
    17.     }
    18. public void GiveMeInfo(int number)
    19. {
    20.     indexWeapon = number;
    21.     onlyTrigger = false;
    22.  
    23. }
    24.  
    and for pass info to prefabTrigger:

    Code (CSharp):
    1. [Command]
    2.     public void CmdSpawnTrigger(int number)
    3.     {
    4.         var go = Instantiate(prefabTrigger);
    5.         go.GetComponent<ScriptGameObjectTrigger>().GiveMeInfo(number);
    6.  
    7.         NetworkServer.Spawn(go);
    8.     }
    9.  
    10.     //CmdSpawnTrigger(your int info to share)
    Now all clients have shared int on inputfield, and all clients call FunctionTocall.
    I dont know if I good explain, i have bad english capacities ;) but with this method I solved a lot of problem with sync vars and make all clients know when something happening and what do when something happend.
    For example, when a client connect, the client spawn prefabTrigger for say all clients new player its connected.
    I hope this helps.
     
    Last edited: May 10, 2017
  5. unidad2pete

    unidad2pete

    Joined:
    Feb 17, 2017
    Posts:
    22
    I can´t edit , change numberToShare to number on line 5 on last script
    the empty gameObject in scene, have networkIdentity and should be spawned by server on start server (Networkserver.spawnObjects())
     
  6. _spacepig_

    _spacepig_

    Joined:
    Jan 18, 2016
    Posts:
    151
    thanks but I actually figured it out