Skip to content

Game.PrefabSystem

Assembly: Game (Cities: Skylines 2)
Namespace: Game.Prefabs

Type: class

Base: GameSystemBase, IDefaultSerializable, ISerializable

Summary:
PrefabSystem is the central runtime registry and manager for PrefabBase instances in the game. It tracks loaded prefabs, manages the underlying ECS entities that represent prefabs, handles prefab add/remove/update operations, resolves obsolete (missing) prefab IDs during save/load, caches availability and unlockable state for content and unlock requirements, and exposes helper APIs to query prefab-related ECS components and buffers. It also integrates with the game update pipeline to finalize prefab updates and to notify other systems about replaced prefabs and content availability changes.


Fields

  • private ILog m_UnlockingLog
    Logger used to report unlocking-related diagnostics and warnings.

  • private UpdateSystem m_UpdateSystem
    Reference to the UpdateSystem used to run prefab update phase.

  • private List<PrefabBase> m_Prefabs
    Ordered list of currently registered prefabs. Index in this list is stored in PrefabData on the prefab entity.

  • private List<ObsoleteData> m_ObsoleteIDs
    List of obsolete IDs discovered when loading saved data; used to map negative indices to missing prefab identifiers.

  • private List<LoadedIndexData> m_LoadedIndexData
    Temporary list populated while deserializing to map saved indices to current prefab entities.

  • private Dictionary<PrefabBase, Entity> m_UpdateMap
    Map of prefabs scheduled for update -> optional source instance entity; processed during OnUpdate.

  • private Dictionary<PrefabBase, Entity> m_Entities
    Map of prefab object -> ECS entity that stores component prototypes and prefab metadata.

  • private Dictionary<PrefabBase, bool> m_IsUnlockable
    Cache: whether a prefab (or its dependency tree) is unlockable.

  • private Dictionary<ContentPrefab, bool> m_IsAvailable
    Cache of content prerequisites' availability states to avoid repeated checks.

  • private Dictionary<int, PrefabID> m_LoadedObsoleteIDs
    Mapping for loaded indices (from saved games) that pointed to obsolete/missing PrefabIDs.

  • private Dictionary<PrefabID, int> m_PrefabIndices
    Reverse lookup mapping from PrefabID -> index in m_Prefabs.

  • private ComponentTypeSet m_UnlockableTypes
    (Declared but not referenced in public API) likely used to store component types required for unlockable prefabs.

Properties

  • internal IEnumerable<PrefabBase> prefabs => m_Prefabs
    Read-only enumerable view of the registered prefabs in registration order.

  • public event PrefabSystem.EventContentAvailabilityChanged onContentAvailabilityChanged
    Event invoked when a tracked ContentPrefab's availability changes (used to update UI or dependent systems). Delegate signature: void EventContentAvailabilityChanged(ContentPrefab contentPrefab).

Constructors

  • public PrefabSystem()
    Default parameterless constructor (annotated with [Preserve] in source). Initialization of runtime collections happens in OnCreate.

