--- a/net/minecraft/world/RandomizableContainer.java +++ b/net/minecraft/world/RandomizableContainer.java @@ -28,7 +28,7 @@ void setLootTable(@Nullable ResourceKey lootTable); - default void setLootTable(ResourceKey lootTableId, long lootTableSeed) { + default void setLootTable(@Nullable ResourceKey lootTableId, long lootTableSeed) { // Paper - add nullable this.setLootTable(lootTableId); this.setLootTableSeed(lootTableSeed); } @@ -51,13 +51,14 @@ default boolean tryLoadLootTable(CompoundTag nbt) { if (nbt.contains("LootTable", 8)) { this.setLootTable(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("LootTable")))); + if (this.lootableData() != null && this.getLootTable() != null) this.lootableData().loadNbt(nbt); // Paper - LootTable API if (nbt.contains("LootTableSeed", 4)) { this.setLootTableSeed(nbt.getLong("LootTableSeed")); } else { this.setLootTableSeed(0L); } - return true; + return this.lootableData() == null; // Paper - only track the loot table if there is chance for replenish } else { return false; } @@ -69,26 +70,44 @@ return false; } else { nbt.putString("LootTable", resourceKey.location().toString()); + if (this.lootableData() != null) this.lootableData().saveNbt(nbt); // Paper - LootTable API long l = this.getLootTableSeed(); if (l != 0L) { nbt.putLong("LootTableSeed", l); } - return true; + return this.lootableData() == null; // Paper - only track the loot table if there is chance for replenish } } default void unpackLootTable(@Nullable Player player) { + // Paper start - LootTable API + this.unpackLootTable(player, false); + } + default void unpackLootTable(@Nullable final Player player, final boolean forceClearLootTable) { + // Paper end - LootTable API Level level = this.getLevel(); BlockPos blockPos = this.getBlockPos(); ResourceKey resourceKey = this.getLootTable(); - if (resourceKey != null && level != null && level.getServer() != null) { + // Paper start - LootTable API + lootReplenish: if (resourceKey != null && level != null && level.getServer() != null) { + if (this.lootableData() != null && !this.lootableData().shouldReplenish(this, com.destroystokyo.paper.loottable.PaperLootableInventoryData.CONTAINER, player)) { + if (forceClearLootTable) { + this.setLootTable(null); + } + break lootReplenish; + } + // Paper end - LootTable API LootTable lootTable = level.getServer().reloadableRegistries().getLootTable(resourceKey); if (player instanceof ServerPlayer) { CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, resourceKey); } - this.setLootTable(null); + // Paper start - LootTable API + if (forceClearLootTable || this.lootableData() == null || this.lootableData().shouldClearLootTable(this, com.destroystokyo.paper.loottable.PaperLootableInventoryData.CONTAINER, player)) { + this.setLootTable(null); + } + // Paper end - LootTable API LootParams.Builder builder = new LootParams.Builder((ServerLevel)level).withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(blockPos)); if (player != null) { builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player); @@ -97,4 +116,16 @@ lootTable.fill(this, builder.create(LootContextParamSets.CHEST), this.getLootTableSeed()); } } + + // Paper start - LootTable API + @Nullable @org.jetbrains.annotations.Contract(pure = true) + default com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData() { + return null; // some containers don't really have a "replenish" ability like decorated pots + } + + default com.destroystokyo.paper.loottable.PaperLootableInventory getLootableInventory() { + final org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(java.util.Objects.requireNonNull(this.getLevel(), "Cannot manage loot tables on block entities not in world"), this.getBlockPos()); + return (com.destroystokyo.paper.loottable.PaperLootableInventory) block.getState(false); + } + // Paper end - LootTable API }