Pumpkin/crates/pumpkin/src/block/blocks/campfire.rs
2026-09-02 15:16:42 +02:00

109 lines
3.9 KiB
Rust

use pumpkin_data::{
Block, BlockDirection, BlockState, BlockStateId, Enchantment,
block_properties::CampfireLikeProperties, damage::DamageType,
data_component_impl::EquipmentSlot, effect::StatusEffect, fluid::Fluid,
};
use pumpkin_macros::pumpkin_block_from_tag;
use pumpkin_world::tick::TickPriority;
use crate::block::entities::campfire::CampfireBlockEntity;
use crate::{
block::{
BlockBehaviour, BlockIsReplacing, GetStateForNeighborUpdateArgs, OnEntityCollisionArgs,
OnPlaceArgs, PathComputationType, PlacedArgs,
},
entity::EntityBase,
};
use std::sync::Arc;
#[pumpkin_block_from_tag("minecraft:campfires")]
pub struct CampfireBlock;
impl BlockBehaviour for CampfireBlock {
fn placed(&self, args: PlacedArgs<'_>) {
{
let entity = CampfireBlockEntity::new(*args.position);
args.world.add_block_entity(Arc::new(entity));
}
}
// TODO: cooking food on campfire (CampfireBlockEntity)
fn on_entity_collision(&self, args: OnEntityCollisionArgs<'_>) {
{
if CampfireLikeProperties::from_state_id(args.state.id).lit
&& let Some(living_entity) = args.entity.get_living_entity()
{
let has_frost_walker_enchantment = {
let equipment = living_entity
.entity_equipment
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
equipment
.equipment
.get(&EquipmentSlot::FEET)
.is_some_and(|boots| {
boots.get_enchantment_level(&Enchantment::FROST_WALKER) != 0
})
};
let has_fire_res = living_entity
.get_effect(&StatusEffect::FIRE_RESISTANCE)
.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);
}
}
}
fn on_place(&self, args: OnPlaceArgs<'_>) -> BlockStateId {
let is_replacing_water = matches!(args.replacing, BlockIsReplacing::Water(_));
let mut props = CampfireLikeProperties::from_state_id(args.block.default_state.id);
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(
&self,
args: GetStateForNeighborUpdateArgs<'_>,
) -> BlockStateId {
let mut props = CampfireLikeProperties::from_state_id(args.state_id);
if props.waterlogged {
props.lit = false;
args.world.schedule_fluid_tick(
&Fluid::WATER,
*args.position,
Fluid::WATER.flow_speed as u8,
TickPriority::Normal,
);
}
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)
}
fn is_pathfindable(&self, _state: &BlockState, _computation_type: PathComputationType) -> bool {
false
}
// TODO: onProjectileHit
}
fn is_signal_fire_base_block(block: &Block) -> bool {
block == &Block::HAY_BLOCK
}