Drop items & xp and reset hunger on death (#972)

* Drop items & xp and reset hunger on death

resolves #955

* clippy and fmt

* reset xp and hunger on respawn instead on death
This commit is contained in:
Commandcracker
2025-07-03 09:39:22 +02:00
committed by GitHub
parent 8ee7150715
commit fcf2700d65
5 changed files with 61 additions and 16 deletions

View File

@@ -87,13 +87,15 @@ impl EntityBase for ExperienceOrbEntity {
}
async fn on_player_collision(&self, player: &Arc<Player>) {
let mut delay = player.experience_pick_up_delay.lock().await;
if *delay == 0 {
*delay = 2;
player.living_entity.pickup(&self.entity, 1).await;
player.add_experience_points(self.amount as i32).await;
// TODO: pickingCount for merging
self.entity.remove().await;
if player.living_entity.health.load() > 0.0 {
let mut delay = player.experience_pick_up_delay.lock().await;
if *delay == 0 {
*delay = 2;
player.living_entity.pickup(&self.entity, 1).await;
player.add_experience_points(self.amount as i32).await;
// TODO: pickingCount for merging
self.entity.remove().await;
}
}
}

View File

@@ -81,6 +81,13 @@ impl HungerManager {
self.exhaustion
.store((self.exhaustion.load() + exhaustion).min(40.0));
}
pub fn restart(&self) {
self.level.store(20);
self.saturation.store(5.0);
self.exhaustion.store(0.0);
self.tick_timer.store(0);
}
}
#[async_trait]

View File

@@ -98,6 +98,7 @@ impl EntityBase for ItemEntity {
};
if can_pickup
&& player.living_entity.health.load() > 0.0
&& player
.inventory
.insert_stack_anywhere(&mut *self.item_stack.lock().await)

View File

@@ -10,7 +10,7 @@ use async_trait::async_trait;
use crossbeam::atomic::AtomicCell;
use log::warn;
use pumpkin_world::chunk::{ChunkData, ChunkEntityData};
use pumpkin_world::inventory::Inventory;
use pumpkin_world::inventory::{Clearable, Inventory};
use tokio::sync::{Mutex, RwLock};
use tokio::task::JoinHandle;
use uuid::Uuid;
@@ -72,10 +72,17 @@ use pumpkin_world::entity::entity_data_flags::{
use pumpkin_world::item::ItemStack;
use pumpkin_world::level::{SyncChunk, SyncEntityChunk};
use super::combat::{self, AttackType, player_attack_sound};
use super::effect::Effect;
use super::hunger::HungerManager;
use super::item::ItemEntity;
use super::living::LivingEntity;
use super::{Entity, EntityBase, EntityId, NBTStorage};
use crate::block::blocks::bed::BedBlock;
use crate::command::client_suggestions;
use crate::command::dispatcher::CommandDispatcher;
use crate::data::op_data::OPERATOR_CONFIG;
use crate::entity::experience_orb::ExperienceOrbEntity;
use crate::error::PumpkinError;
use crate::net::GameProfile;
use crate::net::{Client, PlayerConfig};
@@ -86,13 +93,6 @@ use crate::server::Server;
use crate::world::World;
use crate::{PERMISSION_MANAGER, block};
use super::combat::{self, AttackType, player_attack_sound};
use super::effect::Effect;
use super::hunger::HungerManager;
use super::item::ItemEntity;
use super::living::LivingEntity;
use super::{Entity, EntityBase, EntityId, NBTStorage};
const MAX_CACHED_SIGNATURES: u8 = 128; // Vanilla: 128
const MAX_PREVIOUS_MESSAGES: u8 = 20; // Vanilla: 20
@@ -1277,6 +1277,35 @@ impl Player {
pub async fn kill(&self) {
self.living_entity.kill().await;
let world = self.world().await;
if !world.level_info.read().await.game_rules.keep_inventory {
let pos = self.living_entity.entity.block_pos.load();
for item in &self.inventory.main_inventory {
world.drop_stack(&pos, *item.lock().await).await;
}
for item in self
.inventory
.entity_equipment
.lock()
.await
.equipment
.values()
{
world.drop_stack(&pos, *item.lock().await).await;
}
self.inventory.clear().await;
if self.gamemode.load() != GameMode::Spectator {
ExperienceOrbEntity::spawn(
&world,
pos.to_f64(),
(self.experience_level.load(Ordering::Relaxed) * 7).min(100) as u32,
)
.await;
}
}
self.handle_killed().await;
}

View File

@@ -1091,8 +1091,14 @@ impl World {
player.send_permission_lvl_update().await;
// Teleport
player.hunger_manager.restart();
let info = &self.level_info.read().await;
if !info.game_rules.keep_inventory {
player.set_experience(0, 0.0, 0).await;
}
// Teleport
let pitch = 0.0;
let (position, yaw) = if let Some(respawn) = player.get_respawn_point().await {
respawn