How Relay Nodes Get Flattened During Serialization in Ceres for Optimization

Relay nodes in Ceres are flattened during serialization by replacing indirect connections with direct edges between source and destination ports, using an isFlattened flag to ensure accurate graph reconstruction on load.

When saving complex flow graphs in the Ceres visual scripting system, relay nodes present a unique serialization challenge. These utility nodes exist purely to route data between distant ports, yet storing every intermediate edge would bloat the serialized file and slow down I/O operations. According to the Ceres source code, the framework solves this by flattening relay nodes during serialization—collapsing multi-hop connections into single direct edges while preserving enough metadata to reconstruct the original topology on deserialization.

The Relay Node Flattening Pipeline

Step 1: Collecting Relay Metadata Before Flattening

The process begins in FlowGraphView.SerializeGraph located in Editor/Flow/UIElements/FlowGraphView.cs. Before the standard node compilation flattens any connections, the serializer gathers every RelayNodeView in the visual graph and invokes Compile() on each one. This preemptive collection ensures that the relay's input and output connections are recorded before they are optimized away.

Step 2: Compiling Raw Relay Connections

In Editor/Core/UIElements/Graph/Nodes/RelayNodeView.cs, the Compile() method (lines 95-155) constructs a RelayNode data object containing the relay's GUID, position, and port type. Crucially, it iterates through the _inputPort.connections and _outputPort.connections to populate Data.inputs and Data.outputs arrays with RelayConnection objects. This method performs no flattening itself—it merely snapshots the raw connectivity state.

Step 3: Resolving Final Ports Through Relay Chains

The actual flattening logic resides in Editor/Core/UIElements/Graph/Ports/CeresPortView.cs. When CeresPortView.Commit processes outgoing connections, it calls ResolveTargetPortsThroughRelayNodes to determine the ultimate destination ports. This helper method traverses the graph recursively: if it encounters a port belonging to a RelayNodeView (where currentPort.View == null), it continues following the relay's output connections until reaching a concrete node port. During traversal, it sets a hasTraversedRelay boolean flag to true for all final ports reached via relay chains.

Step 4: Marking Connections as Flattened

Still within CeresPortView.Commit (lines 79-89), the serializer creates PortConnectionData objects for each resolved final port. It assigns the isFlattened field based on the boolean flag collected during traversal. If the connection path included any relay nodes, isFlattened is set to true; otherwise, it remains false. This flag serves as the critical metadata for deserialization.

Step 5: Skipping Flattened Connections on Restore

During deserialization, CeresPortView.Connect (lines 48-53) iterates through the stored PortData.connections. It explicitly checks the isFlattened flag and continues to the next iteration if the value is true. This prevents the creation of duplicate edges that would otherwise connect directly to the relay node's ports. Instead, the missing connections are restored later when the RelayNodeView itself is reconstructed and its RestoreRelayConnections method re-applies the saved input and output connection lists from the RelayNode metadata.

Performance Benefits of Relay Flattening

Flattening relay nodes during serialization delivers measurable performance improvements for Ceres flow graphs. By replacing chains of intermediate edges with single direct connections, the system reduces the total number of PortConnectionData objects stored in the serialized file. This compression minimizes memory footprint and accelerates both save and load operations, particularly for complex graphs containing numerous relay nodes used for organizational layout. The isFlattened flag ensures this optimization remains lossless—when the graph reloads, the original visual topology is reconstructed exactly as the user designed it.

Summary

  • Relay nodes flatten during serialization by replacing multi-hop connections with direct edges between source and destination ports.
  • The FlowGraphView.SerializeGraph method collects relay metadata before flattening occurs to preserve connection data.
  • RelayNodeView.Compile() records raw input and output connections without performing flattening.
  • CeresPortView.Commit resolves final destination ports by traversing relay chains and sets the isFlattened flag in PortConnectionData.
  • During deserialization, CeresPortView.Connect skips flattened connections, allowing RelayNodeView.RestoreRelayConnections to rebuild the original topology.

Frequently Asked Questions

What is the purpose of the isFlattened flag in Ceres serialization?

The isFlattened flag in PortConnectionData indicates whether a connection was originally routed through one or more relay nodes before being flattened into a direct edge. During deserialization, this flag prevents the creation of duplicate connections to relay ports, ensuring that the relay node itself can restore its original input and output wiring without conflicts.

How does Ceres ensure no data is lost when flattening relay connections?

Ceres preserves connection integrity by collecting relay node metadata before any flattening occurs. The RelayNodeView.Compile() method stores the original input and output connections in a RelayNode object. Even though the serialized graph contains flattened direct edges, the relay's metadata is saved separately, allowing RestoreRelayConnections to reconstruct the exact original topology when the graph loads.

Does flattening relay nodes affect runtime execution of Ceres flow graphs?

No, flattening is purely a serialization optimization. At runtime, Ceres flow graphs execute using the concrete node connections that exist in memory. The relay nodes are restored with their original connections during deserialization, so the visual representation and logical data flow remain identical to what the user designed. The optimization only reduces file size and I/O time during save and load operations.

Where can I find the implementation of relay node flattening in the Ceres source code?

The flattening logic is distributed across several files in the akikurisu/ceres repository. The entry point is Editor/Flow/UIElements/FlowGraphView.cs, which orchestrates serialization. Relay node compilation occurs in Editor/Core/UIElements/Graph/Nodes/RelayNodeView.cs. The actual flattening and isFlattened flag assignment happen in Editor/Core/UIElements/Graph/Ports/CeresPortView.cs. Runtime data structures are defined in Runtime/Core/Models/Graph/Ports/CeresPort.cs and Runtime/Core/Models/Graph/Nodes/RelayNode.cs.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →