From dfcf3b41463f4c9aaac3c874b8a82cb4efb4e48c Mon Sep 17 00:00:00 2001 From: KnightMiner Date: Sat, 16 Jan 2021 12:59:20 -0500 Subject: [PATCH] Make InventoryBlock more general Uses item capabilities for item dropping and a new interface for renaming --- .../mantle/block/InventoryBlock.java | 56 +++++++++++++++++-- .../mantle/inventory/EmptyItemHandler.java | 44 +++++++++++++++ .../IRenamableContainerProvider.java | 44 +++++++++++++++ .../mantle/tileentity/NamableTileEntity.java | 46 ++++----------- 4 files changed, 148 insertions(+), 42 deletions(-) create mode 100644 src/main/java/slimeknights/mantle/inventory/EmptyItemHandler.java create mode 100644 src/main/java/slimeknights/mantle/tileentity/IRenamableContainerProvider.java diff --git a/src/main/java/slimeknights/mantle/block/InventoryBlock.java b/src/main/java/slimeknights/mantle/block/InventoryBlock.java index 4409d6c..5bec25a 100644 --- a/src/main/java/slimeknights/mantle/block/InventoryBlock.java +++ b/src/main/java/slimeknights/mantle/block/InventoryBlock.java @@ -15,8 +15,13 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.fml.network.NetworkHooks; +import net.minecraftforge.items.CapabilityItemHandler; +import net.minecraftforge.items.IItemHandler; import slimeknights.mantle.inventory.BaseContainer; +import slimeknights.mantle.inventory.EmptyItemHandler; +import slimeknights.mantle.tileentity.IRenamableContainerProvider; import slimeknights.mantle.tileentity.InventoryTileEntity; import javax.annotation.Nullable; @@ -87,8 +92,8 @@ public abstract class InventoryBlock extends Block { // set custom name from named stack if (stack.hasDisplayName()) { TileEntity tileentity = worldIn.getTileEntity(pos); - if (tileentity instanceof InventoryTileEntity) { - ((InventoryTileEntity) tileentity).setCustomName(stack.getDisplayName()); + if (tileentity instanceof IRenamableContainerProvider) { + ((IRenamableContainerProvider) tileentity).setCustomName(stack.getDisplayName()); } } } @@ -110,9 +115,15 @@ public abstract class InventoryBlock extends Block { @Override public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { if (state.getBlock() != newState.getBlock()) { - TileEntity tileentity = worldIn.getTileEntity(pos); - if (tileentity instanceof InventoryTileEntity) { - dropInventoryItems(state, worldIn, pos, (InventoryTileEntity) tileentity); + TileEntity te = worldIn.getTileEntity(pos); + if (te != null) { + // FIXME legacy support, switch to non-deprecated method in 1.17 + if (te instanceof InventoryTileEntity) { + dropInventoryItems(state, worldIn, pos, (InventoryTileEntity) te); + } else { + te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) + .ifPresent(inventory -> dropInventoryItems(state, worldIn, pos, inventory)); + } worldIn.updateComparatorOutputLevel(pos, this); } } @@ -126,9 +137,42 @@ public abstract class InventoryBlock extends Block { * @param worldIn Tile world * @param pos Tile position * @param inventory Tile entity instance + * @deprecated Will remove in 1.17, use {@link #dropInventoryItems(BlockState, World, BlockPos, IItemHandler)} */ + @Deprecated protected void dropInventoryItems(BlockState state, World worldIn, BlockPos pos, InventoryTileEntity inventory) { - InventoryHelper.dropInventoryItems(worldIn, pos, inventory); + LazyOptional itemCapability = inventory.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); + if (itemCapability.isPresent()) { + dropInventoryItems(state, worldIn, pos, itemCapability.orElse(EmptyItemHandler.INSTANCE)); + } else { + InventoryHelper.dropInventoryItems(worldIn, pos, inventory); + } + } + + /** + * Called when the block is replaced to drop contained items. + * @param state Block state + * @param worldIn Tile world + * @param pos Tile position + * @param inventory Item handler + */ + protected void dropInventoryItems(BlockState state, World worldIn, BlockPos pos, IItemHandler inventory) { + dropInventoryItems(worldIn, pos, inventory); + } + + /** + * Drops all items from the given inventory in world + * @param world World instance + * @param pos Position to drop + * @param inventory Inventory instance + */ + public static void dropInventoryItems(World world, BlockPos pos, IItemHandler inventory) { + double x = pos.getX(); + double y = pos.getY(); + double z = pos.getZ(); + for(int i = 0; i < inventory.getSlots(); ++i) { + InventoryHelper.spawnItemStack(world, x, y, z, inventory.getStackInSlot(i)); + } } @SuppressWarnings("deprecation") diff --git a/src/main/java/slimeknights/mantle/inventory/EmptyItemHandler.java b/src/main/java/slimeknights/mantle/inventory/EmptyItemHandler.java new file mode 100644 index 0000000..8984f02 --- /dev/null +++ b/src/main/java/slimeknights/mantle/inventory/EmptyItemHandler.java @@ -0,0 +1,44 @@ +package slimeknights.mantle.inventory; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import net.minecraft.item.ItemStack; +import net.minecraftforge.items.IItemHandler; + +/** + * Item handler that contains no items. Use similarly to {@link net.minecraftforge.fluids.capability.templates.EmptyFluidHandler} + */ +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class EmptyItemHandler implements IItemHandler { + public static final EmptyItemHandler INSTANCE = new EmptyItemHandler(); + + @Override + public int getSlots() { + return 0; + } + + @Override + public int getSlotLimit(int slot) { + return 0; + } + + @Override + public ItemStack getStackInSlot(int slot) { + return ItemStack.EMPTY; + } + + @Override + public boolean isItemValid(int slot, ItemStack stack) { + return false; + } + + @Override + public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + return stack; + } + + @Override + public ItemStack extractItem(int slot, int amount, boolean simulate) { + return ItemStack.EMPTY; + } +} diff --git a/src/main/java/slimeknights/mantle/tileentity/IRenamableContainerProvider.java b/src/main/java/slimeknights/mantle/tileentity/IRenamableContainerProvider.java new file mode 100644 index 0000000..615f872 --- /dev/null +++ b/src/main/java/slimeknights/mantle/tileentity/IRenamableContainerProvider.java @@ -0,0 +1,44 @@ +package slimeknights.mantle.tileentity; + +import net.minecraft.inventory.container.INamedContainerProvider; +import net.minecraft.util.INameable; +import net.minecraft.util.text.ITextComponent; + +import javax.annotation.Nullable; + +/** + * Interface for containers that can be renamed. Used in {@link slimeknights.mantle.block.InventoryBlock} to set the name on placement + */ +public interface IRenamableContainerProvider extends INamedContainerProvider, INameable { + + /** + * Gets the default name of this tile entity + * @return Default name + */ + ITextComponent getDefaultName(); + + /** + * Gets the custom name for this tile entity + * @return Custom name + */ + @Override + @Nullable + ITextComponent getCustomName(); + + /** + * Sets the name for this tile entity + * @param name New custom name + */ + void setCustomName(ITextComponent name); + + @Override + default ITextComponent getName() { + ITextComponent customTitle = getCustomName(); + return customTitle != null ? customTitle : getDefaultName(); + } + + @Override + default ITextComponent getDisplayName() { + return getName(); + } +} diff --git a/src/main/java/slimeknights/mantle/tileentity/NamableTileEntity.java b/src/main/java/slimeknights/mantle/tileentity/NamableTileEntity.java index 9cbe763..938a8f0 100644 --- a/src/main/java/slimeknights/mantle/tileentity/NamableTileEntity.java +++ b/src/main/java/slimeknights/mantle/tileentity/NamableTileEntity.java @@ -1,62 +1,36 @@ package slimeknights.mantle.tileentity; +import lombok.Getter; +import lombok.Setter; import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.container.Container; -import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; -import net.minecraft.util.INameable; import net.minecraft.util.text.ITextComponent; import net.minecraftforge.common.util.Constants.NBT; -import javax.annotation.Nullable; - /** * Extension of tile entity to make it namable */ -public abstract class NamableTileEntity extends MantleTileEntity implements INamedContainerProvider, INameable { +public abstract class NamableTileEntity extends MantleTileEntity implements IRenamableContainerProvider { private static final String TAG_CUSTOM_NAME = "CustomName"; /** Default title for this tile entity */ - private final ITextComponent defaultTitle; + @Getter + private final ITextComponent defaultName; /** Title set to this tile entity */ - private ITextComponent customTitle; + @Getter @Setter + private ITextComponent customName; public NamableTileEntity(TileEntityType tileEntityTypeIn, ITextComponent defaultTitle) { super(tileEntityTypeIn); - this.defaultTitle = defaultTitle; - } - - @Override - public ITextComponent getName() { - return customTitle != null ? customTitle : defaultTitle; - } - - @Nullable - public ITextComponent getCustomName() { - return customTitle; - } - - /** - * Sets the name for this tile entity - * @param customName New custom name - */ - public void setCustomName(ITextComponent customName) { - this.customTitle = customName; - } - - @Override - public ITextComponent getDisplayName() { - return getName(); + this.defaultName = defaultTitle; } @Override public void read(BlockState blockState, CompoundNBT tags) { super.read(blockState, tags); if (tags.contains(TAG_CUSTOM_NAME, NBT.TAG_STRING)) { - this.customTitle = ITextComponent.Serializer.getComponentFromJson(tags.getString(TAG_CUSTOM_NAME)); + this.customName = ITextComponent.Serializer.getComponentFromJson(tags.getString(TAG_CUSTOM_NAME)); } } @@ -64,7 +38,7 @@ public abstract class NamableTileEntity extends MantleTileEntity implements INam public void writeSynced(CompoundNBT tags) { super.writeSynced(tags); if (this.hasCustomName()) { - tags.putString(TAG_CUSTOM_NAME, ITextComponent.Serializer.toJson(this.customTitle)); + tags.putString(TAG_CUSTOM_NAME, ITextComponent.Serializer.toJson(this.customName)); } } }