Some more Item dropping work

And also some fixes
This commit is contained in:
Alexander Medvedev 2025-01-31 23:21:24 +01:00
parent ef497fb435
commit 819e0c62ac
11 changed files with 72 additions and 34 deletions

View File

@ -1,6 +1,6 @@
use super::{position::BlockPos, vector3::Vector3};
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
pub struct BoundingBox {
pub min: Vector3<f64>,
pub max: Vector3<f64>,
@ -74,7 +74,7 @@ impl BoundingBox {
}
}
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Debug)]
pub struct BoundingBoxSize {
pub width: f64,
pub height: f64,

View File

@ -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<BlockProperty> {
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

View File

@ -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)));

View File

@ -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",

View File

@ -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

View File

@ -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<f64>,
world: &Arc<World>,
) -> (Arc<dyn EntityBase>, Uuid) {
let (entity, uuid) = server.add_entity(position, entity_type, world);
) -> Arc<dyn EntityBase> {
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 {

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 {

View File

@ -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<f64>,
entity_type: EntityType,
world: &Arc<World>,
) -> (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(

View File

@ -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<LivingEntity>` reference to the living entity object.
pub async fn spawn_entity(&self, uuid: uuid::Uuid, entity: Arc<dyn EntityBase>) {
self.broadcast_packet_all(&entity.get_entity().create_spawn_packet(uuid))
pub async fn spawn_entity(&self, entity: Arc<dyn EntityBase>) {
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) {