Game.ClimateSystem
Assembly: Assembly-CSharp
Namespace: Game.Simulation
Type: public class ClimateSystem
Base: GameSystemBase, IDefaultSerializable, ISerializable, IPreSerialize, IPostDeserialize
Summary:
Manages the planet/simulation climate for Cities: Skylines 2. Responsible for:
- Storing and switching climate prefabs (current climate/season).
- Sampling temperature, precipitation, cloudiness, aurora and fog values for a given normalized date.
- Calculating seasonal/average statistics (mean temperature, precipitation, cloudiness).
- Selecting and applying weather effects (current and next) using weather prefabs and scheduling them on the ClimateRenderSystem.
- Interfacing with trigger and planetary systems (emits TriggerActions based on current weather) and handling serialization of climate state.
- Maintaining overrideable properties (temperature, precipitation, cloudiness, aurora, fog, date) so other systems or mods can force values.
Fields
-
private TriggerSystem m_TriggerSystem
Reference to the TriggerSystem used to enqueue weather/temperature related triggers. -
private PrefabSystem m_PrefabSystem
Reference to the PrefabSystem used to resolve Climate/Weather/Season prefabs and their entities. -
private TimeSystem m_TimeSystem
Reference to the TimeSystem for conversions between normalized time/date and day-of-year sampling. -
private ClimateRenderSystem m_ClimateRenderSystem
Used to schedule, clear and apply visual weather effects. -
private PlanetarySystem m_PlanetarySystem
Used to set planetary parameters (e.g., latitude/longitude) from the current climate prefab. -
private EntityQuery m_ClimateQuery
EntityQuery used to find climate entities in the world (used when falling back to defaults after deserialization). -
private OverridableProperty<float> m_Date
Internal overridable property for the current normalized date. Exposed via currentDate property. -
private Entity m_CurrentClimate
Entity reference to the currently active Climate prefab/entity. -
private NativeList<Entity> m_CurrentWeatherEffects
Persistent NativeList of Entities representing weather effects currently active (applied). -
private NativeList<Entity> m_NextWeatherEffects
Persistent NativeList of Entities representing weather effects scheduled as "next" (transition target). -
private float m_TemperatureBaseHeight
Cached base height used for temperature calculations (sampled from map start tiles on PreSerialize). -
private SeasonInfo m_CurrentSeason
Cached season information for the currentDate (holds SeasonPrefab reference and season parameters). -
private static readonly int[,] kLut
Lookup-table used by the EkholmModen mean temperature algorithm (12x5 int table). -
private static readonly int[] kSampleTimes
Array [7,13,19] used by the EkholmModen sampling routine. -
public OverridableProperty<float> thunder
Public overridable property controlling thunder intensity (OverridableProperty exposed field).
Notes: - NativeLists are allocated with Allocator.Persistent and disposed in OnDestroy. Mods interacting with the system should not dispose those lists.
Properties
-
public float2 wind { get; private set; }
Current wind vector (x,y). Initialized to (0.0275, 0.0275). Modifiable by the system internally; readable publicly. -
public float hail { get; set; }
Hail intensity. Simple auto-property. -
public float rainbow { get; set; }
Rainbow intensity. Simple auto-property. -
public float aerosolDensity { get; private set; }
Current aerosol density (read-only externally). -
public float seasonTemperature { get; private set; }
Mean temperature for the current season section (calculated when season changes). -
public float seasonPrecipitation { get; private set; }
Mean precipitation for the current season section. -
public float seasonCloudiness { get; private set; }
Mean cloudiness for the current season section. -
public OverridableProperty<float> currentDate => m_Date
Exposes the overridable normalized date property. Allows forcing a date for sampling. -
public OverridableProperty<float> precipitation { get; }
Overrideable precipitation value. If overrideState is true, SampleClimate will return overrideValue. -
public OverridableProperty<float> temperature { get; }
Overrideable temperature value. -
public OverridableProperty<float> cloudiness { get; }
Overrideable cloudiness value. -
public OverridableProperty<float> aurora { get; }
Overrideable aurora intensity. -
public OverridableProperty<float> fog { get; }
Overrideable fog value. -
public Entity currentClimate
Get/set current climate Entity. Setter validates Entity is not Entity.Null, ensures seasons are ordered, computes average temperature and updates season/weather. Setting this will trigger recalculation and possibly UpdateWeather. -
public float temperatureBaseHeight => m_TemperatureBaseHeight
Exposes the stored base height used in temperature calculations. -
public float snowTemperatureHeightScale => 0.01f
Constant scale factor used elsewhere to relate snow/temperature to height. -
public float averageTemperature { get; private set; }
Average temperature calculated from the current climate (depends on time system sampling method). -
public float freezingTemperature { get; private set; }
Freezing threshold taken from the current climate prefab. -
public bool isRaining
True if precipitation > 0 and temperature > freezingTemperature. -
public bool isSnowing
True if precipitation > 0 and temperature <= freezingTemperature. -
public bool isPrecipitating => (float)precipitation > 0f
True if precipitation override or sampled precipitation is > 0. -
public WeatherClassification classification { get; private set; }
Current overall weather classification (Clear, Overcast, Stormy, etc.). Updated when weather effects are applied. -
public Entity currentSeason
Returns the Entity of the current season prefab (or Entity.Null if no current season). -
public string currentSeasonNameID => m_CurrentSeason?.m_NameID
Name ID of current season (if any).
Constructors
public ClimateSystem()
Default constructor. Nothing special beyond standard initialization; core initialization happens in OnCreate (as a Game system).
Methods
-
protected override void OnCreate()
Initializes subsystem references (TriggerSystem, PrefabSystem, TimeSystem, ClimateRenderSystem, PlanetarySystem), allocates NativeLists for current/next weather effects and prepares an EntityQuery for ClimateData. Also constructs m_Date overridable property referencing TimeSystem.normalizedDate. -
protected override void OnDestroy()
Disposes NativeLists created in OnCreate and performs base cleanup. -
protected override void OnUpdate()
Main per-frame update: if currentClimate is set, samples climate for m_Date and fills the overridable property values (temperature, precipitation, cloudiness, aurora, fog), updates season and weather. Also calls HandleTriggers if triggers are enabled. -
private void HandleTriggers()
Creates a TriggerAction buffer and enqueues temperature- and weather-related TriggerActions (e.g., WeatherRainy, WeatherSnowy, WeatherSunny, WeatherCloudy, AuroraBorealis) based on current sampled values, classification and time-of-day. -
public void PreSerialize(Context context)
If saving a map, calculates and stores temperature base height (CalculateTemperatureBaseHeight) to include in save. Called before Serialize. -
public void Serialize<TWriter>(TWriter writer) where TWriter : IWriter
Serializes current climate entity, current/next weather effect lists, and m_TemperatureBaseHeight. Uses the passed writer to write Entities and lists. -
public void SetDefaults(Context context)
Resets climate state to defaults: clears current climate, resizes weather lists to 0 and sets temperature base height to 0. -
public void Deserialize<TReader>(TReader reader) where TReader : IReader
Reads back currentClimate, m_CurrentWeatherEffects, m_NextWeatherEffects and m_TemperatureBaseHeight from the reader. -
public void PostDeserialize(Context context)
After deserialization, validates the current climate prefab; if missing, selects the first available Climate entity. Ensures seasons order, recalculates averageTemperature, updates season and either applies saved effects or recomputes weather. Also sets planetary latitude/longitude from the loaded climate prefab. -
private bool AreEffectsInvalid(NativeList<Entity> list)
Checks a saved weather-effects list for invalid (Entity.Null) entries. If any found, clears the list and returns true. -
public ClimateSample SampleClimate(ClimatePrefab prefab, float t)
Sample raw climate values from the given ClimatePrefab at normalized date t (temperature, precipitation, cloudiness, aurora, fog). Returns a ClimateSample (struct with those fields). -
public ClimateSample SampleClimate(float t)
Samples current climate prefab at date t and respects overrideable properties (temperature, precipitation, cloudiness, aurora, fog) — that is, if any OverridableProperty has overrideState = true, the returned Sample uses the overrideValue. -
private void UpdateSeason(ClimatePrefab prefab, float normalizedDate)
Looks up the season corresponding to normalizedDate (prefab.FindSeasonByTime) and if season changed, recalculates seasonTemperature, seasonPrecipitation and seasonCloudiness for the season range. -
private void UpdateWeather(ClimatePrefab prefab)
Core weather selection logic: - Builds temporary lists of WeatherTempData for current and next period.
- If prefab has a default weather, will attempt to select a placeholder/neighbor default weathers and then randomize using SelectRandomWeather.
- Sorts and compares with existing m_CurrentWeatherEffects / m_NextWeatherEffects; if changed, calls ApplyWeatherEffects.
-
If no default weather, clears both effect lists.
-
private bool SelectDefaultWeather(ClimatePrefab prefab, ref NativeList<WeatherTempData> currentWeathers, ref NativeList<WeatherTempData> nextWeathers)
If prefab.m_DefaultWeather is present, adds it to both current and next lists (with large negative priority) and returns true. -
private bool SelectWeatherPlaceholder(ClimatePrefab prefab, out WeatherPrefab current, out WeatherPrefab next)
If prefab.m_DefaultWeathers array is present, picks two adjacent default weather prefabs based on closeness of their cloudiness to the current cloudiness to serve as placeholders for current and next. Returns true if placeholders selected. -
private void SelectRandomWeather(WeatherPrefab weather, ref NativeList<WeatherTempData> weathers)
Given a chosen placeholder WeatherPrefab, adds the placeholder entity (priority -1000) and iterates its PlaceholderObjectElement buffer to consider random concrete weather effect prefabs. Evaluates requirements and randomization layer (Aurora / Cloudiness / Season) and pushes candidates with layer-based priority biases. Also considers currentSeason requirements. -
private bool ResetWeatherEffects(ref NativeList<Entity> weatherEffects)
Clears the given weatherEffects list and returns true if the list had elements (i.e., a change happened). -
private bool SortAndCheckUpdate(ref NativeList<WeatherTempData> weatherEffects, ref NativeList<Entity> reference)
Sorts weatherEffects by priority (WeatherTempData implements IComparable), then compares to the reference entity list; if lengths or entries differ, resizes and updates reference, returning true to indicate an update. -
private void ApplyWeatherEffects()
Clears existing scheduled climate render data, iterates m_CurrentWeatherEffects and schedules "from" effects and enumerates m_NextWeatherEffects scheduling "to" effects on ClimateRenderSystem. Updates classification to the highest non-irrelevant classification seen. This triggers the actual rendering/effect system to apply visual effects. -
Calculation utilities:
private float CalculateMeanTemperature(ClimatePrefab prefab, int resolutionPerDay = 48, float startRange = 0f, float endRange = 1f)
Samples min/max per-day temperature and returns the average of daily minima and maxima across a period.private float CalculateMeanPrecipitation(ClimatePrefab prefab, int resolutionPerDay = 48, float startRange = 0f, float endRange = 1f)
Averages precipitation samples across a period.private float CalculateMeanCloudiness(ClimatePrefab prefab, int resolutionPerDay = 48, float startRange = 0f, float endRange = 1f)
Averages cloudiness samples across a period.private float CalculateTemperatureAverage(ClimatePrefab prefab, int resolutionPerDay = 48)
Chooses a method for average temperature depending on days-per-year (special behavior when daysPerYear == 12 uses EkholmModen).private float CalculateMeanTemperatureEkholmModen(ClimatePrefab prefab, int resolutionPerDay)
Specialized algorithm used when there are 12 daysPerYear (uses kLut and kSampleTimes).private float CalculateMeanTemperatureStandard(ClimatePrefab prefab, int resolutionPerDay, out float meanMin, out float meanMax)
Standard method for mean temperature calculation across the year.private float CalculateTemperatureBaseHeight()
Samples terrain and water surface height over start tiles to compute an average base height used in some temperature/altitude calculations. Accesses TerrainSystem, WaterSystem and MapTileSystem; must complete jobs when acquiring water surface data.
Notes: - Many private helper methods operate on Prefab data and on entity buffers (PlaceholderObjectElement and ObjectRequirementElement buffers). They assume that m_PrefabSystem and EntityManager are available and valid. - All methods that allocate temporary NativeList or NativeArray use Allocator.Temp or Dispose afterwards.
Usage Example
// Example: Force a particular climate prefab entity and sample climate at current date.
var climateSystem = World.GetOrCreateSystemManaged<Game.Simulation.ClimateSystem>();
// Set current climate entity (ensure you have a valid Climate prefab entity)
climateSystem.currentClimate = myClimateEntity;
// Read sampled climate at the system's current date
var sample = climateSystem.SampleClimate(climateSystem.currentDate);
// Or sample at an arbitrary normalized date (0..1)
var noonSample = climateSystem.SampleClimate(0.5f);
// Force an override temperature value (e.g., for testing or a mod effect)
climateSystem.temperature.overrideState = true;
climateSystem.temperature.overrideValue = 25.0f;
// When done, remove override to return to prefab-driven values
climateSystem.temperature.overrideState = false;
If you want further details for any specific method or field (parameters, return values, expected prefab structure or example Climate/Weather prefab setup), tell me which part you want expanded and I will provide more focused documentation and examples.