167 lines
6.7 KiB
Java
167 lines
6.7 KiB
Java
|
package net.minecraft.world.level.block.entity;
|
||
|
|
||
|
import com.google.common.annotations.VisibleForTesting;
|
||
|
import java.util.Optional;
|
||
|
import net.minecraft.core.BlockPos;
|
||
|
import net.minecraft.core.Holder;
|
||
|
import net.minecraft.core.HolderLookup;
|
||
|
import net.minecraft.core.component.DataComponents;
|
||
|
import net.minecraft.nbt.CompoundTag;
|
||
|
import net.minecraft.nbt.NbtOps;
|
||
|
import net.minecraft.nbt.Tag;
|
||
|
import net.minecraft.resources.RegistryOps;
|
||
|
import net.minecraft.world.Container;
|
||
|
import net.minecraft.world.entity.item.ItemEntity;
|
||
|
import net.minecraft.world.item.ItemStack;
|
||
|
import net.minecraft.world.item.JukeboxSong;
|
||
|
import net.minecraft.world.item.JukeboxSongPlayer;
|
||
|
import net.minecraft.world.level.Level;
|
||
|
import net.minecraft.world.level.block.JukeboxBlock;
|
||
|
import net.minecraft.world.level.block.state.BlockState;
|
||
|
import net.minecraft.world.level.gameevent.GameEvent;
|
||
|
import net.minecraft.world.phys.Vec3;
|
||
|
import net.minecraft.world.ticks.ContainerSingleItem;
|
||
|
|
||
|
public class JukeboxBlockEntity extends BlockEntity implements ContainerSingleItem.BlockContainerSingleItem {
|
||
|
public static final String SONG_ITEM_TAG_ID = "RecordItem";
|
||
|
public static final String TICKS_SINCE_SONG_STARTED_TAG_ID = "ticks_since_song_started";
|
||
|
private ItemStack item = ItemStack.EMPTY;
|
||
|
private final JukeboxSongPlayer jukeboxSongPlayer = new JukeboxSongPlayer(this::onSongChanged, this.getBlockPos());
|
||
|
|
||
|
public JukeboxBlockEntity(BlockPos p_155613_, BlockState p_155614_) {
|
||
|
super(BlockEntityType.JUKEBOX, p_155613_, p_155614_);
|
||
|
}
|
||
|
|
||
|
public JukeboxSongPlayer getSongPlayer() {
|
||
|
return this.jukeboxSongPlayer;
|
||
|
}
|
||
|
|
||
|
public void onSongChanged() {
|
||
|
this.level.updateNeighborsAt(this.getBlockPos(), this.getBlockState().getBlock());
|
||
|
this.setChanged();
|
||
|
}
|
||
|
|
||
|
private void notifyItemChangedInJukebox(boolean p_342785_) {
|
||
|
if (this.level != null && this.level.getBlockState(this.getBlockPos()) == this.getBlockState()) {
|
||
|
this.level.setBlock(this.getBlockPos(), this.getBlockState().setValue(JukeboxBlock.HAS_RECORD, p_342785_), 2);
|
||
|
this.level.gameEvent(GameEvent.BLOCK_CHANGE, this.getBlockPos(), GameEvent.Context.of(this.getBlockState()));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void popOutTheItem() {
|
||
|
if (this.level != null && !this.level.isClientSide) {
|
||
|
BlockPos blockpos = this.getBlockPos();
|
||
|
ItemStack itemstack = this.getTheItem();
|
||
|
if (!itemstack.isEmpty()) {
|
||
|
this.removeTheItem();
|
||
|
Vec3 vec3 = Vec3.atLowerCornerWithOffset(blockpos, 0.5, 1.01, 0.5).offsetRandom(this.level.random, 0.7F);
|
||
|
ItemStack itemstack1 = itemstack.copy();
|
||
|
ItemEntity itementity = new ItemEntity(this.level, vec3.x(), vec3.y(), vec3.z(), itemstack1);
|
||
|
itementity.setDefaultPickUpDelay();
|
||
|
this.level.addFreshEntity(itementity);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static void tick(Level p_273615_, BlockPos p_273143_, BlockState p_273372_, JukeboxBlockEntity p_343932_) {
|
||
|
p_343932_.jukeboxSongPlayer.tick(p_273615_, p_273372_);
|
||
|
}
|
||
|
|
||
|
public int getComparatorOutput() {
|
||
|
return JukeboxSong.fromStack(this.level.registryAccess(), this.item).map(Holder::value).map(JukeboxSong::comparatorOutput).orElse(0);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void loadAdditional(CompoundTag p_329712_, HolderLookup.Provider p_330255_) {
|
||
|
super.loadAdditional(p_329712_, p_330255_);
|
||
|
RegistryOps<Tag> registryops = p_330255_.createSerializationContext(NbtOps.INSTANCE);
|
||
|
ItemStack itemstack = p_329712_.read("RecordItem", ItemStack.CODEC, registryops).orElse(ItemStack.EMPTY);
|
||
|
if (!this.item.isEmpty() && !ItemStack.isSameItemSameComponents(itemstack, this.item)) {
|
||
|
this.jukeboxSongPlayer.stop(this.level, this.getBlockState());
|
||
|
}
|
||
|
|
||
|
this.item = itemstack;
|
||
|
p_329712_.getLong("ticks_since_song_started")
|
||
|
.ifPresent(
|
||
|
p_390965_ -> JukeboxSong.fromStack(p_330255_, this.item)
|
||
|
.ifPresent(p_390967_ -> this.jukeboxSongPlayer.setSongWithoutPlaying((Holder<JukeboxSong>)p_390967_, p_390965_))
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void saveAdditional(CompoundTag p_187507_, HolderLookup.Provider p_332390_) {
|
||
|
super.saveAdditional(p_187507_, p_332390_);
|
||
|
if (!this.getTheItem().isEmpty()) {
|
||
|
RegistryOps<Tag> registryops = p_332390_.createSerializationContext(NbtOps.INSTANCE);
|
||
|
p_187507_.store("RecordItem", ItemStack.CODEC, registryops, this.getTheItem());
|
||
|
}
|
||
|
|
||
|
if (this.jukeboxSongPlayer.getSong() != null) {
|
||
|
p_187507_.putLong("ticks_since_song_started", this.jukeboxSongPlayer.getTicksSinceSongStarted());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public ItemStack getTheItem() {
|
||
|
return this.item;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public ItemStack splitTheItem(int p_309876_) {
|
||
|
ItemStack itemstack = this.item;
|
||
|
this.setTheItem(ItemStack.EMPTY);
|
||
|
return itemstack;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setTheItem(ItemStack p_309430_) {
|
||
|
this.item = p_309430_;
|
||
|
boolean flag = !this.item.isEmpty();
|
||
|
Optional<Holder<JukeboxSong>> optional = JukeboxSong.fromStack(this.level.registryAccess(), this.item);
|
||
|
this.notifyItemChangedInJukebox(flag);
|
||
|
if (flag && optional.isPresent()) {
|
||
|
this.jukeboxSongPlayer.play(this.level, optional.get());
|
||
|
} else {
|
||
|
this.jukeboxSongPlayer.stop(this.level, this.getBlockState());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getMaxStackSize() {
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public BlockEntity getContainerBlockEntity() {
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean canPlaceItem(int p_273369_, ItemStack p_273689_) {
|
||
|
return p_273689_.has(DataComponents.JUKEBOX_PLAYABLE) && this.getItem(p_273369_).isEmpty();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean canTakeItem(Container p_273497_, int p_273168_, ItemStack p_273785_) {
|
||
|
return p_273497_.hasAnyMatching(ItemStack::isEmpty);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void preRemoveSideEffects(BlockPos p_392593_, BlockState p_397692_) {
|
||
|
this.popOutTheItem();
|
||
|
}
|
||
|
|
||
|
@VisibleForTesting
|
||
|
public void setSongItemWithoutPlaying(ItemStack p_343692_) {
|
||
|
this.item = p_343692_;
|
||
|
JukeboxSong.fromStack(this.level.registryAccess(), p_343692_).ifPresent(p_343857_ -> this.jukeboxSongPlayer.setSongWithoutPlaying((Holder<JukeboxSong>)p_343857_, 0L));
|
||
|
this.level.updateNeighborsAt(this.getBlockPos(), this.getBlockState().getBlock());
|
||
|
this.setChanged();
|
||
|
}
|
||
|
|
||
|
@VisibleForTesting
|
||
|
public void tryForcePlaySong() {
|
||
|
JukeboxSong.fromStack(this.level.registryAccess(), this.getTheItem())
|
||
|
.ifPresent(p_343793_ -> this.jukeboxSongPlayer.play(this.level, (Holder<JukeboxSong>)p_343793_));
|
||
|
}
|
||
|
}
|