Asset Property Graph
Role
Stride.Core.Assets.Quantum wraps the core Quantum graph with asset-specific semantics: override tracking, base-asset linking, and archetype/prefab inheritance. When a derived prefab overrides a value from its base, the graph records that override and can reset it. This is the layer that makes "this property is bold because it's overridden" possible in GameStudio.
IAssetNode Extensions
IAssetNode extends IGraphNode with asset-aware members:
| Member | Type | Purpose |
|---|---|---|
PropertyGraph |
AssetPropertyGraph |
The graph that owns this node |
BaseNode |
IGraphNode |
The corresponding node in the base asset, or null if none |
OverrideChanging |
event | Raised before override state changes |
OverrideChanged |
event | Raised after override state changes |
ResetOverrideRecursively() |
method | Resets this node and all descendants to inherited values |
SetContent(key, node) |
method | Attaches an auxiliary node (used internally) |
GetContent(key) |
method | Retrieves an attached auxiliary node |
IAssetMemberNode (extends IAssetNode, IMemberNode) and IAssetObjectNode (extends IAssetNode, IObjectNode) are the concrete asset-aware node types. IAssetObjectNode adds per-item override tracking for collections (IsItemInherited, IsItemOverridden, OverrideItem, etc.).
Override Model
A property in a derived asset is in one of three states:
| State | Meaning | GameStudio visual |
|---|---|---|
| Inherited | Value comes from the base asset; any change to the base propagates here | Normal weight, italic |
| Overridden | Value was explicitly set on this derived asset, shadowing the base | Bold |
| No base | Asset has no base (or this property has no base equivalent) | Normal weight |
ResetOverride() is a method on IAssetNodePresenter (the presenter layer — see property-grid.md), not on IAssetNode directly. Calling it restores the overridden value to its inherited state, and the graph then re-propagates the base value. The underlying graph node's ResetOverrideRecursively() handles the recursive reset; the presenter method is the entry point from the UI.
When a composite node (an object with children) is reset, all descendant nodes are also reset recursively.
Note
When just adding a new asset type: if your asset has no base/derived relationship and you are not implementing archetypes or prefab composition, the override model is invisible to you. IsInherited will always be false and HasBase will always be false. You do not need to understand this layer to add a new asset type.
AssetPropertyGraph
AssetPropertyGraph wraps a NodeContainer and adds override semantics on top:
- Created via
AssetQuantumRegistry.ConstructPropertyGraph(container, assetItem, logger)wherecontaineris anAssetPropertyGraphContainer(not a rawNodeContainer) — this is obtained from the editor session; do not instantiate it manually - Tied to the editor session — created when an asset is opened, disposed when closed
- Links each node to its counterpart in the base asset graph (if the asset has an archetype)
- Propagates base values to all inherited nodes on load
You rarely interact with AssetPropertyGraph directly. The presenter layer reads from it via IAssetNodePresenter.Asset and IAssetNodePresenter.HasBase.
AssetPropertyGraphDefinition
AssetPropertyGraphDefinition tells the graph which member values are object references (shared identities, loaded separately by ContentManager) vs inline data (copied into the asset).
Provide one only when your asset type holds references to other content objects. If you don't, the default definition treats all values as inline — which is correct for most new asset types.
// sources/engine/Stride.Assets/YourFeature/YourAssetPropertyGraphDefinition.cs
using Stride.Core.Assets.Quantum;
using Stride.Core.Quantum;
namespace Stride.Assets.YourFeature;
[AssetPropertyGraphDefinition(typeof(YourAsset))]
public class YourAssetPropertyGraphDefinition : AssetPropertyGraphDefinition
{
// Return true when the value stored in 'member' is an object reference
// (i.e. a handle to a separately-loaded content object, not an inline copy).
public override bool IsMemberTargetObjectReference(IMemberNode member, object? value)
{
// Example: treat any Prefab member as an object reference
if (value is Prefab)
return true;
return base.IsMemberTargetObjectReference(member, value);
}
// Return true when a collection item is an object reference.
public override bool IsTargetItemObjectReference(IObjectNode collection, NodeIndex itemIndex, object? value)
{
// Example: treat items in PrefabCollection as object references
if (collection.Descriptor.ElementType == typeof(Prefab))
return true;
return base.IsTargetItemObjectReference(collection, itemIndex, value);
}
}
The [AssetPropertyGraphDefinition(typeof(YourAsset))] attribute is discovered automatically when the assembly is registered. No manual registration is needed beyond AssetQuantumRegistry.RegisterAssembly() in Module.cs.
Note
When just adding a new asset type: if all your asset's properties are plain data values (numbers, strings, lists of structs), you do not need an AssetPropertyGraphDefinition. Only provide one when your asset class has members that hold references to other content objects (Prefabs, Textures, Materials, etc.) that should remain as references rather than be embedded inline.
AssetQuantumRegistry
| Method | When to call |
|---|---|
AssetQuantumRegistry.RegisterAssembly(assembly) |
From Module.cs — call once per assembly containing asset graph types |
AssetQuantumRegistry.ConstructPropertyGraph(AssetPropertyGraphContainer, AssetItem, ILogger?) |
Called internally by the editor session; do not call manually |
AssetQuantumRegistry.GetDefinition(assetType) |
Called internally; do not call manually |
RegisterAssembly scans the assembly for AssetPropertyGraph subclasses (decorated with [AssetPropertyGraph(typeof(T))]) and AssetPropertyGraphDefinition subclasses (decorated with [AssetPropertyGraphDefinition(typeof(T))]) and registers them.
In Module.cs for an assembly that contains both asset classes and graph types:
[ModuleInitializer]
public static void Initialize()
{
// AssemblyRegistry.Register is required for assemblies that contain Asset subclasses.
// If the assembly only contains graph types (no Asset subclasses), omit this line.
AssemblyRegistry.Register(typeof(Module).Assembly, AssemblyCommonCategories.Assets);
AssetQuantumRegistry.RegisterAssembly(typeof(Module).Assembly);
}
Assembly Placement
Stride.Core.Assets.Quantum — sources/assets/Stride.Core.Assets.Quantum/
Concrete AssetPropertyGraphDefinition subclasses for engine assets live alongside their asset classes (e.g. sources/engine/Stride.Assets/).