Skip to content

Game.Citizens.CitizenUtils

Assembly:
Game (inferred from namespace and project structure)

Namespace:
Game.Citizens

Type:
public static class

Base:
static (helper/utility class — no instance base)

Summary:
A collection of helper methods for working with Citizen-related ECS components in Cities: Skylines 2. Contains convenience checks (dead, resident, commuter, workable), household utilities (move-in status, move-away), pathfinding weight calculation, sound selection for selected citizens, and prefab selection. Many APIs are provided in overloads for both ComponentLookup-based (job-friendly) and EntityManager-based access patterns. Use these utilities from systems or mod code that interacts with the game's ECS citizen data.


Fields

  • None {{ This static utility class declares no persistent fields. All functionality is provided via static methods that operate on ECS components and buffers. }}

Properties

  • None {{ CitizenUtils does not expose properties. All operations are performed through static methods. }}

Constructors

  • None (static class) {{ Being a static class, CitizenUtils has no user-visible constructors. Its methods are intended to be called directly without instantiation. }}

Methods

  • public static bool IsDead(Entity citizen, ref ComponentLookup<HealthProblem> healthProblems) {{ Checks whether the given citizen entity has a HealthProblem component flag indicating death. Uses the job-friendly ComponentLookup (passed by ref) and will return false if the component is missing. }}

  • public static bool IsDead(EntityManager entityManager, Entity citizen) {{ Same check as the ComponentLookup overload but using an EntityManager. Returns true if HealthProblem is present and has the Dead flag. }}

  • public static bool IsDead(HealthProblem healthProblem) {{ Low-level helper that checks the HealthProblemFlags.Dead bit on the provided HealthProblem value. Useful when you already have the component data. }}

  • public static bool IsCorpsePickedByHearse(Entity citizen, ref ComponentLookup<HealthProblem> healthProblems, ref ComponentLookup<TravelPurpose> travelPurposes) {{ Returns true when the citizen is dead and its TravelPurpose component indicates either Purpose.Deathcare or Purpose.InDeathcare (i.e., a hearse has picked up the corpse). Uses ComponentLookup for both components. }}

  • public static bool IsCorpsePickedByHearse(EntityManager entityManager, Entity citizen) {{ EntityManager-based version of the above corpse/hearse check. }}

  • public static bool TryGetResident(Entity entity, ComponentLookup<Citizen> citizenFromEntity, out Citizen citizen) {{ Attempts to read a Citizen component from the given entity via a ComponentLookup. If successful, returns true only when the citizen is a resident (not a tourist, commuter, or moving-away), determined by inspecting m_State flags. The out parameter provides the retrieved Citizen. }}

  • public static PathfindWeights GetPathfindWeights(Citizen citizen, Household household, int householdCitizens) {{ Computes and returns a PathfindWeights instance for the citizen based on:

  • a time weight derived from the citizen's leisure counter,
  • a fixed behaviour weight,
  • a money/consumption-based weight influenced by household consumption and household size,
  • and a comfort weight that includes randomization via citizen.GetPseudoRandom(TrafficComfort).

Also applies a multiplier reducing the money weight if the household has not moved in and the citizen is a normal resident. Useful when initiating citizen pathfinding and simulating their preferences. }}

  • public static bool IsCommuter(Entity citizenEntity, ref ComponentLookup<Citizen> citizens) {{ Returns true if the specified entity's Citizen component has the CitizenFlags.Commuter flag set. Uses ComponentLookup for reading. }}

  • public static bool IsResident(EntityManager entityManager, Entity entity, out Citizen citizen) {{ EntityManager-based check that determines whether the given entity is a resident:

  • requires a Citizen component and a HouseholdMember component,
  • rejects the entity if its household is tagged as a TouristHousehold, CommuterHousehold, or MovingAway,
  • ensures citizen.m_State does not have MovingAwayReachOC, Tourist, or Commuter flags. Returns false and leaves out parameter unset if checks fail. }}

  • public static bool IsResident(Entity entity, Citizen citizen, ComponentLookup<HouseholdMember> householdMemberFromEntity, ComponentLookup<MovingAway> movingAwayFromEntity, ComponentLookup<TouristHousehold> touristHouseholdFromEntity, ComponentLookup<CommuterHousehold> commuterHouseholdFromEntity) {{ ComponentLookup-based overload that checks whether the provided entity (and provided Citizen value) is a resident. Verifies the household membership via householdMemberFromEntity, then ensures the household is not a tourist/commuter/moving-away household. Finally checks citizen.m_State flags to confirm resident status. }}

  • public static bool HasMovedIn(Entity householdEntity, ComponentLookup<Household> householdDatas) {{ Returns true if the Household component on householdEntity has HouseholdFlags.MovedIn set; uses ComponentLookup. }}

  • public static bool HasMovedIn(Entity citizen, ref ComponentLookup<HouseholdMember> householdMembers, ref ComponentLookup<Household> households, ref ComponentLookup<HomelessHousehold> homelessHouseholds) {{ Determines whether the citizen belongs to a household that has moved in:

  • reads the citizen's HouseholdMember to get the household entity,
  • reads that Household component and checks the MovedIn flag,
  • returns false if the household is marked as a HomelessHousehold. This overload is job-friendly (ComponentLookup refs). }}

  • public static CitizenHappiness GetHappinessKey(int happiness) {{ Maps an integer happiness value to a CitizenHappiness enum:

  • 70 => Happy

  • 55 => Content

  • 40 => Neutral

  • 25 => Sad

  • otherwise => Depressed Use when selecting audio or other responses based on happiness tiers. }}

  • public static Entity GetCitizenSelectedSound(EntityManager entityManager, Entity entity, Citizen citizen, Entity citizenPrefabRef) {{ Chooses an appropriate selected-sound prefab entity for the citizen using data stored on the citizen prefab (CitizenSelectedSoundData buffer):

  • returns Entity.Null if the prefab has no CitizenSelectedSoundData,
  • determines age, happiness key, and whether the citizen is sick/injured (by checking HealthProblem flags),
  • iterates the DynamicBuffer on the prefab and returns the matching sound Entity if found. Useful for playing contextually-appropriate selection sounds. }}

  • public static bool IsHouseholdNeedSupport(DynamicBuffer<HouseholdCitizen> householdCitizens, ref ComponentLookup<Citizen> citizens, ref ComponentLookup<Student> students) {{ Returns true if all adults in the household are students (i.e., there are no non-student adults). Iterates the householdCitizens buffer and checks each citizen's age and Student component presence. Use to determine whether the household needs adult support. }}

  • public static bool IsWorkableCitizen(Entity citizenEntity, ref ComponentLookup<Citizen> citizens, ref ComponentLookup<Student> m_Students, ref ComponentLookup<HealthProblem> healthProblems) {{ Determines if a citizen is eligible for work:

  • not dead,
  • not a student,
  • not a tourist or commuter,
  • age is Teen or Adult. Uses ComponentLookup refs. Returns true when citizen can work. }}

  • public static Entity GetCitizenPrefabFromCitizen(NativeList<Entity> citizenPrefabs, Citizen citizen, ComponentLookup<CitizenData> citizenDatas, Random rnd) {{ Selects a random prefab entity for the citizen matching the citizen's gender state:

  • counts the number of prefabs with the correct gender,
  • picks a random index among them using the provided Random,
  • returns the selected prefab Entity or Entity.Null if none matched. The method wraps prefab Entity in a PrefabRef when selecting but returns the raw Entity. }}

  • public static void HouseholdMoveAway(EntityCommandBuffer.ParallelWriter commandBuffer, int sortKey, Entity householdEntity) {{ Adds a MovingAway component to the householdEntity using an EntityCommandBuffer.ParallelWriter and the given sortKey. Use within jobs/systems that record commands for later playback. }}

  • public static void HouseholdMoveAway(EntityCommandBuffer commandBuffer, Entity householdEntity) {{ Adds a MovingAway component to householdEntity immediately via an EntityCommandBuffer (non-parallel). Use in main-thread systems or when recording single-threaded commands. }}

Usage Example

// Example usage inside a System (pseudo-code)
protected override void OnUpdate()
{
    var citizensLookup = SystemAPI.GetComponentLookup<Citizen>(false);
    var healthLookup = SystemAPI.GetComponentLookup<HealthProblem>(false);
    var householdMemberLookup = SystemAPI.GetComponentLookup<HouseholdMember>(true);

    Entities.ForEach((Entity e) =>
    {
        // Check if a citizen is dead
        if (CitizenUtils.IsDead(e, ref healthLookup))
        {
            // do something, e.g. log or schedule cleanup
        }

        // Try to get a resident
        if (CitizenUtils.TryGetResident(e, citizensLookup, out var citizen))
        {
            // compute pathfind weights for this citizen (example needs household data)
            // PathfindWeights w = CitizenUtils.GetPathfindWeights(citizen, household, householdSize);
        }
    }).Schedule();
}

// Example of marking a household as moving away using an EntityCommandBuffer:
var ecb = new EntityCommandBuffer(Allocator.Temp);
CitizenUtils.HouseholdMoveAway(ecb, householdEntity);
ecb.Playback(EntityManager);
ecb.Dispose();

{{ Tips: - Prefer the ComponentLookup-based overloads in jobs/systems for better performance and safety. - Use EntityManager overloads only when you have main-thread access. - Many checks are bitmask-based (m_State, m_Flags), so ensure you understand the flags enums (CitizenFlags, HouseholdFlags, HealthProblemFlags) when interpreting results. - The class assumes the existence of various ECS components and buffers defined in the game's assemblies (e.g., Household, HouseholdMember, CitizenData, CitizenSelectedSoundData). }}