using System.Collections.Generic; using UnityEngine; namespace Game.WorldGen { public enum IslandShape { Radial, Square } /// /// All parameters for one world. Stored as an asset so you can version several /// presets (test island, final island, flat playground, ...) side by side. /// [CreateAssetMenu(fileName = "WorldGenSettings", menuName = "Game/World Gen Settings")] public class WorldGenSettings : ScriptableObject { [Header("Output")] [Tooltip("Name of the root GameObject that will hold all terrain tiles.")] public string worldRootName = "GeneratedWorld"; [Tooltip("Project folder where TerrainData + shared material assets are saved.")] public string outputFolder = "Assets/GAME/World/Generated"; [Header("World layout")] public int seed = 12345; [Tooltip("World edge length in meters (square). 6000 = 6 km like ARK: The Island.")] public float worldSizeMeters = 6000f; [Tooltip("Tiles per side. 6 -> 36 tiles of 1 km.")] [Range(1, 16)] public int tilesPerSide = 6; [Tooltip("Heightmap resolution per tile. Must be 2^n + 1 (513 / 1025 / 2049 / 4097).")] public int heightmapResolution = 1025; [Tooltip("Max terrain height in meters (the terrain's Y size).")] public float maxHeightMeters = 1000f; [Tooltip("Reference sea level as a height fraction. Used for the water plane + splat rules.")] [Range(0f, 1f)] public float seaLevel01 = 0.30f; [Header("Base terrain noise")] [Tooltip("Approx size of the largest land features, in meters.")] public float baseFeatureSizeMeters = 1500f; [Range(1, 10)] public int baseOctaves = 6; [Range(1.5f, 3f)] public float lacunarity = 2f; [Range(0.2f, 0.8f)] public float gain = 0.5f; [Tooltip("Remaps the raw [0,1] base height -> lets you flatten lowlands or sharpen peaks.")] public AnimationCurve heightCurve = AnimationCurve.Linear(0, 0, 1, 1); [Header("Domain warp (organic, less grid-like coastlines)")] public bool domainWarp = true; [Range(0f, 1f)] public float warpStrength = 0.35f; [Header("Procedural mountains (ridged)")] [Range(0f, 1f), Tooltip("How strongly ridged mountains rise above the base.")] public float mountainAmplitude = 0.55f; public float mountainFeatureSizeMeters = 2200f; [Range(1, 8)] public int mountainOctaves = 5; [Tooltip("Size of the regions where mountains are allowed to appear.")] public float mountainMaskFeatureSizeMeters = 3500f; [Range(0f, 1f), Tooltip("Higher = mountains confined to fewer, tighter ranges.")] public float mountainThreshold = 0.55f; [Header("Island falloff")] public bool island = true; public IslandShape islandShape = IslandShape.Radial; [Tooltip("Maps normalised distance-from-center (0..1) to a height multiplier (1 center -> 0 edge).")] public AnimationCurve falloffCurve = new AnimationCurve( new Keyframe(0f, 1f), new Keyframe(0.55f, 1f), new Keyframe(1f, 0f)); [Header("Hand-placed features")] public List features = new List(); [Header("Auto texturing by height (optional)")] [Tooltip("Enable height/slope based auto texturing at bake (and via the Apply button).")] public bool autoTexture = false; [Tooltip("Alphamap (splatmap) resolution per tile. Higher = smoother blends but more VRAM.")] public int alphamapResolution = 1024; [Tooltip("Height/slope bands, painted bottom-to-top. Heights are in world meters.")] public List splatRules = new List(); [Header("Detail / grass painting")] [Tooltip("Grid resolution for painted details (grass meshes). 0 = details disabled. " + "1024 over a 1 km tile ≈ 1 detail cell/m. Must be a multiple of 'per patch'.")] public int detailResolution = 1024; [Tooltip("Detail cells per patch. detailResolution / this = number of patches per axis.")] [Range(8, 128)] public int detailResolutionPerPatch = 32; [Header("Terrain quality")] [Range(1f, 50f)] public float heightmapPixelError = 5f; public float basemapDistance = 1000f; public bool drawInstanced = true; void Reset() { heightCurve = AnimationCurve.Linear(0, 0, 1, 1); falloffCurve = new AnimationCurve( new Keyframe(0f, 1f), new Keyframe(0.55f, 1f), new Keyframe(1f, 0f)); } /// Validates / repairs values; returns false with a reason if unusable. public bool Validate(out string error) { error = null; if (tilesPerSide < 1) { error = "tilesPerSide must be >= 1."; return false; } if (worldSizeMeters <= 0f) { error = "worldSizeMeters must be > 0."; return false; } if (!IsPowerOfTwoPlusOne(heightmapResolution)) { error = $"heightmapResolution ({heightmapResolution}) must be 2^n + 1 (e.g. 513, 1025, 2049, 4097)."; return false; } if (string.IsNullOrWhiteSpace(outputFolder) || !outputFolder.StartsWith("Assets")) { error = "outputFolder must be a project path starting with 'Assets'."; return false; } return true; } public static bool IsPowerOfTwoPlusOne(int v) { int n = v - 1; return n >= 32 && (n & (n - 1)) == 0; } } }