Game.Citizens.Citizen
Assembly: Game
Namespace: Game.Citizens
Type: struct
Base: IComponentData, IQueryTypeParameter, ISerializable
Summary:
Represents the compact, ECS-compatible data for a single city citizen used by the simulation. Stores a small pseudo-random seed, a bitmask of state flags (age, education bits, failed-education bits, etc.), wellbeing/health, counters (leisure, penalty, unemployment) and birthday. Provides helpers to compute happiness and age in days, manipulate education/age flags encoded in m_State, produce per-citizen pseudo-random generators and read/write itself to the game's serialization format (with version-aware deserialization). This struct is intended to be used as a component on entities in the Unity Entities (DOTS) world.
Fields
-
public ushort m_PseudoRandom
A 16-bit pseudo-random seed stored per-citizen. Used to generate deterministic Random instances for various citizen-specific random decisions. Serialized for newer save versions (checked in Deserialize). -
public CitizenFlags m_State
Bitmask describing multiple boolean/bit-state values for the citizen (age bits, education bits, failed-education bits and other flag bits defined by CitizenFlags). Many getters/setters operate on these bits to represent education level, failed-education count and age. -
public byte m_WellBeing
Well-being level (0..255). Used together with health to calculate Happiness. -
public byte m_Health
Health level (0..255). Used together with well-being to calculate Happiness. -
public byte m_LeisureCounter
Small counter used by AI to track leisure-related state/progression. -
public byte m_PenaltyCounter
Penalty counter (introduced in later versions). Deserialized conditionally based on save version. -
public int m_UnemploymentCounter
Integer counter that tracks unemployment duration. Present in saves from a later version (economyFix) — deserialized conditionally. -
public short m_BirthDay
Citizen's birth day expressed in game days (signed 16-bit). Used to compute age in days.
Properties
public int Happiness { get; }
Calculated property returning the average of well-being and health: (m_WellBeing + m_Health) / 2. Useful as a quick measure of citizen mood for gameplay or simulation logic.
Constructors
public Citizen()
Default value-type constructor. No explicit custom constructor is defined in code; fields are initialized to their default values when a new Citizen is created.
Methods
-
public float GetAgeInDays(uint simulationFrame, TimeData timeData)
Returns the citizen's age in days by computing the current day from simulationFrame and timeData (via TimeSystem.GetDay) and subtracting m_BirthDay. Use this to obtain a floating-point age suitable for age-dependent logic (e.g., lifecycle, schooling). -
public Random GetPseudoRandom(CitizenPseudoRandom reason)
Creates and returns a Unity.Mathematics.Random instance seeded deterministically from the citizen's stored m_PseudoRandom and the provided reason. Implementation notes: - Combines m_PseudoRandom into a 32-bit word ((m_PseudoRandom << 16) | m_PseudoRandom), XORs with the reason, constructs a Random, advances it once (random.NextUInt()), then uses a nonzero uint (ensures seed != 0) to create and return the final Random.
-
This yields deterministic but varied per-citizen randomness for different reasons.
-
public int GetEducationLevel()
Reads education bits from m_State and returns an integer education level (0..4). The encoding: - If EducationBit3 is set => level 4.
-
Else level is computed from EducationBit1 (adds 2 if set) and EducationBit2 (adds 1 if set).
-
public void SetEducationLevel(int level)
Sets or clears the education-related bits in m_State to represent the supplied level (0..4). If level == 4, EducationBit3 is set; other bits manipulated so that bits combine to represent 0..3 as binary using EducationBit1 and EducationBit2 as described above. -
public int GetFailedEducationCount()
Reads failed-education bits from m_State and returns 0..3 representing the number of failed education attempts. Encoding is similar to GetEducationLevel but uses FailedEducationBit1 and FailedEducationBit2. -
public void SetFailedEducationCount(int fails)
Sets or clears failed-education bits in m_State according to fails (0..3). Uses FailedEducationBit1 for the high bit (value 2) and FailedEducationBit2 for the low bit (value 1). -
public void SetAge(CitizenAge newAge)
Sets the citizen age bits in m_State to represent the supplied CitizenAge enum value. This method clears the age bits and writes them so age encoding matches the bit layout used elsewhere in the simulation. -
public CitizenAge GetAge()
Reads the encoded age bits from m_State and returns the corresponding CitizenAge value. -
public void Serialize<TWriter>(TWriter writer) where TWriter : IWriter
Writes the citizen data into the provided writer in the order expected by the save format: - m_State cast to short
- m_WellBeing (byte)
- m_Health (byte)
- m_LeisureCounter (byte)
- m_PenaltyCounter (byte)
- m_BirthDay (short)
- m_PseudoRandom (ushort)
-
m_UnemploymentCounter (int) Note: Serialization writes all these fields; compatibility is handled in Deserialize.
-
public void Deserialize<TReader>(TReader reader) where TReader : IReader
Reads citizen data from reader in a version-aware way. Important details: - For very old save versions (version < Version.saveOptimizations) the stream contains an extra uint that is read and discarded.
- Reads the stored short for state/value2 first (value2 is assigned to m_State later).
- Reads well-being, health and leisureCounter always.
- penaltyCounter is read only when reader.context.version >= Version.penaltyCounter.
- m_BirthDay is read and m_State is assigned from the earlier value2.
- m_PseudoRandom is read only when reader.context.version >= Version.snow.
- m_UnemploymentCounter is read only when reader.context.version >= Version.economyFix.
- This method preserves compatibility with older save formats and conditionally restores newer fields.
Usage Example
// Example: use within a system to inspect/update Citizen components
// (pseudocode; adapt to your system type and context)
public void ProcessCitizen(ref Citizen citizen, uint simulationFrame, TimeData timeData)
{
// Read computed values
int happiness = citizen.Happiness;
float ageDays = citizen.GetAgeInDays(simulationFrame, timeData);
CitizenAge ageCategory = citizen.GetAge();
int education = citizen.GetEducationLevel();
// Update education (e.g., graduating)
if (education < 4 && ShouldAdvanceEducation(citizen))
{
citizen.SetEducationLevel(education + 1);
}
// Get a deterministic per-citizen random for giving bonuses
var rnd = citizen.GetPseudoRandom(CitizenPseudoRandom.WorkChoice);
if (rnd.NextFloat() < 0.01f)
{
// small chance to modify some citizen state
citizen.m_WellBeing = (byte)math.min(255, citizen.m_WellBeing + 5);
}
}
Notes and tips: - m_State is a compact bitfield — use the provided getters/setters rather than manipulating bits manually unless you mirror the exact CitizenFlags layout. - Deserialize handles multiple save-version branches; if adding new fields, follow the existing pattern (conditional reads based on Version constants) to maintain backward compatibility. - Randomness: GetPseudoRandom ensures the returned Random seed is nonzero and is deterministic per (citizen, reason). This is intended for reproducible simulation behavior.