diff --git a/Content.Shared/DeviceLinking/DeviceLinkSinkComponent.cs b/Content.Shared/DeviceLinking/DeviceLinkSinkComponent.cs index a66431e68a..5d901b3fa6 100644 --- a/Content.Shared/DeviceLinking/DeviceLinkSinkComponent.cs +++ b/Content.Shared/DeviceLinking/DeviceLinkSinkComponent.cs @@ -1,4 +1,5 @@ using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; namespace Content.Shared.DeviceLinking; @@ -11,13 +12,14 @@ public sealed partial class DeviceLinkSinkComponent : Component /// /// The ports this sink has /// - [DataField("ports", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))] - public HashSet? Ports; + [DataField] + public HashSet> Ports = new(); /// - /// Used for removing a sink from all linked sources when it gets removed + /// Used for removing a sink from all linked sources when this component gets removed. + /// This is not serialized to yaml as it can be inferred from source components. /// - [DataField("links")] + [ViewVariables] public HashSet LinkedSources = new(); /// @@ -25,14 +27,13 @@ public sealed partial class DeviceLinkSinkComponent : Component /// The counter is counted down by one every tick if it's higher than 0 /// This is for preventing infinite loops /// - [DataField("invokeCounter")] + [DataField] public int InvokeCounter; /// /// How high the invoke counter is allowed to get before the links to the sink are removed and the DeviceLinkOverloadedEvent gets raised /// If the invoke limit is smaller than 1 the sink can't overload /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("invokeLimit")] + [DataField] public int InvokeLimit = 10; } diff --git a/Content.Shared/DeviceLinking/DeviceLinkSourceComponent.cs b/Content.Shared/DeviceLinking/DeviceLinkSourceComponent.cs index 332eff23cb..856dc91acd 100644 --- a/Content.Shared/DeviceLinking/DeviceLinkSourceComponent.cs +++ b/Content.Shared/DeviceLinking/DeviceLinkSourceComponent.cs @@ -12,12 +12,12 @@ public sealed partial class DeviceLinkSourceComponent : Component /// The ports the device link source sends signals from /// [DataField] - public HashSet>? Ports; + public HashSet> Ports = new(); /// - /// A list of sink uids that got linked for each port + /// Dictionary mapping each port to a set of linked sink entities. /// - [ViewVariables] + [ViewVariables] // This is not serialized as it can be constructed from LinkedPorts public Dictionary, HashSet> Outputs = new(); /// @@ -32,7 +32,7 @@ public sealed partial class DeviceLinkSourceComponent : Component /// The list of source to sink ports for each linked sink entity for easier managing of links /// [DataField] - public Dictionary source, ProtoId sink)>> LinkedPorts = new(); + public Dictionary Source, ProtoId Sink)>> LinkedPorts = new(); /// /// Limits the range devices can be linked across. diff --git a/Content.Shared/DeviceLinking/SharedDeviceLinkSystem.cs b/Content.Shared/DeviceLinking/SharedDeviceLinkSystem.cs index 79a32268e8..3f969684b6 100644 --- a/Content.Shared/DeviceLinking/SharedDeviceLinkSystem.cs +++ b/Content.Shared/DeviceLinking/SharedDeviceLinkSystem.cs @@ -20,98 +20,56 @@ public abstract class SharedDeviceLinkSystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnSourceStartup); - SubscribeLocalEvent(OnSinkStartup); SubscribeLocalEvent(OnSourceRemoved); SubscribeLocalEvent(OnSinkRemoved); } #region Link Validation - private void OnInit(EntityUid uid, DeviceLinkSourceComponent component, ComponentInit args) - { - // Populate the output dictionary. - foreach (var (sinkUid, links) in component.LinkedPorts) - { - foreach (var link in links) - { - component.Outputs.GetOrNew(link.source).Add(sinkUid); - } - } - } - /// /// Removes invalid links where the saved sink doesn't exist/have a sink component for example /// - private void OnSourceStartup(EntityUid sourceUid, DeviceLinkSourceComponent sourceComponent, ComponentStartup args) + private void OnSourceStartup(Entity source, ref ComponentStartup args) { List invalidSinks = new(); - foreach (var sinkUid in sourceComponent.LinkedPorts.Keys) + List<(string, string)> invalidLinks = new(); + foreach (var (sink, links) in source.Comp.LinkedPorts) { - if (!TryComp(sinkUid, out var sinkComponent)) + if (!TryComp(sink, out DeviceLinkSinkComponent? sinkComponent)) { - invalidSinks.Add(sinkUid); - foreach (var savedSinks in sourceComponent.Outputs.Values) - { - savedSinks.Remove(sinkUid); - } - + invalidSinks.Add(sink); continue; } - sinkComponent.LinkedSources.Add(sourceUid); - } - - foreach (var invalidSink in invalidSinks) - { - sourceComponent.LinkedPorts.Remove(invalidSink); - } - } - - /// - /// Same with but also checks that the saved ports are present on the sink - /// - private void OnSinkStartup(EntityUid sinkUid, DeviceLinkSinkComponent sinkComponent, ComponentStartup args) - { - List invalidSources = new(); - foreach (var sourceUid in sinkComponent.LinkedSources) - { - if (!TryComp(sourceUid, out var sourceComponent)) + foreach (var link in links) { - invalidSources.Add(sourceUid); - continue; - } - - if (!sourceComponent.LinkedPorts.TryGetValue(sinkUid, out var linkedPorts)) - { - foreach (var savedSinks in sourceComponent.Outputs.Values) - { - savedSinks.Remove(sinkUid); - } - continue; - } - - if (sinkComponent.Ports == null) - continue; - - List<(string, string)> invalidLinks = new(); - foreach (var link in linkedPorts) - { - if (!sinkComponent.Ports.Contains(link.sink)) + if (sinkComponent.Ports.Contains(link.Sink) && source.Comp.Ports.Contains(link.Source)) + source.Comp.Outputs.GetOrNew(link.Source).Add(sink); + else invalidLinks.Add(link); } - foreach (var invalidLink in invalidLinks) + foreach (var link in invalidLinks) { - linkedPorts.Remove(invalidLink); - sourceComponent.Outputs.GetValueOrDefault(invalidLink.Item1)?.Remove(sinkUid); + Log.Warning($"Device source {ToPrettyString(source)} contains invalid links to entity {ToPrettyString(sink)}: {link.Item1}->{link.Item2}"); + links.Remove(link); } + + if (links.Count == 0) + { + invalidSinks.Add(sink); + continue; + } + + invalidLinks.Clear(); + sinkComponent.LinkedSources.Add(source.Owner); } - foreach (var invalidSource in invalidSources) + foreach (var sink in invalidSinks) { - sinkComponent.LinkedSources.Remove(invalidSource); + source.Comp.LinkedPorts.Remove(sink); + Log.Warning($"Device source {ToPrettyString(source)} contains invalid sink: {ToPrettyString(sink)}"); } } #endregion @@ -119,26 +77,29 @@ public abstract class SharedDeviceLinkSystem : EntitySystem /// /// Ensures that its links get deleted when a source gets removed /// - private void OnSourceRemoved(EntityUid uid, DeviceLinkSourceComponent component, ComponentRemove args) + private void OnSourceRemoved(Entity source, ref ComponentRemove args) { var query = GetEntityQuery(); - foreach (var sinkUid in component.LinkedPorts.Keys) + foreach (var sinkUid in source.Comp.LinkedPorts.Keys) { if (query.TryGetComponent(sinkUid, out var sink)) - RemoveSinkFromSourceInternal(uid, sinkUid, component, sink); + RemoveSinkFromSourceInternal(source, sinkUid, source, sink); + else + Log.Error($"Device source {ToPrettyString(source)} links to invalid entity: {ToPrettyString(sinkUid)}"); } } /// /// Ensures that its links get deleted when a sink gets removed /// - private void OnSinkRemoved(EntityUid sinkUid, DeviceLinkSinkComponent sinkComponent, ComponentRemove args) + private void OnSinkRemoved(Entity sink, ref ComponentRemove args) { - var query = GetEntityQuery(); - foreach (var linkedSource in sinkComponent.LinkedSources) + foreach (var sourceUid in sink.Comp.LinkedSources) { - if (query.TryGetComponent(sinkUid, out var source)) - RemoveSinkFromSourceInternal(linkedSource, sinkUid, source, sinkComponent); + if (TryComp(sourceUid, out DeviceLinkSourceComponent? source)) + RemoveSinkFromSourceInternal(sourceUid, sink, source, sink); + else + Log.Error($"Device sink {ToPrettyString(sink)} source list contains invalid entity: {ToPrettyString(sourceUid)}"); } } @@ -146,36 +107,36 @@ public abstract class SharedDeviceLinkSystem : EntitySystem /// /// Convenience function to add several ports to an entity /// - public void EnsureSourcePorts(EntityUid uid, params string[] ports) + public void EnsureSourcePorts(EntityUid uid, params ProtoId[] ports) { if (ports.Length == 0) return; var comp = EnsureComp(uid); - comp.Ports ??= new HashSet>(); - foreach (var port in ports) { - DebugTools.Assert(_prototypeManager.HasIndex(port)); - comp.Ports?.Add(port); + if (!_prototypeManager.HasIndex(port)) + Log.Error($"Attempted to add invalid port {port} to {ToPrettyString(uid)}"); + else + comp.Ports.Add(port); } } /// /// Convenience function to add several ports to an entity. /// - public void EnsureSinkPorts(EntityUid uid, params string[] ports) + public void EnsureSinkPorts(EntityUid uid, params ProtoId[] ports) { if (ports.Length == 0) return; var comp = EnsureComp(uid); - comp.Ports ??= new HashSet(); - foreach (var port in ports) { - DebugTools.Assert(_prototypeManager.HasIndex(port)); - comp.Ports?.Add(port); + if (!_prototypeManager.HasIndex(port)) + Log.Error($"Attempted to add invalid port {port} to {ToPrettyString(uid)}"); + else + comp.Ports.Add(port); } } @@ -185,13 +146,13 @@ public abstract class SharedDeviceLinkSystem : EntitySystem /// A list of source port prototypes public List GetSourcePorts(EntityUid sourceUid, DeviceLinkSourceComponent? sourceComponent = null) { - if (!Resolve(sourceUid, ref sourceComponent) || sourceComponent.Ports == null) + if (!Resolve(sourceUid, ref sourceComponent)) return new List(); var sourcePorts = new List(); foreach (var port in sourceComponent.Ports) { - sourcePorts.Add(_prototypeManager.Index(port)); + sourcePorts.Add(_prototypeManager.Index(port)); } return sourcePorts; @@ -203,13 +164,13 @@ public abstract class SharedDeviceLinkSystem : EntitySystem /// A list of sink port prototypes public List GetSinkPorts(EntityUid sinkUid, DeviceLinkSinkComponent? sinkComponent = null) { - if (!Resolve(sinkUid, ref sinkComponent) || sinkComponent.Ports == null) + if (!Resolve(sinkUid, ref sinkComponent)) return new List(); var sinkPorts = new List(); foreach (var port in sinkComponent.Ports) { - sinkPorts.Add(_prototypeManager.Index(port)); + sinkPorts.Add(_prototypeManager.Index(port)); } return sinkPorts; @@ -315,9 +276,6 @@ public abstract class SharedDeviceLinkSystem : EntitySystem if (!Resolve(sourceUid, ref sourceComponent) || !Resolve(sinkUid, ref sinkComponent)) return; - if (sourceComponent.Ports == null || sinkComponent.Ports == null) - return; - if (!InRange(sourceUid, sinkUid, sourceComponent.Range)) { if (userId != null) @@ -391,7 +349,7 @@ public abstract class SharedDeviceLinkSystem : EntitySystem else { Log.Error($"Attempted to remove link between {ToPrettyString(sourceUid)} and {ToPrettyString(sinkUid)}, but the sink component was missing."); - sourceComponent.LinkedPorts.Remove(sourceUid); + sourceComponent.LinkedPorts.Remove(sinkUid); } } @@ -414,12 +372,10 @@ public abstract class SharedDeviceLinkSystem : EntitySystem sinkComponent.LinkedSources.Remove(sourceUid); sourceComponent.LinkedPorts.Remove(sinkUid); - var outputLists = sourceComponent.Outputs.Values; - foreach (var outputList in outputLists) + foreach (var outputList in sourceComponent.Outputs.Values) { outputList.Remove(sinkUid); } - } /// @@ -438,9 +394,6 @@ public abstract class SharedDeviceLinkSystem : EntitySystem if (!Resolve(sourceUid, ref sourceComponent) || !Resolve(sinkUid, ref sinkComponent)) return false; - if (sourceComponent.Ports == null || sinkComponent.Ports == null) - return false; - var outputs = sourceComponent.Outputs.GetOrNew(source); var linkedPorts = sourceComponent.LinkedPorts.GetOrNew(sinkUid); diff --git a/Resources/Maps/core.yml b/Resources/Maps/core.yml index 48ee0290fa..09bb60c4eb 100644 --- a/Resources/Maps/core.yml +++ b/Resources/Maps/core.yml @@ -115412,9 +115412,6 @@ entities: rot: 3.141592653589793 rad pos: 50.5,-2.5 parent: 2 - - type: DeviceLinkSource - linkedPorts: - 6516: [] - proto: SignalButtonDirectional entities: - uid: 2100