Tune tree density/spacing and fix trail distance to use segments

- nearest_trail_distance2 now measures point-to-segment distance to each
  trail edge instead of only to stored points, with a single-point fallback.
- Tree height scaling keeps canopy proportions; maturity adds subtle
  variation instead of shrinking young trees to bare poles.
- Raise forest spawn probability and tighten spacing for denser, more
  coherent stands; redwoods cluster a bit closer.
- Cabins near trails favor a wooded setback off the centerline; the spur
  still connects.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
MC-Worldgen Dev
2026-07-11 20:33:21 +00:00
parent e2436f6e24
commit 0a06f34d99
2 changed files with 19 additions and 13 deletions

Binary file not shown.

View File

@@ -2000,7 +2000,9 @@ static void generate_tree(worldgen_ctx *ctx, const tree_archetype *arch, int x,
double maturity, rng_state *rng, block_list *out) {
if (!arch) return;
int height = rng_range_inclusive(rng, arch->min_height, arch->max_height);
double height_scale = 0.62 + clamp01(maturity) * 0.38;
/* Preserve the proportions expected by each canopy builder; maturity now
* adds subtle height variation without reducing young trees to bare poles. */
double height_scale = 0.86 + clamp01(maturity) * 0.14;
height = (int)llround((double)height * height_scale);
if (height < 4) height = 4;
if (!can_place_tree(ctx, x, y, z, height, arch->space_radius, arch->canopy_extra)) {
@@ -2972,10 +2974,10 @@ static void generate_chunk_cabins(worldgen_ctx *ctx, int chunk_x, int chunk_z, c
double dist2 = nearest_trail_distance2(ctx, world_cx, world_cz, 1.0e12);
double bonus = 0.0;
double dist = sqrt(dist2);
if (dist < 640.0) {
double t = clamp01(1.0 - dist / 640.0);
bonus += 0.45 * t;
}
/* Favor a wooded setback instead of putting the building footprint
* directly on the centerline. The spur still handles the connection. */
if (dist < 8.0) bonus -= (8.0 - dist) * 0.9;
else if (dist < 96.0) bonus += 0.45 * clamp01(1.0 - fabs(dist - 20.0) / 76.0);
score += bonus;
}
if (score > best_score) {
@@ -3304,14 +3306,14 @@ static void generate_chunk_trees(worldgen_ctx *ctx, int chunk_x, int chunk_z, ch
}
/* Openings retain a few isolated field trees, while forest interiors
* become substantially denser than their regenerating edges. */
spawn_prob = (0.035 + density * 0.78) * altitude_factor;
spawn_prob = (0.08 + density * 0.9) * altitude_factor;
if (is_old_growth) {
spawn_prob = clamp01(0.25 + grove_mask * 0.7) * altitude_factor;
}
}
if (rng_next_f64(&rng) > spawn_prob) continue;
double spacing = is_redwood ? (10.0 + (1.0 - stand_density) * 4.0)
: (4.5 + (1.0 - cover) * 4.5 + maturity * 1.5);
double spacing = is_redwood ? (8.0 + (1.0 - stand_density) * 3.0)
: (3.5 + (1.0 - cover) * 2.5 + maturity * 0.75);
if (!tree_wins_spacing(ctx, gx, gz, grid, candidate_x, candidate_z, spacing)) continue;
block_list tmp;
@@ -3582,11 +3584,15 @@ static double nearest_trail_distance2(worldgen_ctx *ctx, int x, int z, double fa
for (size_t i = 0; i < ctx->trail_segment_count; ++i) {
trail_segment *seg = &ctx->trail_segments[i];
if (!seg || seg->count < 1 || !seg->points) continue;
for (int p = 0; p < seg->count; ++p) {
int tx = seg->points[p * 2];
int tz = seg->points[p * 2 + 1];
double dx = (double)(tx - x);
double dz = (double)(tz - z);
for (int p = 0; p < seg->count - 1; ++p) {
double d2 = point_segment_distance2((double)x, (double)z,
(double)seg->points[p * 2], (double)seg->points[p * 2 + 1],
(double)seg->points[(p + 1) * 2], (double)seg->points[(p + 1) * 2 + 1]);
if (d2 < best) best = d2;
}
if (seg->count == 1) {
double dx = (double)(seg->points[0] - x);
double dz = (double)(seg->points[1] - z);
double d2 = dx * dx + dz * dz;
if (d2 < best) best = d2;
}