Skip to content

Game.WaterTradeSystem

Assembly:
Likely part of the game's main "Game" assembly (Game.dll). This system lives in the simulation layer of Cities: Skylines 2 and is packaged with the game's runtime code.

Namespace: Game.Simulation

Type:
class

Base:
GameSystemBase, IDefaultSerializable, ISerializable

Summary:
Handles outside-water trading logic for the city: it scans trade-enabled water pipe nodes, aggregates exported/imported fresh water and sewage amounts (including polluted export estimation), and enqueues service fee events for outside trade (water export, water import, sewage export). The system uses Burst-compiled jobs (SumJob and WaterTradeJob) for parallel aggregation and cost calculation, and integrates with other simulation systems: WaterPipeFlowSystem (to know source/sink nodes), WaterStatisticsSystem (to compute available water), and ServiceFeeSystem (to enqueue fees). The system persists summary values (last export/import/sewage counts) via the ISerializable interface and updates at a coarse interval (see GetUpdateInterval/GetUpdateOffset).


Fields

  • private WaterPipeFlowSystem m_WaterPipeFlowSystem
    Reference to the WaterPipeFlowSystem. Used to get the source/sink trade nodes for water flow direction and to identify which connected edges represent exports vs imports.

  • private WaterStatisticsSystem m_WaterStatisticsSystem
    Reference to the WaterStatisticsSystem. Used to compute available fresh water (capacity minus consumption) for export limiting.

  • private EntityQuery m_TradeNodeGroup
    EntityQuery used to select trade nodes having TradeNode, WaterPipeNode and ConnectedFlowEdge components. Iterated by the SumJob to aggregate trade flows.

  • private ServiceFeeSystem m_ServiceFeeSystem
    Reference to the ServiceFeeSystem. Provides a FeeQueue writer to enqueue outside trade cost events for player resources.

  • private NativePerThreadSumInt m_FreshExport
    Thread-safe per-thread integer aggregator for fresh water exported toward the outside.

  • private NativePerThreadSumInt m_PollutedExport
    Thread-safe per-thread integer aggregator for polluted amount attributed to exports (used to limit export of polluted water).

  • private NativePerThreadSumInt m_FreshImport
    Thread-safe per-thread integer aggregator for fresh water imported from outside.

  • private NativePerThreadSumInt m_SewageExport
    Thread-safe per-thread integer aggregator for sewage exported to outside.

  • private int m_LastFreshExport
    Serialized/persisted snapshot of the last frame's fresh export total (written during Serialize). Exposed via freshExport property.

  • private int m_LastFreshImport
    Serialized/persisted snapshot of the last frame's fresh import total. Exposed via freshImport property.

  • private int m_LastSewageExport
    Serialized/persisted snapshot of the last frame's sewage export total. Exposed via sewageExport property.

  • private TypeHandle __TypeHandle
    Internal container for BufferTypeHandle and ComponentLookup handles used by the job (ConnectedFlowEdge buffer and WaterPipeEdge lookup). Populated in OnCreateForCompiler.

  • private EntityQuery __query_1457460959_0
    Internal EntityQuery used to access the singleton OutsideTradeParameterData (includes import/export prices and pollution tolerance).

Properties

  • public int freshExport { get; }
    Returns m_LastFreshExport, the persisted snapshot of fresh water exported during the last update. Use for statistics/UI reporting.

  • public int freshImport { get; }
    Returns m_LastFreshImport, the persisted snapshot of fresh water imported during the last update.

  • public int sewageExport { get; }
    Returns m_LastSewageExport, the persisted snapshot of sewage exported during the last update.

Constructors

  • public WaterTradeSystem()
    Default constructor. The real initialization is done in OnCreate (obtains other systems, initializes queries and native aggregators). Constructor itself is empty.

