211 lines
8.0 KiB
Rust
211 lines
8.0 KiB
Rust
use crate::block::registry::BlockActionResult;
|
|
use crate::block::{
|
|
GetStateForNeighborUpdateArgs, NormalUseArgs, OnNeighborUpdateArgs, OnPlaceArgs,
|
|
UseWithItemArgs,
|
|
};
|
|
use pumpkin_data::BlockStateId;
|
|
use pumpkin_data::block_properties::{Axis, NoteblockInstrument};
|
|
use pumpkin_data::sound::{Sound, SoundCategory};
|
|
use pumpkin_data::{Block, block_properties::NoteBlockLikeProperties};
|
|
use pumpkin_macros::pumpkin_block;
|
|
use pumpkin_util::math::position::BlockPos;
|
|
use pumpkin_world::world::BlockFlags;
|
|
|
|
use crate::{
|
|
block::{BlockBehaviour, OnSyncedBlockEventArgs},
|
|
world::World,
|
|
};
|
|
|
|
use super::redstone::block_receives_redstone_power;
|
|
|
|
#[pumpkin_block("minecraft:note_block")]
|
|
pub struct NoteBlock;
|
|
|
|
impl NoteBlock {
|
|
pub fn play_note(props: &NoteBlockLikeProperties, world: &World, pos: &BlockPos) {
|
|
if !is_base_block(props.instrument) || world.get_block_state(&pos.up()).is_air() {
|
|
let mut event = crate::plugin::api::events::block::note_play::NotePlayEvent::new(
|
|
*pos,
|
|
format!("{:?}", props.instrument),
|
|
props.note,
|
|
);
|
|
if let Some(server) = world.server.upgrade() {
|
|
server.plugin_manager.fire_blocking(&server, &mut event);
|
|
}
|
|
if event.cancelled {
|
|
return;
|
|
}
|
|
world.add_synced_block_event(*pos, 0, 0);
|
|
}
|
|
}
|
|
fn get_note_pitch(note: u16) -> f32 {
|
|
((f32::from(note) - 12.0) / 12.0).exp2()
|
|
}
|
|
|
|
fn get_state_with_instrument(
|
|
world: &World,
|
|
pos: &BlockPos,
|
|
state: BlockStateId,
|
|
block: &Block,
|
|
) -> BlockStateId {
|
|
let upper_instrument = world.get_block_state(&pos.up()).instrument;
|
|
|
|
let mut note_props = NoteBlockLikeProperties::from_state_id(state);
|
|
if !is_base_block(upper_instrument) {
|
|
note_props.instrument = upper_instrument;
|
|
return note_props.to_state_id(block);
|
|
}
|
|
let below_instrument = world.get_block_state(&pos.down()).instrument;
|
|
let below_instrument = if is_base_block(below_instrument) {
|
|
below_instrument
|
|
} else {
|
|
NoteblockInstrument::Harp
|
|
};
|
|
note_props.instrument = below_instrument;
|
|
note_props.to_state_id(block)
|
|
}
|
|
}
|
|
|
|
impl BlockBehaviour for NoteBlock {
|
|
fn on_neighbor_update(&self, args: OnNeighborUpdateArgs<'_>) {
|
|
let block_state = args.world.get_block_state(args.position);
|
|
let mut note_props = NoteBlockLikeProperties::from_state_id(block_state.id);
|
|
let powered = block_receives_redstone_power(args.world, args.position);
|
|
// check if powered state changed
|
|
if note_props.powered != powered {
|
|
if powered {
|
|
Self::play_note(¬e_props, args.world, args.position);
|
|
}
|
|
note_props.powered = powered;
|
|
args.world.set_block_state(
|
|
args.position,
|
|
note_props.to_state_id(args.block),
|
|
BlockFlags::NOTIFY_ALL,
|
|
);
|
|
}
|
|
}
|
|
|
|
fn normal_use(&self, args: NormalUseArgs<'_>) -> BlockActionResult {
|
|
let block_state = args.world.get_block_state(args.position);
|
|
let mut note_props = NoteBlockLikeProperties::from_state_id(block_state.id);
|
|
note_props.note = (note_props.note + 1) % 25;
|
|
args.world.set_block_state(
|
|
args.position,
|
|
note_props.to_state_id(args.block),
|
|
BlockFlags::NOTIFY_ALL,
|
|
);
|
|
Self::play_note(¬e_props, args.world, args.position);
|
|
|
|
args.player.increment_stat(
|
|
pumpkin_data::statistic::StatisticCategory::Custom,
|
|
pumpkin_data::statistic::CustomStatistic::TuneNoteblock as i32,
|
|
1,
|
|
);
|
|
|
|
BlockActionResult::Success
|
|
}
|
|
|
|
fn use_with_item(&self, _args: UseWithItemArgs<'_>) -> BlockActionResult {
|
|
// TODO
|
|
BlockActionResult::PassToDefaultBlockAction
|
|
}
|
|
|
|
fn on_synced_block_event(&self, args: OnSyncedBlockEventArgs<'_>) -> bool {
|
|
let block_state = args.world.get_block_state(args.position);
|
|
let note_props = NoteBlockLikeProperties::from_state_id(block_state.id);
|
|
let instrument = note_props.instrument;
|
|
let pitch = if is_base_block(instrument) {
|
|
// checks if can be pitched
|
|
Self::get_note_pitch(u16::from(note_props.note))
|
|
} else {
|
|
1.0 // default pitch
|
|
};
|
|
// check hasCustomSound
|
|
args.world.play_sound_raw(
|
|
convert_instrument_to_sound(instrument) as u16,
|
|
SoundCategory::Records,
|
|
&args.position.to_f64(),
|
|
3.0,
|
|
pitch,
|
|
);
|
|
true
|
|
}
|
|
|
|
fn on_place(&self, args: OnPlaceArgs<'_>) -> BlockStateId {
|
|
Self::get_state_with_instrument(
|
|
args.world,
|
|
args.position,
|
|
Block::NOTE_BLOCK.default_state.id,
|
|
args.block,
|
|
)
|
|
}
|
|
|
|
fn get_state_for_neighbor_update(
|
|
&self,
|
|
args: GetStateForNeighborUpdateArgs<'_>,
|
|
) -> BlockStateId {
|
|
if args.direction.to_axis() == Axis::Y {
|
|
return Self::get_state_with_instrument(
|
|
args.world,
|
|
args.position,
|
|
args.state_id,
|
|
args.block,
|
|
);
|
|
}
|
|
args.state_id
|
|
}
|
|
}
|
|
|
|
const fn convert_instrument_to_sound(instrument: NoteblockInstrument) -> Sound {
|
|
match instrument {
|
|
NoteblockInstrument::Harp => Sound::BlockNoteBlockHarp,
|
|
NoteblockInstrument::Basedrum => Sound::BlockNoteBlockBasedrum,
|
|
NoteblockInstrument::Snare => Sound::BlockNoteBlockSnare,
|
|
NoteblockInstrument::Hat => Sound::BlockNoteBlockHat,
|
|
NoteblockInstrument::Bass => Sound::BlockNoteBlockBass,
|
|
NoteblockInstrument::Flute => Sound::BlockNoteBlockFlute,
|
|
NoteblockInstrument::Bell => Sound::BlockNoteBlockBell,
|
|
NoteblockInstrument::Guitar => Sound::BlockNoteBlockGuitar,
|
|
NoteblockInstrument::Chime => Sound::BlockNoteBlockChime,
|
|
NoteblockInstrument::Xylophone => Sound::BlockNoteBlockXylophone,
|
|
NoteblockInstrument::IronXylophone => Sound::BlockNoteBlockIronXylophone,
|
|
NoteblockInstrument::CowBell => Sound::BlockNoteBlockCowBell,
|
|
NoteblockInstrument::Didgeridoo => Sound::BlockNoteBlockDidgeridoo,
|
|
NoteblockInstrument::Bit => Sound::BlockNoteBlockBit,
|
|
NoteblockInstrument::Banjo => Sound::BlockNoteBlockBanjo,
|
|
NoteblockInstrument::Pling => Sound::BlockNoteBlockPling,
|
|
NoteblockInstrument::Zombie => Sound::BlockNoteBlockImitateZombie,
|
|
NoteblockInstrument::Skeleton => Sound::BlockNoteBlockImitateSkeleton,
|
|
NoteblockInstrument::Creeper => Sound::BlockNoteBlockImitateCreeper,
|
|
NoteblockInstrument::Dragon => Sound::BlockNoteBlockImitateEnderDragon,
|
|
NoteblockInstrument::WitherSkeleton => Sound::BlockNoteBlockImitateWitherSkeleton,
|
|
NoteblockInstrument::Piglin => Sound::BlockNoteBlockImitatePiglin,
|
|
NoteblockInstrument::CustomHead => Sound::UiButtonClick,
|
|
NoteblockInstrument::Trumpet => Sound::BlockNoteBlockTrumpet,
|
|
NoteblockInstrument::TrumpetExposed => Sound::BlockNoteBlockTrumpetExposed,
|
|
NoteblockInstrument::TrumpetOxidized => Sound::BlockNoteBlockTrumpetOxidized,
|
|
NoteblockInstrument::TrumpetWeathered => Sound::BlockNoteBlockTrumpetWeathered,
|
|
}
|
|
}
|
|
|
|
const fn is_base_block(instrument: NoteblockInstrument) -> bool {
|
|
matches!(
|
|
instrument,
|
|
NoteblockInstrument::Harp
|
|
| NoteblockInstrument::Basedrum
|
|
| NoteblockInstrument::Snare
|
|
| NoteblockInstrument::Hat
|
|
| NoteblockInstrument::Bass
|
|
| NoteblockInstrument::Flute
|
|
| NoteblockInstrument::Bell
|
|
| NoteblockInstrument::Guitar
|
|
| NoteblockInstrument::Chime
|
|
| NoteblockInstrument::Xylophone
|
|
| NoteblockInstrument::IronXylophone
|
|
| NoteblockInstrument::CowBell
|
|
| NoteblockInstrument::Didgeridoo
|
|
| NoteblockInstrument::Bit
|
|
| NoteblockInstrument::Banjo
|
|
)
|
|
}
|