Jump to content

[1.18.2] Hopper and Custom Containers(how to prevent items from the output slot from moving into the hopper)


vntlyy007

Recommended Posts

Hi guys) I have a custom furnace, and an idea that is impossible to implement if it is possible to move items from there to somewhere using a hopper (automatic farm or something), so I need to prevent the item from exiting to third-party objects (ie, not the player)

Link to comment
Share on other sites

2 minutes ago, diesieben07 said:

Hoppers will use getCapability with ITEM_HANDLER_CAPABILITY to interact with your BlockEntity. Make sure you return an IItemHandler that represents your intended interactino with hoppers (or do not expose the capability at all if you do not want them to interact).

Make sure your BE does not inherit from Container (legacy vanilla code).

very fast answer dude, thank you, i will try it

Edited by vntlyy007
Link to comment
Share on other sites

3 hours ago, diesieben07 said:

Hoppers will use getCapability with ITEM_HANDLER_CAPABILITY to interact with your BlockEntity. Make sure you return an IItemHandler that represents your intended interactino with hoppers (or do not expose the capability at all if you do not want them to interact).

Make sure your BE does not inherit from Container (legacy vanilla code).

I found this code in my custom block entity:

 

public class CleaningTableBlockEntity extends BlockEntity implements MenuProvider {
    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @javax.annotation.Nullable Direction side) {
        if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
            return lazyItemHandler.cast();
        }

        return super.getCapability(cap, side);
    }
}

but actually idk what should i do about this?) i tried deleted it(but slots dont load) Or what do you mean by "do not expose the capability at all"?

 

Also, I have another thing I'm trying to do is be able to put in the slot only items with a special tag (like furnace fuel)

Edited by vntlyy007
Link to comment
Share on other sites

HOWEVER, actualy there are more things

 

My furnace more like crafting table, but with time - cleaning of fossil ores with special item with durability

 

everything is in order:

1)to prevent items from the output slot from moving into the hopper

2)to be able to put in the slot only items with a special tag (like furnace fuel)

3)remove the ability to discard a finished smelting item back to output slot through use quick move

