alex/beta-minecraft-rust
Minecraft Beta 1.7.3 Rewrite
BRANCH main
SNAPSHOT Draw terrain GPU-driven from packed per-section buffers with GPU occlusion culling, add a render distance slider (2-128) with a quad/disk shape, cut chunk bookkeeping at high render distances, and fix a light underflow at y=0
DOWNLOAD
root crates server src populate mod.rs
//! Port of `ChunkProviderGenerate.populate` and the `WorldGenerator` features it places.
mod big_tree;
mod dungeons;
mod lakes;
mod ores;
mod plants;
mod springs;
pub(crate) mod trees;
use common::JavaRandom;
use common::biome::Biome;
use common::world::{Block, ChunkPos, Material};
use crate::level::Level;
use crate::terrain::{Generator, OverworldGenerator};
mod nether;
/// `IChunkProvider.populate` of the level's dimension.
pub fn populate(level: &mut Level, generator: &Generator, pos: ChunkPos) {
level.instant_falling = true;
match generator {
Generator::Overworld(generator) => populate_overworld(level, generator, pos),
Generator::Nether(_) => nether::populate(level, pos),
}
level.instant_falling = false;
}
/// Decorates the 16x16 area offset by 8 blocks from the chunk origin, so features spill
/// into the three neighbors that must already be loaded.
fn populate_overworld(level: &mut Level, generator: &OverworldGenerator, pos: ChunkPos) {
let (x0, z0) = (pos.min_block_x(), pos.min_block_z());
let biome = generator.climate.sample(x0 + 16, z0 + 16, 1, 1).biomes[0];
let seed = level.seed();
let mut rand = JavaRandom::new(seed);
let a = rand.next_long() / 2 * 2 + 1;
let b = rand.next_long() / 2 * 2 + 1;
rand.set_seed(
i64::from(pos.x)
.wrapping_mul(a)
.wrapping_add(i64::from(pos.z).wrapping_mul(b))
^ seed,
);
let rand = &mut rand;
let spread = |rand: &mut JavaRandom, base: i32| base + rand.next_int(16) + 8;
let point = |rand: &mut JavaRandom| [spread(rand, x0), rand.next_int(128), spread(rand, z0)];
let corner = |rand: &mut JavaRandom| {
[
x0 + rand.next_int(16),
rand.next_int(128),
z0 + rand.next_int(16),
]
};
if rand.next_int(4) == 0 {
lakes::generate(level, point(rand), rand, Block::WATER);
}
if rand.next_int(8) == 0 {
let x = spread(rand, x0);
let bound = rand.next_int(120) + 8;
let y = rand.next_int(bound);
let z = spread(rand, z0);
if y < 64 || rand.next_int(10) == 0 {
lakes::generate(level, [x, y, z], rand, Block::LAVA);
}
}
for _ in 0..8 {
dungeons::generate(level, point(rand), rand);
}
for _ in 0..10 {
ores::clay(level, corner(rand), rand, 32);
}
let veins: [(Block, i32, i32, i32); 8] = [
(Block::DIRT, 32, 20, 128),
(Block::GRAVEL, 32, 10, 128),
(Block::COAL_ORE, 16, 20, 128),
(Block::IRON_ORE, 8, 20, 64),
(Block::GOLD_ORE, 8, 2, 32),
(Block::REDSTONE_ORE, 7, 8, 16),
(Block::DIAMOND_ORE, 7, 1, 16),
(Block::LAPIS_ORE, 6, 1, 0),
];
for (ore, size, count, max_y) in veins {
for _ in 0..count {
let x = x0 + rand.next_int(16);
let y = if ore == Block::LAPIS_ORE {
rand.next_int(16) + rand.next_int(16)
} else {
rand.next_int(max_y)
};
let z = z0 + rand.next_int(16);
ores::vein(level, [x, y, z], rand, ore, size);
}
}
let noise = generator
.tree_noise
.sample_2d(f64::from(x0) * 0.5, f64::from(z0) * 0.5);
let density = ((noise / 8.0 + rand.next_double() * 4.0 + 4.0) / 3.0) as i32;
let mut trees = i32::from(rand.next_int(10) == 0);
trees += match biome {
Biome::Forest | Biome::Rainforest | Biome::Taiga => density + 5,
Biome::SeasonalForest => density + 2,
Biome::Desert | Biome::Tundra | Biome::Plains => -20,
_ => 0,
};
for _ in 0..trees {
let (x, z) = (spread(rand, x0), spread(rand, z0));
let tree = trees::Kind::pick(biome, rand);
let y = level.height(x, z);
tree.generate(level, [x, y, z], rand);
}
let dandelions = match biome {
Biome::Forest | Biome::Taiga => 2,
Biome::SeasonalForest => 4,
Biome::Plains => 3,
_ => 0,
};
for _ in 0..dandelions {
plants::flowers(level, point(rand), rand, Block::DANDELION);
}
let grass = match biome {
Biome::Forest | Biome::SeasonalForest => 2,
Biome::Rainforest | Biome::Plains => 10,
Biome::Taiga => 1,
_ => 0,
};
for _ in 0..grass {
let fern = biome == Biome::Rainforest && rand.next_int(3) != 0;
plants::tall_grass(level, point(rand), rand, if fern { 2 } else { 1 });
}
let (dead_bushes, cacti) = if biome == Biome::Desert {
(2, 10)
} else {
(0, 0)
};
for _ in 0..dead_bushes {
plants::dead_bushes(level, point(rand), rand);
}
for (chance, plant) in [
(2, Block::ROSE),
(4, Block::BROWN_MUSHROOM),
(8, Block::RED_MUSHROOM),
] {
if rand.next_int(chance) == 0 {
plants::flowers(level, point(rand), rand, plant);
}
}
for _ in 0..10 {
plants::sugar_cane(level, point(rand), rand);
}
if rand.next_int(32) == 0 {
plants::pumpkins(level, point(rand), rand);
}
for _ in 0..cacti {
plants::cacti(level, point(rand), rand);
}
for _ in 0..50 {
let x = spread(rand, x0);
let bound = rand.next_int(120) + 8;
let y = rand.next_int(bound);
let z = spread(rand, z0);
springs::generate(level, [x, y, z], Block::FLOWING_WATER);
}
for _ in 0..20 {
let x = spread(rand, x0);
let inner = rand.next_int(112) + 8;
let bound = rand.next_int(inner) + 8;
let y = rand.next_int(bound);
let z = spread(rand, z0);
springs::generate(level, [x, y, z], Block::FLOWING_LAVA);
}
let temperatures = generator.climate.temperatures(x0 + 8, z0 + 8, 16, 16);
for (dx, x) in (x0 + 8..x0 + 24).enumerate() {
for (dz, z) in (z0 + 8..z0 + 24).enumerate() {
let y = level.top_solid_or_liquid(x, z);
let temperature = temperatures[dx * 16 + dz] - f64::from(y - 64) / 64.0 * 0.3;
if temperature < 0.5
&& y > 0
&& y < 128
&& level.is_air(x, y, z)
&& level.material(x, y - 1, z).is_solid()
&& level.material(x, y - 1, z) != Material::Ice
{
level.set_block_notify(x, y, z, Block::SNOW_LAYER);
}
}
}
}