Methods

  • protected override void OnCreate()
    Initializes the system: creates internal lists and dictionaries, retrieves UpdateSystem, and acquires logger. Called by the ECS runtime when the system is created.

  • public bool AddPrefab(PrefabBase prefab, string parentName = null, PrefabBase parentPrefab = null, ComponentBase parentComponent = null)
    Registers a prefab into the system: creates an ECS entity with the prefab's component archetype, stores its PrefabData (index), updates reverse lookup maps, registers obsolete identifiers if provided by the prefab. Returns true if registration succeeded. Performs availability check and logs errors/warnings for duplicates or missing dependencies.

  • public bool RemovePrefab(PrefabBase prefab)
    Unregisters a prefab: marks the prefab entity as Deleted, removes and updates indices so the m_Prefabs list remains dense, updates m_PrefabIndices, and removes caches for that prefab. Returns true if removal succeeded.

  • public PrefabBase DuplicatePrefab(PrefabBase template, string name = null)
    Creates a cloned copy of a given prefab (calls Clone), removes ObsoleteIdentifiers from the clone, registers it and returns the new PrefabBase instance.

  • public void UpdatePrefab(PrefabBase prefab, Entity sourceInstance = default(Entity))
    Schedules a prefab to be updated on the next update cycle. sourceInstance is passed to the ReplacePrefab system to copy data from an instance if provided.

  • public string[] GetAvailablePrerequisitesNames()
    Returns names of content prerequisites currently marked available. Returns null if none.

  • public IEnumerable<ContentPrefab> GetAvailableContentPrefabs()
    Enumerates ContentPrefab instances considered available in the cached map.

  • public bool IsAvailable(PrefabBase prefab)
    Checks whether the prefab's ContentPrerequisite (if present) is available. Caches the result in m_IsAvailable and invokes onContentAvailabilityChanged when first discovered.

  • public void UpdateAvailabilityCache()
    Re-evaluates all cached ContentPrefab entries in m_IsAvailable and fires onContentAvailabilityChanged whenever availability changes.

  • public bool IsUnlockable(PrefabBase prefab)
    Determines (and caches) whether the prefab is unlockable. Uses IsUnlockableImpl to traverse dependencies and detect UnlockRequirementPrefabs or UnlockableBase components.

  • private bool IsUnlockableImpl(PrefabBase prefab, List<PrefabBase> dependencies, List<ComponentBase> components)
    Recursive helper that walks prefab component dependencies to determine unlockable status while avoiding cycles.

  • public void AddUnlockRequirement(PrefabBase unlocker, PrefabBase unlocked)
    Adds an UnlockRequirement buffer entry to the unlocked prefab referencing the unlocker entity, if both sides are unlockable. Logs warnings if not.

  • public void AddUnlockRequirement(PrefabBase unlocker, PrefabBase[] unlocked)
    Overload that adds the same unlocker requirement to multiple unlocked prefabs.

  • public T GetPrefab<T>(PrefabData prefabData) where T : PrefabBase
    Return the PrefabBase instance for the given PrefabData index cast to T.

  • public T GetPrefab<T>(Entity entity) where T : PrefabBase
    Return the prefab for an ECS entity (reads PrefabData component).

  • public T GetPrefab<T>(PrefabRef refData) where T : PrefabBase
    Return the prefab referenced by a PrefabRef.

  • public bool TryGetPrefab<T>(PrefabData prefabData, out T prefab) where T : PrefabBase
    Try-get variant that returns false for negative/invalid indices.

  • public bool TryGetPrefab<T>(Entity entity, out T prefab) where T : PrefabBase
    Try-get by entity.

  • public bool TryGetPrefab<T>(PrefabRef refData, out T prefab) where T : PrefabBase
    Try-get by PrefabRef.

  • public T GetSingletonPrefab<T>(EntityQuery group) where T : PrefabBase
    Returns the prefab corresponding to the singleton entity in the provided query.

  • public bool TryGetSingletonPrefab<T>(EntityQuery group, out T prefab) where T : PrefabBase
    Try-get singleton prefab if query not empty.

  • public Entity GetEntity(PrefabBase prefab)
    Returns the internal ECS entity associated with the given prefab. Throws if not registered.

  • public bool TryGetEntity(PrefabBase prefab, out Entity entity)
    Try-get the entity for a prefab.

  • public bool HasComponent<T>(PrefabBase prefab) where T : unmanaged
    Checks whether the prefab entity has a particular component type.

  • public bool HasEnabledComponent<T>(PrefabBase prefab) where T : unmanaged, IEnableableComponent
    Checks whether an enableable component is enabled on the prefab entity.

  • public T GetComponentData<T>(PrefabBase prefab) where T : unmanaged, IComponentData
    Gets a component's data from the prefab entity.

  • public bool TryGetComponentData<T>(PrefabBase prefab, out T component) where T : unmanaged, IComponentData
    Try-get component data.

  • public DynamicBuffer<T> GetBuffer<T>(PrefabBase prefab, bool isReadOnly) where T : unmanaged, IBufferElementData
    Returns a dynamic buffer from the prefab entity.

  • public bool TryGetBuffer<T>(PrefabBase prefab, bool isReadOnly, out DynamicBuffer<T> buffer) where T : unmanaged, IBufferElementData
    Try-get buffer.

  • public void AddComponentData<T>(PrefabBase prefab, T componentData) where T : unmanaged, IComponentData
    Adds a component instance to the prefab entity.

  • public void RemoveComponent<T>(PrefabBase prefab) where T : unmanaged, IComponentData
    Removes a component type from the prefab entity.

  • protected override void OnUpdate()
    Main update loop: calls UpdatePrefabs to process scheduled prefab updates, executes UpdateSystem prefab update phase, and asks ReplacePrefabSystem to finalize replacements when updates occurred.

  • private bool UpdatePrefabs()
    Processes m_UpdateMap: for each prefab scheduled to update, creates a new prefab entity with current components, copies PrefabData index, preserves Locked enabled state where applicable, and registers replacements with ReplacePrefabSystem. Returns true if any update processed.

  • public void Serialize<TWriter>(TWriter writer) where TWriter : IWriter
    Serializes currently enabled prefabs and obsolete IDs into the writer. Writes counts followed by PrefabID entries for present prefabs and obsolete ids.

  • public void Deserialize<TReader>(TReader reader) where TReader : IReader
    Deserializes saved prefab lists: attempts to map saved PrefabID entries to registered prefabs. Populates m_LoadedIndexData for known prefab mappings and m_LoadedObsoleteIDs for missing ones (obsolete). Supports version-specific handling for obsolete prefab fixes.

  • public void SetDefaults(Context context)
    Resets internal temporary lists (used prior to loading).

  • public void UpdateLoadedIndices()
    After deserialization, writes LoadedIndex buffer entries into prefab entities to restore which saved-indexed prefabs were loaded into which current entities.

  • public bool TryGetPrefab(PrefabID id, out PrefabBase prefab)
    Lookup by PrefabID using m_PrefabIndices.

  • public PrefabID GetLoadedObsoleteID(int loadedIndex)
    Returns the PrefabID for a loaded index that was obsolete/missing at load time; returns a placeholder "[Missing]" id if not found.

  • public void AddObsoleteID(Entity entity, PrefabID id)
    Records that this entity corresponds to an unknown/missing saved PrefabID, logs a warning.

  • public PrefabID GetObsoleteID(PrefabData prefabData)
    Gets obsolete ID for a PrefabData representing a missing prefab (negative index).

  • public PrefabID GetObsoleteID(Entity entity)
    Gets obsolete ID by entity.

  • public string GetPrefabName(Entity entity)
    Returns the prefab name for an entity. If the PrefabData index is negative, will return the obsolete PrefabID's name; otherwise returns the registered prefab's name. Falls back to entity.ToString() if PrefabData missing.

Usage Example

// Example: registering a prefab, subscribing to content availability changes and querying prefab ECS data.

public class MyMod
{
    PrefabSystem m_PrefabSystem;

    public void Initialize(World world)
    {
        m_PrefabSystem = world.GetOrCreateSystemManaged<PrefabSystem>();
        // Subscribe to content availability changes (UI or other systems can react)
        m_PrefabSystem.onContentAvailabilityChanged += OnContentAvailabilityChanged;
    }

    private void OnContentAvailabilityChanged(ContentPrefab content)
    {
        Debug.Log($"Content availability changed: {content.name}");
    }

    public void RegisterMyPrefab(PrefabBase prefab)
    {
        // Add prefab (parentName / parentPrefab optional for logging)
        if (m_PrefabSystem.AddPrefab(prefab))
        {
            var entity = m_PrefabSystem.GetEntity(prefab);
            Debug.Log($"Prefab registered, entity: {entity}");
        }
    }

    public void RemoveMyPrefab(PrefabBase prefab)
    {
        m_PrefabSystem.RemovePrefab(prefab);
    }
}

If you want, I can generate a smaller quick-reference (method signatures only) or add explicit examples for serialization/deserialization and UnlockRequirement usage.