Skip to content

Game.CitizenHappinessSystem

Assembly: Game
Namespace: Game.Simulation

Type: class

Base: GameSystemBase, IDefaultSerializable, ISerializable

Summary:
CitizenHappinessSystem is the central system that computes and aggregates citizen wellbeing and health-related happiness factors every simulation interval. It: - Iterates citizens in parallel (via CitizenHappinessJob) and computes many per-citizen bonuses/penalties (electricity, water, pollution, crime, healthcare, education, leisure, taxes, garbage, telecom, mail, homelessness, death, etc.). - Enqueues aggregated per-factor values for later processing (HappinessFactorJob), which converts raw int4 tallies into averaged float3 values and emits trigger actions for each happiness factor. - Exposes many static helper methods that compute individual factor contributions for buildings and citizens (GetApartmentWellbeing, GetElectricitySupplyBonuses, GetWaterSupplyBonuses, GetCrimeBonuses, GetTelecomBonuses, GetTaxBonuses, etc.), useful for calculating or previewing effects without running the full job. - Holds an internal rolling buffer of happiness statistics (m_HappinessFactors) that is serialized/deserialized by the save system. - Runs on a fixed update interval (GetUpdateInterval => 16) and uses multiple other systems (pollution, telecom coverage, local effects, tax, city statistics, trigger system) to compute final values.

It also defines the HappinessFactor enum which enumerates the tracked factors (Telecom, Crime, AirPollution, Apartment, Electricity, Healthcare, GroundPollution, NoisePollution, Water, WaterPollution, Sewage, Garbage, Entertainment, Education, Mail, Welfare, Leisure, Tax, Buildings, Consumption, TrafficPenalty, DeathPenalty, Homelessness, ElectricityFee, WaterFee, Count).


Fields

  • private DebugWatchDistribution m_DebugData
    Tracks runtime debug distribution data. Used when debugging to collect numerical values from job runs (only active if debug is enabled).

  • private NativeQueue<FactorItem> m_FactorQueue
    Thread-safe queue used by the parallel CitizenHappinessJob to enqueue aggregated per-chunk FactorItem entries. Consumed later by HappinessFactorJob.

  • private EntityQuery m_CitizenQuery
    Query used to select the citizens to be processed (requires Citizen, HouseholdMember and UpdateFrame). Filtered each update to the correct update frame group.

  • private EntityQuery m_HappinessFactorParameterQuery
    Query to find the prefab/buffer entity that contains HappinessFactorParameterData.

  • private SimulationSystem m_SimulationSystem
    Cached reference to the SimulationSystem for retrieving the current simulation frame.

  • private GroundPollutionSystem m_GroundPollutionSystem
    Cached system for querying ground pollution map data.

  • private AirPollutionSystem m_AirPollutionSystem
    Cached system for querying air pollution map data.

  • private NoisePollutionSystem m_NoisePollutionSystem
    Cached system for querying noise pollution map data.

  • private TelecomCoverageSystem m_TelecomCoverageSystem
    Cached system for telecom coverage sampling.

  • private LocalEffectSystem m_LocalEffectSystem
    Cached local effect read data, applied to wellbeing/health modifiers near objects.

  • private CitySystem m_CitySystem
    Cached CitySystem used to obtain the city/parameter entity.

  • private TriggerSystem m_TriggerSystem
    Cached trigger system used to enqueue TriggerAction events derived from happiness factors.

  • private TaxSystem m_TaxSystem
    Cached tax system for obtaining current tax rates used in tax-related happiness calculations.

  • private CityStatisticsSystem m_CityStatisticsSystem
    Cached statistics system used to emit wellbeing/health change events.

  • private EntityQuery m_HealthcareParameterQuery
    Query for HealthcareParameterData singleton.

  • private EntityQuery m_ParkParameterQuery
    Query for ParkParameterData singleton.

  • private EntityQuery m_EducationParameterQuery
    Query for EducationParameterData singleton.

  • private EntityQuery m_TelecomParameterQuery
    Query for TelecomParameterData singleton.

  • private EntityQuery m_GarbageParameterQuery
    Query for GarbageParameterData singleton.

  • private EntityQuery m_PoliceParameterQuery
    Query for PoliceConfigurationData singleton.

  • private EntityQuery m_CitizenHappinessParameterQuery
    Query for CitizenHappinessParameterData singleton.

  • private EntityQuery m_TimeSettingQuery
    Query for TimeSettingsData singleton.

  • private EntityQuery m_TimeDataQuery
    Query for TimeData singleton.

  • private NativeArray<int4> m_HappinessFactors
    Persistent native array used as a circular/rolling storage for aggregated per-factor int4 values across update frames. Size is 400 (25 factors * 16 frames). Used to compute averaged float3 factor values.

  • private JobHandle m_LastDeps
    Keeps the last dependency job handle to ensure correctness when reading cached results (GetHappinessFactor waits on this).

  • private TypeHandle __TypeHandle
    Internal container that stores ComponentTypeHandle/ComponentLookup/BufferLookup objects for job scheduling and safety. Assigned in OnCreateForCompiler.

  • private EntityQuery __query_429327288_0
    Internally created EntityQuery used to obtain ServiceFeeParameterData (created in __AssignQueries).


