Skip to content

Game.Simulation.UpdateGroupSystem

Assembly:
Game (simulation / Entities systems for Cities: Skylines 2)

Namespace:
Game.Simulation

Type:
class (SystemBase / managed ECS system)

Base:
GameSystemBase

Summary:
UpdateGroupSystem is an ECS system used by the simulation to assign and maintain UpdateFrame shared-component indices for entities and to balance update-group sizes (how many entities belong to each update slot). It tracks created/deleted entities that have an UpdateFrame shared component, updates per-entity InterpolatedTransform data for moving objects, and schedules two main jobs:

  • UpdateGroupJob: handles newly created / deleted entities (assigning UpdateFrame indices based on several heuristics: controller/original entity, prefab data, or balancing across available update groups). It also copies or initializes TransformFrame buffers for interpolation and updates InterpolatedTransform components for newly created entities.
  • MovingObjectsUpdatedJob: runs for updated moving objects to refresh their InterpolatedTransform and rotate transform-history buffers (TransformFrame) so interpolation uses the most recent frames.

The system keeps per-category group size arrays (moving objects, trees, buildings, net, lanes, companies, households, citizens, household pets) in UpdateGroupSizes for balancing. It interacts with a ModificationBarrier to apply SetSharedComponent commands safely.


Fields

  • private SimulationSystem m_SimulationSystem
    Reference to the SimulationSystem used to obtain the running simulation frame index (m_SimulationSystem.frameIndex). Used by MovingObjectsUpdatedJob to compute frame offsets for transform frame rotation.

  • private ModificationBarrier5 m_ModificationBarrier
    Barrier system used to produce EntityCommandBuffer operations (SetSharedComponent) from jobs. Ensures safe mutation of shared components from job threads.

  • private EntityQuery m_CreatedQuery
    Query that finds entities that have an UpdateFrame shared component and are either Created or Deleted (used to process newly created or deleted entities).

  • private EntityQuery m_UpdatedQuery
    Query that finds entities that were Updated and have UpdateFrame and Moving components (and exclude Created). Used to schedule MovingObjectsUpdatedJob.

  • private UpdateGroupTypes m_UpdateGroupTypes
    Helper struct holding ComponentTypeHandle and method to update them each frame (handles for various component types used to detect archetype categories, e.g., Moving, Plant, Building, Node, Lane, CompanyData, Citizen, etc.). Used by UpdateGroupSizes.Get to determine which group-size array to use for a chunk.

  • private UpdateGroupSizes m_UpdateGroupSizes
    Holds NativeArray arrays (per update-group slot) for multiple categories (moving objects, trees, buildings, net, lane, company, household, citizen, household pet). These arrays are used by UpdateGroupJob to pick the least-loaded update slot and to keep counts up-to-date when entities are added/removed.

  • private TypeHandle __TypeHandle
    Internal container of ComponentTypeHandles / SharedComponentTypeHandle / BufferLookup / ComponentLookup used by the system to fetch handles from SystemState in a single place (generated helper type).

Properties

  • None (no public properties exposed by this system class).
    The system exposes a getter method GetUpdateGroupSizes() to access the UpdateGroupSizes.

Constructors

  • public UpdateGroupSystem()
    Default constructor. No special initialization beyond the base class (OnCreate contains runtime initialization).

Methods

  • protected override void OnCreate()
    Initializes system-level resources:
  • Gets references to SimulationSystem and ModificationBarrier5 from the world.
  • Creates two EntityQuery objects: m_CreatedQuery (entities with UpdateFrame plus Created/Deleted) and m_UpdatedQuery (Updated + UpdateFrame + Moving, excluding Created).
  • Initializes m_UpdateGroupTypes (component handles) and allocates m_UpdateGroupSizes with Allocator.Persistent.

  • protected override void OnDestroy()
    Disposes m_UpdateGroupSizes (NativeArrays) then calls base.OnDestroy().

  • protected override void OnUpdate()
    Main update loop:

  • If m_CreatedQuery is not empty: collects archetype chunks async, updates component handles, constructs and schedules UpdateGroupJob which processes entity creation/deletion and assigns UpdateFrame indices and manages TransformFrame buffers. Adds job handle dependency to the ModificationBarrier producer.
  • If m_UpdatedQuery is not empty: builds and schedules MovingObjectsUpdatedJob (parallel) to refresh InterpolatedTransform and rotate or copy TransformFrame history for moving objects. Uses m_SimulationSystem.frameIndex for frame math.

  • public UpdateGroupSizes GetUpdateGroupSizes()
    Returns the m_UpdateGroupSizes struct (by value). This lets other systems inspect the current group-size NativeArrays used for balancing. Note: the returned struct owns NativeArrays allocated by this system — do not Dispose() them externally.

  • protected override void OnCreateForCompiler()
    Generated helper used by the build/runtime to assign queries and type handles via __AssignQueries and __TypeHandle.__AssignHandles. (Boilerplate for the generated TypeHandle pattern in compiled systems.)

  • private void __AssignQueries(ref SystemState state)
    Generated helper for constructing entity queries (here it simply creates/tears down an EntityQueryBuilder; present for compiler-generated scaffolding).

