Solved Grindstone container not supporting other items?

Discussion in 'Spigot Plugin Development' started by Qruet, Jan 24, 2020.

  1. I am currently working on creating a custom container extending the existing ContainerGrindstone class. Unfortunately, when it comes to registering custom item slots, the inventory continues to behave oddly with different items. I've gotten to the point where I am clearing the modified lists and copy pasting exactly what the ContainerGrindstone is doing to register the slots. It would appear the client isn't syncing properly with the server registered inventory. I am hoping the client isn't hardcoded to only allow certain items to be displayed in the inventory, therefore this conflict is causing the client and server to be out of sync? Please view the media below to view an example of what I mean.

    Snippet:
    Code (Java):
        public SmithingContainer(int i, PlayerInventory playerinventory, ContainerAccess containeraccess) {
            super(i, playerinventory, containeraccess);

            Object cI = null;
            Object rI = null;
            try {
                Field craftInventory = ContainerGrindstone.class.getDeclaredField("craftInventory");
                craftInventory.setAccessible(true);
                Field modifiersField = Field.class.getDeclaredField("modifiers");
                modifiersField.setAccessible(true);
                modifiersField.setInt(craftInventory, craftInventory.getModifiers() & ~Modifier.FINAL);
                cI = craftInventory.get(this);

                Field resultInventory = ContainerGrindstone.class.getDeclaredField("craftInventory");
                resultInventory.setAccessible(true);
                modifiersField.setInt(resultInventory, resultInventory.getModifiers() & ~Modifier.FINAL);
                rI = resultInventory.get(this);
            } catch (IllegalAccessException | NoSuchFieldException e) {
                e.printStackTrace();
            }

            craftInventory = (IInventory) cI;
            resultInventory = (IInventory) rI;

            slots.clear();
            items.clear();

            this.a(new Slot(this.craftInventory, 0, 49, 19) {
                public boolean isAllowed(ItemStack itemstack) {
                    return CraftingRegistrar.RECIPE_TYPES.contains(CraftItemStack.asBukkitCopy(itemstack).getType());
                }
            });
            this.a(new Slot(this.craftInventory, 1, 49, 40) {
                public boolean isAllowed(ItemStack itemstack) {
                    return CraftingRegistrar.RECIPE_TYPES.contains(CraftItemStack.asBukkitCopy(itemstack).getType());
                }
            });
            this.a(new Slot(this.resultInventory, 2, 129, 34) {
                public boolean isAllowed(ItemStack itemstack) {
                    return false;
                }

                public ItemStack a(EntityHuman entityhuman, ItemStack itemstack) {
                    containeraccess.a((world, blockposition) -> {
                        int j = this.a(world);

                        while (j > 0) {
                            int k = EntityExperienceOrb.getOrbValue(j);
                            j -= k;
                            world.addEntity(new EntityExperienceOrb(world, (double) blockposition.getX(), (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, k));
                        }

                        world.triggerEffect(1042, blockposition, 0);
                    });
                    SmithingContainer.this.craftInventory.setItem(0, ItemStack.a);
                    SmithingContainer.this.craftInventory.setItem(1, ItemStack.a);
                    return itemstack;
                }

                private int a(World world) {
                    byte b0 = 0;
                    int j = b0 + this.e(SmithingContainer.this.craftInventory.getItem(0));
                    j += this.e(SmithingContainer.this.craftInventory.getItem(1));
                    if (j > 0) {
                        int k = (int) Math.ceil((double) j / 2.0D);
                        return k + world.random.nextInt(k);
                    } else {
                        return 0;
                    }
                }

                private int e(ItemStack itemstack) {
                    int j = 0;
                    Map<Enchantment, Integer> map = EnchantmentManager.a(itemstack);
                    Iterator iterator = map.entrySet().iterator();

                    while (iterator.hasNext()) {
                        Map.Entry<Enchantment, Integer> entry = (Map.Entry) iterator.next();
                        Enchantment enchantment = (Enchantment) entry.getKey();
                        Integer integer = (Integer) entry.getValue();
                        if (!enchantment.c()) {
                            j += enchantment.a(integer);
                        }
                    }

                    return j;
                }
            });

            int j;
            for (j = 0; j < 3; ++j) {
                for (int k = 0; k < 9; ++k) {
                    this.a(new Slot(playerinventory, k + j * 9 + 9, 8 + k * 18, 84 + j * 18));
                }
            }

            for (j = 0; j < 9; ++j) {
                this.a(new Slot(playerinventory, j, 8 + j * 18, 142));
            }
        }
    [​IMG]
     
    #1 Qruet, Jan 24, 2020
    Last edited: Jan 24, 2020
  2. You could try using the PacketPlayOutWindowItems packet, and try to see if that works. Maybe the server just isn't sending a packet to the client when the inventory updates..?
     
  3. Gave it a try to no avail.
    Code (Java):
            addSlotListener(new ICrafting() {
                @Override
                public void a(Container container, NonNullList<ItemStack> nonNullList) {

                }

                @Override
                public void a(Container container, int i, ItemStack itemStack) {
                    PacketPlayOutWindowItems packet = new PacketPlayOutWindowItems(container.windowId, container.items);
                    ((EntityPlayer) playerinventory.player).playerConnection.sendPacket(packet);
                    Bukkit.broadcastMessage("!"); //general debug to ensure packet is being sent
                }

                @Override
                public void setContainerData(Container container, int i, int i1) {

                }
            });
     
  4. Figured it out. The PacketPlayOutWindowItems is only good for updating the actual inventory slots, so it's only half of the solution. The second solution is to actually update the player's cursor which can be done by calling EntityPlayer#broadcastCarriedItem() which essentially just sends the following PacketPlayOutSetSlot(-1, -1, this.inventory.getCarried()). In the end, here is what I did for those who stumble across this thread in the future.
    Code (Java):
            addSlotListener(new ICrafting() {
                @Override
                public void a(Container container, NonNullList<ItemStack> nonNullList) {

                }

                @Override
                public void a(Container container, int i, ItemStack itemStack) {
                    updateClient(playerinventory);
                }

                @Override
                public void setContainerData(Container container, int i, int i1) {

                }
            });

            private void updateClient(PlayerInventory inventory) {
                PacketPlayOutWindowItems packet = new PacketPlayOutWindowItems(windowId, items);
                ((EntityPlayer) inventory.player).playerConnection.sendPacket(packet);
                ((EntityPlayer) inventory.player).broadcastCarriedItem();
            }
     
    • Like Like x 1