Hopper Transactions

Bonjour,
j’aimerais empêcher certains items de rentrer ou sortir d’un Hopper et je n’y arrive pas.
Comment je dois faire ?

Actuellement dans mon code d’exemple, si j’ai de la pierre sur le premier slot et de la terre dans le second du coffre sur le Hopper rien ne passe alors que la terre devrait passer. Au contraire si la terre est sur le premier slot elle peut passer dans le Hopper.
On peut voir dans les log qu’il y a deux Transactions, mais cela exécute que la première.

[Google translate]
Hello,
I would like to prevent certain items from going in or out of a Hopper and I can not do it.
How should I do ?

Currently in my example code, if I have stone on the first slot and earth in the second of the safe on the Hopper nothing happens while the earth should pass. On the contrary if the earth is on the first slot it can pass in the Hopper.
We can see in the log that there are two Transactions, but it executes only the first one.

Code:

public class ChangeInventory {
    public static void event(ChangeInventoryEvent event) {
        if(event.getCause().first(Hopper.class).isPresent()) {
            Hopper hopper = event.getCause().first(Hopper.class).get();
            Location<World> hopperLoc = hopper.getLocation();

            if(event instanceof ChangeInventoryEvent.Transfer) {
                ToolCore.getLogger().info(" ChangeInventoryEvent.Transfer Hopper: Transactions size " + event.getTransactions().size());

                for(SlotTransaction transaction : event.getTransactions()) {
                    ItemStackSnapshot itemStackSnapshotTransaction = transaction.getOriginal();

                    if(!itemStackSnapshotTransaction.getType().equals(ItemTypes.AIR)) {
                        if(itemStackSnapshotTransaction.getType().equals(ItemTypes.STONE)) {
                            event.setCancelled(true);

                        } else {
                            event.setCancelled(false);
                        }
                        ToolCore.getLogger().info(event.isCancelled() + " " + hopperLoc.getPosition().toString() + " " + itemStackSnapshotTransaction.getType().getId() + " " + itemStackSnapshotTransaction.getQuantity());
                    }
                }
            }
        }
    }
}

So first of all, you can clean up your code a lot. Secondly it all depends on the order/placement due to how hoppers work in mc. If you attempt to move an item from one hopper to another, it takes the first slot and moves that slot, 1 item at a time and then moves to the second.

Due to the fact your cancelling the move, all that happens is the slots stay the same, therefore it will attempt to move the exact same item again and again and again.

Also due to the fact you are saying event.setCancelled(false), it can undo the cancelling of the event, allowing the stone to be passed

I would suggest that if the item is in your blacklist then move it to the last slot in the hopper. Also here is your code just cleaned up.

public void onEvent(ChangeInventoryEvent.Transfer event, @First Hopper hopper) {
    Location<World> loc = hopper.getLocation();
    for(SlotTransaction transaction : event.getTransactions()){
        ItemStackSnapshot snapshot = transaction.getOriginal();
        ItemType type = snapshot.getType();
        if(type.equals(ItemTypes.AIR)) {
            continue;
        }
        if(type.equals(ItemTypes.STONE)) {
            event.setCancelled(true);
            return;
       }
}

Je dois ranger le coffre ?
2019-11-03%2022-51-17

So same logic applies here. Hoppers take from the least slot index until there is nothing left. Because the stone is getting cancelled, Minecraft itself keeps trying to process the stone. As mentioned before, the way around this would be when it detects stone then move it to the last slot of the inventory

J’ai fait comme çà pour le coffre avant que le Hopper prenne l’item:

[Google translate]
I did like that for the chest before the Hopper took the item:

            for(Inventory inventory : chest.getInventory().slots()) {
                inventory.peek().ifPresent(itemStack -> {
                    if(!itemStack.getType().equals(ItemTypes.STONE)) {
                        inventory.clear();
                    chest.getInventory().offer(itemStack);
                    }
                });
            }

While that will put the none stone items to the front (if stone isnt already at the front) however my guess is you tied that to the item remove event? Right? If so then the order is wrong. The check for the transfer occurs, if that event isnt cancelled then this code will run.

In that state, this code is only ran when it isnt stone attempting to be processed, meaning that the item your trying to bring to the front … Is already at the front.

You need to use the previous event to get the inventory the stone originated from and move the stones to the last index

Il y a une méthode pour le mettre au dernier index disponible?

[Google translate]
There is a method to put it at the last available index?

Inventory inventory;
Slot slot = (Slot) inventory.query(QueryOperationTypes.INVENTORY_PROPERTY.of(new SlotIndex(inventory.getSize() - 1)));

Its something like that. Im doing it from memory as i don’t have a pc infront of me