Theme

alex/beta-minecraft-rust

Minecraft Beta 1.7.3 Rewrite

BRANCH main
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
Download file

root / crates / server / src / entity / fireball.rs

use common::entity::{Entity, EntityWorld};
use glam::DVec3;

use super::{Kind, Stuck};
use crate::level::Level;

#[derive(Clone, Debug, Default)]
pub struct Fireball {
    pub owner: Option<i32>,
    pub acceleration: DVec3,
    pub stuck: Stuck,
    pub shake: i32,
}

impl Level {
    pub(super) fn shoot_fireball(&mut self, owner: &Entity, direction: DVec3) {
        let mut stored = self.entities.create(Kind::Fireball(Fireball::default()));
        let entity = &mut stored.entity;
        let scatter = DVec3::from_array(std::array::from_fn(|_| entity.rand.next_gaussian()));
        let direction = direction + scatter * 0.4;
        let look = owner.look();
        let offset = DVec3::new(
            look.x * 4.0,
            f64::from(owner.height / 2.0) + 0.5,
            look.z * 4.0,
        );
        entity.set_location_and_angles(owner.pos + offset, owner.yaw, owner.pitch);
        stored.kind = Kind::Fireball(Fireball {
            owner: Some(owner.id),
            acceleration: direction / f64::from(direction.length() as f32) * 0.1,
            ..Default::default()
        });
        self.entities.insert(stored);
    }

    pub(super) fn tick_fireball(&mut self, entity: &mut Entity, fireball: &mut Fireball) {
        entity.base_update(self);
        entity.fire = 10;
        fireball.shake = (fireball.shake - 1).max(0);
        if self.stays_stuck(entity, &mut fireball.stuck) {
            return;
        }
        let owner = fireball.owner.filter(|_| fireball.stuck.air_ticks < 25);
        let (hit, target) = self.projectile_hit(entity, false, owner, 0);
        if hit.is_some() || target.is_some() {
            if let Some(target) = target {
                let source = self.entity_copy(fireball.owner);
                self.attack_entity(target, source.as_ref(), 0);
            }
            self.explode(entity.pos, 1.0, None, true);
            entity.dead = true;
            return;
        }
        entity.set_position(entity.pos + entity.motion);
        // `inWater` from the start of the tick
        entity.motion = (entity.motion + fireball.acceleration) * self.drag(entity, 0.95);
        self.spawn_particle("smoke", entity.pos + DVec3::Y * 0.5, DVec3::ZERO);
    }
}