Machine Port Prototypes (#7659)

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
Leon Friedrich
2022-05-12 20:46:20 +12:00
committed by GitHub
parent 32c2eb7a02
commit c00b459e31
29 changed files with 422 additions and 220 deletions

View File

@@ -7,9 +7,9 @@ using Content.Shared.Interaction;
using Content.Shared.MachineLinking;
using Content.Shared.Popups;
using Robust.Server.GameObjects;
using Robust.Shared.Utility;
using Robust.Shared.Player;
using Content.Shared.Verbs;
using Robust.Shared.Prototypes;
using Content.Shared.MachineLinking.Events;
namespace Content.Server.MachineLinking.System
@@ -18,24 +18,12 @@ namespace Content.Server.MachineLinking.System
{
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
private static readonly (string, string)[][] _defaultMappings =
{
new [] { ("Pressed", "Toggle") },
new [] { ("On", "On"), ("Off", "Off") },
new [] { ("On", "Open"), ("Off", "Close") },
new [] { ("On", "Forward"), ("Off", "Off") },
new [] { ("Left", "On"), ("Right", "On"), ("Middle", "Off") },
new [] { ("Left", "Open"), ("Right", "Open"), ("Middle", "Close") },
new [] { ("Left", "Forward"), ("Right", "Reverse"), ("Middle", "Off") },
};
[Dependency] private readonly IPrototypeManager _protoMan = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SignalTransmitterComponent, InvokePortEvent>(OnTransmitterInvokePort);
SubscribeLocalEvent<SignalTransmitterComponent, ComponentStartup>(OnTransmitterStartup);
SubscribeLocalEvent<SignalTransmitterComponent, ComponentRemove>(OnTransmitterRemoved);
SubscribeLocalEvent<SignalTransmitterComponent, InteractUsingEvent>(OnTransmitterInteractUsing);
@@ -52,6 +40,27 @@ namespace Content.Server.MachineLinking.System
SubscribeLocalEvent<SignalLinkerComponent, BoundUIClosedEvent>(OnLinkerUIClosed);
}
/// <summary>
/// Convenience function to add several ports to an entity.
/// </summary>
public void EnsureReceiverPorts(EntityUid uid, params string[] ports)
{
var comp = EnsureComp<SignalReceiverComponent>(uid);
foreach (var port in ports)
{
comp.Inputs.TryAdd(port, new());
}
}
public void EnsureTransmitterPorts(EntityUid uid, params string[] ports)
{
var comp = EnsureComp<SignalTransmitterComponent>(uid);
foreach (var port in ports)
{
comp.Outputs.TryAdd(port, new());
}
}
/// <summary>
/// Add an alt-click verb to allow users to link the default ports, without needing to open the UI.
/// </summary>
@@ -117,9 +126,15 @@ namespace Content.Server.MachineLinking.System
verb.Message = Loc.GetString("signal-linking-verb-disabled-no-receiver");
}
private void OnTransmitterInvokePort(EntityUid uid, SignalTransmitterComponent component, InvokePortEvent args)
public void InvokePort(EntityUid uid, string port, SignalTransmitterComponent? component = null)
{
foreach (var receiver in component.Outputs[args.Port])
if (!Resolve(uid, ref component))
return;
if (!component.Outputs.TryGetValue(port, out var receivers))
return;
foreach (var receiver in receivers)
RaiseLocalEvent(receiver.Uid, new SignalReceivedEvent(receiver.Port), false);
}
@@ -264,10 +279,18 @@ namespace Content.Server.MachineLinking.System
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 receivers) ||
!receiver.Inputs.TryGetValue(args.ReceiverPort, out var transmitters))
if (!transmitter.Outputs.TryGetValue(args.TransmitterPort, out var linkedReceivers) ||
!receiver.Inputs.TryGetValue(args.ReceiverPort, out var linkedTransmitters))
return false;
// Does the link already exist? Under the assumption that nothing has broken, lets only check the
// transmitter ports.
foreach (var identifier in linkedTransmitters)
{
if (identifier.Uid == transmitter.Owner && identifier.Port == args.TransmitterPort)
return true;
}
if (checkRange && !IsInRange(transmitter, receiver))
{
if (!quiet)
@@ -295,12 +318,12 @@ namespace Content.Server.MachineLinking.System
return false;
}
receivers.Add(new(receiver.Owner, args.ReceiverPort));
transmitters.Add(new(transmitter.Owner, args.TransmitterPort));
linkedReceivers.Add(new(receiver.Owner, args.ReceiverPort));
linkedTransmitters.Add(new(transmitter.Owner, args.TransmitterPort));
if (!quiet)
_popupSystem.PopupCursor(Loc.GetString("signal-linker-component-linked-port",
("machine1", transmitter.Owner), ("port1", args.TransmitterPort),
("machine2", receiver.Owner), ("port2", args.ReceiverPort)),
("machine1", transmitter.Owner), ("port1", PortName<TransmitterPortPrototype>(args.TransmitterPort)),
("machine2", receiver.Owner), ("port2", PortName<ReceiverPortPrototype>(args.ReceiverPort))),
Filter.Entities(user));
return true;
@@ -326,8 +349,8 @@ namespace Content.Server.MachineLinking.System
RaiseLocalEvent(receiver.Owner, new PortDisconnectedEvent(args.ReceiverPort));
RaiseLocalEvent(transmitter.Owner, new PortDisconnectedEvent(args.TransmitterPort));
_popupSystem.PopupCursor(Loc.GetString("signal-linker-component-unlinked-port",
("machine1", transmitter.Owner), ("port1", args.TransmitterPort),
("machine2", receiver.Owner), ("port2", args.ReceiverPort)),
("machine1", transmitter.Owner), ("port1", PortName<TransmitterPortPrototype>(args.TransmitterPort)),
("machine2", receiver.Owner), ("port2", PortName<ReceiverPortPrototype>(args.ReceiverPort))),
Filter.Entities(attached));
}
else
@@ -343,6 +366,19 @@ namespace Content.Server.MachineLinking.System
TryUpdateUI(linker, transmitter, receiver);
}
/// <summary>
/// Convenience function to retrieve the name of a port prototype.
/// </summary>
/// <param name="port"></param>
/// <returns></returns>
public string PortName<TPort>(string port) where TPort : MachinePortPrototype, IPrototype
{
if (!_protoMan.TryIndex<TPort>(port, out var proto))
return port;
return Loc.GetString(proto.Name);
}
private void OnLinkerClearSelected(EntityUid uid, SignalLinkerComponent linker, LinkerClearSelected args)
{
if (!TryComp(linker.SavedTransmitter, out SignalTransmitterComponent? transmitter) ||
@@ -388,19 +424,27 @@ namespace Content.Server.MachineLinking.System
var allLinksSucceeded = true;
if (_defaultMappings.TryFirstOrDefault(map => !map.ExceptBy(transmitter.Outputs.Keys, item => item.Item1).Any() &&
!map.ExceptBy(receiver.Inputs.Keys, item => item.Item2).Any(), out var mapping))
// First, disconnect existing links.
foreach (var (port, receivers) in transmitter.Outputs)
if (receivers.RemoveAll(id => id.Uid == receiver.Owner) > 0)
RaiseLocalEvent(transmitter.Owner, new PortDisconnectedEvent(port));
foreach (var (port, transmitters) in receiver.Inputs)
if (transmitters.RemoveAll(id => id.Uid == transmitter.Owner) > 0)
RaiseLocalEvent(receiver.Owner, new PortDisconnectedEvent(port));
// Then make any valid default connections.
foreach (var outPort in transmitter.Outputs.Keys)
{
foreach (var (port, receivers) in transmitter.Outputs)
if (receivers.RemoveAll(id => id.Uid == receiver.Owner) > 0)
RaiseLocalEvent(transmitter.Owner, new PortDisconnectedEvent(port));
var prototype = _protoMan.Index<TransmitterPortPrototype>(outPort);
if (prototype.DefaultLinks == null)
continue;
foreach (var (port, transmitters) in receiver.Inputs)
if (transmitters.RemoveAll(id => id.Uid == transmitter.Owner) > 0)
RaiseLocalEvent(receiver.Owner, new PortDisconnectedEvent(port));
foreach (var (t, r) in mapping)
allLinksSucceeded &= !TryLink(transmitter, receiver, new(t, r), user, quiet: true, checkRange: false);
foreach (var inPort in prototype.DefaultLinks)
{
if (receiver.Inputs.ContainsKey(inPort))
allLinksSucceeded &= TryLink(transmitter, receiver, new(outPort, inPort), user, quiet: true, checkRange: false);
}
}
return allLinksSucceeded;