Skip to content

Game.Prefabs.ReferenceCollector

Assembly:
Assembly-CSharp (game code)

Namespace:
Game.Prefabs

Type:
class

Base:
System.Object

Summary:
ReferenceCollector traverses an object graph rooted at IAssetData (and other Unity/Colossal asset objects) using reflection to discover references to game assets. It collects PrefabBase, ScriptableObject, AssetReference and AssetData instances found during traversal and returns them grouped in a CollectedReferences result. The collector handles special Colossal/Unity types (PrefabAsset, SurfaceAsset, AssetReference), follows collections (IEnumerable) and dictionaries (IDictionary), caches reflected fields per type for performance, and avoids infinite loops using a visited-object set.


Fields

  • private readonly Dictionary<object, bool> m_VisitedObjects
    Used to record objects already visited during traversal to avoid cycles / repeated work.

  • private readonly Dictionary<Type, FieldInfo[]> m_CachedFields
    Caches the array of reflected fields for each inspected Type (public instance fields + non-public fields marked with [SerializeField]) to reduce repeated reflection cost. Initialized with a capacity of 100.

Nested class CollectedReferences fields:

  • private readonly HashSet<PrefabBase> m_PrefabReferences
    Collects discovered PrefabBase references.

  • private readonly HashSet<ScriptableObject> m_ScriptableObjectReferences
    Collects discovered ScriptableObject references (excluding ComponentBase instances).

  • private readonly HashSet<AssetReference> m_AssetReferences
    Collects discovered AssetReference instances.

  • private readonly HashSet<AssetData> m_AssetDatas
    Collects discovered AssetData instances.

Properties

Nested CollectedReferences exposes these read-only collections:

  • public IReadOnlyCollection<PrefabBase> prefabReferences { get; }
    A read-only view of collected PrefabBase references.

  • public IReadOnlyCollection<ScriptableObject> scriptableObjectReferences { get; }
    A read-only view of collected ScriptableObject references.

  • public IReadOnlyCollection<AssetReference> assetReferences { get; }
    A read-only view of collected AssetReference instances.

  • public IReadOnlyCollection<AssetData> assetDatas { get; }
    A read-only view of collected AssetData instances.

ReferenceCollector itself does not expose any public properties.

Constructors

  • public ReferenceCollector()
    Initializes the internal visited-object dictionary and the per-type field cache (m_CachedFields) with an initial capacity of 100.

Nested CollectedReferences has the implicit default constructor that initializes its internal HashSet collections.

Methods

  • public CollectedReferences CollectDependencies(IEnumerable<IAssetData> objs, bool addRoot)
    Clears visited state, traverses each IAssetData in the enumerable, and returns a CollectedReferences containing discovered assets. If addRoot is true, each provided IAssetData is also added to the returned result (as an AssetData).

  • public CollectedReferences CollectDependencies(IAssetData obj)
    Clears visited state, traverses the single IAssetData root, and returns discovered references. The root itself is not automatically added (use the IEnumerable overload with addRoot to include the root).

  • private void TraverseSurfaceAsset(SurfaceAsset surfaceAsset, CollectedReferences references)
    Handles SurfaceAsset-specific traversal:

  • Ensures the SurfaceAsset is loaded and not already visited.
  • Adds texture assets from surfaceAsset.textures.
  • If the material is a VT material, adds the vtSurfaceAsset and any preprocessed textures referenced by pre-processed texture GUIDs using AssetDatabase.global.GetAsset.

  • private void TraverseObject(object obj, CollectedReferences references)
    Core recursive traversal method:

  • Skips nulls and objects already visited (via TryAddVisited).
  • Special-cases:
    • PrefabBase: adds the prefab and its asset.
    • PrefabAsset: loads the PrefabBase via prefabAsset.Load() and traverses it.
    • SurfaceAsset and AssetReference: delegate to TraverseSurfaceAsset.
    • AssetReference (non-generic): resolves the referenced AssetData via AssetDatabase.global.GetAsset(guid) and adds it.
  • Uses reflection to get fields for the object's Type (cached per type). The fields include public instance fields plus non-public instance fields that have [SerializeField].
  • For each field value:
    • Adds the raw value to the collections.
    • If the value is IDictionary, iterates entries and adds/traverses both keys and values.
    • Else if the value is IEnumerable, iterates elements and adds/traverses each element.
    • Otherwise, recursively TraverseObject on the field value.
  • This method allows discovering embedded and referenced assets in complex nested structures.

  • private bool TryAddVisited(object obj)
    Attempts to add the object to m_VisitedObjects and returns true if the object was not previously visited. Used to prevent infinite recursion on cycles. (Relies on Dictionary.TryAdd semantics.)

Nested CollectedReferences method:

  • public void Add(object obj)
    Adds obj to the appropriate internal collection based on runtime type:
  • If obj is PrefabBase => add to m_PrefabReferences.
  • Else if obj is ScriptableObject and not a ComponentBase => add to m_ScriptableObjectReferences.
  • Else if obj is AssetReference => add to m_AssetReferences.
  • Else if obj is AssetData => add to m_AssetDatas.
  • Ignores nulls.

Notes / Behavior / Caveats: - The collector uses reflection and will inspect public instance fields and non-public instance fields decorated with [SerializeField]. Properties are not inspected. - Collections and dictionaries are traversed by iterating them; any lazy/enumeration side effects will be executed. - The traversal resolves AssetReference GUIDs via AssetDatabase.global.GetAsset and will call PrefabAsset.Load() for prefab assets: this may cause asset loading operations. - Not thread-safe: designed to be used from the main thread or a single-threaded context. - Performance: for large object graphs this can be relatively expensive; field caching reduces repeated reflection overhead. - The visited-object comparison uses object reference equality (dictionary keyed by object), so different instances with equal content are treated separately.

Usage Example

// Example: collect dependencies for a single asset
ReferenceCollector collector = new ReferenceCollector();
IAssetData someAsset = /* obtain an IAssetData, e.g. from AssetDatabase */;
ReferenceCollector.CollectedReferences refs = collector.CollectDependencies(someAsset);

// Iterate collected prefabs
foreach (PrefabBase prefab in refs.prefabReferences)
{
    Debug.Log($"Found prefab: {prefab.name}");
}

// Example: collect dependencies for multiple assets and include the roots
List<IAssetData> assets = new List<IAssetData> { /* ... */ };
ReferenceCollector.CollectedReferences refs2 = collector.CollectDependencies(assets, addRoot: true);

// Inspect collected asset data GUIDs
foreach (AssetData ad in refs2.assetDatas)
{
    Debug.Log($"AssetData: {ad.name} ({ad.GetGuid()})");
}