Nested/inner types (high-level summaries): - UpdateGroupTypes (struct)
Holds ComponentTypeHandle references for many component types used to classify archetype chunks (Moving, Stopped, Plant, Building, Extension, Node, Edge, Lane, CompanyData, Household, Citizen, HouseholdPet, CurrentVehicle). Has constructor taking a SystemBase and an Update(system) method to refresh the handles each frame.

  • UpdateGroupSizes (struct)
    Pre-allocates multiple NativeArray arrays sized to 16 update-group slots for each category: moving objects, trees (plants), buildings, net (node/edge), lanes, companies, households, citizens, household pets. Has Clear(), Dispose(), and Get(ArchetypeChunk, UpdateGroupTypes) which selects the appropriate array based on the presence of component types in the chunk.

  • UpdateGroupJob (Burst-compiled IJob)
    Iterates provided archetype-chunks (created & deleted sets) and:

  • For deleted-only chunks: decrements the count for the chunk's assigned UpdateFrame index in the correct category array (unless the chunk has Temp).
  • For created chunks: decides an UpdateFrame index for each entity based on multiple heuristics:

    • If entity has Controller referencing another entity, try to inherit update frame from controller (falls back).
    • If Temp with original entity, try to inherit update frame of original.
    • If prefab provides UpdateFrameData, use prefab-specified group index.
    • Otherwise pick the least-loaded slot from the category-specific group-size array.
    • Sets shared UpdateFrame on entities (via EntityCommandBuffer) and on associated LayoutElement vehicles (e.g., coach/attached vehicles).
    • Initializes InterpolatedTransform components and TransformFrame buffers (copy from original if Temp.original exists, else create default frames from current transform). It updates group-size arrays accordingly.
  • MovingObjectsUpdatedJob (Burst-compiled IJobChunk)
    For chunks of moving objects that were updated, updates InterpolatedTransform components and rotates or copies TransformFrame buffers such that interpolation uses recent frames and sets state and activity based on HumanNavigation when available. It computes a per-entity write offset using simulation frame and the entity's UpdateFrame index.

Implementation notes / important details: - The system relies on UpdateFrame as a SharedComponent to distribute entities across 16 update-group indices (UpdateFrame index range is 0..15; many loops assume length 16 and transform-frame buffer length 4). - UpdateGroupSizes uses 16-group arrays and TransformFrame history uses 4 slots (implementation-specific values). - UpdateGroupJob uses the ModificationBarrier's EntityCommandBuffer to set shared components from a job context. - The system uses several component lookups (Created, UpdateFrameData from prefabs, TransformFrame buffers) to make decisions and copy initial buffers.

Usage Example

// Accessing the system and reading update group sizes from a mod or another system:
var world = World.DefaultGameObjectInjectionWorld;
var updateSystem = world.GetExistingSystemManaged<Game.Simulation.UpdateGroupSystem>();
if (updateSystem != null)
{
    var sizes = updateSystem.GetUpdateGroupSizes();
    // Example: read moving-object group sizes (do NOT Dispose() the arrays)
    // The struct exposes NativeArray<int> fields internally; if you need read access,
    // you would extend the system or add an accessor method that returns a snapshot.
}

// Typical usage is letting the system run automatically in the simulation update loop.
// The system assigns UpdateFrame shared-components for new entities and keeps
// interpolation history up to date for moving entities.

Notes for modders: - Do not Dispose() the native arrays returned by GetUpdateGroupSizes(); they are owned by the system and freed in OnDestroy(). - If you need to influence how entities are assigned to update groups (for example for a custom prefab), provide UpdateFrameData on the prefab or ensure controllers/original entities have UpdateFrame set. Otherwise the system will balance entities to the least-loaded slot automatically. - When modifying or setting UpdateFrame shared-components yourself, be careful to use appropriate command buffers or scheduling to avoid race conditions with this system and its ModificationBarrier.