mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
Fix damage & death msg & portal delay (#1095)
* fix: damage sound & death message * fix * fix * fix rustfmt * fix: reset_state * fix
This commit is contained in:
@@ -69,9 +69,9 @@ pub(crate) fn build() -> TokenStream {
|
||||
let death_message_type = match &data.death_message_type {
|
||||
Some(msg) => {
|
||||
let msg_ident = Ident::new(&format!("{msg:?}"), proc_macro2::Span::call_site());
|
||||
quote! { Some(DeathMessageType::#msg_ident) }
|
||||
quote! { DeathMessageType::#msg_ident }
|
||||
}
|
||||
None => quote! { None },
|
||||
None => quote! { DeathMessageType::Default },
|
||||
};
|
||||
|
||||
let effects = match &data.effects {
|
||||
@@ -106,7 +106,7 @@ pub(crate) fn build() -> TokenStream {
|
||||
quote! {
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct DamageType {
|
||||
pub death_message_type: Option<DeathMessageType>,
|
||||
pub death_message_type: DeathMessageType,
|
||||
pub exhaustion: f32,
|
||||
pub effects: Option<DamageEffects>,
|
||||
pub message_id: &'static str,
|
||||
|
||||
@@ -20,14 +20,16 @@ impl NetherPortalBlock {
|
||||
/// Gets the portal delay time based on entity type and gamemode
|
||||
async fn get_portal_time(world: &Arc<World>, entity: &dyn EntityBase) -> u32 {
|
||||
let entity_type = entity.get_entity().entity_type;
|
||||
|
||||
let level_info = world.level_info.read().await;
|
||||
match entity_type.id {
|
||||
id if id == EntityType::PLAYER.id => (world
|
||||
.get_player_by_id(entity.get_entity().entity_id)
|
||||
.await)
|
||||
.map_or(80, |player| match player.gamemode.load() {
|
||||
GameMode::Creative => 0,
|
||||
_ => 80,
|
||||
GameMode::Creative => {
|
||||
level_info.game_rules.players_nether_portal_creative_delay as u32
|
||||
}
|
||||
_ => level_info.game_rules.players_nether_portal_default_delay as u32,
|
||||
}),
|
||||
_ => 0,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use core::f32;
|
||||
use pumpkin_data::potion::Effect;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::atomic::{AtomicU8, Ordering::Relaxed};
|
||||
use std::{collections::HashMap, sync::atomic::AtomicI32};
|
||||
|
||||
@@ -17,6 +16,7 @@ use pumpkin_data::damage::DeathMessageType;
|
||||
use pumpkin_data::data_component_impl::EquipmentSlot;
|
||||
use pumpkin_data::effect::StatusEffect;
|
||||
use pumpkin_data::entity::{EntityPose, EntityStatus, EntityType};
|
||||
use pumpkin_data::sound::SoundCategory;
|
||||
use pumpkin_data::{damage::DamageType, sound::Sound};
|
||||
use pumpkin_inventory::entity_equipment::EntityEquipment;
|
||||
use pumpkin_nbt::tag::NbtTag;
|
||||
@@ -231,7 +231,46 @@ impl LivingEntity {
|
||||
|
||||
/// Kills the Entity
|
||||
pub async fn kill(&self) {
|
||||
self.damage(f32::MAX, DamageType::OUT_OF_WORLD).await;
|
||||
self.damage(f32::MAX, DamageType::GENERIC_KILL).await;
|
||||
}
|
||||
|
||||
pub async fn get_death_message(
|
||||
dyn_self: &dyn EntityBase,
|
||||
damage_type: DamageType,
|
||||
source: Option<&dyn EntityBase>,
|
||||
cause: Option<&dyn EntityBase>,
|
||||
) -> TextComponent {
|
||||
match damage_type.death_message_type {
|
||||
DeathMessageType::Default => {
|
||||
if cause.is_some() && source.is_some() {
|
||||
TextComponent::translate(
|
||||
format!("death.attack.{}.player", damage_type.message_id),
|
||||
[
|
||||
dyn_self.get_display_name().await,
|
||||
cause.unwrap().get_display_name().await,
|
||||
],
|
||||
)
|
||||
} else {
|
||||
TextComponent::translate(
|
||||
format!("death.attack.{}", damage_type.message_id),
|
||||
[dyn_self.get_display_name().await],
|
||||
)
|
||||
}
|
||||
}
|
||||
DeathMessageType::FallVariants => {
|
||||
//TODO
|
||||
TextComponent::translate(
|
||||
"death.fell.accident.generic",
|
||||
[dyn_self.get_display_name().await],
|
||||
)
|
||||
}
|
||||
DeathMessageType::IntentionalGameDesign => TextComponent::text("[")
|
||||
.add_child(TextComponent::translate(
|
||||
format!("death.attack.{}.message", damage_type.message_id),
|
||||
[dyn_self.get_display_name().await],
|
||||
))
|
||||
.add_child(TextComponent::text("]")),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn on_death(
|
||||
@@ -269,45 +308,8 @@ impl LivingEntity {
|
||||
let game_rules = &level_info.game_rules;
|
||||
if self.entity.entity_type == &EntityType::PLAYER && game_rules.show_death_messages {
|
||||
//TODO: KillCredit
|
||||
let death_message = if let Some(death_message_type) = damage_type.death_message_type
|
||||
{
|
||||
match death_message_type {
|
||||
DeathMessageType::Default => {
|
||||
if cause.is_some() && source.is_some() {
|
||||
TextComponent::translate(
|
||||
format!("death.attack.{}.player", damage_type.message_id),
|
||||
[
|
||||
dyn_self.get_display_name().await,
|
||||
cause.unwrap().get_display_name().await,
|
||||
],
|
||||
)
|
||||
} else {
|
||||
TextComponent::translate(
|
||||
format!("death.attack.{}", damage_type.message_id),
|
||||
[dyn_self.get_display_name().await],
|
||||
)
|
||||
}
|
||||
}
|
||||
DeathMessageType::FallVariants => {
|
||||
//TODO
|
||||
TextComponent::translate(
|
||||
"death.fell.accident.generic",
|
||||
[dyn_self.get_display_name().await],
|
||||
)
|
||||
}
|
||||
DeathMessageType::IntentionalGameDesign => TextComponent::text("[")
|
||||
.add_child(TextComponent::translate(
|
||||
format!("death.attack.{}.message", damage_type.message_id),
|
||||
[dyn_self.get_display_name().await],
|
||||
))
|
||||
.add_child(TextComponent::text("]")),
|
||||
}
|
||||
} else {
|
||||
TextComponent::translate(
|
||||
"death.attack.generic",
|
||||
[dyn_self.get_display_name().await],
|
||||
)
|
||||
};
|
||||
let death_message =
|
||||
Self::get_death_message(&*dyn_self, damage_type, source, cause).await;
|
||||
if let Some(server) = world.server.upgrade() {
|
||||
for player in server.get_all_players().await {
|
||||
player.send_system_message(&death_message).await;
|
||||
@@ -361,6 +363,16 @@ impl LivingEntity {
|
||||
pub fn is_part_of_game(&self) -> bool {
|
||||
self.is_spectator() && self.entity.is_alive()
|
||||
}
|
||||
|
||||
pub async fn reset_state(&self) {
|
||||
self.entity.reset_state().await;
|
||||
self.hurt_cooldown.store(0, Relaxed);
|
||||
self.last_damage_taken.store(0f32);
|
||||
self.entity.portal_cooldown.store(0, Relaxed);
|
||||
*self.entity.portal_manager.lock().await = None;
|
||||
self.fall_distance.store(0f32);
|
||||
self.dead.store(false, Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl LivingEntityTrait for LivingEntity {}
|
||||
@@ -397,13 +409,16 @@ impl EntityBase for LivingEntity {
|
||||
let world = self.entity.world.read().await;
|
||||
|
||||
let last_damage = self.last_damage_taken.load();
|
||||
let play_sound;
|
||||
let mut damage_amount = if self.hurt_cooldown.load(Relaxed) > 10 {
|
||||
if amount <= last_damage {
|
||||
return false;
|
||||
}
|
||||
play_sound = false;
|
||||
amount - self.last_damage_taken.load()
|
||||
} else {
|
||||
self.hurt_cooldown.store(20, Relaxed);
|
||||
play_sound = true;
|
||||
amount
|
||||
};
|
||||
self.last_damage_taken.store(amount);
|
||||
@@ -431,11 +446,26 @@ impl EntityBase for LivingEntity {
|
||||
))
|
||||
.await;
|
||||
|
||||
if play_sound {
|
||||
self.entity
|
||||
.world
|
||||
.read()
|
||||
.await
|
||||
.play_sound(
|
||||
// Sound::EntityPlayerHurt,
|
||||
Sound::EntityGenericHurt,
|
||||
SoundCategory::Players,
|
||||
&self.entity.pos.load(),
|
||||
)
|
||||
.await;
|
||||
// todo: calculate knockback
|
||||
}
|
||||
|
||||
let new_health = self.health.load() - damage_amount;
|
||||
if damage_amount > 0.0 {
|
||||
self.on_actually_hurt(damage_amount, damage_type).await;
|
||||
self.set_health(new_health).await;
|
||||
}
|
||||
self.set_health(new_health).await;
|
||||
|
||||
if new_health <= 0.0 {
|
||||
self.on_death(damage_type, source, cause).await;
|
||||
@@ -452,7 +482,7 @@ impl EntityBase for LivingEntity {
|
||||
self.hurt_cooldown.fetch_sub(1, Relaxed);
|
||||
}
|
||||
if self.health.load() <= 0.0 {
|
||||
let time = self.death_time.fetch_add(1, Ordering::Relaxed);
|
||||
let time = self.death_time.fetch_add(1, Relaxed);
|
||||
if time == 20 {
|
||||
// Spawn Death particles
|
||||
self.entity
|
||||
|
||||
@@ -946,14 +946,20 @@ impl Entity {
|
||||
vehicle.is_some()
|
||||
}
|
||||
|
||||
pub async fn check_out_of_world(&self) {
|
||||
pub async fn check_out_of_world(&self, dyn_self: &dyn EntityBase) {
|
||||
if self.pos.load().y
|
||||
< f64::from(self.world.read().await.generation_settings().shape.min_y) - 64.0
|
||||
{
|
||||
// Tick out of world damage
|
||||
self.damage(4.0, DamageType::OUT_OF_WORLD).await;
|
||||
dyn_self.damage(4.0, DamageType::OUT_OF_WORLD).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unused_async)]
|
||||
pub async fn reset_state(&self) {
|
||||
self.pose.store(EntityPose::Standing);
|
||||
self.fall_flying.store(false, Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -971,6 +977,7 @@ impl EntityBase for Entity {
|
||||
|
||||
async fn tick(&self, caller: Arc<dyn EntityBase>, _server: &Server) {
|
||||
self.tick_portal(&caller).await;
|
||||
self.check_out_of_world(&*caller).await;
|
||||
let fire_ticks = self.fire_ticks.load(Ordering::Relaxed);
|
||||
if fire_ticks > 0 {
|
||||
if self.entity_type.fire_immune {
|
||||
|
||||
@@ -1288,16 +1288,12 @@ impl Player {
|
||||
|
||||
pub async fn kill(&self) {
|
||||
self.living_entity.kill().await;
|
||||
self.handle_killed().await;
|
||||
}
|
||||
|
||||
async fn handle_killed(&self) {
|
||||
async fn handle_killed(&self, death_msg: TextComponent) {
|
||||
self.set_client_loaded(false);
|
||||
self.client
|
||||
.send_packet_now(&CCombatDeath::new(
|
||||
self.entity_id().into(),
|
||||
&TextComponent::text("noob"),
|
||||
))
|
||||
.send_packet_now(&CCombatDeath::new(self.entity_id().into(), &death_msg))
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -1901,6 +1897,10 @@ impl Player {
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reset_state(&self) {
|
||||
self.living_entity.reset_state().await;
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -2037,14 +2037,11 @@ impl EntityBase for Player {
|
||||
if self.abilities.lock().await.invulnerable {
|
||||
return false;
|
||||
}
|
||||
self.world()
|
||||
let world = self.living_entity.entity.world.read().await;
|
||||
let dyn_self = world
|
||||
.get_entity_by_id(self.living_entity.entity.entity_id)
|
||||
.await
|
||||
.play_sound(
|
||||
Sound::EntityPlayerHurt,
|
||||
SoundCategory::Players,
|
||||
&self.living_entity.entity.pos.load(),
|
||||
)
|
||||
.await;
|
||||
.expect("Entity not found in world");
|
||||
let result = self
|
||||
.living_entity
|
||||
.damage_with_context(amount, damage_type, position, source, cause)
|
||||
@@ -2052,7 +2049,9 @@ impl EntityBase for Player {
|
||||
if result {
|
||||
let health = self.living_entity.health.load();
|
||||
if health <= 0.0 {
|
||||
self.handle_killed().await;
|
||||
let death_message =
|
||||
LivingEntity::get_death_message(&*dyn_self, damage_type, source, cause).await;
|
||||
self.handle_killed(death_message).await;
|
||||
}
|
||||
}
|
||||
result
|
||||
|
||||
@@ -41,7 +41,7 @@ impl ItemRegistry {
|
||||
) {
|
||||
let pumpkin_item = self.get_pumpkin_item(item);
|
||||
if let Some(pumpkin_item) = pumpkin_item {
|
||||
return pumpkin_item
|
||||
pumpkin_item
|
||||
.use_on_block(item, player, location, face, block, server)
|
||||
.await;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ impl ItemRegistry {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_pumpkin_item(&self, item: &Item) -> Option<&Arc<dyn ItemBehaviour>> {
|
||||
self.items.get(item)
|
||||
pub fn get_pumpkin_item(&self, item: &Item) -> Option<&dyn ItemBehaviour> {
|
||||
self.items.get(item).map(|value| &**value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1464,6 +1464,8 @@ impl World {
|
||||
))
|
||||
.await;
|
||||
|
||||
player.reset_state().await;
|
||||
|
||||
log::debug!("Sending player abilities to {}", player.gameprofile.name);
|
||||
player.send_abilities_update().await;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user