FlowGraphObject vs FlowGraphInstanceObject: Understanding Container Differences in Ceres
The difference between FlowGraphObject and FlowGraphInstanceObject containers is that FlowGraphObject embeds graph data directly within the MonoBehaviour via source-generated code, while FlowGraphInstanceObject references an external FlowGraphAsset to supply the graph data.
Both classes are Unity MonoBehaviours in the akikurisu/ceres repository that expose runtime FlowGraphs, but they implement the IFlowGraphContainer interface through fundamentally different storage mechanisms. Understanding these container patterns is essential for deciding whether to store graph data per-object or share it across multiple instances.
Container Source: Embedded vs External Asset
FlowGraphObject: Self-Generated Container
In Runtime/Flow/FlowGraphObject.cs, the FlowGraphObject class uses source generation to turn the MonoBehaviour itself into an IFlowGraphContainer. The [GenerateFlow(GenerateRuntime = false, GenerateImplementation = true)] attribute (lines 136-144) triggers the generator to create a partial class that stores persistent FlowGraphData as a hidden sub-asset inside the component.
This approach makes each GameObject fully own its graph data. The generated implementation handles serialization automatically, embedding the graph definition directly within the prefab or scene object.
FlowGraphInstanceObject: Asset Reference Container
Conversely, Runtime/Flow/FlowGraphInstanceObject.cs (lines 7-15) defines an explicit container reference:
public class FlowGraphInstanceObject : FlowGraphObjectBase
{
[SerializeField] internal FlowGraphAsset graphAsset; // External container
// Container calls forwarded to graphAsset
}
Rather than generating container code, this class implements IFlowGraphContainer by delegating all calls to the serialized FlowGraphAsset field. The graph data lives in a separate asset file, allowing multiple components to reference the same graph definition.
Runtime Container Resolution
The FlowGraphObjectBase class determines which container to use at runtime through the GetContainer() method implemented in Runtime/Flow/FlowGraphObject.cs (lines 76-90):
protected IFlowGraphContainer GetContainer()
{
// Check for external asset reference first
if (this is FlowGraphInstanceObject instanceObject && instanceObject.graphAsset != null)
{
return instanceObject.graphAsset;
}
// Fall back to self-contained container
return this as IFlowGraphContainer;
}
This logic ensures that FlowGraphInstanceObject instances return their referenced FlowGraphAsset, while FlowGraphObject instances return themselves as the container.
Implementation Architecture
Source Generation vs Explicit Implementation
FlowGraphObject relies on compile-time code generation:
- The
partial class FlowGraphObjectis augmented by the Ceres source generator - The generator implements
IFlowGraphContainerandIFlowGraphRuntimeinterfaces automatically - Graph data persists as a sub-asset within the MonoBehaviour (visible in
Runtime/Flow/Models/FlowGraph.csinterface definitions)
FlowGraphInstanceObject uses runtime composition:
- Explicitly declares the
graphAssetfield of typeFlowGraphAsset(defined inRuntime/Flow/FlowGraphAsset.cs) - No source generation required for container implementation
- All container interface methods forward to the referenced asset
Data Persistence Locations
- FlowGraphObject: Stores
FlowGraphDatainside the component as a hidden serialized object (self-contained) - FlowGraphInstanceObject: Stores data in the external
FlowGraphAssetfile (shared resource)
When to Use Each Container Type
Choose FlowGraphObject when:
- Each GameObject requires unique graph data
- You want self-contained prefabs without external dependencies
- The graph should serialize with the scene or prefab directly
Choose FlowGraphInstanceObject when:
- Multiple objects must share identical graph logic
- Memory efficiency is critical (avoid duplicating graph data across instances)
- You need to update graph logic in one place (the asset) and affect all instances
Summary
- FlowGraphObject implements a self-container pattern where the MonoBehaviour itself becomes the
IFlowGraphContainerthrough source-generated code, embeddingFlowGraphDataas a sub-asset - FlowGraphInstanceObject implements an external-container pattern that references a
FlowGraphAssetto supply graph data, enabling data sharing across multiple GameObjects - The
GetContainer()method inFlowGraphObjectBaseautomatically detects which pattern is in use at runtime - Use
FlowGraphObjectfor per-object unique graphs andFlowGraphInstanceObjectfor shared, asset-based graph definitions
Frequently Asked Questions
Can I switch a FlowGraphObject to use an external asset without changing the component type?
No, the container architecture is determined by the class type itself. FlowGraphObject relies on source-generated container implementation that embeds data within the MonoBehaviour, while FlowGraphInstanceObject explicitly implements container forwarding to a FlowGraphAsset field. Migrating between patterns requires changing the component type and manually transferring graph data to a FlowGraphAsset file.
Where is the graph data physically stored in a FlowGraphObject?
According to the source code in Runtime/Flow/FlowGraphObject.cs, the data persists as a hidden sub-asset directly inside the MonoBehaviour component. The source generator creates this embedded storage when processing the GenerateFlow attribute, making the graph data serialize as part of the GameObject or prefab rather than as a separate asset file.
Does modifying a FlowGraphAsset at runtime affect all FlowGraphInstanceObject instances?
Yes, since FlowGraphInstanceObject forwards all IFlowGraphContainer calls to its shared graphAsset reference, any runtime modifications to that asset would propagate to all instances using it. For independent runtime states, you should instantiate unique copies of the graph data or use FlowGraphObject instead, which stores data per-instance.
How does the Ceres source generator know to implement IFlowGraphContainer for FlowGraphObject?
The GenerateFlow attribute applied to the partial class in FlowGraphObject.cs includes the parameters GenerateRuntime = false and GenerateImplementation = true. This configuration signals the Ceres source generator to create the container implementation and embed the graph data within the component, as seen in the generated code linked through the attribute at lines 136-144 of the source file.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →