namespace Sandbox.Navigation.Generation; // Basically rcConfig with a frew extra fields internal struct Config { public static Config CreateValidatedConfig( Vector2Int tilePosition, BBox tileBoundsWorld, float cellSize, float cellHeight, float agentHeight, float agentRadius, float agentStepSize, float agentMaxSlope ) { var cfg = new Config(); cfg.CellSize = cellSize; if ( cfg.CellSize < 2f ) cfg.CellSize = 2f; cfg.CellHeight = cellHeight; if ( cfg.CellHeight < 0.5f ) cfg.CellHeight = 0.5f; cfg.WalkableSlopeAngle = Math.Clamp( agentMaxSlope, 0.0f, 90.0f ); cfg.WalkableHeight = (int)MathF.Ceiling( agentHeight / cfg.CellHeight ); cfg.WalkableHeight = Math.Max( cfg.WalkableHeight, 3 ); cfg.WalkableClimb = (int)MathF.Floor( agentStepSize / cfg.CellHeight ); cfg.WalkableClimb = Math.Max( cfg.WalkableClimb, 0 ); cfg.WalkableRadius = (int)MathF.Ceiling( agentRadius / cfg.CellSize ); cfg.WalkableRadius = Math.Max( cfg.WalkableRadius, 0 ); cfg.MaxVertsPerPoly = (int)Constants.VERTS_PER_POLYGON; cfg.MaxEdgeLen = (int)(256.0f / cfg.CellSize); cfg.MaxEdgeLen = Math.Max( cfg.MaxEdgeLen, 0 ); cfg.MaxSimplificationError = 2.0f; cfg.MaxSimplificationError = Math.Max( cfg.MaxSimplificationError, 0.0f ); cfg.MinRegionArea = (int)(8.0f * 8.0f); cfg.MinRegionArea = Math.Max( cfg.MinRegionArea, 0 ); cfg.MergeRegionArea = (int)(12.0f * 12.0f); cfg.MergeRegionArea = Math.Max( cfg.MergeRegionArea, 0 ); cfg.BorderSize = cfg.WalkableRadius + 3; cfg.BorderSize = Math.Max( cfg.BorderSize, 0 ); cfg.Bounds = tileBoundsWorld; // Pad the bounding box by border size to find the extents of geometry we need to build this tile. // :''''''''': // : +-----+ : // : | | : // : | |<--- tile to build // : | | : // : +-----+ :<-- geometry needed // :.........: // Only pad X & Y bounds // Z is not required as tiles cannnot overlap in z direction cfg.Bounds.Mins.x -= cfg.BorderSize * cfg.CellSize; cfg.Bounds.Mins.y -= cfg.BorderSize * cfg.CellSize; cfg.Bounds.Maxs.x += cfg.BorderSize * cfg.CellSize; cfg.Bounds.Maxs.y += cfg.BorderSize * cfg.CellSize; cfg.TileX = tilePosition.x; cfg.TileY = tilePosition.y; var sizeX = cfg.Bounds.Maxs.x - cfg.Bounds.Mins.x; var sizeY = cfg.Bounds.Maxs.y - cfg.Bounds.Mins.y; if ( !MathX.AlmostEqual( sizeX, sizeY, 0.1f ) ) { Log.Warning( $"Tile bounds {sizeX}x{sizeY} should be square" ); } if ( !MathX.AlmostEqual( sizeX.UnsignedMod( cellSize ), 0f, 0.1f ) && !MathX.AlmostEqual( sizeX.UnsignedMod( cellSize ), cellSize, 0.1f ) ) { Log.Warning( $"Tile bounds {sizeX}x{sizeY} should be divisible by cell size {cfg.CellSize}" ); } cfg.TileSizeXY = (int)(sizeX / cellSize + 0.5f); return cfg; } /// /// The tiles x position in tile coordinates. /// public int TileX; /// /// The tiles y position in tile coordinates. /// public int TileY; /// /// The width/height size of tile's on the xy-plane. [Limit: >= 0] [Units: vx] /// public int TileSizeXY; /// /// The size of the non-navigable border around the heightfield. [Limit: >=0] [Units: vx] /// public int BorderSize; /// /// The xz-plane cell size to use for fields. [Limit: > 0] [Units: wu] /// public float CellSize; /// /// The y-axis cell size to use for fields. [Limit: > 0] [Units: wu] /// public float CellHeight; /// /// The bounds of the field's AABB. [Units: wu] /// public BBox Bounds; /// /// The maximum slope that is considered walkable. [Limits: 0 <= value < 90] [Units: Degrees] /// public float WalkableSlopeAngle; /// /// Minimum floor to 'ceiling' height that will still allow the floor area to /// be considered walkable. [Limit: >= 3] [Units: vx] /// public int WalkableHeight; /// /// Maximum ledge height that is considered to still be traversable. [Limit: >=0] [Units: vx] /// public int WalkableClimb; /// /// The distance to erode/shrink the walkable area of the heightfield away from /// obstructions. [Limit: >=0] [Units: vx] /// public int WalkableRadius; /// /// The maximum allowed length for contour edges along the border of the mesh. [Limit: >=0] [Units: vx] /// public int MaxEdgeLen; /// /// The maximum distance a simplified contour's border edges should deviate /// the original raw contour. [Limit: >=0] [Units: vx] /// public float MaxSimplificationError; /// /// The minimum number of cells allowed to form isolated island areas. [Limit: >=0] [Units: vx] /// public int MinRegionArea; /// /// Any regions with a span count smaller than this value will, if possible, /// be merged with larger regions. [Limit: >=0] [Units: vx] /// public int MergeRegionArea; /// /// The maximum number of vertices allowed for polygons generated during the /// contour to polygon conversion process. [Limit: >= 3] /// public int MaxVertsPerPoly; };