Game.WindSimulationSystem
Assembly:
Namespace: Game.Simulation
Type: public class
Base: GameSystemBase, IDefaultSerializable, ISerializable
Summary:
Simulates 3D wind as a grid of volumetric cells (WindCell) using Unity Jobs / Burst for performance. The system maintains per-cell pressure and velocity, steps the simulation in two alternating job phases (velocity update and pressure update), integrates terrain and water surface heights to affect flow, supports serialization/deserialization, debug save/load to disk, and exposes APIs to read the cell buffer and to set a global wind/pressure. The system is intended for use in Cities: Skylines 2 modding as the engine-level wind field provider for other systems (e.g., weather, particles, and environment effects).
Fields
public struct WindCell
Represents a single cell in the wind volume. Contains:float m_Pressure
— scalar pressure value for the cell.float3 m_Velocities
— velocity components (x, y, z) for the cell.-
The struct implements ISerializable with Serialize/Deserialize methods to read/write pressure and velocities.
-
private struct UpdateWindVelocityJob
(BurstCompiled)
Job that updates per-cell velocities based on neighboring cell pressures, terrain/water heights and slowdown factors. Runs over each cell and: - Applies slowdown factors (air, terrain, vertical) and change factor to produce new velocity components.
- Samples water/terrain height information via provided TerrainHeightData and WaterSurfaceData.
-
Writes updated WindCell values back into the NativeArray.
-
private struct UpdatePressureJob
(BurstCompiled)
Job that updates per-cell pressure from velocity divergence and applies boundary/edge driving forces based on the constant wind vector. Runs over every cell and: - Subtracts outgoing velocities, adds incoming neighbor velocities.
-
On edges, applies a computed driving pressure that depends on the constant wind, cell position and altitude layer.
-
public static readonly int kUpdateInterval
Update frequency (in simulation ticks) for this system. Value: 512. -
public static readonly int3 kResolution
Grid resolution of the voxel wind field (x,y,z). Uses WindSystem.kTextureSize for x/y and 16 layers for z. -
public static readonly float kChangeFactor
Factor controlling how quickly pressure differences change velocities. Value: 0.02. -
public static readonly float kTerrainSlowdown
Slowdown multiplier applied near terrain. Value: 0.99. -
public static readonly float kAirSlowdown
General air slowdown per step. Value: 0.995. -
public static readonly float kVerticalSlowdown
Vertical velocity slowdown multiplier. Value: 0.9. -
private SimulationSystem m_SimulationSystem
Cached reference to the SimulationSystem from the World. -
private TerrainSystem m_TerrainSystem
Cached reference to the TerrainSystem used to read height data. -
private WaterSystem m_WaterSystem
Cached reference to the WaterSystem used to read water surface data. -
private ClimateSystem m_ClimateSystem
Cached reference to the ClimateSystem (present but not heavily used in this file). -
private bool m_Odd
Toggle used to alternate between velocity update and pressure update phases each frame the system runs. -
private JobHandle m_Deps
Current combined job dependency handle for outstanding jobs that operate on the wind cell buffer. -
private NativeArray<WindCell> m_Cells
Persistent NativeArray storing the entire wind grid (kResolution.x * kResolution.y * kResolution.z) of WindCell entries. -
public float2 constantWind { get; set; }
Public property representing global horizontal wind direction/magnitude used by the boundary pressure driver. -
private float m_ConstantPressure { get; set; }
Private property storing the base pressure value used when initializing/resetting cells.
Properties
-
public float2 constantWind { get; set; }
Global, public horizontal wind vector used to seed and drive wind at the grid edges. Can be changed at runtime (SetWind method also sets pressure and resets cells). -
private float m_ConstantPressure { get; set; }
Internal pressure default used when setting/resetting the grid.
Constructors
public WindSimulationSystem()
Default constructor. The system uses OnCreate to initialize subsystems and allocate the NativeArray; the constructor itself is present and marked with [Preserve] at runtime to prevent stripping.
Methods
-
public override int GetUpdateInterval(SystemUpdatePhase phase)
Returns how often the system should be updated for the given phase. For GameSimulation phase it returns kUpdateInterval (512); for other phases it returns 1. -
public unsafe byte[] CreateByteArray<T>(NativeArray<T> src) where T : struct
Utility to copy a NativeArrayinto a managed byte[] using UnsafeUtility.MemCpy. Useful for debug dumps or serialization helpers. -
public void DebugSave()
Completes outstanding jobs, then writes the grid resolution and raw cell bytes to Application.streamingAssetsPath + "/wind_temp.dat" using a BinaryWriter. Useful for offline debugging. -
public unsafe void DebugLoad()
Completes outstanding jobs, reads raw bytes from streamingAssetsPath + "/wind_temp.dat" and copies them directly into the m_Cells NativeArray memory. Use with caution because it performs unsafe raw memory writes. -
public void Serialize<TWriter>(TWriter writer) where TWriter : IWriter
Writes the number of cells, the cells NativeArray, and the constantWind vector to the writer. Used by the engine save/load streaming. -
public void Deserialize<TReader>(TReader reader) where TReader : IReader
Reads saved data back into the system. Handles version checks and compatibility: - If reader.context.version <= Version.stormWater then it returns early (older versions unsupported).
-
Supports reading cell array length and contents if versions indicate compatibility, and reads constantWind if available; otherwise sets a default constantWind.
-
public void SetDefaults(Context context)
Completes outstanding jobs and initializes all cells to the current m_ConstantPressure and velocities using constantWind (z velocity = 0). Called on reset/initialization. -
public void SetWind(float2 direction, float pressure)
Completes outstanding jobs, sets constantWind and m_ConstantPressure, then calls SetDefaults to apply the new wind/pressure across the grid. -
public static float3 GetCenterVelocity(int3 cell, NativeArray<WindCell> cells)
Compute an interpolated/center velocity for a cell by averaging the cell's velocity with those of negative-direction neighbors (to provide a center-sampled velocity). Helpful for sampling velocity at a voxel center. -
public static float3 GetCellCenter(int index)
Get world-space center position of the given flat index cell. Accounts for x/y cell location inside the horizontal CellMapSystem.kMapSize and maps z layers to world heights (100 + 1024 * layerNormalized). -
public NativeArray<WindCell> GetCells(out JobHandle deps)
Returns the internal NativeArrayand outputs the current dependency JobHandle so callers can add their own dependencies (reader jobs) or complete before reading. -
public void AddReader(JobHandle reader)
Combine an external reader job handle with the system's m_Deps to ensure correct job dependency tracking. -
[Preserve] protected override void OnCreate()
System initialization: - Retrieves references to SimulationSystem, TerrainSystem, WaterSystem, ClimateSystem from the World.
- Sets default constantWind (0.275, 0.275) and default pressure (40f).
-
Allocates the persistent NativeArray m_Cells sized to kResolution.x * kResolution.y * kResolution.z.
-
[Preserve] protected override void OnDestroy()
Disposes the persistent NativeArray m_Cells. Ensures no memory leaks. -
private WindCell GetCell(int3 position)
Instance helper to read a WindCell from m_Cells using 3D coordinates. -
public static WindCell GetCell(int3 position, NativeArray<WindCell> cells)
Static safe lookup that converts 3D coordinates to flat index and returns default(WindCell) when out of bounds. -
[Preserve] protected override void OnUpdate()
Main update loop invoked by the engine: - Requires terrain heightmap to be present.
- Alternates m_Odd each frame to schedule either UpdateWindVelocityJob or UpdatePressureJob.
- When scheduling UpdateWindVelocityJob it fetches TerrainHeightData and WaterSurfaceData and schedules the job over the entire grid. Adds readers to water/terrain systems to manage dependencies.
- When scheduling UpdatePressureJob it uses constantWind/10f for the driving wind.
-
Updates base.Dependency to the returned job handle so downstream systems in the same frame can depend on the wind results.
-
[Preserve] public WindSimulationSystem()
Empty preserved constructor (same as the public constructor mentioned earlier).
Usage Example
// Example: initialize and set a new wind direction / pressure at runtime
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
// The system will allocate m_Cells and set a default wind/pressure in OnCreate.
// To change the wind vector and pressure at runtime:
var windSystem = base.World.GetOrCreateSystemManaged<WindSimulationSystem>();
windSystem.SetWind(new float2(0.5f, 0.0f), 50f);
// If you need to read the cell array on the CPU:
JobHandle deps;
var cells = windSystem.GetCells(out deps);
deps.Complete(); // ensure jobs are finished before accessing cells on main thread
// read cells[index] as needed, then continue...
}