Game.Simulation.WaterPipeFlowSystem
Assembly: Assembly-CSharp
Namespace: Game.Simulation
Type: class
Base: GameSystemBase, IDefaultSerializable, ISerializable, IPostDeserialize
Summary:
Manages the water and sewage pipe flow simulation using Unity's Entities + Jobs + Burst pipeline. The system prepares node/edge data from ECS components, builds connection lists, schedules flow solver jobs (separate data for fresh water and sewage), and applies computed flows back to WaterPipeEdge components. It is frame-scheduled across multiple phases (Prepare, Flow, Apply) to spread work over simulation frames, supports serialization/deserialization of minimal state, and maintains persistent native containers used by the flow job. The system also handles creation of helper source/sink nodes and compatibility fixes for legacy save versions.
Fields
-
public const int kUpdateInterval = 128
Constant controlling the update interval (frames) used by the system. -
public const int kUpdateOffset = 64
Constant for update offset. -
public const int kUpdatesPerDay = 2048
Constant giving number of updates per day (game-specific). -
public const int kStartFrames = 2
Frame count constants used to schedule phases. -
public const int kAdjustFrame = 64
Frame index constants (used for scheduling). -
public const int kPrepareFrame = 65
Frame index when Prepare phase runs. -
public const int kFlowFrames = 124
Number of frames allocated to flow processing. -
public const int kFlowCompletionFrame = 61
Frame index used to determine flow completion. -
public const int kEndFrames = 2
Frame count constants used to schedule phases. -
public const int kApplyFrame = 62
Frame index when Apply phase runs. -
public const int kStatusFrame = 63
Frame index for status handling. -
public const int kMaxEdgeCapacity = 1073741823
Maximum capacity used for edges (int max-like constraint for flow jobs). -
private const int kLayerHeight = 20
Layer height passed to flow job (internal job parameter). -
private SimulationSystem m_SimulationSystem
Reference to the SimulationSystem used to read frame index and schedule phase transitions. -
private EntityQuery m_NodeGroup
EntityQuery selecting WaterPipeNode + ConnectedFlowEdge components (nodes). -
private EntityQuery m_EdgeGroup
EntityQuery selecting WaterPipeEdge components (edges). -
private EntityArchetype m_NodeArchetype
Archetype used for creating node entities (used for source/sink). -
private EntityArchetype m_EdgeArchetype
Archetype used for creating edge entities (not commonly created here, but used for capacity/chunk info). -
private WaterPipeFlowJob.Data m_FreshData
Persistent data container for fresh (water) flow simulation, includes nodes, edges, states, layer structures. -
private WaterPipeFlowJob.Data m_SewageData
Persistent data container for sewage flow simulation. -
private NativeList<Connection> m_Connections
NativeList of Connection structures built during Prepare phase and consumed by flow jobs. -
private NativeReference<NodeIndices> m_NodeIndices
NativeReference storing source/sink indices (node indices) for the flow job. -
private NativeList<int> m_TradeNodes
NativeList of node indices flagged as trade nodes (special behavior in flow job). -
private Entity m_SourceNode
Entity used as an artificial source node for the flow simulation. -
private Entity m_SinkNode
Entity used as an artificial sink node for the flow simulation. -
private Phase m_NextPhase
Internal enum value tracking next scheduled phase (Prepare, Flow, Apply). -
private JobHandle m_DataDependency
JobHandle tracking outstanding job dependencies for safe scheduling and disposal. -
private TypeHandle __TypeHandle
Struct holding component/handle types used by job scheduling (cached to avoid repeated lookups). -
public bool ready { get; private set; }
Property tracking whether the system has completed a full Prepare->Flow->Apply cycle and applied flows (set in ApplyPhase).
(There are additional nested job structs and job-related fields inside the class used to implement per-chunk work; those are part of the implementation and scheduled by the system. See Methods for job descriptions.)
Properties
-
public bool ready { get; private set; }
Indicates that the system has completed the last Apply phase (true after ApplyPhase runs). Readable publicly; set privately by system. -
public EntityArchetype nodeArchetype => m_NodeArchetype
Public getter exposing the node archetype used by the system. -
public EntityArchetype edgeArchetype => m_EdgeArchetype
Public getter exposing the edge archetype used by the system. -
public Entity sourceNode => m_SourceNode
Public getter exposing the artificial source node entity (can be used by other systems). -
public Entity sinkNode => m_SinkNode
Public getter exposing the artificial sink node entity. -
public bool fluidFlowEnabled { get; set; } = true
Flag to enable/disable fluid-specific flow behavior in the flow job. Can be toggled by other code.
Constructors
public WaterPipeFlowSystem()
Default constructor. System initializes internal fields in OnCreate; constructor itself is preserved for Unity serialization. The heavy initialization (allocations of persistent native containers and entity queries) occurs in OnCreate.
Methods
-
protected override void OnCreate()
Initializes system: acquires SimulationSystem, builds entity queries (nodes/edges), creates archetypes, allocates persistent WaterPipeFlowJob.Data containers for fresh and sewage flows (200000 size in this implementation), allocates connections/node indices/trade node lists. Must be paired with OnDestroy to dispose native containers. -
protected override void OnDestroy()
Completes outstanding jobs and disposes all persistent native containers (WaterPipeFlowJob.Data, m_Connections, m_NodeIndices, m_TradeNodes). Ensures no job left referencing disposed memory. -
public void Reset()
Resets internal flow state: completes data dependency, sets next phase to Prepare, reinitializes WaterPipeFlowJob.State for fresh and sewage data, and sets ready = false. -
protected override void OnUpdate()
Called every frame. Routes execution to the current m_NextPhase method: PreparePhase, FlowPhase, or ApplyPhase depending on Phase enum. -
private void PreparePhase()
When scheduled (on specific frame index: m_SimulationSystem.frameIndex % 128 == 65), prepares native data for jobs: resizes node/edge native arrays, builds connection list, schedules PrepareNetworkJob, PrepareNodesJob, PrepareEdgesJob, PrepareConnectionsJob and PopulateNodeIndicesJob. After scheduling sets m_NextPhase = Phase.Flow and stores combined m_DataDependency. -
Nested jobs involved:
- PrepareNetworkJob: resizes native node/edge lists, clears/initializes connection list and trade node list.
- PrepareNodesJob (IJobChunk): assigns contiguous indices to WaterPipeNode.m_Index per-chunk.
- PrepareEdgesJob (IJobChunk): initializes per-edge Flow.Edge data (capacities/directions) and assigns WaterPipeEdge.m_Index.
- PrepareConnectionsJob (IJobChunk): iterates nodes, reads ConnectedFlowEdge buffers, and populates m_Connections with Connection structs linking start/end nodes and edge indices; also flags trade nodes.
- PopulateNodeIndicesJob: fills NodeIndices (source/sink) based on current m_SourceNode/m_SinkNode.
-
private void FlowPhase()
Runs repeated flow solver jobs during flow frames. Calculates uint num = frameIndex % 128 and schedules two flow jobs (one for fresh water, one for sewage) by calling ScheduleFlowJob. The function also asserts that FlowPhase does not run on specific reserved frames and sets m_NextPhase = Phase.Apply when finalFrame flag is true (frame index 61 indicates final). -
private JobHandle ScheduleFlowJob(WaterPipeFlowJob.Data jobData, int importCapacity, int exportCapacity, bool finalFrame)
Schedules the main WaterPipeFlowJob with the given Data container and capacities, controlled by m_DataDependency. Passes references to nodes, edges, connections, node indices, trade nodes, layer data, and flow flags. Returns the scheduled JobHandle. -
private void ApplyPhase()
When scheduled (m_SimulationSystem.frameIndex % 128 == 62), schedules ApplyEdgesJob (IJobChunk) to write results from the flow job back to WaterPipeEdge components (m_FreshFlow, m_SewageFlow, and sets WaterPipeEdgeFlags based on cut element IDs). Completes and updates dependencies, sets m_NextPhase = Phase.Prepare and ready = true. -
ApplyEdgesJob: reads m_FreshEdges and m_SewageEdges results and writes final flows and flags into WaterPipeEdge components in ECS.
-
public void Serialize<TWriter>(TWriter writer) where TWriter : IWriter
Completes outstanding jobs and writes essential state to writer: m_SourceNode, m_SinkNode, and lastTotalSteps for fresh and sewage flow states (used to resume solver progression across save/load). -
public void Deserialize<TReader>(TReader reader) where TReader : IReader
Completes outstanding jobs and reads state back in depending on save version. Handles compatibility with older versions (may ignore old saved source/sink values and instead recreate nodes). Reads lastTotalSteps for both fresh and sewage states when supported. -
public void SetDefaults(Context context)
Sets default values for the system when constructing a new save/context: calls Reset and sets source/sink to Entity.Null. -
public void PostDeserialize(Context context)
Called after all deserialization is done. Ensures source and sink nodes exist (creates them if both are Entity.Null). Calls Reset. Performs compatibility adjustments for very old versions: disables some consumption notifications (via DispatchWaterSystem) if save predates water pipe flow sim, and removes invalid WaterPipeNodeConnection components where the referenced node is null (legacy fix). -
protected override void OnCreateForCompiler()
Compiler-related initialization that assigns query handles and component type handles via __AssignQueries and __TypeHandle.__AssignHandles. -
private void __AssignQueries(ref SystemState state)
Internal helper to assign queries for the compiler-generated setup (empty here aside from a builder call). -
Additional internal job structs (PrepareNetworkJob, PrepareNodesJob, PrepareEdgesJob, PrepareConnectionsJob, PopulateNodeIndicesJob, ApplyEdgesJob) are declared as nested types and used to prepare, populate, and apply flow data across chunks using IJob / IJobChunk patterns with Burst compilation attributes. Each is responsible for specific per-chunk or per-array initialization used by the main WaterPipeFlowJob.
Usage Example
// Example: simple usage inside a system or mod initialization
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
// The system's OnCreate sets up queries and allocates native data.
// You can optionally toggle fluid flow behavior:
var waterSystem = World.GetExistingSystemManaged<Game.Simulation.WaterPipeFlowSystem>();
if (waterSystem != null)
{
// Disable detailed fluid flow (jobs still run but with simplified behavior)
waterSystem.fluidFlowEnabled = false;
// Reset simulation state (clears flow job states)
waterSystem.Reset();
}
}
Notes: - The system relies heavily on persistent Native containers (Allocator.Persistent). Always allow OnDestroy to run or call Reset/Dispose appropriately to avoid memory leaks. - Frame scheduling: Prepare runs at frame % 128 == 65, flow runs across frames with a final flow frame at 61, and apply runs at frame % 128 == 62. These offsets are important when interacting with other simulation systems. - Serialization compatibility code handles older save versions—if modifying serialization, maintain compatibility checks against Version constants used in game saves.