Methods

  • public override int GetUpdateInterval(SystemUpdatePhase phase)
    Returns 128 — this system runs every 128 frames (coarse-grain update to reduce cost).

  • public override int GetUpdateOffset(SystemUpdatePhase phase)
    Returns 62 — offset to stagger updates.

  • [Preserve] protected override void OnCreate()
    Initializes references to other systems (WaterPipeFlowSystem, ServiceFeeSystem, WaterStatisticsSystem), builds the TradeNode entity query, requires the OutsideTradeParameterData singleton for updates, and allocates NativePerThreadSumInt aggregators (persistent). Called when the system is created.

  • [Preserve] protected override void OnDestroy()
    Disposes the NativePerThreadSumInt aggregators and calls base.OnDestroy(). Ensures native memory is freed.

  • public void Serialize<TWriter>(TWriter writer) where TWriter : IWriter
    Writes three integers (m_LastFreshExport, m_LastFreshImport, m_LastSewageExport) into the save stream so last-known trade numbers persist across loads.

  • public void Deserialize<TReader>(TReader reader) where TReader : IReader
    Reads and restores the three persisted integers from the save stream into the corresponding fields.

  • public void SetDefaults(Context context)
    Sets default values for persisted counters (zeros). Called when initializing default save state.

  • [Preserve] protected override void OnUpdate()
    Main runtime logic run on the update interval. Steps:

  • Save current aggregators into m_Last* fields for persistence/UI.
  • Compute available water from WaterStatisticsSystem (freshCapacity - freshConsumption).
  • Reset per-thread aggregator counts to zero.
  • If any trade nodes exist:

    • Obtain OutsideTradeParameterData singleton (prices and pollution tolerance).
    • Schedule SumJob as a parallel IJobChunk over trade node group to aggregate fresh/polluted exports and imports/sewage exports per connected flow edges. SumJob uses ConnectedFlowEdge buffers and WaterPipeEdge component lookup to classify edges as exports (edges that end at sink node) or imports (edges that start at source node). Polluted export estimate uses the outside pollution tolerance param.
    • Schedule WaterTradeJob (IJob) after the chunk job and after getting a FeeQueue writer from ServiceFeeSystem. WaterTradeJob clamps fresh export to available water, normalizes counts (dividing by 2048f) then computes costs using prices in OutsideTradeParameterData. For each positive cost a ServiceFeeSystem.FeeEvent is enqueued for Water or Sewage resource with appropriate positive or negative amount and m_Outside = true.
    • Register the ServiceFeeSystem queue writer dependency.
  • private void __AssignQueries(ref SystemState state)
    Compiler-generated helper that builds the internal entity query for OutsideTradeParameterData (includes systems). Called from OnCreateForCompiler.

  • protected override void OnCreateForCompiler()
    Compiler-time initialization path that assigns queries and type handles into __TypeHandle by calling __AssignQueries and TypeHandle.__AssignHandles.

Nested job summaries: - SumJob (BurstCompile, IJobChunk)
Iterates trade node chunks, reads ConnectedFlowEdge buffers and WaterPipeEdge components to collect per-thread sums for: FreshExport, PollutedExport (estimated), FreshImport, SewageExport. Uses m_SourceNode and m_SinkNode (from WaterPipeFlowSystem) to determine flow direction. Asserts on non-negative flows and zero sewage on export edges.

  • WaterTradeJob (BurstCompile, IJob)
    Reads aggregated counts, clamps fresh export to available water, scales counts by 1/2048f, multiplies by outside trade prices to compute costs, and enqueues ServiceFeeSystem.FeeEvent entries for positive costs (water export revenue, water import cost as negative amount, sewage export cost as negative amount).

Usage Example

// Example: from another mod/system obtaining the WaterTradeSystem and reading last recorded trade numbers
[Preserve]
protected override void OnCreate()
{
    base.OnCreate();
    var waterTrade = World.GetOrCreateSystemManaged<Game.Simulation.WaterTradeSystem>();
    // Read persisted snapshot values (updated on the system's update tick)
    int lastExport = waterTrade.freshExport;
    int lastImport = waterTrade.freshImport;
    int lastSewageExport = waterTrade.sewageExport;
    // You can use those values to display UI or generate statistics.
}

Notes and modding tips: - The system relies on OutsideTradeParameterData for prices and pollution tolerance; you can inspect or modify that singleton if you need to change outside trade economics. - NativePerThreadSumInt is used for parallel aggregation; ensure you match the system's update interval if you depend on its outputs (it only updates every 128 frames). - To observe or monitor enqueued fee events, inspect ServiceFeeSystem or subscribe to its queue writers; WaterTradeSystem enqueues FeeEvent entries with m_Outside = true so they are identifiable as outside trades. - The export/import amounts are normalized by 2048f before pricing — this is important when interpreting fee magnitudes in the UI or logs.