Tune redwoods cabins and chunk heightmaps
This commit is contained in:
Binary file not shown.
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
Reference in New Issue
Block a user