How do I disable a craft operation?

Sponge Build: spongevanilla-1.12.1-7.0.0-BETA-314
Forge Build: (Ignore if using SpongeVanilla)
Java Version: 1.8.0_131

Plugin Source:

        @Listener
        public void onPlayerCraft(ClickInventoryEvent event, @First Player player)
        {
            Inventory inventory = event.getTargetInventory();
            for (SlotTransaction transaction : event.getTransactions())
            {
                Inventory craftInventory = inventory.query(CraftingInventory.class);
                //craft manipulation here
            }
        }

Hello Everyone,

As mentioned in the title, I am trying to disable a craft operation. Specifically I am trying to make a “new” set of items (represented by named gold nuggets, ingots, and blocks) that can be crafted into each other, but not other recipes that use typical gold.

However, I can’t seem to find a way to accomplish this task. Here’s a list of things I have tried/looked into:

  • Using the CraftItemEvent (seems to no longer exist)
  • Unregistering the vanilla craft recipe (can only register new recipes)
  • Using the ClickInventoryEvent (best lead so far, things I’ve tried inside below)
  • Getting CraftingInventory, GridInventory, etc using the Inventory Api’s query method using the click event’s inventory
  • Getting the above directly through the “clicking” player’s inventory

The snippet of code written above is a near copy of the code I found in a question similar to this one in 2016 but it seems to no longer work. I’ve tried everything I could think of short of using NMS or doing a PR. Of the two I’d prefer to take on the latter.

So, is there a better way to go about this or does sponge currently lack this ability? If sponge is lacking in this aspect, what unimplemented factor do I need to do a PR for to make this happen?

Thank you for your time!

1 Like

This is how I do it in ProtectionPerms

@Listener
public void onItemCraft(ClickInventoryEvent event, @Root Player player, @Getter("getTargetInventory") Inventory inventory) {

    if (inventory.getArchetype() == InventoryArchetypes.PLAYER || inventory.getArchetype() == InventoryArchetypes.WORKBENCH) {

        Inventory craftingOutputs = inventory.query(CraftingOutput.class);

        craftingOutputs.slots().forEach(slot -> slot.peek().ifPresent(itemStack -> {
            String itemId = itemStack.getItem().getType().getId();
            if (!player.hasPermission("protectionperms.item.craft." + itemId)) {
                event.setCancelled(true);
                player.sendMessage(ChatTypes.ACTION_BAR, Text.of(TextColors.RED, "You don't have permission to craft " + itemId + '!'));
            }
        }));
    }
}

You can see here that I’m specifically looking at the output slots to determine what was being crafted, but you could easily flip this around to examine the input slots to determine what is being put in, if any of the items don’t match what is allowed then you can simply cancel the event. Hope that helps!

2 Likes

Thanks for the tip! I’ll give it a shot when I get back from work and let you know how it goes!

Unfortunately, it appears your method only worked for the crafting output. Using CraftingInventory and CraftingGridInventory both returns empty inventories.

Looking into the values of inventory in the debugger I think I might poke around getting the specific slot numbers of the crafting input to work. If anyone else has a better idea of how to go about this, or what in sponge I could implement this to add it as a real feature, please let me know!

Thanks!

What about Input Slot?
Though CraftingInventory should work, if it doesn’t you should file a bug report.

Input Slot appears to get me an instance of GridInventory oddly enough. I’ll fill out a bug report in a bit, though first I have an idea I’d like to try.

Please update with your results if they work, as I am trying to do something virtually identical - adding “cardboard box technology” items (aka, imagination powered, not mod-powered) that makes copper ingots from bricks, and can be used in recipes to make special tools and items, but I don’t want someone consuming them accidentally making regular bricks, or prismarine blocks out of rare and expensive ‘jade’, or a special tool from bricks instead of copper ingots (though I think I can register the recipes in such a way that covers that)

Ok so after some tinkering and testing I’ve learned a few things.

Zerthick’s suggestion on the input slot works, but only for the crafting table (not the player menu crafting). It’ll give you a GridInventory of the 3 by 3 you’ll find in the craft table (where 0, 0 is upper left corner, 0, 1 is the one below it, etc).

However, there isn’t a way to get this for the player inventory crafting as far as I could find, so I’ll have to rely on the bug report. Another thing to note is that I’m working on sponge 7.0.0 (to make use of the Recipe API ironically) so that may be some of my issue.

I’ll put in the bug report on that lack of crafting inventory and make a pr if I somehow manage to figure out a fix.

1 Like

Hi all, I was attempting to try something similar, using @Zerthick 's onItemCraft method as an example. The code works fine in the player inventory, but throws an error in the workbench inventory. As a note, I’m using spongeapi:5.1.0 for minecraft 1.10.2.

It fails on this line:

    Inventory craftingOutputs = inventory.query(CraftingOutput.class);

Googling has given me this post from a few months ago.

Is this an issue that is only in the 1.10.2 builds of sponge?

Would depend on the build of sponge you are using, and implimentation.
Yes, that issue - if you get the same error - is due to a thing that was not fixed until early February 2017, if you are using a version from that long ago.
The 1.10.2 builds from long ago will contain that error, but the more recent builds should include that codefix in both SF and SV versions, and you may be looking at a different error.

Even the 1.10.2 Api 5.1 version seems to have had its last versions updated at the end of February, so they will either be including that code fix in them, or that code fix was added at the start of the 5.2 verisions

1 Like

You were completely right :slight_smile: I updated to the 5.2.0 series of versions and the error went away. Very embarrassing oops!

I’ve still been trying out the code, and it cancels the event when an item is put into the input slot that produces the output we are checking for. Is there a way to detect specifically if the transaction slot being clicked is the out put slot? I tried doing the below, but I think the output is added to the list of transactions. Would be happy to hear of best way to do so, as well as any better coding practices :slight_smile:

boolean IsClickingOutput = false;
if ( event.getTransactions().get(0).getSlot().getProperty(SlotIndex.class, "slotindex") == slot.getProperty(SlotIndex.class, "slotindex") )
{
     logger.info("Player is trying to craft the item " + itemId);
     IsClickingOutput = true;
}