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 fishing.rs
use common::entity::{Entity, EntityWorld};
use common::item::{Item, ItemStack};
use common::math::floor_f64;
use common::world::shape::BlockView;
use glam::DVec3;
use super::projectiles::{heading, smooth_angles};
use super::{Kind, Stuck, velocity_packet};
use crate::level::{DroppedItem, Level};
#[derive(Clone, Debug)]
pub struct Hook {
pub owner: i32,
pub caught: Option<i32>,
pub catchable: i32,
pub stuck: Stuck,
}
impl Level {
pub fn fish(&mut self, owner: &Entity) -> i32 {
let existing = self
.entities
.iter()
.find(|e| matches!(&e.kind, Kind::Hook(h) if h.owner == owner.id))
.map(|e| e.entity.id);
if let Some(id) = existing {
let Some(mut stored) = self.entities.remove(id) else {
return 0;
};
let Kind::Hook(hook) = &stored.kind else {
return 0;
};
let delta = owner.pos - stored.entity.pos;
let lift = f64::from((f64::from(delta.length() as f32)).sqrt() as f32) * 0.08;
let motion = delta * 0.1 + DVec3::Y * lift;
let mut wear = 0;
if let Some(caught) = hook.caught.and_then(|id| self.entities.get_mut(id)) {
caught.entity.motion += motion;
self.events.push(velocity_packet(&caught.entity));
wear = 3;
} else if hook.catchable > 0 {
self.add_stat(owner.id, 2025, 1);
self.dropped_items.push(DroppedItem {
x: stored.entity.pos.x,
y: stored.entity.pos.y,
z: stored.entity.pos.z,
stack: ItemStack::one(Item::RAW_FISH),
motion: Some(motion),
impulse: glam::DVec3::ZERO,
pickup_delay: 0,
});
wear = 1;
}
if hook.stuck.grounded {
wear = 2;
}
stored.entity.dead = true;
wear
} else {
let mut stored = self.entities.create(Kind::Hook(Hook {
owner: owner.id,
caught: None,
catchable: 0,
stuck: Stuck::default(),
}));
let entity = &mut stored.entity;
let yaw = owner.yaw.to_radians();
let at = owner.pos
+ DVec3::new(
-f64::from(common::math::cos(yaw) * 0.16),
1.62 - f64::from(owner.y_offset) - f64::from(0.1_f32),
-f64::from(common::math::sin(yaw) * 0.16),
);
entity.set_location_and_angles(at, owner.yaw, owner.pitch);
heading(entity, owner.look() * f64::from(0.4_f32), 1.5, 1.0);
let pitch = 0.4 / (self.rand.next_float() * 0.4 + 0.8);
self.play_sound(owner, "random.bow", 0.5, pitch);
self.entities.insert(stored);
0
}
}
pub(super) fn tick_hook(&mut self, entity: &mut Entity, hook: &mut Hook) {
entity.base_update(self);
let fishing = self.entities.get(hook.owner).is_some_and(|e| {
!e.entity.dead
&& e.entity.living.as_ref().is_some_and(|l| l.health > 0)
&& matches!(e.kind, Kind::Player { held: Some(stack), .. } if stack.item == Item::FISHING_ROD)
&& entity.pos.distance_squared(e.entity.pos) <= 1024.0
});
if !fishing {
entity.dead = true;
return;
}
if let Some(caught) = hook
.caught
.and_then(|id| self.entities.get(id))
.filter(|e| !e.entity.dead)
{
entity.set_position(
caught
.entity
.pos
.with_y(caught.entity.bb.min.y + f64::from(caught.entity.height) * 0.8),
);
return;
}
hook.caught = None;
let stuck = &mut hook.stuck;
if self.stays_stuck(entity, stuck) {
return;
}
let (hit, target) = self.projectile_hit(entity, false, Some(hook.owner), stuck.air_ticks);
if let Some(target) = target {
let owner = self.entity_copy(Some(hook.owner));
if self.attack_entity(target, owner.as_ref(), 0) {
hook.caught = Some(target);
}
} else if let Some(hit) = hit {
stuck.grounded = true;
stuck.tile = [hit.x, hit.y, hit.z];
stuck.block = BlockView::block(self, hit.x, hit.y, hit.z);
return;
}
entity.move_entity(self, entity.motion);
smooth_angles(entity);
let mut drag = if entity.on_ground || entity.collided_horizontally {
0.5_f32
} else {
0.92_f32
};
let water = self.submerged(entity, 0.0);
if water > 0.0 {
if hook.catchable > 0 {
hook.catchable -= 1;
} else {
let [x, y, z] = entity.pos.to_array().map(floor_f64);
if entity.rand.next_int(if self.rained_on(x, y + 1, z) {
300
} else {
500
}) == 0
{
hook.catchable = entity.rand.next_int(30) + 10;
entity.motion.y -= f64::from(0.2_f32);
let pitch = 1.0 + (entity.rand.next_float() - entity.rand.next_float()) * 0.4;
self.play_sound(entity, "random.splash", 0.25, pitch);
for bubble in [true, false] {
for _ in 0..6 {
let x = (entity.rand.next_float() * 2.0 - 1.0) * entity.width;
let z = (entity.rand.next_float() * 2.0 - 1.0) * entity.width;
let position = entity
.pos
.with_y(f64::from(floor_f64(entity.bb.min.y) as f32 + 1.0))
+ DVec3::new(f64::from(x), 0.0, f64::from(z));
let motion = if bubble {
entity.motion - DVec3::Y * f64::from(entity.rand.next_float() * 0.2)
} else {
entity.motion
};
self.spawn_particle(
if bubble { "bubble" } else { "splash" },
position,
motion,
);
}
}
}
}
}
if hook.catchable > 0 {
entity.motion.y -= f64::from(
entity.rand.next_float() * entity.rand.next_float() * entity.rand.next_float(),
) * 0.2;
}
entity.motion.y += f64::from(0.04_f32) * (water * 2.0 - 1.0);
if water > 0.0 {
drag = (f64::from(drag) * 0.9) as f32;
entity.motion.y *= 0.8;
}
entity.motion *= f64::from(drag);
}
}