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 <comedian_vs_clown@hotmail.com>
This commit is contained in:
exincore
2024-04-28 01:12:45 -05:00
committed by GitHub
parent 5c817ddfc1
commit faa7f3461c
7 changed files with 72 additions and 17 deletions

View File

@@ -52,8 +52,27 @@ public sealed class FaxBoundUi : BoundUserInterface
} }
using var reader = new StreamReader(file); using var reader = new StreamReader(file);
var firstLine = await reader.ReadLineAsync();
string? label = null;
var content = await reader.ReadToEndAsync(); 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() private void OnSendButtonPressed()

View File

@@ -55,7 +55,7 @@ public sealed class AdminFaxEui : BaseEui
} }
case AdminFaxEuiMsg.Send sendData: 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 } }); new() { new StampDisplayInfo { StampedName = sendData.From, StampedColor = sendData.StampColor } });
_faxSystem.Receive(_entityManager.GetEntity(sendData.Target), printout); _faxSystem.Receive(_entityManager.GetEntity(sendData.Target), printout);
break; break;

View File

@@ -23,6 +23,7 @@ public static class FaxConstants
public const string FaxNameData = "fax_data_name"; public const string FaxNameData = "fax_data_name";
public const string FaxPaperNameData = "fax_data_title"; public const string FaxPaperNameData = "fax_data_title";
public const string FaxPaperLabelData = "fax_data_label";
public const string FaxPaperPrototypeData = "fax_data_prototype"; public const string FaxPaperPrototypeData = "fax_data_prototype";
public const string FaxPaperContentData = "fax_data_content"; public const string FaxPaperContentData = "fax_data_content";
public const string FaxPaperStampStateData = "fax_data_stamp_state"; public const string FaxPaperStampStateData = "fax_data_stamp_state";

View File

@@ -4,6 +4,7 @@ using Content.Server.Chat.Managers;
using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork;
using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Components;
using Content.Server.DeviceNetwork.Systems; using Content.Server.DeviceNetwork.Systems;
using Content.Server.Labels;
using Content.Server.Paper; using Content.Server.Paper;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.Power.Components; using Content.Server.Power.Components;
@@ -19,6 +20,7 @@ using Content.Shared.Fax;
using Content.Shared.Fax.Systems; using Content.Shared.Fax.Systems;
using Content.Shared.Fax.Components; using Content.Shared.Fax.Components;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Labels.Components;
using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Components;
using Content.Shared.Paper; using Content.Shared.Paper;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
@@ -39,6 +41,7 @@ public sealed class FaxSystem : EntitySystem
[Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!;
[Dependency] private readonly PaperSystem _paperSystem = default!; [Dependency] private readonly PaperSystem _paperSystem = default!;
[Dependency] private readonly LabelSystem _labelSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly ToolSystem _toolSystem = default!; [Dependency] private readonly ToolSystem _toolSystem = default!;
[Dependency] private readonly QuickDialogSystem _quickDialog = default!; [Dependency] private readonly QuickDialogSystem _quickDialog = default!;
@@ -240,7 +243,7 @@ public sealed class FaxSystem : EntitySystem
} }
_adminLogger.Add(LogType.Action, LogImpact.Low, _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; component.FaxName = newName;
_popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-name-set"), uid); _popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-name-set"), uid);
UpdateUserInterface(uid, component); UpdateUserInterface(uid, component);
@@ -292,11 +295,12 @@ public sealed class FaxSystem : EntitySystem
!args.Data.TryGetValue(FaxConstants.FaxPaperContentData, out string? content)) !args.Data.TryGetValue(FaxConstants.FaxPaperContentData, out string? content))
return; return;
args.Data.TryGetValue(FaxConstants.FaxPaperLabelData, out string? label);
args.Data.TryGetValue(FaxConstants.FaxPaperStampStateData, out string? stampState); args.Data.TryGetValue(FaxConstants.FaxPaperStampStateData, out string? stampState);
args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List<StampDisplayInfo>? stampedBy); args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List<StampDisplayInfo>? stampedBy);
args.Data.TryGetValue(FaxConstants.FaxPaperPrototypeData, out string? prototypeId); 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); Receive(uid, printout, args.SenderAddress);
break; break;
@@ -311,6 +315,7 @@ public sealed class FaxSystem : EntitySystem
private void OnFileButtonPressed(EntityUid uid, FaxMachineComponent component, FaxFileMessage args) 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)]; args.Content = args.Content[..Math.Min(args.Content.Length, FaxFileMessageValidation.MaxContentSize)];
PrintFile(uid, component, args); PrintFile(uid, component, args);
} }
@@ -328,7 +333,7 @@ public sealed class FaxSystem : EntitySystem
if (HasComp<MobStateComponent>(component.PaperSlot.Item)) if (HasComp<MobStateComponent>(component.PaperSlot.Item))
_faxecute.Faxecute(uid, component); /// when button pressed it will hurt the mob. _faxecute.Faxecute(uid, component); /// when button pressed it will hurt the mob.
else else
Send(uid, component, args.Actor); Send(uid, component, args);
} }
private void OnRefreshButtonPressed(EntityUid uid, FaxMachineComponent component, FaxRefreshMessage args) private void OnRefreshButtonPressed(EntityUid uid, FaxMachineComponent component, FaxRefreshMessage args)
@@ -425,16 +430,20 @@ public sealed class FaxSystem : EntitySystem
else else
prototype = DefaultPaperPrototypeId; 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.PrintingQueue.Enqueue(printout);
component.SendTimeoutRemaining += component.SendTimeout; component.SendTimeoutRemaining += component.SendTimeout;
UpdateUserInterface(uid, component); 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, _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}");
} }
/// <summary> /// <summary>
@@ -454,9 +463,12 @@ public sealed class FaxSystem : EntitySystem
!TryComp<PaperComponent>(sendEntity, out var paper)) !TryComp<PaperComponent>(sendEntity, out var paper))
return; return;
TryComp<LabelComponent>(sendEntity, out var labelComponent);
// TODO: See comment in 'Send()' about not being able to copy whole entities // TODO: See comment in 'Send()' about not being able to copy whole entities
var printout = new FaxPrintout(paper.Content, var printout = new FaxPrintout(paper.Content,
metadata.EntityName, labelComponent?.OriginalName ?? metadata.EntityName,
labelComponent?.CurrentLabel,
metadata.EntityPrototype?.ID ?? DefaultPaperPrototypeId, metadata.EntityPrototype?.ID ?? DefaultPaperPrototypeId,
paper.StampState, paper.StampState,
paper.StampedBy); paper.StampedBy);
@@ -470,14 +482,16 @@ public sealed class FaxSystem : EntitySystem
UpdateUserInterface(uid, component); UpdateUserInterface(uid, component);
_adminLogger.Add(LogType.Action, LogImpact.Low, _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}");
} }
/// <summary> /// <summary>
/// Sends message to addressee if paper is set and a known fax is selected /// 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. /// A timeout is set after sending, which is shared by the copy button.
/// </summary> /// </summary>
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)) if (!Resolve(uid, ref component))
return; return;
@@ -496,10 +510,13 @@ public sealed class FaxSystem : EntitySystem
!TryComp<PaperComponent>(sendEntity, out var paper)) !TryComp<PaperComponent>(sendEntity, out var paper))
return; return;
TryComp<LabelComponent>(sendEntity, out var labelComponent);
var payload = new NetworkPayload() var payload = new NetworkPayload()
{ {
{ DeviceNetworkConstants.Command, FaxConstants.FaxPrintCommand }, { DeviceNetworkConstants.Command, FaxConstants.FaxPrintCommand },
{ FaxConstants.FaxPaperNameData, metadata.EntityName }, { FaxConstants.FaxPaperNameData, labelComponent?.OriginalName ?? metadata.EntityName },
{ FaxConstants.FaxPaperLabelData, labelComponent?.CurrentLabel },
{ FaxConstants.FaxPaperContentData, paper.Content }, { FaxConstants.FaxPaperContentData, paper.Content },
}; };
@@ -520,7 +537,11 @@ public sealed class FaxSystem : EntitySystem
_deviceNetworkSystem.QueuePacket(uid, component.DestinationFaxAddress, payload); _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; component.SendTimeoutRemaining += component.SendTimeout;
@@ -576,7 +597,13 @@ public sealed class FaxSystem : EntitySystem
} }
_metaData.SetEntityName(printed, printout.Name); _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) private void NotifyAdmins(string faxName)