4) add the ability to add smelting time in json recipe(it's the easier)

 

GITHub There is my project, if somebody want/can, I will be grateful for your help  < 3

 

Edited by vntlyy007
Link to comment
Share on other sites

11 hours ago, vntlyy007 said:

to be able to put in the slot only items with a special tag (like furnace fuel)

Override #mayPlace in your Slot class you can take a look at how vanilla done this (e.g. AbstractFurnaceMenu).

11 hours ago, vntlyy007 said:

remove the ability to discard a finished smelting item back to output slot through use quick move

Should you be able to place Items in the result slot?
Yes -> You need to handle this is #quickMoveStack of your Menu
No -> Override #mayPlace in your result Slot class and return false

11 hours ago, vntlyy007 said:

add the ability to add smelting time in json recipe(it's the easier)

Take a look how vanilla done this, basically you need to add a property for the cooking time to the recipe, when you get the recipe for the current item in the input slot(s) you need to set the cooking time.

Btw you need to register your Recipe Serializer you can not create it in a static initializer, the highly recommended way is to use DeferredRegister.

Link to comment
Share on other sites

6 hours ago, Luis_ST said:

Перевизначте #mayPlace у вашому класі Slot, ви можете подивитися, як vanilla це зробила (наприклад, AbstractFurnaceMenu).

Чи можна розміщувати предмети в слоті результатів?
Так -> Вам потрібно обробити це #quickMoveStack вашого меню
Ні -> Замінити #mayPlace у вашому класі результатів Slot і повернути false

Подивіться, як Vanilla це зробила, загалом, вам потрібно додати властивість для часу приготування до рецепту, коли ви отримаєте рецепт для поточного елемента у вхідних слотах, вам потрібно встановити час приготування.

До речі, вам потрібно зареєструвати свій серіалізатор рецептів, ви не можете створити його в статичному ініціалізаторі, настійно рекомендованим способом є використання DeferredRegister.

I have completed two tasks, it remains to add the time in json. But I still have a problem with Hopper. It takes items from input slots (I still haven't figured out what I was advised to do with getCapabilities)

 

I tried all my ideas to reproduce it, so I still will be grateful for help

BlockEntity:

Spoiler
public class CleaningTableBlockEntity extends BlockEntity implements MenuProvider {
    private final ItemStackHandler itemHandler = new ItemStackHandler(3){
        @Override
        protected void onContentsChanged(int Slot){
            setChanged();
        }
    };

    private LazyOptional<IItemHandler> lazyItemHandler = LazyOptional.empty();



    protected final ContainerData data;
    private int progress = 0;
    private int maxProgress = 26;

    public CleaningTableBlockEntity(BlockPos p_155229_, BlockState p_155230_) {
        super(ModBlockEntities.CLEANING_TABLE_BLOCK_ENTITY.get(), p_155229_, p_155230_);

        this.data = new ContainerData() {
            public int get(int index) {
                switch (index) {
                    case 0: return CleaningTableBlockEntity.this.progress;
                    case 1: return CleaningTableBlockEntity.this.maxProgress;
                    default: return 0;
                }
            }

            public void set(int index, int value) {
                switch(index) {
                    case 0: CleaningTableBlockEntity.this.progress = value; break;
                    case 1: CleaningTableBlockEntity.this.maxProgress = value; break;
                }
            }

            public int getCount() {
                return 2;
            }
        };
    }

    @Override
    public Component getDisplayName() {
        return new TextComponent("Cleaning Table");
    }

    @Nullable
    @Override
    public AbstractContainerMenu createMenu(int pContainerId, Inventory pInventory, Player pPlayer) {
        return new CleaningTableMenu(pContainerId, pInventory, this, this.data);
    }
    @Nonnull

    @Override
    public void onLoad() {
        super.onLoad();
        lazyItemHandler = LazyOptional.of(() -> itemHandler);
    }

    @Override
    public void invalidateCaps()  {
        super.invalidateCaps();
        lazyItemHandler.invalidate();
    }

    @Override
    protected void saveAdditional(@NotNull CompoundTag tag) {
        tag.put("inventory", itemHandler.serializeNBT());
        tag.putInt("cleaning.progress", progress);
        super.saveAdditional(tag);
    }

    @Override
    public void load(CompoundTag nbt) {
        super.load(nbt);
        itemHandler.deserializeNBT(nbt.getCompound("inventory"));
        progress = nbt.getInt("cleaning.progress");
    }

    public void drops() {
        SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots());
        for (int i = 0; i < itemHandler.getSlots(); i++) {
            inventory.setItem(i, itemHandler.getStackInSlot(i));
        }

        Containers.dropContents(this.level, this.worldPosition, inventory);
    }


    public static void serverTick(Level pLevel, BlockPos pPos, BlockState pState, CleaningTableBlockEntity pBlockEntity) {
        if(hasRecipe(pBlockEntity)) {
            pBlockEntity.progress++;
            setChanged(pLevel, pPos, pState);
            if(pBlockEntity.progress > pBlockEntity.maxProgress) {
                craftItem(pBlockEntity);
            }
        } else {
            pBlockEntity.resetProgress();
            setChanged(pLevel, pPos, pState);
        }
    }

    private static boolean hasRecipe(@NotNull CleaningTableBlockEntity entity) {
        Level level = entity.level;
        SimpleContainer inventory = new SimpleContainer(entity.itemHandler.getSlots());
        for (int i = 0; i < entity.itemHandler.getSlots(); i++) {
            inventory.setItem(i, entity.itemHandler.getStackInSlot(i));
        }

        Optional<CleaningTableRecipe> match = level.getRecipeManager()
                .getRecipeFor(CleaningTableRecipe.Type.INSTANCE, inventory, level);

        return match.isPresent() && canInsertAmountIntoOutputSlot(inventory)
                && canInsertItemIntoOutputSlot(inventory, match.get().getResultItem())
                 && hasToolsInToolSlot(entity);
    }


    private static boolean hasToolsInToolSlot(CleaningTableBlockEntity entity) {
        return !entity.itemHandler.getStackInSlot(1).isEmpty();
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @javax.annotation.Nullable Direction side) {
        if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
            return lazyItemHandler.cast();
        }

        return super.getCapability(cap, side);
    }

    private static void craftItem(CleaningTableBlockEntity entity) {
        Level level = entity.level;
        SimpleContainer inventory = new SimpleContainer(entity.itemHandler.getSlots());
        for (int i = 0; i < entity.itemHandler.getSlots(); i++) {
            inventory.setItem(i, entity.itemHandler.getStackInSlot(i));
        }

        Optional<CleaningTableRecipe> match = level.getRecipeManager()
                .getRecipeFor(CleaningTableRecipe.Type.INSTANCE, inventory, level);

        if(match.isPresent()) {
            entity.itemHandler.extractItem(0,1, false);
            if(entity.itemHandler.getStackInSlot(1).hurt(1, new Random(), null)) {
                entity.itemHandler.extractItem(1, 1, false);
            }

            entity.itemHandler.setStackInSlot(2, new ItemStack(match.get().getResultItem().getItem(),
                    entity.itemHandler.getStackInSlot(2).getCount() + 1));

            entity.resetProgress();
        }
    }

    private void resetProgress() {
        this.progress = 0;
    }

    private static boolean canInsertItemIntoOutputSlot(SimpleContainer inventory, ItemStack output) {
        return inventory.getItem(2).getItem() == output.getItem() || inventory.getItem(2).isEmpty();
    }

    private static boolean canInsertAmountIntoOutputSlot(SimpleContainer inventory) {
        return inventory.getItem(2).getMaxStackSize() > inventory.getItem(2).getCount();
    }

 

 

Edited by vntlyy007
Link to comment
Share on other sites

Hopper takes items from input slot, i tried to clone the code of vanilla containers, but it doesn't work

 

BlockEntity:

Spoiler
public class CleaningTableBlockEntity extends BlockEntity implements MenuProvider {
    private final ItemStackHandler itemHandler = new ItemStackHandler(3){
        @Override
        protected void onContentsChanged(int Slot){
            setChanged();
        }
    };

    private LazyOptional<IItemHandler> lazyItemHandler = LazyOptional.empty();



    protected final ContainerData data;
    private int progress = 0;
    private int maxProgress = 26;

    public CleaningTableBlockEntity(BlockPos p_155229_, BlockState p_155230_) {
        super(ModBlockEntities.CLEANING_TABLE_BLOCK_ENTITY.get(), p_155229_, p_155230_);

        this.data = new ContainerData() {
            public int get(int index) {
                switch (index) {
                    case 0: return CleaningTableBlockEntity.this.progress;
                    case 1: return CleaningTableBlockEntity.this.maxProgress;
                    default: return 0;
                }
            }

            public void set(int index, int value) {
                switch(index) {
                    case 0: CleaningTableBlockEntity.this.progress = value; break;
                    case 1: CleaningTableBlockEntity.this.maxProgress = value; break;
                }
            }

            public int getCount() {
                return 2;
            }
        };
    }

    @Override
    public Component getDisplayName() {
        return new TextComponent("Cleaning Table");
    }

    @Nullable
    @Override
    public AbstractContainerMenu createMenu(int pContainerId, Inventory pInventory, Player pPlayer) {
        return new CleaningTableMenu(pContainerId, pInventory, this, this.data);
    }
    @Nonnull

    @Override
    public void onLoad() {
        super.onLoad();
        lazyItemHandler = LazyOptional.of(() -> itemHandler);
    }

    @Override
    public void invalidateCaps()  {
        super.invalidateCaps();
        lazyItemHandler.invalidate();
    }

    @Override
    protected void saveAdditional(@NotNull CompoundTag tag) {
        tag.put("inventory", itemHandler.serializeNBT());
        tag.putInt("cleaning.progress", progress);
        super.saveAdditional(tag);
    }

    @Override
    public void load(CompoundTag nbt) {
        super.load(nbt);
        itemHandler.deserializeNBT(nbt.getCompound("inventory"));
        progress = nbt.getInt("cleaning.progress");
    }

    public void drops() {
        SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots());
        for (int i = 0; i < itemHandler.getSlots(); i++) {
            inventory.setItem(i, itemHandler.getStackInSlot(i));
        }

        Containers.dropContents(this.level, this.worldPosition, inventory);
    }


    public static void serverTick(Level pLevel, BlockPos pPos, BlockState pState, CleaningTableBlockEntity pBlockEntity) {
        if(hasRecipe(pBlockEntity)) {
            pBlockEntity.progress++;
            setChanged(pLevel, pPos, pState);
            if(pBlockEntity.progress > pBlockEntity.maxProgress) {
                craftItem(pBlockEntity);
            }
        } else {
            pBlockEntity.resetProgress();
            setChanged(pLevel, pPos, pState);
        }
    }

    private static boolean hasRecipe(@NotNull CleaningTableBlockEntity entity) {
        Level level = entity.level;
        SimpleContainer inventory = new SimpleContainer(entity.itemHandler.getSlots());
        for (int i = 0; i < entity.itemHandler.getSlots(); i++) {
            inventory.setItem(i, entity.itemHandler.getStackInSlot(i));
        }

        Optional<CleaningTableRecipe> match = level.getRecipeManager()
                .getRecipeFor(CleaningTableRecipe.Type.INSTANCE, inventory, level);

        return match.isPresent() && canInsertAmountIntoOutputSlot(inventory)
                && canInsertItemIntoOutputSlot(inventory, match.get().getResultItem())
                 && hasToolsInToolSlot(entity);
    }


    private static boolean hasToolsInToolSlot(CleaningTableBlockEntity entity) {
        return !entity.itemHandler.getStackInSlot(1).isEmpty();
    }

    @Nonnull
    @Override
    public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @javax.annotation.Nullable Direction side) {
        if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
            return lazyItemHandler.cast();
        }

        return super.getCapability(cap, side);
    }

    private static void craftItem(CleaningTableBlockEntity entity) {
        Level level = entity.level;
        SimpleContainer inventory = new SimpleContainer(entity.itemHandler.getSlots());
        for (int i = 0; i < entity.itemHandler.getSlots(); i++) {
            inventory.setItem(i, entity.itemHandler.getStackInSlot(i));
        }

        Optional<CleaningTableRecipe> match = level.getRecipeManager()
                .getRecipeFor(CleaningTableRecipe.Type.INSTANCE, inventory, level);

        if(match.isPresent()) {
            entity.itemHandler.extractItem(0,1, false);
            if(entity.itemHandler.getStackInSlot(1).hurt(1, new Random(), null)) {
                entity.itemHandler.extractItem(1, 1, false);
            }

            entity.itemHandler.setStackInSlot(2, new ItemStack(match.get().getResultItem().getItem(),
                    entity.itemHandler.getStackInSlot(2).getCount() + 1));

            entity.resetProgress();
        }
    }

    private void resetProgress() {
        this.progress = 0;
    }

    private static boolean canInsertItemIntoOutputSlot(SimpleContainer inventory, ItemStack output) {
        return inventory.getItem(2).getItem() == output.getItem() || inventory.getItem(2).isEmpty();
    }

    private static boolean canInsertAmountIntoOutputSlot(SimpleContainer inventory) {
        return inventory.getItem(2).getMaxStackSize() > inventory.getItem(2).getCount();
    }

 

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.