From d1ef0f1d41b402b9726bfb1a268c510ebf223f6a Mon Sep 17 00:00:00 2001 From: Ultimationzzz Date: Thu, 9 Jul 2026 13:21:29 +0200 Subject: [PATCH] Fix scenario chain graph normalization --- CodeWalker.Core/World/Scenarios.cs | 133 ++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 2 deletions(-) diff --git a/CodeWalker.Core/World/Scenarios.cs b/CodeWalker.Core/World/Scenarios.cs index 367f82b75..07ffb8c29 100644 --- a/CodeWalker.Core/World/Scenarios.cs +++ b/CodeWalker.Core/World/Scenarios.cs @@ -864,6 +864,7 @@ public bool RemoveNode(ScenarioNode node) } res = res && Nodes.Remove(node); + RebuildChains(); return res; } @@ -910,6 +911,8 @@ public bool RemoveChain(MCScenarioChain chain, bool delpoints) } } + RebuildChains(); + return true; } @@ -1496,11 +1499,137 @@ public void RebuildChains() { if (Region == null) return; - //update chain nodes array, update from/to indexes - //currently not necessary - editor updates indexes and arrays already. + NormalizeScenarioChainingGraph(Region.Paths); + } + + private static void NormalizeScenarioChainingGraph(MCScenarioChainingGraph graph) + { + if (graph == null) return; + + var nodes = graph.Nodes ?? new MCScenarioChainingNode[0]; + for (var i = 0; i < nodes.Length; i++) + { + var node = nodes[i]; + if (node == null) continue; + + node.NodeIndex = i; + node.Parent = graph; + node.Region = graph.Region; + node.HasIncomingEdges = false; + node.HasOutgoingEdges = false; + node.Chain = null; + } + + var oldEdges = graph.Edges ?? new MCScenarioChainingEdge[0]; + var keptEdges = new List(); + var oldToNewEdgeIndex = new Dictionary(); + var edgeToNewIndex = new Dictionary(); + + for (var oldIndex = 0; oldIndex < oldEdges.Length; oldIndex++) + { + var edge = oldEdges[oldIndex]; + if (edge == null) + { + continue; + } + + var from = ResolveChainingNode(nodes, edge.NodeFrom, edge.NodeIndexFrom); + var to = ResolveChainingNode(nodes, edge.NodeTo, edge.NodeIndexTo); + if ((from == null) || (to == null) || (from == to)) + { + continue; + } + + edge.Region = graph.Region; + edge.NodeFrom = from; + edge.NodeTo = to; + edge.NodeIndexFrom = (ushort)from.NodeIndex; + edge.NodeIndexTo = (ushort)to.NodeIndex; + edge.EdgeIndex = keptEdges.Count; + + oldToNewEdgeIndex[oldIndex] = keptEdges.Count; + edgeToNewIndex[edge] = keptEdges.Count; + keptEdges.Add(edge); + } + + graph.Edges = keptEdges.Count == 0 ? null : keptEdges.ToArray(); + + if (graph.Chains != null) + { + var keptChains = new List(); + foreach (var chain in graph.Chains) + { + if (chain == null) + { + continue; + } + + var ids = new List(); + var seenIds = new HashSet(); + + if (chain.Edges != null) + { + foreach (var edge in chain.Edges) + { + if ((edge != null) && edgeToNewIndex.TryGetValue(edge, out var newIndex)) + { + var id = (ushort)newIndex; + if (seenIds.Add(id)) + { + ids.Add(id); + } + } + } + } + else if (chain.EdgeIds != null) + { + foreach (var oldId in chain.EdgeIds) + { + if (oldToNewEdgeIndex.TryGetValue(oldId, out var newIndex)) + { + var id = (ushort)newIndex; + if (seenIds.Add(id)) + { + ids.Add(id); + } + } + } + } + + if (ids.Count == 0) + { + continue; + } + + chain.Region = graph.Region; + chain.ChainIndex = keptChains.Count; + chain.EdgeIds = ids.ToArray(); + chain.Edges = graph.Edges == null ? null : ids.Select(id => graph.Edges[id]).ToArray(); + foreach (var edge in chain.Edges) + { + edge.NodeFrom.HasOutgoingEdges = true; + edge.NodeTo.HasIncomingEdges = true; + edge.NodeFrom.Chain = chain; + edge.NodeTo.Chain = chain; + } + + keptChains.Add(chain); + } + + graph.Chains = keptChains.Count == 0 ? null : keptChains.ToArray(); + } } + private static MCScenarioChainingNode ResolveChainingNode(MCScenarioChainingNode[] nodes, MCScenarioChainingNode node, ushort nodeIndex) + { + if ((node != null) && (node.NodeIndex >= 0) && (node.NodeIndex < nodes.Length) && (nodes[node.NodeIndex] == node)) + { + return node; + } + + return nodeIndex < nodes.Length ? nodes[nodeIndex] : null; + } }