Represents a river segment between two node ids using a cubic Bezier setup and per-end properties. Stores start/end node ids, tangents, width, speed, waves and depth with clamped setters and provides simple helpers (Touches, OtherNodeId, WidthAt).
using Sandbox;
namespace RedSnail.WaterTool2;
/// <summary>
/// A river between two nodes: a cubic Bezier whose handles hang off the nodes. The water always flows from the start
/// node to the end node, so a river reads upstream to downstream; reversing a river swaps its ends.
/// </summary>
public sealed class WaterRiver
{
public const float MinWidth = 32.0f;
public const float MaxWidth = 16384.0f;
public int Id { get; set; }
/// <summary>
/// The upstream node.
/// </summary>
public int StartNodeId { get; set; }
/// <summary>
/// The downstream node.
/// </summary>
public int EndNodeId { get; set; }
/// <summary>
/// Bezier handle leaving the start node into the river (P1 - P0).
/// </summary>
public Vector3 StartTangent { get; set; }
/// <summary>
/// Bezier handle leaving the end node into the river (P2 - P3).
/// </summary>
public Vector3 EndTangent { get; set; }
/// <summary>
/// Width at the upstream end. The banks ease from this to <see cref="EndWidth"/> along the river.
/// </summary>
[Range(MinWidth, 4000.0f)] public float StartWidth { get; set { field = value.Clamp(MinWidth, MaxWidth); } } = 400.0f;
/// <summary>
/// Width at the downstream end.
/// </summary>
[Range(MinWidth, 4000.0f)] public float EndWidth { get; set { field = value.Clamp(MinWidth, MaxWidth); } } = 400.0f;
/// <summary>
/// How fast the water runs on level ground, in units per second. A river with nothing flowing into it starts at
/// this speed; slopes speed the water up and it settles back towards this on the flat. Rivers joining another
/// carry their own speed into it.
/// </summary>
[Range(0.0f, 1000.0f)] public float Speed { get; set { field = value.Clamp(0.0f, 10000.0f); } } = 120.0f;
/// <summary>
/// Wave strength, relative to the network's wave profile (a lake is 1 by default). Rivers are usually calmer than
/// the lakes they run into; the change is blended where they meet.
/// </summary>
[Range(0.0f, 2.0f)] public float Waves { get; set { field = value.Clamp(0.0f, 10.0f); } } = 0.35f;
/// <summary>
/// How deep the water is under its surface. Only gameplay reads it: swimming, drowning and buoyancy.
/// </summary>
[Range(10.0f, 2000.0f)] public float Depth { get; set { field = value.Clamp(1.0f, 100000.0f); } } = 250.0f;
public bool Touches(int _NodeId)
{
return StartNodeId == _NodeId || EndNodeId == _NodeId;
}
public int OtherNodeId(int _NodeId)
{
return StartNodeId == _NodeId ? EndNodeId : StartNodeId;
}
/// <summary>
/// The width at one of the river's ends, by node.
/// </summary>
public float WidthAt(int _NodeId)
{
return StartNodeId == _NodeId ? StartWidth : EndWidth;
}
}