Game.TimeSystem
Assembly: Assembly-CSharp (typical Unity game assembly)
Namespace: Game.Simulation
Type: class
Base: GameSystemBase (implements ITimeSystem, IPostDeserialize)
Summary:
TimeSystem manages the in-game simulation time and date for Cities: Skylines 2. It converts the simulation frame index (from SimulationSystem) into normalized day/time values, computes year/day offsets, and exposes helper methods to obtain DateTime values for rendering or gameplay use. The system reads time configuration from a TimeSettingsData singleton and stores persistent offsets in a TimeData entity. Key behaviors:
- Uses a fixed tick resolution: kTicksPerDay = 262144 ticks per day.
- Exposes normalizedTime (time of day) and normalizedDate (time of year) and the current year.
- During deserialization it ensures a TimeData entity exists and initializes start-frame/starting year for new games.
- Updates its cached time values each frame in UpdateTime() (called from OnUpdate).
Fields
-
private SimulationSystem m_SimulationSystem
Reference to the simulation system used to read the current simulation frame index (frame-based time source). -
public const int kTicksPerDay = 262144
Constant tick count representing one in-game day. Used throughout time calculations. -
private float m_Time
Cached normalized time-of-day [0..1) for the current simulation frame (updated in UpdateTime()). -
private float m_Date
Cached normalized time-of-year [0..1) (updated in UpdateTime()). -
private int m_Year = 1
Cached current year (initialized to 1, updated in UpdateTime()). -
private int m_DaysPerYear = 1
Cached days-per-year value. Lazily read from TimeSettingsData if zero. -
private uint m_InitialFrame
An unsigned integer intended to store an initial frame index. Present in the class but not used directly in other methods in this file. -
private EntityQuery m_TimeSettingGroup
EntityQuery that selects the TimeSettingsData singleton used to configure days per year and other settings. -
private EntityQuery m_TimeDataQuery
EntityQuery that selects the TimeData singleton which stores persistent time offsets and starting-frame data.
Properties
-
public int startingYear { get; set; }
Public property that holds the starting year for new games. When creating a new game during PostDeserialize, this is written into the TimeData singleton. -
public float normalizedTime => m_Time
Read-only property exposing the cached normalized time-of-day (0..1). Use for UI, rendering and other time-dependent logic. -
public float normalizedDate => m_Date
Read-only property exposing the cached normalized time-of-year (0..1). -
public int year => m_Year
Read-only property exposing the cached current year. -
public int daysPerYear
Read-only property that returns the number of days per year. If m_DaysPerYear is zero the value is fetched from the TimeSettingsData singleton and clamped to at least 1.
Constructors
public TimeSystem()
Default constructor. Marked with [Preserve] in source to prevent stripping; no initialization beyond field defaults. The real initialization occurs in OnCreate().
Methods
-
protected override void OnCreate()
Initializes the system: gets/creates the SimulationSystem, sets up EntityQuery objects (TimeSettingsData and TimeData), and requires those queries for update (RequireForUpdate). Called when the system is created. -
public void PostDeserialize(Context context)
Called after serialization/deserialization. Ensures a TimeData entity exists, initializes TimeData fields for new games (sets m_FirstFrame to the current simulation frame and m_StartingYear from startingYear), and calls UpdateTime() to populate cached time fields. -
protected int GetTicks(uint frameIndex, TimeSettingsData settings, TimeData data)
Compute total tick count relative to a TimeData.m_FirstFrame using an explicit frameIndex. Adds TimeOffset and date offset contributions. Returns ticks as an int. -
protected int GetTicks(TimeSettingsData settings, TimeData data)
Same as above but uses the current simulation frame from m_SimulationSystem.frameIndex. -
protected double GetTimeWithOffset(TimeSettingsData settings, TimeData data, double renderingFrame)
Returns a double representing the rendering frame plus time and date offsets (in ticks). Used as helper for fractional time calculations. -
public float GetTimeOfDay(TimeSettingsData settings, TimeData data, double renderingFrame)
Public helper that returns the time-of-day [0..1) for a given rendering frame (accounts for TimeData offsets). -
protected float GetTimeOfDay(TimeSettingsData settings, TimeData data)
Returns the time-of-day [0..1) for the current simulation frame. -
public float GetTimeOfYear(TimeSettingsData settings, TimeData data, double renderingFrame)
Returns normalized time-of-year [0..1) for a given rendering frame. Takes days-per-year into account. -
protected float GetTimeOfYear(TimeSettingsData settings, TimeData data)
Returns normalized time-of-year [0..1) for the current simulation frame. -
public float GetElapsedYears(TimeSettingsData settings, TimeData data)
Returns the number of elapsed years (floating-point) since TimeData.m_FirstFrame based on tick counts and days-per-year. -
public float GetStartingDate(TimeSettingsData settings, TimeData data)
Returns the starting normalized date-of-year (based on data stored in TimeData and TimeSettingsData). -
public int GetYear(TimeSettingsData settings, TimeData data)
Compute the integer year given settings and TimeData (adds data.m_StartingYear and the number of full years elapsed since m_FirstFrame). -
public static int GetDay(uint frame, TimeData data)
Static helper to get the integer day count since m_FirstFrame using a frame index and data.TimeOffset. Returns floor((frame - firstFrame)/ticksPerDay + TimeOffset). -
public void DebugAdvanceTime(int minutes)
Debug helper that advances in-game time by a number of minutes by subtracting from TimeData.m_FirstFrame (effectively fast-forwarding). Useful for testing. -
private static DateTime CreateDateTime(int year, int day, int hour, int minute, float second)
Constructs a UTC DateTime from year/day/hour/minute/second values. Applies daylight-saving-time correction (adds an hour if the resulting DateTime falls into DST). Used by GetDateTime/GetCurrentDateTime to create real DateTime instances from normalized values. -
public DateTime GetDateTime(double renderingFrame)
Returns a DateTime corresponding to a given rendering frame (fractional frame), factoring in TimeSettingsData and TimeData offsets. Converts normalized time-of-day and time-of-year into concrete year/day/hour/minute/second values. -
public DateTime GetCurrentDateTime()
Returns a DateTime built from the cached normalizedTime, normalizedDate and year. Useful for code that needs the current in-game wall-clock time. -
protected override void OnUpdate()
Called each frame by the ECS world. Calls UpdateTime() to refresh cached values. -
private void UpdateTime()
Internal method that reads the TimeSettingsData and TimeData singletons and updates m_Time, m_Date, m_Year and m_DaysPerYear fields.
Usage Example
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
// Example: get a reference to the TimeSystem and query current DateTime
var timeSystem = World.GetOrCreateSystemManaged<Game.Simulation.TimeSystem>();
DateTime current = timeSystem.GetCurrentDateTime();
Debug.Log($"In-game date/time: {current.ToString("u")}");
}
Notes and tips: - kTicksPerDay (262144) is used as the base resolution for fractional day calculations; many methods rely on this constant. - TimeSettingsData.m_DaysPerYear configures the number of days in a year; ensure this singleton exists (the system requires it). - TimeData stores m_FirstFrame, TimeOffset, date offsets and m_StartingYear; PostDeserialize ensures it's created on load. - DateTime values produced by the system use UTC as a base and apply a daylight-saving hour if the computed DateTime would be in DST.