using System.Diagnostics.CodeAnalysis; using System.Linq; using Robust.Shared.Utility; namespace Content.Shared.StationRecords; /// /// Set of station records for a single station. StationRecordsComponent stores these. /// Keyed by the record id, which should be obtained from /// an entity that stores a reference to it. /// A StationRecordKey has both the station entity (use to get the record set) and id (use for this). /// [DataDefinition] public sealed partial class StationRecordSet { [DataField("currentRecordId")] private uint _currentRecordId; /// /// Every key id that has a record(s) stored. /// Presumably this is faster than iterating the dictionary to check if any tables have a key. /// [DataField] public HashSet Keys = new(); /// /// Recently accessed key ids which are used to synchronize them efficiently. /// [DataField] private HashSet _recentlyAccessed = new(); /// /// Dictionary between a record's type and then each record indexed by id. /// [DataField] private Dictionary> _tables = new(); /// /// Gets all records of a specific type stored in the record set. /// /// The type of record to fetch. /// An enumerable object that contains a pair of both a station key, and the record associated with it. public IEnumerable<(uint, T)> GetRecordsOfType() { if (!_tables.ContainsKey(typeof(T))) { yield break; } foreach (var (key, entry) in _tables[typeof(T)]) { if (entry is not T cast) { continue; } _recentlyAccessed.Add(key); yield return (key, cast); } } /// /// Create a new record with an entry. /// Returns an id that can only be used to access the record for this station. /// /// Entry to add. /// Type of the entry that's being added. public uint? AddRecordEntry(T entry) { if (entry == null) return null; var key = _currentRecordId++; AddRecordEntry(key, entry); return key; } /// /// Add an entry into an existing record. /// /// Key id for the record. /// Entry to add. /// Type of the entry that's being added. public void AddRecordEntry(uint key, T entry) { if (entry == null) return; Keys.Add(key); _tables.GetOrNew(typeof(T))[key] = entry; } /// /// Try to get an record entry by type, from this record key. /// /// The record id to get the entries from. /// The entry that is retrieved from the record set. /// The type of entry to search for. /// True if the record exists and was retrieved, false otherwise. public bool TryGetRecordEntry(uint key, [NotNullWhen(true)] out T? entry) { entry = default; if (!Keys.Contains(key) || !_tables.TryGetValue(typeof(T), out var table) || !table.TryGetValue(key, out var entryObject)) { return false; } entry = (T) entryObject; _recentlyAccessed.Add(key); return true; } /// /// Checks if the record associated with this key has an entry of a certain type. /// /// The record key id. /// Type to check. /// True if the entry exists, false otherwise. public bool HasRecordEntry(uint key) { return Keys.Contains(key) && _tables.TryGetValue(typeof(T), out var table) && table.ContainsKey(key); } /// /// Get the recently accessed keys from this record set. /// /// All recently accessed keys from this record set. public IEnumerable GetRecentlyAccessed() { return _recentlyAccessed.ToArray(); } /// /// Clears the recently accessed keys from the set. /// public void ClearRecentlyAccessed() { _recentlyAccessed.Clear(); } /// /// Removes a recently accessed key from the set. /// public void RemoveFromRecentlyAccessed(uint key) { _recentlyAccessed.Remove(key); } /// /// Removes all record entries related to this key from this set. /// /// The key to remove. /// True if successful, false otherwise. public bool RemoveAllRecords(uint key) { if (!Keys.Remove(key)) return false; foreach (var table in _tables.Values) { table.Remove(key); } return true; } }