A SyncDictionary is an associative array containing an unordered list of key, value pairs. Keys and values can be any supported mirror type. By default we use .Net Dictionary which may impose additional constraints on the keys and values.
SyncDictionary works much like SyncLists: when you make a change on the server the change is propagated to all clients and the appropriate Actions are invoked. Only deltas are transmitted.
Usage
SyncDictionary must be declared readonly and initialized in the constructor.
Note that by the time you wire up the Action handlers, the dictionary will already be initialized, so they will not get invoked for the initial data, only updates.
Simple Example
usingSystem.Collections.Generic;usingUnityEngine;usingMirror;publicenumSlots:byte { head, body, feet, hands }publicstructItem{publicstring name;publicint hitPoints;publicint durability;publicItem(string name,int hitPoints,int durability) {this.name= name;this.hitPoints= hitPoints;this.durability= durability; }publicoverridestringToString() {return$"name={name} hitPoints={hitPoints} durability={durability}"; }}publicclassSyncDictionaryExample:NetworkBehaviour{publicreadonlySyncDictionary<Slots,Item> Equipment =newSyncDictionary<Slots,Item>();publicoverridevoidOnStartServer() {Equipment[Slots.head] =newItem("Helmet",10,20);Equipment[Slots.body] =newItem("Epic Armor",50,50);Equipment[Slots.feet] =newItem("Sneakers",3,40);Equipment[Slots.hands] =newItem("Sword",30,15); }publicoverridevoidOnStartClient() { // Add handlers for SyncDictionary ActionsEquipment.OnAdd+= OnItemAdded;Equipment.OnSet+= OnItemChanged;Equipment.OnRemove+= OnItemRemoved;Equipment.OnClear+= OnDictionaryCleared; // OnChange is a catch-all event that is called for any change // to the dictionary. It is called after the specific events above. // Strongly recommended to use the specific events above instead!Equipment.OnChange+= OnDictionaryChanged; // Dictionary is populated before handlers are wired up so we // need to manually invoke OnAdd for each element.foreach (Slots key inEquipment.Keys)Equipment.OnAdd.Invoke(key); }publicoverridevoidOnStopClient() { // Remove handlers when client stopsEquipment.OnAdd-= OnItemAdded;Equipment.OnSet-= OnItemChanged;Equipment.OnRemove-= OnItemRemoved;Equipment.OnClear-= OnDictionaryCleared;Equipment.OnChange-= OnDictionaryChanged; }voidOnItemAdded(Slots key) {Debug.Log($"Element added {key} {Equipment[key]}"); }voidOnItemChanged(Slots key,Item oldValue) {Debug.Log($"Element changed {key} from {oldValue} to {Equipment[key]}"); }voidOnItemRemoved(Slots key,Item oldValue) {Debug.Log($"Element removed {key} {oldValue}"); }voidOnDictionaryCleared() { // OnDictionaryCleared is called before the dictionary is actually cleared // so we can iterate the dictionary to get the elements if needed.foreach (KeyValuePair<Slots,Item> kvp in Equipment)Debug.Log($"Element cleared {kvp.Key} {kvp.Value}"); } // OnDictionaryChanged is a catch-all event that is called for any change // to the dictionary. It is called after the specific events above. // // NOTE: It's strongly recommended to use the specific events above instead! // // For OP_ADD, the value param is the NEW entry. // For OP_SET, the value param is the OLD entry. // For OP_REMOVE, the value param is the OLD entry. // For OP_CLEAR, the value param is null / default.voidOnDictionaryChanged(SyncDictionary<Slots,Item>.Operation op,Slots key,Item value) {switch (op) {caseSyncDictionary<Slots,Item>.Operation.OP_ADD: // value is the new entryDebug.Log($"Element added {key} {value}");break;caseSyncDictionary<Slots,Item>.Operation.OP_SET: // value is the old entryDebug.Log($"Element set {key} from {value} to {Equipment[key]}");break;caseSyncDictionary<Slots,Item>.Operation.OP_REMOVE: // value is the old entryDebug.Log($"Element removed {key} {value}");break;caseSyncDictionary<Slots,Item>.Operation.OP_CLEAR: // value is null / default // we can iterate the dictionary to get the elements if needed.foreach (KeyValuePair<Slots,Item> kvp in Equipment)Debug.Log($"Element cleared {kvp.Key} {kvp.Value}");break; } }}
By default, SyncDictionary uses a Dictionary to store it's data. If you want to use a different IDictionary implementation such as SortedList or SortedDictionary, then use SyncIDictionary and pass the dictionary instance you want it to use. For example: