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 aStatisticType
and an integerparameter
to identify unique statistic entities. -
public struct SafeStatisticQueue
Thread-safe wrapper around a NativeQueue. Provides Enqueue
that only enqueues when statistics are enabled. Returned viaGetSafeStatisticsQueue
. -
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 inOnCreate
.
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 NativeArraycontaining 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 atindex
(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).