262 lines
7.5 KiB
Java
262 lines
7.5 KiB
Java
package net.minecraft.world.level.block.entity;
|
|
|
|
import net.minecraft.commands.CommandSource;
|
|
import net.minecraft.commands.CommandSourceStack;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.HolderLookup;
|
|
import net.minecraft.core.component.DataComponents;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.Clearable;
|
|
import net.minecraft.world.Container;
|
|
import net.minecraft.world.MenuProvider;
|
|
import net.minecraft.world.entity.player.Inventory;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
|
import net.minecraft.world.inventory.ContainerData;
|
|
import net.minecraft.world.inventory.LecternMenu;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.WrittenBookItem;
|
|
import net.minecraft.world.item.component.WritableBookContent;
|
|
import net.minecraft.world.item.component.WrittenBookContent;
|
|
import net.minecraft.world.level.block.LecternBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.phys.Vec2;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class LecternBlockEntity extends BlockEntity implements Clearable, MenuProvider {
|
|
public static final int DATA_PAGE = 0;
|
|
public static final int NUM_DATA = 1;
|
|
public static final int SLOT_BOOK = 0;
|
|
public static final int NUM_SLOTS = 1;
|
|
private final Container bookAccess = new Container() {
|
|
@Override
|
|
public int getContainerSize() {
|
|
return 1;
|
|
}
|
|
|
|
@Override
|
|
public boolean isEmpty() {
|
|
return LecternBlockEntity.this.book.isEmpty();
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getItem(int slot) {
|
|
return slot == 0 ? LecternBlockEntity.this.book : ItemStack.EMPTY;
|
|
}
|
|
|
|
@Override
|
|
public ItemStack removeItem(int slot, int amount) {
|
|
if (slot == 0) {
|
|
ItemStack itemStack = LecternBlockEntity.this.book.split(amount);
|
|
if (LecternBlockEntity.this.book.isEmpty()) {
|
|
LecternBlockEntity.this.onBookItemRemove();
|
|
}
|
|
|
|
return itemStack;
|
|
} else {
|
|
return ItemStack.EMPTY;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ItemStack removeItemNoUpdate(int slot) {
|
|
if (slot == 0) {
|
|
ItemStack itemStack = LecternBlockEntity.this.book;
|
|
LecternBlockEntity.this.book = ItemStack.EMPTY;
|
|
LecternBlockEntity.this.onBookItemRemove();
|
|
return itemStack;
|
|
} else {
|
|
return ItemStack.EMPTY;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setItem(int slot, ItemStack stack) {
|
|
}
|
|
|
|
@Override
|
|
public int getMaxStackSize() {
|
|
return 1;
|
|
}
|
|
|
|
@Override
|
|
public void setChanged() {
|
|
LecternBlockEntity.this.setChanged();
|
|
}
|
|
|
|
@Override
|
|
public boolean stillValid(Player player) {
|
|
return Container.stillValidBlockEntity(LecternBlockEntity.this, player) && LecternBlockEntity.this.hasBook();
|
|
}
|
|
|
|
@Override
|
|
public boolean canPlaceItem(int slot, ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void clearContent() {
|
|
}
|
|
};
|
|
private final ContainerData dataAccess = new ContainerData() {
|
|
@Override
|
|
public int get(int index) {
|
|
return index == 0 ? LecternBlockEntity.this.page : 0;
|
|
}
|
|
|
|
@Override
|
|
public void set(int index, int value) {
|
|
if (index == 0) {
|
|
LecternBlockEntity.this.setPage(value);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int getCount() {
|
|
return 1;
|
|
}
|
|
};
|
|
ItemStack book = ItemStack.EMPTY;
|
|
int page;
|
|
private int pageCount;
|
|
|
|
public LecternBlockEntity(BlockPos pos, BlockState blockState) {
|
|
super(BlockEntityType.LECTERN, pos, blockState);
|
|
}
|
|
|
|
public ItemStack getBook() {
|
|
return this.book;
|
|
}
|
|
|
|
/**
|
|
* @return whether the ItemStack in this lectern is a book or written book
|
|
*/
|
|
public boolean hasBook() {
|
|
return this.book.has(DataComponents.WRITABLE_BOOK_CONTENT) || this.book.has(DataComponents.WRITTEN_BOOK_CONTENT);
|
|
}
|
|
|
|
/**
|
|
* Sets the ItemStack in this lectern. Note that this does not update the block state, use {@link net.minecraft.world.level.block.LecternBlock#tryPlaceBook} for that.
|
|
*/
|
|
public void setBook(ItemStack stack) {
|
|
this.setBook(stack, null);
|
|
}
|
|
|
|
void onBookItemRemove() {
|
|
this.page = 0;
|
|
this.pageCount = 0;
|
|
LecternBlock.resetBookState(null, this.getLevel(), this.getBlockPos(), this.getBlockState(), false);
|
|
}
|
|
|
|
/**
|
|
* Sets the ItemStack in this lectern. Note that this does not update the block state, use {@link net.minecraft.world.level.block.LecternBlock#tryPlaceBook} for that.
|
|
*
|
|
* @param player the player used for resolving the components within the book
|
|
*/
|
|
public void setBook(ItemStack stack, @Nullable Player player) {
|
|
this.book = this.resolveBook(stack, player);
|
|
this.page = 0;
|
|
this.pageCount = getPageCount(this.book);
|
|
this.setChanged();
|
|
}
|
|
|
|
void setPage(int page) {
|
|
int i = Mth.clamp(page, 0, this.pageCount - 1);
|
|
if (i != this.page) {
|
|
this.page = i;
|
|
this.setChanged();
|
|
LecternBlock.signalPageChange(this.getLevel(), this.getBlockPos(), this.getBlockState());
|
|
}
|
|
}
|
|
|
|
public int getPage() {
|
|
return this.page;
|
|
}
|
|
|
|
public int getRedstoneSignal() {
|
|
float f = this.pageCount > 1 ? this.getPage() / (this.pageCount - 1.0F) : 1.0F;
|
|
return Mth.floor(f * 14.0F) + (this.hasBook() ? 1 : 0);
|
|
}
|
|
|
|
/**
|
|
* Resolves the contents of the passed ItemStack, if it is a book
|
|
*/
|
|
private ItemStack resolveBook(ItemStack stack, @Nullable Player player) {
|
|
if (this.level instanceof ServerLevel serverLevel) {
|
|
WrittenBookItem.resolveBookComponents(stack, this.createCommandSourceStack(player, serverLevel), player);
|
|
}
|
|
|
|
return stack;
|
|
}
|
|
|
|
private CommandSourceStack createCommandSourceStack(@Nullable Player player, ServerLevel serverLevel) {
|
|
String string;
|
|
Component component;
|
|
if (player == null) {
|
|
string = "Lectern";
|
|
component = Component.literal("Lectern");
|
|
} else {
|
|
string = player.getName().getString();
|
|
component = player.getDisplayName();
|
|
}
|
|
|
|
Vec3 vec3 = Vec3.atCenterOf(this.worldPosition);
|
|
return new CommandSourceStack(CommandSource.NULL, vec3, Vec2.ZERO, serverLevel, 2, string, component, serverLevel.getServer(), player);
|
|
}
|
|
|
|
@Override
|
|
public boolean onlyOpCanSetNbt() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
|
super.loadAdditional(tag, registries);
|
|
if (tag.contains("Book", 10)) {
|
|
this.book = this.resolveBook((ItemStack)ItemStack.parse(registries, tag.getCompound("Book")).orElse(ItemStack.EMPTY), null);
|
|
} else {
|
|
this.book = ItemStack.EMPTY;
|
|
}
|
|
|
|
this.pageCount = getPageCount(this.book);
|
|
this.page = Mth.clamp(tag.getInt("Page"), 0, this.pageCount - 1);
|
|
}
|
|
|
|
@Override
|
|
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
|
super.saveAdditional(tag, registries);
|
|
if (!this.getBook().isEmpty()) {
|
|
tag.put("Book", this.getBook().save(registries));
|
|
tag.putInt("Page", this.page);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void clearContent() {
|
|
this.setBook(ItemStack.EMPTY);
|
|
}
|
|
|
|
@Override
|
|
public AbstractContainerMenu createMenu(int i, Inventory inventory, Player player) {
|
|
return new LecternMenu(i, this.bookAccess, this.dataAccess);
|
|
}
|
|
|
|
@Override
|
|
public Component getDisplayName() {
|
|
return Component.translatable("container.lectern");
|
|
}
|
|
|
|
private static int getPageCount(ItemStack stack) {
|
|
WrittenBookContent writtenBookContent = stack.get(DataComponents.WRITTEN_BOOK_CONTENT);
|
|
if (writtenBookContent != null) {
|
|
return writtenBookContent.pages().size();
|
|
} else {
|
|
WritableBookContent writableBookContent = stack.get(DataComponents.WRITABLE_BOOK_CONTENT);
|
|
return writableBookContent != null ? writableBookContent.pages().size() : 0;
|
|
}
|
|
}
|
|
}
|