only require block ids, should make bin size smaller and let the compiler better optimize, should also be faster performance wise
153 lines
5.0 KiB
Rust
153 lines
5.0 KiB
Rust
use std::sync::Arc;
|
|
|
|
use pumpkin_data::{Block, item::Item};
|
|
use pumpkin_macros::pumpkin_block_from_tag;
|
|
use pumpkin_util::{GameMode, math::position::BlockPos};
|
|
use pumpkin_world::{
|
|
BlockStateId,
|
|
item::ItemStack,
|
|
tick::TickPriority,
|
|
world::{BlockAccessor, BlockFlags},
|
|
};
|
|
|
|
use crate::{
|
|
block::{
|
|
BlockBehaviour, BlockFuture, GetStateForNeighborUpdateArgs, NormalUseArgs,
|
|
OnScheduledTickArgs, UseWithItemArgs, blocks::cake::CakeBlock, registry::BlockActionResult,
|
|
},
|
|
entity::player::Player,
|
|
world::World,
|
|
};
|
|
|
|
const CANDLE_MAP: [(&Item, &Block); 17] = [
|
|
(&Item::CANDLE, &Block::CANDLE_CAKE),
|
|
(&Item::WHITE_CANDLE, &Block::WHITE_CANDLE_CAKE),
|
|
(&Item::ORANGE_CANDLE, &Block::ORANGE_CANDLE_CAKE),
|
|
(&Item::MAGENTA_CANDLE, &Block::MAGENTA_CANDLE_CAKE),
|
|
(&Item::LIGHT_BLUE_CANDLE, &Block::LIGHT_BLUE_CANDLE_CAKE),
|
|
(&Item::YELLOW_CANDLE, &Block::YELLOW_CANDLE_CAKE),
|
|
(&Item::LIME_CANDLE, &Block::LIME_CANDLE_CAKE),
|
|
(&Item::PINK_CANDLE, &Block::PINK_CANDLE_CAKE),
|
|
(&Item::GRAY_CANDLE, &Block::GRAY_CANDLE_CAKE),
|
|
(&Item::LIGHT_GRAY_CANDLE, &Block::LIGHT_GRAY_CANDLE_CAKE),
|
|
(&Item::CYAN_CANDLE, &Block::CYAN_CANDLE_CAKE),
|
|
(&Item::PURPLE_CANDLE, &Block::PURPLE_CANDLE_CAKE),
|
|
(&Item::BLUE_CANDLE, &Block::BLUE_CANDLE_CAKE),
|
|
(&Item::BROWN_CANDLE, &Block::BROWN_CANDLE_CAKE),
|
|
(&Item::GREEN_CANDLE, &Block::GREEN_CANDLE_CAKE),
|
|
(&Item::RED_CANDLE, &Block::RED_CANDLE_CAKE),
|
|
(&Item::BLACK_CANDLE, &Block::BLACK_CANDLE_CAKE),
|
|
];
|
|
|
|
#[must_use]
|
|
pub fn cake_from_candle(item: &Item) -> &'static Block {
|
|
CANDLE_MAP
|
|
.binary_search_by_key(&item.id, |(key, _)| key.id)
|
|
.map_or_else(
|
|
|_| panic!("Expected a candle item, got {}", item.id),
|
|
|index| CANDLE_MAP[index].1,
|
|
)
|
|
}
|
|
|
|
#[must_use]
|
|
pub fn candle_from_cake(block: &Block) -> &'static Item {
|
|
CANDLE_MAP
|
|
.binary_search_by_key(&block.id, |(_, value)| value.id)
|
|
.map_or_else(
|
|
|_| panic!("Expected a candle cake block, got {}", block.id),
|
|
|index| CANDLE_MAP[index].0,
|
|
)
|
|
}
|
|
|
|
#[pumpkin_block_from_tag("minecraft:candle_cakes")]
|
|
pub struct CandleCakeBlock;
|
|
|
|
impl CandleCakeBlock {
|
|
async fn consume_and_drop_candle(
|
|
block: &Block,
|
|
player: &Player,
|
|
location: &BlockPos,
|
|
world: &Arc<World>,
|
|
) -> BlockActionResult {
|
|
match player.gamemode.load() {
|
|
GameMode::Survival | GameMode::Adventure => {
|
|
if player.hunger_manager.level.load() >= 20 {
|
|
return BlockActionResult::Pass;
|
|
}
|
|
}
|
|
GameMode::Creative => {}
|
|
GameMode::Spectator => return BlockActionResult::Pass,
|
|
}
|
|
|
|
let candle_item = candle_from_cake(block);
|
|
|
|
let item_stack = ItemStack::new(1, candle_item);
|
|
|
|
world.drop_stack(location, item_stack).await;
|
|
|
|
world
|
|
.set_block_state(
|
|
location,
|
|
Block::CAKE.default_state.id,
|
|
BlockFlags::NOTIFY_ALL,
|
|
)
|
|
.await;
|
|
|
|
let (block, state) = world.get_block_and_state_id(location).await;
|
|
|
|
CakeBlock::consume_if_hungry(world, player, block, location, state).await
|
|
}
|
|
}
|
|
|
|
impl BlockBehaviour for CandleCakeBlock {
|
|
fn use_with_item<'a>(
|
|
&'a self,
|
|
args: UseWithItemArgs<'a>,
|
|
) -> BlockFuture<'a, BlockActionResult> {
|
|
Box::pin(async move {
|
|
let item_id = args.item_stack.lock().await.item.id;
|
|
match item_id {
|
|
id if id == Item::FIRE_CHARGE.id || id == Item::FLINT_AND_STEEL.id => {
|
|
BlockActionResult::Pass
|
|
} // Item::FIRE_CHARGE | Item::FLINT_AND_STEEL
|
|
_ => BlockActionResult::PassToDefaultBlockAction,
|
|
}
|
|
})
|
|
}
|
|
|
|
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
|
|
Box::pin(async move {
|
|
Self::consume_and_drop_candle(args.block, args.player, args.position, args.world).await
|
|
})
|
|
}
|
|
|
|
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
|
|
Box::pin(async move {
|
|
if !can_place_at(args.world.as_ref(), args.position).await {
|
|
args.world
|
|
.break_block(args.position, None, BlockFlags::empty())
|
|
.await;
|
|
}
|
|
})
|
|
}
|
|
|
|
fn get_state_for_neighbor_update<'a>(
|
|
&'a self,
|
|
args: GetStateForNeighborUpdateArgs<'a>,
|
|
) -> BlockFuture<'a, BlockStateId> {
|
|
Box::pin(async move {
|
|
if !can_place_at(args.world, args.position).await {
|
|
args.world
|
|
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
|
|
.await;
|
|
}
|
|
args.state_id
|
|
})
|
|
}
|
|
}
|
|
|
|
async fn can_place_at(world: &dyn BlockAccessor, position: &BlockPos) -> bool {
|
|
let state = world.get_block_state(&position.down()).await;
|
|
state.is_solid()
|
|
}
|