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 blocks fire.rs
use common::world::Block;
use common::world::shape::BlockView;
use crate::level::Level;
fn encouragement(level: &Level, [x, y, z]: [i32; 3]) -> i32 {
common::interaction::OFFSETS
.iter()
.map(|[dx, dy, dz]| {
BlockView::block(level, x + dx, y + dy, z + dz)
.fire_rates()
.0
})
.max()
.unwrap_or(0)
}
pub fn supported(level: &Level, x: i32, y: i32, z: i32) -> bool {
BlockView::block(level, x, y - 1, z).is_normal_cube() || encouragement(level, [x, y, z]) > 0
}
pub fn added(level: &mut Level, x: i32, y: i32, z: i32) {
if level.block(x, y - 1, z) == Block::OBSIDIAN && super::portal::try_create(level, x, y, z) {
return;
}
if supported(level, x, y, z) {
level.schedule_tick(x, y, z, Block::FIRE, 40);
} else {
level.set_block_notify(x, y, z, Block::AIR);
}
}
/// Rain reaching the block or one beside it.
fn rain_near(level: &Level, x: i32, y: i32, z: i32) -> bool {
level.rained_on(x, y, z)
|| super::SIDES
.iter()
.any(|[dx, dz]| level.rained_on(x + dx, y, z + dz))
}
/// `BlockFire.updateTick`: ages, burns out, spreads, and goes out in the rain.
pub fn tick(level: &mut Level, x: i32, y: i32, z: i32) {
let eternal = BlockView::block(level, x, y - 1, z) == Block::NETHERRACK;
if !supported(level, x, y, z) {
level.set_block_notify(x, y, z, Block::AIR);
}
if !eternal && level.weather.is_raining() && rain_near(level, x, y, z) {
level.set_block_notify(x, y, z, Block::AIR);
return;
}
let age = level.metadata(x, y, z);
if age < 15 {
let next = age + (level.rand.next_int(3) / 2) as u8;
level.set_metadata(x, y, z, next);
}
level.schedule_tick(x, y, z, Block::FIRE, 40);
if !eternal && encouragement(level, [x, y, z]) == 0 {
if !BlockView::block(level, x, y - 1, z).is_normal_cube() || age > 3 {
level.set_block_notify(x, y, z, Block::AIR);
}
return;
}
if !eternal
&& BlockView::block(level, x, y - 1, z).fire_rates().0 == 0
&& age == 15
&& level.rand.next_int(4) == 0
{
level.set_block_notify(x, y, z, Block::AIR);
return;
}
for [dx, dy, dz] in [
[1, 0, 0],
[-1, 0, 0],
[0, -1, 0],
[0, 1, 0],
[0, 0, -1],
[0, 0, 1],
] {
let [x, y, z] = [x + dx, y + dy, z + dz];
let block = level.block(x, y, z);
if level.rand.next_int(if dy == 0 { 300 } else { 250 }) < block.fire_rates().1 {
if level.rand.next_int(i32::from(age) + 10) < 5 && !level.rained_on(x, y, z) {
let next = (age + (level.rand.next_int(5) / 4) as u8).min(15);
level.set_block_with_metadata_notify(x, y, z, Block::FIRE, next);
} else {
level.set_block_notify(x, y, z, Block::AIR);
}
if block == Block::TNT {
level.prime_tnt(glam::IVec3::new(x, y, z).as_dvec3() + 0.5, false);
}
}
}
for tx in x - 1..=x + 1 {
for tz in z - 1..=z + 1 {
for ty in y - 1..=y + 4 {
if [tx, ty, tz] == [x, y, z] || !level.is_air(tx, ty, tz) {
continue;
}
let encouragement = encouragement(level, [tx, ty, tz]);
if encouragement <= 0 {
continue;
}
let chance = (encouragement + 40) / (i32::from(age) + 30);
let distance = 100 + (ty - y - 1).max(0) * 100;
// The original checks the western neighbor in the fire's own row
if chance > 0
&& level.rand.next_int(distance) <= chance
&& (!level.weather.is_raining() || !level.rained_on(tx, ty, tz))
&& !level.rained_on(tx - 1, ty, z)
&& !level.rained_on(tx + 1, ty, tz)
&& !level.rained_on(tx, ty, tz - 1)
&& !level.rained_on(tx, ty, tz + 1)
{
let next = (age + (level.rand.next_int(5) / 4) as u8).min(15);
level.set_block_with_metadata_notify(tx, ty, tz, Block::FIRE, next);
}
}
}
}
}