fix: make item drops fall smooth

This commit is contained in:
Alexander Medvedev 2026-01-15 20:29:30 +01:00
parent 0ef17af5d0
commit db486d5572
19 changed files with 43 additions and 40 deletions

View File

@ -7,7 +7,7 @@ pub(crate) fn build() -> TokenStream {
println!("cargo:rerun-if-changed=../assets/tracked_data.json"); println!("cargo:rerun-if-changed=../assets/tracked_data.json");
let mut handlers: Vec<(String, u8)> = let mut handlers: Vec<(String, u8)> =
serde_json::from_str::<std::collections::HashMap<String, u8>>( serde_json::from_str::<std::collections::BTreeMap<String, u8>>(
&fs::read_to_string("../assets/tracked_data.json").unwrap(), &fs::read_to_string("../assets/tracked_data.json").unwrap(),
) )
.expect("Failed to parse tracked_data.json") .expect("Failed to parse tracked_data.json")

View File

@ -22,7 +22,7 @@ fn abs_max(a: f64, b: f64) -> f64 {
} }
fn to_long(value: f64) -> i64 { fn to_long(value: f64) -> i64 {
((value * 0.5 + 0.5) * MAX_15_BIT_VALUE).round() as i64 (((value * 0.5 + 0.5) * MAX_15_BIT_VALUE).round() as i64).clamp(0, 32766)
} }
impl Serialize for Velocity { impl Serialize for Velocity {

View File

@ -1624,7 +1624,7 @@ impl GenerationSchedule {
level: Arc<Level>, level: Arc<Level>,
lock: IOLock, lock: IOLock,
) { ) {
log::info!("io read thread start"); log::debug!("io read thread start");
use crate::biome::hash_seed; use crate::biome::hash_seed;
let biome_mixer_seed = hash_seed(level.world_gen.random_config.seed); let biome_mixer_seed = hash_seed(level.world_gen.random_config.seed);
let dimension = &level.world_gen.dimension; let dimension = &level.world_gen.dimension;
@ -1687,7 +1687,7 @@ impl GenerationSchedule {
break; break;
} }
} }
log::info!("io read thread stop"); log::debug!("io read thread stop");
} }
async fn io_write_work(recv: AsyncRx<Vec<(ChunkPos, Chunk)>>, level: Arc<Level>, lock: IOLock) { async fn io_write_work(recv: AsyncRx<Vec<(ChunkPos, Chunk)>>, level: Arc<Level>, lock: IOLock) {

View File

@ -309,7 +309,7 @@ impl Level {
}; };
for handle in handles { for handle in handles {
log::info!( log::debug!(
"Waiting for thread {:?} ({}) to stop", "Waiting for thread {:?} ({}) to stop",
handle.thread().id(), handle.thread().id(),
handle.thread().name().unwrap_or("unknown") handle.thread().name().unwrap_or("unknown")

View File

@ -1,6 +1,6 @@
use super::{Controls, Goal, to_goal_ticks}; use super::{Controls, Goal, to_goal_ticks};
use crate::entity::ai::goal::GoalFuture; use crate::entity::ai::goal::GoalFuture;
use crate::entity::ai::goal::track_target_goal::TrackTargetGoal; use crate::entity::ai::goal::track_target::TrackTargetGoal;
use crate::entity::ai::target_predicate::TargetPredicate; use crate::entity::ai::target_predicate::TargetPredicate;
use crate::entity::living::LivingEntity; use crate::entity::living::LivingEntity;
use crate::entity::mob::Mob; use crate::entity::mob::Mob;

View File

@ -1,16 +1,16 @@
use crate::entity::mob::Mob; use crate::entity::mob::Mob;
use std::{any::TypeId, ops::BitOr, pin::Pin, ptr}; use std::{any::TypeId, ops::BitOr, pin::Pin, ptr};
pub mod active_target_goal; pub mod active_target;
pub mod ambient_stand_goal; pub mod ambient_stand;
pub mod goal_selector; pub mod goal_selector;
pub mod look_around_goal; pub mod look_around;
pub mod look_at_entity; pub mod look_at_entity;
mod melee_attack_goal; mod melee_attack;
pub mod move_to_target_pos_goal; pub mod move_to_target_pos;
pub mod step_and_destroy_block_goal; pub mod step_and_destroy_block;
mod track_target_goal; mod track_target;
pub mod zombie_attack_goal; pub mod zombie_attack;
#[must_use] #[must_use]
pub fn to_goal_ticks(server_ticks: i32) -> i32 { pub fn to_goal_ticks(server_ticks: i32) -> i32 {

View File

@ -1,5 +1,5 @@
use super::{Controls, Goal, to_goal_ticks}; use super::{Controls, Goal, to_goal_ticks};
use crate::entity::ai::goal::move_to_target_pos_goal::{MoveToTargetPos, MoveToTargetPosGoal}; use crate::entity::ai::goal::move_to_target_pos::{MoveToTargetPos, MoveToTargetPosGoal};
use crate::entity::ai::goal::{GoalFuture, ParentHandle}; use crate::entity::ai::goal::{GoalFuture, ParentHandle};
use crate::entity::mob::Mob; use crate::entity::mob::Mob;
use crate::world::World; use crate::world::World;

View File

@ -45,7 +45,7 @@ impl TrackTargetGoal {
// TODO: get from entity attribute // TODO: get from entity attribute
pub fn get_follow_range(_mob: &MobEntity) -> f32 { pub fn get_follow_range(_mob: &MobEntity) -> f32 {
1.0 32.0
} }
fn can_navigate_to_entity(&mut self, mob: &dyn Mob, _target: &LivingEntity) -> bool { fn can_navigate_to_entity(&mut self, mob: &dyn Mob, _target: &LivingEntity) -> bool {

View File

@ -1,6 +1,6 @@
use super::{Controls, Goal}; use super::{Controls, Goal};
use crate::entity::ai::goal::GoalFuture; use crate::entity::ai::goal::GoalFuture;
use crate::entity::ai::goal::melee_attack_goal::MeleeAttackGoal; use crate::entity::ai::goal::melee_attack::MeleeAttackGoal;
use crate::entity::mob::Mob; use crate::entity::mob::Mob;
pub struct ZombieAttackGoal { pub struct ZombieAttackGoal {

View File

@ -324,18 +324,9 @@ impl EntityBase for ItemEntity {
entity.update_fluid_state(&caller).await; entity.update_fluid_state(&caller).await;
let velocity_dirty = entity.velocity_dirty.swap(false, Ordering::SeqCst) let velocity_dirty = entity.velocity_dirty.swap(false, Ordering::SeqCst)
|| entity.touching_water.load(Ordering::SeqCst) || entity.touching_water.load(Ordering::SeqCst)
|| entity.touching_lava.load(Ordering::SeqCst) || entity.touching_lava.load(Ordering::SeqCst)
|| entity.velocity.load().sub(&original_velo).length_squared() > 0.01;
//|| entity.velocity.load().sub(&original_velo).length_squared() > 0.01;
|| entity.velocity.load() != original_velo;
if velocity_dirty { if velocity_dirty {
entity.send_pos_rot().await; entity.send_pos_rot().await;

View File

@ -1077,6 +1077,14 @@ impl EntityBase for LivingEntity {
}) })
} }
fn tick_in_void<'a>(&'a self, dyn_self: &'a dyn EntityBase) -> EntityBaseFuture<'a, ()> {
Box::pin(async move {
dyn_self
.damage(dyn_self, 4.0, DamageType::OUT_OF_WORLD)
.await;
})
}
fn get_gravity(&self) -> f64 { fn get_gravity(&self) -> f64 {
const GRAVITY: f64 = 0.08; const GRAVITY: f64 = 0.08;
GRAVITY GRAVITY

View File

@ -5,7 +5,7 @@ use pumpkin_data::entity::EntityType;
use crate::entity::{ use crate::entity::{
Entity, NBTStorage, Entity, NBTStorage,
ai::goal::{ ai::goal::{
active_target_goal::ActiveTargetGoal, look_around_goal::LookAroundGoal, active_target::ActiveTargetGoal, look_around::LookAroundGoal,
look_at_entity::LookAtEntityGoal, look_at_entity::LookAtEntityGoal,
}, },
mob::{Mob, MobEntity}, mob::{Mob, MobEntity},

View File

@ -1,14 +1,14 @@
use super::{Mob, MobEntity}; use super::{Mob, MobEntity};
use crate::entity::ai::goal::look_around_goal::LookAroundGoal; use crate::entity::ai::goal::look_around::LookAroundGoal;
use crate::entity::ai::goal::move_to_target_pos_goal::MoveToTargetPos; use crate::entity::ai::goal::move_to_target_pos::MoveToTargetPos;
use crate::entity::ai::goal::step_and_destroy_block_goal::{ use crate::entity::ai::goal::step_and_destroy_block::{
StepAndDestroyBlockGoal, Stepping, SteppingFuture, StepAndDestroyBlockGoal, Stepping, SteppingFuture,
}; };
use crate::entity::ai::goal::zombie_attack_goal::ZombieAttackGoal; use crate::entity::ai::goal::zombie_attack::ZombieAttackGoal;
use crate::entity::ai::goal::{Controls, Goal, GoalFuture, ParentHandle}; use crate::entity::ai::goal::{Controls, Goal, GoalFuture, ParentHandle};
use crate::entity::{ use crate::entity::{
Entity, NBTStorage, Entity, NBTStorage,
ai::goal::{active_target_goal::ActiveTargetGoal, look_at_entity::LookAtEntityGoal}, ai::goal::{active_target::ActiveTargetGoal, look_at_entity::LookAtEntityGoal},
}; };
use crate::world::World; use crate::world::World;
use pumpkin_data::Block; use pumpkin_data::Block;

View File

@ -126,6 +126,10 @@ pub trait EntityBase: Send + Sync + NBTStorage {
0.0 0.0
} }
fn tick_in_void<'a>(&'a self, _dyn_self: &'a dyn EntityBase) -> EntityBaseFuture<'a, ()> {
Box::pin(async move { self.get_entity().remove().await })
}
/// Returns if damage was successful or not /// Returns if damage was successful or not
fn damage<'a>( fn damage<'a>(
&'a self, &'a self,
@ -1776,10 +1780,7 @@ impl Entity {
pub async fn check_out_of_world(&self, dyn_self: &dyn EntityBase) { pub async fn check_out_of_world(&self, dyn_self: &dyn EntityBase) {
if self.pos.load().y < f64::from(self.world.dimension.min_y) - 64.0 { if self.pos.load().y < f64::from(self.world.dimension.min_y) - 64.0 {
// Tick out of world damage dyn_self.tick_in_void(dyn_self).await;
dyn_self
.damage(dyn_self, 4.0, DamageType::OUT_OF_WORLD)
.await;
} }
} }

View File

@ -7,7 +7,9 @@ use uuid::Uuid;
use crate::{ use crate::{
entity::{ entity::{
Entity, EntityBase, Entity, EntityBase,
decoration::{end_crystal::EndCrystalEntity, painting::PaintingEntity}, decoration::{
armor_stand::ArmorStandEntity, end_crystal::EndCrystalEntity, painting::PaintingEntity,
},
living::LivingEntity, living::LivingEntity,
mob::{drowned::DrownedEntity, zombie::ZombieEntity}, mob::{drowned::DrownedEntity, zombie::ZombieEntity},
}, },
@ -25,6 +27,7 @@ pub async fn from_type(
let mob: Arc<dyn EntityBase> = match entity_type.id { let mob: Arc<dyn EntityBase> = match entity_type.id {
id if id == EntityType::ZOMBIE.id => ZombieEntity::make(entity).await, id if id == EntityType::ZOMBIE.id => ZombieEntity::make(entity).await,
id if id == EntityType::DROWNED.id => DrownedEntity::make(entity).await, id if id == EntityType::DROWNED.id => DrownedEntity::make(entity).await,
id if id == EntityType::ARMOR_STAND.id => Arc::new(ArmorStandEntity::new(entity)),
id if id == EntityType::PAINTING.id => Arc::new(PaintingEntity::new(entity)), id if id == EntityType::PAINTING.id => Arc::new(PaintingEntity::new(entity)),
id if id == EntityType::END_CRYSTAL.id => Arc::new(EndCrystalEntity::new(entity)), id if id == EntityType::END_CRYSTAL.id => Arc::new(EndCrystalEntity::new(entity)),
// Fallback Entity // Fallback Entity