Cause any item dropped from the block that was broken by player in survival mode depends on the loot table, and the the contents of include
and exclude
in copy_components
function of item modifier of the loot table determines what components to keep when a block entity is broken. Checking data/minecraft/loot_table/blocks/shulker_box.json
from vanilla datapack, you can find
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"functions": [
{
"function": "minecraft:copy_components",
"include": [
"minecraft:custom_name",
"minecraft:container",
"minecraft:lock",
"minecraft:container_loot"
],
"source": "block_entity"
}
],
"name": "minecraft:shulker_box"
}
],
"rolls": 1.0
}
],
"random_sequence": "minecraft:blocks/shulker_box"
}
Obviously there are 4 kinds of components in total are kept. If you wanna add new component types, just write down a datapack where the loot table of shulker box are copied to the same relative path, and yet plus your expected components like minecraft:rarity
into include
. Though all shulker boxes might resolved by the same steps, it is the most effective methods without modifying the source code of Minecraft by modding or something else.
If you are familiar with modding, taking yarn mapping for example, you need to mixin like
@Mixin(CopyComponentsLootFunction.class)
public abstract class CopyComponentsLootFunctionMixin implements CCLFTouch {
@Final @Shadow
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private Optional<List<ComponentType<?>>> include;
@Mutable @Final @Shadow
private Predicate<ComponentType<?>> filter;
@Override
public void mod$touch(List<ComponentType<?>> types) {
include.ifPresent(componentTypes ->
filter = Stream.concat(componentTypes.stream(), types.stream()).toList()::contains);
}
}
And place the following hook (in Kotlin, you can convert it to Java version) after the server started and datapack reloaded
Registries.BLOCK.iterateEntries(BlockTags.SHULKER_BOXES).forEach { entry ->
val lootTable = server.reloadableRegistries.getLootTable(entry.value().lootTableKey.get()) as LootTableAccessor
(lootTable.pools[0]?.entries[0] as? LeafEntry as? LeafEntryAccessor)
?.functions?.filterIsInstance<CopyComponentsLootFunction>()?.forEach {
(it as CCLFTouch).`mod$touch`(listOf(DataComponentTypes.RARITY))
}
}
Where server
is MinecraftServer
instance, CCLFTouch
is a defined interface, LootTableAccessor
and LeafEntryAccessor
are used to access certain private fields, which are trivial.
Affects 19w04b, and also occurs when /fill is used to remove campfires
This issue emerged at 25w09a, when the collision code was modified, and until now (25w20a) it still exists. Actually this problem is so severe that almost any survival servers running continuously where players AFK for several days are bound to crash. Hope it will receive immediate attention.