using System.Collections.Frozen; using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Content.Shared.Guidebook; /// /// Used by GuidebookDataSystem to hold data extracted from prototype values, /// both for storage and for network transmission. /// [Serializable, NetSerializable] [DataDefinition] public sealed partial class GuidebookData { /// /// Total number of data values stored. /// [DataField] public int Count { get; private set; } /// /// The data extracted by the system. /// /// /// Structured as PrototypeName, ComponentName, FieldName, Value /// [DataField] public Dictionary>> Data = []; /// /// The data extracted by the system, converted to a FrozenDictionary for faster lookup. /// public FrozenDictionary>> FrozenData; /// /// Has the data been converted to a FrozenDictionary for faster lookup? /// This should only be done on clients, as FrozenDictionary isn't serializable. /// public bool IsFrozen; /// /// Adds a new value using the given identifiers. /// public void AddData(string prototype, string component, string field, object? value) { if (IsFrozen) throw new InvalidOperationException("Attempted to add data to GuidebookData while it is frozen!"); Data.GetOrNew(prototype).GetOrNew(component).Add(field, value); Count++; } /// /// Attempts to retrieve a value using the given identifiers. /// /// true if the value was retrieved, otherwise false public bool TryGetValue(string prototype, string component, string field, out object? value) { if (!IsFrozen) throw new InvalidOperationException("Freeze the GuidebookData before calling TryGetValue!"); // Look in frozen dictionary if (FrozenData.TryGetValue(prototype, out var p) && p.TryGetValue(component, out var c) && c.TryGetValue(field, out value)) { return true; } value = null; return false; } /// /// Deletes all data. /// public void Clear() { Data.Clear(); Count = 0; IsFrozen = false; } public void Freeze() { var protos = new Dictionary>>(); foreach (var (protoId, protoData) in Data) { var comps = new Dictionary>(); foreach (var (compId, compData) in protoData) { comps.Add(compId, FrozenDictionary.ToFrozenDictionary(compData)); } protos.Add(protoId, FrozenDictionary.ToFrozenDictionary(comps)); } FrozenData = FrozenDictionary.ToFrozenDictionary(protos); Data.Clear(); IsFrozen = true; } }