]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Rejig device link sink & source startup & shutdown (#29035)
authorLeon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Wed, 19 Jun 2024 15:03:32 +0000 (03:03 +1200)
committerGitHub <noreply@github.com>
Wed, 19 Jun 2024 15:03:32 +0000 (01:03 +1000)
* Fix DeviceLinkSinkComponent not updating sources on shutdown

* Log error

* Misc link changes & fixes

* Fix core

Content.Shared/DeviceLinking/DeviceLinkSinkComponent.cs
Content.Shared/DeviceLinking/DeviceLinkSourceComponent.cs
Content.Shared/DeviceLinking/SharedDeviceLinkSystem.cs
Resources/Maps/core.yml

index a66431e68ae635120d9ae578115fc8e7f95b03b6..5d901b3fa68b4e0a2d7094755f540c3bd6899192 100644 (file)
@@ -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
     /// <summary>
     /// The ports this sink has
     /// </summary>
-    [DataField("ports", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<SinkPortPrototype>))]
-    public HashSet<string>? Ports;
+    [DataField]
+    public HashSet<ProtoId<SinkPortPrototype>> Ports = new();
 
     /// <summary>
-    /// 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.
     /// </summary>
-    [DataField("links")]
+    [ViewVariables]
     public HashSet<EntityUid> LinkedSources = new();
 
     /// <summary>
@@ -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
     /// </summary>
-    [DataField("invokeCounter")]
+    [DataField]
     public int InvokeCounter;
 
     /// <summary>
     /// 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
     /// </summary>
-    [ViewVariables(VVAccess.ReadWrite)]
-    [DataField("invokeLimit")]
+    [DataField]
     public int InvokeLimit = 10;
 }
index 332eff23cb2df688b4c88ca3b445864613da3d89..856dc91acdc7b68ed5ebf05b1101e970b0fd8fb4 100644 (file)
@@ -12,12 +12,12 @@ public sealed partial class DeviceLinkSourceComponent : Component
     /// The ports the device link source sends signals from
     /// </summary>
     [DataField]
-    public HashSet<ProtoId<SourcePortPrototype>>? Ports;
+    public HashSet<ProtoId<SourcePortPrototype>> Ports = new();
 
     /// <summary>
-    /// A list of sink uids that got linked for each port
+    /// Dictionary mapping each port to a set of linked sink entities.
     /// </summary>
-    [ViewVariables]
+    [ViewVariables] // This is not serialized as it can be constructed from LinkedPorts
     public Dictionary<ProtoId<SourcePortPrototype>, HashSet<EntityUid>> Outputs = new();
 
     /// <summary>
@@ -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
     /// </summary>
     [DataField]
-    public Dictionary<EntityUid, HashSet<(ProtoId<SourcePortPrototype> source, ProtoId<SinkPortPrototype> sink)>> LinkedPorts = new();
+    public Dictionary<EntityUid, HashSet<(ProtoId<SourcePortPrototype> Source, ProtoId<SinkPortPrototype> Sink)>> LinkedPorts = new();
 
     /// <summary>
     ///     Limits the range devices can be linked across.
index 79a32268e803bd936356ec47e445eec6e4f83fb4..3f969684b64f7d47552d5e17ec621bf6a83a1758 100644 (file)
@@ -20,98 +20,56 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
     /// <inheritdoc/>
     public override void Initialize()
     {
-        SubscribeLocalEvent<DeviceLinkSourceComponent, ComponentInit>(OnInit);
         SubscribeLocalEvent<DeviceLinkSourceComponent, ComponentStartup>(OnSourceStartup);
-        SubscribeLocalEvent<DeviceLinkSinkComponent, ComponentStartup>(OnSinkStartup);
         SubscribeLocalEvent<DeviceLinkSourceComponent, ComponentRemove>(OnSourceRemoved);
         SubscribeLocalEvent<DeviceLinkSinkComponent, ComponentRemove>(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);
-            }
-        }
-    }
-
     /// <summary>
     /// Removes invalid links where the saved sink doesn't exist/have a sink component for example
     /// </summary>
