From c27088bb3ba8e83d9fd4b5bd0d944be54c1482b2 Mon Sep 17 00:00:00 2001 From: Uko Kokņevičs Date: Wed, 10 Jan 2024 02:05:34 +0100 Subject: Move out common chest logic to separate files --- .../eris_alchemy/block/AlchemicalChestBlock.java | 196 +------------------ .../enes/mc/eris_alchemy/block/ChestLikeBlock.java | 213 +++++++++++++++++++++ .../block/entity/AlchemicalChestBlockEntity.java | 174 +---------------- .../block/entity/ChestLikeBlockEntity.java | 200 +++++++++++++++++++ .../mc/eris_alchemy/menu/AlchemicalChestMenu.java | 58 +----- .../mc/eris_alchemy/menu/ChestLikeBlockMenu.java | 67 +++++++ 6 files changed, 500 insertions(+), 408 deletions(-) create mode 100644 src/main/java/lv/enes/mc/eris_alchemy/block/ChestLikeBlock.java create mode 100644 src/main/java/lv/enes/mc/eris_alchemy/block/entity/ChestLikeBlockEntity.java create mode 100644 src/main/java/lv/enes/mc/eris_alchemy/menu/ChestLikeBlockMenu.java (limited to 'src/main/java') diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/AlchemicalChestBlock.java b/src/main/java/lv/enes/mc/eris_alchemy/block/AlchemicalChestBlock.java index 1d8698a..d50ee77 100644 --- a/src/main/java/lv/enes/mc/eris_alchemy/block/AlchemicalChestBlock.java +++ b/src/main/java/lv/enes/mc/eris_alchemy/block/AlchemicalChestBlock.java @@ -4,144 +4,23 @@ import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry; import lv.enes.mc.eris_alchemy.block.entity.AlchemicalChestBlockEntity; -import lv.enes.mc.eris_alchemy.menu.AlchemicalChestMenu; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; -import net.minecraft.world.*; -import net.minecraft.world.entity.monster.piglin.PiglinAi; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.context.BlockPlaceContext; -import net.minecraft.world.level.BlockGetter; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; -import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityTicker; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.ChestBlockEntity; 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.DirectionProperty; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.level.material.Fluids; -import net.minecraft.world.level.pathfinder.PathComputationType; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.shapes.CollisionContext; -import net.minecraft.world.phys.shapes.VoxelShape; -public class AlchemicalChestBlock - extends AbstractChestBlock - implements SimpleWaterloggedBlock +public class AlchemicalChestBlock extends ChestLikeBlock { - public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; - public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; - public static final Component CONTAINER_TITLE = Component.translatable("container.eris_alchemy.alchemical_chest"); - public static final VoxelShape SHAPE = Block.box( - 1.0, 0.0, 1.0, - 15.0, 14.0, 15.0 - ); - - public static Container getContainer(Level world, BlockPos pos) { - if (world.getBlockEntity(pos) instanceof AlchemicalChestBlockEntity container) { - return container; - } - return null; - } public AlchemicalChestBlock(Properties properties) { super(properties, () -> ErisAlchemyRegistry.BlockEntities.ALCHEMICAL_CHEST); - registerDefaultState(getStateDefinition().any() - .setValue(FACING, Direction.NORTH) - .setValue(WATERLOGGED, false) - ); - } - - @Nonnull - @Override - public DoubleBlockCombiner.NeighborCombineResult combine( - BlockState state, - Level world, - BlockPos pos, - boolean ignoreBlocked - ) { - return DoubleBlockCombiner.Combiner::acceptNone; - } - - @SuppressWarnings("deprecation") - @Override - public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) { - return AlchemicalChestMenu.getRedstoneSignalFromContainer(getContainer(world, pos)); - } - - @SuppressWarnings("deprecation") - @Nonnull - @Override - public FluidState getFluidState(BlockState state) { - return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state); - } - - @Override - public MenuProvider getMenuProvider(BlockState state, Level world, BlockPos pos) { - if (world.getBlockEntity(pos) instanceof AlchemicalChestBlockEntity entity) { - return new SimpleMenuProvider(entity, CONTAINER_TITLE); - } - return null; } - @Nonnull @Override - public RenderShape getRenderShape(BlockState state) { - return RenderShape.ENTITYBLOCK_ANIMATED; - } - - @SuppressWarnings("deprecation") @Nonnull - @Override - public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext ctx) { - return SHAPE; - } - - @Override - public BlockState getStateForPlacement(BlockPlaceContext ctx) { - return defaultBlockState() - .setValue(FACING, ctx.getHorizontalDirection().getOpposite()) - .setValue(WATERLOGGED, ctx.getLevel().getFluidState(ctx.getClickedPos()).is(Fluids.WATER)); - } - - @Override - public BlockEntityTicker getTicker( - Level ignoredWorld, - BlockState ignoredState, - BlockEntityType type - ) { - return createTickerHelper( - type, - blockEntityType.get(), - (world, pos, state, entity) -> entity.tick(world, pos, state) - ); - } - - @SuppressWarnings("deprecation") - @Override - public boolean hasAnalogOutputSignal(BlockState state) { - return true; - } - - @SuppressWarnings("deprecation") - @Override - public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) { - return false; - } - - @SuppressWarnings("deprecation") - @Nonnull - @Override - public BlockState mirror(BlockState state, Mirror mirror) { - return state.rotate(mirror.getRotation(state.getValue(FACING))); + protected Component getContainerTitle() { + return CONTAINER_TITLE; } @Nullable @@ -149,73 +28,4 @@ public class AlchemicalChestBlock public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { return new AlchemicalChestBlockEntity(pos, state); } - - @SuppressWarnings("deprecation") - @Override - public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) { - if (!state.is(newState.getBlock())) { - var entity = world.getBlockEntity(pos); - if (entity instanceof Container container) { - Containers.dropContents(world, pos, container); - world.updateNeighbourForOutputSignal(pos, this); - } - - super.onRemove(state, world, pos, newState, moved); - } - } - - @SuppressWarnings("deprecation") - @Nonnull - @Override - public BlockState rotate(BlockState state, Rotation rotation) { - return state.setValue(FACING, rotation.rotate(state.getValue(FACING))); - } - - @SuppressWarnings("deprecation") - @Nonnull - @Override - public BlockState updateShape( - BlockState state, - Direction direction, - BlockState neighborState, - LevelAccessor world, - BlockPos pos, - BlockPos neighborPos - ) { - if (state.getValue(WATERLOGGED)) { - world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); - } - - return super.updateShape(state, direction, neighborState, world, pos, neighborPos); - } - - @SuppressWarnings("deprecation") - @Nonnull - @Override - public InteractionResult use( - BlockState state, - Level world, - BlockPos pos, - Player player, - InteractionHand hand, - BlockHitResult hit - ) { - if (world.isClientSide) { - return InteractionResult.SUCCESS; - } - - var provider = getMenuProvider(state, world, pos); - if (provider != null) { - player.openMenu(provider); - // TODO: player.awardStat(getOpenChestStat); - PiglinAi.angerNearbyPiglins(player, true); - } - - return InteractionResult.CONSUME; - } - - @Override - protected void createBlockStateDefinition(StateDefinition.Builder builder) { - builder.add(FACING, WATERLOGGED); - } } diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/ChestLikeBlock.java b/src/main/java/lv/enes/mc/eris_alchemy/block/ChestLikeBlock.java new file mode 100644 index 0000000..e50563a --- /dev/null +++ b/src/main/java/lv/enes/mc/eris_alchemy/block/ChestLikeBlock.java @@ -0,0 +1,213 @@ +package lv.enes.mc.eris_alchemy.block; + +import jakarta.annotation.Nonnull; +import lv.enes.mc.eris_alchemy.block.entity.ChestLikeBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.*; +import net.minecraft.world.entity.monster.piglin.PiglinAi; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.DoubleBlockCombiner.NeighborCombineResult; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.ChestBlockEntity; +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.DirectionProperty; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; + +import java.util.function.Supplier; + +public abstract class ChestLikeBlock + extends AbstractChestBlock + implements SimpleWaterloggedBlock +{ + public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; + public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; + + public static final VoxelShape SHAPE = Block.box( + 1.0, 0.0, 1.0, + 15.0, 14.0, 15.0 + ); + + protected ChestLikeBlock(Properties settings, Supplier> blockEntityTypeSupplier) { + super(settings, blockEntityTypeSupplier); + registerDefaultState(getStateDefinition().any() + .setValue(FACING, Direction.NORTH) + .setValue(WATERLOGGED, false) + ); + } + + @Nonnull + protected abstract Component getContainerTitle(); + + @Nonnull + @Override + public NeighborCombineResult combine( + BlockState state, + Level world, + BlockPos pos, + boolean ignoreBlocked + ) { + return DoubleBlockCombiner.Combiner::acceptNone; + } + + @SuppressWarnings("deprecation") + @Override + public int getAnalogOutputSignal(BlockState state, Level world, BlockPos pos) { + if (world.getBlockEntity(pos) instanceof Container container) { + return AbstractContainerMenu.getRedstoneSignalFromContainer(container); + } + return 0; + } + + @SuppressWarnings("deprecation") + @Nonnull + @Override + public FluidState getFluidState(BlockState state) { + return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state); + } + + @Override + public MenuProvider getMenuProvider(BlockState state, Level world, BlockPos pos) { + if (world.getBlockEntity(pos) instanceof ChestLikeBlockEntity entity) { + return new SimpleMenuProvider(entity, getContainerTitle()); + } + return null; + } + + @Nonnull + @Override + public RenderShape getRenderShape(BlockState state) { + return RenderShape.ENTITYBLOCK_ANIMATED; + } + + @SuppressWarnings("deprecation") + @Nonnull + @Override + public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext ctx) { + return SHAPE; + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext ctx) { + return defaultBlockState() + .setValue(FACING, ctx.getHorizontalDirection().getOpposite()) + .setValue(WATERLOGGED, ctx.getLevel().getFluidState(ctx.getClickedPos()).is(Fluids.WATER)); + } + + @Override + public BlockEntityTicker getTicker( + Level ignoredWorld, + BlockState ignoredState, + BlockEntityType type + ) { + return createTickerHelper( + type, + blockEntityType.get(), + (world, pos, state, entity) -> entity.tick(world, pos, state) + ); + } + + @SuppressWarnings("deprecation") + @Override + public boolean hasAnalogOutputSignal(BlockState state) { + return true; + } + + @SuppressWarnings("deprecation") + @Override + public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) { + return false; + } + + @SuppressWarnings("deprecation") + @Nonnull + @Override + public BlockState mirror(BlockState state, Mirror mirror) { + return state.rotate(mirror.getRotation(state.getValue(FACING))); + } + + @SuppressWarnings("deprecation") + @Override + public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean moved) { + if (!state.is(newState.getBlock())) { + if (world.getBlockEntity(pos) instanceof Container container) { + Containers.dropContents(world, pos, container); + world.updateNeighbourForOutputSignal(pos, this); + } + + super.onRemove(state, world, pos, newState, moved); + } + } + + @SuppressWarnings("deprecation") + @Nonnull + @Override + public BlockState rotate(BlockState state, Rotation rotation) { + return state.setValue(FACING, rotation.rotate(state.getValue(FACING))); + } + + @SuppressWarnings("deprecation") + @Nonnull + @Override + public BlockState updateShape( + BlockState state, + Direction direction, + BlockState neighborState, + LevelAccessor world, + BlockPos pos, + BlockPos neighborPos + ) { + if (state.getValue(WATERLOGGED)) { + world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world)); + } + + return super.updateShape(state, direction, neighborState, world, pos, neighborPos); + } + + @SuppressWarnings("deprecation") + @Nonnull + @Override + public InteractionResult use( + BlockState state, + Level world, + BlockPos pos, + Player player, + InteractionHand hand, + BlockHitResult hit + ) { + if (world.isClientSide) { + return InteractionResult.SUCCESS; + } + + var provider = getMenuProvider(state, world, pos); + if (provider != null) { + player.openMenu(provider); + // TODO: player.awardStat(getOpenChestStat); + PiglinAi.angerNearbyPiglins(player, true); + } + + return InteractionResult.CONSUME; + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(FACING, WATERLOGGED); + } +} diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/entity/AlchemicalChestBlockEntity.java b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/AlchemicalChestBlockEntity.java index 1e881f8..bac49b6 100644 --- a/src/main/java/lv/enes/mc/eris_alchemy/block/entity/AlchemicalChestBlockEntity.java +++ b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/AlchemicalChestBlockEntity.java @@ -3,202 +3,44 @@ package lv.enes.mc.eris_alchemy.block.entity; import jakarta.annotation.Nonnull; import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry; import lv.enes.mc.eris_alchemy.menu.AlchemicalChestMenu; +import lv.enes.mc.eris_alchemy.menu.ChestLikeBlockMenu; 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.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; -import net.minecraft.world.level.block.entity.ChestLidController; -import net.minecraft.world.level.block.entity.ContainerOpenersCounter; -import net.minecraft.world.level.block.entity.LidBlockEntity; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -public class AlchemicalChestBlockEntity extends BaseContainerBlockEntity implements LidBlockEntity { +public class AlchemicalChestBlockEntity extends ChestLikeBlockEntity { private final static int WIDTH = 13; private final static int HEIGHT = 8; - private final static int EVENT = 1; - private final NonNullList items = NonNullList.withSize(WIDTH * HEIGHT, ItemStack.EMPTY); - private final ChestLidController lidController = new ChestLidController(); - private final ContainerOpenersCounter openersCounter = new ContainerOpenersCounter() { - @Override - protected void onOpen(Level world, BlockPos pos, BlockState state) { - // TODO: Sound effects? - world.playSound( - null, - pos.getX() + 0.5, - pos.getY() + 0.5, - pos.getZ() + 0.5, - SoundEvents.ENDER_CHEST_OPEN, - SoundSource.BLOCKS, - 0.5f, - world.random.nextFloat() * 0.1f + 0.9f - ); - } - - @Override - protected void onClose(Level world, BlockPos pos, BlockState state) { - // TODO: Sound effects? - world.playSound( - null, - pos.getX() + 0.5, - pos.getY() + 0.5, - pos.getZ() + 0.5, - SoundEvents.ENDER_CHEST_CLOSE, - SoundSource.BLOCKS, - 0.5f, - world.random.nextFloat() * 0.1f + 0.9f - ); - } - - @Override - protected void openerCountChanged( - Level world, - BlockPos pos, - BlockState state, - int oldViewerCount, - int newViewerCount - ) { - world.blockEvent(worldPosition, ErisAlchemyRegistry.Blocks.ALCHEMICAL_CHEST, EVENT, newViewerCount); - } - - @Override - protected boolean isOwnContainer(Player player) { - if (player.containerMenu instanceof AlchemicalChestMenu menu) { - return menu.getContainer() == AlchemicalChestBlockEntity.this; - } - return false; - } - }; public AlchemicalChestBlockEntity(BlockPos pos, BlockState state) { super(ErisAlchemyRegistry.BlockEntities.ALCHEMICAL_CHEST, pos, state); } - @Override - public void clearContent() { - items.clear(); - } - @Nonnull @Override - protected AbstractContainerMenu createMenu(int syncId, Inventory playerInventory) { + protected ChestLikeBlockMenu createMenu(int syncId, Inventory playerInventory) { return new AlchemicalChestMenu(syncId, playerInventory, this); } - @Override - public int getContainerSize() { - return items.size(); - } - @Nonnull @Override protected Component getDefaultName() { return Component.translatable("container.eris_alchemy.alchemical_chest"); } - @Nonnull - @Override - public ItemStack getItem(int slot) { - return items.get(slot); - } - - @Override - public float getOpenNess(float tickDelta) { - return lidController.getOpenness(tickDelta); - } - - @Override - public boolean isEmpty() { - return items.stream().allMatch(ItemStack::isEmpty); - } - - @Override - public void load(CompoundTag nbt) { - super.load(nbt); - ContainerHelper.loadAllItems(nbt, items); - } - - private void recheckOpen() { - if (!remove) { - openersCounter.recheckOpeners(getLevel(), getBlockPos(), getBlockState()); - } - } - - @Nonnull - @Override - public ItemStack removeItem(int slot, int amount) { - var stack = ContainerHelper.removeItem(items, slot, amount); - if (!stack.isEmpty()) { - this.setChanged(); - } - return stack; - } - - @Nonnull - @Override - public ItemStack removeItemNoUpdate(int slot) { - return ContainerHelper.takeItem(items, slot); - } - - @Override - protected void saveAdditional(CompoundTag nbt) { - super.saveAdditional(nbt); - ContainerHelper.saveAllItems(nbt, items); - } - @Override - public void setItem(int slot, ItemStack stack) { - items.set(slot, stack); - if (stack.getCount() > getMaxStackSize()) { - stack.setCount(getMaxStackSize()); - } - this.setChanged(); + protected NonNullList getItems() { + return items; } @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) { - lidController.shouldBeOpen(data > 0); - return true; - } - - return super.triggerEvent(type, data); + protected Block getParent() { + return ErisAlchemyRegistry.Blocks.ALCHEMICAL_CHEST; } } diff --git a/src/main/java/lv/enes/mc/eris_alchemy/block/entity/ChestLikeBlockEntity.java b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/ChestLikeBlockEntity.java new file mode 100644 index 0000000..48b3ad7 --- /dev/null +++ b/src/main/java/lv/enes/mc/eris_alchemy/block/entity/ChestLikeBlockEntity.java @@ -0,0 +1,200 @@ +package lv.enes.mc.eris_alchemy.block.entity; + +import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; +import lv.enes.mc.eris_alchemy.menu.ChestLikeBlockMenu; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; +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; + +public abstract class ChestLikeBlockEntity 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) { + ChestLikeBlockEntity.this.onOpen(world, pos); + } + + @Override + protected void onClose(Level world, BlockPos pos, BlockState state) { + ChestLikeBlockEntity.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 ChestLikeBlockMenu menu) { + return menu.getContainer() == ChestLikeBlockEntity.this; + } + return false; + } + }; + + public ChestLikeBlockEntity( + BlockEntityType type, + BlockPos pos, + BlockState state + ) { + super(type, pos, state); + } + + protected abstract Block getParent(); + protected abstract NonNullList getItems(); + + @Override + public void clearContent() { + getItems().clear(); + } + + @Override + public int getContainerSize() { + return getItems().size(); + } + + @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()) { + this.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()); + } + this.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); + } +} + diff --git a/src/main/java/lv/enes/mc/eris_alchemy/menu/AlchemicalChestMenu.java b/src/main/java/lv/enes/mc/eris_alchemy/menu/AlchemicalChestMenu.java index a464f3f..1dc3364 100644 --- a/src/main/java/lv/enes/mc/eris_alchemy/menu/AlchemicalChestMenu.java +++ b/src/main/java/lv/enes/mc/eris_alchemy/menu/AlchemicalChestMenu.java @@ -1,38 +1,31 @@ package lv.enes.mc.eris_alchemy.menu; -import jakarta.annotation.Nonnull; import lv.enes.mc.eris_alchemy.ErisAlchemyRegistry; import net.minecraft.world.Container; import net.minecraft.world.SimpleContainer; 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.Slot; -import net.minecraft.world.item.ItemStack; -public class AlchemicalChestMenu extends AbstractContainerMenu { +public class AlchemicalChestMenu extends ChestLikeBlockMenu { private static final int WIDTH = 13; private static final int HEIGHT = 8; - private final Container container; - public AlchemicalChestMenu(int syncId, Inventory playerInventory) { this(syncId, playerInventory, new SimpleContainer(WIDTH * HEIGHT)); } - public AlchemicalChestMenu(int syncId, Inventory playerInventory, Container inventory) { - super(ErisAlchemyRegistry.Menus.ALCHEMICAL_CHEST, syncId); - checkContainerSize(inventory, WIDTH * HEIGHT); - - this.container = inventory; - inventory.startOpen(playerInventory.player); + public AlchemicalChestMenu(int syncId, Inventory playerInventory, Container container) { + super(ErisAlchemyRegistry.Menus.ALCHEMICAL_CHEST, syncId, playerInventory, container); + } + @Override + protected void addSlots(Inventory playerInventory) { var x_off = 8; var y_off = 8; for (var y = 0; y < HEIGHT; y++) { for (var x = 0; x < WIDTH; x++ ) { - addSlot(new Slot(inventory, y * WIDTH + x, x_off + x * 18, y_off + y * 18)); + addSlot(new Slot(container, y * WIDTH + x, x_off + x * 18, y_off + y * 18)); } } @@ -52,41 +45,8 @@ public class AlchemicalChestMenu extends AbstractContainerMenu { } } - public Container getContainer() { - return container; - } - - @Nonnull - @Override - public ItemStack quickMoveStack(Player player, int fromIndex) { - var newStack = ItemStack.EMPTY; - var slot = slots.get(fromIndex); - if (!slot.hasItem()) { - return newStack; - } - - var originalStack = slot.getItem(); - newStack = originalStack.copy(); - - if (fromIndex < container.getContainerSize()) { - if (!moveItemStackTo(originalStack, container.getContainerSize(), slots.size(), true)) { - return ItemStack.EMPTY; - } - } else if (!moveItemStackTo(originalStack, 0, container.getContainerSize(), false)) { - return ItemStack.EMPTY; - } - - if (originalStack.isEmpty()) { - slot.setByPlayer(ItemStack.EMPTY); - } else { - slot.setChanged(); - } - - return newStack; - } - @Override - public boolean stillValid(Player player) { - return container.stillValid(player); + protected int getRequiredSize() { + return WIDTH * HEIGHT; } } diff --git a/src/main/java/lv/enes/mc/eris_alchemy/menu/ChestLikeBlockMenu.java b/src/main/java/lv/enes/mc/eris_alchemy/menu/ChestLikeBlockMenu.java new file mode 100644 index 0000000..897abe9 --- /dev/null +++ b/src/main/java/lv/enes/mc/eris_alchemy/menu/ChestLikeBlockMenu.java @@ -0,0 +1,67 @@ +package lv.enes.mc.eris_alchemy.menu; + +import jakarta.annotation.Nonnull; +import net.minecraft.world.Container; +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.MenuType; +import net.minecraft.world.item.ItemStack; + +public abstract class ChestLikeBlockMenu extends AbstractContainerMenu { + protected final Container container; + + public ChestLikeBlockMenu( + MenuType type, + int syncId, + Inventory playerInventory, + Container container + ) { + super(type, syncId); + checkContainerSize(container, getRequiredSize()); + this.container = container; + container.startOpen(playerInventory.player); + addSlots(playerInventory); + } + + protected abstract void addSlots(Inventory playerInventory); + protected abstract int getRequiredSize(); + + public Container getContainer() { + return container; + } + + @Nonnull + @Override + public ItemStack quickMoveStack(Player player, int fromIndex) { + var newStack = ItemStack.EMPTY; + var slot = slots.get(fromIndex); + if (!slot.hasItem()) { + return newStack; + } + + var originalStack = slot.getItem(); + newStack = originalStack.copy(); + + if (fromIndex < container.getContainerSize()) { + if (!moveItemStackTo(originalStack, container.getContainerSize(), slots.size(), true)) { + return ItemStack.EMPTY; + } + } else if (!moveItemStackTo(originalStack, 0, container.getContainerSize(), false)) { + return ItemStack.EMPTY; + } + + if (originalStack.isEmpty()) { + slot.setByPlayer(ItemStack.EMPTY); + } else { + slot.setChanged(); + } + + return newStack; + } + + @Override + public boolean stillValid(Player player) { + return container.stillValid(player); + } +} -- cgit v1.2.3