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;
}
}