164 lines
6.5 KiB
Java
164 lines
6.5 KiB
Java
package net.minecraft.world.level.block;
|
|
|
|
import com.mojang.serialization.MapCodec;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.stats.Stats;
|
|
import net.minecraft.tags.ItemTags;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.world.InteractionResult;
|
|
import net.minecraft.world.ItemInteractionResult;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import net.minecraft.world.level.block.entity.SkullBlockEntity;
|
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.StateDefinition;
|
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
|
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
|
|
import net.minecraft.world.level.gameevent.GameEvent;
|
|
import net.minecraft.world.phys.BlockHitResult;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class NoteBlock extends Block {
|
|
public static final MapCodec<NoteBlock> CODEC = simpleCodec(NoteBlock::new);
|
|
public static final EnumProperty<NoteBlockInstrument> INSTRUMENT = BlockStateProperties.NOTEBLOCK_INSTRUMENT;
|
|
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
|
|
public static final IntegerProperty NOTE = BlockStateProperties.NOTE;
|
|
public static final int NOTE_VOLUME = 3;
|
|
|
|
@Override
|
|
public MapCodec<NoteBlock> codec() {
|
|
return CODEC;
|
|
}
|
|
|
|
public NoteBlock(BlockBehaviour.Properties properties) {
|
|
super(properties);
|
|
this.registerDefaultState(this.stateDefinition.any().setValue(INSTRUMENT, NoteBlockInstrument.HARP).setValue(NOTE, 0).setValue(POWERED, false));
|
|
}
|
|
|
|
private BlockState setInstrument(LevelAccessor level, BlockPos pos, BlockState state) {
|
|
NoteBlockInstrument noteBlockInstrument = level.getBlockState(pos.above()).instrument();
|
|
if (noteBlockInstrument.worksAboveNoteBlock()) {
|
|
return state.setValue(INSTRUMENT, noteBlockInstrument);
|
|
} else {
|
|
NoteBlockInstrument noteBlockInstrument2 = level.getBlockState(pos.below()).instrument();
|
|
NoteBlockInstrument noteBlockInstrument3 = noteBlockInstrument2.worksAboveNoteBlock() ? NoteBlockInstrument.HARP : noteBlockInstrument2;
|
|
return state.setValue(INSTRUMENT, noteBlockInstrument3);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
|
return this.setInstrument(context.getLevel(), context.getClickedPos(), this.defaultBlockState());
|
|
}
|
|
|
|
@Override
|
|
protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
|
|
boolean bl = direction.getAxis() == Direction.Axis.Y;
|
|
return bl ? this.setInstrument(level, pos, state) : super.updateShape(state, direction, neighborState, level, pos, neighborPos);
|
|
}
|
|
|
|
@Override
|
|
protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, BlockPos neighborPos, boolean movedByPiston) {
|
|
boolean bl = level.hasNeighborSignal(pos);
|
|
if (bl != (Boolean)state.getValue(POWERED)) {
|
|
if (bl) {
|
|
this.playNote(null, state, level, pos);
|
|
}
|
|
|
|
level.setBlock(pos, state.setValue(POWERED, bl), 3);
|
|
}
|
|
}
|
|
|
|
private void playNote(@Nullable Entity entity, BlockState state, Level level, BlockPos pos) {
|
|
if (((NoteBlockInstrument)state.getValue(INSTRUMENT)).worksAboveNoteBlock() || level.getBlockState(pos.above()).isAir()) {
|
|
level.blockEvent(pos, this, 0, 0);
|
|
level.gameEvent(entity, GameEvent.NOTE_BLOCK_PLAY, pos);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected ItemInteractionResult useItemOn(
|
|
ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult
|
|
) {
|
|
return stack.is(ItemTags.NOTE_BLOCK_TOP_INSTRUMENTS) && hitResult.getDirection() == Direction.UP
|
|
? ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION
|
|
: super.useItemOn(stack, state, level, pos, player, hand, hitResult);
|
|
}
|
|
|
|
@Override
|
|
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
|
|
if (level.isClientSide) {
|
|
return InteractionResult.SUCCESS;
|
|
} else {
|
|
state = state.cycle(NOTE);
|
|
level.setBlock(pos, state, 3);
|
|
this.playNote(player, state, level, pos);
|
|
player.awardStat(Stats.TUNE_NOTEBLOCK);
|
|
return InteractionResult.CONSUME;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void attack(BlockState state, Level level, BlockPos pos, Player player) {
|
|
if (!level.isClientSide) {
|
|
this.playNote(player, state, level, pos);
|
|
player.awardStat(Stats.PLAY_NOTEBLOCK);
|
|
}
|
|
}
|
|
|
|
public static float getPitchFromNote(int note) {
|
|
return (float)Math.pow(2.0, (note - 12) / 12.0);
|
|
}
|
|
|
|
@Override
|
|
protected boolean triggerEvent(BlockState state, Level level, BlockPos pos, int id, int param) {
|
|
NoteBlockInstrument noteBlockInstrument = state.getValue(INSTRUMENT);
|
|
float f;
|
|
if (noteBlockInstrument.isTunable()) {
|
|
int i = (Integer)state.getValue(NOTE);
|
|
f = getPitchFromNote(i);
|
|
level.addParticle(ParticleTypes.NOTE, pos.getX() + 0.5, pos.getY() + 1.2, pos.getZ() + 0.5, i / 24.0, 0.0, 0.0);
|
|
} else {
|
|
f = 1.0F;
|
|
}
|
|
|
|
Holder<SoundEvent> holder;
|
|
if (noteBlockInstrument.hasCustomSound()) {
|
|
ResourceLocation resourceLocation = this.getCustomSoundId(level, pos);
|
|
if (resourceLocation == null) {
|
|
return false;
|
|
}
|
|
|
|
holder = Holder.direct(SoundEvent.createVariableRangeEvent(resourceLocation));
|
|
} else {
|
|
holder = noteBlockInstrument.getSoundEvent();
|
|
}
|
|
|
|
level.playSeededSound(null, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, holder, SoundSource.RECORDS, 3.0F, f, level.random.nextLong());
|
|
return true;
|
|
}
|
|
|
|
@Nullable
|
|
private ResourceLocation getCustomSoundId(Level level, BlockPos pos) {
|
|
return level.getBlockEntity(pos.above()) instanceof SkullBlockEntity skullBlockEntity ? skullBlockEntity.getNoteBlockSound() : null;
|
|
}
|
|
|
|
@Override
|
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
|
builder.add(INSTRUMENT, POWERED, NOTE);
|
|
}
|
|
}
|