From 547af7c7e899cefd5f891f3f242b9efc48cf22c3 Mon Sep 17 00:00:00 2001 From: 20kdc Date: Sat, 3 Sep 2022 19:30:57 +0100 Subject: [PATCH] AutoLink port from Outer Rim (#10967) * C# half of Outer Rim commit 5081906bd17e715ecae422dd7a003d9f103e6884 "autolink gaming." Ported from Outer Rim with permission. * YAML half of Outer Rim commit 5081906bd17e715ecae422dd7a003d9f103e6884 "autolink gaming." Ported from Outer Rim with permission. * commit fixed AL summary Co-authored-by: Moony * NewLinkEvent.User & LinkAttemptEvent.User now nullable, fix possible AccessReaderSystem AutoLink bug Co-authored-by: Moony --- .../Components/AutoLinkReceiverComponent.cs | 12 +++ .../AutoLinkTransmitterComponent.cs | 12 +++ .../MachineLinking/System/AutoLinkSystem.cs | 36 ++++++++ .../System/SignalLinkerSystem.cs | 23 ++--- .../Access/Systems/AccessReaderSystem.cs | 4 +- .../MachineLinking/Events/LinkAttemptEvent.cs | 4 +- .../MachineLinking/Events/NewLinkEvent.cs | 4 +- .../Doors/Shutter/blast_door_autolink.yml | 85 +++++++++++++++++++ .../Structures/Wallmounts/switch_autolink.yml | 47 ++++++++++ 9 files changed, 212 insertions(+), 15 deletions(-) create mode 100644 Content.Server/MachineLinking/Components/AutoLinkReceiverComponent.cs create mode 100644 Content.Server/MachineLinking/Components/AutoLinkTransmitterComponent.cs create mode 100644 Content.Server/MachineLinking/System/AutoLinkSystem.cs create mode 100644 Resources/Prototypes/Entities/Structures/Doors/Shutter/blast_door_autolink.yml create mode 100644 Resources/Prototypes/Entities/Structures/Wallmounts/switch_autolink.yml diff --git a/Content.Server/MachineLinking/Components/AutoLinkReceiverComponent.cs b/Content.Server/MachineLinking/Components/AutoLinkReceiverComponent.cs new file mode 100644 index 0000000000..7bb9f99a4e --- /dev/null +++ b/Content.Server/MachineLinking/Components/AutoLinkReceiverComponent.cs @@ -0,0 +1,12 @@ +namespace Content.Server.MachineLinking.Components; + +/// +/// This is used for automatic linkage with buttons and other transmitters. +/// +[RegisterComponent] +public sealed class AutoLinkReceiverComponent : Component +{ + [DataField("channel", required: true, readOnly: true)] + public string AutoLinkChannel = default!; +} + diff --git a/Content.Server/MachineLinking/Components/AutoLinkTransmitterComponent.cs b/Content.Server/MachineLinking/Components/AutoLinkTransmitterComponent.cs new file mode 100644 index 0000000000..b3760a2f2c --- /dev/null +++ b/Content.Server/MachineLinking/Components/AutoLinkTransmitterComponent.cs @@ -0,0 +1,12 @@ +namespace Content.Server.MachineLinking.Components; + +/// +/// This is used for automatic linkage with various receivers, like shutters. +/// +[RegisterComponent] +public sealed class AutoLinkTransmitterComponent : Component +{ + [DataField("channel", required: true, readOnly: true)] + public string AutoLinkChannel = default!; +} + diff --git a/Content.Server/MachineLinking/System/AutoLinkSystem.cs b/Content.Server/MachineLinking/System/AutoLinkSystem.cs new file mode 100644 index 0000000000..c7590e564d --- /dev/null +++ b/Content.Server/MachineLinking/System/AutoLinkSystem.cs @@ -0,0 +1,36 @@ +using Content.Server.MachineLinking.Components; + +namespace Content.Server.MachineLinking.System; + +/// +/// This handles automatically linking autolinked entities at round-start. +/// +public sealed class AutoLinkSystem : EntitySystem +{ + [Dependency] private readonly SignalLinkerSystem _signalLinkerSystem = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnAutoLinkMapInit); + } + + private void OnAutoLinkMapInit(EntityUid uid, AutoLinkTransmitterComponent component, MapInitEvent args) + { + var xform = Transform(uid); + + foreach (var receiver in EntityQuery()) + { + if (receiver.AutoLinkChannel != component.AutoLinkChannel) + continue; // Not ours. + + var rxXform = Transform(receiver.Owner); + + if (rxXform.GridUid != xform.GridUid) + continue; + + _signalLinkerSystem.TryLinkDefaults(receiver.Owner, uid, null); + } + } +} + diff --git a/Content.Server/MachineLinking/System/SignalLinkerSystem.cs b/Content.Server/MachineLinking/System/SignalLinkerSystem.cs index 4011d5e7ab..edc7ab9c78 100644 --- a/Content.Server/MachineLinking/System/SignalLinkerSystem.cs +++ b/Content.Server/MachineLinking/System/SignalLinkerSystem.cs @@ -277,12 +277,15 @@ namespace Content.Server.MachineLinking.System } - private bool TryLink(SignalTransmitterComponent transmitter, SignalReceiverComponent receiver, SignalPortSelected args, EntityUid user, bool quiet = false, bool checkRange = true) + private bool TryLink(SignalTransmitterComponent transmitter, SignalReceiverComponent receiver, SignalPortSelected args, EntityUid? user, bool quiet = false, bool checkRange = true) { if (!transmitter.Outputs.TryGetValue(args.TransmitterPort, out var linkedReceivers) || !receiver.Inputs.TryGetValue(args.ReceiverPort, out var linkedTransmitters)) return false; + // Accounts for possibly missing user & the quiet option. + var alertFilter = (!quiet && user != null) ? Filter.Entities(user.Value) : null; + // Does the link already exist? Under the assumption that nothing has broken, lets only check the // transmitter ports. foreach (var identifier in linkedTransmitters) @@ -293,9 +296,9 @@ namespace Content.Server.MachineLinking.System if (checkRange && !IsInRange(transmitter, receiver)) { - if (!quiet) + if (alertFilter != null) _popupSystem.PopupCursor(Loc.GetString("signal-linker-component-out-of-range"), - Filter.Entities(user)); + alertFilter); return false; } @@ -304,27 +307,27 @@ namespace Content.Server.MachineLinking.System RaiseLocalEvent(transmitter.Owner, linkAttempt, true); if (linkAttempt.Cancelled) { - if (!quiet) + if (alertFilter != null) _popupSystem.PopupCursor(Loc.GetString("signal-linker-component-connection-refused", ("machine", transmitter.Owner)), - Filter.Entities(user)); + alertFilter); return false; } RaiseLocalEvent(receiver.Owner, linkAttempt, true); if (linkAttempt.Cancelled) { - if (!quiet) + if (alertFilter != null) _popupSystem.PopupCursor(Loc.GetString("signal-linker-component-connection-refused", ("machine", receiver.Owner)), - Filter.Entities(user)); + alertFilter); return false; } linkedReceivers.Add(new(receiver.Owner, args.ReceiverPort)); linkedTransmitters.Add(new(transmitter.Owner, args.TransmitterPort)); - if (!quiet) + if (alertFilter != null) _popupSystem.PopupCursor(Loc.GetString("signal-linker-component-linked-port", ("machine1", transmitter.Owner), ("port1", PortName(args.TransmitterPort)), ("machine2", receiver.Owner), ("port2", PortName(args.ReceiverPort))), - Filter.Entities(user), PopupType.Medium); + alertFilter, PopupType.Medium); var newLink = new NewLinkEvent(user, transmitter.Owner, args.TransmitterPort, receiver.Owner, args.ReceiverPort); RaiseLocalEvent(receiver.Owner, newLink); @@ -417,7 +420,7 @@ namespace Content.Server.MachineLinking.System /// Attempt to link all default ports connections. Returns true if all links succeeded. Otherwise returns /// false. /// - public bool TryLinkDefaults(EntityUid receiverUid, EntityUid transmitterUid, EntityUid user, + public bool TryLinkDefaults(EntityUid receiverUid, EntityUid transmitterUid, EntityUid? user, SignalReceiverComponent? receiver = null, SignalTransmitterComponent? transmitter = null) { if (!Resolve(receiverUid, ref receiver, false) || !Resolve(transmitterUid, ref transmitter, false)) diff --git a/Content.Shared/Access/Systems/AccessReaderSystem.cs b/Content.Shared/Access/Systems/AccessReaderSystem.cs index ea66232c65..692b574f0f 100644 --- a/Content.Shared/Access/Systems/AccessReaderSystem.cs +++ b/Content.Shared/Access/Systems/AccessReaderSystem.cs @@ -26,7 +26,9 @@ namespace Content.Shared.Access.Systems private void OnLinkAttempt(EntityUid uid, AccessReaderComponent component, LinkAttemptEvent args) { - if (component.Enabled && !IsAllowed(args.User, component)) + if (args.User == null) // AutoLink (and presumably future external linkers) have no user. + return; + if (component.Enabled && !IsAllowed(args.User.Value, component)) args.Cancel(); } diff --git a/Content.Shared/MachineLinking/Events/LinkAttemptEvent.cs b/Content.Shared/MachineLinking/Events/LinkAttemptEvent.cs index 8def85fbd6..4eb75bdc7c 100644 --- a/Content.Shared/MachineLinking/Events/LinkAttemptEvent.cs +++ b/Content.Shared/MachineLinking/Events/LinkAttemptEvent.cs @@ -4,11 +4,11 @@ namespace Content.Shared.MachineLinking.Events { public readonly EntityUid Transmitter; public readonly EntityUid Receiver; - public readonly EntityUid User; + public readonly EntityUid? User; public readonly string TransmitterPort; public readonly string ReceiverPort; - public LinkAttemptEvent(EntityUid user, EntityUid transmitter, string transmitterPort, EntityUid receiver, string receiverPort) + public LinkAttemptEvent(EntityUid? user, EntityUid transmitter, string transmitterPort, EntityUid receiver, string receiverPort) { User = user; Transmitter = transmitter; diff --git a/Content.Shared/MachineLinking/Events/NewLinkEvent.cs b/Content.Shared/MachineLinking/Events/NewLinkEvent.cs index f4ee0a1d79..22dfce7b8f 100644 --- a/Content.Shared/MachineLinking/Events/NewLinkEvent.cs +++ b/Content.Shared/MachineLinking/Events/NewLinkEvent.cs @@ -4,11 +4,11 @@ namespace Content.Shared.MachineLinking.Events { public readonly EntityUid Transmitter; public readonly EntityUid Receiver; - public readonly EntityUid User; + public readonly EntityUid? User; public readonly string TransmitterPort; public readonly string ReceiverPort; - public NewLinkEvent(EntityUid user, EntityUid transmitter, string transmitterPort, EntityUid receiver, string receiverPort) + public NewLinkEvent(EntityUid? user, EntityUid transmitter, string transmitterPort, EntityUid receiver, string receiverPort) { User = user; Transmitter = transmitter; diff --git a/Resources/Prototypes/Entities/Structures/Doors/Shutter/blast_door_autolink.yml b/Resources/Prototypes/Entities/Structures/Doors/Shutter/blast_door_autolink.yml new file mode 100644 index 0000000000..399760616c --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Doors/Shutter/blast_door_autolink.yml @@ -0,0 +1,85 @@ +# AutoLink variants of BlastDoor (from Outer Rim) + +- type: entity + id: BlastDoorExterior1 + parent: BlastDoor + suffix: Autolink, Ext1 + components: + - type: AutoLinkReceiver + channel: Ext1 + + +- type: entity + id: BlastDoorExterior1Open + parent: BlastDoorOpen + suffix: Open, Autolink, Ext1 + components: + - type: AutoLinkReceiver + channel: Ext1 + +- type: entity + id: BlastDoorExterior2 + parent: BlastDoor + suffix: Autolink, Ext2 + components: + - type: AutoLinkReceiver + channel: Ext2 + + +- type: entity + id: BlastDoorExterior2Open + parent: BlastDoorOpen + suffix: Open, Autolink, Ext2 + components: + - type: AutoLinkReceiver + channel: Ext2 + +- type: entity + id: BlastDoorExterior3 + parent: BlastDoor + suffix: Autolink, Ext3 + components: + - type: AutoLinkReceiver + channel: Ext3 + + +- type: entity + id: BlastDoorExterior3Open + parent: BlastDoorOpen + suffix: Open, Autolink, Ext3 + components: + - type: AutoLinkReceiver + channel: Ext3 + +- type: entity + id: BlastDoorBridge + parent: BlastDoor + suffix: Autolink, Bridge + components: + - type: AutoLinkReceiver + channel: Bridge + +- type: entity + id: BlastDoorBridgeOpen + parent: BlastDoorOpen + suffix: Open, Autolink, Bridge + components: + - type: AutoLinkReceiver + channel: Bridge + +- type: entity + id: BlastDoorWindows + parent: BlastDoor + suffix: Autolink, Windows + components: + - type: AutoLinkReceiver + channel: Windows + +- type: entity + id: BlastDoorWindowsOpen + parent: BlastDoorOpen + suffix: Open, Autolink, Windows + components: + - type: AutoLinkReceiver + channel: Windows + diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/switch_autolink.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/switch_autolink.yml new file mode 100644 index 0000000000..fc15956225 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/switch_autolink.yml @@ -0,0 +1,47 @@ +# AutoLink variants of SignalButton (from Outer Rim) + +- type: entity + id: SignalButtonExt1 + parent: SignalButton + name: exterior button 1 + suffix: Autolink, Ext1 + components: + - type: AutoLinkTransmitter + channel: Ext1 + +- type: entity + id: SignalButtonExt2 + parent: SignalButton + name: exterior button 2 + suffix: Autolink, Ext2 + components: + - type: AutoLinkTransmitter + channel: Ext2 + +- type: entity + id: SignalButtonExt3 + parent: SignalButton + name: exterior button 3 + suffix: Autolink, Ext3 + components: + - type: AutoLinkTransmitter + channel: Ext3 + +- type: entity + id: SignalButtonBridge + parent: SignalButton + name: bridge windows button + suffix: Autolink, Bridge + components: + - type: AutoLinkTransmitter + channel: Bridge + +- type: entity + id: SignalButtonWindows + parent: SignalButton + name: exterior windows button + suffix: Autolink, Windows + components: + - type: AutoLinkTransmitter + channel: Windows +