Skip to content

Game.ResidentialDemandSystem

Assembly: Assembly-CSharp
Namespace: Game.Simulation

Type: class

Base: GameSystemBase, IDefaultSerializable, ISerializable

Summary:
ResidentialDemandSystem is an ECS-managed game system that computes residential demand for Cities: Skylines 2. It periodically (every 16 ticks with an update offset) runs a Burst-compiled job (UpdateResidentialDemandJob) that collects data from multiple supporting systems (taxes, study positions, workplaces, household counts, residential property counts, city population, zone prefabs, etc.), calculates household and per-density building demand (low/medium/high), populates demand factor arrays used for debugging/UI, and enqueues a ResidentialDemand trigger when appropriate. The system stores the last-computed demands and exposes readers for other systems/jobs via NativeContainers and JobHandles.


Fields

  • public static readonly int kMaxFactorEffect
    Maximum cap used for some factor effects (value = 15).

  • private TaxSystem m_TaxSystem
    Reference to the TaxSystem used to read residential tax rates.

  • private CountStudyPositionsSystem m_CountStudyPositionsSystem
    System used to count study (student) positions by education.

  • private CountWorkplacesSystem m_CountWorkplacesSystem
    System used to query free/total workplaces across simple/complex types.

  • private CountHouseholdDataSystem m_CountHouseholdDataSystem
    Provides household counts, homelessness and unemployment rates.

  • private CountResidentialPropertySystem m_CountResidentialPropertySystem
    Provides counts of free and total residential properties by density.

  • private CitySystem m_CitySystem
    Provides the city entity reference.

  • private TriggerSystem m_TriggerSystem
    Used to enqueue TriggerAction instances (e.g., ResidentialDemand trigger).

  • private EntityQuery m_DemandParameterGroup
    EntityQuery to fetch DemandParameterData.

  • private EntityQuery m_UnlockedZonePrefabQuery
    EntityQuery to enumerate unlocked Zone prefabs (ZoneData + ZonePropertiesData).

  • private EntityQuery m_GameModeSettingQuery
    EntityQuery to fetch ModeSettingData (game mode tweaks to demand weighting).

  • private NativeValue<int> m_HouseholdDemand
    Persistent NativeValue holding the current household demand (written by the job).

  • private NativeValue<int3> m_BuildingDemand
    Persistent NativeValue holding the current per-density building demand (low/med/high).

  • private NativeArray<int> m_LowDemandFactors
    EnumArray-sized NativeArray storing individual demand factor contributions for low density (debug/UI).

  • private NativeArray<int> m_MediumDemandFactors
    EnumArray-sized NativeArray storing individual demand factor contributions for medium density (debug/UI).

  • private NativeArray<int> m_HighDemandFactors
    EnumArray-sized NativeArray storing individual demand factor contributions for high density (debug/UI).

  • private JobHandle m_WriteDependencies
    Latest JobHandle that writers produce — used to expose dependency to readers.

  • private JobHandle m_ReadDependencies
    Combined JobHandle of readers; used to combine with new scheduled jobs.

  • private int m_LastHouseholdDemand
    Cached value of the last-known household demand (used by property).

  • private int3 m_LastBuildingDemand
    Cached value of the last-known building demand per density.

  • private float2 m_ResidentialDemandWeightsSelector
    Weight selector used to convert factor floats into integer contributions; comes from ModeSettingData or defaults to (1,1).

  • private TypeHandle __TypeHandle
    Internal struct holding ComponentLookup handles assigned at creation for safe access in jobs.


Properties

  • public int householdDemand { get; }
    Returns the last computed household demand (m_LastHouseholdDemand). This value is updated each OnUpdate when demand is recomputed.

  • public int3 buildingDemand { get; }
    Returns the last computed per-density building demand (m_LastBuildingDemand). int3 components correspond to low, medium, high densities.


