Skip to content

Game.Simulation.ResidentPurposeCounterSystem

Assembly: Assembly-CSharp (Game code)
Namespace: Game.Simulation

Type: class

Base: GameSystemBase

Summary:
ResidentPurposeCounterSystem is a game simulation system that samples all resident (human creature) entities and tallies what purpose they are currently travelling for. It iterates resident archetype chunks and counts destinations/purposes into a persistent NativeArray (m_Results). The results are intended for debug/monitoring (they are annotated with DebugWatch attributes) and include categories such as GoingHome, GoingToWork, Leisure, MovingAway, TouristLeaving, MovingIn, etc. The system is disabled by default in OnCreate and is scheduled to run infrequently (every 256 frames) via GetUpdateInterval.


Nested types

  • enum CountPurpose
    The index mapping for the results array (m_Results). Values:
  • GoingHome = 0
  • GoingToSchool = 1
  • GoingToWork = 2
  • Leisure = 3
  • MovingAway = 4
  • Shopping = 5
  • Travel = 6
  • None = 7
  • Other = 8
  • TouristLeaving = 9
  • Mail = 10
  • MovingIn = 11
  • Count = 12

  • struct PurposeCountJob (BurstCompiled, implements IJob)
    Job that receives a snapshot list of archetype chunks and component handles/lookups and produces counts into the supplied NativeArray (m_Results). It:

  • Zeroes the results array.
  • Iterates each resident in the chunks.
  • Skips residents that have no PathElement buffer entries (buffer length == 0).
  • Resolves the resident's citizen entity and household via HouseholdMember.
  • If the household has MovingAway: increments TouristLeaving (if TouristHousehold) or MovingAway.
  • Else if the household exists, the citizen has TravelPurpose and does not have CurrentBuilding:
    • Increments MovingIn if the household flag indicates the household hasn't finished moving in.
    • Reads TravelPurpose.m_Purpose (overridden by a Divert component if present) and increments the appropriate counter (GoingHome, GoingToSchool, GoingToWork, Leisure, Shopping, Traveling, SendMail -> Mail). Unknown purposes fall back to Other.
  • Otherwise increments None.

  • struct TypeHandle
    Internal container of EntityTypeHandle, ComponentTypeHandle, BufferTypeHandle and ComponentLookup entries used to prepare the job's handles. It exposes __AssignHandles(ref SystemState) to populate these handles.


Fields

  • private EntityQuery m_CreatureQuery
    EntityQuery used to find relevant resident entities. It filters for Resident, Human, PrefabRef, UpdateFrame, PathOwner, Target and excludes Unspawned, Deleted, Temp and Stumbling.

  • private NativeArray<int> m_Results
    NativeArray of length 12 (Allocator.Persistent). Holds counts for each CountPurpose index. Annotated with [EnumArray(typeof(CountPurpose))] and [DebugWatchValue(historyLength = 1024)] so it's intended for debugging/inspection. The array is created in OnCreate and disposed in OnDestroy. Other code must not dispose it. Values are written by the scheduled PurposeCountJob.

  • private TypeHandle __TypeHandle
    Internal storage of the various type handles / lookups to be passed into the job. Initialized by OnCreateForCompiler (calling __AssignHandles).


Properties

  • None (no public properties exposed by this system).

Constructors

  • public ResidentPurposeCounterSystem()
    Default constructor. No custom logic; initialization occurs in OnCreate. The constructor is marked with [Preserve] attribute in the source.

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    Returns 256. This instructs the update scheduler that this system should run with an interval of 256 frames (i.e., infrequent sampling).

  • protected override void OnCreate()

  • Builds m_CreatureQuery to select all human resident creatures that are active for path/travel checking.
  • Allocates m_Results = new NativeArray(12, Allocator.Persistent).
  • Sets base.Enabled = false (system disabled by default). Marked [Preserve].

  • protected override void OnDestroy()

  • Disposes m_Results.
  • Calls base.OnDestroy(). Marked [Preserve].

  • protected override void OnUpdate()

  • Creates and schedules PurposeCountJob:
    • Uses m_CreatureQuery.ToArchetypeChunkListAsync to get the chunk list and an async dependency (outJobHandle).
    • Initializes the job's handles via InternalCompilerInterface.GetEntityTypeHandle / GetComponentTypeHandle / GetBufferTypeHandle / GetComponentLookup passing references from __TypeHandle and the system's CheckedStateRef.
    • Passes m_Results to the job so the job writes the counters directly into the NativeArray.
  • Schedules the job via IJobExtensions.Schedule and combines dependencies into base.Dependency.
  • Marked [Preserve].

  • private void __AssignQueries(ref SystemState state)
    Compiler helper that currently only constructs and disposes a temporary EntityQueryBuilder. Present for compiler-generated plumbing.

  • protected override void OnCreateForCompiler()
    Called by compiler-infrastructure; it invokes __AssignQueries and assigns handles via __TypeHandle.__AssignHandles(ref base.CheckedStateRef).

  • Other generated/utility methods exist to support the job system (e.g., TypeHandle.__AssignHandles).

Notes about concurrency, safety and behavior: - PurposeCountJob is Burst-compiled and runs as an IJob scheduled from OnUpdate. It writes to the NativeArray (m_Results) directly; consumers that read m_Results must respect job dependencies (i.e., combine dependencies or read after the job completes) to avoid race conditions. - m_Results is created with Allocator.Persistent and disposed in OnDestroy; it is intended to persist across frames for debugging and monitoring. - The system is disabled by default (base.Enabled = false) — to use it you must enable the system (see usage example below). - The job inspects buffer length of PathElement to determine whether a resident currently has a travel path. If buffer length is zero the resident is skipped (no travel counted). - Divert component, if present for that resident chunk, overrides the TravelPurpose read from the TravelPurpose lookup. - Household flags are inspected; if a Household doesn't have MovedIn flag set the code increments the MovingIn counter.


Usage Example

// Example: enable the system and read counts via reflection.
// Note: m_Results is private and a NativeArray<int>. Accessing it directly requires care
// to respect jobs/dependencies and to avoid disposing it. This example demonstrates
// how to get the system instance and read the counts (safely blocking until completion).

using System;
using System.Reflection;
using Unity.Collections;
using Unity.Entities;

// Obtain system (Entities API / world injection may differ in your project)
var world = World.DefaultGameObjectInjectionWorld;
var system = world.GetExistingSystemManaged<Game.Simulation.ResidentPurposeCounterSystem>();
if (system != null)
{
    // Ensure the system is enabled so it runs on its interval:
    system.Enabled = true;

    // Force update to run immediately (or let scheduler run by interval).
    world.Update();

    // Wait for the system's job to finish by completing world dependency:
    world.EntityManager.CompleteAllJobs();

    // Reflectively get the private m_Results field:
    var fi = typeof(Game.Simulation.ResidentPurposeCounterSystem)
                .GetField("m_Results", BindingFlags.NonPublic | BindingFlags.Instance);
    var results = (NativeArray<int>)fi.GetValue(system);

    int goingHome = results[(int)Game.Simulation.ResidentPurposeCounterSystem.CountPurpose.GoingHome];
    int movingIn = results[(int)Game.Simulation.ResidentPurposeCounterSystem.CountPurpose.MovingIn];

    Console.WriteLine($"Going home: {goingHome}, Moving in: {movingIn}");
}

Additional notes: - Preferably extend the system or expose a safe API if you need regular access to the counts instead of using reflection. - Be mindful of NativeArray lifetime: do not dispose m_Results from external code. - The enum CountPurpose maps directly to indices used in m_Results; CountPurpose.Count equals 12, which is the allocated array length.