diff --git a/Content.Server/Access/Systems/AgentIDCardSystem.cs b/Content.Server/Access/Systems/AgentIDCardSystem.cs index d5e9dc357dd..0150eef4d4d 100644 --- a/Content.Server/Access/Systems/AgentIDCardSystem.cs +++ b/Content.Server/Access/Systems/AgentIDCardSystem.cs @@ -102,7 +102,10 @@ private void OnJobIconChanged(EntityUid uid, AgentIDCardComponent comp, AgentIDC _cardSystem.TryChangeJobIcon(uid, jobIcon, idCard); if (TryFindJobProtoFromIcon(jobIcon, out var job)) + { _cardSystem.TryChangeJobDepartment(uid, job, idCard); + _cardSystem.TryChangeJobPrototype(uid, job, idCard); + } } private bool TryFindJobProtoFromIcon(StatusIconPrototype jobIcon, [NotNullWhen(true)] out JobPrototype? job) diff --git a/Content.Server/Access/Systems/IdCardConsoleSystem.cs b/Content.Server/Access/Systems/IdCardConsoleSystem.cs index 07275724a27..efb9bf6e222 100644 --- a/Content.Server/Access/Systems/IdCardConsoleSystem.cs +++ b/Content.Server/Access/Systems/IdCardConsoleSystem.cs @@ -161,6 +161,7 @@ private void TryWriteToTargetId(EntityUid uid, { _idCard.TryChangeJobIcon(targetId, jobIcon, player: player); _idCard.TryChangeJobDepartment(targetId, job); + _idCard.TryChangeJobPrototype(targetId, job); } if (!newAccessList.TrueForAll(x => component.AccessLevels.Contains(x))) diff --git a/Content.Server/Access/Systems/PresetIdCardSystem.cs b/Content.Server/Access/Systems/PresetIdCardSystem.cs index 3e775b9c35d..58facc6e4a9 100644 --- a/Content.Server/Access/Systems/PresetIdCardSystem.cs +++ b/Content.Server/Access/Systems/PresetIdCardSystem.cs @@ -81,6 +81,7 @@ private void SetupIdAccess(EntityUid uid, PresetIdCardComponent id, bool extende _cardSystem.TryChangeJobTitle(uid, job.LocalizedName); _cardSystem.TryChangeJobDepartment(uid, job); + _cardSystem.TryChangeJobPrototype(uid, job); if (_prototypeManager.TryIndex(job.Icon, out var jobIcon)) { diff --git a/Content.Server/CrewManifest/CrewManifestSystem.cs b/Content.Server/CrewManifest/CrewManifestSystem.cs index e7424560159..4adcfcc8266 100644 --- a/Content.Server/CrewManifest/CrewManifestSystem.cs +++ b/Content.Server/CrewManifest/CrewManifestSystem.cs @@ -1,6 +1,7 @@ using System.Linq; using Content.Server.Administration; using Content.Server.EUI; +using Content.Server.Medical.CrewMonitoring; using Content.Server.Station.Components; using Content.Server.Station.Systems; using Content.Server.StationRecords; @@ -34,13 +35,16 @@ public sealed class CrewManifestSystem : EntitySystem /// private readonly Dictionary _cachedEntries = new(); + private CrewManifestEntries? _entries; + private readonly Dictionary> _openEuis = new(); public override void Initialize() { - SubscribeLocalEvent(AfterGeneralRecordCreated); - SubscribeLocalEvent(OnRecordModified); - SubscribeLocalEvent(OnRecordRemoved); + //SubscribeLocalEvent(AfterGeneralRecordCreated); + //SubscribeLocalEvent(OnRecordModified); + //SubscribeLocalEvent(OnRecordRemoved); + SubscribeLocalEvent(OnSensorStatusUpdate); SubscribeLocalEvent(OnRoundRestart); SubscribeNetworkEvent(OnRequestCrewManifest); @@ -60,6 +64,7 @@ private void OnRoundRestart(RoundRestartCleanupEvent ev) _openEuis.Clear(); _cachedEntries.Clear(); + _entries = null; } private void OnRequestCrewManifest(RequestCrewManifestMessage message, EntitySessionEventArgs args) @@ -94,6 +99,39 @@ private void OnRecordRemoved(RecordRemovedEvent ev) UpdateEuis(ev.Key.OriginStation); } + private void OnSensorStatusUpdate(SensorStatusUpdateEvent e) + { + var entries = new CrewManifestEntries(); + + var entriesSort = new List<(JobPrototype? job, CrewManifestEntry entry)>(); + foreach (var recordObject in e.SensorStatus.Values) + { + if (!recordObject.IsAlive) + continue; + + var entry = new CrewManifestEntry(recordObject.Name, recordObject.Job, recordObject.JobIcon, recordObject.JobPrototype!); + + JobPrototype? job = null; + + if (recordObject.JobPrototype is not null) + _prototypeManager.TryIndex(recordObject.JobPrototype, out job); + + entriesSort.Add((job, entry)); + } + + entriesSort.Sort((a, b) => + { + var cmp = JobUIComparer.Instance.Compare(a.job, b.job); + if (cmp != 0) + return cmp; + + return string.Compare(a.entry.Name, b.entry.Name, StringComparison.CurrentCultureIgnoreCase); + }); + + entries.Entries = entriesSort.Select(x => x.entry).ToArray(); + _entries = entries; + } + private void OnBoundUiClose(EntityUid uid, CrewManifestViewerComponent component, BoundUIClosedEvent ev) { if (!Equals(ev.UiKey, component.OwnerKey)) @@ -115,8 +153,7 @@ private void OnBoundUiClose(EntityUid uid, CrewManifestViewerComponent component /// The name and crew manifest entries (unordered) of the station. public (string name, CrewManifestEntries? entries) GetCrewManifest(EntityUid station) { - var valid = _cachedEntries.TryGetValue(station, out var manifest); - return (valid ? MetaData(station).EntityName : string.Empty, valid ? manifest : null); + return (_entries is not null ? MetaData(station).EntityName : string.Empty, _entries); } private void UpdateEuis(EntityUid station) diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs index d7e64ec48fd..e1027f16f11 100644 --- a/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs @@ -39,6 +39,8 @@ public override void Update(float frameTime) return; _updateDiff -= UpdateRate; + Dictionary sensors = []; + var servers = EntityQueryEnumerator(); while (servers.MoveNext(out var id, out var server)) @@ -48,7 +50,12 @@ public override void Update(float frameTime) UpdateTimeout(id); BroadcastSensorStatus(id, server); + + foreach (var sensor in server.SensorStatus) + sensors[sensor.Key] = sensor.Value; } + + RaiseLocalEvent(new SensorStatusUpdateEvent(sensors)); } /// @@ -113,3 +120,5 @@ private void OnDisconnected(EntityUid uid, CrewMonitoringServerComponent compone component.SensorStatus.Clear(); } } + +public sealed record SensorStatusUpdateEvent(Dictionary SensorStatus); diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index 4d60da835d3..4dd55103f16 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -20,7 +20,8 @@ using Robust.Shared.Random; using Robust.Shared.Timing; using System.Numerics; //Frontier modification -using Content.Server.Salvage.Expeditions; // Frontier modification +using Content.Server.Salvage.Expeditions; +using Content.Server.CryoSleep; // Frontier modification namespace Content.Server.Medical.SuitSensors; @@ -34,6 +35,7 @@ public sealed class SuitSensorSystem : EntitySystem [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; // [Dependency] private readonly StationSystem _stationSystem = default!; // Frontier + [Dependency] private readonly CryoSleepSystem _cryo = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; // Frontier [Dependency] private readonly SingletonDeviceNetServerSystem _singletonServerSystem = default!; [Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; @@ -75,6 +77,9 @@ public override void Update(float frameTime) continue; */ + if (sensor.User is not null && _cryo.IsBodyStored(sensor.User.Value)) + continue; + // TODO: This would cause imprecision at different tick rates. sensor.NextUpdate = curTime + sensor.UpdateRate; @@ -329,6 +334,7 @@ public void SetSensor(EntityUid uid, SuitSensorMode mode, EntityUid? userUid = n var userJob = Loc.GetString("suit-sensor-component-unknown-job"); var userJobIcon = "JobIconNoId"; var userJobDepartments = new List(); + var userJobPrototype = ""; var userLocationName = Loc.GetString("suit-sensor-location-unknown"); // Frontier modification if (_idCardSystem.TryFindIdCard(sensor.User.Value, out var card)) @@ -339,6 +345,8 @@ public void SetSensor(EntityUid uid, SuitSensorMode mode, EntityUid? userUid = n userJob = card.Comp.JobTitle; if (card.Comp.JobIcon != null) userJobIcon = card.Comp.JobIcon; + if (card.Comp.JobPrototype is not null) + userJobPrototype = card.Comp.JobPrototype; foreach (var department in card.Comp.JobDepartments) userJobDepartments.Add(Loc.GetString(department)); @@ -361,7 +369,7 @@ public void SetSensor(EntityUid uid, SuitSensorMode mode, EntityUid? userUid = n // finally, form suit sensor status // will additonally check the grid and name if it exists, as well if its expedition - var status = new SuitSensorStatus(GetNetEntity(uid), userName, userJob, userJobIcon, userJobDepartments, userLocationName); + var status = new SuitSensorStatus(GetNetEntity(uid), userName, userJob, userJobIcon, userJobDepartments, userJobPrototype, userLocationName); switch (sensor.Mode) { case SuitSensorMode.SensorBinary: @@ -443,6 +451,7 @@ public NetworkPayload SuitSensorToPacket(SuitSensorStatus status) [SuitSensorConstants.NET_JOB] = status.Job, [SuitSensorConstants.NET_JOB_ICON] = status.JobIcon, [SuitSensorConstants.NET_JOB_DEPARTMENTS] = status.JobDepartments, + [SuitSensorConstants.NET_JOB_PROTOTYPE] = status.JobPrototype, [SuitSensorConstants.NET_IS_ALIVE] = status.IsAlive, [SuitSensorConstants.NET_SUIT_SENSOR_UID] = status.SuitSensorUid, }; @@ -475,6 +484,7 @@ public NetworkPayload SuitSensorToPacket(SuitSensorStatus status) if (!payload.TryGetValue(SuitSensorConstants.NET_JOB, out string? job)) return null; if (!payload.TryGetValue(SuitSensorConstants.NET_JOB_ICON, out string? jobIcon)) return null; if (!payload.TryGetValue(SuitSensorConstants.NET_JOB_DEPARTMENTS, out List? jobDepartments)) return null; + if (!payload.TryGetValue(SuitSensorConstants.NET_JOB_PROTOTYPE, out string? jobPrototype)) return null; if (!payload.TryGetValue(SuitSensorConstants.NET_IS_ALIVE, out bool? isAlive)) return null; if (!payload.TryGetValue(SuitSensorConstants.NET_SUIT_SENSOR_UID, out NetEntity suitSensorUid)) return null; if (!payload.TryGetValue(SuitSensorConstants.NET_LOCATION_NAME, out string? location)) return null; // Frontier modification @@ -484,7 +494,7 @@ public NetworkPayload SuitSensorToPacket(SuitSensorStatus status) payload.TryGetValue(SuitSensorConstants.NET_TOTAL_DAMAGE_THRESHOLD, out int? totalDamageThreshold); payload.TryGetValue(SuitSensorConstants.NET_COORDINATES, out NetCoordinates? coords); - var status = new SuitSensorStatus(suitSensorUid, name, job, jobIcon, jobDepartments, location) + var status = new SuitSensorStatus(suitSensorUid, name, job, jobIcon, jobDepartments, jobPrototype, location) { IsAlive = isAlive.Value, TotalDamage = totalDamage, diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs index 56d4675138a..59d8bbe6a13 100644 --- a/Content.Server/Station/Systems/StationSpawningSystem.cs +++ b/Content.Server/Station/Systems/StationSpawningSystem.cs @@ -311,6 +311,7 @@ public void SetPdaAndIdCardData(EntityUid entity, string characterName, JobProto _cardSystem.TryChangeFullName(cardId, characterName, card); _cardSystem.TryChangeJobTitle(cardId, jobPrototype.LocalizedName, card); + _cardSystem.TryChangeJobPrototype(cardId, jobPrototype, card); if (_prototypeManager.TryIndex(jobPrototype.Icon, out var jobIcon)) { diff --git a/Content.Server/_NF/CryoSleep/CryoSleepSystem.cs b/Content.Server/_NF/CryoSleep/CryoSleepSystem.cs index 1133ebbff84..10759077548 100644 --- a/Content.Server/_NF/CryoSleep/CryoSleepSystem.cs +++ b/Content.Server/_NF/CryoSleep/CryoSleepSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using System.Numerics; using Content.Server.DoAfter; using Content.Server.EUI; @@ -314,6 +315,11 @@ public bool EjectBody(EntityUid pod, CryoSleepComponent? component = null, Entit return true; } + public bool IsBodyStored(EntityUid entity) + { + return _storedBodies.Any(body => body.Value?.Body == entity); + } + private bool IsOccupied(CryoSleepComponent component) { return component.BodyContainer.ContainedEntity != null; diff --git a/Content.Shared/Access/Components/IdCardComponent.cs b/Content.Shared/Access/Components/IdCardComponent.cs index 9459f6c1910..5ce336a6bc0 100644 --- a/Content.Shared/Access/Components/IdCardComponent.cs +++ b/Content.Shared/Access/Components/IdCardComponent.cs @@ -36,6 +36,8 @@ public sealed partial class IdCardComponent : Component [AutoNetworkedField] public List JobDepartments = new(); + public string JobPrototype; + /// /// Determines if accesses from this card should be logged by /// diff --git a/Content.Shared/Access/Systems/SharedIdCardSystem.cs b/Content.Shared/Access/Systems/SharedIdCardSystem.cs index 63f671e894a..33a9b062b78 100644 --- a/Content.Shared/Access/Systems/SharedIdCardSystem.cs +++ b/Content.Shared/Access/Systems/SharedIdCardSystem.cs @@ -156,6 +156,16 @@ public bool TryChangeJobDepartment(EntityUid uid, JobPrototype job, IdCardCompon return true; } + public bool TryChangeJobPrototype(EntityUid entity, JobPrototype job, IdCardComponent? card = null) + { + if (!Resolve(entity, ref card)) + return false; + + card.JobPrototype = job.ID; + + return true; + } + /// /// Attempts to change the full name of a card. /// Returns true/false. diff --git a/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs b/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs index d27dd5d94a2..c158bcd2be9 100644 --- a/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs +++ b/Content.Shared/Medical/SuitSensor/SharedSuitSensor.cs @@ -6,13 +6,14 @@ namespace Content.Shared.Medical.SuitSensor; [Serializable, NetSerializable] public sealed class SuitSensorStatus { - public SuitSensorStatus(NetEntity suitSensorUid, string name, string job, string jobIcon, List jobDepartments, string locationName) + public SuitSensorStatus(NetEntity suitSensorUid, string name, string job, string jobIcon, List jobDepartments, string jobPrototype, string locationName) { SuitSensorUid = suitSensorUid; Name = name; Job = job; JobIcon = jobIcon; JobDepartments = jobDepartments; + JobPrototype = jobPrototype; LocationName = locationName; } @@ -22,6 +23,7 @@ public SuitSensorStatus(NetEntity suitSensorUid, string name, string job, string public string Job; public string JobIcon; public List JobDepartments; + public string JobPrototype; public bool IsAlive; public int? TotalDamage; public int? TotalDamageThreshold; @@ -60,6 +62,7 @@ public static class SuitSensorConstants public const string NET_JOB = "job"; public const string NET_JOB_ICON = "jobIcon"; public const string NET_JOB_DEPARTMENTS = "jobDepartments"; + public const string NET_JOB_PROTOTYPE = "jobPrototype"; public const string NET_IS_ALIVE = "alive"; public const string NET_TOTAL_DAMAGE = "vitals"; public const string NET_TOTAL_DAMAGE_THRESHOLD = "vitalsThreshold";