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
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 } ] } ] }
Save it for example in a data pack under
\data\loot_tables\custom\test_loot_table.json
Load the world and place a chest with the loot table
/setblock ~ ~ ~ chest{LootTable:"custom:test_loot_table"}
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);
}
Attachments
Comments 23
I've seen this happen with vanilla loot tables. Like when I go to a nether fortress, often, I find gold ingots, all in stacks of one, spread throughout the chest.
Im working on a datapack and I guess the issue is becuase the items are being spread, other items are failing to be added if there's no room left. Basically, this bug but backwards. If you have the torches placed first, they spread so there's not enough room for everything else/.
Aceplante, unfortunately I can't reproduce your bug. Spreading is done after all rolls have been made. Please verify your datapack and if you still find the bug present in latest stable or snapshot version, feel free to create a new bug report with steps to reproduce. Thank you.
@@unknown, to me it sounds like you are requesting the behavior which was originally considered a bug here. It appears there can either be the current behavior of omitting items if there is no free space, or overwriting existing ones, but not both.
You can create a new bug report (please refer to this one then), but most likely the Mojang developers will close it as "Works as Intended" or similar.
Note that this is similar to MC-91310 which they just fixed, which is another instance of 'DeathLootTable's being exact, whereas chest 'LootTable's were "lossy". So I expect this bug is an unintended thing they will fix, since they fixed the other similar issue.