mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
* chore(bedrock): Update most of the packets to mirror the official docs more closely. * Fix typo * Fix CCreativeContent * Undo unrelated `registry.rs` change * Update WIT to merged PR --------- Signed-off-by: Demetrius Kanios <demetrius@kanios.net>
156 lines
4.9 KiB
Rust
156 lines
4.9 KiB
Rust
use crate::{
|
|
entity::{Entity, EntityBase, EntityBaseFuture, projectile::ThrownItemEntity},
|
|
server::Server,
|
|
world::World,
|
|
};
|
|
use pumpkin_data::entity::EntityStatus;
|
|
use pumpkin_protocol::bedrock::server::actor_event::ActorEventID;
|
|
use pumpkin_protocol::{codec::optional_int::OptionalInt, java::client::play::Metadata};
|
|
use pumpkin_util::{
|
|
math::vector3::Vector3,
|
|
random::{RandomGenerator, RandomImpl, get_seed, xoroshiro128::Xoroshiro},
|
|
};
|
|
use std::sync::atomic::AtomicBool;
|
|
use std::sync::{
|
|
Arc,
|
|
atomic::{AtomicU32, Ordering},
|
|
};
|
|
|
|
const GRAVITY: f64 = 0.0;
|
|
|
|
pub struct FireworkRocketEntity {
|
|
entity: ThrownItemEntity,
|
|
life: AtomicU32,
|
|
life_time: AtomicU32,
|
|
}
|
|
|
|
impl FireworkRocketEntity {
|
|
pub fn new(entity: Entity) -> Self {
|
|
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(get_seed()));
|
|
|
|
entity.set_velocity(Vector3::new(
|
|
random.next_triangular(0.0, 0.002_297),
|
|
0.05,
|
|
random.next_triangular(0.0, 0.002_297),
|
|
));
|
|
Self {
|
|
entity: ThrownItemEntity {
|
|
entity,
|
|
owner_id: None,
|
|
collides_with_projectiles: false,
|
|
has_hit: AtomicBool::new(false),
|
|
gravity: GRAVITY,
|
|
},
|
|
life: 0.into(),
|
|
// TODO
|
|
life_time: (10 + random.next_bounded_i32(6) as u32 + random.next_bounded_i32(7) as u32)
|
|
.into(),
|
|
}
|
|
}
|
|
|
|
pub fn new_shot(entity: Entity, shooter: &Entity) -> Self {
|
|
let mut random = RandomGenerator::Xoroshiro(Xoroshiro::from_seed(get_seed()));
|
|
|
|
// Set random initial velocity
|
|
// Set on the inner entity after constructing ThrownItemEntity
|
|
let thrown = ThrownItemEntity::new(entity, shooter, GRAVITY);
|
|
thrown.entity.set_velocity(Vector3::new(
|
|
random.next_triangular(0.0, 0.002_297),
|
|
0.05,
|
|
random.next_triangular(0.0, 0.002_297),
|
|
));
|
|
|
|
// Set random life
|
|
let rocket = Self {
|
|
entity: thrown,
|
|
life: 0.into(),
|
|
life_time: (10 + random.next_bounded_i32(6) as u32 + random.next_bounded_i32(7) as u32)
|
|
.into(),
|
|
};
|
|
|
|
// Set shooter metadata
|
|
rocket.entity.entity.send_meta_data(
|
|
&[Metadata::new(
|
|
pumpkin_data::tracked_data::firework_rocket::ATTACHED_TO_TARGET,
|
|
OptionalInt(Some(shooter.entity_id)),
|
|
)],
|
|
None,
|
|
);
|
|
|
|
rocket
|
|
}
|
|
|
|
pub async fn explode_and_remove(&self, world: &World) {
|
|
let entity = self.get_entity();
|
|
world.send_entity_status(
|
|
entity,
|
|
EntityStatus::FireworksExplode,
|
|
Some(ActorEventID::FireworksExplode),
|
|
);
|
|
|
|
// TODO: Explode/colors
|
|
|
|
entity.remove().await;
|
|
}
|
|
}
|
|
|
|
impl EntityBase for FireworkRocketEntity {
|
|
fn tick<'a>(
|
|
&'a self,
|
|
caller: &'a Arc<dyn EntityBase>,
|
|
server: &'a Server,
|
|
) -> EntityBaseFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
self.entity.process_tick(caller, server).await;
|
|
|
|
let entity = self.get_entity();
|
|
let world = entity.world.load();
|
|
let mut velocity = entity.velocity.load();
|
|
|
|
if let Some(shooter_id) = self.entity.owner_id {
|
|
// Check if the player who fired this rocket still exists in the world
|
|
if let Some(shooter) = world.get_entity_by_id(shooter_id) {
|
|
let shooter = shooter.get_entity();
|
|
|
|
// Logic for boosting Elytra flight
|
|
if shooter.is_fall_flying() {
|
|
let rotation = shooter.rotation().to_f64();
|
|
let shooter_vel = shooter.velocity.load();
|
|
|
|
let new_shooter_vel =
|
|
shooter_vel + (rotation * 0.1 + (rotation * 1.5 - shooter_vel) * 0.5);
|
|
|
|
shooter.set_velocity(new_shooter_vel);
|
|
|
|
entity.set_pos(shooter.pos.load());
|
|
entity.set_velocity(new_shooter_vel);
|
|
}
|
|
}
|
|
} else {
|
|
// Standard firework rocket flight logic
|
|
velocity.x *= 1.15;
|
|
velocity.z *= 1.15;
|
|
velocity.y += 0.04;
|
|
entity.set_velocity(velocity);
|
|
}
|
|
|
|
// Increment life and check for explosion
|
|
let current_life = self.life.fetch_add(1, Ordering::Relaxed);
|
|
if current_life > self.life_time.load(Ordering::Relaxed) {
|
|
self.explode_and_remove(&world).await;
|
|
}
|
|
})
|
|
}
|
|
|
|
fn get_entity(&self) -> &crate::entity::Entity {
|
|
&self.entity.entity
|
|
}
|
|
|
|
fn get_living_entity(&self) -> Option<&crate::entity::living::LivingEntity> {
|
|
None
|
|
}
|
|
fn cast_any(&self) -> &dyn std::any::Any {
|
|
self
|
|
}
|
|
}
|