From faa7f3461cec072e2023af3d1a93d647d66f4f78 Mon Sep 17 00:00:00 2001 From: exincore Date: Sun, 28 Apr 2024 01:12:45 -0500 Subject: [PATCH] feat(fax): Fax machines print, copy, and send paper labels (#25979) * feat(fax): Client fax file-print parses and stores label * feat(fax): Fax machines print, copy, and send paper labels * style(Fax): Comments and formatting * feat(fax): Make fax admin logging more consistent and clear * refactor(fax): Replace ternary with a simpler null coalescing * refactor(fax): Make FaxSystem Send method signature consistent with Copy, PrintFile * refactor(fax): Read entire file and process later instead of peeking first * refactor(fax): Remove local variables only used for style * style(fax): Fix some nearby style errors * fix(fax): Undo an inaccurate change to admin log formatting * refactor(fax): Separate `firstLine` variable * fix(fax): Use Environment.NewLine * bienvenidos --------- Co-authored-by: metalgearsloth --- Content.Client/Fax/UI/FaxBoundUi.cs | 23 ++++++++- Content.Server/Fax/AdminUI/AdminFaxEui.cs | 2 +- Content.Server/Fax/FaxConstants.cs | 1 + Content.Server/Fax/FaxSystem.cs | 51 ++++++++++++++----- Content.Server/Nuke/NukeCodePaperSystem.cs | 1 + .../Fax/Components/FaxMachineComponent.cs | 6 ++- Content.Shared/Fax/SharedFax.cs | 5 +- 7 files changed, 72 insertions(+), 17 deletions(-) diff --git a/Content.Client/Fax/UI/FaxBoundUi.cs b/Content.Client/Fax/UI/FaxBoundUi.cs index 9b57595d7b..a95066a3b5 100644 --- a/Content.Client/Fax/UI/FaxBoundUi.cs +++ b/Content.Client/Fax/UI/FaxBoundUi.cs @@ -40,7 +40,7 @@ public sealed class FaxBoundUi : BoundUserInterface { if (_dialogIsOpen) return; - + _dialogIsOpen = true; var filters = new FileDialogFilters(new FileDialogFilters.Group("txt")); await using var file = await _fileDialogManager.OpenFile(filters); @@ -52,8 +52,27 @@ public sealed class FaxBoundUi : BoundUserInterface } using var reader = new StreamReader(file); + + var firstLine = await reader.ReadLineAsync(); + string? label = null; var content = await reader.ReadToEndAsync(); - SendMessage(new FaxFileMessage(content[..Math.Min(content.Length, FaxFileMessageValidation.MaxContentSize)], _window.OfficePaper)); + + if (firstLine is { }) + { + if (firstLine.StartsWith('#')) + { + label = firstLine[1..].Trim(); + } + else + { + content = firstLine + "\n" + content; + } + } + + SendMessage(new FaxFileMessage( + label?[..Math.Min(label.Length, FaxFileMessageValidation.MaxLabelSize)], + content[..Math.Min(content.Length, FaxFileMessageValidation.MaxContentSize)], + _window.OfficePaper)); } private void OnSendButtonPressed() diff --git a/Content.Server/Fax/AdminUI/AdminFaxEui.cs b/Content.Server/Fax/AdminUI/AdminFaxEui.cs index 5153e62195..452fc593d9 100644 --- a/Content.Server/Fax/AdminUI/AdminFaxEui.cs +++ b/Content.Server/Fax/AdminUI/AdminFaxEui.cs @@ -55,7 +55,7 @@ public sealed class AdminFaxEui : BaseEui } case AdminFaxEuiMsg.Send sendData: { - var printout = new FaxPrintout(sendData.Content, sendData.Title, null, sendData.StampState, + var printout = new FaxPrintout(sendData.Content, sendData.Title, null, null, sendData.StampState, new() { new StampDisplayInfo { StampedName = sendData.From, StampedColor = sendData.StampColor } }); _faxSystem.Receive(_entityManager.GetEntity(sendData.Target), printout); break; diff --git a/Content.Server/Fax/FaxConstants.cs b/Content.Server/Fax/FaxConstants.cs index 102510bd46..24ed7cbcf3 100644 --- a/Content.Server/Fax/FaxConstants.cs +++ b/Content.Server/Fax/FaxConstants.cs @@ -23,6 +23,7 @@ public static class FaxConstants public const string FaxNameData = "fax_data_name"; public const string FaxPaperNameData = "fax_data_title"; + public const string FaxPaperLabelData = "fax_data_label"; public const string FaxPaperPrototypeData = "fax_data_prototype"; public const string FaxPaperContentData = "fax_data_content"; public const string FaxPaperStampStateData = "fax_data_stamp_state"; diff --git a/Content.Server/Fax/FaxSystem.cs b/Content.Server/Fax/FaxSystem.cs index c21e0db20c..e86dbca4a1 100644 --- a/Content.Server/Fax/FaxSystem.cs +++ b/Content.Server/Fax/FaxSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Chat.Managers; using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; +using Content.Server.Labels; using Content.Server.Paper; using Content.Server.Popups; using Content.Server.Power.Components; @@ -19,6 +20,7 @@ using Content.Shared.Fax; using Content.Shared.Fax.Systems; using Content.Shared.Fax.Components; using Content.Shared.Interaction; +using Content.Shared.Labels.Components; using Content.Shared.Mobs.Components; using Content.Shared.Paper; using Robust.Server.GameObjects; @@ -39,6 +41,7 @@ public sealed class FaxSystem : EntitySystem [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; [Dependency] private readonly PaperSystem _paperSystem = default!; + [Dependency] private readonly LabelSystem _labelSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly ToolSystem _toolSystem = default!; [Dependency] private readonly QuickDialogSystem _quickDialog = default!; @@ -240,7 +243,7 @@ public sealed class FaxSystem : EntitySystem } _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.User):user} renamed {ToPrettyString(uid)} from \"{component.FaxName}\" to \"{newName}\""); + $"{ToPrettyString(args.User):user} renamed {ToPrettyString(uid):tool} from \"{component.FaxName}\" to \"{newName}\""); component.FaxName = newName; _popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-name-set"), uid); UpdateUserInterface(uid, component); @@ -292,11 +295,12 @@ public sealed class FaxSystem : EntitySystem !args.Data.TryGetValue(FaxConstants.FaxPaperContentData, out string? content)) return; + args.Data.TryGetValue(FaxConstants.FaxPaperLabelData, out string? label); args.Data.TryGetValue(FaxConstants.FaxPaperStampStateData, out string? stampState); args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List? stampedBy); args.Data.TryGetValue(FaxConstants.FaxPaperPrototypeData, out string? prototypeId); - var printout = new FaxPrintout(content, name, prototypeId, stampState, stampedBy); + var printout = new FaxPrintout(content, name, label, prototypeId, stampState, stampedBy); Receive(uid, printout, args.SenderAddress); break; @@ -311,6 +315,7 @@ public sealed class FaxSystem : EntitySystem private void OnFileButtonPressed(EntityUid uid, FaxMachineComponent component, FaxFileMessage args) { + args.Label = args.Label?[..Math.Min(args.Label.Length, FaxFileMessageValidation.MaxLabelSize)]; args.Content = args.Content[..Math.Min(args.Content.Length, FaxFileMessageValidation.MaxContentSize)]; PrintFile(uid, component, args); } @@ -328,7 +333,7 @@ public sealed class FaxSystem : EntitySystem if (HasComp(component.PaperSlot.Item)) _faxecute.Faxecute(uid, component); /// when button pressed it will hurt the mob. else - Send(uid, component, args.Actor); + Send(uid, component, args); } private void OnRefreshButtonPressed(EntityUid uid, FaxMachineComponent component, FaxRefreshMessage args) @@ -425,16 +430,20 @@ public sealed class FaxSystem : EntitySystem else prototype = DefaultPaperPrototypeId; - var name = Loc.GetString("fax-machine-printed-paper-name"); + var name = Loc.GetString("fax-machine-printed-paper-name"); - var printout = new FaxPrintout(args.Content, name, prototype); + var printout = new FaxPrintout(args.Content, name, args.Label, prototype); component.PrintingQueue.Enqueue(printout); component.SendTimeoutRemaining += component.SendTimeout; UpdateUserInterface(uid, component); + // Unfortunately, since a paper entity does not yet exist, we have to emulate what LabelSystem will do. + var nameWithLabel = (args.Label is { } label) ? $"{name} ({label})" : name; _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.Actor):actor} added print job to {ToPrettyString(uid):tool} with text: {args.Content}"); + $"{ToPrettyString(args.Actor):actor} " + + $"added print job to \"{component.FaxName}\" {ToPrettyString(uid):tool} " + + $"of {nameWithLabel}: {args.Content}"); } /// @@ -454,9 +463,12 @@ public sealed class FaxSystem : EntitySystem !TryComp(sendEntity, out var paper)) return; + TryComp(sendEntity, out var labelComponent); + // TODO: See comment in 'Send()' about not being able to copy whole entities var printout = new FaxPrintout(paper.Content, - metadata.EntityName, + labelComponent?.OriginalName ?? metadata.EntityName, + labelComponent?.CurrentLabel, metadata.EntityPrototype?.ID ?? DefaultPaperPrototypeId, paper.StampState, paper.StampedBy); @@ -470,14 +482,16 @@ public sealed class FaxSystem : EntitySystem UpdateUserInterface(uid, component); _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.Actor):actor} added copy job to {ToPrettyString(uid):tool} with text: {ToPrettyString(component.PaperSlot.Item):subject}"); + $"{ToPrettyString(args.Actor):actor} " + + $"added copy job to \"{component.FaxName}\" {ToPrettyString(uid):tool} " + + $"of {ToPrettyString(sendEntity):subject}: {printout.Content}"); } /// /// Sends message to addressee if paper is set and a known fax is selected /// A timeout is set after sending, which is shared by the copy button. /// - public void Send(EntityUid uid, FaxMachineComponent? component = null, EntityUid? sender = null) + public void Send(EntityUid uid, FaxMachineComponent? component, FaxSendMessage args) { if (!Resolve(uid, ref component)) return; @@ -496,10 +510,13 @@ public sealed class FaxSystem : EntitySystem !TryComp(sendEntity, out var paper)) return; + TryComp(sendEntity, out var labelComponent); + var payload = new NetworkPayload() { { DeviceNetworkConstants.Command, FaxConstants.FaxPrintCommand }, - { FaxConstants.FaxPaperNameData, metadata.EntityName }, + { FaxConstants.FaxPaperNameData, labelComponent?.OriginalName ?? metadata.EntityName }, + { FaxConstants.FaxPaperLabelData, labelComponent?.CurrentLabel }, { FaxConstants.FaxPaperContentData, paper.Content }, }; @@ -520,7 +537,11 @@ public sealed class FaxSystem : EntitySystem _deviceNetworkSystem.QueuePacket(uid, component.DestinationFaxAddress, payload); - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{(sender != null ? ToPrettyString(sender.Value) : "Unknown"):user} sent fax from \"{component.FaxName}\" {ToPrettyString(uid)} to {faxName} ({component.DestinationFaxAddress}): {paper.Content}"); + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} " + + $"sent fax from \"{component.FaxName}\" {ToPrettyString(uid):tool} " + + $"to \"{faxName}\" ({component.DestinationFaxAddress}) " + + $"of {ToPrettyString(sendEntity):subject}: {paper.Content}"); component.SendTimeoutRemaining += component.SendTimeout; @@ -576,7 +597,13 @@ public sealed class FaxSystem : EntitySystem } _metaData.SetEntityName(printed, printout.Name); - _adminLogger.Add(LogType.Action, LogImpact.Low, $"\"{component.FaxName}\" {ToPrettyString(uid)} printed {ToPrettyString(printed)}: {printout.Content}"); + + if (printout.Label is { } label) + { + _labelSystem.Label(printed, label); + } + + _adminLogger.Add(LogType.Action, LogImpact.Low, $"\"{component.FaxName}\" {ToPrettyString(uid):tool} printed {ToPrettyString(printed):subject}: {printout.Content}"); } private void NotifyAdmins(string faxName) diff --git a/Content.Server/Nuke/NukeCodePaperSystem.cs b/Content.Server/Nuke/NukeCodePaperSystem.cs index c1725536e7..8025e2bbd5 100644 --- a/Content.Server/Nuke/NukeCodePaperSystem.cs +++ b/Content.Server/Nuke/NukeCodePaperSystem.cs @@ -66,6 +66,7 @@ namespace Content.Server.Nuke paperContent, Loc.GetString("nuke-codes-fax-paper-name"), null, + null, "paper_stamp-centcom", new List { diff --git a/Content.Shared/Fax/Components/FaxMachineComponent.cs b/Content.Shared/Fax/Components/FaxMachineComponent.cs index ee9459f508..6664ce023d 100644 --- a/Content.Shared/Fax/Components/FaxMachineComponent.cs +++ b/Content.Shared/Fax/Components/FaxMachineComponent.cs @@ -135,6 +135,9 @@ public sealed partial class FaxPrintout [DataField(required: true)] public string Name { get; private set; } = default!; + [DataField] + public string? Label { get; private set; } + [DataField(required: true)] public string Content { get; private set; } = default!; @@ -151,10 +154,11 @@ public sealed partial class FaxPrintout { } - public FaxPrintout(string content, string name, string? prototypeId = null, string? stampState = null, List? stampedBy = null) + public FaxPrintout(string content, string name, string? label = null, string? prototypeId = null, string? stampState = null, List? stampedBy = null) { Content = content; Name = name; + Label = label; PrototypeId = prototypeId ?? ""; StampState = stampState; StampedBy = stampedBy ?? new List(); diff --git a/Content.Shared/Fax/SharedFax.cs b/Content.Shared/Fax/SharedFax.cs index 15674aef7e..55c928fa95 100644 --- a/Content.Shared/Fax/SharedFax.cs +++ b/Content.Shared/Fax/SharedFax.cs @@ -37,11 +37,13 @@ public sealed class FaxUiState : BoundUserInterfaceState [Serializable, NetSerializable] public sealed class FaxFileMessage : BoundUserInterfaceMessage { + public string? Label; public string Content; public bool OfficePaper; - public FaxFileMessage(string content, bool officePaper) + public FaxFileMessage(string? label, string content, bool officePaper) { + Label = label; Content = content; OfficePaper = officePaper; } @@ -49,6 +51,7 @@ public sealed class FaxFileMessage : BoundUserInterfaceMessage public static class FaxFileMessageValidation { + public const int MaxLabelSize = 50; // parity with Content.Server.Labels.Components.HandLabelerComponent.MaxLabelChars public const int MaxContentSize = 10000; }