hello. I try to create my custom chest BUT that's make me crazy.
1.if I put an item in my custom chest it become doubled, and if I click it ,it will be dispeared.:(
2.the custom chest what i made use the same container in different blocks.
TileEntity:
public class SFCTileEntity extends TileEntity implements INamedContainerProvider {
public static final int NUMBER_OF_SLOTS = 27;
public SFCTileEntity()
{
super(TileEntityTypeRegistry.TileEntity.get());
chestContents = ChestContents.createForTileEntity(NUMBER_OF_SLOTS,
this::canPlayerAccessInventory, this::setChanged);
}
public boolean canPlayerAccessInventory(PlayerEntity player) {
if (this.level.getBlockEntity(this.worldPosition) != this) return false;
final double X_CENTRE_OFFSET = 0.5;
final double Y_CENTRE_OFFSET = 0.5;
final double Z_CENTRE_OFFSET = 0.5;
final double MAXIMUM_DISTANCE_SQ = 8.0 * 8.0;
return player.distanceToSqr(worldPosition.getX() + X_CENTRE_OFFSET, worldPosition.getY() + Y_CENTRE_OFFSET, worldPosition.getZ() + Z_CENTRE_OFFSET) < MAXIMUM_DISTANCE_SQ;
}
private static final String CHESTCONTENTS_INVENTORY_TAG = "contents";
@Override
public CompoundNBT save(CompoundNBT parentNBTTagCompound)
{
super.save(parentNBTTagCompound);
CompoundNBT inventoryNBT = chestContents.serializeNBT();
parentNBTTagCompound.put(CHESTCONTENTS_INVENTORY_TAG, inventoryNBT);
return parentNBTTagCompound;
}
@Override
public void load(BlockState blockState, CompoundNBT parentNBTTagCompound)
{
super.load(blockState, parentNBTTagCompound);
CompoundNBT inventoryNBT = parentNBTTagCompound.getCompound(CHESTCONTENTS_INVENTORY_TAG);
chestContents.deserializeNBT(inventoryNBT);
}
@Override
@Nullable
public SUpdateTileEntityPacket getUpdatePacket()
{
CompoundNBT nbtTagCompound = new CompoundNBT();
save(nbtTagCompound);
int tileEntityType = 42;
return new SUpdateTileEntityPacket(this.worldPosition, tileEntityType, nbtTagCompound);
}
@Override
public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) {
BlockState blockState = level.getBlockState(worldPosition);
load(blockState, pkt.getTag());
}
@Override
public CompoundNBT getUpdateTag()
{
CompoundNBT nbtTagCompound = new CompoundNBT();
save(nbtTagCompound);
return nbtTagCompound;
}
/* Populates this TileEntity with information from the tag, used by vanilla to transmit from server to client
* The vanilla default is suitable for this example but I've included an explicit definition anyway.
*/
@Override
public void handleUpdateTag(BlockState blockState, CompoundNBT tag)
{
this.load(blockState, tag);
}
@Override
public ITextComponent getDisplayName() {
return null;
}
@Nullable
@Override
public Container createMenu(int windowID, PlayerInventory playerInventory, PlayerEntity playerEntity) {
return SFContainer.createContainerServerSide(windowID, playerInventory, chestContents);
}
public static ChestContents getChestContents() {
return chestContents;
}
private static ChestContents chestContents;
}
Container:
public class SFContainer extends Container {
private static final int HOTBAR_SLOT_COUNT = 9;
private static final int PLAYER_INVENTORY_ROW_COUNT = 3;
private static final int PLAYER_INVENTORY_COLUMN_COUNT = 9;
private static final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_COLUMN_COUNT * PLAYER_INVENTORY_ROW_COUNT;
private static final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT;
private static final int VANILLA_FIRST_SLOT_INDEX = 0;
private static final int TE_INVENTORY_FIRST_SLOT_INDEX = VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT;
private static final int TE_INVENTORY_SLOT_COUNT = SFCTileEntity.NUMBER_OF_SLOTS;
public static final int TILE_INVENTORY_YPOS = 18;
public static final int PLAYER_INVENTORY_YPOS = 86;
public SFContainer(int windowID, PlayerInventory playerInventory, ChestContents chestContents) {
super(ContainerTypeRegistry.Container.get(), windowID);
PlayerInvWrapper playerInventoryForge = new PlayerInvWrapper(playerInventory);
this.chestContents = chestContents;
final int SLOT_X_SPACING = 18;
final int SLOT_Y_SPACING = 18;
final int HOTBAR_XPOS = 8;
final int HOTBAR_YPOS = 144;
for (int x = 0; x < HOTBAR_SLOT_COUNT; x++) {
int slotNumber = x;
addSlot(new SlotItemHandler(playerInventoryForge, slotNumber, HOTBAR_XPOS + SLOT_X_SPACING * x, HOTBAR_YPOS));
}
final int PLAYER_INVENTORY_XPOS = 8;
// Add the rest of the player's inventory to the gui
for (int y = 0; y < PLAYER_INVENTORY_ROW_COUNT; y++) {
for (int x = 0; x < PLAYER_INVENTORY_COLUMN_COUNT; x++) {
int slotNumber = HOTBAR_SLOT_COUNT + y * PLAYER_INVENTORY_COLUMN_COUNT + x;
int xpos = PLAYER_INVENTORY_XPOS + x * SLOT_X_SPACING;
int ypos = PLAYER_INVENTORY_YPOS + y * SLOT_Y_SPACING;
addSlot(new SlotItemHandler(playerInventoryForge, slotNumber, xpos, ypos));
}
}
// Add the tile inventory container to the gui
for(int i = 0;i<9;i++){
addSlot(new Slot(chestContents, i, 8+18*i, 18));
addSlot(new Slot(chestContents, i+9, 8+18*i, 36));
addSlot(new Slot(chestContents, i+18, 8+18*i, 54));
}
}
public static SFContainer createContainerServerSide(int windowID, PlayerInventory playerInventory, ChestContents chestContents) {
return new SFContainer(windowID, playerInventory, chestContents);
}
public static SFContainer createContainerClientSide(int windowID, PlayerInventory playerInventory, net.minecraft.network.PacketBuffer extraData) {
ChestContents chestContents = ChestContents.createForClientSideContainer(SFCTileEntity.NUMBER_OF_SLOTS);
return new SFContainer(windowID, playerInventory, chestContents);
}
@Override
public boolean stillValid(PlayerEntity playerEntity)
{
return chestContents.stillValid(playerEntity);
}
@Override
public ItemStack quickMoveStack(PlayerEntity playerEntity, int sourceSlotIndex)
{
Slot sourceSlot = getSlot(sourceSlotIndex);
if (sourceSlot == null || !sourceSlot.hasItem()) return ItemStack.EMPTY; //EMPTY_ITEM
ItemStack sourceStack = sourceSlot.getItem();
ItemStack copyOfSourceStack = sourceStack.copy();
// Check if the slot clicked is one of the vanilla container slots
if (sourceSlotIndex >= VANILLA_FIRST_SLOT_INDEX && sourceSlotIndex < VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT) {
// This is a vanilla container slot so merge the stack into the tile inventory
if (!moveItemStackTo(sourceStack, TE_INVENTORY_FIRST_SLOT_INDEX, TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT, false)){
return ItemStack.EMPTY; // EMPTY_ITEM
}
} else if (sourceSlotIndex >= TE_INVENTORY_FIRST_SLOT_INDEX && sourceSlotIndex < TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT) {
// This is a TE slot so merge the stack into the players inventory
if (!moveItemStackTo(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) {
return ItemStack.EMPTY;
}
} else {
LOGGER.warn("Invalid slotIndex:" + sourceSlotIndex);
return ItemStack.EMPTY;
}
// If stack size == 0 (the entire stack was moved) set slot contents to null
if (sourceStack.getCount() == 0) {
sourceSlot.mayPlace(ItemStack.EMPTY);
} else {
sourceSlot.setChanged();
}
sourceSlot.onTake(playerEntity, sourceStack);
return copyOfSourceStack;
}
// pass the close container message to the parent inventory (not strictly needed for this example)
// see ContainerChest and TileEntityChest - used to animate the lid when no players are accessing the chest any more
@Override
public void removed(PlayerEntity playerIn)
{
super.removed(playerIn);
}
private ChestContents chestContents;
private static final Logger LOGGER = LogManager.getLogger();
}