[Solved] Getting Villager price on InventoryClickEvent

Discussion in 'Spigot Plugin Development' started by Kongolan, May 24, 2015.

  1. Hey there,

    i currently work on a plugin, which simply takes the player inventory items fist instead of those in the trading GUI. All it should do is basically check for the costs and reduce the player inventory by it and as well refill the trading GUI with the used items at the same time.

    Sadly it's amazingly difficult to get the actual cost of the Merchant. Does anyone have any solution, how i can get the specific amount a Itemstack needs to have in slot 0 and 1 in the trading inventory?

    Code (Text):
        @EventHandler
        public void onTradeWithVillager(InventoryClickEvent event) {
             Inventory inv = event.getInventory();
            if (!(inv.getType() == InventoryType.MERCHANT))
                return;

            if (!(event.getSlotType() == SlotType.RESULT))
                return;

            if (event.getAction() == InventoryAction.NOTHING)
                return;

                    // getting the cost now here
     
  2. This currently requires some nms code.

    Untested but something among those lines:
    * The top inventory can be casted to CraftInventory and then getInventory() can be called on that, which returns an nms IInventory.
    * Then this IInventory can be casted to InventoryMerchant.
    * On this you can call the method getRecipe() this should return the currently used MerchantRecipe. Note that this is not necessarily the recipe the player has currently selected, but it is the one which is going to be used for the trade. For some reason minecraft sometimes allows you to trade for the conditions of a different offer, when the input-items don't match the selected offer.
    * In MerchantRecipe you then have the methods getBuyItem1() and getBuyItem2() which return minecraft ItemStacks, which you then have to convert to CraftBukkit ItemStacks first by calling CraftItemStack.asBukkitCopy(nmsItemStack).

    That's it. Completly untested.

    Edit: As I need this for one of the plugins I am currently working on as well, this is how it could look like in code. Still untested though.

    Code (Text):
    public ItemStack[] getUsedTradingRecipe(Inventory merchantInventory) {
            try {
                InventoryMerchant handle = (InventoryMerchant) ((CraftInventoryMerchant) merchantInventory).getInventory();
                MerchantRecipe merchantRecipe = handle.getRecipe();
                ItemStack[] recipe = new ItemStack[3];
                recipe[0] = merchantRecipe.getBuyItem1() != null ? CraftItemStack.asBukkitCopy(merchantRecipe.getBuyItem1()) : null;
                recipe[1] = merchantRecipe.getBuyItem2() != null ? CraftItemStack.asBukkitCopy(merchantRecipe.getBuyItem2()) : null;
                recipe[2] = merchantRecipe.getBuyItem3() != null ? CraftItemStack.asBukkitCopy(merchantRecipe.getBuyItem3()) : null;
                return recipe;
            } catch (Exception e) {
                return null;
            }
        }
    Edit: Alternatively you could try the following for your usecase:

    Let the event / the trading happen like normal, but start a delayed task (maybe waiting for 1 tick). After that 1 tick check if the player still has the same trading inventory open. If yes, simply refill the slots 1 and 2 with similar items from the players inventory.
    With this it wouldn't matter what the player exactly traded. All that matters is that the slots are getting refilled with what was removed.
    Also it would fix one remaining issue: In certain cases (on versions below 1.8 or on 1.8 and when the required item has no meta data) minecraft accepts different items (of the same type) for the same trade (ignoring the exact meta data of the item). So the exact recipe would be rather useless here, because the items the player is using for the trade might have different meta data than those which the villager is actually asking for.
    So it makes more sense to refill the slots with the items the player is actually using, instead of those of the recipe.
     
    #2 blablubbabc, May 24, 2015
    Last edited: May 24, 2015
    • Useful Useful x 1
  3. Second works flawless, thank you :3 I don't know, how i couldn't figure it myself!