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
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 DynamicBufferinto 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
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.