Compare commits

...

11 Commits

Author SHA1 Message Date
MC-Worldgen Dev
0a06f34d99 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>
2026-07-11 20:33:21 +00:00
root
e2436f6e24 Improve roads, cabins, forests, and woodland communities 2026-07-11 20:00:19 +00:00
chelsea
afbf333622 Add subtle island terrain relief 2026-05-03 11:58:59 -05:00
chelsea
acd5eaa52f Add dry sand patches near beaches 2026-05-03 11:53:07 -05:00
chelsea
84a0435312 Place wall stairs above walkway surface 2026-05-03 11:39:35 -05:00
chelsea
46f1d24e9d Add stair ramps to border wall walks 2026-05-03 11:32:22 -05:00
chelsea
aed76c3b1b Add dead sequoias and align tower walks 2026-05-03 01:22:38 -05:00
chelsea
95bd106a3b Fix generated map integrity and wall access 2026-05-02 23:48:35 -05:00
chelsea
127e706bcb Fix wall rails and water biomes 2026-05-02 23:23:29 -05:00
chelsea
335b35d416 Add plant and aquatic variety 2026-05-02 23:18:00 -05:00
chelsea
d0f3c9a048 Address border wall issue reports 2026-05-02 21:54:12 -05:00
6 changed files with 799 additions and 135 deletions

View File

@@ -74,11 +74,30 @@ Features
- Redwoods are enabled automatically. The biome classifier marks high-rainfall, - Redwoods are enabled automatically. The biome classifier marks high-rainfall,
higher-relief areas as redwood forest, then places titan trees, dirt/mulch higher-relief areas as redwood forest, then places titan trees, dirt/mulch
floor cover, tall grass, and occasional fallen logs. floor cover, tall grass, and occasional fallen logs.
- General forests grow as broad, coherent oak, maple, birch, pine, spruce,
walnut, and cypress stands with occasional companion species. Seeded
clearings, sparse field trees, regenerating edges, mature interiors, variable
tree height, and irregular crown spacing keep the distribution from resolving
into a uniform grid.
- Cabins are enabled automatically. With `--trails`, cabins only try to spawn on - Cabins are enabled automatically. With `--trails`, cabins only try to spawn on
chunks crossed by the trail network so their spur paths can connect to roads. chunks crossed by the trail network so their spur paths can connect to roads.
Without `--trails`, cabins can still spawn, but they are rarer and unconnected. Without `--trails`, cabins can still spawn, but they are rarer and unconnected.
- Cabin generation includes compact homesteads, longhouses, two-story houses,
L-shaped cabins, cross-gabled lodges, mixed-height tower lodges, and rambling
multi-wing cabins. Roof direction, wing height, material palette, windows,
porches, chimneys, decay, and path width vary by design.
- Seeded woodland-community regions raise the local cabin frequency and give
their roads permission to bridge narrowly bounded water at exact sea level.
Eligible crossings must have nearby dry banks on both sides; deep water,
broad lakes, and open ocean remain impassable. Bridges use raised spruce
decks, timber supports, and intermittent edge posts rather than gravel fill.
- Trails are optional because they need a prepass over the target area. Use - Trails are optional because they need a prepass over the target area. Use
`--trails` when you want roads and better-connected cabins. `--trails` when you want roads and better-connected cabins.
- Long roads search a broad terrain corridor and prefer valley floors, gentle
contour-following grades, low ridge crossings, and stable side slopes. Deep
water remains impassable; shallow water is crossed only when the detour cost
is greater, keeping fords and causeways short. Short cabin spurs use looser
engineering constraints so they can still reach the main network.
Minecraft Version Minecraft Version
----------------- -----------------

Binary file not shown.

View File

