Feat/survival prep#1065
Conversation
|
⏱️ Benchmark run finished in 1m 1s 📈 Compared against baseline: 27s time, 900 MB memory 🟢 Generation time is unchanged. 📅 Last benchmark: 2026-05-26 22:17:41 UTC You can retrigger the benchmark by commenting |
There was a problem hiding this comment.
Pull request overview
This PR expands world generation variety and “survival prep” features by improving tree diversity, adding Java chunk biome assignment based on land-cover, optimizing --fillground, and adding deterministic underground ore veins when --fillground is enabled.
Changes:
- Add land-cover-driven biome palettes to Java Anvil chunk NBT (
biomesper section, palette+data packing). - Improve vegetation variety (many new tree variants/species, density modulation, mangrove/willow handling in wetlands).
- Optimize
--fillgroundby bulk-filling fully buried empty sections, and add a new ore vein pass gated on--fillground.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/world_editor/mod.rs | Exposes MIN_SECTION_Y and adds WorldEditor wrapper for bulk-filling buried sections. |
| src/world_editor/java.rs | Plumbs per-chunk biome NBT into chunk creation/writing and updates tests accordingly. |
| src/world_editor/common.rs | Adds MIN_SECTION_Y and implements/test bulk fill of empty chunk sections. |
| src/ground_generation.rs | Uses the bulk-fill fast path to reduce transient allocations during --fillground. |
| src/biome.rs | New module: maps ESA WorldCover to Minecraft biomes and packs 4x4 chunk biome palettes into Anvil format. |
| src/ore_generation.rs | New module: deterministic ore vein placement pass when --fillground is enabled. |
| src/data_processing.rs | Invokes ore generation after ground/building/natural passes when --fillground is on. |
| src/element_processing/tree.rs | Major tree variety expansion (variants, jitter, branches, droops, new species, accents). |
| src/element_processing/natural.rs | Expands tree pools, adds density modulation, wires mangrove/willow wetland spawning. |
| src/element_processing/landuse.rs | Expands tree pools and adds density-modulated forest spawning; avoids cherry/flowering oak in tagged pools. |
| src/block_definitions.rs | Repurposes some block IDs for new leaves/logs and new ore blocks. |
| src/main.rs | Registers new biome and ore_generation modules. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ariety Address feedback that dense oak forests looked like cookie-cutter clones. - 27 shape variants across 9 existing species (Oak: 5, Spruce/Birch/DarkOak: 3 each, others: 2). Per-coord deterministic variant pick via coord_rng salt 1. - Per-instance jitter: trunk height +/-1..+2, ~4% organic leaf gaps via coord-derived hash. - Side branches with tapered octahedral leaf clusters (Manhattan dist <= 2). - Drooping leaf tendrils for Willow / weeping Cherry (8 cardinal+diagonal columns, variable length per direction). - LeafPlacer split into place_core (inner cross + droops, never accent) and place_surface (outermost ring + branch tip, may be accent). Trunk height clamped to canopy_top - 1 so caps always cover the trunk top regardless of jitter. - New species using shape-only variation: Bush (leaf clump, no trunk), AzaleaBush, Willow, FloweringOak (oak silhouette + cherry blossom accents). - New species using repurposed unused block IDs: Mangrove (MANGROVE_LOG=0, MANGROVE_LEAVES=233, AZALEA_LEAVES=234). Wired into wetland=mangrove and 60/40 with Willow for wetland=swamp; resolves the long-standing "TODO implement mangrove" in natural.rs. - Broadleaved/needleleaved/mixed tree pools in landuse.rs and natural.rs expanded with the new variants and species. - Forest density modulated by value_noise_01(x, z, 32) for organic clearings vs thickets; average rate unchanged (~1/30).
Replaces the hardcoded minecraft:plains biome on every chunk with a per-chunk 4x4 biome palette derived from ESA WorldCover land cover, packed into the Anvil 1.18+ per-section biomes NBT. Mapping (latitude- and water-distance-aware): LC_TREE_COVER -> taiga (>55 deg) / jungle (<23.5 deg) / forest (otherwise) LC_SHRUBLAND -> savanna LC_GRASSLAND -> plains LC_CROPLAND -> plains LC_BUILT_UP -> plains (neutral; avoids weird ambience in cities) LC_BARE -> desert LC_SNOW_ICE -> snowy_plains LC_WATER -> ocean (water_distance >= 8) / river (otherwise) LC_WETLAND -> swamp LC_MANGROVES -> mangrove_swamp LC_MOSS -> taiga fallback -> plains Format-aware encoding: - 4x4 LC samples per chunk (one per biome cell, centred in each 4-block footprint). Same compound is cloned across all sections in the chunk because LC is 2D, so biomes are y-invariant. - Palette deduped in first-occurrence order. data array is OMITTED for uniform-biome chunks (palette size 1) -- the common case for arnis since cities sit inside a single land-cover class. - Mixed-biome chunks pack the 64 cell indices into i64 longs using the post-1.16 no-straddle layout (1 bit -> 1 long, 2 bits -> 2 longs, 3 bits -> 4 longs with padding). Cost analysis on a 250 km^2 generation: - ~1-2 seconds added wall-clock (parallelised across regions via rayon) - ~4 MB transient peak per region during save, released after region write - No persistent fields added to Chunk / ChunkToModify / Section Bedrock and Luanti save paths are unchanged; they still default to plains. A separate change can wire LC-driven biomes through bedrock.rs once the Java mapping has been validated in-game.
The "expand broadleaved/mixed tree pools" change in 8eff06c put Cherry and FloweringOak into the explicit OSM-tagged forest pools, giving them ~14% (1 in 7) instead of the intended ~2%. A tagged broadleaved forest ended up looking like a cherry orchard. Both species are now only reachable via the random Tree::create pool at the original low rates (Cherry 2%, FloweringOak 6%), so an OSM-tagged broadleaved/mixed forest contains zero overtly pink trees while untagged contexts (cemeteries, scrub, swamp tree spawns) still see them as the rare specimens they're supposed to be.
--fillground writes STONE to every block from MIN_Y+1 to ground_y-3 per column. For each fresh section the very first STONE write promotes BlockStorage::Uniform(AIR) -> Full(Vec<Block>), allocating 4 KiB. On a 250 km^2 world that is ~3 fully-buried sections per chunk times ~977k chunks times 4 KiB = ~11 GB of transient heap that compact_sections() later collapses back to Uniform at save time. Add a per-chunk pre-pass that, when the chunk is fully inside both the xzbbox and the rotated bbox, computes the highest section whose entire 16-block y span sits strictly below ground_y - 3 for every column, and sets each empty section in [MIN_SECTION_Y, top_buried] directly to Uniform(STONE). The per-column path then raises its y_min to (top_buried + 1) * 16 so it only walks the boundary section. Sections with pre-existing content (e.g. a deep bridge pier) are detected as non-empty, skipped, and the per-column path takes over via the existing skip_existing branch — final block content is bit-for-bit identical to the previous behavior. 4 new unit tests cover empty chunk, occupied chunk, below-min request, and second-call behavior. All 141 tests pass; clippy clean.
Sprinkles vanilla-flavoured ore veins through the underground stone
produced by --fillground. Off when --fillground is off (no stone to
convert).
7 ore types: COAL, IRON, COPPER (existing IDs 127-130) plus DIAMOND,
REDSTONE, LAPIS using IDs 249-251 which were unused dead slots
("red_sand", "red_sandstone", "cactus" — never referenced by any
arnis code). Y ranges, vein sizes, and per-chunk densities are
simplified vanilla 1.21 distributions.
Each chunk is deterministically seeded from (chunk_x, chunk_z, 0xC0DE)
so re-generating the same world places ore in the same spots and the
seed can't collide with the tree-variant or biome RNGs. Each vein is
a short 3D random walk that replaces STONE only — bedrock, air above
surface, buildings, water carved by water_depth, and subway tunnels
are all left intact, so ore placement is safe in any order relative
to those passes.
Single-line // only, drop multi-line // blocks, remove section dividers and over-detailed doc comments per project style.
…s overwritten
The previous ore placement called set_block_absolute(ore, x, y, z, None, None)
which silently no-ops over any non-AIR block. set_block_with_properties_absolute
at mod.rs:892 routes to an else { false } branch when there is an existing block
and no filters are given. So every vein step that landed on stone was a no-op.
Passing Some(&[STONE]) as the whitelist makes the existing-block path match and
write. The earlier check_for_block_absolute pre-gate is kept because, when the
target cell is AIR, the same function's else { true } branch would otherwise
write ore into the air above the surface.
Anchor each ore's Y range to the chunk's local ground level (sampled once at chunk centre) instead of fixed absolute Y. Mountains now carry the full ore column inside their bulk; flat terrain keeps a vanilla-like underground distribution. One get_ground_level call per chunk — under 10 ms across a 250 km^2 world. Drop COPPER_ORE Also: tighten the bulk_fill_chunk_sections_below doc comment to match the implementation (a section already Uniform(block) is treated as occupied and counts against the "all_clean" return) per code review.
ee9265a to
3a29f86
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (2)
src/element_processing/tree.rs:92
SPRUCE_LEAVES_FILL_STANDARDcontains a duplicated column definition((0, 3, -1), (0, 10, -1))(it appears twice). This is redundant work at placement time and may be masking an intended missing column; consider removing the duplicate or replacing it with the intended coordinate.
const SPRUCE_LEAVES_FILL_STANDARD: [(Coord, Coord); 6] = [
((-1, 3, 0), (-1, 10, 0)),
((0, 3, -1), (0, 10, -1)),
((1, 3, 0), (1, 10, 0)),
((0, 3, -1), (0, 10, -1)),
src/element_processing/tree.rs:238
PINE_LEAVES_FILL_STANDARDhas a duplicated entry for((0, 5, -1), (0, 12, -1)). This places the same column twice; consider removing the duplicate or replacing it with the intended missing column.
const PINE_LEAVES_FILL_STANDARD: [(Coord, Coord); 6] = [
((-1, 5, 0), (-1, 12, 0)),
((0, 5, -1), (0, 12, -1)),
((1, 5, 0), (1, 12, 0)),
((0, 5, -1), (0, 12, -1)),
- biome.rs: drop redundant `as u64` cast (c is already u64; -D warnings in CI flagged clippy::unnecessary_cast). - tree.rs: remove duplicate `(0, _, -1)` column from SPRUCE_LEAVES_FILL_* and PINE_LEAVES_FILL_* (carried over from the original SPRUCE_LEAVES_FILL pattern). The duplicate produced the same leaves twice; trimming to 5 entries matches the oak/birch shape and removes wasted writes. - bedrock_block_map.rs: add explicit persistent_bit + update_bit states for mangrove_leaves and azalea_leaves (matching the cherry_leaves pattern) so Bedrock exports don't decay the new leaves. cargo clippy --all-targets --all-features -- -D warnings clean.
No description provided.