Properties

  • None public. (Most interactions go through public methods and static helpers.)

Constructors

  • public CitizenHappinessSystem()
    Default constructor. The real initialization is done in OnCreate. The constructor is preserved for serialization and system creation.

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    Returns the update interval for this system. Implementation returns 16 (system runs every 16 frames in the GameSimulation phase).

  • private static int GetFactorIndex(HappinessFactor factor, uint updateFrame)
    Internal helper to compute the index into the m_HappinessFactors array given a factor and an updateFrame (factor + 25 * updateFrame).

  • public float3 GetHappinessFactor(HappinessFactor factor, DynamicBuffer<HappinessFactorParameterData> parameters, ref ComponentLookup<Locked> locked)
    High-level method to query the current averaged float3 value for a happiness factor. It waits for any pending jobs to complete (m_LastDeps.Complete()) and then computes the value by summing across the stored frames with GetHappinessFactor(...) static helper. Returns a float3: (combined/normalized value, health component, wellbeing component) minus the parameter base level.

  • private static float3 GetHappinessFactor(HappinessFactor factor, NativeArray<int4> happinessFactors, DynamicBuffer<HappinessFactorParameterData> parameters, ref ComponentLookup<Locked> locked)
    Static backend used by the public GetHappinessFactor. Sums int4 entries over the stored frames, checks lock override, divides sums into averages and subtracts configured base level.

  • protected override void OnCreate()
    Initializes internal references to other systems, allocates NativeArray and NativeQueue, creates queries, sets up debug distribution and requires certain components for update. Binds to many other systems used during happiness computation. Must be called by system creation; modders typically won't call directly.

  • public static float GetApartmentWellbeing(float sizePerResident, int level)
    Returns a computed wellbeing value for apartment space per resident and building level. This uses an empirical curve used by the game to convert space to apartment wellbeing.

  • protected override void OnDestroy()
    Disposes NativeArray/NativeQueue and debug data and calls base.OnDestroy.

  • public static float GetFreetimeWellbeingDifferential(int freetime)
    Returns the incremental wellbeing differential for a given free time value.

  • public static float GetFreetimeWellbeing(int freetime)
    Computes the free-time-based wellbeing (uses a logarithmic curve).

  • public static int GetElectricityFeeHappinessEffect(float relativeFee, in CitizenHappinessParameterData data)
    Returns an integer happiness effect derived from electricity fee relative level and configured parameter curves.

  • public static int2 GetElectricityFeeBonuses(Entity building, ref ComponentLookup electricityConsumers, float relativeFee, in CitizenHappinessParameterData data)
    Returns electricity fee bonuses for a specific building (delegates to float version if building consumes electricity).

  • public static int2 GetElectricityFeeBonuses(float relativeFee, in CitizenHappinessParameterData data)
    Returns electricity fee bonuses based solely on relativeFee and parameter curves (y component holds wellbeing effect).

  • public static int2 GetElectricitySupplyBonuses(Entity building, ref ComponentLookup electricityConsumers, in CitizenHappinessParameterData data)
    Returns electricity supply penalties/bonuses for the building based on cooldown counters and parameter delay. Used to apply wellbeing penalties when electricity is frequently missing.

  • public static int GetWaterFeeHappinessEffect(float relativeFee, in CitizenHappinessParameterData data)
    Analogous to electricity fee effect but for water.

  • public static int2 GetWaterFeeBonuses(Entity building, ref ComponentLookup waterConsumers, float relativeFee, in CitizenHappinessParameterData data)
    Per-building water fee bonuses (delegates to static float version if the building uses water).

  • public static int2 GetWaterFeeBonuses(float relativeFee, in CitizenHappinessParameterData data)
    Water fee health & wellbeing effects computed from curves.

  • public static int2 GetWaterSupplyBonuses(Entity building, ref ComponentLookup waterConsumers, in CitizenHappinessParameterData data)
    Water supply penalties based on fresh water cooldown counters and configured delay.

  • public static int2 GetWaterPollutionBonuses(Entity building, ref ComponentLookup waterConsumers, DynamicBuffer cityModifiers, in CitizenHappinessParameterData data)
    Returns water pollution health penalty for a building based on building's pollution and city modifiers.

  • public static int2 GetSewageBonuses(Entity building, ref ComponentLookup waterConsumers, in CitizenHappinessParameterData data)
    Returns sewage-based health/wellbeing effects from sewage cooldowns.

  • public static int2 GetHealthcareBonuses(float curvePosition, DynamicBuffer serviceCoverage, ref ComponentLookup locked, Entity healthcareService, in CitizenHappinessParameterData data)
    Computes healthcare-based health & wellbeing contributions using service coverage at a position. Returns (health, wellbeing). Respects the Locked component if the healthcare service is disabled.

  • public static int2 GetEducationBonuses(float curvePosition, DynamicBuffer serviceCoverage, ref ComponentLookup locked, Entity educationService, in CitizenHappinessParameterData data, int children)
    Computes education wellbeing bonus scaled by number of children and coverage. Respects lock.

  • public static int2 GetEntertainmentBonuses(float curvePosition, DynamicBuffer serviceCoverage, DynamicBuffer cityModifiers, ref ComponentLookup locked, Entity entertainmentService, in CitizenHappinessParameterData data)
    Computes park/entertainment wellbeing bonus based on coverage and city modifiers. Respects lock.

  • public static int2 GetGroundPollutionBonuses(Entity building, ref ComponentLookup transforms, NativeArray pollutionMap, DynamicBuffer cityModifiers, in CitizenHappinessParameterData data)
    Computes ground pollution health penalty for a building using GroundPollutionSystem sample and city modifiers.

  • public static int2 GetAirPollutionBonuses(Entity building, ref ComponentLookup transforms, NativeArray airPollutionMap, DynamicBuffer cityModifiers, in CitizenHappinessParameterData data)
    Computes air pollution health penalty using AirPollutionSystem sampling and city modifiers.

  • public static int2 GetNoiseBonuses(Entity building, ref ComponentLookup transforms, NativeArray noiseMap, in CitizenHappinessParameterData data)
    Returns noise wellbeing penalty using NoisePollutionSystem sampling.

  • public static int2 GetGarbageBonuses(Entity building, ref ComponentLookup garbages, ref ComponentLookup locked, Entity garbageService, in GarbageParameterData data)
    Computes garbage-related health & wellbeing penalties for a building (if garbage rises above thresholds). Respects lock on garbage service.

  • public static int2 GetCrimeBonuses(CrimeVictim crimeVictim, Entity building, ref ComponentLookup crimes, ref ComponentLookup locked, Entity policeService, in CitizenHappinessParameterData data)
    Computes crime-related wellbeing penalty at a building, including per-citizen crime victim effect. Respects police service lock.

  • public static int2 GetMailBonuses(Entity building, ref ComponentLookup mails, ref ComponentLookup locked, Entity telecomService, in CitizenHappinessParameterData data)
    Computes mail delivery wellbeing bonuses/penalties based on counts of sending/receiving mail and delivery status. Respects telecom lock.

  • public static int2 GetTelecomBonuses(Entity building, ref ComponentLookup transforms, CellMapData telecomCoverage, ref ComponentLookup locked, Entity telecomService, in CitizenHappinessParameterData data)
    Computes telecom wellbeing bonus/penalty based on sampled network quality at the building position and configured baseline. Respects lock.

  • public static int2 GetTaxBonuses(int educationLevel, NativeArray taxRates, in CitizenHappinessParameterData data)
    Computes tax-related wellbeing penalty/bonus for a resident at a specific education level using configured multipliers and current tax rates.

  • public static int2 GetWellfareBonuses(float curvePosition, DynamicBuffer serviceCoverage, in CitizenHappinessParameterData data, int currentHappiness)
    Computes welfare service wellbeing bonus scaled by how unhappy a citizen currently is.

  • public static float GetWelfareValue(float curvePosition, DynamicBuffer serviceCoverage, in CitizenHappinessParameterData data)
    Returns the raw welfare coverage value (multiplied by multiplier) for caching.

  • public static int2 GetCachedWelfareBonuses(float cachedValue, int currentHappiness)
    Compute welfare bonuses from a cached welfare value (helper to avoid repeated coverage computation).

  • public static int2 GetSicknessBonuses(bool hasHealthProblem, in CitizenHappinessParameterData data)
    If the citizen has health problems, applies a health penalty.

  • public static int2 GetHomelessBonuses(in CitizenHappinessParameterData data)
    Returns the health & wellbeing modifiers for homeless citizens.

  • public static int2 GetDeathPenalty(DynamicBuffer householdCitizens, ref ComponentLookup healthProblems, in CitizenHappinessParameterData data)
    If any citizen in the household buffer is dead, returns configured death penalties for health & wellbeing.

  • public static float GetConsumptionHappinessDifferential(float dailyConsumption, int citizens)
    Returns the marginal effect of consumption per citizen on happiness using a tuned formula.

  • public static int2 GetConsumptionBonuses(float dailyConsumption, int citizens, in CitizenHappinessParameterData data)
    Returns consumption-based wellbeing bonuses (clamped to a range).

  • public static int2 GetLeisureBonuses(byte leisureValue)
    Returns a wellbeing bonus derived from a citizen's leisure counter.

  • public static int GetMaxHealth(float ageInYears)
    Returns maximum possible health for a citizen based on age-in-years. Used to clamp health increases. Younger citizens have higher maximums until aging penalties apply.

  • public static void GetBuildingHappinessFactors(Entity property, NativeArray factors, ... many refs and parameters ...)
    Big util method that computes per-building happiness factors by inspecting the building, its renters, associated companies/processes, available services, transforms and pollution maps. This method is intended for obtaining a buildings' contribution to each happiness factor (useful for building tooltips/panels or external calculations). Needs many game-specific lookups and parameter buffers. Returns results in the provided NativeArray factors. (See method signature for full list of required component lookups and parameters.)

  • private static void AddCompanyHappinessFactors(NativeArray factors, Entity property, Entity prefab, Entity renter, Entity renterPrefab, IndustrialProcessData processData, ServiceCompanyData serviceCompanyData, bool commercial, int level, ref ComponentLookup officeBuildings, ref ComponentLookup workProviders, ref BufferLookup employees, ref ComponentLookup workplaceDatas, ref ComponentLookup serviceAvailables, ref ComponentLookup resourceDatas, ref BufferLookup efficiencies, ref ComponentLookup buildingPropertyDatas, ref BufferLookup availabilities, ref BufferLookup tradeCosts, NativeArray taxRates, Building building, SpawnableBuildingData spawnableData, BuildingData buildingData, ResourcePrefabs resourcePrefabs, ref EconomyParameterData economyParameters)
    Internal helper used by GetBuildingHappinessFactors to add modifiers coming from companies/services inside mixed-use buildings. Implementation is empty in this listing (likely filled elsewhere or intentionally omitted).

  • private static int GetFactor(float profit, float defaultProfit)
    Helper to compute a 0..n scaled factor based on profit relative to a default profit (rounded and scaled by 10).

  • protected override void OnUpdate()
    Main scheduling method: Filters citizens to the current UpdateFrame group, schedules CitizenHappinessJob (parallel) to compute per-chunk values and enqueue FactorItem entries, then schedules HappinessFactorJob to consume the FactorQueue and produce the final per-factor float3 values and trigger actions. Also sets up dependencies with multiple systems (pollution, telecom, local effects, tax, city statistics) and records m_LastDeps.

  • private static TriggerType GetTriggerTypeForHappinessFactor(HappinessFactor factor)
    Maps a HappinessFactor to a TriggerType used for sending trigger actions. If a factor has no mapping an error is logged and TriggerType.NewNotification is returned.

  • public void Serialize(TWriter writer) where TWriter : IWriter
    Writes the number of tracked factors (25) followed by the content of the m_HappinessFactors array to the writer for save serialization.

  • public void Deserialize(TReader reader) where TReader : IReader
    Reads saved happiness factor data. Backwards-compatible: if reader.context.version < Version.happinessFactorSerialization, reads an older fixed count (352), otherwise reads as written by Serialize (count * 16). Restores the m_HappinessFactors array.

  • public void SetDefaults(Context context)
    Resets m_HappinessFactors to default (zeroed) for all 400 entries. Used for new games or when resetting values.

  • private void __AssignQueries(ref SystemState state)
    Internal method used by compiler-generated OnCreateForCompiler to create internal queries (e.g., __query_429327288_0 used to fetch ServiceFeeParameterData). Not for external use.

  • protected override void OnCreateForCompiler()
    Compiler-generated initialization that assigns queries and component type handles for job scheduling safety.


