Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Third Party Unity - Mirror : Using SyncDictionary

Discussion in 'Multiplayer' started by Clashman, Nov 2, 2022.

  1. Clashman

    Clashman

    Joined:
    Feb 18, 2019
    Posts:
    53
    I am using Unity with Mirror Networking and I have a SyncDictionary but I can't fill it in client side even if I send a command. Do someone can help me please ?

    Thanks a lot for answers !

    The SyncDictionary and a callback method :

    Code (CSharp):
    1. public class PlayerEquipmentManager : NetworkBehaviour
    2. {
    3.    public SyncDictionary<string, int> playersMasks = new SyncDictionary<string, int>();
    4.  
    5.    public void OnAddMask(SyncDictionary<string, int>.Operation op, string key, int value)
    6.    {
    7.       if(op == SyncIDictionary<string, int>.Operation.OP_ADD)
    8.       {
    9.          Debug.Log("key : " + key + "\tvalue : " + value.ToString());
    10.       }
    11.    }
    The method for adding entry in my SyncDictionary :

    Code (CSharp):
    1. public class PlayerBehaviour : NetworkBehaviour
    2. {
    3.    [Command]
    4.    public void AddPlayerMasks(int maskID)
    5.    {
    6.       PlayerEquipmentManager equipmentManager = GameObject.Find("PlayerEquipmentManager").GetComponent<PlayerEquipmentManager>();
    7.       string username = PlayerPrefs.GetString("username");
    8.       if (equipmentManager.playersMasks.ContainsKey(username))
    9.       {
    10.          equipmentManager.playersMasks[username] = maskID;
    11.       }
    12.       else
    13.       {
    14.          equipmentManager.playersMasks.Add(username, maskID);
    15.       }
    16.       equipmentManager.playersMasks.Callback += equipmentManager.OnAddMask;
    17.    }
     
  2. Punfish

    Punfish

    Joined:
    Dec 7, 2014
    Posts:
    404
    Iirc server cannot receive callbacks on syncvar, dictionary, ect changes. You're listening for a callback on the server so that's possibly one issue.

    Second, you're subscribing to the callback AFTER setting data which means it won't occur until after the next entry is added.

    Last, it's wasteful to check contains first, just assign the value using xyz[ABC] = blah.
     
  3. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    Hi @Clashman ! If you want to receive notifications on the client for when the Dictionary is changed on the server, you need to subscribe to the callback on the client, not on the server. You can see how to do it in the OnStartClient method of the documentation.

    Also remember that the command is called by the client but executed on the server, so you probably don't want to use PlayerPrefs to access the username as the server won't have that information. You could instead send it as a parameter to the command. Does this solve your issue?
     
  4. Clashman

    Clashman

    Joined:
    Feb 18, 2019
    Posts:
    53
    Thanks, I fixed all things. I moved the callback subscription but out of my command but it still doesn't work.
    I'm not sure about your first point because on host side, I can receive the callback but not on client side. It's as if the command was not called.
     
  5. Clashman

    Clashman

    Joined:
    Feb 18, 2019
    Posts:
    53
    Move the callback subscription changed nothing. It's as if the command was not called.
     
  6. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    Can you show us the code that's calling the command? IIRC You should put in your player's class
     
  7. Clashman

    Clashman

    Joined:
    Feb 18, 2019
    Posts:
    53
    I call the button when I'm pushing a button in canvas dedicated to customize my character. The script is attached to the canvas.

    Code (CSharp):
    1.    public void ValidateChoosenMask()
    2.    {
    3.       PlayerEquipmentManager equipmentManager = GameObject.FindGameObjectWithTag("PlayerEquipmentManager").GetComponent<PlayerEquipmentManager>();
    4.       equipmentManager.SetMasksList(masks);
    5.       PlayerBehaviour playerBehaviour = player.GetComponent<PlayerBehaviour>();
    6.       playerBehaviour.AddPlayerMasks(maskIdx); //calling the command
    7. }
     
  8. RikuTheFuffs-U

    RikuTheFuffs-U

    Unity Technologies

    Joined:
    Feb 20, 2020
    Posts:
    440
    I think the issue in this case is that you're trying the command from the Canvas and not the player object itself. Try doing:

    Code (CSharp):
    1. public void ValidateChoosenMask()
    2.    {
    3.        //the rest of your code here
    4.       playerBehaviour.OnClientAddPlayerMask(maskIdx); //call the client method
    5. }
    6.  
    Code (CSharp):
    1. public class PlayerBehaviour : NetworkBehaviour
    2. {
    3.    public void OnClientAddPlayerMask(int maskID)
    4.    {
    5.          AddPlayerMasks(maskID); //call the command from the player
    6.    }
    7.  
    8.    [Command]
    9.    void AddPlayerMasks(int maskID)
    10.    {
    11.         //your code here
    12.    }
    13. }
    For clarity I'd also rename AddPlayerMasks to CmdAddPlayerMasks , to signal that it's a command andcan't be called directly outside of the player class
     
  9. Clashman

    Clashman

    Joined:
    Feb 18, 2019
    Posts:
    53
    It' doesn't work.
     
  10. Punfish

    Punfish

    Joined:
    Dec 7, 2014
    Posts:
    404
    How you're adding it should be okay. But how do you know with certainty it's not being added?
     
  11. Clashman

    Clashman

    Joined:
    Feb 18, 2019
    Posts:
    53
    Good question. I didn't mention it. When I search the key in the dictionary, it's not found.
    I got an error message :
    Code (CSharp):
    1. KeyNotFoundException: The given key 'client' was not present in the dictionary.
    Moreover, on host side, when I filled the dictionary, the callback function logged the objects.
    It didn't on client side.
     
  12. Punfish

    Punfish

    Joined:
    Dec 7, 2014
    Posts:
    404
    The callback will only occur if you subscribe to it client side. Try subscribing in Awake. If you don't get the callback then and the data is populating on host try a simple syncvar. If the syncvar works I'd say it's possibly a bug.
     
  13. Clashman

    Clashman

    Joined:
    Feb 18, 2019
    Posts:
    53
    I tried subscribing in awake and I can see when the host add something in the syncdictionary but I still have the error messages when I search for the added from client side.
    I have other variables using syncvar and they work well so maybe it's a bug.
     
  14. Punfish

    Punfish

    Joined:
    Dec 7, 2014
    Posts:
    404
    The error could occur if you are searching before the data arrives over the network. But if you aren't getting the callback and the data NEVER arrives, and with other syncvars working I'd say chances of it being a bug are plausible.