From c8ad0a06e8e938f2216abea511892a257ef4d4a1 Mon Sep 17 00:00:00 2001 From: chelsea Date: Tue, 2 Dec 2025 20:45:50 -0600 Subject: [PATCH] Add log cabin variants and fix palette --- worldgen-c/bin/worldgen | Bin 106160 -> 127552 bytes worldgen-c/include/worldgen.h | 25 +- worldgen-c/src/main.c | 49 ++- worldgen-c/src/worldgen.c | 611 +++++++++++++++++++++++++++++++++- 4 files changed, 673 insertions(+), 12 deletions(-) diff --git a/worldgen-c/bin/worldgen b/worldgen-c/bin/worldgen index 0a3e066a511aebfdcb4422aa4fc5db427492170b..92fd3db2a41a6c8d4305bb6435c690bba68a47f7 100755 GIT binary patch delta 53142 zcma&P3w#vC(muR1WFd)!S&$$gV2}hz1O%1Ks%SRs;;e2UDwjk7k$9pU6;Kla1vVHK z7}tU55Wx$IcV88S!$Be%+}t2s4WJl}K)47SA`n0!A(H)`>YfRkIq!MDzdzZTuCA)C zs;;iC?&+DVD{31!-Y&me$I%w{UoyW~ET>*g`q;a)4=);5i;b5BTEn3v7he>_YW z7K?EWr;DJ9d|q$9PU=mS7K?s;*b+|I78UEh=Y;EiXnmck3${kT8gwFPh%R>*$It!E zxN4sXuXozDju)?9wFks0z0=lku=)B02V1_-_KIU~{BN?P=`y6*w3IeuI`<7E{5<^1 z!CiBDb-Xs>vw0s4^*x%s;lnlqBZL}lU%Q)ynhj#)U2VLEMv;(~{#$bozZUA68t|z) zJYa&KeU%GWWr7Q@ad^E6-cg4~ReYy$W zQ-{yG3TN$G2J00|uU0TG9Hqn8nBWiT@In)Oh7PYZ!58W9pb7ql=H-%F_O;g7@QFwh zJWcQ8t|qvFA7_Fm>-d9B@b$VtBfO>xqXF3jHwe;9aHD~#CiqspfjK64wGPkK;a;PU z;|_2OE>OJ* zZs0eV;K>Xh{ujBwb>ABVHWR!?FUOhS27Z4NJXbG|Fu~7hyuDJ_WPDro$5*WqhS@Hid*sR`a!hp#iiZ_?p~ zCivhL0w4bYQ^hcypuz+P0gDSYCb*$-&;&O$t~bFAg&X$ks?6M>;|r3r3mTxEhA3e=e3Miℜne>Iff4Zxfeei!^+;&I-7C0H*i3Lk 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 diff --git a/worldgen-c/include/worldgen.h b/worldgen-c/include/worldgen.h index 561b1b0..f4ea7e0 100644 --- a/worldgen-c/include/worldgen.h +++ b/worldgen-c/include/worldgen.h @@ -24,7 +24,30 @@ BLOCK_GRAVEL = 12, BLOCK_SNOW = 13, BLOCK_TALL_GRASS = 14, - BLOCK_WILDFLOWER = 15 + BLOCK_WILDFLOWER = 15, + BLOCK_COPPER_ORE = 16, + BLOCK_IRON_ORE = 17, + BLOCK_GOLD_ORE = 18, + BLOCK_REDSTONE_ORE = 19, + BLOCK_LAPIS_ORE = 20, + BLOCK_DIAMOND_ORE = 21, + BLOCK_OAK_PLANKS = 22, + BLOCK_SPRUCE_PLANKS = 23, + BLOCK_OAK_LOG_X = 24, + BLOCK_OAK_LOG_Z = 25, + 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 }; struct trail_segment; diff --git a/worldgen-c/src/main.c b/worldgen-c/src/main.c index 43488c0..d53db3e 100644 --- a/worldgen-c/src/main.c +++ b/worldgen-c/src/main.c @@ -74,10 +74,23 @@ typedef struct { } block_state; static const kv_pair PROPS_LOG_AXIS[] = {{"axis", "y"}}; +static const kv_pair PROPS_LOG_AXIS_X[] = {{"axis", "x"}}; +static const kv_pair PROPS_LOG_AXIS_Z[] = {{"axis", "z"}}; static const kv_pair PROPS_GRASS[] = {{"snowy", "false"}}; static const kv_pair PROPS_WATER[] = {{"level", "0"}}; static const kv_pair PROPS_LEAVES[] = {{"distance", "1"}, {"persistent", "false"}}; +static const kv_pair PROPS_STAIRS_E[] = {{"facing", "east"}, {"half", "bottom"}, {"shape", "straight"}, {"waterlogged", "false"}}; +static const kv_pair PROPS_STAIRS_W[] = {{"facing", "west"}, {"half", "bottom"}, {"shape", "straight"}, {"waterlogged", "false"}}; +static const kv_pair PROPS_DOOR_S_LOWER[] = {{"facing", "south"}, {"half", "lower"}, {"hinge", "left"}, {"open", "false"}, {"powered", "false"}}; +static const kv_pair PROPS_DOOR_S_UPPER[] = {{"facing", "south"}, {"half", "upper"}, {"hinge", "left"}, {"open", "false"}, {"powered", "false"}}; +static const kv_pair PROPS_DOOR_N_LOWER[] = {{"facing", "north"}, {"half", "lower"}, {"hinge", "left"}, {"open", "false"}, {"powered", "false"}}; +static const kv_pair PROPS_DOOR_N_UPPER[] = {{"facing", "north"}, {"half", "upper"}, {"hinge", "left"}, {"open", "false"}, {"powered", "false"}}; +static const kv_pair PROPS_DOOR_W_LOWER[] = {{"facing", "west"}, {"half", "lower"}, {"hinge", "left"}, {"open", "false"}, {"powered", "false"}}; +static const kv_pair PROPS_DOOR_W_UPPER[] = {{"facing", "west"}, {"half", "upper"}, {"hinge", "left"}, {"open", "false"}, {"powered", "false"}}; +static const kv_pair PROPS_DOOR_E_LOWER[] = {{"facing", "east"}, {"half", "lower"}, {"hinge", "left"}, {"open", "false"}, {"powered", "false"}}; +static const kv_pair PROPS_DOOR_E_UPPER[] = {{"facing", "east"}, {"half", "upper"}, {"hinge", "left"}, {"open", "false"}, {"powered", "false"}}; +static const size_t BLOCK_STATE_CAP = 256; static const block_state BLOCK_STATE_TABLE[] = { [BLOCK_BEDROCK] = {"minecraft:bedrock", NULL, 0}, [BLOCK_STONE] = {"minecraft:stone", NULL, 0}, @@ -94,7 +107,30 @@ static const block_state BLOCK_STATE_TABLE[] = { [BLOCK_GRAVEL] = {"minecraft:gravel", NULL, 0}, [BLOCK_SNOW] = {"minecraft:snow", NULL, 0}, [BLOCK_TALL_GRASS] = {"minecraft:grass", NULL, 0}, - [BLOCK_WILDFLOWER] = {"minecraft:poppy", NULL, 0} + [BLOCK_WILDFLOWER] = {"minecraft:poppy", NULL, 0}, + [BLOCK_COPPER_ORE] = {"minecraft:copper_ore", NULL, 0}, + [BLOCK_IRON_ORE] = {"minecraft:iron_ore", NULL, 0}, + [BLOCK_GOLD_ORE] = {"minecraft:gold_ore", NULL, 0}, + [BLOCK_REDSTONE_ORE] = {"minecraft:redstone_ore", NULL, 0}, + [BLOCK_LAPIS_ORE] = {"minecraft:lapis_ore", NULL, 0}, + [BLOCK_DIAMOND_ORE] = {"minecraft:diamond_ore", NULL, 0}, + [BLOCK_OAK_PLANKS] = {"minecraft:oak_planks", NULL, 0}, + [BLOCK_SPRUCE_PLANKS] = {"minecraft:spruce_planks", NULL, 0}, + [BLOCK_OAK_LOG_X] = {"minecraft:oak_log", PROPS_LOG_AXIS_X, 1}, + [BLOCK_OAK_LOG_Z] = {"minecraft:oak_log", PROPS_LOG_AXIS_Z, 1}, + [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_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}, + [BLOCK_SPRUCE_DOOR_N_UPPER] = {"minecraft:spruce_door", PROPS_DOOR_N_UPPER, 5}, + [BLOCK_SPRUCE_DOOR_W_LOWER] = {"minecraft:spruce_door", PROPS_DOOR_W_LOWER, 5}, + [BLOCK_SPRUCE_DOOR_W_UPPER] = {"minecraft:spruce_door", PROPS_DOOR_W_UPPER, 5}, + [BLOCK_SPRUCE_DOOR_E_LOWER] = {"minecraft:spruce_door", PROPS_DOOR_E_LOWER, 5}, + [BLOCK_SPRUCE_DOOR_E_UPPER] = {"minecraft:spruce_door", PROPS_DOOR_E_UPPER, 5}, + [BLOCK_SPRUCE_STAIRS_E] = {"minecraft:spruce_stairs", PROPS_STAIRS_E, 4}, + [BLOCK_SPRUCE_STAIRS_W] = {"minecraft:spruce_stairs", PROPS_STAIRS_W, 4} }; static const block_state *get_block_state(uint16_t id) { @@ -308,9 +344,9 @@ static void write_palette_entry(buf *b, const block_state *state) { } static void write_section(buf *b, const chunk_data *chunk, int section_y) { - int palette_index[16]; - for (size_t i = 0; i < 16; ++i) palette_index[i] = -1; - const block_state *palette_states[16]; + int palette_index[BLOCK_STATE_CAP]; + for (size_t i = 0; i < BLOCK_STATE_CAP; ++i) palette_index[i] = -1; + const block_state *palette_states[BLOCK_STATE_CAP]; uint16_t block_indices[4096]; size_t palette_len = 0; @@ -322,10 +358,13 @@ static void write_section(buf *b, const chunk_data *chunk, int section_y) { for (int z = 0; z < CHUNK_SIZE; ++z) { for (int x = 0; x < CHUNK_SIZE; ++x) { uint16_t bid = chunk->blocks[gy][x][z]; + if (bid >= BLOCK_STATE_CAP) continue; if (palette_index[bid] == -1) { palette_index[bid] = (int)palette_len; palette_states[palette_len] = get_block_state(bid); - palette_len++; + if (palette_len < BLOCK_STATE_CAP) { + palette_len++; + } } block_indices[idx++] = (uint16_t)palette_index[bid]; } diff --git a/worldgen-c/src/worldgen.c b/worldgen-c/src/worldgen.c index 1dd4d7d..38f668f 100644 --- a/worldgen-c/src/worldgen.c +++ b/worldgen-c/src/worldgen.c @@ -118,15 +118,23 @@ static inline double clamp01(double v) { return v; } +static inline int clamp_int(int v, int min_v, int max_v) { + if (v < min_v) return min_v; + if (v > max_v) return max_v; + return v; +} + static int ground_slope(worldgen_ctx *ctx, int x, int z); static uint16_t select_surface_block(worldgen_ctx *ctx, const column_data *data, int world_x, int world_z); static void generate_chunk_trails(worldgen_ctx *ctx, int chunk_x, int chunk_z, column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *out); 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_cabins(worldgen_ctx *ctx, int chunk_x, int chunk_z, column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *out); static void trail_node_position(worldgen_ctx *ctx, int node_x, int node_z, double spacing, double *out_x, double *out_z); static void carve_trail_pad(worldgen_ctx *ctx, int chunk_x, int chunk_z, chunk_data *out, column_data columns[CHUNK_SIZE][CHUNK_SIZE], int center_x, int center_z, int radius, int target_height); static double old_growth_plains_mask(worldgen_ctx *ctx, int x, int z); static double old_growth_grove_mask(worldgen_ctx *ctx, int x, int z); +static uint16_t generate_normal_ores(worldgen_ctx *ctx, int x, int y, int z, const column_data *col); static uint32_t hash_coords(int x, int z, uint32_t seed) { uint32_t h = (uint32_t)(x * 374761393 + z * 668265263) ^ seed; @@ -134,6 +142,25 @@ static uint32_t hash_coords(int x, int z, uint32_t seed) { return h ^ (h >> 16); } +static uint32_t hash_coords3(int x, int y, int z, uint32_t seed) { + uint32_t h = (uint32_t)(x * 374761393 + y * 668265263 + z * 362827313) ^ seed; + h ^= (uint32_t)y * 0x9E3779B9u; + h = (h ^ (h >> 13)) * 1274126177u; + return h ^ (h >> 16); +} + +static void set_block_with_height(chunk_data *chunk, int local_x, int local_z, int y, uint16_t id) { + if (local_x < 0 || local_x >= CHUNK_SIZE || local_z < 0 || local_z >= CHUNK_SIZE) return; + if (y < 0 || y >= CHUNK_HEIGHT) return; + chunk->blocks[y][local_x][local_z] = id; + if (id != BLOCK_AIR) { + uint16_t current = chunk->heightmap[local_x][local_z]; + if ((uint16_t)y > current) { + chunk->heightmap[local_x][local_z] = (uint16_t)y; + } + } +} + static double worley_distance(int x, int z, double scale, uint32_t seed) { double px = x * scale; double pz = z * scale; @@ -156,6 +183,25 @@ static double worley_distance(int x, int z, double scale, uint32_t seed) { return min_dist; } +static double ore_depth_weight(int y, int top, int bottom) { + if (y > top || y < bottom) return 0.0; + if (top <= bottom) return 1.0; + double span = (double)(top - bottom); + if (span <= 0.0) return 1.0; + double weight = (double)(top - y) / span; + if (weight < 0.0) weight = 0.0; + if (weight > 1.0) weight = 1.0; + return weight; +} + +static double ore_cluster_field(worldgen_ctx *ctx, int x, int y, int z, double scale, double offset) { + double n = simplex_noise3(&ctx->noise, + x * scale + offset, + y * scale * 0.9 - offset * 0.37, + z * scale - offset * 0.21); + return n * 0.5 + 0.5; +} + static double old_growth_plains_mask(worldgen_ctx *ctx, int x, int z) { (void)ctx; double coarse = worley_distance(x + 21000, z - 21000, 0.00065, 0x9E3779B9u); @@ -547,7 +593,7 @@ static int sample_block(worldgen_ctx *ctx, int x, int y, int z) { if (generate_coal(ctx, x, y, z, data.height, data.biome)) { return BLOCK_COAL; } - return BLOCK_STONE; + return (int)generate_normal_ores(ctx, x, y, z, &data); } if (y < data.height) return BLOCK_DIRT; if (y == data.height) { @@ -1285,7 +1331,549 @@ static void generate_chunk_flowers(worldgen_ctx *ctx, int chunk_x, int chunk_z, } } -static int column_has_trail_surface(chunk_data *chunk, int chunk_x, int chunk_z, int world_x, int world_z) { +static void place_log_line(chunk_data *chunk, int chunk_origin_x, int chunk_origin_z, + int x0, int z0, int x1, int z1, int y, uint16_t block, + int door_x, int door_z, int door_clear_top, + rng_state *rng, double skip_prob) { + int dx = (x1 > x0) ? 1 : (x1 < x0 ? -1 : 0); + int dz = (z1 > z0) ? 1 : (z1 < z0 ? -1 : 0); + int length = (dx != 0) ? abs(x1 - x0) : abs(z1 - z0); + int respect_door = (door_x != INT_MIN && door_z != INT_MIN); + for (int i = 0; i <= length; ++i) { + int wx = x0 + dx * i; + int wz = z0 + dz * i; + if (respect_door && wx == door_x && wz == door_z && y <= door_clear_top) continue; + if (rng && skip_prob > 0.0 && rng_next_f64(rng) < skip_prob) continue; + int lx = wx - chunk_origin_x; + int lz = wz - chunk_origin_z; + if (lx < 0 || lx >= CHUNK_SIZE || lz < 0 || lz >= CHUNK_SIZE) continue; + set_block_with_height(chunk, lx, lz, y, block); + } +} + +typedef struct { + int offset_x; + int offset_z; + int half_w; + int half_l; +} cabin_rect; + +#define CABIN_MAX_RECTS 4 + +typedef struct { + const cabin_rect *rects; + size_t rect_count; + int wall_height; + int stories; + uint16_t floor_block; + uint16_t roof_block; + uint16_t log_x_block; + uint16_t log_z_block; + uint16_t corner_log; + uint16_t stair_e_block; + uint16_t stair_w_block; + uint16_t window_block; + double log_decay; + double plank_decay; + double window_chance; + double door_decay; + int door_rect_index; +} cabin_blueprint; + +static const cabin_rect CABIN_RECT_SMALL[] = { + {0, 0, 2, 3} +}; + +static const cabin_rect CABIN_RECT_LONG[] = { + {0, 0, 3, 4} +}; + +static const cabin_rect CABIN_RECT_TWO_STORY[] = { + {0, 0, 3, 3} +}; + +static const cabin_rect CABIN_RECT_L_SHAPE[] = { + {0, 0, 3, 3}, + {3, -2, 2, 2} +}; + +static const cabin_blueprint CABIN_BLUEPRINTS[] = { + { + CABIN_RECT_SMALL, + sizeof(CABIN_RECT_SMALL) / sizeof(CABIN_RECT_SMALL[0]), + 3, + 1, + BLOCK_SPRUCE_PLANKS, + BLOCK_OAK_PLANKS, + BLOCK_OAK_LOG_X, + BLOCK_OAK_LOG_Z, + BLOCK_OAK_LOG, + BLOCK_SPRUCE_STAIRS_E, + BLOCK_SPRUCE_STAIRS_W, + BLOCK_GLASS_PANE, + 0.04, + 0.25, + 0.45, + 0.35, + 0 + }, + { + CABIN_RECT_LONG, + sizeof(CABIN_RECT_LONG) / sizeof(CABIN_RECT_LONG[0]), + 4, + 1, + BLOCK_OAK_PLANKS, + BLOCK_SPRUCE_PLANKS, + BLOCK_SPRUCE_LOG_X, + BLOCK_SPRUCE_LOG_Z, + BLOCK_OAK_LOG, + BLOCK_SPRUCE_STAIRS_E, + BLOCK_SPRUCE_STAIRS_W, + BLOCK_GLASS_PANE, + 0.05, + 0.3, + 0.4, + 0.4, + 0 + }, + { + CABIN_RECT_TWO_STORY, + sizeof(CABIN_RECT_TWO_STORY) / sizeof(CABIN_RECT_TWO_STORY[0]), + 4, + 2, + BLOCK_SPRUCE_PLANKS, + BLOCK_SPRUCE_PLANKS, + BLOCK_OAK_LOG_X, + BLOCK_OAK_LOG_Z, + BLOCK_OAK_LOG, + BLOCK_SPRUCE_STAIRS_E, + BLOCK_SPRUCE_STAIRS_W, + BLOCK_GLASS_PANE, + 0.04, + 0.22, + 0.5, + 0.3, + 0 + }, + { + CABIN_RECT_L_SHAPE, + sizeof(CABIN_RECT_L_SHAPE) / sizeof(CABIN_RECT_L_SHAPE[0]), + 3, + 1, + BLOCK_OAK_PLANKS, + BLOCK_OAK_PLANKS, + BLOCK_OAK_LOG_X, + BLOCK_OAK_LOG_Z, + BLOCK_OAK_LOG, + BLOCK_SPRUCE_STAIRS_E, + BLOCK_SPRUCE_STAIRS_W, + BLOCK_GLASS_PANE, + 0.04, + 0.28, + 0.45, + 0.4, + 0 + } +}; + +static void update_columns_for_rect(column_data columns[CHUNK_SIZE][CHUNK_SIZE], int chunk_origin_x, int chunk_origin_z, + int x0, int x1, int z0, int z1, int new_height) { + for (int wz = z0 - 1; wz <= z1 + 1; ++wz) { + for (int wx = x0 - 1; wx <= x1 + 1; ++wx) { + int lx = wx - chunk_origin_x; + int lz = wz - chunk_origin_z; + if (lx < 0 || lx >= CHUNK_SIZE || lz < 0 || lz >= CHUNK_SIZE) continue; + if (columns[lx][lz].height < new_height) { + columns[lx][lz].height = new_height; + columns[lx][lz].has_water = 0; + } + } + } +} + +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) { + int chunk_origin_x = chunk_x * CHUNK_SIZE; + int chunk_origin_z = chunk_z * CHUNK_SIZE; + int overhang = 1; + int x0 = rect_center_x - half_w; + int x1 = rect_center_x + half_w; + int z0 = rect_center_z - half_l; + int z1 = rect_center_z + half_l; + int layers = half_w + 3; + for (int layer = 0; layer < layers; ++layer) { + int start_x = (x0 - overhang) + layer; + int end_x = (x1 + overhang) - layer; + if (start_x > end_x) break; + int y = roof_base_y + layer + 1; + for (int wz = z0 - overhang; wz <= z1 + overhang; ++wz) { + for (int wx = start_x; wx <= end_x; ++wx) { + if (rng && bp->plank_decay > 0.0 && rng_next_f64(rng) < bp->plank_decay * 0.2) continue; + int lx = wx - chunk_origin_x; + int lz = wz - chunk_origin_z; + if (lx < 0 || lx >= CHUNK_SIZE || lz < 0 || lz >= CHUNK_SIZE) continue; + set_block_with_height(chunk, lx, lz, y, bp->roof_block); + } + } + for (int wz = z0 - overhang; wz <= z1 + overhang; ++wz) { + int east_x = end_x + 1; + int west_x = start_x - 1; + int lx_e = east_x - chunk_origin_x; + int lx_w = west_x - chunk_origin_x; + int lz = wz - chunk_origin_z; + if (lx_e >= 0 && lx_e < CHUNK_SIZE && lz >= 0 && lz < CHUNK_SIZE) { + set_block_with_height(chunk, lx_e, lz, y, bp->stair_e_block); + } + if (lx_w >= 0 && lx_w < CHUNK_SIZE && lz >= 0 && lz < CHUNK_SIZE) { + set_block_with_height(chunk, lx_w, lz, y, bp->stair_w_block); + } + } + } +} + +static void place_wall_window(chunk_data *chunk, int chunk_origin_x, int chunk_origin_z, + int wx, int wz, int window_y, uint16_t window_block) { + int lx = wx - chunk_origin_x; + int lz = wz - chunk_origin_z; + if (lx < 0 || lx >= CHUNK_SIZE || lz < 0 || lz >= CHUNK_SIZE) return; + set_block_with_height(chunk, lx, lz, window_y, window_block); +} + +static void build_cabin_rect(worldgen_ctx *ctx, const cabin_blueprint *bp, const cabin_rect *rect, + int chunk_x, int chunk_z, chunk_data *chunk, column_data columns[CHUNK_SIZE][CHUNK_SIZE], + int rect_center_x, int rect_center_z, int base_floor_y, + int door_x, int door_z, int door_side, int has_door, rng_state *rng) { + (void)ctx; + int chunk_origin_x = chunk_x * CHUNK_SIZE; + int chunk_origin_z = chunk_z * CHUNK_SIZE; + int x0 = rect_center_x - rect->half_w; + int x1 = rect_center_x + rect->half_w; + int z0 = rect_center_z - rect->half_l; + int z1 = rect_center_z + rect->half_l; + int clear_top = base_floor_y + bp->wall_height * bp->stories + 6; + + for (int wz = z0 - 2; wz <= z1 + 2; ++wz) { + for (int wx = x0 - 2; wx <= x1 + 2; ++wx) { + int lx = wx - chunk_origin_x; + int lz = wz - chunk_origin_z; + if (lx < 0 || lx >= CHUNK_SIZE || lz < 0 || lz >= CHUNK_SIZE) continue; + for (int y = base_floor_y; y <= clear_top && y < CHUNK_HEIGHT; ++y) { + set_block_with_height(chunk, lx, lz, y, BLOCK_AIR); + } + } + } + + for (int story = 0; story < bp->stories; ++story) { + int story_floor = base_floor_y + story * bp->wall_height; + if (story_floor >= CHUNK_HEIGHT - 4) break; + 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; + if (lx < 0 || lx >= CHUNK_SIZE || lz < 0 || lz >= CHUNK_SIZE) continue; + set_block_with_height(chunk, lx, lz, story_floor, bp->floor_block); + } + } + int story_has_door = has_door && story == 0; + int door_clear_top = story_has_door ? (story_floor + 2) : story_floor; + int door_x_story = story_has_door ? door_x : INT_MIN; + int door_z_story = story_has_door ? door_z : INT_MIN; + for (int h = 0; h < bp->wall_height; ++h) { + int yy = story_floor + 1 + h; + if (yy >= CHUNK_HEIGHT - 2) break; + int extend_x = ((story * bp->wall_height + h) % 2 == 0); + double base_skip = bp->log_decay; + double extend_skip = bp->log_decay * 0.6; + int north_start_x = extend_x ? x0 - 1 : x0; + int north_end_x = extend_x ? x1 + 1 : x1; + int south_start_x = extend_x ? x0 - 1 : x0; + int south_end_x = extend_x ? x1 + 1 : x1; + if (extend_x) { + place_log_line(chunk, chunk_origin_x, chunk_origin_z, x0, z0, x0, z1, yy, bp->log_z_block, + door_x_story, door_z_story, door_clear_top, rng, base_skip); + place_log_line(chunk, chunk_origin_x, chunk_origin_z, x1, z0, x1, z1, yy, bp->log_z_block, + door_x_story, door_z_story, door_clear_top, rng, base_skip); + place_log_line(chunk, chunk_origin_x, chunk_origin_z, north_start_x, z0, north_end_x, z0, yy, bp->log_x_block, + door_x_story, door_z_story, door_clear_top, rng, extend_skip); + place_log_line(chunk, chunk_origin_x, chunk_origin_z, south_start_x, z1, south_end_x, z1, yy, bp->log_x_block, + door_x_story, door_z_story, door_clear_top, rng, extend_skip); + } else { + int west_start_z = z0 - 1; + int west_end_z = z1 + 1; + int east_start_z = z0 - 1; + int east_end_z = z1 + 1; + place_log_line(chunk, chunk_origin_x, chunk_origin_z, north_start_x, z0, north_end_x, z0, yy, bp->log_x_block, + door_x_story, door_z_story, door_clear_top, rng, base_skip); + place_log_line(chunk, chunk_origin_x, chunk_origin_z, south_start_x, z1, south_end_x, z1, yy, bp->log_x_block, + door_x_story, door_z_story, door_clear_top, rng, base_skip); + place_log_line(chunk, chunk_origin_x, chunk_origin_z, x0, west_start_z, x0, west_end_z, yy, bp->log_z_block, + door_x_story, door_z_story, door_clear_top, rng, extend_skip); + place_log_line(chunk, chunk_origin_x, chunk_origin_z, x1, east_start_z, x1, east_end_z, yy, bp->log_z_block, + door_x_story, door_z_story, door_clear_top, rng, extend_skip); + } + } + + if (bp->window_block && bp->window_chance > 0.0) { + int window_y = story_floor + 2; + for (int wx = x0 + 1; wx <= x1 - 1; wx += 2) { + if (story_has_door && door_side == 0 && wx == door_x) continue; + if (rng_next_f64(rng) < bp->window_chance) { + place_wall_window(chunk, chunk_origin_x, chunk_origin_z, wx, z0, window_y, bp->window_block); + } + if (story_has_door && door_side == 1 && wx == door_x) continue; + if (rng_next_f64(rng) < bp->window_chance) { + place_wall_window(chunk, chunk_origin_x, chunk_origin_z, wx, z1, window_y, bp->window_block); + } + } + for (int wz = z0 + 1; wz <= z1 - 1; wz += 2) { + if (story_has_door && door_side == 2 && wz == door_z) continue; + if (rng_next_f64(rng) < bp->window_chance) { + place_wall_window(chunk, chunk_origin_x, chunk_origin_z, x0, wz, window_y, bp->window_block); + } + if (story_has_door && door_side == 3 && wz == door_z) continue; + if (rng_next_f64(rng) < bp->window_chance) { + place_wall_window(chunk, chunk_origin_x, chunk_origin_z, x1, wz, window_y, bp->window_block); + } + } + } + + if (story_has_door) { + if (rng_next_f64(rng) >= bp->door_decay) { + uint16_t lower = BLOCK_SPRUCE_DOOR_S_LOWER; + uint16_t upper = BLOCK_SPRUCE_DOOR_S_UPPER; + switch (door_side) { + case 0: lower = BLOCK_SPRUCE_DOOR_N_LOWER; upper = BLOCK_SPRUCE_DOOR_N_UPPER; break; + case 1: lower = BLOCK_SPRUCE_DOOR_S_LOWER; upper = BLOCK_SPRUCE_DOOR_S_UPPER; break; + case 2: lower = BLOCK_SPRUCE_DOOR_W_LOWER; upper = BLOCK_SPRUCE_DOOR_W_UPPER; break; + case 3: lower = BLOCK_SPRUCE_DOOR_E_LOWER; upper = BLOCK_SPRUCE_DOOR_E_UPPER; break; + } + int lx = door_x - chunk_origin_x; + int lz = door_z - chunk_origin_z; + if (lx >= 0 && lx < CHUNK_SIZE && lz >= 0 && lz < CHUNK_SIZE) { + set_block_with_height(chunk, lx, lz, story_floor + 1, lower); + set_block_with_height(chunk, lx, lz, story_floor + 2, upper); + } + } + } + } + + int roof_base = base_floor_y + bp->wall_height * bp->stories; + build_cabin_roof(bp, chunk_x, chunk_z, chunk, rect_center_x, rect_center_z, rect->half_w, rect->half_l, roof_base, rng); + + if (has_door) { + int step_x = (door_side == 2) ? -1 : (door_side == 3) ? 1 : 0; + int step_z = (door_side == 0) ? -1 : (door_side == 1) ? 1 : 0; + int pad_x = door_x + step_x; + int pad_z = door_z + step_z; + int lx = pad_x - chunk_origin_x; + int lz = pad_z - chunk_origin_z; + if (lx >= 0 && lx < CHUNK_SIZE && lz >= 0 && lz < CHUNK_SIZE) { + set_block_with_height(chunk, lx, lz, base_floor_y, BLOCK_GRAVEL); + } + } + + update_columns_for_rect(columns, chunk_origin_x, chunk_origin_z, x0, x1, z0, z1, roof_base + 2); +} + +static int try_place_cabin(worldgen_ctx *ctx, int chunk_x, int chunk_z, chunk_data *chunk, column_data columns[CHUNK_SIZE][CHUNK_SIZE], + int center_x, int center_z, const cabin_blueprint *bp, rng_state *rng) { + int chunk_origin_x = chunk_x * CHUNK_SIZE; + int chunk_origin_z = chunk_z * CHUNK_SIZE; + if (bp->rect_count == 0 || bp->rect_count > CABIN_MAX_RECTS) return 0; + int rect_center_x[CABIN_MAX_RECTS]; + int rect_center_z[CABIN_MAX_RECTS]; + int rect_x0[CABIN_MAX_RECTS]; + int rect_x1[CABIN_MAX_RECTS]; + int rect_z0[CABIN_MAX_RECTS]; + int rect_z1[CABIN_MAX_RECTS]; + 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; + int x1 = rcx + rect->half_w; + int z0 = rcz - rect->half_l; + int z1 = rcz + rect->half_l; + if (x0 < chunk_origin_x + 1 || x1 > chunk_origin_x + CHUNK_SIZE - 2) return 0; + if (z0 < chunk_origin_z + 1 || z1 > chunk_origin_z + CHUNK_SIZE - 2) return 0; + rect_center_x[i] = rcx; + rect_center_z[i] = rcz; + rect_x0[i] = x0; + rect_x1[i] = x1; + rect_z0[i] = z0; + rect_z1[i] = z1; + 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; + if (max_h - min_h > 3) return 0; + int base_floor_y = min_h + 1; + if (base_floor_y + bp->wall_height * bp->stories + 6 >= CHUNK_HEIGHT) return 0; + + int door_rect_index = clamp_int(bp->door_rect_index, 0, (int)bp->rect_count - 1); + int door_side = rng_range_inclusive(rng, 0, 3); + int door_x = rect_center_x[door_rect_index]; + int door_z = rect_z0[door_rect_index]; + if (door_side == 1) door_z = rect_z1[door_rect_index]; + if (door_side == 2) { + door_x = rect_x0[door_rect_index]; + door_z = rect_center_z[door_rect_index]; + } else if (door_side == 3) { + door_x = rect_x1[door_rect_index]; + door_z = rect_center_z[door_rect_index]; + } + int door_offset = rng_range_inclusive(rng, -1, 1); + if (door_side == 0 || door_side == 1) { + door_x = clamp_int(door_x + door_offset, rect_x0[door_rect_index] + 1, rect_x1[door_rect_index] - 1); + } else { + door_z = clamp_int(door_z + door_offset, rect_z0[door_rect_index] + 1, rect_z1[door_rect_index] - 1); + } + + for (size_t i = 0; i < bp->rect_count; ++i) { + int has_door = (int)i == door_rect_index; + build_cabin_rect(ctx, bp, &bp->rects[i], chunk_x, chunk_z, chunk, columns, + rect_center_x[i], rect_center_z[i], base_floor_y, + door_x, door_z, door_side, has_door, rng); + } + + return 1; +} + +static void generate_chunk_cabins(worldgen_ctx *ctx, int chunk_x, int chunk_z, column_data columns[CHUNK_SIZE][CHUNK_SIZE], chunk_data *out) { + uint64_t seed = (uint64_t)ctx->world_seed * 6364136223846793005ULL + (uint64_t)chunk_x * 374761393ULL + (uint64_t)chunk_z * 668265263ULL; + rng_state rng; + rng_seed(&rng, seed ^ 0xCAB1A5u); + double noise = simplex_noise2(&ctx->noise, (chunk_x * CHUNK_SIZE + 5000) * 0.0006, (chunk_z * CHUNK_SIZE - 5000) * 0.0006) * 0.5 + 0.5; + double spawn_chance = 0.015 + noise * 0.02; + if (rng_next_f64(&rng) > spawn_chance) return; + size_t blueprint_count = sizeof(CABIN_BLUEPRINTS) / sizeof(CABIN_BLUEPRINTS[0]); + int attempts = 1 + (rng_next_f64(&rng) < 0.2 ? 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; + int max_local_x = CHUNK_SIZE - 3; + int min_local_z = 2; + int max_local_z = CHUNK_SIZE - 3; + for (size_t i = 0; i < bp->rect_count; ++i) { + const cabin_rect *rect = &bp->rects[i]; + int req_min_x = rect->half_w - rect->offset_x + 1; + int req_max_x = CHUNK_SIZE - 2 - (rect->half_w + rect->offset_x); + int req_min_z = rect->half_l - rect->offset_z + 1; + int req_max_z = CHUNK_SIZE - 2 - (rect->half_l + rect->offset_z); + if (req_min_x > min_local_x) min_local_x = req_min_x; + if (req_max_x < max_local_x) max_local_x = req_max_x; + if (req_min_z > min_local_z) min_local_z = req_min_z; + if (req_max_z < max_local_z) max_local_z = req_max_z; + } + if (min_local_x >= max_local_x - 1 || min_local_z >= max_local_z - 1) continue; + 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; + if (try_place_cabin(ctx, chunk_x, chunk_z, out, columns, world_cx, world_cz, bp, &rng)) { + break; + } + } +} + +static uint16_t generate_normal_ores(worldgen_ctx *ctx, int x, int y, int z, const column_data *col) { + uint32_t seed = (uint32_t)ctx->world_seed; + double cluster; + double chance; + double weight; + uint32_t h; + + weight = ore_depth_weight(y, 16, 0); + if (weight > 0.0) { + cluster = ore_cluster_field(ctx, x, y, z, 0.032, 19000.0); + if (cluster > 0.78) { + chance = 0.003 + weight * 0.02; + h = hash_coords3(x, y, z, seed ^ 0x0D14F1A3u); + if ((h & 0xFFFF) <= (uint32_t)(chance * 65535.0)) { + return BLOCK_DIAMOND_ORE; + } + } + } + + weight = ore_depth_weight(y, 20, 0); + if (weight > 0.0) { + cluster = ore_cluster_field(ctx, x, y, z, 0.028, 12000.0); + if (cluster > 0.65) { + chance = 0.01 + weight * 0.12; + h = hash_coords3(x, y, z, seed ^ 0x0BADC0DEu); + if ((h & 0xFFFF) <= (uint32_t)(chance * 65535.0)) { + return BLOCK_REDSTONE_ORE; + } + } + } + + weight = ore_depth_weight(y, 24, 2); + if (weight > 0.0) { + cluster = ore_cluster_field(ctx, x, y, z, 0.026, 15000.0); + if (cluster > 0.67) { + chance = 0.006 + weight * 0.07; + h = hash_coords3(x, y, z, seed ^ 0x1A5150Eu); + if ((h & 0xFFFF) <= (uint32_t)(chance * 65535.0)) { + return BLOCK_LAPIS_ORE; + } + } + } + + weight = ore_depth_weight(y, 32, 0); + if (weight > 0.0) { + cluster = ore_cluster_field(ctx, x, y, z, 0.02, 8000.0); + if (cluster > 0.63) { + double altitude = (double)(col->height - ctx->sea_level); + double mountain = clamp01(altitude / 40.0); + chance = (0.008 + weight * 0.06) * (1.0 + mountain * 0.8); + h = hash_coords3(x, y, z, seed ^ 0x90ADCAFEu); + if ((h & 0xFFFF) <= (uint32_t)(chance * 65535.0)) { + return BLOCK_GOLD_ORE; + } + } + } + + weight = ore_depth_weight(y, 68, -4); + if (weight > 0.0) { + cluster = ore_cluster_field(ctx, x, y, z, 0.018, 6000.0); + if (cluster > 0.58) { + double biome_bonus = (col->biome == BIOME_EAST_KY_RIDGEBREAKS) ? 0.05 : 0.0; + chance = 0.04 + weight * 0.25 + biome_bonus; + h = hash_coords3(x, y, z, seed ^ 0x1B0EFACEu); + if ((h & 0xFFFF) <= (uint32_t)(chance * 65535.0)) { + return BLOCK_IRON_ORE; + } + } + } + + weight = ore_depth_weight(y, 92, 10); + if (weight > 0.0) { + cluster = ore_cluster_field(ctx, x, y, z, 0.015, 4200.0); + if (cluster > 0.62) { + double plains_bonus = (col->biome == BIOME_WEST_KY_COALFIELDS) ? 0.05 : 0.0; + chance = 0.03 + weight * 0.18 + plains_bonus; + h = hash_coords3(x, y, z, seed ^ 0xC0FFEE12u); + if ((h & 0xFFFF) <= (uint32_t)(chance * 65535.0)) { + return BLOCK_COPPER_ORE; + } + } + } + + return BLOCK_STONE; +} + +static int column_has_manmade_surface(chunk_data *chunk, int chunk_x, int chunk_z, int world_x, int world_z) { int local_x = world_x - chunk_x * CHUNK_SIZE; int local_z = world_z - chunk_z * CHUNK_SIZE; if (local_x < 0 || local_x >= CHUNK_SIZE || local_z < 0 || local_z >= CHUNK_SIZE) return 0; @@ -1293,7 +1881,17 @@ static int column_has_trail_surface(chunk_data *chunk, int chunk_x, int chunk_z, uint16_t block = chunk->blocks[y][local_x][local_z]; if (block == BLOCK_AIR) continue; if (block == BLOCK_WATER) return 0; - return block == BLOCK_GRAVEL; + if (block == BLOCK_GRAVEL || 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_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_E_LOWER || block == BLOCK_SPRUCE_DOOR_E_UPPER || + block == BLOCK_SPRUCE_DOOR_W_LOWER || block == BLOCK_SPRUCE_DOOR_W_UPPER) { + return 1; + } + return 0; } return 0; } @@ -1373,7 +1971,7 @@ static void generate_chunk_trees(worldgen_ctx *ctx, int chunk_x, int chunk_z, ch if (surface == BLOCK_SNOW) { base_y = data.height; } - if (column_has_trail_surface(chunk, chunk_x, chunk_z, candidate_x, candidate_z)) { + if (column_has_manmade_surface(chunk, chunk_x, chunk_z, candidate_x, candidate_z)) { block_list_free(&tmp); continue; } @@ -1863,10 +2461,10 @@ void worldgen_generate_chunk(worldgen_ctx *ctx, int chunk_x, int chunk_z, chunk_ if (y == 0) { id = BLOCK_BEDROCK; } else if (y < cd.height - 3) { - if (generate_coal(ctx, chunk_x * CHUNK_SIZE + dx, y, chunk_z * CHUNK_SIZE + dz, cd.height, cd.biome)) { + if (generate_coal(ctx, world_x, y, world_z, cd.height, cd.biome)) { id = BLOCK_COAL; } else { - id = BLOCK_STONE; + id = (int)generate_normal_ores(ctx, world_x, y, world_z, &cd); } } else if (y < cd.height) { id = BLOCK_DIRT; @@ -1886,6 +2484,7 @@ void worldgen_generate_chunk(worldgen_ctx *ctx, int chunk_x, int chunk_z, chunk_ generate_chunk_trails(ctx, chunk_x, chunk_z, columns, out); } + generate_chunk_cabins(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);