diff --git a/pumpkin-util/src/math/boundingbox.rs b/pumpkin-util/src/math/boundingbox.rs index 3bceadf29..415035ce0 100644 --- a/pumpkin-util/src/math/boundingbox.rs +++ b/pumpkin-util/src/math/boundingbox.rs @@ -1,6 +1,6 @@ use super::{position::BlockPos, vector3::Vector3}; -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub struct BoundingBox { pub min: Vector3, pub max: Vector3, @@ -74,7 +74,7 @@ impl BoundingBox { } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub struct BoundingBoxSize { pub width: f64, pub height: f64, diff --git a/pumpkin/src/block/properties.rs b/pumpkin/src/block/properties.rs index c46787853..bd99bc4e3 100644 --- a/pumpkin/src/block/properties.rs +++ b/pumpkin/src/block/properties.rs @@ -58,7 +58,7 @@ pub enum Direction { West, } -// TODO: We can automaticly parse them ig +// TODO: We can automatically parse them ig #[must_use] pub fn get_property_key(property_name: &str) -> Option { match property_name { @@ -93,7 +93,6 @@ pub fn evaluate_layers( } if block.id == clicked_block.id { - dbg!(property); // bro its is so hacky :crying: let mut layer: u8 = property.replace("layers", "").parse().unwrap(); // lets add a new layer diff --git a/pumpkin/src/command/args/textcomponent.rs b/pumpkin/src/command/args/textcomponent.rs index 6a10384c7..739849c38 100644 --- a/pumpkin/src/command/args/textcomponent.rs +++ b/pumpkin/src/command/args/textcomponent.rs @@ -32,7 +32,6 @@ impl ArgumentConsumer for TextComponentArgConsumer { let text_component = parse_text_component(s); let Some(text_component) = text_component else { - dbg!(text_component); if s.starts_with('"') && s.ends_with('"') { let s = s.replace('"', ""); return Some(Arg::TextComponent(TextComponent::text(s))); diff --git a/pumpkin/src/command/commands/summon.rs b/pumpkin/src/command/commands/summon.rs index bd07b1bd5..6cc1ee9da 100644 --- a/pumpkin/src/command/commands/summon.rs +++ b/pumpkin/src/command/commands/summon.rs @@ -37,8 +37,8 @@ impl CommandExecutor for SummonExecutor { // TODO: Make this work in console if let Some(player) = sender.as_player() { let pos = pos.unwrap_or(player.living_entity.entity.pos.load()); - let (mob, uuid) = mob::from_type(entity, server, pos, player.world()).await; - player.world().spawn_entity(uuid, mob).await; + let mob = mob::from_type(entity, server, pos, player.world()).await; + player.world().spawn_entity(mob).await; sender .send_message(TextComponent::translate( "commands.summon.success", diff --git a/pumpkin/src/entity/item.rs b/pumpkin/src/entity/item.rs index f402ff25e..19cb963ec 100644 --- a/pumpkin/src/entity/item.rs +++ b/pumpkin/src/entity/item.rs @@ -1,3 +1,5 @@ +use std::sync::atomic::AtomicI8; + use async_trait::async_trait; use pumpkin_protocol::{ client::play::{MetaDataType, Metadata}, @@ -10,12 +12,17 @@ use super::{living::LivingEntity, Entity, EntityBase}; pub struct ItemEntity { entity: Entity, item: Slot, + pickup_delay: AtomicI8, } impl ItemEntity { pub fn new(entity: Entity, stack: &ItemStack) -> Self { let slot = Slot::from(stack); - Self { entity, item: slot } + Self { + entity, + item: slot, + pickup_delay: AtomicI8::new(10), // Vanilla + } } pub async fn send_meta_packet(&self) { self.entity @@ -26,7 +33,18 @@ impl ItemEntity { #[async_trait] impl EntityBase for ItemEntity { - async fn tick(&self) {} + async fn tick(&self) { + if self.pickup_delay.load(std::sync::atomic::Ordering::Relaxed) >= 0 { + self.pickup_delay + .fetch_sub(1, std::sync::atomic::Ordering::Relaxed); + } + } + async fn on_player_collision(&self) { + if self.pickup_delay.load(std::sync::atomic::Ordering::Relaxed) == 0 { + // check if inventory is full + self.entity.remove().await; + } + } fn get_entity(&self) -> &Entity { &self.entity diff --git a/pumpkin/src/entity/mob/mod.rs b/pumpkin/src/entity/mob/mod.rs index 5aae39082..08e462aff 100644 --- a/pumpkin/src/entity/mob/mod.rs +++ b/pumpkin/src/entity/mob/mod.rs @@ -4,7 +4,6 @@ use async_trait::async_trait; use pumpkin_data::entity::EntityType; use pumpkin_util::math::vector3::Vector3; use tokio::sync::Mutex; -use uuid::Uuid; use zombie::Zombie; use crate::{server::Server, world::World}; @@ -56,8 +55,8 @@ pub async fn from_type( server: &Server, position: Vector3, world: &Arc, -) -> (Arc, Uuid) { - let (entity, uuid) = server.add_entity(position, entity_type, world); +) -> Arc { + let entity = server.add_entity(position, entity_type, world); let mob = MobEntity { living_entity: LivingEntity::new(entity), goals: Mutex::new(vec![]), @@ -69,7 +68,7 @@ pub async fn from_type( // TODO _ => (), } - (Arc::new(mob), uuid) + Arc::new(mob) } impl MobEntity { diff --git a/pumpkin/src/entity/mod.rs b/pumpkin/src/entity/mod.rs index 444ffa11a..60a644703 100644 --- a/pumpkin/src/entity/mod.rs +++ b/pumpkin/src/entity/mod.rs @@ -25,7 +25,6 @@ use pumpkin_util::math::{ wrap_degrees, }; use serde::Serialize; -use uuid::Uuid; use crate::world::World; @@ -39,7 +38,10 @@ pub type EntityId = i32; #[async_trait] pub trait EntityBase: Send + Sync { - async fn tick(&self); + /// Gets Called every tick + async fn tick(&self) {} + /// Called when a player collides with the entity + async fn on_player_collision(&self) {} fn get_entity(&self) -> &Entity; fn get_living_entity(&self) -> Option<&LivingEntity>; } @@ -222,12 +224,12 @@ impl Entity { self.world.remove_entity(self).await; } - pub fn create_spawn_packet(&self, uuid: Uuid) -> CSpawnEntity { + pub fn create_spawn_packet(&self) -> CSpawnEntity { let entity_loc = self.pos.load(); let entity_vel = self.velocity.load(); CSpawnEntity::new( VarInt(self.entity_id), - uuid, + self.entity_uuid, VarInt((self.entity_type) as i32), entity_loc.x, entity_loc.y, @@ -328,7 +330,7 @@ impl Entity { pub async fn set_pose(&self, pose: EntityPose) { self.pose.store(pose); let pose = pose as i32; - self.send_meta_data(Metadata::new(6, MetaDataType::EntityPose, pose)) + self.send_meta_data(Metadata::new(6, MetaDataType::EntityPose, VarInt(pose))) .await; } } diff --git a/pumpkin/src/entity/player.rs b/pumpkin/src/entity/player.rs index 144c58640..688ea11ab 100644 --- a/pumpkin/src/entity/player.rs +++ b/pumpkin/src/entity/player.rs @@ -537,9 +537,9 @@ impl Player { // TODO: This should be optimized for larger servers based on current player chunk pub async fn send_mobs(&self, world: &World) { let entities = world.entities.lock().await.clone(); - for (uuid, entity) in entities { + for (_, entity) in entities { self.client - .send_packet(&entity.get_entity().create_spawn_packet(uuid)) + .send_packet(&entity.get_entity().create_spawn_packet()) .await; } } @@ -718,13 +718,13 @@ impl Player { pub async fn drop_item(&self, server: &Server) { let inv = self.inventory.lock().await; if let Some(item) = inv.held_item() { - let (entity, uuid) = server.add_entity( + let entity = server.add_entity( self.living_entity.entity.pos.load(), EntityType::Item, self.world(), ); let item_entity = Arc::new(ItemEntity::new(entity, item)); - self.world().spawn_entity(uuid, item_entity.clone()).await; + self.world().spawn_entity(item_entity.clone()).await; item_entity.send_meta_packet().await; } } diff --git a/pumpkin/src/net/packet/play.rs b/pumpkin/src/net/packet/play.rs index 3c0a9d4af..538fb296d 100644 --- a/pumpkin/src/net/packet/play.rs +++ b/pumpkin/src/net/packet/play.rs @@ -1125,7 +1125,7 @@ impl Player { let world = self.world(); // create new mob and uuid based on spawn egg id - let (mob, uuid) = mob::from_type( + let mob = mob::from_type( EntityType::from_raw(*spawn_item_id).unwrap(), server, pos, @@ -1137,7 +1137,7 @@ impl Player { mob.get_entity().set_rotation(yaw, 0.0); // broadcast new mob to all players - world.spawn_entity(uuid, mob).await; + world.spawn_entity(mob).await; // TODO: send/configure additional commands/data based on type of entity (horse, slime, etc) } else { diff --git a/pumpkin/src/server/mod.rs b/pumpkin/src/server/mod.rs index ceab121a3..1ec6e8c3a 100644 --- a/pumpkin/src/server/mod.rs +++ b/pumpkin/src/server/mod.rs @@ -29,7 +29,6 @@ use std::{ time::Duration, }; use tokio::sync::{Mutex, RwLock}; -use uuid::Uuid; use crate::block::block_manager::BlockManager; use crate::block::properties::BlockPropertiesManager; @@ -218,7 +217,7 @@ impl Server { position: Vector3, entity_type: EntityType, world: &Arc, - ) -> (Entity, Uuid) { + ) -> Entity { let entity_id = self.new_entity_id(); // TODO: this should be resolved to a integer using a macro when calling this function @@ -235,18 +234,21 @@ impl Server { // TODO: standing eye height should be per mob let new_uuid = uuid::Uuid::new_v4(); - let entity = Entity::new( + Entity::new( entity_id, new_uuid, world.clone(), position, entity_type, 1.62, - AtomicCell::new(BoundingBox::new_default(&bounding_box_size)), + AtomicCell::new(BoundingBox::new_from_pos( + position.x, + position.y, + position.z, + &bounding_box_size, + )), AtomicCell::new(bounding_box_size), - ); - - (entity, new_uuid) + ) } pub async fn try_get_container( diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index 9968deac6..e453e74e0 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -234,9 +234,27 @@ impl World { for player in self.players.lock().await.values() { player.tick().await; } + // entities tick for entity in self.entities.lock().await.values() { entity.tick().await; + // this boolean thing prevents deadlocks, since we lock players we can't broadcast packets + let mut collied = false; + for player in self.players.lock().await.values() { + if player + .living_entity + .entity + .bounding_box + .load() + .intersects(&entity.get_entity().bounding_box.load()) + { + collied = true; + break; + } + } + if collied { + entity.on_player_collision().await; + } } } @@ -838,11 +856,12 @@ impl World { /// /// * `uuid`: The unique UUID of the living entity to add. /// * `living_entity`: A `Arc` reference to the living entity object. - pub async fn spawn_entity(&self, uuid: uuid::Uuid, entity: Arc) { - self.broadcast_packet_all(&entity.get_entity().create_spawn_packet(uuid)) + pub async fn spawn_entity(&self, entity: Arc) { + let base_entity = entity.get_entity(); + self.broadcast_packet_all(&base_entity.create_spawn_packet()) .await; let mut current_living_entities = self.entities.lock().await; - current_living_entities.insert(uuid, entity); + current_living_entities.insert(base_entity.entity_uuid, entity); } pub async fn remove_entity(&self, entity: &Entity) {