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). }}