Skip to content

Game.Simulation.CityStatisticsSystem

Assembly:
Assembly-CSharp.dll

Namespace:
Game.Simulation

Type:
class

Base:
GameSystemBase

Summary:
Manages city-level statistics (population, money, lodging, education, age groups, etc.) for Cities: Skylines 2. The system collects per-frame/sample statistics via job producers, stores them in DynamicBuffers on statistic entities, provides lookup/utility methods to read current and historical data, and handles serialization/deserialization of pending statistic events and sample metadata. It exposes a safe queue API for other systems/jobs to enqueue statistic events and ensures proper job dependency tracking for writers.


Fields

  • public readonly struct StatisticsKey : IEquatable<StatisticsKey>
    Helper struct used as the key in the statistics lookup map. Combines a StatisticType and an integer parameter to identify unique statistic entities.

  • public struct SafeStatisticQueue
    Thread-safe wrapper around a NativeQueue. Provides Enqueue that only enqueues when statistics are enabled. Returned via GetSafeStatisticsQueue.

  • private const int kUpdatesPerDay = 32
    Number of statistic updates that make up a day (used by ResetEntityJob and sampling logic).

  • private CitySystem m_CitySystem
    Reference to the CitySystem used for city-level data (money, city entity, etc).

  • private EndFrameBarrier m_EndFrameBarrier
    End-of-frame barrier used for scheduling producer jobs that write to Unity containers.

  • private SimulationSystem m_SimulationSystem
    Reference to the simulation system (used for retrieving frameIndex for sample timestamps).

  • private CountHouseholdDataSystem m_CountHouseholdDataSystem
    Reference to the household counting system which provides household/population counts used by the CityStatisticsJob.

  • private TriggerSystem m_TriggerSystem
    Trigger system used to register job writers for triggers.

  • private EntityQuery m_StatisticsPrefabQuery
    Query for statistic prefabs (StatisticsData).

  • private EntityQuery m_StatisticsQuery
    Query for statistic entities (CityStatistic buffer instances).

  • private EntityQuery m_CityQuery
    Query used to require city data for this system to update.

  • private NativeParallelHashMap<StatisticsKey, Entity> m_StatisticsLookup
    Lookup mapping StatisticsKey → statistic entity. Populated/initialized by InitializeLookup and used to find the entity/buffer for a given statistic.

  • private NativeQueue<StatisticsEvent> m_StatisticsEventQueue
    Queue of pending statistic events produced by jobs/systems. Processed during OnUpdate by ProcessStatisticsJob.

  • private JobHandle m_Writers
    Combined JobHandle that tracks all writer dependencies that have produced to the statistics queue. Used to ensure completion before reading/serialization.

  • private bool m_Initialized
    Flag indicating whether InitializeLookup has been run.

  • private int m_SampleCount = 1
    Number of samples collected (used for historical arrays and sampling). Serialized/deserialized.

  • private uint m_LastSampleFrameIndex
    Frame index of the last sample. Serialized/deserialized.

  • private TypeHandle __TypeHandle
    Generated container for ComponentLookup/BufferLookup handles used by jobs.

Properties

  • public int sampleCount => m_SampleCount
    Current number of samples recorded. Incremented each OnUpdate when system runs.

  • public Action eventStatisticsUpdated { get; set; }
    Event invoked at the end of OnUpdate when statistics are processed. Useful for UI or other systems that need to refresh after stats update.

