islaApocalypse/Core/Scripts/ChunkData.cs
beezm f9ea2da3f4 roads: enable Rugged+Trail carving + per-tier character (D-022)
All four road tiers now carve into the 3D world. Rugged and Trail were
generated, exported and parsed all along, but nothing ever consumed them —
which is why county roads visible on the 2D map did not exist in 3D.

Tier identity is now carried into the carve via a RoadSegment struct, so each
tier gets its own width, shoulder and grade-smoothing from one tunable block in
Constants: highways widest and holding a grade, trails narrow and hugging the
land. Rugged and Trail surface as dirt rather than asphalt.

Because tiers now have different reach, nearest-by-distance was no longer a
sound way to pick the governing road — a nearby footpath could shadow a highway
whose shoulder still covered the column. The carve now considers only roads
whose shoulder actually reaches, and takes the closest of those.

The per-chunk cull pad is derived from the widest shoulder plus a margin, so
widening a road cannot silently truncate it at chunk edges.

Untouched: density field, Marching Cubes interpolation/welding, chunk dims,
the .dat contract, the 2D A* generation, and mesher normals.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 03:53:32 -04:00

49 lines
2.4 KiB
C#

using Godot;
namespace IslaApocalypse.Core
{
public class ChunkData
{
public Vector2I ChunkPosition; // The X/Z coordinate of this chunk (e.g., 0,0 or 1,0)
// We need Width+1 and Depth+1 so the Marching Cubes mesh connects seamlessly to the neighbor chunks!
// public float[,,] Densities = new float[Constants.CHUNK_SIZE_X + 1, Constants.CHUNK_HEIGHT, Constants.CHUNK_SIZE_Z + 1];
// public byte[,,] BlockIDs = new byte[Constants.CHUNK_SIZE_X + 1, Constants.CHUNK_HEIGHT, Constants.CHUNK_SIZE_Z + 1];
// OLD:
// Densities = new float[Constants.CHUNK_SIZE_X, Constants.CHUNK_HEIGHT, Constants.CHUNK_SIZE_Z];
// BlockIDs = new int[Constants.CHUNK_SIZE_X, Constants.CHUNK_HEIGHT, Constants.CHUNK_SIZE_Z];
// NEW (Fix 3): We expand by 1 to sample the neighbor's border perfectly without seams!
public float[,,] Densities = new float[Constants.CHUNK_SIZE_X + 1, Constants.CHUNK_HEIGHT + 1, Constants.CHUNK_SIZE_Z + 1];
public byte[,,] BlockIDs = new byte[Constants.CHUNK_SIZE_X + 1, Constants.CHUNK_HEIGHT + 1, Constants.CHUNK_SIZE_Z + 1];
// --- PER-COLUMN DATA, FOR VERTEX COLOURING ONLY ----------------------
// One entry per X/Z column of this chunk (same +1 padding as above).
//
// Why these exist: BlockIDs are classified against a ROUNDED surface
// height, which is fine for storage but makes the rendered colour jump
// in whole-metre steps (the "contour band" artefact). The renderer
// instead reads the TRUE, unrounded surface height from here, so the
// material fade follows the real ground.
//
// These are read by the mesher only. Nothing about geometry, collision
// or storage depends on them.
public float[,] SurfaceHeights = new float[Constants.CHUNK_SIZE_X + 1, Constants.CHUNK_SIZE_Z + 1];
public Biome[,] ColumnBiomes = new Biome[Constants.CHUNK_SIZE_X + 1, Constants.CHUNK_SIZE_Z + 1];
// What this column's road surface is paved with — asphalt for highways,
// dirt for trails, and 0 (BlockRegistry.AIR) for "not a road at all".
// Carries the tier's material rather than a plain yes/no, so a footpath
// doesn't get painted like a motorway.
public byte[,] ColumnRoadMaterial = new byte[Constants.CHUNK_SIZE_X + 1, Constants.CHUNK_SIZE_Z + 1];
// For our future delta-save system
public bool IsPlayerProtected = false;
public bool NeedsSaving = false;
public ChunkData(Vector2I position)
{
ChunkPosition = position;
}
}
}