OpenRA/OpenRA · error · MapGenerationException

Could not fit tiles for sand-sand cliffs

Error message

Could not fit tiles for sand-sand cliffs

What it means

Thrown when PathTile.Tile(sandSandCliffTilingRandom) returns null while tiling the sand-sand cliff contours. Tile returns null when the SegmentedBrushes-based tiling cannot fit the brush pieces along a contour loop after OptimizeLoop/ExtendEdge/SetAutoEndDeviation. This is a MapGenerationException specific to the sand-cliff generation branch (param.SandCliffs > 0).

Source

Thrown at OpenRA.Mods.D2k/Traits/World/D2kMapGenerator.cs:343

					param.SmoothingThreshold, /*smoothingThresholdOutOf=*/FractionMax,
					param.MinimumSandCliffThickness,
					false);
				var contours = MatrixUtils.BordersToPoints(plan);
				var partitionMask = cliffMask.Map(masked => masked ? sandSandCliffZone : sandZone);
				var tilingPaths = terraformer.PartitionPaths(
					contours,
					[sandSandCliffZone, sandZone],
					partitionMask,
					param.SegmentedBrushes,
					param.MinimumSandCliffStraight);
				foreach (var tilingPath in tilingPaths)
				{
					var brush = tilingPath
						.OptimizeLoop()
						.ExtendEdge(4)
						.SetAutoEndDeviation()
						.Tile(sandSandCliffTilingRandom)
							?? throw new MapGenerationException("Could not fit tiles for sand-sand cliffs");
					terraformer.PaintTiling(pickAnyRandom, brush);
				}
			}

			// Sand Detail
			if (param.SandDetail > 0)
			{
				var space = terraformer.CheckSpace(param.PlayableTerrain);
				var passages = terraformer.PlanPassages(
					topologyRandom,
					terraformer.ImproveSymmetry(space, true, (a, b) => a && b),
					param.SandDetailCutout,
					param.MaximumSandDetailCutoutSpacing);
				var plan = terraformer.BooleanNoise(
					sandDetailRandom,
					param.SandDetailFeatureSize,
					param.SandDetail,
					param.SandDetailClumpiness);

View on GitHub (pinned to a520984d91)

Solutions

  1. Reduce param.SandCliffs or relax MinimumSandCliffStraight so contours need fewer straight pieces.
  2. Enlarge the map so cliff contours are longer and smoother.
  3. Retry with a different seed to get more tileable contours.
  4. Ensure the SegmentedBrushes set includes all required straight and corner segments for the sand-sand cliff zone.
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check cliff brush segment availability against minimum straight requirement
if (param.SandCliffs > 0 &&
    param.SegmentedBrushes.Brushes.Count(b => b.IsStraight) < param.MinimumSandCliffStraight)
    throw new MapGenerationException("SegmentedBrushes lack enough straight segments.");

Try / catch

for (int attempt = 0; attempt < 8; attempt++)
{
    try { return generator.Generate(modData, args.WithSeed(baseSeed + attempt)); }
    catch (MapGenerationException) when (attempt < 7) { }
}
throw new MapGenerationException("Sand cliff tiling failed after retries.");

Prevention

When it happens

Trigger: The sand cliff branch runs: contours are sliced into tilingPaths, each path is optimized and tiled with sand-sand cliff brushes (param.SegmentedBrushes); if any single path cannot be tiled, the ?? throws.

Common situations: SandCliffs parameter set high relative to map size; segmented cliff brushes with insufficient straight-segment pieces to satisfy MinimumSandCliffStraight; a contour that is too jagged for the available brush set; modded cliff templates missing required segments.

Related errors


AI-assisted analysis of OpenRA/OpenRA@a520984d91 (2026-08-13). Data as JSON: /api/errors/91de5e2ec17c3ba1. Report an issue: GitHub.