Constructors

  • public CityStatisticsSystem()
    Default constructor (empty). Initialization occurs in OnCreate.

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    Returns the system update interval. This implementation returns 8192 (used for sample frame calculations).

  • public override int GetUpdateOffset(SystemUpdatePhase phase)
    Returns the update offset (0 here).

  • public NativeParallelHashMap<StatisticsKey, Entity> GetLookup()
    Returns the internal statistics lookup map. Useful for other systems that want direct access to the map.

  • protected override void OnCreate()
    Initializes references to other systems, sets up entity queries and allocates the statistics lookup and event queue. Disables the system by default until game-mode enables it.

  • protected override void OnGamePreload(Purpose purpose, GameMode mode)
    Enables or disables the system based on GameMode (only enabled for game).

  • protected override void OnDestroy()
    Disposes native containers (lookup, queue) and cleans up.

  • protected override void OnUpdate()
    Main update loop:

  • Ensures lookup is initialized.
  • Schedules CityStatisticsJob (producer) to enqueue current metrics.
  • Schedules ProcessStatisticsJob to apply queued events to CityStatistic buffers.
  • Schedules ResetEntityJob to advance/roll buffers according to collection type (Cumulative/Point/Daily).
  • Adds writer dependencies to TriggerSystem and EndFrameBarrier.
  • Increments sample count, updates last sample frame index, and invokes eventStatisticsUpdated.

  • public static int GetStatisticValue(NativeParallelHashMap<StatisticsKey, Entity> statisticsLookup, BufferLookup<CityStatistic> stats, StatisticType type, int parameter = 0)
    Helper to read a statistic's current total as int (clamped to int range) using a provided lookup & BufferLookup.

  • public static long GetStatisticValueLong(...)
    Same as above but returns long (clamped).

  • private static double GetStatisticValueDouble(...)
    Returns the statistic total as a rounded double (internal). Returns 0 if missing.

  • public int GetStatisticValue(BufferLookup<CityStatistic> stats, StatisticType type, int parameter = 0)
    Instance wrapper that calls static helper using this system's lookup.

  • public long GetStatisticValueLong(BufferLookup<CityStatistic> stats, StatisticType type, int parameter = 0)
    Instance wrapper for long.

  • private double GetStatisticValueDouble(StatisticType type, int parameter = 0)
    Instance method that completes writers and reads the current total value from the entity manager buffers.

  • public int GetStatisticValue(StatisticType type, int parameter = 0)
    Instance convenience method to get int value (clamped).

  • public long GetStatisticValueLong(StatisticType type, int parameter = 0)
    Instance convenience to get long value.

  • public static NativeArray<long> GetStatisticDataArrayLong(NativeParallelHashMap<StatisticsKey, Entity> statisticsLookup, BufferLookup<CityStatistic> stats, StatisticType type, int parameter = 0)
    Returns a NativeArray containing the historical totals of the statistic (rounded and clamped). If not found returns a single-element array.

  • public static NativeArray<int> GetStatisticDataArray(...)
    Same as above but int array (clamped to int range).

  • public NativeArray<long> GetStatisticDataArrayLong(BufferLookup<CityStatistic> stats, StatisticType type, int parameter = 0)
    Instance wrapper.

  • public NativeArray<int> GetStatisticDataArray(BufferLookup<CityStatistic> stats, StatisticType type, int parameter = 0)
    Instance wrapper.

  • public NativeArray<long> GetStatisticDataArrayLong(StatisticType type, int parameter = 0)
    Reads historical data via EntityManager (instance).

  • public NativeArray<int> GetStatisticDataArray(StatisticType type, int parameter = 0)
    Reads historical data as ints via EntityManager.

  • public NativeArray<CityStatistic> GetStatisticArray(StatisticType type, int parameter = 0)
    Gets the full DynamicBuffer as a NativeArray. Completes writers before reading.

  • public uint GetSampleFrameIndex(int index)
    Returns the frame index corresponding to the sample at index (0 is latest).

  • private void InitializeLookup()
    Builds m_StatisticsLookup by:

  • Reading all StatisticsData prefabs and their StatisticParameterData buffers to determine keys,
  • Searching existing statistic entities to see if any match existing prefab parameters; if not, creates instances of statistic prefabs via StatisticsPrefab.CreateInstance,
  • Clears the map of missing entries and sets m_Initialized = true. This method also resets the event queue if prefab/parameter mismatch occurs (legacy save handling).

  • public void CompleteWriters()
    Completes any outstanding writer JobHandles.

  • public NativeQueue<StatisticsEvent> GetStatisticsEventQueue(out JobHandle deps)
    Returns the raw NativeQueue for producers and outputs the current writer dependencies. Asserts that the system is enabled.

  • public SafeStatisticQueue GetSafeStatisticsQueue(out JobHandle deps)
    Returns a SafeStatisticQueue wrapper that will only enqueue if the system is enabled. Also returns writer dependencies to be combined by producers.

  • public void AddWriter(JobHandle writer)
    Combine the provided writer JobHandle into the internal m_Writers dependency (call after scheduling a producing job).

  • public void DiscardStatistics()
    Completes writers and clears the event queue (useful when resetting city or discarding partial data).

  • public void Serialize<TWriter>(TWriter writer) where TWriter : IWriter
    Serializes sample count, last sample frame index and pending statistics events (writes event count then each StatisticsEvent). Completes writers before serialization.

  • public void Deserialize<TReader>(TReader reader) where TReader : IReader
    Deserializes sampleCount, last sample frame index and pending events (handles multiple legacy save versions). Clears and repopulates event queue accordingly.

  • public void SetDefaults(Context context)
    Reset defaults for serialization: sets sampleCount to 0 and clears event queue.

  • public void PostDeserialize(Context context)
    Called after deserialization: clears and reinitializes the lookup (calls InitializeLookup).

  • protected override void OnCreateForCompiler()
    Generated method used by the ECS compiler to assign queries/handles.

  • Additional internal methods / generated helpers:

  • private void __AssignQueries(ref SystemState state) (compiler helper)
  • private struct TypeHandle.__AssignHandles(ref SystemState state) (assigns ComponentLookup/BufferLookup used in jobs)

Usage Example

// Example: Get system and enqueue a statistic event from a Job or system.
// 1) Get the system
var statsSystem = World.GetOrCreateSystemManaged<Game.Simulation.CityStatisticsSystem>();

// 2) When scheduling a job that will produce statistics:
//    get a SafeStatisticQueue and the writer dependencies from the system.
JobHandle writerDeps;
var safeQueue = statsSystem.GetSafeStatisticsQueue(out writerDeps);

// In your producer job or job setup you can enqueue events via safeQueue.Enqueue(...)
// After scheduling your producer job, make sure to add its handle:
JobHandle myProducerHandle = /* the JobHandle returned when scheduling your producer */;
statsSystem.AddWriter(myProducerHandle);

// If you need to read a statistic on the main thread:
int population = statsSystem.GetStatisticValue(StatisticType.Population);
long money = statsSystem.GetStatisticValueLong(StatisticType.Money);

// To get the historical array of a statistic:
var history = statsSystem.GetStatisticDataArray(StatisticType.Population);

Notes and tips: - Producers must call statsSystem.AddWriter(jobHandle) so the system can wait for those writers before reading or serializing. - Use GetSafeStatisticsQueue from jobs to safely enqueue without checking system enabled state; combine job handles with AddWriter. - Call CompleteWriters() before directly accessing the underlying NativeQueue or before serializing to ensure all producers are finished. - InitializeLookup creates statistic entities from statistic prefabs when needed; it runs automatically on first update and after deserialization (via PostDeserialize).