-    private void OnSourceStartup(EntityUid sourceUid, DeviceLinkSourceComponent sourceComponent, ComponentStartup args)
+    private void OnSourceStartup(Entity<DeviceLinkSourceComponent> source, ref ComponentStartup args)
     {
         List<EntityUid> invalidSinks = new();
-        foreach (var sinkUid  in sourceComponent.LinkedPorts.Keys)
+        List<(string, string)> invalidLinks = new();
+        foreach (var (sink, links)  in source.Comp.LinkedPorts)
         {
-            if (!TryComp<DeviceLinkSinkComponent>(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);
-        }
-    }
-
-    /// <summary>
-    /// Same with <see cref="OnSourceStartup"/> but also checks that the saved ports are present on the sink
-    /// </summary>
-    private void OnSinkStartup(EntityUid sinkUid, DeviceLinkSinkComponent sinkComponent, ComponentStartup args)
-    {
-        List<EntityUid> invalidSources = new();
-        foreach (var sourceUid in sinkComponent.LinkedSources)
-        {
-            if (!TryComp<DeviceLinkSourceComponent>(sourceUid, out var sourceComponent))
+            foreach (var link in links)
             {
-                invalidSources.Add(sourceUid);
-                continue;
+                if (sinkComponent.Ports.Contains(link.Sink) && source.Comp.Ports.Contains(link.Source))
+                    source.Comp.Outputs.GetOrNew(link.Source).Add(sink);
+                else
+                    invalidLinks.Add(link);
             }
 
-            if (!sourceComponent.LinkedPorts.TryGetValue(sinkUid, out var linkedPorts))
+            foreach (var link in invalidLinks)
             {
-                foreach (var savedSinks in sourceComponent.Outputs.Values)
-                {
-                    savedSinks.Remove(sinkUid);
-                }
-                continue;
+                Log.Warning($"Device source {ToPrettyString(source)} contains invalid links to entity {ToPrettyString(sink)}: {link.Item1}->{link.Item2}");
+                links.Remove(link);
             }
 
-            if (sinkComponent.Ports == null)
-                continue;
-
-            List<(string, string)> invalidLinks = new();
-            foreach (var link in linkedPorts)
+            if (links.Count == 0)
             {
-                if (!sinkComponent.Ports.Contains(link.sink))
-                    invalidLinks.Add(link);
+                invalidSinks.Add(sink);
+                continue;
             }
 
-            foreach (var invalidLink in invalidLinks)
-            {
-                linkedPorts.Remove(invalidLink);
-                sourceComponent.Outputs.GetValueOrDefault(invalidLink.Item1)?.Remove(sinkUid);
-            }
+            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
     /// <summary>
     /// Ensures that its links get deleted when a source gets removed
     /// </summary>
-    private void OnSourceRemoved(EntityUid uid, DeviceLinkSourceComponent component, ComponentRemove args)
+    private void OnSourceRemoved(Entity<DeviceLinkSourceComponent> source, ref ComponentRemove args)
     {
         var query = GetEntityQuery<DeviceLinkSinkComponent>();
-        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)}");
         }
     }
 
     /// <summary>
     /// Ensures that its links get deleted when a sink gets removed
     /// </summary>
-    private void OnSinkRemoved(EntityUid sinkUid, DeviceLinkSinkComponent sinkComponent, ComponentRemove args)
+    private void OnSinkRemoved(Entity<DeviceLinkSinkComponent> sink, ref ComponentRemove args)
     {
-        var query = GetEntityQuery<DeviceLinkSourceComponent>();
-        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
     /// <summary>
     /// Convenience function to add several ports to an entity
     /// </summary>
-    public void EnsureSourcePorts(EntityUid uid, params string[] ports)
+    public void EnsureSourcePorts(EntityUid uid, params ProtoId<SourcePortPrototype>[] ports)
     {
         if (ports.Length == 0)
             return;
 
         var comp = EnsureComp<DeviceLinkSourceComponent>(uid);
-        comp.Ports ??= new HashSet<ProtoId<SourcePortPrototype>>();
-
         foreach (var port in ports)
         {
-            DebugTools.Assert(_prototypeManager.HasIndex<SourcePortPrototype>(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);
         }
     }
 
     /// <summary>
     /// Convenience function to add several ports to an entity.
     /// </summary>
-    public void EnsureSinkPorts(EntityUid uid, params string[] ports)
+    public void EnsureSinkPorts(EntityUid uid, params ProtoId<SinkPortPrototype>[] ports)
     {
         if (ports.Length == 0)
             return;
 
         var comp = EnsureComp<DeviceLinkSinkComponent>(uid);
-        comp.Ports ??= new HashSet<string>();
-
         foreach (var port in ports)
         {
-            DebugTools.Assert(_prototypeManager.HasIndex<SinkPortPrototype>(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
     /// <returns>A list of source port prototypes</returns>
     public List<SourcePortPrototype> GetSourcePorts(EntityUid sourceUid, DeviceLinkSourceComponent? sourceComponent = null)
     {
-        if (!Resolve(sourceUid, ref sourceComponent) || sourceComponent.Ports == null)
+        if (!Resolve(sourceUid, ref sourceComponent))
             return new List<SourcePortPrototype>();
 
         var sourcePorts = new List<SourcePortPrototype>();
         foreach (var port in sourceComponent.Ports)
         {
-            sourcePorts.Add(_prototypeManager.Index<SourcePortPrototype>(port));
+            sourcePorts.Add(_prototypeManager.Index(port));
         }
 
         return sourcePorts;
@@ -203,13 +164,13 @@ public abstract class SharedDeviceLinkSystem : EntitySystem
     /// <returns>A list of sink port prototypes</returns>
     public List<SinkPortPrototype> GetSinkPorts(EntityUid sinkUid, DeviceLinkSinkComponent? sinkComponent = null)
     {
-        if (!Resolve(sinkUid, ref sinkComponent) || sinkComponent.Ports == null)
+        if (!Resolve(sinkUid, ref sinkComponent))
             return new List<SinkPortPrototype>();
 
         var sinkPorts = new List<SinkPortPrototype>();
         foreach (var port in sinkComponent.Ports)
         {
-            sinkPorts.Add(_prototypeManager.Index<SinkPortPrototype>(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);
         }
-
     }
 
     /// <summary>
@@ -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);
 
index 48ee0290fa219cad4d7ec1541d7cd21b2b5eb7ba..09bb60c4eb984e9e1f171e340c502d245553987e 100644 (file)
@@ -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