make linking logic gates 1000% better (#25041)
* make door status use SendSignal * LastSignals and logic, add ClearSignal api too * make everything outputting a logic signal default to false * refactor ops * :trollface: * :trollface: * protoid for LastSignals * oop --------- Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
@@ -7,6 +7,7 @@ using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.NetworkConfigurator;
|
||||
|
||||
@@ -160,7 +161,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
|
||||
/// </summary>
|
||||
private sealed class LinksRender : Control
|
||||
{
|
||||
public readonly List<(string, string)> Links = new();
|
||||
public readonly List<(ProtoId<SourcePortPrototype>, ProtoId<SinkPortPrototype>)> Links = new();
|
||||
public readonly Dictionary<string, Button> SourceButtons = new();
|
||||
public readonly Dictionary<string, Button> SinkButtons = new();
|
||||
private readonly BoxContainer _leftButtonContainer;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using Content.Server.DeviceLinking.Components;
|
||||
using Content.Server.DeviceLinking.Events;
|
||||
using Content.Server.DeviceLinking.Components;
|
||||
using Content.Server.DeviceLinking.Events;
|
||||
using Content.Server.DeviceNetwork;
|
||||
using Content.Server.DeviceNetwork.Components;
|
||||
using Content.Server.DeviceNetwork.Systems;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Content.Shared.DeviceLinking.Events;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
|
||||
namespace Content.Server.DeviceLinking.Systems;
|
||||
@@ -15,7 +16,9 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DeviceLinkSinkComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||
SubscribeLocalEvent<DeviceLinkSourceComponent, NewLinkEvent>(OnNewLink);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
@@ -51,32 +54,42 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
||||
|
||||
foreach (var (source, sink) in links)
|
||||
{
|
||||
if (source != port)
|
||||
continue;
|
||||
|
||||
if (sinkComponent.InvokeCounter > sinkComponent.InvokeLimit)
|
||||
{
|
||||
sinkComponent.InvokeCounter = 0;
|
||||
var args = new DeviceLinkOverloadedEvent();
|
||||
RaiseLocalEvent(sinkUid, ref args);
|
||||
RemoveAllFromSink(sinkUid, sinkComponent);
|
||||
continue;
|
||||
if (source == port)
|
||||
InvokeDirect((uid, sourceComponent), (sinkUid, sinkComponent), source, sink, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sinkComponent.InvokeCounter++;
|
||||
/// <summary>
|
||||
/// Raises an event on or sends a network packet directly to a sink from a source.
|
||||
/// </summary>
|
||||
private void InvokeDirect(Entity<DeviceLinkSourceComponent> source, Entity<DeviceLinkSinkComponent?> sink, string sourcePort, string sinkPort, NetworkPayload? data)
|
||||
{
|
||||
if (!Resolve(sink, ref sink.Comp))
|
||||
return;
|
||||
|
||||
if (sink.Comp.InvokeCounter > sink.Comp.InvokeLimit)
|
||||
{
|
||||
sink.Comp.InvokeCounter = 0;
|
||||
var args = new DeviceLinkOverloadedEvent();
|
||||
RaiseLocalEvent(sink, ref args);
|
||||
RemoveAllFromSink(sink, sink.Comp);
|
||||
return;
|
||||
}
|
||||
|
||||
sink.Comp.InvokeCounter++;
|
||||
|
||||
//Just skip using device networking if the source or the sink doesn't support it
|
||||
if (!HasComp<DeviceNetworkComponent>(uid) || !TryComp<DeviceNetworkComponent>(sinkUid, out var sinkNetworkComponent))
|
||||
if (!HasComp<DeviceNetworkComponent>(source) || !TryComp<DeviceNetworkComponent>(sink, out var sinkNetwork))
|
||||
{
|
||||
var eventArgs = new SignalReceivedEvent(sink, uid);
|
||||
|
||||
RaiseLocalEvent(sinkUid, ref eventArgs);
|
||||
continue;
|
||||
var eventArgs = new SignalReceivedEvent(sinkPort, source);
|
||||
RaiseLocalEvent(sink, ref eventArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
var payload = new NetworkPayload()
|
||||
{
|
||||
[InvokedPort] = sink
|
||||
[InvokedPort] = sinkPort
|
||||
};
|
||||
|
||||
if (data != null)
|
||||
@@ -91,9 +104,7 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
||||
|
||||
// force using wireless network so things like atmos devices are able to send signals
|
||||
var network = (int) DeviceNetworkComponent.DeviceNetIdDefaults.Wireless;
|
||||
_deviceNetworkSystem.QueuePacket(uid, sinkNetworkComponent.Address, payload, sinkNetworkComponent.ReceiveFrequency, network);
|
||||
}
|
||||
}
|
||||
_deviceNetworkSystem.QueuePacket(source, sinkNetwork.Address, payload, sinkNetwork.ReceiveFrequency, network);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,11 +112,29 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
||||
/// </summary>
|
||||
public void SendSignal(EntityUid uid, string port, bool signal, DeviceLinkSourceComponent? comp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref comp))
|
||||
return;
|
||||
|
||||
var data = new NetworkPayload
|
||||
{
|
||||
[DeviceNetworkConstants.LogicState] = signal ? SignalState.High : SignalState.Low
|
||||
};
|
||||
InvokePort(uid, port, data, comp);
|
||||
|
||||
comp.LastSignals[port] = signal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the last signals state for linking.
|
||||
/// This is not to be confused with sending a low signal, this is the complete absence of anything.
|
||||
/// Use if the device is in an invalid state and has no reasonable output signal.
|
||||
/// </summary>
|
||||
public void ClearSignal(Entity<DeviceLinkSourceComponent?> ent, string port)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return;
|
||||
|
||||
ent.Comp.LastSignals.Remove(port);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -120,5 +149,24 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
||||
var eventArgs = new SignalReceivedEvent(port, args.Sender, args.Data);
|
||||
RaiseLocalEvent(uid, ref eventArgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When linking from a port that currently has a signal being sent, invoke the new link with that signal.
|
||||
/// </summary>
|
||||
private void OnNewLink(Entity<DeviceLinkSourceComponent> ent, ref NewLinkEvent args)
|
||||
{
|
||||
if (args.Source != ent.Owner)
|
||||
return;
|
||||
|
||||
// only do anything if a signal is being sent from a port
|
||||
if (!ent.Comp.LastSignals.TryGetValue(args.SourcePort, out var signal))
|
||||
return;
|
||||
|
||||
var payload = new NetworkPayload()
|
||||
{
|
||||
[DeviceNetworkConstants.LogicState] = signal ? SignalState.High : SignalState.Low
|
||||
};
|
||||
InvokeDirect(ent, args.Sink, args.SourcePort, args.SinkPort, payload);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -85,23 +85,18 @@ namespace Content.Server.DeviceLinking.Systems
|
||||
|
||||
private void OnStateChanged(EntityUid uid, DoorSignalControlComponent door, DoorStateChangedEvent args)
|
||||
{
|
||||
var data = new NetworkPayload()
|
||||
{
|
||||
{ DeviceNetworkConstants.LogicState, SignalState.Momentary }
|
||||
};
|
||||
|
||||
if (args.State == DoorState.Closed)
|
||||
{
|
||||
data[DeviceNetworkConstants.LogicState] = SignalState.Low;
|
||||
_signalSystem.InvokePort(uid, door.OutOpen, data);
|
||||
// only ever say the door is closed when it is completely airtight
|
||||
_signalSystem.SendSignal(uid, door.OutOpen, false);
|
||||
}
|
||||
else if (args.State == DoorState.Open
|
||||
|| args.State == DoorState.Opening
|
||||
|| args.State == DoorState.Closing
|
||||
|| args.State == DoorState.Emagging)
|
||||
{
|
||||
data[DeviceNetworkConstants.LogicState] = SignalState.High;
|
||||
_signalSystem.InvokePort(uid, door.OutOpen, data);
|
||||
// say the door is open whenever it would be letting air pass
|
||||
_signalSystem.SendSignal(uid, door.OutOpen, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.DeviceLinking;
|
||||
|
||||
@@ -11,25 +11,32 @@ public sealed partial class DeviceLinkSourceComponent : Component
|
||||
/// <summary>
|
||||
/// The ports the device link source sends signals from
|
||||
/// </summary>
|
||||
[DataField("ports", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<SourcePortPrototype>))]
|
||||
public HashSet<string>? Ports;
|
||||
[DataField]
|
||||
public HashSet<ProtoId<SourcePortPrototype>>? Ports;
|
||||
|
||||
/// <summary>
|
||||
/// A list of sink uids that got linked for each port
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public Dictionary<string, HashSet<EntityUid>> Outputs = new();
|
||||
public Dictionary<ProtoId<SourcePortPrototype>, HashSet<EntityUid>> Outputs = new();
|
||||
|
||||
/// <summary>
|
||||
/// If set to High or Low, the last signal state for a given port.
|
||||
/// Used when linking ports of devices that are currently outputting a signal.
|
||||
/// Only set by <c>DeviceLinkSystem.SendSignal</c>.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Dictionary<ProtoId<SourcePortPrototype>, bool> LastSignals = new();
|
||||
|
||||
/// <summary>
|
||||
/// The list of source to sink ports for each linked sink entity for easier managing of links
|
||||
/// </summary>
|
||||
[DataField("linkedPorts")]
|
||||
public Dictionary<EntityUid, HashSet<(string source, string sink)>> LinkedPorts = new();
|
||||
[DataField]
|
||||
public Dictionary<EntityUid, HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)>> LinkedPorts = new();
|
||||
|
||||
/// <summary>
|
||||
/// Limits the range devices can be linked across.
|
||||
/// </summary>
|
||||
[DataField("range")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float Range = 30f;
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
|
||||
return;
|
||||
|
||||
var comp = EnsureComp<DeviceLinkSourceComponent>(uid);
|
||||
comp.Ports ??= new HashSet<string>();
|
||||
comp.Ports ??= new HashSet<ProtoId<SourcePortPrototype>>();
|
||||
|
||||
foreach (var port in ports)
|
||||
{
|
||||
@@ -233,10 +233,10 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
|
||||
/// Returns the links of a source
|
||||
/// </summary>
|
||||
/// <returns>A list of sink and source port ids that are linked together</returns>
|
||||
public HashSet<(string source, string sink)> GetLinks(EntityUid sourceUid, EntityUid sinkUid, DeviceLinkSourceComponent? sourceComponent = null)
|
||||
public HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)> GetLinks(EntityUid sourceUid, EntityUid sinkUid, DeviceLinkSourceComponent? sourceComponent = null)
|
||||
{
|
||||
if (!Resolve(sourceUid, ref sourceComponent) || !sourceComponent.LinkedPorts.TryGetValue(sinkUid, out var links))
|
||||
return new HashSet<(string source, string sink)>();
|
||||
return new HashSet<(ProtoId<SourcePortPrototype>, ProtoId<SinkPortPrototype>)>();
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.DeviceNetwork;
|
||||
@@ -30,12 +31,18 @@ public sealed class DeviceLinkUserInterfaceState : BoundUserInterfaceState
|
||||
{
|
||||
public readonly List<SourcePortPrototype> Sources;
|
||||
public readonly List<SinkPortPrototype> Sinks;
|
||||
public readonly HashSet<(string source, string sink)> Links;
|
||||
public readonly HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)> Links;
|
||||
public readonly List<(string source, string sink)>? Defaults;
|
||||
public readonly string SourceAddress;
|
||||
public readonly string SinkAddress;
|
||||
|
||||
public DeviceLinkUserInterfaceState(List<SourcePortPrototype> sources, List<SinkPortPrototype> sinks, HashSet<(string source, string sink)> links, string sourceAddress, string sinkAddress, List<(string source, string sink)>? defaults = default)
|
||||
public DeviceLinkUserInterfaceState(
|
||||
List<SourcePortPrototype> sources,
|
||||
List<SinkPortPrototype> sinks,
|
||||
HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)> links,
|
||||
string sourceAddress,
|
||||
string sinkAddress,
|
||||
List<(string source, string sink)>? defaults = default)
|
||||
{
|
||||
Links = links;
|
||||
SourceAddress = sourceAddress;
|
||||
|
||||
@@ -95,6 +95,8 @@
|
||||
- type: DeviceLinkSource
|
||||
ports:
|
||||
- DoorStatus
|
||||
lastSignals:
|
||||
DoorStatus: false
|
||||
- type: SoundOnOverload
|
||||
- type: SpawnOnOverload
|
||||
- type: UserInterface
|
||||
|
||||
@@ -90,6 +90,8 @@
|
||||
- type: DeviceLinkSource
|
||||
ports:
|
||||
- DoorStatus
|
||||
lastSignals:
|
||||
DoorStatus: false
|
||||
- type: InteractionPopup
|
||||
interactSuccessString: comp-window-knock
|
||||
messagePerceivedByOthers: comp-window-knock
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
- type: DeviceLinkSource
|
||||
ports:
|
||||
- DoorStatus
|
||||
lastSignals:
|
||||
DoorStatus: false
|
||||
- type: Damageable
|
||||
damageContainer: Inorganic
|
||||
damageModifierSet: Glass
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
- AirDanger
|
||||
- AirWarning
|
||||
- AirNormal
|
||||
lastSignals:
|
||||
AirDanger: false
|
||||
AirWarning: false
|
||||
AirNormal: false
|
||||
- type: AtmosAlarmable
|
||||
syncWith:
|
||||
- AirAlarm
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
- On
|
||||
- Off
|
||||
- Status
|
||||
lastSignals:
|
||||
Status: false
|
||||
|
||||
- type: entity
|
||||
id: SignalButton
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
- type: DeviceLinkSource
|
||||
ports:
|
||||
- Output
|
||||
lastSignals:
|
||||
Output: false
|
||||
- type: Construction
|
||||
graph: LogicGate
|
||||
node: logic_gate
|
||||
@@ -65,6 +67,9 @@
|
||||
ports:
|
||||
- OutputHigh
|
||||
- OutputLow
|
||||
lastSignals:
|
||||
OutputHigh: false
|
||||
OutputLow: false
|
||||
- type: Construction
|
||||
graph: LogicGate
|
||||
node: edge_detector
|
||||
@@ -108,6 +113,9 @@
|
||||
ports:
|
||||
- PowerCharging
|
||||
- PowerDischarging
|
||||
lastSignals:
|
||||
PowerCharging: false
|
||||
PowerDischarging: false
|
||||
- type: Construction
|
||||
graph: LogicGate
|
||||
node: power_sensor
|
||||
|
||||
Reference in New Issue
Block a user