Search Unity

[Mirror] Setting initial values on client connect for SyncDictionary / SyncList

Discussion in 'Scripting' started by veggiesama, Apr 7, 2019.

  1. veggiesama


    Jul 11, 2017
    As I understand it, SyncDictionaries (Mirror-only) are basically fancy SyncLists (present in UNET). So I hope this general forum can still provide an answer.

    In the Mirror documentation, it says: "SyncDictionaries work much like SyncLists: when you make a change on the server the change is propagated to all clients and the Callback is called."

    Under SyncLists, the documentation says, "You can also detect when a synclist changes in the client or server. This is useful for refreshing your character when you add equipment or determining when you need to update your database. Subscribe to the Callback event typically during Start, OnClientStart or OnServerStart for that. Note that by the time you subscribe, the list will already be initialized, so you will not get a call for the initial data, only updates."

    OK--the SyncList will sync for future updates, but for the initial data I'm on my own. Right?

    My question: What is the right way to initialize SyncList/SyncDictionary values for newly connecting clients?

    My situation: I have a SyncDictionary<int slot, GameObject player>. When the server starts, a game controller object builds 4 unassigned player objects and puts them into the dictionary. Players are assigned one of these objects. Your slot determines where your UI healthbar appears on screen. Anyway, when a new client connects, this SyncDictionary has 0 items in it. I want it to have the server's 4. I'm not sure how to force the server to update a new client with those initial values.
    Last edited: Apr 7, 2019
  2. veggiesama


    Jul 11, 2017
    So, I switched from using SyncDictionary to a SyncList, but I'm having the same issue where initial values aren't syncing on client join.

    I tried writing an RPC call to iterate through the server's list and add each entry to the client's list, but I got an error. SyncList can only be modified on the server side.

    Next things I want to try:
    1. Switch from GameObject to int. Even though the documentation indicates GameObjects are sync-able, maybe that's the issue. I could set a Player ID SyncVar and try the SyncList again to order it.
    2. I saw this suggestion somewhere else: use a "server list" and a "local list." Whenever the server list is updated, RPC the update to the client's local list. This seems horribly redundant.
    3. Is there some way to force an update? I've tried using Dirty() to force the sync to trigger but couldn't figure it out.
  3. goldbug


    Oct 12, 2011
    When the object is spawned the syncdictionaries will be populated with whatever the server has at the time.

    If you want to do something with the initial value, just do it in your OnStartClient(), for example:

    Code (CSharp):
    1. using UnityEngine;
    2. using Mirror;
    4. public class ExamplePlayer : NetworkBehaviour
    5. {
    6.     public class SyncDictionaryStringItem : SyncDictionary<string, Item> {}
    8.     public struct Item
    9.     {
    10.         public string name;
    11.         public int hitPoints;
    12.         public int durability;
    13.     }
    15.     public SyncDictionaryStringItem Equipment = new SyncDictionaryStringItem();
    17.     public void OnStartServer()
    18.     {
    19.         Equipment.Add("head", new Item { name = "Helmet", hitPoints = 10, durability = 20 });
    20.         Equipment.Add("body", new Item { name = "Epic Armor", hitPoints = 50, durability = 50 });
    21.         Equipment.Add("feet", new Item { name = "Sneakers", hitPoints = 3, durability = 40 });
    22.         Equipment.Add("hands", new Item { name = "Sword", hitPoints = 30, durability = 15 });
    23.     }
    25.     private void OnStartClient()
    26.     {
    27.         // Equipment is already populated with anything the server set up
    28.         // but we can subscribe to the callback in case it is updated later on
    29.         Equipment.Callback += OnEquipmentChange;
    31.         InitEquipment();
    32.     }
    34.     private void OnEquipmentChange(SyncDictionaryStringItem.Operation op, string key, Item item)
    35.     {
    36.         // equipment changed,  perhaps update the gameobject
    37.         Debug.Log(op + " - " + key);
    38.     }
    40.    private void InitEquipment()
    41.    {
    42.        // do whatever you want here with the initial equipment,  the syncdictionary already
    43.        // contains the initial values.
    44.        // for example,  build your character model and attach all equipment mesh
    46.        // I typically call a "RefreshEquipment()"  function,  
    47.        // and I also call RefreshEquipment() in the callback
    48.    }
    49. }
    See the InitEquipment() function? do whatever you want there with the initial values.
    Last edited: Apr 10, 2019