Compare commits
11 Commits
f93ebff0b9
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a06f34d99 | ||
|
|
e2436f6e24 | ||
|
|
afbf333622 | ||
|
|
acd5eaa52f | ||
|
|
84a0435312 | ||
|
|
46f1d24e9d | ||
|
|
aed76c3b1b | ||
|
|
95bd106a3b | ||
|
|
127e706bcb | ||
|
|
335b35d416 | ||
|
|
d0f3c9a048 |
19
README.md
19
README.md
@@ -74,11 +74,30 @@ Features
|
||||
- Redwoods are enabled automatically. The biome classifier marks high-rainfall,
|
||||
higher-relief areas as redwood forest, then places titan trees, dirt/mulch
|
||||
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
|
||||
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.
|
||||
- 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` 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
|
||||
-----------------
|
||||
|
||||
Binary file not shown.
@@ -61,7 +61,19 @@
|
||||
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,
|
||||
BLOCK_IRON_BARS_NS = 60,
|
||||
BLOCK_IRON_BARS_EW = 61,
|
||||
BLOCK_SPRUCE_STAIRS_N = 62,
|
||||
BLOCK_SPRUCE_STAIRS_S = 63
|
||||
};
|
||||
|
||||
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);
|
||||
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_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
|
||||
|
||||
@@ -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_W[] = {{"facing", "west"}, {"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 int32_t DATA_VERSION = 2730; /* Java Edition 1.17.1; includes copper ore. */
|
||||
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_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},
|
||||
[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) {
|
||||
@@ -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) {
|
||||
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) {
|
||||
uint64_t value = indices[idx];
|
||||
size_t bit_index = idx * (size_t)bits_per_value;
|
||||
size_t long_id = bit_index / 64;
|
||||
size_t offset = bit_index % 64;
|
||||
size_t long_id = idx / (size_t)values_per_long;
|
||||
size_t offset = (idx % (size_t)values_per_long) * (size_t)bits_per_value;
|
||||
if (long_id >= out_count) continue;
|
||||
uint64_t *target = (uint64_t *)&out_longs[long_id];
|
||||
*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) {
|
||||
int y_base = section_y * 16;
|
||||
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));
|
||||
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));
|
||||
if (!packed) return;
|
||||
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) {
|
||||
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];
|
||||
pack_heightmap(chunk, heightmap, 37);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@ static int is_cabin_block(uint16_t block) {
|
||||
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_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_SPRUCE_DOOR_N_LOWER || block == BLOCK_SPRUCE_DOOR_N_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 gravel_columns = 0;
|
||||
long cabin_gravel_columns = 0;
|
||||
long bridge_deck_columns = 0;
|
||||
long eligible_bridge_columns = 0;
|
||||
long tall_log_columns = 0;
|
||||
long max_oak_log_run = 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];
|
||||
double redwood_mask = worldgen_debug_redwood_mask(&ctx, wx, wz);
|
||||
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_gravel = 0;
|
||||
int has_bridge_deck = 0;
|
||||
int current_run = 0;
|
||||
int best_run = 0;
|
||||
for (int y = 1; y < CHUNK_HEIGHT; ++y) {
|
||||
@@ -109,6 +115,8 @@ int main(int argc, char **argv) {
|
||||
if (block == BLOCK_GRAVEL) {
|
||||
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) {
|
||||
++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 (has_cabin) ++cabin_columns;
|
||||
if (has_gravel) ++gravel_columns;
|
||||
if (has_bridge_deck) ++bridge_deck_columns;
|
||||
if (has_cabin && has_gravel) {
|
||||
++cabin_gravel_columns;
|
||||
}
|
||||
@@ -133,6 +142,8 @@ int main(int argc, char **argv) {
|
||||
printf("cabin_columns=%ld\n", cabin_columns);
|
||||
printf("gravel_columns=%ld\n", 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("max_oak_log_run=%ld\n", max_oak_log_run);
|
||||
printf("biome_west_ky=%ld\n", biome_columns[0]);
|
||||
|
||||
Reference in New Issue
Block a user