Skip to content

Game.CityModifierUpdateSystem

Assembly: Game
Namespace: Game.Simulation

Type: class

Base: GameSystemBase

Summary:
CityModifierUpdateSystem is an ECS system that collects and updates city-level modifiers used by the simulation. It aggregates modifiers coming from active policies, building effect providers (buildings/prefabs), installed upgrades and policy sliders. The system runs on an interval (GetUpdateInterval returns 256) and schedules a Burst-compiled IJobChunk (UpdateCityModifiersJob) to perform the per-city work in parallel. Core responsibilities: - Refresh each city's option mask (city.m_OptionMask) based on active policies that expose CityOptionData. - Rebuild each city's DynamicBuffer by aggregating CityModifierData from policies, building prefabs, and installed upgrades. - Respect policy slider adjustments (interpolating modifier ranges), building efficiency (interpolating modifier ranges), and installed-upgrade stacking. - Support modifier modes: Relative, Absolute and InverseRelative (applies math and merging rules). - Uses NativeList/NativeArray and BufferLookup/ComponentLookup to access data efficiently in jobs.


Fields

  • private EntityQuery m_CityQuery
    Tracks the set of city entities to update (cities with Game.City.City). Required for the system to run and used for scheduling the job.

  • private EntityQuery m_EffectProviderQuery
    Query to find effect-provider entities (CityEffectProvider) while excluding Deleted, Destroyed and Temp. Used to gather archetype chunks of effect providers (buildings etc.) to include their modifiers.

  • private CityModifierRefreshData m_CityModifierRefreshData
    Helper struct instance that bundles all the Buffer/Component lookups and logic for refreshing city options and modifiers. It is updated each frame (Update(system)) to refresh type handles/lookups before being used inside the job.

  • private TypeHandle __TypeHandle
    Internal container for Component/Buffer type handles (policy buffer, city component, city modifier buffer). Assigned in OnCreateForCompiler and used when scheduling the job to obtain the actual handles from the system state.

Properties

  • This class does not expose public properties.

Constructors

  • public CityModifierUpdateSystem()
    Default constructor (preserved for the ECS runtime). Initialization happens in OnCreate rather than here.

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    Returns 256. The system is intended to run at a reduced frequency; this value controls update interval.

  • [Preserve] protected override void OnCreate()
    Initializes m_CityModifierRefreshData, creates the queries:

  • m_CityQuery = GetEntityQuery(ComponentType.ReadWrite())
  • m_EffectProviderQuery = GetEntityQuery(ComponentType.ReadOnly(), ComponentType.Exclude(), ComponentType.Exclude(), ComponentType.Exclude()) Also calls RequireForUpdate(m_CityQuery).

  • [Preserve] protected override void OnUpdate()
    Main update:

  • Asynchronously obtains archetype chunks for effect providers (ToArchetypeChunkListAsync).
  • Calls m_CityModifierRefreshData.Update(this) to refresh type & buffer lookups for job usage.
  • Schedules the Burst-compiled UpdateCityModifiersJob (IJobChunk) in parallel over m_CityQuery, passing city/policy/cityModifier handles and the effect provider chunks.
  • Ensures effectProviderChunks are disposed when the job completes and sets base.Dependency to the new job handle.

  • protected override void OnCreateForCompiler()
    Called by the generated/compiled flow to assign queries and the type handle mapping used by the job scheduling. Calls __AssignQueries(...) and __TypeHandle.__AssignHandles(...).

  • private void __AssignQueries(ref SystemState state)
    Internal placeholder used by compiler-generated code. (No query contents assigned here beyond a temporary builder.)

  • public static void InitializeTempList(NativeList<CityModifierData> tempModifierList)
    Clears the supplied NativeList used as a temporary accumulator for modifiers.

  • public static void InitializeTempList(NativeList<CityModifierData> tempModifierList, DynamicBuffer<CityModifierData> cityModifiers)
    Clears and copies the DynamicBuffer into the NativeList for further processing.

  • public static void AddToTempList(NativeList<CityModifierData> tempModifierList, DynamicBuffer<CityModifierData> cityModifiers)
    Merges items from cityModifiers into tempModifierList. If a modifier of the same type already exists in tempModifierList, their ranges (min/max) are summed. Enforces that modes match; throws an Exception if a type collision occurs with differing ModifierValueMode:

  • Exception message: "Modifier mode mismatch (type: {value.m_Type})"