View File

@@ -66,6 +66,7 @@ namespace Content.Server.Nuke
paperContent, paperContent,
Loc.GetString("nuke-codes-fax-paper-name"), Loc.GetString("nuke-codes-fax-paper-name"),
null, null,
null,
"paper_stamp-centcom", "paper_stamp-centcom",
new List<StampDisplayInfo> new List<StampDisplayInfo>
{ {

View File

@@ -135,6 +135,9 @@ public sealed partial class FaxPrintout
[DataField(required: true)] [DataField(required: true)]
public string Name { get; private set; } = default!; public string Name { get; private set; } = default!;
[DataField]
public string? Label { get; private set; }
[DataField(required: true)] [DataField(required: true)]
public string Content { get; private set; } = default!; 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<StampDisplayInfo>? stampedBy = null) public FaxPrintout(string content, string name, string? label = null, string? prototypeId = null, string? stampState = null, List<StampDisplayInfo>? stampedBy = null)
{ {
Content = content; Content = content;
Name = name; Name = name;
Label = label;
PrototypeId = prototypeId ?? ""; PrototypeId = prototypeId ?? "";
StampState = stampState; StampState = stampState;
StampedBy = stampedBy ?? new List<StampDisplayInfo>(); StampedBy = stampedBy ?? new List<StampDisplayInfo>();

View File

@@ -37,11 +37,13 @@ public sealed class FaxUiState : BoundUserInterfaceState
[Serializable, NetSerializable] [Serializable, NetSerializable]
public sealed class FaxFileMessage : BoundUserInterfaceMessage public sealed class FaxFileMessage : BoundUserInterfaceMessage
{ {
public string? Label;
public string Content; public string Content;
public bool OfficePaper; public bool OfficePaper;
public FaxFileMessage(string content, bool officePaper) public FaxFileMessage(string? label, string content, bool officePaper)
{ {
Label = label;
Content = content; Content = content;
OfficePaper = officePaper; OfficePaper = officePaper;
} }
@@ -49,6 +51,7 @@ public sealed class FaxFileMessage : BoundUserInterfaceMessage
public static class FaxFileMessageValidation public static class FaxFileMessageValidation
{ {
public const int MaxLabelSize = 50; // parity with Content.Server.Labels.Components.HandLabelerComponent.MaxLabelChars
public const int MaxContentSize = 10000; public const int MaxContentSize = 10000;
} }