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;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.NetworkConfigurator;
|
namespace Content.Client.NetworkConfigurator;
|
||||||
|
|
||||||
@@ -160,7 +161,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private sealed class LinksRender : Control
|
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> SourceButtons = new();
|
||||||
public readonly Dictionary<string, Button> SinkButtons = new();
|
public readonly Dictionary<string, Button> SinkButtons = new();
|
||||||
private readonly BoxContainer _leftButtonContainer;
|
private readonly BoxContainer _leftButtonContainer;
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
using Content.Server.DeviceLinking.Components;
|
using Content.Server.DeviceLinking.Components;
|
||||||
using Content.Server.DeviceLinking.Events;
|
using Content.Server.DeviceLinking.Events;
|
||||||
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.Shared.DeviceLinking;
|
using Content.Shared.DeviceLinking;
|
||||||
|
using Content.Shared.DeviceLinking.Events;
|
||||||
using Content.Shared.DeviceNetwork;
|
using Content.Shared.DeviceNetwork;
|
||||||
|
|
||||||
namespace Content.Server.DeviceLinking.Systems;
|
namespace Content.Server.DeviceLinking.Systems;
|
||||||
@@ -15,7 +16,9 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
|||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<DeviceLinkSinkComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
SubscribeLocalEvent<DeviceLinkSinkComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
|
||||||
|
SubscribeLocalEvent<DeviceLinkSourceComponent, NewLinkEvent>(OnNewLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
@@ -51,32 +54,42 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
|||||||
|
|
||||||
foreach (var (source, sink) in links)
|
foreach (var (source, sink) in links)
|
||||||
{
|
{
|
||||||
if (source != port)
|
if (source == port)
|
||||||
continue;
|
InvokeDirect((uid, sourceComponent), (sinkUid, sinkComponent), source, sink, data);
|
||||||
|
}
|
||||||
if (sinkComponent.InvokeCounter > sinkComponent.InvokeLimit)
|
}
|
||||||
{
|
|
||||||
sinkComponent.InvokeCounter = 0;
|
|
||||||
var args = new DeviceLinkOverloadedEvent();
|
|
||||||
RaiseLocalEvent(sinkUid, ref args);
|
|
||||||
RemoveAllFromSink(sinkUid, sinkComponent);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
//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);
|
var eventArgs = new SignalReceivedEvent(sinkPort, source);
|
||||||
|
RaiseLocalEvent(sink, ref eventArgs);
|
||||||
RaiseLocalEvent(sinkUid, ref eventArgs);
|
return;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var payload = new NetworkPayload()
|
var payload = new NetworkPayload()
|
||||||
{
|
{
|
||||||
[InvokedPort] = sink
|
[InvokedPort] = sinkPort
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data != null)
|
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
|
// force using wireless network so things like atmos devices are able to send signals
|
||||||
var network = (int) DeviceNetworkComponent.DeviceNetIdDefaults.Wireless;
|
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>
|
/// <summary>
|
||||||
@@ -101,11 +112,29 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendSignal(EntityUid uid, string port, bool signal, DeviceLinkSourceComponent? comp = null)
|
public void SendSignal(EntityUid uid, string port, bool signal, DeviceLinkSourceComponent? comp = null)
|
||||||
{
|
{
|
||||||
|
if (!Resolve(uid, ref comp))
|
||||||
|
return;
|
||||||
|
|
||||||
var data = new NetworkPayload
|
var data = new NetworkPayload
|
||||||
{
|
{
|
||||||
[DeviceNetworkConstants.LogicState] = signal ? SignalState.High : SignalState.Low
|
[DeviceNetworkConstants.LogicState] = signal ? SignalState.High : SignalState.Low
|
||||||
};
|
};
|
||||||
InvokePort(uid, port, data, comp);
|
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>
|
/// <summary>
|
||||||
@@ -120,5 +149,24 @@ public sealed class DeviceLinkSystem : SharedDeviceLinkSystem
|
|||||||
var eventArgs = new SignalReceivedEvent(port, args.Sender, args.Data);
|
var eventArgs = new SignalReceivedEvent(port, args.Sender, args.Data);
|
||||||
RaiseLocalEvent(uid, ref eventArgs);
|
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
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,23 +85,18 @@ namespace Content.Server.DeviceLinking.Systems
|
|||||||
|
|
||||||
private void OnStateChanged(EntityUid uid, DoorSignalControlComponent door, DoorStateChangedEvent args)
|
private void OnStateChanged(EntityUid uid, DoorSignalControlComponent door, DoorStateChangedEvent args)
|
||||||
{
|
{
|
||||||
var data = new NetworkPayload()
|
|
||||||
{
|
|
||||||
{ DeviceNetworkConstants.LogicState, SignalState.Momentary }
|
|
||||||
};
|
|
||||||
|
|
||||||
if (args.State == DoorState.Closed)
|
if (args.State == DoorState.Closed)
|
||||||
{
|
{
|
||||||
data[DeviceNetworkConstants.LogicState] = SignalState.Low;
|
// only ever say the door is closed when it is completely airtight
|
||||||
_signalSystem.InvokePort(uid, door.OutOpen, data);
|
_signalSystem.SendSignal(uid, door.OutOpen, false);
|
||||||
}
|
}
|
||||||
else if (args.State == DoorState.Open
|
else if (args.State == DoorState.Open
|
||||||
|| args.State == DoorState.Opening
|
|| args.State == DoorState.Opening
|
||||||
|| args.State == DoorState.Closing
|
|| args.State == DoorState.Closing
|
||||||
|| args.State == DoorState.Emagging)
|
|| args.State == DoorState.Emagging)
|
||||||
{
|
{
|
||||||
data[DeviceNetworkConstants.LogicState] = SignalState.High;
|
// say the door is open whenever it would be letting air pass
|
||||||
_signalSystem.InvokePort(uid, door.OutOpen, data);
|
_signalSystem.SendSignal(uid, door.OutOpen, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Shared.DeviceLinking;
|
namespace Content.Shared.DeviceLinking;
|
||||||
|
|
||||||
@@ -11,25 +11,32 @@ public sealed partial class DeviceLinkSourceComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The ports the device link source sends signals from
|
/// The ports the device link source sends signals from
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("ports", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<SourcePortPrototype>))]
|
[DataField]
|
||||||
public HashSet<string>? Ports;
|
public HashSet<ProtoId<SourcePortPrototype>>? Ports;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of sink uids that got linked for each port
|
/// A list of sink uids that got linked for each port
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables]
|
[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>
|
/// <summary>
|
||||||
/// The list of source to sink ports for each linked sink entity for easier managing of links
|
/// The list of source to sink ports for each linked sink entity for easier managing of links
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("linkedPorts")]
|
[DataField]
|
||||||
public Dictionary<EntityUid, HashSet<(string source, string sink)>> LinkedPorts = new();
|
public Dictionary<EntityUid, HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)>> LinkedPorts = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Limits the range devices can be linked across.
|
/// Limits the range devices can be linked across.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("range")]
|
[DataField]
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public float Range = 30f;
|
public float Range = 30f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var comp = EnsureComp<DeviceLinkSourceComponent>(uid);
|
var comp = EnsureComp<DeviceLinkSourceComponent>(uid);
|
||||||
comp.Ports ??= new HashSet<string>();
|
comp.Ports ??= new HashSet<ProtoId<SourcePortPrototype>>();
|
||||||
|
|
||||||
foreach (var port in ports)
|
foreach (var port in ports)
|
||||||
{
|
{
|
||||||
@@ -233,10 +233,10 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
|
|||||||
/// Returns the links of a source
|
/// Returns the links of a source
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A list of sink and source port ids that are linked together</returns>
|
/// <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))
|
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;
|
return links;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.DeviceLinking;
|
using Content.Shared.DeviceLinking;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.DeviceNetwork;
|
namespace Content.Shared.DeviceNetwork;
|
||||||
@@ -30,12 +31,18 @@ public sealed class DeviceLinkUserInterfaceState : BoundUserInterfaceState
|
|||||||
{
|
{
|
||||||
public readonly List<SourcePortPrototype> Sources;
|
public readonly List<SourcePortPrototype> Sources;
|
||||||
public readonly List<SinkPortPrototype> Sinks;
|
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 List<(string source, string sink)>? Defaults;
|
||||||
public readonly string SourceAddress;
|
public readonly string SourceAddress;
|
||||||
public readonly string SinkAddress;
|
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;
|
Links = links;
|
||||||
SourceAddress = sourceAddress;
|
SourceAddress = sourceAddress;
|
||||||
|
|||||||
@@ -95,6 +95,8 @@
|
|||||||
- type: DeviceLinkSource
|
- type: DeviceLinkSource
|
||||||
ports:
|
ports:
|
||||||
- DoorStatus
|
- DoorStatus
|
||||||
|
lastSignals:
|
||||||
|
DoorStatus: false
|
||||||
- type: SoundOnOverload
|
- type: SoundOnOverload
|
||||||
- type: SpawnOnOverload
|
- type: SpawnOnOverload
|
||||||
- type: UserInterface
|
- type: UserInterface
|
||||||
|
|||||||
@@ -90,6 +90,8 @@
|
|||||||
- type: DeviceLinkSource
|
- type: DeviceLinkSource
|
||||||
ports:
|
ports:
|
||||||
- DoorStatus
|
- DoorStatus
|
||||||
|
lastSignals:
|
||||||
|
DoorStatus: false
|
||||||
- type: InteractionPopup
|
- type: InteractionPopup
|
||||||
interactSuccessString: comp-window-knock
|
interactSuccessString: comp-window-knock
|
||||||
messagePerceivedByOthers: comp-window-knock
|
messagePerceivedByOthers: comp-window-knock
|
||||||
|
|||||||
@@ -59,6 +59,8 @@
|
|||||||
- type: DeviceLinkSource
|
- type: DeviceLinkSource
|
||||||
ports:
|
ports:
|
||||||
- DoorStatus
|
- DoorStatus
|
||||||
|
lastSignals:
|
||||||
|
DoorStatus: false
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
damageContainer: Inorganic
|
damageContainer: Inorganic
|
||||||
damageModifierSet: Glass
|
damageModifierSet: Glass
|
||||||
|
|||||||
@@ -30,6 +30,10 @@
|
|||||||
- AirDanger
|
- AirDanger
|
||||||
- AirWarning
|
- AirWarning
|
||||||
- AirNormal
|
- AirNormal
|
||||||
|
lastSignals:
|
||||||
|
AirDanger: false
|
||||||
|
AirWarning: false
|
||||||
|
AirNormal: false
|
||||||
- type: AtmosAlarmable
|
- type: AtmosAlarmable
|
||||||
syncWith:
|
syncWith:
|
||||||
- AirAlarm
|
- AirAlarm
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
- On
|
- On
|
||||||
- Off
|
- Off
|
||||||
- Status
|
- Status
|
||||||
|
lastSignals:
|
||||||
|
Status: false
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: SignalButton
|
id: SignalButton
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
- type: DeviceLinkSource
|
- type: DeviceLinkSource
|
||||||
ports:
|
ports:
|
||||||
- Output
|
- Output
|
||||||
|
lastSignals:
|
||||||
|
Output: false
|
||||||
- type: Construction
|
- type: Construction
|
||||||
graph: LogicGate
|
graph: LogicGate
|
||||||
node: logic_gate
|
node: logic_gate
|
||||||
@@ -65,6 +67,9 @@
|
|||||||
ports:
|
ports:
|
||||||
- OutputHigh
|
- OutputHigh
|
||||||
- OutputLow
|
- OutputLow
|
||||||
|
lastSignals:
|
||||||
|
OutputHigh: false
|
||||||
|
OutputLow: false
|
||||||
- type: Construction
|
- type: Construction
|
||||||
graph: LogicGate
|
graph: LogicGate
|
||||||
node: edge_detector
|
node: edge_detector
|
||||||
@@ -108,6 +113,9 @@
|
|||||||
ports:
|
ports:
|
||||||
- PowerCharging
|
- PowerCharging
|
||||||
- PowerDischarging
|
- PowerDischarging
|
||||||
|
lastSignals:
|
||||||
|
PowerCharging: false
|
||||||
|
PowerDischarging: false
|
||||||
- type: Construction
|
- type: Construction
|
||||||
graph: LogicGate
|
graph: LogicGate
|
||||||
node: power_sensor
|
node: power_sensor
|
||||||
|
|||||||
Reference in New Issue
Block a user