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 common src entity player.rs
//! The local player's tick: `EntityPlayerSP.onLivingUpdate` with `EntityPlayer.onLivingUpdate`.
use glam::DVec3;
use super::{Entity, EntityWorld, Sleep, flags};
use crate::world::shape::BlockView;
use crate::world::{Block, bed};
/// The keys of `MovementInputFromOptions`.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct MovementKeys {
pub forward: bool,
pub back: bool,
pub left: bool,
pub right: bool,
pub jump: bool,
pub sneak: bool,
}
/// Player state beyond `EntityLiving`.
#[derive(Clone, Debug, Default)]
pub struct PlayerState {
pub camera_yaw: f32,
pub prev_camera_yaw: f32,
swing_ticks: i32,
pub swinging: bool,
}
impl PlayerState {
/// `swingItem`.
pub fn swing(&mut self) {
self.swing_ticks = -1;
self.swinging = true;
}
pub fn tick_swing(&mut self) -> f32 {
if self.swinging {
self.swing_ticks += 1;
if self.swing_ticks >= 8 {
self.swing_ticks = 0;
self.swinging = false;
}
} else {
self.swing_ticks = 0;
}
self.swing_ticks as f32 / 8.0
}
}
/// `Entity.onUpdate` of the local player: the living update, then movement from `keys`.
pub fn tick(
e: &mut Entity,
state: &mut PlayerState,
keys: MovementKeys,
world: &mut impl EntityWorld,
) {
e.sleep.tick();
e.living_entity_update(world);
let axis = |positive: bool, negative: bool| f32::from(i8::from(positive) - i8::from(negative));
let mut strafe = axis(keys.left, keys.right);
let mut forward = axis(keys.forward, keys.back);
if keys.sneak {
strafe = (f64::from(strafe) * 0.3) as f32;
forward = (f64::from(forward) * 0.3) as f32;
}
let blocked = e.sleep.sleeping;
e.set_flag(flags::SNEAKING, keys.sneak && !blocked);
if keys.sneak && e.y_size < 0.2 {
e.y_size = 0.2;
}
let half = f64::from(e.width) * 0.35;
let y = e.bb.min.y + 0.5;
let (x, z) = (e.pos.x, e.pos.z);
for (dx, dz) in [(-half, half), (-half, -half), (half, -half), (half, half)] {
e.push_out_of_blocks(world, x + dx, y, z + dz);
}
state.prev_camera_yaw = state.camera_yaw;
let swing = state.tick_swing();
if let Some(living) = &mut e.living {
living.swing_progress = swing;
if living.health > 0 && !blocked {
living.move_strafing = strafe;
living.move_forward = forward;
living.jumping = keys.jump;
}
}
e.living_movement(world);
let mut bob = (e.motion.x * e.motion.x + e.motion.z * e.motion.z).sqrt() as f32;
let mut tilt = ((-e.motion.y * f64::from(0.2_f32)).atan() as f32) * 15.0;
let dead = e.living.as_ref().is_some_and(|l| l.health <= 0);
bob = bob.min(0.1);
if !e.on_ground || dead {
bob = 0.0;
}
if e.on_ground || dead {
tilt = 0.0;
}
state.camera_yaw += (bob - state.camera_yaw) * 0.4;
if let Some(living) = &mut e.living {
living.camera_pitch += (tilt - living.camera_pitch) * 0.8;
}
e.update_body_rotation();
}
/// `EntityPlayer.sleepInBedAt` once its checks passed: lies down in the bed at `bed`.
pub fn lie_down(entity: &mut Entity, world: &impl EntityWorld, bed: [i32; 3]) {
let [x, y, z] = bed;
entity.set_size(0.2, 0.2);
entity.y_offset = 0.2;
let (dx, dz) = if world.chunks_exist(bed, bed) {
match bed::direction(world.metadata(x, y, z)) {
0 => (0.5, 0.9),
1 => (0.1, 0.5),
2 => (0.5, 0.1),
_ => (0.9, 0.5),
}
} else {
(0.5, 0.5)
};
entity.set_position(DVec3::new(
f64::from(x as f32 + dx),
f64::from(y as f32 + 15.0 / 16.0),
f64::from(z as f32 + dz),
));
entity.sleep = Sleep {
sleeping: true,
bed: Some(bed),
..Sleep::default()
};
entity.motion = DVec3::ZERO;
}
/// `EntityPlayer.wakeUpPlayer` without its world side effects: stands up beside the bed,
/// at `y_offset` above the feet.
pub fn get_up(entity: &mut Entity, world: &impl BlockView, y_offset: f32, reset_timer: bool) {
entity.set_size(0.6, 1.8);
entity.y_offset = y_offset;
if let Some(bed @ [x, y, z]) = entity.sleep.bed
&& world.block(x, y, z) == Block::BED
{
let [sx, sy, sz] = bed::standing_spot(world, bed, 0).unwrap_or([x, y + 1, z]);
entity.set_position(DVec3::new(
f64::from(sx as f32 + 0.5),
f64::from(sy as f32 + y_offset + 0.1),
f64::from(sz as f32 + 0.5),
));
}
entity.sleep.sleeping = false;
entity.sleep.timer = if reset_timer { 0 } else { 100 };
}