diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/PathHighLighter.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/PathHighLighter.cs index c065d9c..7d60d64 100644 --- a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/PathHighLighter.cs +++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/client/tool/PathHighLighter.cs @@ -23,26 +23,28 @@ namespace CriticalPathAnalyzer.Client.Tool { HighlightCluster(clusterDetails, Color); } - IWorldData world = Instances.MainWorld.Data; + // IWorldData world = Instances.MainWorld.Data; - foreach (ComponentAddress componentAddress in response.PerimeterComponents) { - if (!world.Contains(componentAddress)) { - continue; - } - - Outliner.Outline(componentAddress, PerimeterColor); - _highlightedComponents.Add(componentAddress); - } + // 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); - } + // _clusters.AddRange(response.NextClusters); // add to the collection to unhighlight + // foreach (ClusterDetails clusterDetails in response.NextClusters) { + // HighlightCluster(clusterDetails, NextColor); + // } } - private static void HighlightCluster(ClusterDetails cluster, OutlineData outline) { + private static void HighlightCluster(ClusterDetails cluster, OutlineData outlineOld) { IWorldData world = Instances.MainWorld.Data; + var outline = new OutlineData(new Color24(cluster.Color)); + foreach (ComponentAddress address in cluster.ConnectingComponents) { if (!world.Contains(address)) { continue; diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/server/tool/ServerPathTracer.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/server/tool/ServerPathTracer.cs index 5e3cb3d..3c1b79e 100644 --- a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/server/tool/ServerPathTracer.cs +++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/server/tool/ServerPathTracer.cs @@ -4,9 +4,11 @@ using System.Linq; using CriticalPathAnalyzer.Shared.Packets.S2C; using EccsLogicWorldAPI.Server; using EccsLogicWorldAPI.Shared.AccessHelper; +using JimmysUnityUtilities; using LogicAPI.Data; using LogicAPI.Server.Components; using LogicAPI.Services; +using LogicLog; using LogicWorld.Server.Circuitry; namespace CriticalPathAnalyzer.Server.Tool { @@ -42,18 +44,20 @@ namespace CriticalPathAnalyzer.Server.Tool { PegAddress end, out AnalyzePathResponse response ) { + ILogicLogger logger = CriticalPathAnalyzerServer.LoggerInstance; response = null; - CriticalPathAnalyzerServer.LoggerInstance.Info("Trace start"); + logger.Info("Trace start"); // Validate, that the peg is actually existing: if (!PegExists(start) || !PegExists(end)) { - CriticalPathAnalyzerServer.LoggerInstance.Error("Peg not found"); + logger.Error("Peg not found"); return false; } var clusterNodes = new List(); - var nodeQueue = new Queue(); + var clusterToNodeMapping = new Dictionary(); // Cluster / index of node + var queue = new Queue<(Cluster, int)>(); // An input peg, only has a single cluster. // An output peg however can be connected to multiple clusters. @@ -61,61 +65,95 @@ namespace CriticalPathAnalyzer.Server.Tool { var collectedClusters = new HashSet(); CollectMainClusters(start, collectedClusters); - CriticalPathAnalyzerServer.LoggerInstance.Info($"collected {collectedClusters.Count} main clusters"); - - // Collect clusters that get powered by the original cluster using relays or fast buffers - var oneWayConnectedClusters = new HashSet(); - var twoWayConnectedClusters = new HashSet(); foreach (Cluster cluster in collectedClusters) { - GetLinkedClusters(cluster, oneWayConnectedClusters, twoWayConnectedClusters, GetFollowers); + queue.Enqueue((cluster, 0)); } - CriticalPathAnalyzerServer.LoggerInstance.Info( - $"collected {oneWayConnectedClusters.Count} one way linked clusters"); - CriticalPathAnalyzerServer.LoggerInstance.Info( - $"collected {twoWayConnectedClusters.Count} two way linked clusters"); + logger.Info($"collected {collectedClusters.Count} main clusters"); - // collectedClusters.UnionWith(oneWayConnectedClusters); - collectedClusters.UnionWith(twoWayConnectedClusters); + int iters = 0; + while (queue.TryDequeue(out (Cluster, int) item)) { + iters++; + if (iters > 100000) { + logger.Error("Infinite iterations"); + break; + } - CriticalPathAnalyzerServer.LoggerInstance.Info($"union {collectedClusters.Count} clusters"); + (Cluster cluster, int time) = item; - clusterNodes.Add(new ClusterNode() { - Index = clusterNodes.Count, - Clusters = collectedClusters.ToList(), - Time = 0, - PrevNodeStateId = null, - NextNodes = new Dictionary(), - }); + logger.Warn(">> cluster iter <<"); - var perimeterComponents = new HashSet(); - var collectedNextClusters = new HashSet(); - foreach (Cluster cluster in collectedClusters) { + if (clusterToNodeMapping.ContainsKey(cluster)) { + logger.Info("already mapped, continuing"); + continue; + } + + // Collect clusters that get powered by the original cluster using relays or fast buffers + // var nextClusters = new HashSet(); + // var twoWayConnectedClusters = new HashSet(); + // + // GetLinkedClusters(cluster, nextClusters, twoWayConnectedClusters, GetFollowers); + + // logger.Info($"collected {nextClusters.Count} one way linked clusters"); + // logger.Info($"collected {twoWayConnectedClusters.Count} two way linked clusters"); + + int index = clusterNodes.Count; + + // foreach (Cluster connectedCluster in twoWayConnectedClusters) { + // if (!clusterToNodeMapping.TryAdd(connectedCluster, index)) { + // // already been here + // logger.Error("Adding already mapped cluster"); + // break; + // } + // } + + // foreach (Cluster connectedCluster in nextClusters) { + // var nextClusters = new HashSet(); + // var twoWayConnectedClusters = new HashSet(); + // GetLinkedClusters(connectedCluster, nextClusters, twoWayConnectedClusters, GetFollowers); + // } + + clusterToNodeMapping.Add(cluster, index); + + clusterNodes.Add(new ClusterNode() { + Index = index, + Clusters = new List() {cluster}, + Time = index, + PrevNodeStateId = null, + NextNodes = new Dictionary(), + }); + + // var perimeterComponents = new HashSet(); + var collectedNextClusters = new HashSet(); foreach (InputPeg inputPeg in cluster.ConnectedInputs) { if (inputPeg.LogicComponent == null) { // These are regular pegs, they are not attached to any logic component, skip them continue; } - perimeterComponents.Add(inputPeg.LogicComponent.Address); + // perimeterComponents.Add(inputPeg.LogicComponent.Address); foreach (IOutputPeg outputPeg in inputPeg.LogicComponent.Outputs) { CollectMainClusters(outputPeg.Address, collectedNextClusters); } } - } - CriticalPathAnalyzerServer.LoggerInstance.Info("collected perimeter components"); + foreach (Cluster nextCluster in collectedNextClusters) { + queue.Enqueue((nextCluster, time + 1)); + } + + logger.Info("collected perimeter components"); + } // Collect information about each cluster: response = new AnalyzePathResponse() { RequestGuid = requestGuid, - Clusters = collectedClusters.Select(CollectClusterInformation).ToList(), - PerimeterComponents = perimeterComponents.ToList(), - NextClusters = collectedNextClusters.Select(CollectClusterInformation).ToList(), + Clusters = clusterNodes.SelectMany(node => node.Clusters.Select(cluster => CollectClusterInformation(cluster, node.Time))).ToList(), + // PerimeterComponents = perimeterComponents.ToList(), + // NextClusters = collectedNextClusters.Select(CollectClusterInformation).ToList(), }; - CriticalPathAnalyzerServer.LoggerInstance.Info("Trace end"); + logger.Info("Trace end"); return true; } @@ -191,6 +229,7 @@ namespace CriticalPathAnalyzer.Server.Tool { } 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. @@ -199,6 +238,7 @@ namespace CriticalPathAnalyzer.Server.Tool { 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); @@ -214,11 +254,12 @@ namespace CriticalPathAnalyzer.Server.Tool { twoWayConnectedClusters.Remove(startingPoint); } - private static ClusterDetails CollectClusterInformation(Cluster cluster) { + 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), }; // Two lists are never null, according to how it is created and used: @@ -247,5 +288,49 @@ namespace CriticalPathAnalyzer.Server.Tool { return details; } + + private static int HsvToRgb(int h, float s, float v) { + s = Math.Clamp(s, 0, 1); + v = Math.Clamp(v, 0, 1); + h = (h % 360 + 360) % 360; // Ensure hue is within 0-359 range + + float c = v * s; + float x = c * (1 - Math.Abs((h / 60.0f) % 2 - 1)); + float m = v - c; + + float r = 0, g = 0, b = 0; + + if (h < 60) { + r = c; + g = x; + b = 0; + } else if (h < 120) { + r = x; + g = c; + b = 0; + } else if (h < 180) { + r = 0; + g = c; + b = x; + } else if (h < 240) { + r = 0; + g = x; + b = c; + } else if (h < 300) { + r = x; + g = 0; + b = c; + } else { + r = c; + g = 0; + b = x; + } + + int rInt = (byte) ((r + m) * 255); + int gInt = (byte) ((g + m) * 255); + int bInt = (byte) ((b + m) * 255); + + return (rInt << 16) | (gInt << 8) | bInt; + } } } \ No newline at end of file diff --git a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/shared/packets/s2c/AnalyzePathResponse.cs b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/shared/packets/s2c/AnalyzePathResponse.cs index 1a4a053..aaf23c7 100644 --- a/CriticalPathAnalyzer/CriticalPathAnalyzer/src/shared/packets/s2c/AnalyzePathResponse.cs +++ b/CriticalPathAnalyzer/CriticalPathAnalyzer/src/shared/packets/s2c/AnalyzePathResponse.cs @@ -9,8 +9,8 @@ namespace CriticalPathAnalyzer.Shared.Packets.S2C { public class AnalyzePathResponse : Packet { [Key(0)] public Guid RequestGuid; [Key(1)] public List Clusters; - [Key(2)] public List PerimeterComponents; - [Key(3)] public List NextClusters; + // [Key(2)] public List PerimeterComponents; + // [Key(3)] public List NextClusters; } [MessagePackObject] @@ -18,5 +18,6 @@ namespace CriticalPathAnalyzer.Shared.Packets.S2C { [Key(0)] public List Pegs; [Key(1)] public List ConnectingComponents; // Sockets [Key(2)] public List LinkingComponents; // Relays, fast buffers + [Key(3)] public int Color; } } \ No newline at end of file