Custom Anvil Help

Discussion in 'Spigot Plugin Development' started by hotpatooky, Jul 14, 2018 at 8:31 AM.

Thread Status:
Not open for further replies.
  1. I wanted to use a custom anvil menu to apply special enchants for my plugin. I looked at some nms code and made a special class that extends ContainerAnvil.

    Everything works fine except that the player cannot pickup the output item unless I set it's repair cost above 0. Additionally, when the player does pick up the output item it for some reason does not update the inventory so the player cannot see that the item is on their cursor until they click their inventory a couple times. There most likely is something client side that needs to be sent.

    I
    Code (Java):
    public class EnchantMenu extends ContainerAnvil {


        //Private inherited methods
        IInventory inputSlots;
        IInventory outputSlots;
        int materialCost = 999;
        EntityHuman human;

        int level;
        Enchants inputEnchant;

        public EnchantMenu(PlayerInventory playerinventory, final World world, final BlockPosition blockposition, EntityHuman entityhuman) {
            super(playerinventory, world, blockposition, entityhuman);

        }

        //According to the decompiled code this method is called updateRepairOutput() and is invoked when their          //needs to be logic executed to determine what the anvil output should be. Because I didn't want any repair
        //cost or durability calculations, I just wrote the logic to handle adding my custom enchants from the items          //lore.
        @Override
        public void e() {
            if(inputSlots == null || outputSlots == null || materialCost == 999) {
                try {
                    Field itemfield = this.getClass().getSuperclass().getDeclaredField("h");
                    itemfield.setAccessible(true);

                    Field outputfield = this.getClass().getSuperclass().getDeclaredField("g");
                    outputfield.setAccessible(true);

                    Field materialcostfield = this.getClass().getSuperclass().getDeclaredField("k");
                    materialcostfield.setAccessible(true);

                    Field humanfield = this.getClass().getSuperclass().getDeclaredField("m");
                    humanfield.setAccessible(true);

                    this.inputSlots = (IInventory) itemfield.get(this);
                    this.outputSlots = (IInventory) outputfield.get(this);
                    this.materialCost = (int) materialcostfield.get(this);
                    this.human = (EntityHuman) humanfield.get(this);

                } catch(NoSuchFieldException e) {
                    e.printStackTrace();

                } catch(IllegalAccessException e) {
                    e.printStackTrace();

                }
            }

                ItemStack item = inputSlots.getItem(0);
                ItemStack enchantbook = inputSlots.getItem(1);
                this.a = 0;

                if(item == null) {
                    outputSlots.setItem(0, (ItemStack)null);
                    this.a = 0;
                    return;
                }

                if(enchantbook == null) {
                    Main.getInstance().getLogger().info("BOOK IS NULL");
                    return;
                }

                if(Item.getId(enchantbook.getItem()) == 403) {
                    String name = enchantbook.getName();

                    try {
                        String[] split = name.split(" ");
                        Main.getInstance().getLogger().info(split[3] + " || " + split[3].length());

                        String enchantname = split[2].substring(4, split[2].length());
                        level = RomanNumerals.toNumerical(split[3]);

                        if(level == 0) {
                            Main.getInstance().getLogger().info("Error getting rnumeric value");
                            return;
                        }

                        inputEnchant = null;

                        for(Enchants x : Enchants.values()) {

                            if(x.getPrettyName().equals(enchantname)) {
                                inputEnchant = x;
                            }
                        }

                        if(inputEnchant == null) {
                            Main.getInstance().getLogger().info("Error getting enchant");
                            return;
                        }

                        if(!item.getItem().f_(item)) {
                            Main.getInstance().getLogger().info("Error getting rnumeric value");
                            return;
                        }//Check if item is a tool.

                        ItemStack outputItemNMS = item.cloneItemStack();
                        org.bukkit.inventory.ItemStack outputItem = CraftItemStack.asCraftMirror(outputItemNMS);

                        try {

                            Enchants.addEnchant(inputEnchant, level, outputItem);

                        } catch(AlreadyHasEnchantException e) {

                            try {
                                Enchants.setLevel(inputEnchant, level, outputItem);
                            } catch(DoesNotHaveEnchantException err) {
                                Main.getInstance().getLogger().info("Does not have enchant");
                                return;
                            }

                        }

                        ItemStack finalOutput = CraftItemStack.asNMSCopy(outputItem);
                        finalOutput.setRepairCost(1);
                        materialCost = 1;
                        this.a = 1;
                         
                        //These two lines of code set the anvil output and the second line is a method called
                        // detectAndSendChanges(), I was hoping it might update the inventory so players could see
                        // the output item on their cursor when they finalize the anvil transaction, but it did not seem to                            //work
                        outputSlots.setItem(0, finalOutput);
                        this.b();
                        /*
                        */

                        ArcPrison.getInstance().getLogger().info("Setting output");

                    } catch(ArrayIndexOutOfBoundsException e) {
                        Main.getInstance().getLogger().info("String space slicing error");
                        return;

                    }

                    this.b();
                    Player p = ((CraftPlayer) human.getBukkitEntity());
                    p.updateInventory();
                }
                else {
                    this.b();
                    return;
                }
            this.b();
        }


        //This method is called when the player opens the inventory and checks to see if the anvil specified at
        //block position is in reach. I set it to return true so that the gui can be access globally
        @Override
        public boolean a(EntityHuman entityhuman) {
            return true;
        }

        //This method handles the name changing field of the anvil menu, I just set it to return because I did not want
        //players to change item names
        @Override
        public void a(String s) {
            return;
        }
    }
     
     
  2. Have you tried updating the inventory of the Player ?
     
  3. You can check the inventoryclickevent and give the player the item if he clicks on it. and you can update it's inventory with player#updateInventory
     
  4. Ive tried this and it didn't seem to affect anything. I tried updating it from a separate event listener and within the anvil class itself. I'm still facing issues with setting the xp cost to 0, it just breaks the entire thing.
    I've discovered some code in the constructor of ContainerAnvil that may solve my problems so I will return with my findings

    Edit: I found code in the constructor of ContainerAnvil that I altered to allow my custom anvil to have an xp cost of 0. Additionally, there was a method called whenever a player clicks on the output item that I made adjustments to, so players could actually see the item.
     
    #4 hotpatooky, Jul 14, 2018 at 9:43 PM
    Last edited: Jul 15, 2018 at 12:25 AM
Thread Status:
Not open for further replies.

Share This Page