using System.Diagnostics.CodeAnalysis; using Content.Shared.Random.Helpers; using Content.Shared.StationRecords.Components; using Content.Shared.StationRecords.Events; using JetBrains.Annotations; using Robust.Shared.Random; namespace Content.Shared.StationRecords.Systems; public sealed partial class StationRecordsSystem { /// /// Set the station records key for an id/pda. /// [PublicAPI] public void SetIdKey(EntityUid? uid, StationRecordKey key) { if (uid is not {} idUid) return; var keyStorageEntity = idUid; if (_pdaQuery.TryComp(idUid, out var pda) && pda.ContainedId is {} id) { keyStorageEntity = id; } _keyStorage.AssignKey(keyStorageEntity, key); } /// /// Removes a record from this station. /// /// The station and key to remove. /// Station records component. /// True if the record was removed, false otherwise. [PublicAPI] public bool RemoveRecord(StationRecordKey key, StationRecordsComponent? records = null) { if (!_recordsQuery.Resolve(key.OriginStation, ref records)) return false; if (!records.Records.RemoveAllRecords(key.Id)) return false; var ev = new RecordRemovedEvent(key); RaiseLocalEvent(ref ev); Dirty(key.OriginStation, records); return true; } /// /// Gets a random record from the station's record entries. /// /// The EntityId of the station from which you want to get the record. /// The resulting entry. /// An optional entity to use as a seed (see remarks). /// Type to get from the record set. /// True if a record was obtained. False otherwise. /// should be used where possible with predicted randomness to prevent repeated values within a tick. [PublicAPI] public bool TryGetRandomRecord(Entity ent, [NotNullWhen(true)] out T? entry, EntityUid? seedEntity = null) where T : StationRecord { entry = default; if (!_recordsQuery.Resolve(ent.Owner, ref ent.Comp)) return false; if (ent.Comp.Records.Keys.Count == 0) return false; var random = SharedRandomExtensions.PredictedRandom(_timing, GetNetEntity(seedEntity ?? ent.Owner)); var key = random.Pick(ent.Comp.Records.Keys); return ent.Comp.Records.TryGetRecordEntry(key, out entry); } /// /// Get the name for a record, or an empty string if it has no record. /// [PublicAPI] public string RecordName(StationRecordKey key) { return !TryGetRecord(key, out var record) ? string.Empty : record.Name; } /// /// Adds a new record entry to a station's record set. /// /// The station to add the record to. /// The record to add. /// The type of record to add. [PublicAPI] public StationRecordKey AddRecordEntry(Entity station, T record) where T : StationRecord { if (!_recordsQuery.Resolve(station, ref station.Comp)) return StationRecordKey.Invalid; var id = station.Comp.Records.AddRecordEntry(record); Dirty(station); return id == null ? StationRecordKey.Invalid : new StationRecordKey(id.Value, station); } /// /// Adds a record to an existing entry. /// /// The station and id of the existing entry. /// The record to add. /// Station records component. /// The type of record to add. [PublicAPI] public void AddRecordEntry(StationRecordKey key, T record, StationRecordsComponent? records = null) where T : StationRecord { if (!_recordsQuery.Resolve(key.OriginStation, ref records)) return; records.Records.AddRecordEntry(key.Id, record); Dirty(key.OriginStation, records); } /// /// Synchronizes a station's records with any systems that need it. /// /// The station to synchronize any recently accessed records with. [PublicAPI] public void Synchronize(Entity station) { if (!_recordsQuery.Resolve(station, ref station.Comp)) return; foreach (var key in station.Comp.Records.GetRecentlyAccessed()) { var ev = new RecordModifiedEvent(new StationRecordKey(key, station)); RaiseLocalEvent(ref ev); } station.Comp.Records.ClearRecentlyAccessed(); Dirty(station); } /// /// Synchronizes a single record's entries for a station. /// /// The station and id of the record /// Station records component. [PublicAPI] public void Synchronize(StationRecordKey key, StationRecordsComponent? records = null) { if (!_recordsQuery.Resolve(key.OriginStation, ref records)) return; var ev = new RecordModifiedEvent(key); RaiseLocalEvent(ref ev); records.Records.RemoveFromRecentlyAccessed(key.Id); Dirty(key.OriginStation, records); } /// /// Try to get a record from this station's record entries, /// from the provided station record key. Will always return /// null if the key does not match the station. /// /// Station and key to try and index from the record set. /// The resulting entry. /// Station record component. /// Type to get from the record set. /// True if the record was obtained, false otherwise. Always false on client. [PublicAPI] public bool TryGetRecord(StationRecordKey key, [NotNullWhen(true)] out T? entry, StationRecordsComponent? records = null) where T : StationRecord { entry = null; if (!_recordsQuery.Resolve(key.OriginStation, ref records)) return false; return records.Records.TryGetRecordEntry(key.Id, out entry); } /// /// Gets all records of a specific type from a station. /// /// The station to get the records from. /// Type of record to fetch /// Enumerable of pairs with a station record key, and the entry in question of type T. Always empty on client. [PublicAPI] public IEnumerable<(uint, T)> GetRecordsOfType(Entity station) { if (!_recordsQuery.Resolve(station, ref station.Comp)) return Array.Empty<(uint, T)>(); return station.Comp.Records.GetRecordsOfType(); } /// /// Returns an id if a record with the same name exists. /// /// /// Linear search so O(n) time complexity. /// /// Returns a station record id. Always null on client. [PublicAPI] public uint? GetRecordByName(Entity station, string name) { if (!_recordsQuery.Resolve(station, ref station.Comp, false)) return null; foreach (var (id, record) in GetRecordsOfType(station)) { if (record.Name == name) return id; } return null; } }