@@ -61,7 +61,19 @@
BLOCK_STONE_BRICK_STAIRS_E = 48, BLOCK_STONE_BRICK_STAIRS_E = 48,
BLOCK_STONE_BRICK_STAIRS_W = 49, BLOCK_STONE_BRICK_STAIRS_W = 49,
BLOCK_STONE_BRICK_STAIRS_N = 50, BLOCK_STONE_BRICK_STAIRS_N = 50,
BLOCK_STONE_BRICK_STAIRS_S = 51 BLOCK_STONE_BRICK_STAIRS_S = 51,
BLOCK_DANDELION = 52,
BLOCK_AZURE_BLUET = 53,
BLOCK_OXEYE_DAISY = 54,
BLOCK_CORNFLOWER = 55,
BLOCK_LILY_OF_THE_VALLEY = 56,
BLOCK_FERN = 57,
BLOCK_CLAY = 58,
BLOCK_SEAGRASS = 59,
BLOCK_IRON_BARS_NS = 60,
BLOCK_IRON_BARS_EW = 61,
BLOCK_SPRUCE_STAIRS_N = 62,
BLOCK_SPRUCE_STAIRS_S = 63
}; };
struct trail_segment; struct trail_segment;
@@ -102,5 +114,7 @@ void worldgen_prepass(worldgen_ctx *ctx, int min_x, int max_x, int min_z, int ma
void worldgen_free_trails(worldgen_ctx *ctx); void worldgen_free_trails(worldgen_ctx *ctx);
int worldgen_debug_biome(worldgen_ctx *ctx, int x, int z); int worldgen_debug_biome(worldgen_ctx *ctx, int x, int z);
double worldgen_debug_redwood_mask(worldgen_ctx *ctx, int x, int z); double worldgen_debug_redwood_mask(worldgen_ctx *ctx, int x, int z);
double worldgen_debug_community_strength(worldgen_ctx *ctx, int x, int z);
int worldgen_debug_bridge_site(worldgen_ctx *ctx, int x, int z, int dir_x, int dir_z);
#endif #endif

View File

@@ -100,6 +100,8 @@ static const kv_pair PROPS_LADDER_N[] = {{"facing", "north"}, {"waterlogged", "f
static const kv_pair PROPS_LADDER_S[] = {{"facing", "south"}, {"waterlogged", "false"}}; static const kv_pair PROPS_LADDER_S[] = {{"facing", "south"}, {"waterlogged", "false"}};
static const kv_pair PROPS_LADDER_W[] = {{"facing", "west"}, {"waterlogged", "false"}}; static const kv_pair PROPS_LADDER_W[] = {{"facing", "west"}, {"waterlogged", "false"}};
static const kv_pair PROPS_LADDER_E[] = {{"facing", "east"}, {"waterlogged", "false"}}; static const kv_pair PROPS_LADDER_E[] = {{"facing", "east"}, {"waterlogged", "false"}};
static const kv_pair PROPS_IRON_BARS_NS[] = {{"east", "false"}, {"north", "true"}, {"south", "true"}, {"waterlogged", "false"}, {"west", "false"}};
static const kv_pair PROPS_IRON_BARS_EW[] = {{"east", "true"}, {"north", "false"}, {"south", "false"}, {"waterlogged", "false"}, {"west", "true"}};
static const size_t BLOCK_STATE_CAP = 256; static const size_t BLOCK_STATE_CAP = 256;
static const int32_t DATA_VERSION = 2730; /* Java Edition 1.17.1; includes copper ore. */ static const int32_t DATA_VERSION = 2730; /* Java Edition 1.17.1; includes copper ore. */
static const block_state BLOCK_STATE_TABLE[] = { static const block_state BLOCK_STATE_TABLE[] = {
@@ -154,7 +156,19 @@ static const block_state BLOCK_STATE_TABLE[] = {
[BLOCK_STONE_BRICK_STAIRS_E] = {"minecraft:stone_brick_stairs", PROPS_STAIRS_E, 4}, [BLOCK_STONE_BRICK_STAIRS_E] = {"minecraft:stone_brick_stairs", PROPS_STAIRS_E, 4},
[BLOCK_STONE_BRICK_STAIRS_W] = {"minecraft:stone_brick_stairs", PROPS_STAIRS_W, 4}, [BLOCK_STONE_BRICK_STAIRS_W] = {"minecraft:stone_brick_stairs", PROPS_STAIRS_W, 4},
[BLOCK_STONE_BRICK_STAIRS_N] = {"minecraft:stone_brick_stairs", PROPS_STAIRS_N, 4}, [BLOCK_STONE_BRICK_STAIRS_N] = {"minecraft:stone_brick_stairs", PROPS_STAIRS_N, 4},
[BLOCK_STONE_BRICK_STAIRS_S] = {"minecraft:stone_brick_stairs", PROPS_STAIRS_S, 4} [BLOCK_STONE_BRICK_STAIRS_S] = {"minecraft:stone_brick_stairs", PROPS_STAIRS_S, 4},
[BLOCK_DANDELION] = {"minecraft:dandelion", NULL, 0},
[BLOCK_AZURE_BLUET] = {"minecraft:azure_bluet", NULL, 0},
[BLOCK_OXEYE_DAISY] = {"minecraft:oxeye_daisy", NULL, 0},
[BLOCK_CORNFLOWER] = {"minecraft:cornflower", NULL, 0},
[BLOCK_LILY_OF_THE_VALLEY] = {"minecraft:lily_of_the_valley", NULL, 0},
[BLOCK_FERN] = {"minecraft:fern", NULL, 0},
[BLOCK_CLAY] = {"minecraft:clay", NULL, 0},
[BLOCK_SEAGRASS] = {"minecraft:seagrass", NULL, 0},
[BLOCK_IRON_BARS_NS] = {"minecraft:iron_bars", PROPS_IRON_BARS_NS, 5},
[BLOCK_IRON_BARS_EW] = {"minecraft:iron_bars", PROPS_IRON_BARS_EW, 5},
[BLOCK_SPRUCE_STAIRS_N] = {"minecraft:spruce_stairs", PROPS_STAIRS_N, 4},
[BLOCK_SPRUCE_STAIRS_S] = {"minecraft:spruce_stairs", PROPS_STAIRS_S, 4}
}; };
static const block_state *get_block_state(uint16_t id) { static const block_state *get_block_state(uint16_t id) {
@@ -308,18 +322,18 @@ static int64_t to_signed64(uint64_t v) {
static void pack_bits(const uint16_t *indices, size_t count, int bits_per_value, int64_t *out_longs, size_t out_count) { static void pack_bits(const uint16_t *indices, size_t count, int bits_per_value, int64_t *out_longs, size_t out_count) {
memset(out_longs, 0, out_count * sizeof(int64_t)); memset(out_longs, 0, out_count * sizeof(int64_t));
int values_per_long = 64 / bits_per_value;
if (values_per_long < 1) values_per_long = 1;
for (size_t idx = 0; idx < count; ++idx) { for (size_t idx = 0; idx < count; ++idx) {
uint64_t value = indices[idx]; uint64_t value = indices[idx];
size_t bit_index = idx * (size_t)bits_per_value; size_t long_id = idx / (size_t)values_per_long;
size_t long_id = bit_index / 64; size_t offset = (idx % (size_t)values_per_long) * (size_t)bits_per_value;
size_t offset = bit_index % 64; if (long_id >= out_count) continue;
uint64_t *target = (uint64_t *)&out_longs[long_id]; uint64_t *target = (uint64_t *)&out_longs[long_id];
*target |= value << offset; *target |= value << offset;
int spill = (int)(offset + bits_per_value - 64);
if (spill > 0 && long_id + 1 < out_count) {
uint64_t *next = (uint64_t *)&out_longs[long_id + 1];
*next |= value >> (bits_per_value - spill);
} }
for (size_t i = 0; i < out_count; ++i) {
out_longs[i] = to_signed64((uint64_t)out_longs[i]);
} }
} }
@@ -345,6 +359,13 @@ static void pack_heightmap(const chunk_data *chunk, int64_t *out_longs, size_t o
} }
} }
static int column_contains_water(const chunk_data *chunk, int x, int z) {
for (int y = 1; y < CHUNK_HEIGHT; ++y) {
if (chunk->blocks[y][x][z] == BLOCK_WATER) return 1;
}
return 0;
}
static int section_has_blocks(const chunk_data *chunk, int section_y) { static int section_has_blocks(const chunk_data *chunk, int section_y) {
int y_base = section_y * 16; int y_base = section_y * 16;
for (int y = 0; y < 16; ++y) { for (int y = 0; y < 16; ++y) {
@@ -406,7 +427,9 @@ static void write_section(buf *b, const chunk_data *chunk, int section_y) {
int needed = (int)ceil(log2((double)palette_len)); int needed = (int)ceil(log2((double)palette_len));
if (needed > bits) bits = needed; if (needed > bits) bits = needed;
} }
size_t packed_count = ((size_t)idx * (size_t)bits + 63) / 64; size_t values_per_long = (size_t)(64 / bits);
if (values_per_long < 1) values_per_long = 1;
size_t packed_count = ((size_t)idx + values_per_long - 1) / values_per_long;
int64_t *packed = (int64_t *)calloc(packed_count, sizeof(int64_t)); int64_t *packed = (int64_t *)calloc(packed_count, sizeof(int64_t));
if (!packed) return; if (!packed) return;
pack_bits(block_indices, idx, bits, packed, packed_count); pack_bits(block_indices, idx, bits, packed, packed_count);
@@ -436,7 +459,11 @@ static void write_section(buf *b, const chunk_data *chunk, int section_y) {
static void build_chunk_nbt(const chunk_data *chunk, buf *out) { static void build_chunk_nbt(const chunk_data *chunk, buf *out) {
int32_t biomes[256]; int32_t biomes[256];
for (int i = 0; i < 256; ++i) biomes[i] = 1; // Plains biome for (int z = 0; z < CHUNK_SIZE; ++z) {
for (int x = 0; x < CHUNK_SIZE; ++x) {
biomes[z * CHUNK_SIZE + x] = column_contains_water(chunk, x, z) ? 0 : 1; // Ocean or plains
}
}
int64_t heightmap[37]; int64_t heightmap[37];
pack_heightmap(chunk, heightmap, 37); pack_heightmap(chunk, heightmap, 37);

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@ static int is_cabin_block(uint16_t block) {
block == BLOCK_OAK_LOG_X || block == BLOCK_OAK_LOG_Z || block == BLOCK_OAK_LOG_X || block == BLOCK_OAK_LOG_Z ||
block == BLOCK_SPRUCE_LOG_X || block == BLOCK_SPRUCE_LOG_Z || block == BLOCK_SPRUCE_LOG_X || block == BLOCK_SPRUCE_LOG_Z ||
block == BLOCK_GLASS_PANE || block == BLOCK_GLASS || block == BLOCK_SPRUCE_STAIRS_E || block == BLOCK_SPRUCE_STAIRS_W || block == BLOCK_GLASS_PANE || block == BLOCK_GLASS || block == BLOCK_SPRUCE_STAIRS_E || block == BLOCK_SPRUCE_STAIRS_W ||
block == BLOCK_SPRUCE_STAIRS_N || block == BLOCK_SPRUCE_STAIRS_S ||
block == BLOCK_LADDER_N || block == BLOCK_LADDER_S || block == BLOCK_LADDER_E || block == BLOCK_LADDER_W || block == BLOCK_LADDER_N || block == BLOCK_LADDER_S || block == BLOCK_LADDER_E || block == BLOCK_LADDER_W ||
block == BLOCK_SPRUCE_DOOR_N_LOWER || block == BLOCK_SPRUCE_DOOR_N_UPPER || block == BLOCK_SPRUCE_DOOR_N_LOWER || block == BLOCK_SPRUCE_DOOR_N_UPPER ||
block == BLOCK_SPRUCE_DOOR_S_LOWER || block == BLOCK_SPRUCE_DOOR_S_UPPER || block == BLOCK_SPRUCE_DOOR_S_LOWER || block == BLOCK_SPRUCE_DOOR_S_UPPER ||
@@ -78,6 +79,8 @@ int main(int argc, char **argv) {
long cabin_columns = 0; long cabin_columns = 0;
long gravel_columns = 0; long gravel_columns = 0;
long cabin_gravel_columns = 0; long cabin_gravel_columns = 0;
long bridge_deck_columns = 0;
long eligible_bridge_columns = 0;
long tall_log_columns = 0; long tall_log_columns = 0;
long max_oak_log_run = 0; long max_oak_log_run = 0;
long biome_columns[4] = {0, 0, 0, 0}; long biome_columns[4] = {0, 0, 0, 0};
@@ -96,8 +99,11 @@ int main(int argc, char **argv) {
if (biome >= 0 && biome < 4) ++biome_columns[biome]; if (biome >= 0 && biome < 4) ++biome_columns[biome];
double redwood_mask = worldgen_debug_redwood_mask(&ctx, wx, wz); double redwood_mask = worldgen_debug_redwood_mask(&ctx, wx, wz);
if (redwood_mask > max_redwood_mask) max_redwood_mask = redwood_mask; if (redwood_mask > max_redwood_mask) max_redwood_mask = redwood_mask;
if (worldgen_debug_bridge_site(&ctx, wx, wz, 1, 0) ||
worldgen_debug_bridge_site(&ctx, wx, wz, 0, 1)) ++eligible_bridge_columns;
int has_cabin = 0; int has_cabin = 0;
int has_gravel = 0; int has_gravel = 0;
int has_bridge_deck = 0;
int current_run = 0; int current_run = 0;
int best_run = 0; int best_run = 0;
for (int y = 1; y < CHUNK_HEIGHT; ++y) { for (int y = 1; y < CHUNK_HEIGHT; ++y) {
@@ -109,6 +115,8 @@ int main(int argc, char **argv) {
if (block == BLOCK_GRAVEL) { if (block == BLOCK_GRAVEL) {
has_gravel = 1; has_gravel = 1;
} }
if (block == BLOCK_SPRUCE_PLANKS && y > 1 && chunk.blocks[y - 1][lx][lz] == BLOCK_WATER)
has_bridge_deck = 1;
if (block == BLOCK_OAK_LOG) { if (block == BLOCK_OAK_LOG) {
++current_run; ++current_run;
if (current_run > best_run) best_run = current_run; if (current_run > best_run) best_run = current_run;
@@ -120,6 +128,7 @@ int main(int argc, char **argv) {
if (best_run >= 40) ++tall_log_columns; if (best_run >= 40) ++tall_log_columns;
if (has_cabin) ++cabin_columns; if (has_cabin) ++cabin_columns;
if (has_gravel) ++gravel_columns; if (has_gravel) ++gravel_columns;
if (has_bridge_deck) ++bridge_deck_columns;
if (has_cabin && has_gravel) { if (has_cabin && has_gravel) {
++cabin_gravel_columns; ++cabin_gravel_columns;
} }
@@ -133,6 +142,8 @@ int main(int argc, char **argv) {
printf("cabin_columns=%ld\n", cabin_columns); printf("cabin_columns=%ld\n", cabin_columns);
printf("gravel_columns=%ld\n", gravel_columns); printf("gravel_columns=%ld\n", gravel_columns);
printf("cabin_gravel_columns=%ld\n", cabin_gravel_columns); printf("cabin_gravel_columns=%ld\n", cabin_gravel_columns);
printf("bridge_deck_columns=%ld\n", bridge_deck_columns);
printf("eligible_bridge_columns=%ld\n", eligible_bridge_columns);
printf("tall_oak_log_columns=%ld\n", tall_log_columns); printf("tall_oak_log_columns=%ld\n", tall_log_columns);
printf("max_oak_log_run=%ld\n", max_oak_log_run); printf("max_oak_log_run=%ld\n", max_oak_log_run);
printf("biome_west_ky=%ld\n", biome_columns[0]); printf("biome_west_ky=%ld\n", biome_columns[0]);