diff --git a/FModel/ViewModels/AnimGraphViewModel.cs b/FModel/ViewModels/AnimGraphViewModel.cs index 4da8f3bc..e8f04b13 100644 --- a/FModel/ViewModels/AnimGraphViewModel.cs +++ b/FModel/ViewModels/AnimGraphViewModel.cs @@ -60,6 +60,7 @@ internal class StateMachineMetadata { public string MachineName { get; init; } = string.Empty; public List StateNames { get; } = []; + public List StateRootPropNames { get; } = []; public List<(int PreviousState, int NextState)> Transitions { get; } = []; } @@ -342,6 +343,9 @@ public class AnimGraphViewModel ExportType = "State", IsStateMachineState = true }; + // Store root node property name for StateRootNodeIndex-based lookup + if (i < sm.StateRootPropNames.Count && !string.IsNullOrEmpty(sm.StateRootPropNames[i])) + stateNode.AdditionalProperties["StateRootNodeName"] = sm.StateRootPropNames[i]; stateNode.Pins.Add(new AnimGraphPin { PinName = "In", @@ -535,6 +539,7 @@ public class AnimGraphViewModel if (states.Properties[stateIdx].GetValue(typeof(FStructFallback)) is not FStructFallback stateStruct) { metadata.StateNames.Add($"State_{stateIdx}"); + metadata.StateRootPropNames.Add(string.Empty); continue; } @@ -545,14 +550,16 @@ public class AnimGraphViewModel metadata.StateNames.Add(stateName); - // Mark root node - if (!stateStruct.TryGetValue(out int stateRootIndex, "StateRootNodeIndex")) - continue; - - if (stateRootIndex < 0 || stateRootIndex >= animNodeProps.Count) + // Mark root node via StateRootNodeIndex + if (!stateStruct.TryGetValue(out int stateRootIndex, "StateRootNodeIndex") || + stateRootIndex < 0 || stateRootIndex >= animNodeProps.Count) + { + metadata.StateRootPropNames.Add(string.Empty); continue; + } var rootPropName = animNodeProps[stateRootIndex].name; + metadata.StateRootPropNames.Add(rootPropName); if (nodeByName.TryGetValue(rootPropName, out var rootNode)) rootNode.AdditionalProperties["BelongsToStateMachine"] = machineName; } diff --git a/FModel/Views/AnimGraphViewer.xaml.cs b/FModel/Views/AnimGraphViewer.xaml.cs index d4375367..5bbc8fa0 100644 --- a/FModel/Views/AnimGraphViewer.xaml.cs +++ b/FModel/Views/AnimGraphViewer.xaml.cs @@ -563,10 +563,28 @@ public partial class AnimGraphViewer } else if (node.IsStateMachineState) { - // State nodes within an overview: open the per-state internal sub-graph - // Per-state layers are named "overviewPath > stateName" - var overviewName = _currentLayerState?.Layer.Name ?? string.Empty; - layerName = $"{overviewName}{AnimGraphViewModel.SubGraphPathSeparator}{node.Name}"; + // State nodes within an overview: find the per-state layer by StateRootNodeIndex + // The root node's property name is stored on the overview state node + if (node.AdditionalProperties.TryGetValue("StateRootNodeName", out var rootNodeName) && + !string.IsNullOrEmpty(rootNodeName)) + { + var targetLayer = _viewModel.Layers.FirstOrDefault(l => + l.Nodes.Any(n => n.Name == rootNodeName)); + if (targetLayer != null) + { + // If tab already exists, just select it + foreach (System.Windows.Controls.TabItem tab in LayerTabControl.Items) + { + if (tab.Tag == targetLayer) + { + LayerTabControl.SelectedItem = tab; + return; + } + } + AddLayerTab(targetLayer); + return; + } + } } else if (node.ExportType.Contains("StateMachine", StringComparison.OrdinalIgnoreCase)) {