diff --git a/worldgen-c/bin/worldgen b/worldgen-c/bin/worldgen index 529d512..20868a8 100755 Binary files a/worldgen-c/bin/worldgen and b/worldgen-c/bin/worldgen differ diff --git a/worldgen-c/include/worldgen.h b/worldgen-c/include/worldgen.h index 2e7c749..dfb3283 100644 --- a/worldgen-c/include/worldgen.h +++ b/worldgen-c/include/worldgen.h @@ -38,20 +38,21 @@ BLOCK_SPRUCE_LOG_X = 26, BLOCK_SPRUCE_LOG_Z = 27, BLOCK_GLASS_PANE = 28, - BLOCK_SPRUCE_DOOR_S_LOWER = 29, - BLOCK_SPRUCE_DOOR_S_UPPER = 30, - BLOCK_SPRUCE_DOOR_N_LOWER = 31, - BLOCK_SPRUCE_DOOR_N_UPPER = 32, - BLOCK_SPRUCE_DOOR_W_LOWER = 33, - BLOCK_SPRUCE_DOOR_W_UPPER = 34, - BLOCK_SPRUCE_DOOR_E_LOWER = 35, - BLOCK_SPRUCE_DOOR_E_UPPER = 36, - BLOCK_SPRUCE_STAIRS_E = 37, - BLOCK_SPRUCE_STAIRS_W = 38, - BLOCK_LADDER_N = 39, - BLOCK_LADDER_S = 40, - BLOCK_LADDER_W = 41, - BLOCK_LADDER_E = 42 + BLOCK_GLASS = 29, + BLOCK_SPRUCE_DOOR_S_LOWER = 30, + BLOCK_SPRUCE_DOOR_S_UPPER = 31, + BLOCK_SPRUCE_DOOR_N_LOWER = 32, + BLOCK_SPRUCE_DOOR_N_UPPER = 33, + BLOCK_SPRUCE_DOOR_W_LOWER = 34, + BLOCK_SPRUCE_DOOR_W_UPPER = 35, + BLOCK_SPRUCE_DOOR_E_LOWER = 36, + BLOCK_SPRUCE_DOOR_E_UPPER = 37, + BLOCK_SPRUCE_STAIRS_E = 38, + BLOCK_SPRUCE_STAIRS_W = 39, + BLOCK_LADDER_N = 40, + BLOCK_LADDER_S = 41, + BLOCK_LADDER_W = 42, + BLOCK_LADDER_E = 43 }; struct trail_segment; diff --git a/worldgen-c/src/main.c b/worldgen-c/src/main.c index e40aea7..cc6fc69 100644 --- a/worldgen-c/src/main.c +++ b/worldgen-c/src/main.c @@ -128,6 +128,7 @@ static const block_state BLOCK_STATE_TABLE[] = { [BLOCK_SPRUCE_LOG_X] = {"minecraft:spruce_log", PROPS_LOG_AXIS_X, 1}, [BLOCK_SPRUCE_LOG_Z] = {"minecraft:spruce_log", PROPS_LOG_AXIS_Z, 1}, [BLOCK_GLASS_PANE] = {"minecraft:glass_pane", NULL, 0}, + [BLOCK_GLASS] = {"minecraft:glass", NULL, 0}, [BLOCK_SPRUCE_DOOR_S_LOWER] = {"minecraft:spruce_door", PROPS_DOOR_S_LOWER, 5}, [BLOCK_SPRUCE_DOOR_S_UPPER] = {"minecraft:spruce_door", PROPS_DOOR_S_UPPER, 5}, [BLOCK_SPRUCE_DOOR_N_LOWER] = {"minecraft:spruce_door", PROPS_DOOR_N_LOWER, 5}, @@ -314,13 +315,19 @@ static void pack_bits(const uint16_t *indices, size_t count, int bits_per_value, // Chunk -> NBT helpers // --------------------------------------------------------------------------- static void pack_heightmap(const chunk_data *chunk, int64_t *out_longs, size_t out_count) { - uint16_t values[CHUNK_SIZE * CHUNK_SIZE]; + memset(out_longs, 0, out_count * sizeof(int64_t)); + const int bits = 9; + const int values_per_long = 64 / bits; for (int z = 0; z < CHUNK_SIZE; ++z) { for (int x = 0; x < CHUNK_SIZE; ++x) { - values[x + z * CHUNK_SIZE] = chunk->heightmap[x][z]; + size_t idx = (size_t)(x + z * CHUNK_SIZE); + size_t long_id = idx / (size_t)values_per_long; + size_t offset = (idx % (size_t)values_per_long) * (size_t)bits; + if (long_id >= out_count) continue; + uint64_t *target = (uint64_t *)&out_longs[long_id]; + *target |= ((uint64_t)chunk->heightmap[x][z] & 0x1FFu) << offset; } } - pack_bits(values, CHUNK_SIZE * CHUNK_SIZE, 9, out_longs, out_count); for (size_t i = 0; i < out_count; ++i) { out_longs[i] = to_signed64((uint64_t)out_longs[i]); } @@ -419,8 +426,8 @@ static void build_chunk_nbt(const chunk_data *chunk, buf *out) { int32_t biomes[256]; for (int i = 0; i < 256; ++i) biomes[i] = 1; // Plains biome - int64_t heightmap[36]; - pack_heightmap(chunk, heightmap, 36); + int64_t heightmap[37]; + pack_heightmap(chunk, heightmap, 37); nbt_start_compound(out, ""); nbt_write_int(out, "DataVersion", DATA_VERSION); @@ -434,7 +441,7 @@ static void build_chunk_nbt(const chunk_data *chunk, buf *out) { nbt_write_byte(out, "isLightOn", 1); nbt_start_compound(out, "Heightmaps"); - nbt_write_long_array(out, "MOTION_BLOCKING", heightmap, 36); + nbt_write_long_array(out, "MOTION_BLOCKING", heightmap, 37); nbt_end_compound(out); nbt_write_int_array(out, "Biomes", biomes, 256); diff --git a/worldgen-c/src/worldgen.c b/worldgen-c/src/worldgen.c index 5cc8347..e1b62de 100644 --- a/worldgen-c/src/worldgen.c +++ b/worldgen-c/src/worldgen.c @@ -426,7 +426,7 @@ static int is_cabin_structure_block(uint16_t block) { return block == BLOCK_SPRUCE_PLANKS || block == BLOCK_OAK_PLANKS || block == BLOCK_OAK_LOG_X || block == BLOCK_OAK_LOG_Z || block == BLOCK_SPRUCE_LOG_X || block == BLOCK_SPRUCE_LOG_Z || - block == BLOCK_GLASS_PANE || 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_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_S_LOWER || block == BLOCK_SPRUCE_DOOR_S_UPPER || @@ -1442,41 +1442,37 @@ static void build_maple_ancient(worldgen_ctx *ctx, int x, int y, int z, int heig static void build_redwood_titan(worldgen_ctx *ctx, int x, int y, int z, int height, rng_state *rng, block_list *out, const tree_archetype *arch) { (void)ctx; - int extra = rng_range_inclusive(rng, 20, 32); - int core_height = height + extra; - if (core_height < 60) core_height = 60; - if (y + core_height + 16 >= CHUNK_HEIGHT) { - core_height = CHUNK_HEIGHT - y - 16; - if (core_height < 40) core_height = 40; + int core_height = height + rng_range_inclusive(rng, 2, 7); + if (core_height < 30) core_height = 30; + if (core_height > 44) core_height = 44; + if (y + core_height + 10 >= CHUNK_HEIGHT) { + core_height = CHUNK_HEIGHT - y - 10; + if (core_height < 24) core_height = 24; } - int taper_start = core_height - 12; + int taper_start = core_height - 6; for (int dy = 0; dy < core_height; ++dy) { - int radius = 3; - if (dy > taper_start) radius = 2; - if (dy > taper_start + 6) radius = 1; + int radius = (dy >= taper_start) ? 0 : 1; for (int dx = -radius; dx <= radius; ++dx) { for (int dz = -radius; dz <= radius; ++dz) { - if (radius >= 3 && abs(dx) == radius && abs(dz) == radius && dy > 4) continue; - if (radius == 2 && abs(dx) == 2 && abs(dz) == 2 && dy > taper_start) continue; block_list_push(out, x + dx, y + dy, z + dz, (uint16_t)arch->log_block); } } } - int spire = 6 + rng_range_inclusive(rng, 0, 3); + int spire = 3 + rng_range_inclusive(rng, 0, 2); place_log_column(x, y + core_height, z, spire, arch->log_block, out); int canopy_base = y + core_height - 6; - for (int ring = 0; ring < 5; ++ring) { - int radius = 6 - ring; + for (int ring = 0; ring < 4; ++ring) { + int radius = 4 - ring; if (radius < 2) radius = 2; place_leaf_circle(x, canopy_base + ring, z, radius, arch->leaf_block, rng, 0.1, out); place_leaf_circle(x, canopy_base + ring + 1, z, radius - 1, arch->leaf_block, rng, 0.18, out); } - place_leaf_circle(x, canopy_base + 6, z, 2, arch->leaf_block, rng, 0.0, out); - place_leaf_circle(x, canopy_base + 7, z, 1, arch->leaf_block, rng, 0.0, out); + place_leaf_circle(x, canopy_base + 5, z, 2, arch->leaf_block, rng, 0.0, out); + place_leaf_circle(x, canopy_base + 6, z, 1, arch->leaf_block, rng, 0.0, out); const int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; for (int i = 0; i < 4; ++i) { - int buttress_height = 4 + rng_range_inclusive(rng, 0, 3); - for (int step = 0; step < 4; ++step) { + int buttress_height = 3 + rng_range_inclusive(rng, 0, 2); + for (int step = 0; step < 2; ++step) { int px = x + dirs[i][0] * (2 + step); int pz = z + dirs[i][1] * (2 + step); int stack = buttress_height - step; @@ -1488,10 +1484,10 @@ static void build_redwood_titan(worldgen_ctx *ctx, int x, int y, int z, int heig } for (int i = 0; i < 4; ++i) { int branch_y = canopy_base - 3 - rng_range_inclusive(rng, 0, 3); - int branch_len = 5 + rng_range_inclusive(rng, 0, 3); - place_branch_span(x, branch_y, z, dirs[i][0], dirs[i][1], branch_len, 3, arch->log_block, arch->leaf_block, rng, out); + int branch_len = 3 + rng_range_inclusive(rng, 0, 2); + place_branch_span(x, branch_y, z, dirs[i][0], dirs[i][1], branch_len, 2, arch->log_block, arch->leaf_block, rng, out); } - place_leaf_blob(x, canopy_base - 2, z, 5, 4, arch->leaf_block, rng, out); + place_leaf_blob(x, canopy_base - 2, z, 4, 3, arch->leaf_block, rng, out); } typedef enum { @@ -1540,7 +1536,7 @@ static void build_redwood_titan(worldgen_ctx *ctx, int x, int y, int z, int heig [TREE_OAK_ANCIENT] = {"oak_ancient", TREE_SPECIES_OAK, BLOCK_OAK_LOG, BLOCK_OAK_LEAVES, 12, 16, 6, 7, build_oak_ancient}, [TREE_SPRUCE_ANCIENT] = {"spruce_ancient", TREE_SPECIES_SPRUCE, BLOCK_OAK_LOG, BLOCK_OAK_LEAVES, 12, 16, 5, 7, build_spruce_ancient}, [TREE_MAPLE_ANCIENT] = {"maple_ancient", TREE_SPECIES_MAPLE, BLOCK_OAK_LOG, BLOCK_OAK_LEAVES, 11, 15, 6, 6, build_maple_ancient}, - [TREE_REDWOOD_TITAN] = {"redwood_titan", TREE_SPECIES_PINE, BLOCK_OAK_LOG, BLOCK_OAK_LEAVES, 70, 86, 7, 24, build_redwood_titan}, + [TREE_REDWOOD_TITAN] = {"redwood_titan", TREE_SPECIES_PINE, BLOCK_OAK_LOG, BLOCK_OAK_LEAVES, 28, 38, 4, 10, build_redwood_titan}, }; static const int TREE_VARIANTS_OAK[] = {TREE_OAK_ROUND, TREE_OAK_SPRAWL, TREE_OAK_COLUMNAR, TREE_OAK_ANCIENT}; @@ -1871,7 +1867,7 @@ static const cabin_blueprint CABIN_BLUEPRINTS[] = { BLOCK_OAK_LOG, BLOCK_SPRUCE_STAIRS_E, BLOCK_SPRUCE_STAIRS_W, - BLOCK_GLASS_PANE, + BLOCK_GLASS, BLOCK_STONE, 0.04, 0.25, @@ -1893,7 +1889,7 @@ static const cabin_blueprint CABIN_BLUEPRINTS[] = { BLOCK_OAK_LOG, BLOCK_SPRUCE_STAIRS_E, BLOCK_SPRUCE_STAIRS_W, - BLOCK_GLASS_PANE, + BLOCK_GLASS, BLOCK_STONE, 0.05, 0.3, @@ -1915,7 +1911,7 @@ static const cabin_blueprint CABIN_BLUEPRINTS[] = { BLOCK_OAK_LOG, BLOCK_SPRUCE_STAIRS_E, BLOCK_SPRUCE_STAIRS_W, - BLOCK_GLASS_PANE, + BLOCK_GLASS, BLOCK_STONE, 0.04, 0.22, @@ -1967,6 +1963,39 @@ static void mark_rect_occupancy(unsigned char occupancy[CHUNK_SIZE][CHUNK_SIZE], } } +static int cabin_site_height_range(const cabin_blueprint *bp, int chunk_origin_x, int chunk_origin_z, + column_data columns[CHUNK_SIZE][CHUNK_SIZE], + int center_x, int center_z, int padding, + int *out_min_h, int *out_max_h) { + int min_h = INT_MAX; + int max_h = INT_MIN; + for (size_t i = 0; i < bp->rect_count; ++i) { + const cabin_rect *rect = &bp->rects[i]; + int rcx = center_x + rect->offset_x; + int rcz = center_z + rect->offset_z; + int x0 = rcx - rect->half_w - padding; + int x1 = rcx + rect->half_w + padding; + int z0 = rcz - rect->half_l - padding; + int z1 = rcz + rect->half_l + padding; + if (x0 < chunk_origin_x || x1 >= chunk_origin_x + CHUNK_SIZE) return 0; + if (z0 < chunk_origin_z || z1 >= chunk_origin_z + CHUNK_SIZE) return 0; + for (int wz = z0; wz <= z1; ++wz) { + for (int wx = x0; wx <= x1; ++wx) { + int lx = wx - chunk_origin_x; + int lz = wz - chunk_origin_z; + column_data col = columns[lx][lz]; + if (col.has_water && col.height < col.water_surface) return 0; + if (col.height < min_h) min_h = col.height; + if (col.height > max_h) max_h = col.height; + } + } + } + if (min_h == INT_MAX) return 0; + *out_min_h = min_h; + *out_max_h = max_h; + return 1; +} + static void build_cabin_roof(const cabin_blueprint *bp, int chunk_x, int chunk_z, chunk_data *chunk, int rect_center_x, int rect_center_z, int half_w, int half_l, int roof_base_y, rng_state *rng) { @@ -2302,7 +2331,11 @@ static int try_place_cabin(worldgen_ctx *ctx, int chunk_x, int chunk_z, chunk_da } } if (min_h == INT_MAX) return 0; - if (max_h - min_h > 3) return 0; + if (max_h - min_h > 1) return 0; + int pad_min_h = INT_MAX; + int pad_max_h = INT_MIN; + if (!cabin_site_height_range(bp, chunk_origin_x, chunk_origin_z, columns, center_x, center_z, 2, &pad_min_h, &pad_max_h)) return 0; + if (pad_max_h - pad_min_h > 2) return 0; int base_floor_y = min_h + 1; if (base_floor_y + bp->wall_height * bp->stories + 6 >= CHUNK_HEIGHT) return 0; @@ -2364,7 +2397,7 @@ static void generate_chunk_cabins(worldgen_ctx *ctx, int chunk_x, int chunk_z, c size_t blueprint_count = sizeof(CABIN_BLUEPRINTS) / sizeof(CABIN_BLUEPRINTS[0]); unsigned char occupancy[CHUNK_SIZE][CHUNK_SIZE]; memset(occupancy, 0, sizeof(occupancy)); - int attempts = 1 + (rng_next_f64(&rng) < 0.2 ? 1 : 0); + int attempts = 3 + (rng_next_f64(&rng) < 0.35 ? 1 : 0); while (attempts-- > 0) { const cabin_blueprint *bp = &CABIN_BLUEPRINTS[rng_range_inclusive(&rng, 0, (int)blueprint_count - 1)]; int min_local_x = 2; @@ -2386,13 +2419,22 @@ static void generate_chunk_cabins(worldgen_ctx *ctx, int chunk_x, int chunk_z, c int best_local_x = min_local_x; int best_local_z = min_local_z; double best_score = -1e9; - const int samples = 12; + const int samples = 24; for (int s = 0; s < samples; ++s) { int local_cx = rng_range_inclusive(&rng, min_local_x, max_local_x); int local_cz = rng_range_inclusive(&rng, min_local_z, max_local_z); int world_cx = chunk_x * CHUNK_SIZE + local_cx; int world_cz = chunk_z * CHUNK_SIZE + local_cz; double score = land_value(ctx, world_cx, world_cz); + int flat_min_h = INT_MAX; + int flat_max_h = INT_MIN; + if (!cabin_site_height_range(bp, chunk_x * CHUNK_SIZE, chunk_z * CHUNK_SIZE, columns, + world_cx, world_cz, 2, &flat_min_h, &flat_max_h)) { + continue; + } + int flat_range = flat_max_h - flat_min_h; + if (flat_range > 3) continue; + score += 1.2 - (double)flat_range * 0.45; if (ctx->enable_trails) { double dist2 = nearest_trail_distance2(ctx, world_cx, world_cz, 1.0e12); double bonus = 0.0; @@ -3414,11 +3456,10 @@ void worldgen_generate_chunk(worldgen_ctx *ctx, int chunk_x, int chunk_z, chunk_ } } + generate_chunk_cabins(ctx, chunk_x, chunk_z, columns, out); if (ctx->enable_trails) { generate_chunk_trails(ctx, chunk_x, chunk_z, columns, out); } - - generate_chunk_cabins(ctx, chunk_x, chunk_z, columns, out); generate_chunk_redwood_floor(ctx, chunk_x, chunk_z, columns, out); generate_chunk_grass(ctx, chunk_x, chunk_z, columns, out); generate_chunk_flowers(ctx, chunk_x, chunk_z, columns, out); diff --git a/worldgen-c/tools/worldgen_scan.c b/worldgen-c/tools/worldgen_scan.c index bc7b7ba..328606a 100644 --- a/worldgen-c/tools/worldgen_scan.c +++ b/worldgen-c/tools/worldgen_scan.c @@ -9,7 +9,7 @@ static int is_cabin_block(uint16_t block) { return block == BLOCK_SPRUCE_PLANKS || block == BLOCK_OAK_PLANKS || block == BLOCK_OAK_LOG_X || block == BLOCK_OAK_LOG_Z || block == BLOCK_SPRUCE_LOG_X || block == BLOCK_SPRUCE_LOG_Z || - block == BLOCK_GLASS_PANE || 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_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_S_LOWER || block == BLOCK_SPRUCE_DOOR_S_UPPER ||