Constructors

  • public ResidentialDemandSystem()
    Default constructor. The system initializes internal references and Native containers during OnCreate. No custom parameters.

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    Returns the update interval (16). Controls how often the system recalculates demand.

  • public override int GetUpdateOffset(SystemUpdatePhase phase)
    Returns the update offset (10). Used by scheduler to offset when the system runs relative to other systems.

  • public NativeArray<int> GetLowDensityDemandFactors(out JobHandle deps)
    Returns the NativeArray for low-density demand factors and outputs a JobHandle (deps) representing writers' dependencies. Callers must respect the JobHandle.

  • public NativeArray<int> GetMediumDensityDemandFactors(out JobHandle deps)
    Same as above for medium-density factors.

  • public NativeArray<int> GetHighDensityDemandFactors(out JobHandle deps)
    Same as above for high-density factors.

  • public void AddReader(JobHandle reader)
    Add a reader dependency so the system can combine it when scheduling. Combines with internal m_ReadDependencies.

  • protected override void OnGameLoaded(Context serializationContext)
    Called when a saved game is loaded. Reads ModeSettingData (if present and enabled) to set m_ResidentialDemandWeightsSelector; otherwise sets default (1,1).

  • protected override void OnCreate()
    Sets up EntityQueries, fetches or creates references to dependent systems (tax, workplaces, counts, triggers, city system), and allocates persistent Native containers: m_HouseholdDemand, m_BuildingDemand, and the three demand factor arrays. Also sets default weight selector.

  • protected override void OnDestroy()
    Disposes the persistent NativeValue and NativeArray containers to avoid leaks and calls base.OnDestroy().

  • public void SetDefaults(Context context)
    Resets demand values and factor arrays to zero and clears cached last values — often used on new game or reset.

  • public void Serialize<TWriter>(TWriter writer) where TWriter : IWriter
    Writes current demand state and demand factor arrays to the save writer: household demand, building demand (int3), factor length and arrays, last cached demand values. Used by the save system.

  • public void Deserialize<TReader>(TReader reader) where TReader : IReader
    Reads serialized state. Includes version compatibility handling:

  • For versions before residentialDemandSplit, a single building demand int is read and split across densities.
  • For earlier factor-count versions, it reads a shorter factor array and copies into the internal arrays safely.
  • Restores last cached demand values accordingly.

  • protected override void OnUpdate()
    Main runtime method. If DemandParameterData is present, it:

  • Backs up last demand values,
  • Builds an UpdateResidentialDemandJob with data fetched asynchronously (unlocked zone prefabs, demand parameters list, study positions, workplace counts, household/property counts, tax rates, population, etc.),
  • Schedules the job (Burst) combining existing dependencies and readers,
  • Stores the resulting write dependency in m_WriteDependencies and registers readers with dependent systems (study positions, taxes, trigger buffer writer, etc.). The scheduled job computes all demand math and enqueues a ResidentialDemand trigger when appropriate.

  • private void __AssignQueries(ref SystemState state)
    Internal helper for compiler-inserted query assignment (kept for compatibility with generated code).

  • protected override void OnCreateForCompiler()
    Internal initialization that assigns queries and component lookups to __TypeHandle.

Inner types:

  • UpdateResidentialDemandJob (private struct, BurstCompile, implements IJob)
    Core job that performs the demand calculation. Highlights:
  • Receives read-only lists/lookups for unlocked zone prefabs, populations, zone data/properties, demand parameters, study positions, tax rates, and unemployment rate.
  • Receives value/arrays to write: m_HouseholdDemand, m_BuildingDemand and the three m_*DemandFactors arrays.
  • Computes which residential densities are unlocked, retrieves population and demand parameters, and computes multiple factor contributions:
    • Population smoothing (reduces demand as population grows),
    • Happiness effect,
    • Tax effect across tax brackets,
    • Homelessness effect (with caps),
    • Available workplace effects for simple/complex workplaces,
    • Student (study positions) effect,
    • Unemployment effect.
  • Uses GetFactorValue to convert float factor values into integer contributions using m_ResidentialDemandWeightsSelector (different weight for negative vs positive values).
  • Computes household demand (clamped to 200) and per-density building demand (combining household demand halves, property shortages, and factor sums).
  • Writes factor arrays for each density to allow debugging/UI introspection.
  • Enqueues a TriggerAction(TriggerType.ResidentialDemand) with a value representing relative demand if residential properties exceed thresholds.
  • GetFactorValue(factorValue, weightSelector) helper multiplies factor by weightSelector.y when factor >= 0, weightSelector.x when factor < 0.

  • TypeHandle (private struct)
    Holds ComponentLookup instances that are assigned in OnCreateForCompiler and used to get read-only component lookups for jobs.


Usage Example

Example: reading the computed demands from another managed system (or mod code) and getting factor arrays safely.

protected override void OnUpdate()
{
    base.OnUpdate();

    // Resolve the system (example inside another system)
    var resDemandSystem = World.GetOrCreateSystemManaged<ResidentialDemandSystem>();

    // Get last computed values (cheap direct properties)
    int households = resDemandSystem.householdDemand;
    int3 buildings = resDemandSystem.buildingDemand;

    // If you need the factor arrays inside a job, request the JobHandle
    JobHandle deps;
    NativeArray<int> lowFactors = resDemandSystem.GetLowDensityDemandFactors(out deps);
    // Combine deps with your job scheduling to respect read/write ordering.
}

Notes for modders: - Respect JobHandles returned by Get*DemandFactors and AddReader to avoid race conditions. - The system reads ModeSettingData to apply alternative weighting; mods can provide or alter ModeSettingData to affect demand weighting. - TriggerAction enqueued by the job allows UI/hud or other systems to react to residential demand changes.