namespace IslaApocalypse.Core { /// /// A row in the TERRAIN material schema — what the natural world is made of. /// → `Design - Data - Material Schema.md` §1, D-054. /// /// PROPERTIES-FROM-TYPE: a column run stores only a . Every property /// lives here and is reached by registry lookup. Nothing is ever stored per-run. /// → `Design - Data - Column Model.md`. /// /// ⚠ THERE IS NO MESH-STYLE FIELD ON THIS ROW, AND THERE MUST NEVER BE ONE. /// Mesh style is per-ORIGIN, not per-material: natural terrain meshes smooth, player-placed /// blocks mesh as cubes, and the same material can be both. The origin flag lives on the run /// (), which is where the mesher reads it. /// → D-054 open notes ("material does not override mesh style"), `Design - Rendering - Mesher.md`. /// /// APPEND-ONLY. Adding a material is one new row in — never a /// code change anywhere else. No material logic is hardcoded anywhere. /// public sealed class TerrainMaterial { /// Identity. A registry key, not an ordinal. → . public MaterialKey Key { get; } /// Human-facing name. Presentation only — never an identity, never a lookup key. public string DisplayName { get; } /// Mining difficulty. Units deliberately unfixed this phase; relative for now. public float Hardness { get; } /// /// What a mined voxel gives. SEAM: the resource/item schema is deferred, so this currently /// names a material key. When resources become their own schema this becomes a resource key /// — one field's type, not a redesign. /// public MaterialKey YieldKey { get; } /// How much one mined voxel gives. public int YieldPerVoxel { get; } /// /// How much structural support this material carries as NATURAL terrain. /// Consumed by `Design - Systems - Structural Integrity.md` (stability scalar, D-055). /// Natural terrain is a LAZY anchor there — this is the value it anchors with. /// public float NaturalSupportStrength { get; } /// /// Runtime-only dense index, assigned by the registry in registration order. /// /// ⚠⚠ NEVER SERIALIZE THIS. NEVER SEND IT OVER A WIRE. NEVER STORE IT IN A BLUEPRINT. /// It exists solely so hot loops can index dense arrays instead of hashing strings. It /// changes whenever registration order changes — which a mod adding a row will do. The /// identity that persists is , always. /// public int RuntimeIndex { get; internal set; } = -1; public TerrainMaterial( MaterialKey key, string displayName, float hardness, MaterialKey yieldKey, int yieldPerVoxel, float naturalSupportStrength) { Key = key; DisplayName = displayName; Hardness = hardness; YieldKey = yieldKey; YieldPerVoxel = yieldPerVoxel; NaturalSupportStrength = naturalSupportStrength; } public override string ToString() => $"TerrainMaterial({Key})"; } }