Nested types (high-level overview)

  • private struct UpdateCityModifiersJob : IJobChunk (BurstCompile)
  • Fields passed into the job:
    • m_CityModifierRefreshData (read-only): the helper with lookup handles (this struct itself contains lookup types).
    • m_EffectProviderChunks (read-only NativeList): chunks for effect providers collected asynchronously.
    • m_PolicyType (ReadOnly BufferTypeHandle): buffer handle for per-city policies.
    • m_CityType (ComponentTypeHandle): component handle for the city component (read/write).
    • m_CityModifierType (BufferTypeHandle): buffer handle for city modifiers (read/write).
  • Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask):

    • For each city in the chunk:
    • Calls m_CityModifierRefreshData.RefreshCityOptions(ref city, policies) to set city.m_OptionMask.
    • Calls m_CityModifierRefreshData.RefreshCityModifiers(modifiers, policies, m_EffectProviderChunks, tempModifierList) to populate the city's modifiers buffer.
    • Uses a temporary NativeList per Execute call to aggregate building/upgrades modifiers and disposes it at the end.
    • The job implementation also contains the explicit IJobChunk.Execute wrapper.
  • public struct CityModifierRefreshData

  • Contains BufferTypeHandle/ComponentTypeHandle/ComponentLookup/BufferLookup used to access building efficiencies, prefab refs, installed upgrades, signatures, policy slider data, city option data and CityModifierData buffers.
  • Constructor CityModifierRefreshData(SystemBase system): initializes all handles/lookups (read-only where appropriate).
  • Update(SystemBase system): calls Update on each handle/lookup to get fresh accessors for the job scheduling frame.
  • RefreshCityOptions(ref Game.City.City city, DynamicBuffer policies):
    • Resets city.m_OptionMask and ORs in CityOptionData.m_OptionMask for each active policy that has CityOptionData.
  • RefreshCityModifiers(DynamicBuffer modifiers, DynamicBuffer policies, NativeList effectProviderChunks, NativeList tempModifierList):
    • Clears modifiers buffer, then:
    • Iterates active policies and adds their CityModifierData to the modifiers buffer, respecting policy slider adjustments (interpolating within modifierData.m_Range).
    • Iterates effectProviderChunks (extra loop to handle signature or buffer presence) to process each provider entity:
      • For building providers, uses BuildingUtils.GetEfficiency(bufferAccessor[l]) to compute efficiency and interpolates the modifier range by that efficiency.
      • Includes installed upgrades by calling AddToTempList(tempModifierList, installedUpgradesBuffer).
      • Adds computed deltas into the city modifiers using AddModifier.
    • Handles two paths depending on whether an archetype chunk has a signature component or not (affects how efficiency is interpreted).
  • AddToTempList(DynamicBuffer upgrades):
    • For each installed upgrade (that is not inactive), attempts to get the prefab for the upgrade and, if that prefab has CityModifierData, adds those modifiers to a temp list via static CityModifierUpdateSystem.AddToTempList(tempModifierList, bufferData).
  • private static AddModifier(DynamicBuffer modifiers, CityModifierData modifierData, float delta):
    • Ensures the modifiers buffer is large enough for modifierData.m_Type.
    • Applies delta based on ModifierValueMode:
    • Relative: value.m_Delta.y = value.m_Delta.y * (1f + delta) + delta;
    • Absolute: value.m_Delta.x += delta;
    • InverseRelative: converts delta to inverse (1 / (1+delta) - 1) then uses relative formula.
    • Writes back into the modifiers buffer.

Notes on concurrency & memory: - The job is Burst-compiled and scheduled as an IJobChunk; all Buffer/Component lookups are updated before scheduling. - Temporary NativeList (effectProviderChunks) is allocated with Allocator.TempJob and disposed with a job handle. - Per-chunk temporary NativeList is allocated with Allocator.Temp and disposed inside the job Execute method.

Usage Example

[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    m_CityModifierRefreshData = new CityModifierRefreshData(this);
    m_CityQuery = GetEntityQuery(ComponentType.ReadWrite<Game.City.City>());
    m_EffectProviderQuery = GetEntityQuery(
        ComponentType.ReadOnly<CityEffectProvider>(),
        ComponentType.Exclude<Deleted>(),
        ComponentType.Exclude<Destroyed>(),
        ComponentType.Exclude<Temp>());
    RequireForUpdate(m_CityQuery);
}

Additional tips: - Modders adding new CityModifierData buffers (on policies, prefabs or upgrades) should ensure modifier types and modes are consistent to avoid the "Modifier mode mismatch" exception when merging. - When creating new effect-provider prefabs, ensure PrefabRef and InstalledUpgrade data are set up so CityModifierRefreshData can discover and use their CityModifierData buffers. - Because UpdateCityModifiersJob uses Burst and runs in parallel, avoid accessing managed objects or UnityEngine API from inside CityModifierData-processing paths.