Usage Example

// Example 1: Use a static helper to compute apartment wellbeing
float sizePerResident = 20f; // m^2 per resident (example)
int buildingLevel = 2;
float apartmentWellbeing = CitizenHappinessSystem.GetApartmentWellbeing(sizePerResident, buildingLevel);

// Example 2: Query the system at runtime and read an averaged factor (requires game context)
var world = World.DefaultGameObjectInjectionWorld;
var happinessSystem = world.GetExistingSystemManaged<CitizenHappinessSystem>();
// The following requires obtaining the buffer of HappinessFactorParameterData from the parameter entity
// and a ComponentLookup<Locked> (both are game-specific). This code demonstrates the intended API:
if (happinessSystem != null)
{
    // assume `parametersBuffer` and `lockedLookup` are available from game context:
    // float3 telecomFactor = happinessSystem.GetHappinessFactor(
    //     CitizenHappinessSystem.HappinessFactor.Telecom,
    //     parametersBuffer,
    //     ref lockedLookup);
}

Notes: - Many static helper methods and the job code rely on lots of game-specific component lookups, buffers and parameter data. They are intended to be used inside game systems or tools that can access these lookups. - GetHappinessFactor blocks on m_LastDeps to ensure job results are ready; do not call it from inside a job unless you manage dependencies properly. - Several methods respect Locked components on service prefabs; if a service is locked (disabled), its effect is ignored. - The system aggregates over a rolling window of 16 update frames (25 tracked factors × 16), so values reported are averaged/smoothed over time.