From e560f0305dbe81e1332437b1e36e1ab669ce11db Mon Sep 17 00:00:00 2001 From: Graham Date: Fri, 20 Mar 2026 20:43:48 -0500 Subject: [PATCH 1/2] Add borgs and station AI to crew manifest --- .../CrewManifest/CrewManifestSystem.cs | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/Content.Server/CrewManifest/CrewManifestSystem.cs b/Content.Server/CrewManifest/CrewManifestSystem.cs index 08bf7b53f1c..dc74c5e6db9 100644 --- a/Content.Server/CrewManifest/CrewManifestSystem.cs +++ b/Content.Server/CrewManifest/CrewManifestSystem.cs @@ -16,6 +16,7 @@ using System.Linq; using Content.Server.Administration; using Content.Server.EUI; +using Content.Server.Silicons.StationAi; using Content.Server.Station.Systems; using Content.Server.StationRecords; using Content.Server.StationRecords.Systems; @@ -24,6 +25,8 @@ using Content.Shared.CrewManifest; using Content.Shared.GameTicking; using Content.Shared.Roles; +using Content.Shared.Silicons.Borgs.Components; +using Content.Shared.Silicons.StationAi; using Content.Shared.Station.Components; using Content.Shared.StationRecords; using Robust.Shared.Configuration; @@ -37,6 +40,7 @@ public sealed class CrewManifestSystem : EntitySystem { [Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly StationRecordsSystem _recordsSystem = default!; + [Dependency] private readonly StationAiSystem _stationAiSystem = default!; [Dependency] private readonly EuiManager _euiManager = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -129,6 +133,8 @@ 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) { + BuildCrewManifest(station); + var valid = _cachedEntries.TryGetValue(station, out var manifest); return (valid ? MetaData(station).EntityName : string.Empty, valid ? manifest : null); } @@ -239,6 +245,8 @@ private void BuildCrewManifest(EntityUid station) var iter = _recordsSystem.GetRecordsOfType(station); var entries = new CrewManifestEntries(); + var borgJob = _prototypeManager.Index("Borg"); + var stationAiJob = _prototypeManager.Index("StationAi"); var entriesSort = new List<(JobPrototype? job, CrewManifestEntry entry)>(); foreach (var recordObject in iter) @@ -250,6 +258,30 @@ private void BuildCrewManifest(EntityUid station) entriesSort.Add((job, entry)); } + var borgQuery = EntityQueryEnumerator(); + while (borgQuery.MoveNext(out var uid, out var chassis)) + { + if (_stationSystem.GetOwningStation(uid) != station) + continue; + + if (chassis.BrainEntity == null) + continue; + + entriesSort.Add((borgJob, BuildSiliconEntry(uid, borgJob))); + } + + var aiQuery = EntityQueryEnumerator(); + while (aiQuery.MoveNext(out var uid, out var core)) + { + if (_stationSystem.GetOwningStation(uid) != station) + continue; + + if (!_stationAiSystem.TryGetHeld((uid, core), out var held)) + continue; + + entriesSort.Add((stationAiJob, BuildSiliconEntry(held, stationAiJob))); + } + entriesSort.Sort((a, b) => { var cmp = JobUIComparer.Instance.Compare(a.job, b.job); @@ -262,6 +294,15 @@ private void BuildCrewManifest(EntityUid station) entries.Entries = entriesSort.Select(x => x.entry).ToArray(); _cachedEntries[station] = entries; } + + private CrewManifestEntry BuildSiliconEntry(EntityUid uid, JobPrototype job) + { + return new CrewManifestEntry( + MetaData(uid).EntityName, + job.LocalizedName, + job.Icon.ToString(), + job.ID); + } } [AdminCommand(AdminFlags.Admin)] @@ -309,4 +350,4 @@ public override CompletionResult GetCompletion(IConsoleShell shell, string[] arg return CompletionResult.FromHintOptions(stations, null); } -} \ No newline at end of file +} From e211a63bf99fd3106023902c176f3a8b3102f77b Mon Sep 17 00:00:00 2001 From: Graham Date: Sat, 21 Mar 2026 21:28:42 -0500 Subject: [PATCH 2/2] Move silicon manifest additions into Omu --- .../CrewManifest/OmuCrewManifestSystem.cs | 111 ++++++++++++++++++ .../CrewManifestEntriesCollectEvent.cs | 11 ++ .../CrewManifest/CrewManifestSystem.cs | 42 +------ 3 files changed, 125 insertions(+), 39 deletions(-) create mode 100644 Content.Omu.Server/CrewManifest/OmuCrewManifestSystem.cs create mode 100644 Content.Server/CrewManifest/CrewManifestEntriesCollectEvent.cs diff --git a/Content.Omu.Server/CrewManifest/OmuCrewManifestSystem.cs b/Content.Omu.Server/CrewManifest/OmuCrewManifestSystem.cs new file mode 100644 index 00000000000..7d052d661ee --- /dev/null +++ b/Content.Omu.Server/CrewManifest/OmuCrewManifestSystem.cs @@ -0,0 +1,111 @@ +using Content.Server.CrewManifest; +using Content.Server.Roles; +using Content.Server.Roles.Jobs; +using Content.Server.Silicons.StationAi; +using Content.Server.Station.Systems; +using Content.Shared.CrewManifest; +using Content.Shared.Mind; +using Content.Shared.NPC.Prototypes; +using Content.Shared.NPC.Systems; +using Content.Shared.Roles; +using Content.Shared.Roles.Jobs; +using Content.Shared.Silicons.Borgs.Components; +using Content.Shared.Silicons.StationAi; +using Content.Shared._DV.Silicons.Laws; +using Robust.Shared.Prototypes; + +namespace Content.Omu.Server.CrewManifest; + +/// +/// Omu-specific manifest additions for silicon crew that do not create normal station records. +/// +public sealed class OmuCrewManifestSystem : EntitySystem +{ + private static readonly ProtoId BorgJobId = "Borg"; + private static readonly ProtoId StationAiJobId = "StationAi"; + private static readonly ProtoId NanoTrasenFactionId = "NanoTrasen"; + + [Dependency] private readonly StationSystem _stationSystem = default!; + [Dependency] private readonly StationAiSystem _stationAiSystem = default!; + [Dependency] private readonly SharedMindSystem _mindSystem = default!; + [Dependency] private readonly NpcFactionSystem _npcFactionSystem = default!; + [Dependency] private readonly SharedRoleSystem _roleSystem = default!; + [Dependency] private readonly JobSystem _jobSystem = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnCollectManifestEntries); + } + + private void OnCollectManifestEntries(CrewManifestEntriesCollectEvent args) + { + var borgJob = _prototypeManager.Index(BorgJobId); + var stationAiJob = _prototypeManager.Index(StationAiJobId); + + var borgQuery = EntityQueryEnumerator(); + while (borgQuery.MoveNext(out var uid, out var chassis)) + { + if (_stationSystem.GetOwningStation(uid) != args.Station) + continue; + + if (chassis.BrainEntity == null) + continue; + + if (!_npcFactionSystem.IsMember(uid, NanoTrasenFactionId)) + continue; + + if (!HasComp(uid)) + continue; + + if (!IsCrewSiliconMind(uid, BorgJobId, requireSlavedBorg: true)) + continue; + + args.Entries.Add((borgJob, BuildSiliconEntry(uid, borgJob))); + } + + var aiQuery = EntityQueryEnumerator(); + while (aiQuery.MoveNext(out var uid, out var core)) + { + if (_stationSystem.GetOwningStation(uid) != args.Station) + continue; + + if (!_stationAiSystem.TryGetHeld((uid, core), out var held)) + continue; + + if (!IsCrewSiliconMind(held, StationAiJobId)) + continue; + + args.Entries.Add((stationAiJob, BuildSiliconEntry(held, stationAiJob))); + } + } + + private bool IsCrewSiliconMind(EntityUid uid, ProtoId expectedJob, bool requireSlavedBorg = false) + { + if (!_mindSystem.TryGetMind(uid, out var mindId, out _)) + return false; + + if (!_roleSystem.MindHasRole(mindId)) + return false; + + if (_roleSystem.MindHasRole(mindId)) + return false; + + if (requireSlavedBorg && !HasComp(uid)) + return false; + + if (_jobSystem.MindHasJobWithId(mindId, expectedJob)) + return true; + + return expectedJob == BorgJobId; + } + + private CrewManifestEntry BuildSiliconEntry(EntityUid uid, JobPrototype job) + { + return new CrewManifestEntry( + MetaData(uid).EntityName, + job.LocalizedName, + job.Icon.ToString(), + job.ID); + } +} diff --git a/Content.Server/CrewManifest/CrewManifestEntriesCollectEvent.cs b/Content.Server/CrewManifest/CrewManifestEntriesCollectEvent.cs new file mode 100644 index 00000000000..a07fdcd2594 --- /dev/null +++ b/Content.Server/CrewManifest/CrewManifestEntriesCollectEvent.cs @@ -0,0 +1,11 @@ +using Content.Shared.CrewManifest; +using Content.Shared.Roles; + +namespace Content.Server.CrewManifest; + +/// +/// Allows fork modules to append extra crew manifest rows before the final sort/cache step. +/// +public readonly record struct CrewManifestEntriesCollectEvent( + EntityUid Station, + List<(JobPrototype? job, CrewManifestEntry entry)> Entries); diff --git a/Content.Server/CrewManifest/CrewManifestSystem.cs b/Content.Server/CrewManifest/CrewManifestSystem.cs index dc74c5e6db9..86f995f0151 100644 --- a/Content.Server/CrewManifest/CrewManifestSystem.cs +++ b/Content.Server/CrewManifest/CrewManifestSystem.cs @@ -16,7 +16,6 @@ using System.Linq; using Content.Server.Administration; using Content.Server.EUI; -using Content.Server.Silicons.StationAi; using Content.Server.Station.Systems; using Content.Server.StationRecords; using Content.Server.StationRecords.Systems; @@ -25,8 +24,6 @@ using Content.Shared.CrewManifest; using Content.Shared.GameTicking; using Content.Shared.Roles; -using Content.Shared.Silicons.Borgs.Components; -using Content.Shared.Silicons.StationAi; using Content.Shared.Station.Components; using Content.Shared.StationRecords; using Robust.Shared.Configuration; @@ -40,7 +37,6 @@ public sealed class CrewManifestSystem : EntitySystem { [Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly StationRecordsSystem _recordsSystem = default!; - [Dependency] private readonly StationAiSystem _stationAiSystem = default!; [Dependency] private readonly EuiManager _euiManager = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -245,9 +241,6 @@ private void BuildCrewManifest(EntityUid station) var iter = _recordsSystem.GetRecordsOfType(station); var entries = new CrewManifestEntries(); - var borgJob = _prototypeManager.Index("Borg"); - var stationAiJob = _prototypeManager.Index("StationAi"); - var entriesSort = new List<(JobPrototype? job, CrewManifestEntry entry)>(); foreach (var recordObject in iter) { @@ -258,29 +251,9 @@ private void BuildCrewManifest(EntityUid station) entriesSort.Add((job, entry)); } - var borgQuery = EntityQueryEnumerator(); - while (borgQuery.MoveNext(out var uid, out var chassis)) - { - if (_stationSystem.GetOwningStation(uid) != station) - continue; - - if (chassis.BrainEntity == null) - continue; - - entriesSort.Add((borgJob, BuildSiliconEntry(uid, borgJob))); - } - - var aiQuery = EntityQueryEnumerator(); - while (aiQuery.MoveNext(out var uid, out var core)) - { - if (_stationSystem.GetOwningStation(uid) != station) - continue; - - if (!_stationAiSystem.TryGetHeld((uid, core), out var held)) - continue; - - entriesSort.Add((stationAiJob, BuildSiliconEntry(held, stationAiJob))); - } + // Allow downstream modules to inject extra manifest rows without rewriting this system. + var ev = new CrewManifestEntriesCollectEvent(station, entriesSort); + RaiseLocalEvent(ev); entriesSort.Sort((a, b) => { @@ -294,15 +267,6 @@ private void BuildCrewManifest(EntityUid station) entries.Entries = entriesSort.Select(x => x.entry).ToArray(); _cachedEntries[station] = entries; } - - private CrewManifestEntry BuildSiliconEntry(EntityUid uid, JobPrototype job) - { - return new CrewManifestEntry( - MetaData(uid).EntityName, - job.LocalizedName, - job.Icon.ToString(), - job.ID); - } } [AdminCommand(AdminFlags.Admin)]