package lv.enes.mc.eris_alchemy.block.entity; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import lv.enes.mc.eris_alchemy.menu.ChestLikeMenu; import net.minecraft.client.resources.model.Material; import net.minecraft.core.BlockPos; import net.minecraft.core.NonNullList; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.Container; import net.minecraft.world.ContainerHelper; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.*; import net.minecraft.world.level.block.state.BlockState; import org.quiltmc.loader.api.minecraft.ClientOnly; public abstract class ChestLikeEntity extends BaseContainerBlockEntity implements LidBlockEntity { protected static final int EVENT_INTERACTED = 1; protected final ChestLidController lidController = new ChestLidController(); protected final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() { @Override protected void onOpen(Level world, BlockPos pos, BlockState state) { ChestLikeEntity.this.onOpen(world, pos); } @Override protected void onClose(Level world, BlockPos pos, BlockState state) { ChestLikeEntity.this.onClose(world, pos); } @Override protected void openerCountChanged(Level world, BlockPos pos, BlockState state, int oldViewerCount, int newViewerCount) { world.blockEvent(worldPosition, getParent(), EVENT_INTERACTED, newViewerCount); } @Override protected boolean isOwnContainer(Player player) { if (player.containerMenu instanceof ChestLikeMenu menu) { return menu.getContainer() == ChestLikeEntity.this; } return false; } }; public ChestLikeEntity( BlockEntityType type, BlockPos pos, BlockState state ) { super(type, pos, state); } @Nonnull protected abstract NonNullList getItems(); @ClientOnly @Nonnull public abstract Material getMaterial(); @Nonnull protected abstract Block getParent(); @Override public void clearContent() { getItems().clear(); } @Override public int getContainerSize() { return getItems().size(); } @Nonnull @Override protected Component getDefaultName() { return getBlockState().getBlock().getName(); } @Nonnull @Override public ItemStack getItem(int slot) { return getItems().get(slot); } @Override public float getOpenNess(float tickDelta) { return lidController.getOpenness(tickDelta); } @Override public boolean isEmpty() { return getItems().stream().allMatch(ItemStack::isEmpty); } @Override public void load(CompoundTag nbt) { super.load(nbt); ContainerHelper.loadAllItems(nbt, getItems()); } protected void onClose(@Nullable Level world, BlockPos pos) { if (world == null) { return; } world.playSound( null, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, SoundEvents.CHEST_OPEN, SoundSource.BLOCKS, 0.5f, world.random.nextFloat() * 0.1f + 0.9f ); } protected void onOpen(@Nullable Level world, BlockPos pos) { if (world == null) { return; } world.playSound( null, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, SoundEvents.CHEST_CLOSE, SoundSource.BLOCKS, 0.5f, world.random.nextFloat() * 0.1f + 0.9f ); } private void recheckOpen() { if (!remove) { openersCounter.recheckOpeners(getLevel(), getBlockPos(), getBlockState()); } } @Nonnull @Override public ItemStack removeItem(int slot, int amount) { var stack = ContainerHelper.removeItem(getItems(), slot, amount); if (!stack.isEmpty()) { setChanged(); } return stack; } @Nonnull @Override public ItemStack removeItemNoUpdate(int slot) { return ContainerHelper.takeItem(getItems(), slot); } @Override protected void saveAdditional(CompoundTag nbt) { super.saveAdditional(nbt); ContainerHelper.saveAllItems(nbt, getItems()); } @Override public void setItem(int slot, ItemStack stack) { getItems().set(slot, stack); if (stack.getCount() > getMaxStackSize()) { stack.setCount(getMaxStackSize()); } setChanged(); } @Override public void startOpen(Player player) { if (!remove && !player.isSpectator()) { openersCounter.incrementOpeners(player, getLevel(), getBlockPos(), getBlockState()); } } @Override public boolean stillValid(Player player) { return Container.stillValidBlockEntity(this, player); } @Override public void stopOpen(Player player) { if (!remove && !player.isSpectator()) { openersCounter.decrementOpeners(player, getLevel(), getBlockPos(), getBlockState()); } } public void tick(Level world, BlockPos ignoredPos, BlockState ignoredState) { if (world.isClientSide) { lidController.tickLid(); } recheckOpen(); } @Override public boolean triggerEvent(int type, int data) { if (type == EVENT_INTERACTED) { lidController.shouldBeOpen(data > 0); return true; } return super.triggerEvent(type, data); } }