feat: Falling Blocks
This commit is contained in:
parent
73c2c0115e
commit
306a007e3c
@ -1043,6 +1043,16 @@ pub(crate) fn build() -> TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = r" Get a raw ID from an State ID."]
|
||||
#[inline]
|
||||
pub const fn get_raw_id_from_state_id(state_id: u16) -> u16 {
|
||||
if state_id as usize >= Self::RAW_ID_FROM_STATE_ID.len() {
|
||||
0
|
||||
} else {
|
||||
Self::RAW_ID_FROM_STATE_ID[state_id as usize]
|
||||
}
|
||||
}
|
||||
|
||||
#[doc = r" Get a block from a state id."]
|
||||
#[inline]
|
||||
pub const fn from_state_id(id: u16) -> &'static Self {
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
use crate::block::{BlockBehaviour, OnPlaceArgs};
|
||||
use crate::block::blocks::falling::FallingBlock;
|
||||
use crate::block::{
|
||||
BlockBehaviour, GetStateForNeighborUpdateArgs, OnPlaceArgs, OnScheduledTickArgs, PlacedArgs,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::block_properties::{BlockProperties, WallTorchLikeProperties};
|
||||
use pumpkin_data::tag::{RegistryKey, get_tag_values};
|
||||
@ -23,4 +26,18 @@ impl BlockBehaviour for AnvilBlock {
|
||||
props.facing = dir;
|
||||
props.to_state_id(args.block)
|
||||
}
|
||||
|
||||
async fn placed(&self, args: PlacedArgs<'_>) {
|
||||
FallingBlock::placed(&FallingBlock, args).await;
|
||||
}
|
||||
|
||||
async fn get_state_for_neighbor_update(
|
||||
&self,
|
||||
args: GetStateForNeighborUpdateArgs<'_>,
|
||||
) -> BlockStateId {
|
||||
FallingBlock::get_state_for_neighbor_update(&FallingBlock, args).await
|
||||
}
|
||||
async fn on_scheduled_tick(&self, args: OnScheduledTickArgs<'_>) {
|
||||
FallingBlock::on_scheduled_tick(&FallingBlock, args).await;
|
||||
}
|
||||
}
|
||||
|
||||
62
pumpkin/src/block/blocks/falling.rs
Normal file
62
pumpkin/src/block/blocks/falling.rs
Normal file
@ -0,0 +1,62 @@
|
||||
use crate::{
|
||||
block::{
|
||||
BlockBehaviour, BlockMetadata, GetStateForNeighborUpdateArgs, OnScheduledTickArgs,
|
||||
PlacedArgs,
|
||||
},
|
||||
entity::falling::FallingEntity,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::{
|
||||
Block, BlockState,
|
||||
tag::{self, Taggable},
|
||||
};
|
||||
use pumpkin_world::{BlockStateId, tick::TickPriority};
|
||||
pub struct FallingBlock;
|
||||
|
||||
impl FallingBlock {
|
||||
#[must_use]
|
||||
pub fn can_fall_through(state: &BlockState, block: &Block) -> bool {
|
||||
state.is_air()
|
||||
|| block.is_tagged_with_by_tag(&tag::Block::MINECRAFT_FIRE)
|
||||
|| state.is_liquid()
|
||||
|| state.replaceable()
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockMetadata for FallingBlock {
|
||||
fn namespace(&self) -> &'static str {
|
||||
"minecraft"
|
||||
}
|
||||
|
||||
fn ids(&self) -> &'static [&'static str] {
|
||||
&[Block::GRAVEL.name, Block::SAND.name, Block::RED_SAND.name]
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl BlockBehaviour for FallingBlock {
|
||||
async fn placed(&self, args: PlacedArgs<'_>) {
|
||||
// TODO: make delay configurable
|
||||
args.world
|
||||
.schedule_block_tick(args.block, *args.position, 2, TickPriority::Normal)
|
||||
.await;
|
||||
}
|
||||
async fn get_state_for_neighbor_update(
|
||||
&self,
|
||||
args: GetStateForNeighborUpdateArgs<'_>,
|
||||
) -> BlockStateId {
|
||||
// TODO: make delay configurable
|
||||
args.world
|
||||
.schedule_block_tick(args.block, *args.position, 2, TickPriority::Normal)
|
||||
.await;
|
||||
args.state_id
|
||||
}
|
||||
|
||||
async fn on_scheduled_tick(&self, args: OnScheduledTickArgs<'_>) {
|
||||
let (block, state) = args.world.get_block_and_state(&args.position.down()).await;
|
||||
if !Self::can_fall_through(state, block) || args.position.0.y < args.world.min_y {
|
||||
return;
|
||||
}
|
||||
FallingEntity::replace_spawn(args.world, *args.position, args.block.default_state.id).await;
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@ pub mod dirt_path;
|
||||
pub mod doors;
|
||||
pub mod end_portal;
|
||||
pub mod end_portal_frame;
|
||||
pub mod falling;
|
||||
pub mod farmland;
|
||||
pub mod fence_gates;
|
||||
pub mod fences;
|
||||
|
||||
@ -11,6 +11,7 @@ use crate::block::blocks::dirt_path::DirtPathBlock;
|
||||
use crate::block::blocks::doors::DoorBlock;
|
||||
use crate::block::blocks::end_portal::EndPortalBlock;
|
||||
use crate::block::blocks::end_portal_frame::EndPortalFrameBlock;
|
||||
use crate::block::blocks::falling::FallingBlock;
|
||||
use crate::block::blocks::farmland::FarmlandBlock;
|
||||
use crate::block::blocks::fence_gates::FenceGateBlock;
|
||||
use crate::block::blocks::fences::FenceBlock;
|
||||
@ -205,6 +206,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
||||
manager.register(LecternBlock);
|
||||
manager.register(StemBlock);
|
||||
manager.register(AttachedStemBlock);
|
||||
manager.register(FallingBlock);
|
||||
|
||||
// Fire
|
||||
manager.register(SoulFireBlock);
|
||||
|
||||
128
pumpkin/src/entity/falling.rs
Normal file
128
pumpkin/src/entity/falling.rs
Normal file
@ -0,0 +1,128 @@
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_data::{damage::DamageType, entity::EntityType};
|
||||
use pumpkin_protocol::java::client::play::{MetaDataType, Metadata};
|
||||
use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
|
||||
use pumpkin_world::{BlockStateId, world::BlockFlags};
|
||||
use std::sync::{Arc, atomic::Ordering};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
entity::{Entity, EntityBase, NBTStorage, living::LivingEntity},
|
||||
server::Server,
|
||||
world::World,
|
||||
};
|
||||
|
||||
pub struct FallingEntity {
|
||||
entity: Entity,
|
||||
block_state_id: BlockStateId,
|
||||
}
|
||||
|
||||
impl FallingEntity {
|
||||
pub fn new(entity: Entity, block_state_id: BlockStateId) -> Self {
|
||||
Self {
|
||||
entity,
|
||||
block_state_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaced the current Block and Spawns a new Falling one
|
||||
pub async fn replace_spawn(world: &Arc<World>, position: BlockPos, block_state: BlockStateId) {
|
||||
// Replace the original block, TODO: use fluid state
|
||||
world
|
||||
.set_block_state(
|
||||
&position,
|
||||
Block::AIR.default_state.id,
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
|
||||
let position = position.0.to_f64().add_raw(0.5, 0.0, 0.5);
|
||||
let entity = Entity::new(
|
||||
Uuid::new_v4(),
|
||||
world.clone(),
|
||||
position,
|
||||
&EntityType::FALLING_BLOCK,
|
||||
false,
|
||||
);
|
||||
entity.data.store(i32::from(block_state), Ordering::Relaxed);
|
||||
let entity = Arc::new(Self::new(entity, block_state));
|
||||
world.spawn_entity(entity).await;
|
||||
}
|
||||
}
|
||||
|
||||
impl NBTStorage for FallingEntity {}
|
||||
|
||||
#[async_trait]
|
||||
impl EntityBase for FallingEntity {
|
||||
async fn tick(&self, caller: Arc<dyn EntityBase>, server: &Server) {
|
||||
let entity = &self.entity;
|
||||
entity.tick(caller.clone(), server).await;
|
||||
|
||||
let original_velo = entity.velocity.load();
|
||||
let mut velo = original_velo;
|
||||
velo.y -= self.get_gravity();
|
||||
|
||||
entity.velocity.store(velo);
|
||||
|
||||
entity.move_entity(caller.clone(), velo).await;
|
||||
entity.tick_block_collisions(&caller, server).await;
|
||||
if entity.on_ground.load(Ordering::Relaxed) {
|
||||
entity.velocity.store(velo.multiply(0.7, -0.5, 0.7));
|
||||
entity
|
||||
.world
|
||||
.read()
|
||||
.await
|
||||
.set_block_state(
|
||||
&self.entity.block_pos.load(),
|
||||
self.block_state_id,
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
entity.remove().await;
|
||||
}
|
||||
|
||||
entity.velocity.store(velo.multiply(0.98, 0.98, 0.98));
|
||||
|
||||
entity.send_pos_rot().await;
|
||||
|
||||
entity.send_velocity().await;
|
||||
}
|
||||
|
||||
async fn init_data_tracker(&self) {
|
||||
self.entity
|
||||
.send_meta_data(&[Metadata::new(
|
||||
8,
|
||||
MetaDataType::BlockPos,
|
||||
self.entity.block_pos.load(),
|
||||
)])
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn damage_with_context(
|
||||
&self,
|
||||
_amount: f32,
|
||||
_damage_type: DamageType,
|
||||
_position: Option<Vector3<f64>>,
|
||||
_source: Option<&dyn EntityBase>,
|
||||
_cause: Option<&dyn EntityBase>,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn get_entity(&self) -> &Entity {
|
||||
&self.entity
|
||||
}
|
||||
|
||||
fn get_living_entity(&self) -> Option<&LivingEntity> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_nbt_storage(&self) -> &dyn NBTStorage {
|
||||
self
|
||||
}
|
||||
|
||||
fn get_gravity(&self) -> f64 {
|
||||
0.04
|
||||
}
|
||||
}
|
||||
@ -53,6 +53,7 @@ pub mod ai;
|
||||
pub mod decoration;
|
||||
pub mod effect;
|
||||
pub mod experience_orb;
|
||||
pub mod falling;
|
||||
pub mod hunger;
|
||||
pub mod item;
|
||||
pub mod living;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user