diff --git a/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 index 375d08e3b..30e20ec1a 100644 --- a/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 +++ b/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -1,2 +1,2 @@ // 26.1.2 -999999999-01-01T00:00:00 Language (en_us) -5589189dc52ef213076f236794a99c7c38f6fdd6 assets/xkdeco/lang/en_us.json +b56fa71f361d6b7935df5d77d39ef84227f9e38c assets/xkdeco/lang/en_us.json diff --git a/src/generated/resources/assets/xkdeco/lang/en_us.json b/src/generated/resources/assets/xkdeco/lang/en_us.json index a9ebc89b6..d823f34d7 100644 --- a/src/generated/resources/assets/xkdeco/lang/en_us.json +++ b/src/generated/resources/assets/xkdeco/lang/en_us.json @@ -4,6 +4,7 @@ "item.xkdeco.mimic_wall": "Mimic %s", "modmenu.descriptionTranslation.xkdeco": "Models and textures are created by XeKr: https://github.com/XeKr", "modmenu.nameTranslation.xkdeco": "XeKr's Decoration", + "tip.xkdeco.block_unlocked": "%s has been unlocked.", "xkdeco.config.mimicWalls": "Mimic Walls", "xkdeco.config.mimicWalls.desc": "", "xkdeco.mimic_walls": "Mimic Walls" diff --git a/src/main/java/org/teacon/xkdeco/block/AirDuctBlock.java b/src/main/java/org/teacon/xkdeco/block/AirDuctBlock.java index dca93692c..b434b1c50 100644 --- a/src/main/java/org/teacon/xkdeco/block/AirDuctBlock.java +++ b/src/main/java/org/teacon/xkdeco/block/AirDuctBlock.java @@ -30,8 +30,6 @@ public class AirDuctBlock extends BasicBlock { - private static final Direction[] DIRECTIONS = Direction.values(); - public AirDuctBlock(Properties pProperties) { super(pProperties); BlockState blockState = this.stateDefinition.any(); @@ -94,7 +92,7 @@ public BlockState getStateForPlacement(BlockPlaceContext pContext) { BlockPos pos = pContext.getClickedPos(); BlockPos.MutableBlockPos mutable = pos.mutable(); List neighbors = Lists.newArrayList(); - for (Direction direction : DIRECTIONS) { + for (Direction direction : Block.UPDATE_SHAPE_ORDER) { BlockState neighborState = level.getBlockState(mutable.setWithOffset(pos, direction)); if (isAirDuctSlot(neighborState, direction.getOpposite())) { neighbors.add(direction); @@ -128,7 +126,7 @@ protected BlockState updateShape( } BlockPos.MutableBlockPos mutable = pos.mutable(); List neighbors = Lists.newArrayListWithExpectedSize(2); - for (Direction direction : DIRECTIONS) { + for (Direction direction : Block.UPDATE_SHAPE_ORDER) { if (direction == pDirection) { continue; } @@ -141,7 +139,7 @@ protected BlockState updateShape( } } Direction theOtherDirection = neighbors.isEmpty() ? pDirection.getOpposite() : neighbors.getFirst(); - for (Direction direction : DIRECTIONS) { + for (Direction direction : Block.UPDATE_SHAPE_ORDER) { blockState = blockState.setValue( DIRECTION_PROPERTIES.get(direction.get3DDataValue()), direction == pDirection || direction == theOtherDirection); diff --git a/src/main/java/org/teacon/xkdeco/block/DisplayBlock.java b/src/main/java/org/teacon/xkdeco/block/DisplayBlock.java index 1e4c04efc..28466b16e 100644 --- a/src/main/java/org/teacon/xkdeco/block/DisplayBlock.java +++ b/src/main/java/org/teacon/xkdeco/block/DisplayBlock.java @@ -1,7 +1,11 @@ package org.teacon.xkdeco.block; +import org.teacon.xkdeco.blockentity.SingleSlotContainerBlockEntity; + import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Container; @@ -12,11 +16,17 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.ItemContainerContents; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.ticks.ContainerSingleItem; import snownee.kiwi.block.ModBlock; import snownee.kiwi.customization.block.CheckedWaterloggedBlock; @@ -34,6 +44,9 @@ protected InteractionResult useItemOn( Player player, InteractionHand hand, BlockHitResult hitResult) { + if (checkLock(player, level, pos)) { + return InteractionResult.SUCCESS; + } if (doesHitTop(hitResult)) { return useTop(stack, state, level, pos, player, hand, hitResult); } else { @@ -41,6 +54,20 @@ protected InteractionResult useItemOn( } } + private boolean checkLock(Player player, Level level, BlockPos pos) { + if (!level.isClientSide() && level.getBlockEntity(pos) instanceof SingleSlotContainerBlockEntity container && + container.isLocked()) { + if (container.canOpen(player)) { + container.unlock(); + player.sendOverlayMessage(Component.translatable("tip.xkdeco.block_unlocked", getName())); + } else { + BaseContainerBlockEntity.sendChestLockedNotifications(Vec3.atCenterOf(pos), player, getName()); + } + return true; + } + return false; + } + protected InteractionResult useSide( ItemStack held, BlockState pState, @@ -60,7 +87,7 @@ protected InteractionResult useTop( Player pPlayer, InteractionHand pHand, BlockHitResult pHit) { - if (!(pLevel.getBlockEntity(pPos) instanceof Container container)) { + if (!(pLevel.getBlockEntity(pPos) instanceof ContainerSingleItem container)) { return InteractionResult.FAIL; } if (pLevel.isClientSide()) { @@ -75,6 +102,9 @@ protected InteractionResult useTop( } public void click(BlockState blockState, Level level, BlockPos pos, ServerPlayer player, BlockHitResult hit) { + if (checkLock(player, level, pos)) { + return; + } if (doesHitTop(hit)) { clickTop(blockState, level, pos, player, hit); } else { @@ -88,18 +118,18 @@ protected void clickTop(BlockState blockState, Level level, BlockPos pos, Server grab(blockState, level, pos, player); } - public boolean insertItem(Container container, ItemStack itemStack) { + public boolean insertItem(ContainerSingleItem container, ItemStack itemStack) { if (!container.canPlaceItem(0, itemStack)) { return false; } - ItemStack displayed = container.getItem(0); + ItemStack displayed = container.getTheItem(); if (displayed.isEmpty() || ItemStack.isSameItemSameComponents(displayed, itemStack)) { int maxSize = Math.min(itemStack.getMaxStackSize(), container.getMaxStackSize()); int transferAmount = Math.min(itemStack.getCount(), maxSize - displayed.getCount()); if (transferAmount > 0) { ItemStack split = itemStack.split(transferAmount); split.grow(displayed.getCount()); - container.setItem(0, split); + container.setTheItem(split); return true; } } @@ -110,7 +140,7 @@ public boolean insertItem(Container container, ItemStack itemStack) { public void stepOn(Level pLevel, BlockPos pPos, BlockState pState, Entity pEntity) { super.stepOn(pLevel, pPos, pState, pEntity); if (!pLevel.isClientSide() && pEntity instanceof ItemEntity itemEntity && - pLevel.getBlockEntity(pPos) instanceof Container container) { + pLevel.getBlockEntity(pPos) instanceof ContainerSingleItem container) { if (insertItem(container, itemEntity.getItem())) { itemEntity.setItem(itemEntity.getItem()); // send update packet } @@ -118,14 +148,13 @@ public void stepOn(Level pLevel, BlockPos pPos, BlockState pState, Entity pEntit } public void grab(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer) { - if (pLevel.isClientSide() || !(pLevel.getBlockEntity(pPos) instanceof Container be)) { + if (pLevel.isClientSide() || !(pLevel.getBlockEntity(pPos) instanceof ContainerSingleItem be)) { return; } - ItemStack item = be.getItem(0); + ItemStack item = be.removeTheItem(); if (item.isEmpty()) { return; } - be.setItem(0, ItemStack.EMPTY); double d3 = pPos.getX() + 0.5; double d4 = pPos.getY() + 1; double d5 = pPos.getZ() + 0.5; @@ -161,4 +190,9 @@ public int getAnalogOutputSignal(BlockState pBlockState, Level pLevel, BlockPos public boolean canBeDestroyed(BlockState blockState, Level level, BlockPos pos, Player player, BlockHitResult hit) { return !(level.getBlockEntity(pos) instanceof Container container) || container.isEmpty(); } + + @Override + public BlockItem createItem(Item.Properties builder) { + return super.createItem(builder.component(DataComponents.CONTAINER, ItemContainerContents.EMPTY)); + } } diff --git a/src/main/java/org/teacon/xkdeco/block/ItemDisplayBlock.java b/src/main/java/org/teacon/xkdeco/block/ItemDisplayBlock.java index 65d452969..5b18c5f6c 100644 --- a/src/main/java/org/teacon/xkdeco/block/ItemDisplayBlock.java +++ b/src/main/java/org/teacon/xkdeco/block/ItemDisplayBlock.java @@ -60,7 +60,7 @@ protected void neighborChanged( @Nullable Orientation pOrientation, boolean pIsMoving) { if (!pLevel.isClientSide() && pState.getValue(POWERED) != pLevel.hasNeighborSignal(pPos)) { - pLevel.setBlock(pPos, pState.cycle(POWERED), 2); + pLevel.setBlock(pPos, pState.cycle(POWERED), Block.UPDATE_CLIENTS); } } diff --git a/src/main/java/org/teacon/xkdeco/blockentity/BlockDisplayBlockEntity.java b/src/main/java/org/teacon/xkdeco/blockentity/BlockDisplayBlockEntity.java index 34ef8a71b..ee81acd29 100644 --- a/src/main/java/org/teacon/xkdeco/blockentity/BlockDisplayBlockEntity.java +++ b/src/main/java/org/teacon/xkdeco/blockentity/BlockDisplayBlockEntity.java @@ -30,8 +30,6 @@ public BlockDisplayBlockEntity(BlockPos pWorldPosition, BlockState pBlockState) super(XKDecoEntityTypes.BLOCK_DISPLAY.get(), pWorldPosition, pBlockState); } - // getRenderBoundingBox moved to BlockDisplayRenderer. See there for more info. - @Override public int getMaxStackSize() { return 1; @@ -43,13 +41,13 @@ public boolean canPlaceItem(int pIndex, ItemStack pStack) { } @Override - public void setItem(int pSlot, ItemStack pStack) { - if (pStack.getItem() instanceof BlockItem blockItem) { + public void setTheItem(ItemStack itemStack) { + super.setTheItem(itemStack); + if (itemStack.getItem() instanceof BlockItem blockItem) { setStoredBlockState(blockItem.getBlock().defaultBlockState()); } else { setStoredBlockState(EMPTY); } - super.setItem(pSlot, pStack); } public BlockState getStoredBlockState() { diff --git a/src/main/java/org/teacon/xkdeco/blockentity/ItemDisplayBlockEntity.java b/src/main/java/org/teacon/xkdeco/blockentity/ItemDisplayBlockEntity.java index f8a3fa811..6b4ff68bb 100644 --- a/src/main/java/org/teacon/xkdeco/blockentity/ItemDisplayBlockEntity.java +++ b/src/main/java/org/teacon/xkdeco/blockentity/ItemDisplayBlockEntity.java @@ -23,17 +23,12 @@ public ItemDisplayBlockEntity(BlockPos blockPos, BlockState blockState, boolean blockState); } - // getRenderBoundingBox moved to ItemDisplayRenderer. See there for more info. - public boolean isProjector() { - return XKDecoEntityTypes.ITEM_PROJECTOR.get() == this.getType(); + return is(XKDecoEntityTypes.ITEM_PROJECTOR.get()); } public float getSpin() { - if (hasFixedSpin()) { - return fixedSpin; - } - return level == null ? 0 : level.getGameTime(); + return fixedSpin; } public boolean hasFixedSpin() { diff --git a/src/main/java/org/teacon/xkdeco/blockentity/SingleSlotContainerBlockEntity.java b/src/main/java/org/teacon/xkdeco/blockentity/SingleSlotContainerBlockEntity.java index cabe22c28..ac2fed50b 100644 --- a/src/main/java/org/teacon/xkdeco/blockentity/SingleSlotContainerBlockEntity.java +++ b/src/main/java/org/teacon/xkdeco/blockentity/SingleSlotContainerBlockEntity.java @@ -1,38 +1,29 @@ package org.teacon.xkdeco.blockentity; -import org.jspecify.annotations.Nullable; -import org.slf4j.Logger; - -import com.mojang.logging.LogUtils; +import java.util.List; import net.minecraft.core.BlockPos; -import net.minecraft.core.HolderLookup; -import net.minecraft.core.NonNullList; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.Connection; -import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; -import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.core.component.DataComponentGetter; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponents; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; -import net.minecraft.util.ProblemReporter; -import net.minecraft.util.Util; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.LockCode; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; +import net.minecraft.world.item.component.ItemContainerContents; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.storage.TagValueOutput; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.ticks.ContainerSingleItem; +import snownee.kiwi.block.entity.ModBlockEntity; -public class SingleSlotContainerBlockEntity extends BaseContainerBlockEntity { - private static final Logger LOGGER = LogUtils.getLogger(); +public class SingleSlotContainerBlockEntity extends ModBlockEntity implements ContainerSingleItem.BlockContainerSingleItem { public static final String ITEM_STACK_KEY = "Display"; protected ItemStack item = ItemStack.EMPTY; + private LockCode lockKey = LockCode.NO_LOCK; protected SingleSlotContainerBlockEntity( BlockEntityType pType, @@ -42,69 +33,14 @@ protected SingleSlotContainerBlockEntity( } @Override - protected Component getDefaultName() { - return Component.translatable(Util.makeDescriptionId("container", BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(getType()))); - } - - @SuppressWarnings("NullableProblems") - @Override - protected @Nullable AbstractContainerMenu createMenu(int i, Inventory inventory) { - return null; - } - - @Override - public int getContainerSize() { - return 1; - } - - @Override - protected NonNullList getItems() { - return NonNullList.of(this.item); - } - - @Override - protected void setItems(NonNullList items) { - this.item = items.getFirst(); - } - - @Override - public boolean isEmpty() { - return getFirstItem().isEmpty(); - } - - public ItemStack getFirstItem() { - return getItem(0); - } - - @Override - public ItemStack getItem(int pSlot) { + public ItemStack getTheItem() { return item; } @Override - public ItemStack removeItem(int pSlot, int pAmount) { - if (item.isEmpty() || pAmount <= 0) { - return ItemStack.EMPTY; - } - ItemStack itemstack = item.copyWithCount(pAmount); - setItem(0, item.copyWithCount(item.getCount() - pAmount)); // play the removing sound if possible - return itemstack; - } - - @Override - public ItemStack removeItemNoUpdate(int pSlot) { - ItemStack itemstack = item; - item = ItemStack.EMPTY; - return itemstack; - } - - @Override - public void setItem(int pSlot, ItemStack pStack) { + public void setTheItem(ItemStack itemStack) { boolean empty = isEmpty(); - item = pStack; - if (pStack.getCount() > getMaxStackSize()) { - pStack.setCount(getMaxStackSize()); - } + item = itemStack; refresh(); if (level != null && !level.isClientSide()) { if (empty && !isEmpty()) { @@ -116,56 +52,76 @@ public void setItem(int pSlot, ItemStack pStack) { } @Override - public void clearContent() { - setItem(0, ItemStack.EMPTY); + public ItemStack splitTheItem(int count) { + ItemStack itemStack = BlockContainerSingleItem.super.splitTheItem(count); + refresh(); + return itemStack; } @Override public void loadAdditional(ValueInput input) { super.loadAdditional(input); + lockKey = LockCode.fromTag(input); readPacketData(input); } @Override protected void saveAdditional(ValueOutput output) { super.saveAdditional(output); + lockKey.addToTag(output); writePacketData(output); } @Override - public Packet getUpdatePacket() { - return ClientboundBlockEntityDataPacket.create(this); + protected void readPacketData(ValueInput input) { + item = input.read(ITEM_STACK_KEY, ItemStack.CODEC).orElse(ItemStack.EMPTY); } @Override - public void onDataPacket(Connection net, ValueInput valueInput) { - this.readPacketData(valueInput); + protected void writePacketData(ValueOutput output) { + if (!item.isEmpty()) { + output.store(ITEM_STACK_KEY, ItemStack.CODEC, item); + } + } + + public boolean canOpen(Player player) { + return lockKey.canUnlock(player); + } + + public boolean isLocked() { + return !lockKey.equals(LockCode.NO_LOCK); + } + + public void unlock() { + lockKey = LockCode.NO_LOCK; + setChanged(); } @Override - public CompoundTag getUpdateTag(HolderLookup.Provider registries) { - try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(this.problemPath(), LOGGER)) { - TagValueOutput output = TagValueOutput.createWithContext(reporter, registries); - writePacketData(output); - return output.buildResult(); - } + public BlockEntity getContainerBlockEntity() { + return this; } - protected void readPacketData(ValueInput input) { - item = input.read(ITEM_STACK_KEY, ItemStack.CODEC).orElse(ItemStack.EMPTY); + @Override + protected void applyImplicitComponents(DataComponentGetter components) { + super.applyImplicitComponents(components); + lockKey = components.getOrDefault(DataComponents.LOCK, LockCode.NO_LOCK); + item = components.getOrDefault(DataComponents.CONTAINER, ItemContainerContents.EMPTY).copyOne(); } - protected void writePacketData(ValueOutput output) { - if (!item.isEmpty()) { - output.store(ITEM_STACK_KEY, ItemStack.CODEC, item); + @Override + protected void collectImplicitComponents(DataComponentMap.Builder components) { + super.collectImplicitComponents(components); + if (isLocked()) { + components.set(DataComponents.LOCK, lockKey); } + components.set(DataComponents.CONTAINER, ItemContainerContents.fromItems(List.of(item))); } - public void refresh() { - if (this.hasLevel() && !this.level.isClientSide()) { - BlockState state = this.getBlockState(); - this.level.sendBlockUpdated(this.worldPosition, state, state, 11); - this.setChanged(); - } + @SuppressWarnings("deprecation") + @Override + public void removeComponentsFromTag(ValueOutput output) { + output.discard("lock"); + output.discard(ITEM_STACK_KEY); } } diff --git a/src/main/java/org/teacon/xkdeco/client/renderer/ItemDisplayRenderer.java b/src/main/java/org/teacon/xkdeco/client/renderer/ItemDisplayRenderer.java index 0ab5f1b5c..8b72fb73e 100644 --- a/src/main/java/org/teacon/xkdeco/client/renderer/ItemDisplayRenderer.java +++ b/src/main/java/org/teacon/xkdeco/client/renderer/ItemDisplayRenderer.java @@ -7,6 +7,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; @@ -48,7 +49,7 @@ public void extractRenderState( BlockEntityRenderer.super.extractRenderState(blockEntity, state, partialTicks, cameraPosition, breakProgress); // borrowed from ItemEntityRenderer - ItemStack itemstack = blockEntity.getFirstItem(); + ItemStack itemstack = blockEntity.getTheItem(); state.projector = blockEntity.isProjector(); if (itemstack.isEmpty()) { @@ -57,9 +58,11 @@ public void extractRenderState( return; } - float spin = blockEntity.getSpin(); - if (!blockEntity.hasFixedSpin()) { - spin += partialTicks; + float spin; + if (blockEntity.hasFixedSpin()) { + spin = blockEntity.getSpin(); + } else { + spin = Minecraft.getInstance().clientTickCount + partialTicks; } state.spin = spin * 0.05F; state.amount = getRenderAmount(itemstack); diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index e018ee974..c95c49632 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -23,3 +23,5 @@ public net.minecraft.world.level.block.SnowyBlock isSnowySetting(Lnet/minecraft/ public net.minecraft.world.level.block.state.properties.IntegerProperty min public net.minecraft.world.level.block.state.properties.IntegerProperty max + +public net.minecraft.client.Minecraft clientTickCount \ No newline at end of file diff --git a/src/main/resources/assets/xkdeco/lang/en_us.existing.json b/src/main/resources/assets/xkdeco/lang/en_us.existing.json index 0cf9d6a75..90059af25 100644 --- a/src/main/resources/assets/xkdeco/lang/en_us.existing.json +++ b/src/main/resources/assets/xkdeco/lang/en_us.existing.json @@ -1,4 +1,5 @@ { "block.xkdeco.mimic_wall": "Mimic %s", - "xkdeco.mimic_walls": "Mimic Walls" + "xkdeco.mimic_walls": "Mimic Walls", + "tip.xkdeco.block_unlocked": "%s has been unlocked." } \ No newline at end of file diff --git a/src/main/resources/assets/xkdeco/lang/zh_cn.json b/src/main/resources/assets/xkdeco/lang/zh_cn.json index 0350dc066..94c612198 100644 --- a/src/main/resources/assets/xkdeco/lang/zh_cn.json +++ b/src/main/resources/assets/xkdeco/lang/zh_cn.json @@ -1,4 +1,5 @@ { "block.xkdeco.mimic_wall": "%s(墙柱)", - "xkdeco.mimic_walls": "Mimic Walls" + "xkdeco.mimic_walls": "Mimic Walls", + "tip.xkdeco.block_unlocked": "%s已解锁。" } \ No newline at end of file