Uploaded image for project: 'Minecraft: Java Edition'
  1. Minecraft: Java Edition
  2. MC-91727

loot table "spreading large stacks" will overwrite existing items

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Minecraft 1.13-pre6
    • Minecraft 15w44b, Minecraft 15w45a, Minecraft 15w46a, Minecraft 15w47c, Minecraft 15w50a, Minecraft 16w02a, Minecraft 16w04a, Minecraft 16w05a, Minecraft 16w06a, Minecraft 1.9 Pre-Release 1, Minecraft 1.9 Pre-Release 2, Minecraft 1.9 Pre-Release 3, Minecraft 1.9, Minecraft 1.9.1 Pre-Release 1, Minecraft 1.9.1 Pre-Release 2, Minecraft 1.9.1 Pre-Release 3, Minecraft 1.10.2, Minecraft 1.11.2, Minecraft 17w06a, Minecraft 1.12.2, Minecraft 18w03b, Minecraft 1.13-pre5
    • Confirmed

      The bug

      Item stacks with a count > 1 generated by loot tables are spread into multiple smaller item stacks even if there is not enough place in the container resulting in a loss of items and the following warning message:

      [Server thread/WARN]: Tried to over-fill a container
      

      How to reproduce

      1. Create a loot table which generates 27 item stacks, with some of them having a count > 1
        {
            "pools": [
                {
                    "rolls": 24,
                    "entries": [
                        {
                            "type": "item",
                            "name": "minecraft:iron_sword",
                            "weight": 1
                        }
        	    ]
        	},
                {
                    "rolls": 3,
                    "entries": [
                        {
                            "type": "item",
                            "name": "minecraft:torch",
                            "functions": [
                                {
                                    "function": "set_count",
                                    "count": 16
                                }
                            ],
                            "weight": 1
                        }
                    ]
                }
            ]
        }
        
      2. Save it for example in a data pack under \data\loot_tables\custom\test_loot_table.json
      3. Load the world and place a chest with the loot table
        /setblock ~ ~ ~ chest{LootTable:"custom:test_loot_table"}
        
      4. Open the chest
        → You will notice that it contains less than 24 swords, but the torch item stacks are split into more than 3. Additionally a warning should appear in the log: "[Server thread/WARN]: Tried to over-fill a container"

      Code analysis and suggested fix

      Based on 1.11.2 decompiled using MCP 9.35 rc1

      The problem is that the method net.minecraft.world.storage.loot.LootTable.shuffleItems(List<ItemStack>, int, Random) only calculates the amount of free slots once and not in every iteration and additionally the amount of stacks which should be split is not subtracted.

      Suggested fix
      /**
       * shuffles items by changing their order and splitting stacks
       *
       * @param p_186463_2_ Free slots in container
       */
      private void shuffleItems(List<ItemStack> stacks, int p_186463_2_, Random rand)
      {
          // Comment: "list" contains the item stacks to split
          List<ItemStack> list = Lists.<ItemStack>newArrayList();
          Iterator<ItemStack> iterator = stacks.iterator();
      
          while (iterator.hasNext())
          {
              ItemStack itemstack = (ItemStack)iterator.next();
      
              if (itemstack.isEmpty())
              {
                  iterator.remove();
              }
              else if (itemstack.getCount() > 1)
              {
                  list.add(itemstack);
                  iterator.remove();
              }
          }
      
          // Comment: Removed this and moved it in the loop condition
          // p_186463_2_ = p_186463_2_ - stacks.size();
      
          // while (p_186463_2_ > 0 && ((List)list).size() > 0)
          while ((p_186463_2_ - stacks.size() - list.size()) > 0 && ((List)list).size() > 0)
          {
              ItemStack itemstack2 = (ItemStack)list.remove(MathHelper.getInt(rand, 0, list.size() - 1));
              int i = MathHelper.getInt(rand, 1, itemstack2.getCount() / 2);
              ItemStack itemstack1 = itemstack2.splitStack(i);
      
              if (itemstack2.getCount() > 1 && rand.nextBoolean())
              {
                  list.add(itemstack2);
              }
              else
              {
                  stacks.add(itemstack2);
              }
      
              if (itemstack1.getCount() > 1 && rand.nextBoolean())
              {
                  list.add(itemstack1);
              }
              else
              {
                  stacks.add(itemstack1);
              }
          }
      
          stacks.addAll(list);
          Collections.shuffle(stacks, rand);
      }
      

            dinnerbone [Mojang] Nathan Adams
            brianmcn Brian McNamara
            Votes:
            102 Vote for this issue
            Watchers:
            33 Start watching this issue

              Created:
              Updated:
              Resolved:
              CHK: