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 entity vehicles boat.rs
use common::entity::vehicle::VehiclePose;
use common::entity::{Entity, EntityWorld};
use common::item::{Item, ItemStack};
use common::math::floor_f64;
use common::world::Block;
use glam::DVec3;
use crate::entity::Kind;
use crate::level::Level;
#[derive(Clone, Debug)]
pub struct Boat {
pub pose: VehiclePose,
}
impl Default for Boat {
fn default() -> Self {
Self {
pose: VehiclePose {
direction: 1,
..Default::default()
},
}
}
}
impl Level {
pub fn spawn_boat(&mut self, at: DVec3) {
let mut stored = self.entities.create(Kind::Boat(Boat::default()));
let entity = &mut stored.entity;
entity.set_position(at + DVec3::Y * f64::from(entity.y_offset));
self.spawn(stored);
}
pub(crate) fn break_boat(&mut self, entity: &mut Entity) {
if entity.dead {
return;
}
entity.dead = true;
for _ in 0..3 {
self.mob_drop(entity, ItemStack::one(Item::from_block(Block::PLANKS)));
}
for _ in 0..2 {
self.mob_drop(entity, ItemStack::one(Item::STICK));
}
self.eject_rider(entity);
}
pub(crate) fn hurt_boat(&mut self, entity: &mut Entity, boat: &mut Boat, amount: i32) -> bool {
boat.pose.direction = -boat.pose.direction;
boat.pose.hit = 10;
boat.pose.damage += amount * 10;
if boat.pose.damage > 40 {
self.break_boat(entity);
}
true
}
pub(crate) fn tick_boat(&mut self, entity: &mut Entity, boat: &mut Boat) {
entity.base_update(self);
let damage = std::mem::take(&mut entity.damage_received);
if damage > 0 {
self.hurt_boat(entity, boat, damage);
}
boat.pose.hit = (boat.pose.hit - 1).max(0);
boat.pose.damage = (boat.pose.damage - 1).max(0);
let water = self.submerged(entity, 0.125);
if water < 1.0 {
entity.motion.y += f64::from(0.04_f32) * (water * 2.0 - 1.0);
} else {
if entity.motion.y < 0.0 {
entity.motion.y /= 2.0;
}
entity.motion.y += f64::from(0.007_f32);
}
if let Some(rider) = entity.rider.and_then(|id| self.entities.get(id)) {
entity.motion.x += rider.entity.motion.x * 0.2;
entity.motion.z += rider.entity.motion.z * 0.2;
}
entity.motion.x = entity.motion.x.clamp(-0.4, 0.4);
entity.motion.z = entity.motion.z.clamp(-0.4, 0.4);
if entity.on_ground {
entity.motion *= 0.5;
}
entity.move_entity(self, entity.motion);
// Fire and cactus touched while moving hurt it as well
let damage = std::mem::take(&mut entity.damage_received);
if damage > 0 {
self.hurt_boat(entity, boat, damage);
}
let speed = (entity.motion.x * entity.motion.x + entity.motion.z * entity.motion.z).sqrt();
if speed > 0.15 {
let yaw = f64::from(entity.yaw) * std::f64::consts::PI / 180.0;
let (sin, cos) = yaw.sin_cos();
for _ in 0..(1.0 + speed * 60.0).ceil() as i32 {
let along = f64::from(entity.rand.next_float() * 2.0 - 1.0);
let side = f64::from(entity.rand.next_int(2) * 2 - 1) * 0.7;
let (x, z) = if entity.rand.next_bool() {
(
entity.pos.x - cos * along * 0.8 + sin * side,
entity.pos.z - sin * along * 0.8 - cos * side,
)
} else {
(
entity.pos.x + cos + sin * along * 0.7,
entity.pos.z + sin - cos * along * 0.7,
)
};
self.spawn_particle(
"splash",
DVec3::new(x, entity.pos.y - 0.125, z),
entity.motion,
);
}
}
if entity.collided_horizontally && speed > 0.15 {
self.break_boat(entity);
} else {
entity.motion *= DVec3::new(
f64::from(0.99_f32),
f64::from(0.95_f32),
f64::from(0.99_f32),
);
}
entity.pitch = 0.0;
let delta = entity.prev_pos - entity.pos;
if delta.x * delta.x + delta.z * delta.z > 0.001 {
let yaw = (delta.z.atan2(delta.x) * 180.0 / std::f64::consts::PI) as f32;
let turn = ((yaw - entity.yaw + 180.0).rem_euclid(360.0) - 180.0).clamp(-20.0, 20.0);
entity.yaw += turn;
}
let area = entity
.bb
.inflate(DVec3::new(f64::from(0.2_f32), 0.0, f64::from(0.2_f32)));
let ids: Vec<i32> = self
.entities
.near(&area)
.filter(|other| {
matches!(other.kind, Kind::Boat(_))
&& !other.entity.dead
&& other.entity.bb.intersects(&area)
&& Some(other.entity.id) != entity.rider
})
.map(|other| other.entity.id)
.collect();
for id in ids {
if let Some(other) = self.entities.get_mut(id) {
let delta = other.entity.pos - entity.pos;
let max = delta.x.abs().max(delta.z.abs());
if max >= 0.01 {
let distance = max.sqrt();
let push = delta.with_y(0.0) / distance * (1.0 / distance).min(1.0) * 0.05;
entity.motion -= push;
other.entity.motion += push;
}
}
}
for corner in 0..4 {
let x = floor_f64(entity.pos.x + (f64::from(corner % 2) - 0.5) * 0.8);
let y = floor_f64(entity.pos.y);
let z = floor_f64(entity.pos.z + (f64::from(corner / 2) - 0.5) * 0.8);
if self.block(x, y, z) == Block::SNOW_LAYER {
self.set_block_notify(x, y, z, Block::AIR);
}
}
}
}