109 lines
3.9 KiB
Rust
109 lines
3.9 KiB
Rust
use pumpkin_data::{
|
|
Block, BlockDirection, Enchantment,
|
|
block_properties::{BlockProperties, CampfireLikeProperties},
|
|
damage::DamageType,
|
|
data_component_impl::EquipmentSlot,
|
|
effect::StatusEffect,
|
|
fluid::Fluid,
|
|
};
|
|
use pumpkin_world::{BlockStateId, tick::TickPriority};
|
|
|
|
use crate::{
|
|
block::{
|
|
BlockBehaviour, BlockFuture, BlockIsReplacing, BlockMetadata,
|
|
GetStateForNeighborUpdateArgs, OnEntityCollisionArgs, OnPlaceArgs,
|
|
},
|
|
entity::EntityBase,
|
|
};
|
|
|
|
pub struct CampfireBlock;
|
|
|
|
impl BlockMetadata for CampfireBlock {
|
|
fn ids() -> Box<[u16]> {
|
|
[Block::CAMPFIRE.id, Block::SOUL_CAMPFIRE.id].into()
|
|
}
|
|
}
|
|
|
|
impl BlockBehaviour for CampfireBlock {
|
|
// TODO: cooking food on campfire (CampfireBlockEntity)
|
|
fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
if CampfireLikeProperties::from_state_id(args.state.id, args.block).lit
|
|
&& let Some(living_entity) = args.entity.get_living_entity()
|
|
{
|
|
let has_frost_walker_enchantment = {
|
|
let equipment = living_entity.entity_equipment.lock().await;
|
|
let boots = equipment.get(&EquipmentSlot::FEET);
|
|
|
|
let boots_stack = boots.lock().await;
|
|
|
|
boots_stack.get_enchantment_level(&Enchantment::FROST_WALKER) != 0
|
|
};
|
|
let has_fire_res = living_entity
|
|
.get_effect(&StatusEffect::FIRE_RESISTANCE)
|
|
.await
|
|
.is_some();
|
|
if has_frost_walker_enchantment || has_fire_res {
|
|
//campfire burning doesn't work if entity's boots has frost walker enchantment or entity has fire resistance. source: https://minecraft.wiki/w/Campfire#Damage
|
|
return;
|
|
}
|
|
let damage_amount = if args.block == &Block::SOUL_CAMPFIRE {
|
|
2.0
|
|
} else {
|
|
1.0
|
|
};
|
|
args.entity
|
|
.damage(args.entity, damage_amount, DamageType::CAMPFIRE)
|
|
.await;
|
|
}
|
|
})
|
|
}
|
|
|
|
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
|
|
Box::pin(async move {
|
|
let is_replacing_water = matches!(args.replacing, BlockIsReplacing::Water(_));
|
|
let mut props =
|
|
CampfireLikeProperties::from_state_id(args.block.default_state.id, args.block);
|
|
props.waterlogged = is_replacing_water;
|
|
props.signal_fire =
|
|
is_signal_fire_base_block(args.world.get_block(&args.position.down()));
|
|
props.lit = !is_replacing_water;
|
|
props.facing = args.player.get_entity().get_horizontal_facing();
|
|
props.to_state_id(args.block)
|
|
})
|
|
}
|
|
|
|
fn get_state_for_neighbor_update<'a>(
|
|
&'a self,
|
|
args: GetStateForNeighborUpdateArgs<'a>,
|
|
) -> BlockFuture<'a, BlockStateId> {
|
|
Box::pin(async move {
|
|
let mut props = CampfireLikeProperties::from_state_id(args.state_id, args.block);
|
|
if props.waterlogged {
|
|
props.lit = false;
|
|
args.world
|
|
.schedule_fluid_tick(
|
|
&Fluid::WATER,
|
|
*args.position,
|
|
Fluid::WATER.flow_speed as u8,
|
|
TickPriority::Normal,
|
|
)
|
|
.await;
|
|
}
|
|
|
|
if args.direction == BlockDirection::Down {
|
|
props.signal_fire =
|
|
is_signal_fire_base_block(args.world.get_block(args.neighbor_position));
|
|
}
|
|
|
|
props.to_state_id(args.block)
|
|
})
|
|
}
|
|
|
|
// TODO: onProjectileHit
|
|
}
|
|
|
|
fn is_signal_fire_base_block(block: &Block) -> bool {
|
|
block == &Block::HAY_BLOCK
|
|
}
|