From 78e4f01b576a63498bd5299f12662cdf487d97e3 Mon Sep 17 00:00:00 2001 From: D4VID Date: Mon, 3 Mar 2025 20:51:21 +0100 Subject: [PATCH] Relay handling --- CriticalPathAnalyzer.sln.DotSettings | 2 + .../CriticalPathAnalyzer/manifest.jecs | 2 +- .../src/client/tool/PathHighlighter.cs | 34 ---- .../src/server/tool/ServerPathTracer.cs | 191 +++++++++--------- .../shared/packets/s2c/AnalyzePathResponse.cs | 5 - 5 files changed, 98 insertions(+), 136 deletions(-) create mode 100644 CriticalPathAnalyzer.sln.DotSettings diff --git a/CriticalPathAnalyzer.sln.DotSettings b/CriticalPathAnalyzer.sln.DotSettings new file mode 100644 index 0000000..fb4dc8c --- /dev/null +++ b/CriticalPathAnalyzer.sln.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/manifest.jecs b/CriticalPathAnalyzer/CriticalPathAnalyzer/manifest.jecs index 84f0047..659fc76 100644 --- a/CriticalPathAnalyzer/CriticalPathAnalyzer/manifest.jecs +++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/manifest.jecs @@ -1,7 +1,7 @@ ID: CriticalPathAnalyzer Name: CriticalPathAnalyzer Author: D4VID -Version: 0.0.3 +Version: 0.0.4 Priority: 0 Dependencies: - HarmonyForLogicWorld diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/PathHighlighter.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/PathHighlighter.cs index 965ef4c..baa46e1 100644 --- a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/PathHighlighter.cs +++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/PathHighlighter.cs @@ -9,7 +9,6 @@ using LogicWorld.Outlines; namespace CriticalPathAnalyzer.Client.Tool { public class PathHighlighter { private static List _clusters = new List(); - private static List _highlightedComponents = new List(); private static List _highlightedWires = new List(); public static void HighlightWires(List clusters) { @@ -18,22 +17,6 @@ namespace CriticalPathAnalyzer.Client.Tool { foreach (ClusterDetails clusterDetails in _clusters) { HighlightCluster(clusterDetails); } - - // IWorldData world = Instances.MainWorld.Data; - - // foreach (ComponentAddress componentAddress in response.PerimeterComponents) { - // if (!world.Contains(componentAddress)) { - // continue; - // } - // - // Outliner.Outline(componentAddress, PerimeterColor); - // _highlightedComponents.Add(componentAddress); - // } - - // _clusters.AddRange(response.NextClusters); // add to the collection to unhighlight - // foreach (ClusterDetails clusterDetails in response.NextClusters) { - // HighlightCluster(clusterDetails, NextColor); - // } } /// @@ -52,14 +35,6 @@ namespace CriticalPathAnalyzer.Client.Tool { Outliner.Outline(address, outline); } - foreach (ComponentAddress address in cluster.LinkingComponents) { - if (!world.Contains(address)) { - continue; - } - - Outliner.Outline(address, outline); - } - foreach (PegAddress pegAddress in cluster.Pegs) { if (!world.Contains(pegAddress.ComponentAddress)) { continue; @@ -99,14 +74,9 @@ namespace CriticalPathAnalyzer.Client.Tool { foreach (WireAddress wireAddress in _highlightedWires) { Outliner.RemoveOutline(wireAddress); } - - foreach (ComponentAddress componentAddress in _highlightedComponents) { - Outliner.RemoveOutline(componentAddress); - } _clusters = null; _highlightedWires.Clear(); - _highlightedComponents.Clear(); } private static void UnhighlightCluster(ClusterDetails cluster) { @@ -117,10 +87,6 @@ namespace CriticalPathAnalyzer.Client.Tool { foreach (ComponentAddress address in cluster.ConnectingComponents) { Outliner.RemoveOutline(address); } - - foreach (ComponentAddress address in cluster.LinkingComponents) { - Outliner.RemoveOutline(address); - } } } } \ No newline at end of file diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/server/tool/ServerPathTracer.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/server/tool/ServerPathTracer.cs index 45cf0ed..bc5732a 100644 --- a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/server/tool/ServerPathTracer.cs +++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/server/tool/ServerPathTracer.cs @@ -8,15 +8,13 @@ using LogicAPI.Data; using LogicAPI.Server.Components; using LogicAPI.Services; using LogicLog; +using LogicWorld.LogicCode; using LogicWorld.Server.Circuitry; namespace CriticalPathAnalyzer.Server.Tool { public class ServerPathTracer { // Reflection/Delegate access helpers: private static readonly Func GetCluster; - private static readonly Func GetLinker; - - private static readonly Func> GetFollowers; // Services needed to lookup wires/pegs: private static readonly ICircuitryManager Circuits; @@ -26,12 +24,6 @@ namespace CriticalPathAnalyzer.Server.Tool { GetCluster = Delegator.createPropertyGetter( Properties.getPrivate(typeof(InputPeg), "Cluster") ); - GetLinker = Delegator.createFieldGetter( - Fields.getPrivate(typeof(Cluster), "Linker") - ); - GetFollowers = Delegator.createFieldGetter>( - Fields.getPrivate(typeof(ClusterLinker), "LinkedFollowers") - ); Circuits = ServiceGetter.getService(); World = ServiceGetter.getService(); @@ -62,10 +54,10 @@ namespace CriticalPathAnalyzer.Server.Tool { // An output peg however can be connected to multiple clusters. // It only makes sense to then select all these clusters as primary cluster. var startingClusters = new HashSet(); - CollectMainClusters(start, startingClusters); + CollectPegClusters(start, startingClusters); var endingClusters = new HashSet(); - CollectMainClusters(end, endingClusters); + CollectPegClusters(end, endingClusters); foreach (Cluster startingCluster in startingClusters) { // ignore already mapped clusters @@ -204,55 +196,112 @@ namespace CriticalPathAnalyzer.Server.Tool { // var perimeterComponents = new HashSet(); var collectedNextClusters = new HashSet(); + var collectedNextInstantClusters = new HashSet(); foreach (Cluster cluster in node.Clusters) { foreach (InputPeg inputPeg in cluster.ConnectedInputs) { - if (inputPeg.LogicComponent == null) { + LogicComponent component = inputPeg.LogicComponent; + if (component == null) { // These are regular pegs, they are not attached to any logic component, skip them continue; } - // perimeterComponents.Add(inputPeg.LogicComponent.Address); - foreach (IOutputPeg outputPeg in inputPeg.LogicComponent.Outputs) { - CollectMainClusters(outputPeg.Address, collectedNextClusters); + if (component.GetType() == typeof(Delayer)) { + // Special handling of the delayer + var delayer = (Delayer) component; + //TODO: delayer.Data.DelayLengthInTicks; + CollectPegClusters(delayer.Outputs[0].Address, collectedNextClusters); + } else if (component.GetType() == typeof(Relay)) { + // Collect all next clusters connected via a relay (from the control input side) + if (inputPeg.Address == component.Inputs[0].Address) { + // the top control input + CollectPegClusters(component.Inputs[1].Address, collectedNextClusters); + CollectPegClusters(component.Inputs[2].Address, collectedNextClusters); + } + } else { + // Collect all next cluster connected via normal components + foreach (IOutputPeg outputPeg in component.Outputs) { + CollectPegClusters(outputPeg.Address, collectedNextClusters); + } + + // Collect all next clusters connected via fast buffers + if (inputPeg.OneWayPhasicLinksFollowers != null) { + foreach (InputPeg followerPeg in inputPeg.OneWayPhasicLinksFollowers) { + CollectPegClusters(followerPeg.Address, collectedNextInstantClusters); + } + } } } } - foreach (Cluster nextCluster in collectedNextClusters) { - // ignore already mapped clusters - if (clusterToNodeMapping.TryGetValue(nextCluster, out int nextNodeIndex)) { - ClusterNode nextNode = clusterNodes[nextNodeIndex]; - // only add the link, don't propagate - nextNode.PrevNodeIndexes.Add(node.Index); - node.NextNodes.TryAdd(nextNodeIndex, 1); - } else { - // var nextClusters = new HashSet(); - // var twoWayConnectedClusters = new HashSet(); - // GetLinkedClusters(cluster, nextClusters, twoWayConnectedClusters, GetFollowers); - nextNodeIndex = clusterNodes.Count; - var nextNode = new ClusterNode() { - Index = nextNodeIndex, - Clusters = new HashSet() {nextCluster}, - Time = 0, - NextNodes = new Dictionary(), - PrevNodeIndexes = new HashSet() {node.Index}, - }; - - clusterNodes.Add(nextNode); - - node.NextNodes.TryAdd(nextNodeIndex, 1); - - foreach (Cluster nextNodeCluster in nextNode.Clusters) { - clusterToNodeMapping.Add(nextNodeCluster, nextNodeIndex); - } + LinkNextClusters(queue, clusterToNodeMapping, clusterNodes, collectedNextInstantClusters, node, 0); + LinkNextClusters(queue, clusterToNodeMapping, clusterNodes, collectedNextClusters, node, 1); + } - // propagate - queue.Enqueue(nextNode); + logger.Info($"Finished after {iterations} iterations"); + } + + private static HashSet GetClustersConnectedThroughRelays(Cluster cluster) { + var clusters = new HashSet() {cluster}; + foreach (InputPeg inputPeg in cluster.ConnectedInputs) { + LogicComponent component = inputPeg.LogicComponent; + if (component == null) { + // These are regular pegs, they are not attached to any logic component, skip them + continue; + } + + if (component.GetType() == typeof(Relay)) { + // Collect all next clusters connected via a relay (from the control input side) + if (inputPeg.Address == component.Inputs[1].Address) { + // one of the sides + CollectPegClusters(component.Inputs[2].Address, clusters); + } else if (inputPeg.Address == component.Inputs[2].Address) { + // the other side + CollectPegClusters(component.Inputs[1].Address, clusters); } } } - logger.Info($"Finished after {iterations} iterations"); + return clusters; + } + + private static void LinkNextClusters(Queue queue, Dictionary clusterToNodeMapping, + List clusterNodes, HashSet collectedNextClusters, ClusterNode node, int delay) { + foreach (Cluster nextCluster in collectedNextClusters) { + // ignore already mapped clusters + if (clusterToNodeMapping.TryGetValue(nextCluster, out int nextNodeIndex)) { + ClusterNode nextNode = clusterNodes[nextNodeIndex]; + // only add the link, don't propagate + nextNode.PrevNodeIndexes.Add(node.Index); + node.NextNodes.TryAdd(nextNodeIndex, delay); + } else { + HashSet nextClusters = GetClustersConnectedThroughRelays(nextCluster); + + if (nextClusters.Any(clusterToNodeMapping.ContainsKey)) { + // already discovered cluster node + continue; + } + + nextNodeIndex = clusterNodes.Count; + var nextNode = new ClusterNode() { + Index = nextNodeIndex, + Clusters = nextClusters, + Time = 0, + NextNodes = new Dictionary(), + PrevNodeIndexes = new HashSet() {node.Index}, + }; + + clusterNodes.Add(nextNode); + + node.NextNodes.TryAdd(nextNodeIndex, delay); + + foreach (Cluster nextNodeCluster in nextNode.Clusters) { + clusterToNodeMapping.TryAdd(nextNodeCluster, nextNodeIndex); + } + + // propagate + queue.Enqueue(nextNode); + } + } } @@ -288,18 +337,13 @@ namespace CriticalPathAnalyzer.Server.Tool { return cluster; } - private static bool GetLinkerAt(Cluster cluster, out ClusterLinker linker) { - linker = GetLinker(cluster); - return linker != null; - } - /// /// An output peg can be connected to multiple clusters. Collect all of them. /// /// Address of the peg /// Found clusters get added into this hash set /// A wire of the peg is not in the world - private static void CollectMainClusters(PegAddress pegAddress, HashSet primaryClusters) { + private static void CollectPegClusters(PegAddress pegAddress, HashSet primaryClusters) { if (pegAddress.IsInputAddress(out InputAddress inputAddress)) { primaryClusters.Add(GetClusterAt(inputAddress)); } else { @@ -325,48 +369,11 @@ namespace CriticalPathAnalyzer.Server.Tool { } } - private static void GetLinkedClusters( - Cluster startingPoint, - HashSet oneWayConnectedClusters, - HashSet twoWayConnectedClusters, - Func> linkedLinkerGetter - ) { - var clustersToProcess = new Queue(); - if (!GetLinkerAt(startingPoint, out ClusterLinker startingLinker)) { - return; // No linker on this cluster => no link => nothing to collect - } - - clustersToProcess.Enqueue(startingLinker); - twoWayConnectedClusters.Add(startingPoint); - // While the starting cluster is no source, the algorithm needs to skip it when encountered. - while (clustersToProcess.TryDequeue(out ClusterLinker linkerToCheck)) { - List listOfLinkedLinkers = linkedLinkerGetter(linkerToCheck); // Is never null. - foreach (ClusterLinker linkedLinker in listOfLinkedLinkers) { - Cluster clusterOfLinkedLinker = linkedLinker.ClusterBeingLinked; // Should never be null. - List listOfBackLinkers = linkedLinkerGetter(linkedLinker); // Is never null. - if (listOfBackLinkers.Contains(linkerToCheck)) { - // bidirectional - a relay - // TODO: will not find a relay connection if the relay is turned off - if (twoWayConnectedClusters.Add(clusterOfLinkedLinker)) { - // Element was not yet present in the array, so keep looking into it! - clustersToProcess.Enqueue(linkedLinker); - } - } else { - // unidirectional - a fast buffer - oneWayConnectedClusters.Add(clusterOfLinkedLinker); - // stop propagation - } - } - } - - twoWayConnectedClusters.Remove(startingPoint); - } private static ClusterDetails CollectClusterInformation(Cluster cluster, int time) { var details = new ClusterDetails { Pegs = new List(), ConnectingComponents = new List(), - LinkingComponents = new List(), Color = HsvToRgb(time * 20, 1, 1), }; @@ -380,14 +387,6 @@ namespace CriticalPathAnalyzer.Server.Tool { // Socket details.ConnectingComponents.Add(peg.Address.ComponentAddress); } - - if ((peg.PhasicLinks != null && peg.PhasicLinks.Any()) - || (peg.OneWayPhasicLinksFollowers != null && peg.OneWayPhasicLinksFollowers.Any()) - || (peg.OneWayPhasicLinksLeaders != null && peg.OneWayPhasicLinksLeaders.Any()) - ) { - // Relay / fast buffer - details.LinkingComponents.Add(peg.Address.ComponentAddress); - } } foreach (OutputPeg peg in outputPegs) { diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/shared/packets/s2c/AnalyzePathResponse.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/shared/packets/s2c/AnalyzePathResponse.cs index 296b77e..a9f8b24 100644 --- a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/shared/packets/s2c/AnalyzePathResponse.cs +++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/shared/packets/s2c/AnalyzePathResponse.cs @@ -27,11 +27,6 @@ namespace CriticalPathAnalyzer.Shared.Packets.S2C { /// [Key(1)] public List ConnectingComponents; - /// - /// Relays and fast buffers - /// - [Key(2)] public List LinkingComponents; - [Key(3)] public int Color; } } \ No newline at end of file