mirror of
https://github.com/4sval/FModel.git
synced 2026-03-23 18:24:36 -05:00
Separate _Root and _StateResult into independent passes in BuildLayers
Split BuildLayers into two distinct passes: - Pass 1: AnimGraphNode_Root nodes → graph layers - Pass 2: AnimGraphNode_StateResult nodes → state sub-graphs Previously these were incorrectly mixed in a single loop. Each type defines a fundamentally different concept in UE and must be processed independently. Extracted CollectUpstream helper to share BFS logic. Co-authored-by: LoogLong <86428208+LoogLong@users.noreply.github.com>
This commit is contained in:
parent
7b6f9aac79
commit
6620463154
|
|
@ -166,11 +166,11 @@ public class AnimGraphViewModel
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Groups nodes into layers based on root nodes. In Unreal Engine, each
|
||||
/// animation blueprint layer has a unique AnimGraphNode_Root, and each
|
||||
/// state machine state sub-graph has a unique AnimGraphNode_StateResult.
|
||||
/// Starting from each root node, we trace upstream through directed
|
||||
/// connections to collect all nodes that feed into it.
|
||||
/// Groups nodes into layers based on root nodes. In Unreal Engine:
|
||||
/// - Each animation blueprint layer has a unique AnimGraphNode_Root
|
||||
/// - Each state machine state sub-graph has a unique AnimGraphNode_StateResult
|
||||
/// These two types are processed in separate passes to keep graph layers
|
||||
/// and state machine state sub-graphs independent.
|
||||
/// </summary>
|
||||
private static void BuildLayers(AnimGraphViewModel vm)
|
||||
{
|
||||
|
|
@ -185,43 +185,36 @@ public class AnimGraphViewModel
|
|||
foreach (var conn in vm.Connections)
|
||||
upstreamOf[conn.TargetNode].Add(conn.SourceNode);
|
||||
|
||||
// Find all root nodes that define layers:
|
||||
// _Root nodes define animation blueprint layers
|
||||
// _StateResult nodes define state machine state sub-graphs
|
||||
var rootNodes = vm.Nodes
|
||||
.Where(n => n.ExportType.EndsWith("_Root", StringComparison.OrdinalIgnoreCase) ||
|
||||
n.ExportType.EndsWith("_StateResult", StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
var assigned = new HashSet<AnimGraphNode>();
|
||||
var layerIndex = 0;
|
||||
|
||||
// For each root node, BFS upstream to find all nodes in the layer
|
||||
foreach (var rootNode in rootNodes)
|
||||
// Pass 1: Build graph layers from AnimGraphNode_Root nodes.
|
||||
// Each _Root node defines an animation blueprint layer (e.g. "AnimGraph").
|
||||
var graphRoots = vm.Nodes
|
||||
.Where(n => n.ExportType.EndsWith("_Root", StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
foreach (var rootNode in graphRoots)
|
||||
{
|
||||
if (!assigned.Add(rootNode)) continue;
|
||||
|
||||
var layerNodes = new List<AnimGraphNode> { rootNode };
|
||||
var queue = new Queue<AnimGraphNode>();
|
||||
queue.Enqueue(rootNode);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var current = queue.Dequeue();
|
||||
foreach (var upstream in upstreamOf[current])
|
||||
{
|
||||
if (assigned.Add(upstream))
|
||||
{
|
||||
layerNodes.Add(upstream);
|
||||
queue.Enqueue(upstream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var layerNodes = CollectUpstream(rootNode, upstreamOf, assigned);
|
||||
AddLayer(vm, layerNodes, layerIndex++);
|
||||
}
|
||||
|
||||
// Any remaining unassigned nodes go into fallback layers (connected components)
|
||||
// Pass 2: Build state machine state sub-graphs from AnimGraphNode_StateResult nodes.
|
||||
// Each _StateResult node defines a state's sub-graph within a state machine.
|
||||
var stateResultRoots = vm.Nodes
|
||||
.Where(n => n.ExportType.EndsWith("_StateResult", StringComparison.OrdinalIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
foreach (var stateResultNode in stateResultRoots)
|
||||
{
|
||||
if (!assigned.Add(stateResultNode)) continue;
|
||||
var layerNodes = CollectUpstream(stateResultNode, upstreamOf, assigned);
|
||||
AddLayer(vm, layerNodes, layerIndex++);
|
||||
}
|
||||
|
||||
// Fallback: any remaining unassigned nodes go into connected-component layers
|
||||
var remaining = vm.Nodes.Where(n => !assigned.Contains(n)).ToList();
|
||||
if (remaining.Count == 0) return;
|
||||
|
||||
|
|
@ -263,6 +256,34 @@ public class AnimGraphViewModel
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collects a root node and all its upstream providers via BFS.
|
||||
/// </summary>
|
||||
private static List<AnimGraphNode> CollectUpstream(
|
||||
AnimGraphNode root,
|
||||
Dictionary<AnimGraphNode, List<AnimGraphNode>> upstreamOf,
|
||||
HashSet<AnimGraphNode> assigned)
|
||||
{
|
||||
var nodes = new List<AnimGraphNode> { root };
|
||||
var queue = new Queue<AnimGraphNode>();
|
||||
queue.Enqueue(root);
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var current = queue.Dequeue();
|
||||
foreach (var upstream in upstreamOf[current])
|
||||
{
|
||||
if (assigned.Add(upstream))
|
||||
{
|
||||
nodes.Add(upstream);
|
||||
queue.Enqueue(upstream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an <see cref="AnimGraphLayer"/> from a set of nodes, assigns
|
||||
/// the relevant connections, lays out the nodes and adds the layer to the VM.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user