Search Unity

SyncListInt.Callback for OP_Set Does Not Have Access to New Value

Discussion in 'Multiplayer' started by Zullar, Jul 7, 2015.

  1. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    I have a SyncListInt and when I set a value (not add/remove, but set) the callback is successfully called before the value change (I believe Unity has stated this is intended to give flexibility and access to old values. See issue 706433). However, the only information the SyncListInt callback provides is:
    op=OP_Set
    int index=whatever the index is
    int[ ] array of old values

    I have no way to access the new value that is being set during the SyncListInt.Callback. Am I missing something?
     
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    SyncList callbacks are invoked after the operation has been performed.
     
  3. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Hi Sean, thanks again for the help. I attached code that should replicate the bug.

    I did some more testing to map out the way callbacks are behaving. Some callbacks occur properly after value change, but some callbacks are bugged and occur before value change. This bug only occurs for the localHost, and not the client. Here are my findings.
    SyncListInt.Add occurs after value change (works properly)
    SyncListInt.Remove occurs before value change (bugged)
    SyncListInt.RemoveAt occurs before value change (bugged)
    SyncListInt[index]=value (set) occurs before value change (bugged)
    SyncListInt.Clear occurs after value change (works properly)
    SyncListInt.Insert occurs before value change (bugged)

    Sorry this is kind of long, but it was the only way to illustrate the different callback behaviors.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.Networking; //needed for NetworkBehavior
    5.  
    6. public class TestArray : NetworkBehaviour
    7. {
    8.     private SyncListInt syncListInt = new SyncListInt();
    9.  
    10.     private void Start()
    11.     {
    12.         syncListInt.Callback += MyCallback;
    13.     }
    14.  
    15.     private void Update()
    16.     {
    17.         if(Input.GetKeyDown(KeyCode.H))
    18.         {
    19.             Debug.Log("Key H Pressed");
    20.             syncListInt.Add(11);
    21.             syncListInt.Add(12);
    22.             syncListInt.Add(13);
    23.             syncListInt.Remove(12);
    24.             syncListInt.Remove(13);
    25.             syncListInt.Add(14);
    26.             syncListInt.Add(15);
    27.             syncListInt[0] = 100;
    28.             syncListInt[1] = 200;
    29.             syncListInt[2] = 300;
    30.             syncListInt.Insert(0, 400);
    31.             syncListInt.Insert(0, 500);
    32.             syncListInt.RemoveAt(1);
    33.             syncListInt.RemoveAt(0);
    34.             syncListInt.Clear();
    35.         }
    36.     }
    37.  
    38.     private void MyCallback(SyncListInt.Operation op, int index)
    39.     {
    40.         Debug.Log("MyCallback Called: Op=" + op.ToString() + " Index=" + index + " New Array Length=" + syncListInt.Count);
    41.         for(int i = 0; i < syncListInt.Count; i++)
    42.         {
    43.             Debug.Log("syncListInt[" + i + "]=" + syncListInt[i]);
    44.         }
    45.     }
    46. }
    47.  
    The debug output log:
    Key H Pressed

    //After calling syncListInt.Add(11);
    MyCallback Called: Op=OP_ADD Index=0 New Array Length=1
    syncListInt[0]=11 //works properly, callback has new value

    //After calling syncListInt.Add(12);
    MyCallback Called: Op=OP_ADD Index=0 New Array Length=2
    syncListInt[0]=11
    syncListInt[1]=12 //works properly, callback has new value

    //After calling syncListInt.Add(13);
    MyCallback Called: Op=OP_ADD Index=0 New Array Length=3
    syncListInt[0]=11
    syncListInt[1]=12
    syncListInt[2]=13 //works properly, callback has new value

    //After calling syncListInt.Remove(12);
    MyCallback Called: Op=OP_REMOVE Index=0 New Array Length=3
    syncListInt[0]=11
    syncListInt[1]=12 //The value of 12 should have been removed, but the callback is bugged and occurred before value change.
    syncListInt[2]=13

    //After calling syncListInt.Remove(13);
    MyCallback Called: Op=OP_REMOVE Index=0 New Array Length=2
    syncListInt[0]=11
    //The value of 12 is removed, but only on the subsequent callback
    syncListInt[1]=13 //The value of 13 should have been removed, but the callback is bugged and occurred before value change.

    //After calling syncListInt.Add(14);
    MyCallback Called: Op=OP_ADD Index=0 New Array Length=2
    syncListInt[0]=11
    syncListInt[1]=14 //works properly, callback has new value

    //After calling syncListInt.Add(15);
    MyCallback Called: Op=OP_ADD Index=0 New Array Length=3
    syncListInt[0]=11
    syncListInt[1]=14
    syncListInt[2]=15 //works properly, callback has new value

    //After calling syncListInt[0] = 100;
    MyCallback Called: Op=OP_SET Index=0 New Array Length=3
    syncListInt[0]=11 //The value should be 100, but the callback is bugged and occurred before value change.
    syncListInt[1]=14
    syncListInt[2]=15

    //After calling syncListInt[1] = 200;
    MyCallback Called: Op=OP_SET Index=1 New Array Length=3
    syncListInt[0]=100 //The value is updated to 100, but only on the subsequent callback
    syncListInt[1]=14 //The value should be 200, but the callback is bugged and occurred before value change.
    syncListInt[2]=15

    //After calling syncListInt[2] = 300;
    MyCallback Called: Op=OP_SET Index=2 New Array Length=3
    syncListInt[0]=100
    syncListInt[1]=200 //The value is updated to 200, but only on the subsequent callback
    syncListInt[2]=15 //The value should be 300, but the callback is bugged and occurred before value change.

    //After calling syncListInt.Insert(0, 400);
    MyCallback Called: Op=OP_INSERT Index=0 New Array Length=3
    //a value of 400 should have been inserted here, and list length should be 4, but the callback is bugged and occurred before value change.
    syncListInt[0]=100
    syncListInt[1]=200
    syncListInt[2]=300 //The value is updated to 300, but only on the subsequent callback

    //After calling syncListInt.Insert(0, 500);
    MyCallback Called: Op=OP_INSERT Index=0 New Array Length=4
    //a value of 500 should have been inserted here, and list length should be 5, but the callback is bugged and occurred before value change.
    syncListInt[0]=400 //The value of 400 is inserted, but only on the subsequent callback
    syncListInt[1]=100
    syncListInt[2]=200
    syncListInt[3]=300

    //After calling syncListInt.RemoveAt(1);
    MyCallback Called: Op=OP_REMOVEAT Index=1 New Array Length=5
    syncListInt[0]=500
    syncListInt[1]=400 //This should have been removed, but the callback is bugged and occurred before value change.
    syncListInt[2]=100
    syncListInt[3]=200
    syncListInt[4]=300

    //After calling syncListInt.RemoveAt(0);
    MyCallback Called: Op=OP_REMOVEAT Index=0 New Array Length=4
    syncListInt[0]=500 //This should have been removed, but the callback is bugged and occurred before value change.
    //The value of 400 is removed, but only on the subsequent callback
    syncListInt[1]=100
    syncListInt[2]=200
    syncListInt[3]=300

    //After calling syncListInt.Clear();
    MyCallback Called: Op=OP_CLEAR Index=0 New Array Length=0 //works properly, everything removed
     
    Last edited: Jul 7, 2015
  4. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    bug 710321 filed on this.
     
    GKiernozek likes this.
  5. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    Thanks Sean!
     
  6. Morgenstern_1

    Morgenstern_1

    Joined:
    Jul 1, 2013
    Posts:
    34
    Can anyone tell me what version of Unity this bug was fixed in? The bug tracker doesn't seem to have this information (which would be really useful!). We're running 5.1.2f1 and it's still happening for us.
     
  7. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    verified as fixed in 5.2.0b2
     
    GKiernozek likes this.
  8. Morgenstern_1

    Morgenstern_1

    Joined:
    Jul 1, 2013
    Posts:
    34
    Thank you Seanr.
     
  9. shoo

    shoo

    Joined:
    Nov 19, 2012
    Posts:
    67
    I have 5.4.0b16 but its same bug for me. When OP_ADD it works good, but when OP_SET, my SyncListInt having an old one value.
     
  10. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,191
    I have tested the above script and modified it to get better control for testing, see below. However, it synchronize from host-client to remote-client but not the other way around. I have tested trying to process from server but to no avail. I have also tested with a different script but given the conversation in this post i guess this should work.

    I would really appreciate help here so i can have a solution that synchronize from both sides. @seanr

    Here is my modified script:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.Networking;
    4. using UnityEngine.UI;
    5.  
    6. public class UNET_TestSyncListInt : NetworkBehaviour {
    7.  
    8.     public SyncListInt syncListInt = new SyncListInt();
    9.     private GameObject txtX;
    10.     public Text chatBox;
    11.     private int before;
    12.     private int after;
    13.  
    14.     private void Start()
    15.     {
    16.         GameObject.Find ("Button1").GetComponent<Button>().onClick.AddListener(delegate { Btn_x();});
    17.         GameObject.Find ("Button2").GetComponent<Button>().onClick.AddListener(delegate { Btn_Clear_x();});
    18.         GameObject.Find ("Button3").GetComponent<Button>().onClick.AddListener(delegate { Btn_CheckSize();});
    19.  
    20.         txtX = GameObject.Find ("TextX");
    21.         syncListInt.Callback += MyCallback;
    22.  
    23.     }
    24.  
    25.     private void Btn_x()
    26.     {
    27.         txtX.GetComponent<Text> ().text = "isServer - Btn_x Pressed";
    28.         syncListInt.Add (11);
    29.         syncListInt.Add (12);
    30.         syncListInt.Add (13);
    31.         syncListInt.Remove (12);
    32.         syncListInt.Remove (13);
    33.         syncListInt.Add (14);
    34.         syncListInt.Add (15);
    35.     }
    36.  
    37.     private void Btn_Clear_x() {
    38.        
    39.         syncListInt.Clear();
    40.  
    41.     }
    42.  
    43.     private void Btn_CheckSize() {
    44.  
    45.         txtX.GetComponent<Text> ().text = "Size: " + syncListInt.Count;
    46.  
    47.     }
    48.  
    49.     private void MyCallback(SyncListInt.Operation op, int index)
    50.     {
    51.  
    52.         string jjj = op.ToString ();
    53.  
    54.         if (jjj == "OP_CLEAR") {
    55.             after = syncListInt.Count;
    56.             txtX.GetComponent<Text> ().text = "OP_CLEAR Before: " + before + " | After: " + after;
    57.         } else if (jjj == "OP_ADD") {
    58.             before = syncListInt.Count;
    59.             txtX.GetComponent<Text> ().text = "OP_ADD";
    60.         }
    61.  
    62.  
    63.         Debug.Log("MyCallback Called: Op=" + op.ToString() + " Index=" + index + " New Array Length=" + syncListInt.Count);
    64.         string str = "MyCallback Called: Op=" + op.ToString () + " Index=" + index + " New Array Length=" + syncListInt.Count;
    65.         chatBox.text += str + "\n";
    66.         for(int i = 0; i < syncListInt.Count; i++)
    67.         {
    68.             Debug.Log("syncListInt[" + i + "]=" + syncListInt[i]);
    69.         }
    70.     }
    71. }
     
  11. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    SyncVars and SyncLists only sync from server --> client not the other way around.

    Unfortunately, if you want to send data from Client --> Server you have to use network messages or [Command]s.
     
  12. pKallv

    pKallv

    Joined:
    Mar 2, 2014
    Posts:
    1,191
    @Zullar I am using [command] and the Host-Client => works with this code but still the Remote-Client => Host-Client sync does not work.

    What do I do wrong in this code as I am not able to update and sync correctly?

    Anyone?

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.UI;
    3. using UnityEngine.Networking;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6.  
    7. public class UNET_SyncList_2 : NetworkBehaviour {
    8.  
    9.     public SyncListString myList = new SyncListString();
    10.     private GameObject chatBox;
    11.     private GameObject myText;
    12.     private int before;
    13.     private int after;
    14.  
    15.     void Start () {
    16. //        print ("Start");
    17.  
    18.         chatBox.GetComponent<Text>().text += "\n";
    19.  
    20.         if (isLocalPlayer) {
    21.             Cmd_AddOnServer ();
    22.         }
    23.     }
    24.  
    25.     [Command]
    26.     public void Cmd_AddOnServer () {
    27.         myText.GetComponent<Text> ().text = "Command";
    28.  
    29.         myList.Add ("LETTER A");
    30.         myList.Add ("LETTER B");
    31.         myList.Add ("LETTER C");
    32.     }
    33.  
    34.     public override void OnStartClient() {
    35. //        print ("OnStartClient");
    36.  
    37.         chatBox = GameObject.Find ("ChatBox");
    38.         myText = GameObject.Find ("TextX");
    39.         myList.Callback += MyCallback;
    40.         GameObject.Find ("Button1").GetComponent<Button>().onClick.AddListener(delegate { Btn_Add();});
    41.     }
    42.  
    43.     public void Btn_Add () {
    44. //        if (isLocalPlayer) {
    45. //            print ("isLocalPlayer");
    46. //            myText.GetComponent<Text> ().text = "isLocalPlayer";
    47. //            print ("Btn_Add");
    48. //            Cmd_AddOnButton ();
    49. //        } else {
    50. //            print ("is NOT LocalPlayer");
    51. //            myText.GetComponent<Text> ().text = "is NOT LocalPlayer";
    52. //            print ("Btn_Add");
    53. //            Cmd_AddOnButton ();
    54. //        }
    55.  
    56.         // no isLocalPlayer = Host-Client is able to sync to Remote-Player
    57.         print ("Btn_Add");
    58.         Cmd_AddOnButton ();
    59.          
    60. //        }
    61.     }
    62.  
    63.     [Command]
    64.     public void Cmd_AddOnButton () {
    65.         print ("Cmd_AddOnButton");
    66.         myList.Add ("NUMBER 1");
    67.         myList.Add ("NUMBER 2");
    68.         myList.Add ("NUMBER 3");
    69.     }
    70.  
    71.     private void MyCallback(SyncListInt.Operation op, int index) {
    72.         string str = "Op=" + op.ToString () + " Index=" + myList[index] + " New Array Length=" + myList.Count;
    73.         chatBox.GetComponent<Text>().text += str + "\n";
    74.     }
    75. }
    76.  
     
  13. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    SyncVars and SyncLists only work from host/server --> remote client. They do not sync from remote client -> host/server.

    I do not see you subscribing to MyCallback so maybe that is the reason you are not seeing it?

    Can you be more specific what is not working?