diff --git a/worldgen-c/bin/worldgen b/worldgen-c/bin/worldgen index 881e7f3..0ee30a5 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 45e3ff8..11ac933 100644 --- a/worldgen-c/include/worldgen.h +++ b/worldgen-c/include/worldgen.h @@ -61,7 +61,15 @@ BLOCK_STONE_BRICK_STAIRS_E = 48, BLOCK_STONE_BRICK_STAIRS_W = 49, 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 }; struct trail_segment; diff --git a/worldgen-c/src/main.c b/worldgen-c/src/main.c index da5b69a..b11f51e 100644 --- a/worldgen-c/src/main.c +++ b/worldgen-c/src/main.c @@ -154,7 +154,15 @@ static const block_state BLOCK_STATE_TABLE[] = { [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_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} }; static const block_state *get_block_state(uint16_t id) { diff --git a/worldgen-c/src/worldgen.c b/worldgen-c/src/worldgen.c index 5fff4c2..46376f6 100644 --- a/worldgen-c/src/worldgen.c +++ b/worldgen-c/src/worldgen.c @@ -137,6 +137,7 @@ static void generate_chunk_redwood_floor(worldgen_ctx *ctx, int chunk_x, int chu column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *chunk); static void generate_chunk_grass(worldgen_ctx *ctx, int chunk_x, int chunk_z, column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *out); static void generate_chunk_flowers(worldgen_ctx *ctx, int chunk_x, int chunk_z, column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *out); +static void generate_chunk_aquatic_life(worldgen_ctx *ctx, int chunk_x, int chunk_z, column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *out); static void generate_chunk_cabins(worldgen_ctx *ctx, int chunk_x, int chunk_z, column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *out); static void generate_chunk_border_wall(worldgen_ctx *ctx, int chunk_x, int chunk_z, chunk_data *out); static void ensure_trail_prepass(worldgen_ctx *ctx, int chunk_x, int chunk_z); @@ -939,8 +940,18 @@ static int generate_coal(worldgen_ctx *ctx, int x, int y, int z, int column_heig static uint16_t select_surface_block(worldgen_ctx *ctx, const column_data *data, int world_x, int world_z) { if (data->has_water && data->water_surface >= data->height) { int slope = ground_slope(ctx, world_x, world_z); - if (slope <= 1) return BLOCK_SAND; - if (slope <= 3) return BLOCK_GRAVEL; + double shelf = simplex_noise2(&ctx->noise, (world_x + 45000) * 0.025, (world_z - 45000) * 0.025) * 0.5 + 0.5; + double basin = simplex_noise2(&ctx->noise, (world_x - 23000) * 0.007, (world_z + 23000) * 0.007) * 0.5 + 0.5; + int depth = data->water_surface - data->height; + if (slope <= 1) { + if (depth >= 3 && basin > 0.74) return BLOCK_CLAY; + if (shelf > 0.76) return BLOCK_GRAVEL; + return BLOCK_SAND; + } + if (slope <= 3) { + if (depth >= 4 && basin > 0.82) return BLOCK_CLAY; + return (shelf > 0.44) ? BLOCK_GRAVEL : BLOCK_SAND; + } return BLOCK_STONE; } int snow_line = ctx->snow_line; @@ -1870,7 +1881,7 @@ static void generate_chunk_redwood_floor(worldgen_ctx *ctx, int chunk_x, int chu double litter = simplex_noise2(&ctx->noise, (wx + 8000) * 0.03, (wz - 8000) * 0.03) * 0.5 + 0.5; double fern_chance = clamp01(0.25 + rain * 0.5 + (1.0 - litter) * 0.25); if (chunk->blocks[cd.height + 1][dx][dz] == BLOCK_AIR && rng_next_f64(&rng) < fern_chance) { - chunk->blocks[cd.height + 1][dx][dz] = BLOCK_TALL_GRASS; + chunk->blocks[cd.height + 1][dx][dz] = (rain > 0.55 || rng_next_f64(&rng) < 0.45) ? BLOCK_FERN : BLOCK_TALL_GRASS; } if (rng_next_f64(&rng) < 0.0035) { try_place_redwood_fallen_log(ctx, chunk_x, chunk_z, chunk, columns, dx, dz, &rng); @@ -1901,7 +1912,7 @@ static void generate_chunk_grass(worldgen_ctx *ctx, int chunk_x, int chunk_z, co uint32_t h = hash_coords(world_x, world_z, (uint32_t)(ctx->world_seed ^ 0x5F3759DFu)); double roll = (double)(h & 0xFFFF) / 65535.0; if (roll > chance) continue; - out->blocks[cd.height + 1][dx][dz] = BLOCK_TALL_GRASS; + out->blocks[cd.height + 1][dx][dz] = (humidity > 0.72 && rain > 0.45) ? BLOCK_FERN : BLOCK_TALL_GRASS; if (roll < chance * 0.4) { const int offsets[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; for (int i = 0; i < 4; ++i) { @@ -1912,7 +1923,7 @@ static void generate_chunk_grass(worldgen_ctx *ctx, int chunk_x, int chunk_z, co if (nd.height <= 0 || nd.height >= CHUNK_HEIGHT - 1) continue; if (out->blocks[nd.height][nx][nz] != BLOCK_GRASS) continue; if (out->blocks[nd.height + 1][nx][nz] != BLOCK_AIR) continue; - out->blocks[nd.height + 1][nx][nz] = BLOCK_TALL_GRASS; + out->blocks[nd.height + 1][nx][nz] = ((h >> (i + 3)) & 1u) ? BLOCK_TALL_GRASS : BLOCK_FERN; } } } @@ -1942,7 +1953,17 @@ static void generate_chunk_flowers(worldgen_ctx *ctx, int chunk_x, int chunk_z, uint32_t h = hash_coords(world_x + 30000, world_z - 30000, (uint32_t)(ctx->world_seed ^ 0xA511E9B5u)); double roll = (double)(h & 0xFFFF) / 65535.0; if (roll > chance) continue; - out->blocks[cd.height + 1][dx][dz] = BLOCK_WILDFLOWER; + uint16_t flower = BLOCK_WILDFLOWER; + uint32_t flower_hash = hash_coords(world_x - 17000, world_z + 17000, (uint32_t)(ctx->world_seed ^ 0xB10F00Du)); + switch ((flower_hash >> 8) % 6) { + case 0: flower = BLOCK_DANDELION; break; + case 1: flower = BLOCK_AZURE_BLUET; break; + case 2: flower = BLOCK_OXEYE_DAISY; break; + case 3: flower = BLOCK_CORNFLOWER; break; + case 4: flower = BLOCK_LILY_OF_THE_VALLEY; break; + default: flower = BLOCK_WILDFLOWER; break; + } + out->blocks[cd.height + 1][dx][dz] = flower; static const int offsets[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; for (int i = 0; i < 4; ++i) { int nx = dx + offsets[i][0]; @@ -1954,7 +1975,40 @@ static void generate_chunk_flowers(worldgen_ctx *ctx, int chunk_x, int chunk_z, if (out->blocks[nd.height + 1][nx][nz] != BLOCK_AIR) continue; uint32_t nh = hash_coords(world_x + offsets[i][0] + 60000, world_z + offsets[i][1] - 60000, (uint32_t)(ctx->world_seed ^ 0xF00DBAAu)); if ((nh & 0xFFFF) > 24000) continue; - out->blocks[nd.height + 1][nx][nz] = BLOCK_WILDFLOWER; + uint16_t patch_flower = flower; + if ((nh & 7u) == 0u) patch_flower = BLOCK_DANDELION; + out->blocks[nd.height + 1][nx][nz] = patch_flower; + } + } + } +} + +static void generate_chunk_aquatic_life(worldgen_ctx *ctx, int chunk_x, int chunk_z, column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *out) { + for (int dx = 0; dx < CHUNK_SIZE; ++dx) { + for (int dz = 0; dz < CHUNK_SIZE; ++dz) { + column_data cd = columns[dx][dz]; + if (!cd.has_water || cd.water_surface <= cd.height) continue; + if (cd.height <= 0 || cd.height >= CHUNK_HEIGHT - 2) continue; + int depth = cd.water_surface - cd.height; + if (depth < 1 || depth > 9) continue; + int world_x = chunk_x * CHUNK_SIZE + dx; + int world_z = chunk_z * CHUNK_SIZE + dz; + uint16_t floor = out->blocks[cd.height][dx][dz]; + if (floor != BLOCK_SAND && floor != BLOCK_GRAVEL && floor != BLOCK_CLAY && floor != BLOCK_DIRT) continue; + if (out->blocks[cd.height + 1][dx][dz] != BLOCK_WATER) continue; + double bed = simplex_noise2(&ctx->noise, (world_x + 70000) * 0.035, (world_z - 70000) * 0.035) * 0.5 + 0.5; + double patch = simplex_noise2(&ctx->noise, (world_x - 15000) * 0.011, (world_z + 15000) * 0.011) * 0.5 + 0.5; + double chance = 0.08 + patch * 0.24; + if (floor == BLOCK_CLAY) chance += 0.10; + if (depth <= 3) chance += 0.12; + if (ground_slope(ctx, world_x, world_z) > 2) chance *= 0.35; + uint32_t h = hash_coords(world_x, world_z, (uint32_t)(ctx->world_seed ^ 0x5EA6A55u)); + double roll = (double)(h & 0xFFFF) / 65535.0; + if (roll > clamp01(chance)) continue; + out->blocks[cd.height + 1][dx][dz] = BLOCK_SEAGRASS; + if (depth >= 3 && bed > 0.78 && cd.height + 2 < CHUNK_HEIGHT && + out->blocks[cd.height + 2][dx][dz] == BLOCK_WATER) { + out->blocks[cd.height + 2][dx][dz] = BLOCK_SEAGRASS; } } } @@ -3852,6 +3906,7 @@ void worldgen_generate_chunk(worldgen_ctx *ctx, int chunk_x, int chunk_z, chunk_ 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); + generate_chunk_aquatic_life(ctx, chunk_x, chunk_z, columns, out); // Tree overlay block_list trees;