Skip to content

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.