2021-06-11 14:02:28 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 1 May 2016 21:19:14 -0400
2024-01-23 14:34:17 +01:00
Subject: [PATCH] LootTable API and replenishable lootables
2021-06-11 14:02:28 +02:00
Provides an API to control the loot table for an object.
Also provides a feature that any Lootable Inventory (Chests in Structures)
can automatically replenish after a given time.
This feature is good for long term worlds so that newer players
do not suffer with "Every chest has been looted"
2022-11-20 00:53:20 +01:00
== AT ==
public org.bukkit.craftbukkit.block.CraftBlockEntityState getTileEntity()Lnet/minecraft/world/level/block/entity/BlockEntity;
public org.bukkit.craftbukkit.block.CraftLootable setLootTable(Lorg/bukkit/loot/LootTable;J)V
public org.bukkit.craftbukkit.entity.CraftMinecartContainer setLootTable(Lorg/bukkit/loot/LootTable;J)V
2022-06-07 23:48:09 +02:00
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
new file mode 100644
2023-06-08 01:21:20 +02:00
index 0000000000000000000000000000000000000000..9ca389ca789dc54bba3542cac0aac2e1dc66c870
2022-06-07 23:48:09 +02:00
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperContainerEntityLootableInventory.java
@@ -0,0 +1,63 @@
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.vehicle.AbstractMinecartContainer;
+import net.minecraft.world.entity.vehicle.ContainerEntity;
+import net.minecraft.world.level.Level;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+
+public class PaperContainerEntityLootableInventory implements PaperLootableEntityInventory {
+
+ private final ContainerEntity entity;
+
+ public PaperContainerEntityLootableInventory(ContainerEntity entity) {
+ this.entity = entity;
+ }
+
+ @Override
+ public org.bukkit.loot.LootTable getLootTable() {
+ return entity.getLootTable() != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(entity.getLootTable())) : null;
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
+ setLootTable(table);
+ setSeed(seed);
+ }
+
+ @Override
+ public void setSeed(long seed) {
+ entity.setLootTableSeed(seed);
+ }
+
+ @Override
+ public long getSeed() {
+ return entity.getLootTableSeed();
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table) {
+ entity.setLootTable((table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey()));
+ }
+
+ @Override
+ public PaperLootableInventoryData getLootableData() {
+ return entity.getLootableData();
+ }
+
+ @Override
+ public Entity getHandle() {
+ return entity.getEntity();
+ }
+
+ @Override
+ public LootableInventory getAPILootableInventory() {
+ return (LootableInventory) entity.getEntity().getBukkitEntity();
+ }
+
+ @Override
+ public Level getNMSWorld() {
2023-06-08 01:21:20 +02:00
+ return entity.level();
2022-06-07 23:48:09 +02:00
+ }
+}
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
new file mode 100644
2023-04-07 20:39:13 +02:00
index 0000000000000000000000000000000000000000..24c6ff57cd25533e71f8a1d0b3c0ece2fdbbf87e
2021-06-11 14:02:28 +02:00
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableBlockInventory.java
2021-06-12 06:38:04 +02:00
@@ -0,0 +1,33 @@
2021-06-11 14:02:28 +02:00
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
+import org.bukkit.Chunk;
+import org.bukkit.block.Block;
+
+public interface PaperLootableBlockInventory extends LootableBlockInventory, PaperLootableInventory {
+
+ RandomizableContainerBlockEntity getTileEntity();
+
+ @Override
+ default LootableInventory getAPILootableInventory() {
+ return this;
+ }
+
+ @Override
+ default Level getNMSWorld() {
2023-04-07 20:39:13 +02:00
+ return this.getTileEntity().getLevel();
2021-06-11 14:02:28 +02:00
+ }
+
+ default Block getBlock() {
2023-04-07 20:39:13 +02:00
+ final BlockPos position = this.getTileEntity().getBlockPos();
+ final Chunk bukkitChunk = this.getBukkitWorld().getChunkAt(org.bukkit.craftbukkit.block.CraftBlock.at(this.getNMSWorld(), position));
2021-06-11 14:02:28 +02:00
+ return bukkitChunk.getBlock(position.getX(), position.getY(), position.getZ());
+ }
+
+ @Override
+ default PaperLootableInventoryData getLootableData() {
2023-04-07 20:39:13 +02:00
+ return this.getTileEntity().lootableData;
2021-06-11 14:02:28 +02:00
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
new file mode 100644
2021-06-12 07:20:08 +02:00
index 0000000000000000000000000000000000000000..2fba5bc0f982e143ad5f5bda55d768edc5f847df
2021-06-11 14:02:28 +02:00
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableEntityInventory.java
2021-06-12 07:20:08 +02:00
@@ -0,0 +1,28 @@
2021-06-11 14:02:28 +02:00
+package com.destroystokyo.paper.loottable;
+
+import net.minecraft.world.level.Level;
+import org.bukkit.entity.Entity;
+
+public interface PaperLootableEntityInventory extends LootableEntityInventory, PaperLootableInventory {
+
+ net.minecraft.world.entity.Entity getHandle();
+
+ @Override
+ default LootableInventory getAPILootableInventory() {
+ return this;
+ }
+
+ default Entity getEntity() {
+ return getHandle().getBukkitEntity();
+ }
+
+ @Override
+ default Level getNMSWorld() {
+ return getHandle().getCommandSenderWorld();
+ }
+
+ @Override
+ default PaperLootableInventoryData getLootableData() {
+ return getHandle().lootableData;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
new file mode 100644
2023-08-12 23:26:47 +02:00
index 0000000000000000000000000000000000000000..8e6dac2cef7af26ad74928eff631c1826c2980bb
2021-06-11 14:02:28 +02:00
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventory.java
2023-08-12 23:26:47 +02:00
@@ -0,0 +1,75 @@
2021-06-11 14:02:28 +02:00
+package com.destroystokyo.paper.loottable;
+
+import org.bukkit.loot.Lootable;
+import java.util.UUID;
+import net.minecraft.world.level.Level;
+
+public interface PaperLootableInventory extends LootableInventory, Lootable {
+
+ PaperLootableInventoryData getLootableData();
+ LootableInventory getAPILootableInventory();
+
+ Level getNMSWorld();
+
+ default org.bukkit.World getBukkitWorld() {
+ return getNMSWorld().getWorld();
+ }
+
+ @Override
+ default boolean isRefillEnabled() {
2022-06-09 10:51:45 +02:00
+ return getNMSWorld().paperConfig().lootables.autoReplenish;
2021-06-11 14:02:28 +02:00
+ }
+
+ @Override
+ default boolean hasBeenFilled() {
+ return getLastFilled() != -1;
+ }
+
+ @Override
+ default boolean hasPlayerLooted(UUID player) {
+ return getLootableData().hasPlayerLooted(player);
+ }
+
+ @Override
2023-08-12 23:26:47 +02:00
+ default boolean canPlayerLoot(final UUID player) {
+ return getLootableData().canPlayerLoot(player, this.getNMSWorld().paperConfig());
+ }
+
+ @Override
2021-06-11 14:02:28 +02:00
+ default Long getLastLooted(UUID player) {
+ return getLootableData().getLastLooted(player);
+ }
+
+ @Override
+ default boolean setHasPlayerLooted(UUID player, boolean looted) {
+ final boolean hasLooted = hasPlayerLooted(player);
+ if (hasLooted != looted) {
+ getLootableData().setPlayerLootedState(player, looted);
+ }
+ return hasLooted;
+ }
+
+ @Override
+ default boolean hasPendingRefill() {
+ long nextRefill = getLootableData().getNextRefill();
+ return nextRefill != -1 && nextRefill > getLootableData().getLastFill();
+ }
+
+ @Override
+ default long getLastFilled() {
+ return getLootableData().getLastFill();
+ }
+
+ @Override
+ default long getNextRefill() {
+ return getLootableData().getNextRefill();
+ }
+
+ @Override
+ default long setNextRefill(long refillAt) {
+ if (refillAt < -1) {
+ refillAt = -1;
+ }
+ return getLootableData().setNextRefill(refillAt);
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
new file mode 100644
2024-01-04 14:38:26 +01:00
index 0000000000000000000000000000000000000000..6e72c43b9d3834eb91c02ce68e7d114ad907812d
2021-06-11 14:02:28 +02:00
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperLootableInventoryData.java
2023-08-12 23:26:47 +02:00
@@ -0,0 +1,188 @@
2021-06-11 14:02:28 +02:00
+package com.destroystokyo.paper.loottable;
+
2022-06-09 10:51:45 +02:00
+import io.papermc.paper.configuration.WorldConfiguration;
2023-08-12 23:26:47 +02:00
+import io.papermc.paper.configuration.type.DurationOrDisabled;
+import java.time.temporal.ChronoUnit;
+import java.util.concurrent.TimeUnit;
2021-06-11 14:02:28 +02:00
+import org.bukkit.entity.Player;
+import org.bukkit.loot.LootTable;
+import javax.annotation.Nullable;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.ListTag;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
+
+public class PaperLootableInventoryData {
+
+ private static final Random RANDOM = new Random();
+
+ private long lastFill = -1;
+ private long nextRefill = -1;
+ private int numRefills = 0;
+ private Map<UUID, Long> lootedPlayers;
+ private final PaperLootableInventory lootable;
+
+ public PaperLootableInventoryData(PaperLootableInventory lootable) {
+ this.lootable = lootable;
+ }
+
+ long getLastFill() {
+ return this.lastFill;
+ }
+
+ long getNextRefill() {
+ return this.nextRefill;
+ }
+
+ long setNextRefill(long nextRefill) {
+ long prev = this.nextRefill;
+ this.nextRefill = nextRefill;
+ return prev;
+ }
+
+ public boolean shouldReplenish(@Nullable net.minecraft.world.entity.player.Player player) {
+ LootTable table = this.lootable.getLootTable();
+
+ // No Loot Table associated
+ if (table == null) {
+ return false;
+ }
+
+ // ALWAYS process the first fill or if the feature is disabled
2022-06-09 10:51:45 +02:00
+ if (this.lastFill == -1 || !this.lootable.getNMSWorld().paperConfig().lootables.autoReplenish) {
2021-06-11 14:02:28 +02:00
+ return true;
+ }
+
+ // Only process refills when a player is set
+ if (player == null) {
+ return false;
+ }
+
+ // Chest is not scheduled for refill
+ if (this.nextRefill == -1) {
+ return false;
+ }
+
2022-06-09 10:51:45 +02:00
+ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig();
2021-06-11 14:02:28 +02:00
+
+ // Check if max refills has been hit
2022-06-09 10:51:45 +02:00
+ if (paperConfig.lootables.maxRefills != -1 && this.numRefills >= paperConfig.lootables.maxRefills) {
2021-06-11 14:02:28 +02:00
+ return false;
+ }
+
+ // Refill has not been reached
+ if (this.nextRefill > System.currentTimeMillis()) {
+ return false;
+ }
+
+
+ final Player bukkitPlayer = (Player) player.getBukkitEntity();
+ LootableInventoryReplenishEvent event = new LootableInventoryReplenishEvent(bukkitPlayer, lootable.getAPILootableInventory());
2023-08-12 23:26:47 +02:00
+ event.setCancelled(!canPlayerLoot(player.getUUID(), paperConfig));
2021-06-11 14:02:28 +02:00
+ return event.callEvent();
+ }
+ public void processRefill(@Nullable net.minecraft.world.entity.player.Player player) {
+ this.lastFill = System.currentTimeMillis();
2022-06-09 10:51:45 +02:00
+ final WorldConfiguration paperConfig = this.lootable.getNMSWorld().paperConfig();
+ if (paperConfig.lootables.autoReplenish) {
+ long min = paperConfig.lootables.refreshMin.seconds();
+ long max = paperConfig.lootables.refreshMax.seconds();
+ this.nextRefill = this.lastFill + (min + RANDOM.nextLong(max - min + 1)) * 1000L;
2021-06-11 14:02:28 +02:00
+ this.numRefills++;
2022-06-09 10:51:45 +02:00
+ if (paperConfig.lootables.resetSeedOnFill) {
2021-06-11 14:02:28 +02:00
+ this.lootable.setSeed(0);
+ }
+ if (player != null) { // This means that numRefills can be incremented without a player being in the lootedPlayers list - Seems to be EntityMinecartChest specific
+ this.setPlayerLootedState(player.getUUID(), true);
+ }
+ } else {
+ this.lootable.clearLootTable();
+ }
+ }
+
+
+ public void loadNbt(CompoundTag base) {
+ if (!base.contains("Paper.LootableData", 10)) { // 10 = compound
+ return;
+ }
+ CompoundTag comp = base.getCompound("Paper.LootableData");
+ if (comp.contains("lastFill")) {
+ this.lastFill = comp.getLong("lastFill");
+ }
+ if (comp.contains("nextRefill")) {
+ this.nextRefill = comp.getLong("nextRefill");
+ }
+
+ if (comp.contains("numRefills")) {
+ this.numRefills = comp.getInt("numRefills");
+ }
2024-01-04 14:38:26 +01:00
+ if (comp.contains("lootedPlayers", net.minecraft.nbt.Tag.TAG_LIST)) {
+ ListTag list = comp.getList("lootedPlayers", net.minecraft.nbt.Tag.TAG_COMPOUND);
2021-06-11 14:02:28 +02:00
+ final int size = list.size();
+ if (size > 0) {
+ this.lootedPlayers = new HashMap<>(list.size());
+ }
+ for (int i = 0; i < size; i++) {
+ final CompoundTag cmp = list.getCompound(i);
+ lootedPlayers.put(cmp.getUUID("UUID"), cmp.getLong("Time"));
+ }
+ }
+ }
+ public void saveNbt(CompoundTag base) {
+ CompoundTag comp = new CompoundTag();
+ if (this.nextRefill != -1) {
+ comp.putLong("nextRefill", this.nextRefill);
+ }
+ if (this.lastFill != -1) {
+ comp.putLong("lastFill", this.lastFill);
+ }
+ if (this.numRefills != 0) {
+ comp.putInt("numRefills", this.numRefills);
+ }
+ if (this.lootedPlayers != null && !this.lootedPlayers.isEmpty()) {
+ ListTag list = new ListTag();
+ for (Map.Entry<UUID, Long> entry : this.lootedPlayers.entrySet()) {
+ CompoundTag cmp = new CompoundTag();
2021-06-17 23:39:36 +02:00
+ cmp.putUUID("UUID", entry.getKey());
2021-06-11 14:02:28 +02:00
+ cmp.putLong("Time", entry.getValue());
+ list.add(cmp);
+ }
+ comp.put("lootedPlayers", list);
+ }
+
+ if (!comp.isEmpty()) {
+ base.put("Paper.LootableData", comp);
+ }
+ }
+
+ void setPlayerLootedState(UUID player, boolean looted) {
+ if (looted && this.lootedPlayers == null) {
+ this.lootedPlayers = new HashMap<>();
+ }
+ if (looted) {
2023-08-12 23:26:47 +02:00
+ this.lootedPlayers.put(player, System.currentTimeMillis());
2021-06-11 14:02:28 +02:00
+ } else if (this.lootedPlayers != null) {
+ this.lootedPlayers.remove(player);
+ }
+ }
+
2023-08-12 23:26:47 +02:00
+ boolean canPlayerLoot(final UUID player, final WorldConfiguration worldConfiguration) {
+ final Long lastLooted = getLastLooted(player);
+ if (!worldConfiguration.lootables.restrictPlayerReloot || lastLooted == null) return true;
+
+ final DurationOrDisabled restrictPlayerRelootTime = worldConfiguration.lootables.restrictPlayerRelootTime;
2023-08-16 06:08:00 +02:00
+ if (restrictPlayerRelootTime.value().isEmpty()) return false;
2023-08-12 23:26:47 +02:00
+
+ return TimeUnit.SECONDS.toMillis(restrictPlayerRelootTime.value().get().seconds()) + lastLooted < System.currentTimeMillis();
+ }
+
2021-06-11 14:02:28 +02:00
+ boolean hasPlayerLooted(UUID player) {
+ return this.lootedPlayers != null && this.lootedPlayers.containsKey(player);
+ }
+
+ Long getLastLooted(UUID player) {
+ return lootedPlayers != null ? lootedPlayers.get(player) : null;
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
new file mode 100644
2022-10-24 21:43:46 +02:00
index 0000000000000000000000000000000000000000..9cfa5d36a6991067a3866e0d437749fafcc0158e
2021-06-11 14:02:28 +02:00
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/loottable/PaperTileEntityLootableInventory.java
2021-06-12 06:38:04 +02:00
@@ -0,0 +1,65 @@
2021-06-11 14:02:28 +02:00
+package com.destroystokyo.paper.loottable;
+
2022-10-24 21:43:46 +02:00
+import io.papermc.paper.util.MCUtil;
2021-06-11 14:02:28 +02:00
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+
+public class PaperTileEntityLootableInventory implements PaperLootableBlockInventory {
+ private RandomizableContainerBlockEntity tileEntityLootable;
+
+ public PaperTileEntityLootableInventory(RandomizableContainerBlockEntity tileEntityLootable) {
+ this.tileEntityLootable = tileEntityLootable;
+ }
+
+ @Override
+ public org.bukkit.loot.LootTable getLootTable() {
+ return tileEntityLootable.lootTable != null ? Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(tileEntityLootable.lootTable)) : null;
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table, long seed) {
+ setLootTable(table);
+ setSeed(seed);
+ }
+
+ @Override
+ public void setLootTable(org.bukkit.loot.LootTable table) {
+ tileEntityLootable.lootTable = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey());
+ }
+
+ @Override
+ public void setSeed(long seed) {
+ tileEntityLootable.lootTableSeed = seed;
+ }
+
+ @Override
+ public long getSeed() {
+ return tileEntityLootable.lootTableSeed;
+ }
+
+ @Override
+ public PaperLootableInventoryData getLootableData() {
+ return tileEntityLootable.lootableData;
+ }
+
+ @Override
+ public RandomizableContainerBlockEntity getTileEntity() {
+ return tileEntityLootable;
+ }
+
+ @Override
+ public LootableInventory getAPILootableInventory() {
+ Level world = tileEntityLootable.getLevel();
+ if (world == null) {
+ return null;
+ }
+ return (LootableInventory) getBukkitWorld().getBlockAt(MCUtil.toLocation(world, tileEntityLootable.getBlockPos())).getState();
+ }
+
+ @Override
+ public Level getNMSWorld() {
+ return tileEntityLootable.getLevel();
+ }
+}
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
2024-04-24 03:25:14 +02:00
index bc098b6a9c0e3b19b9154ab3727949232bddb20a..10687787a5fd1a81ad5a625848db4649381eab67 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
2024-04-24 03:25:14 +02:00
@@ -242,6 +242,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
2022-06-07 21:55:39 +02:00
}
2024-01-23 14:34:17 +01:00
// Paper end - Share random for entities to make them more random
2021-06-11 14:02:28 +02:00
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData; // Paper
private CraftEntity bukkitEntity;
public CraftEntity getBukkitEntity() {
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
2024-04-24 03:25:14 +02:00
index 67840327e934b631a85cf2d64911f5cfab4402b1..2704389bc3ec6dbbf1b568a4380972f8c0d62d15 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java
2024-04-24 03:25:14 +02:00
@@ -35,6 +35,20 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
public ResourceKey<LootTable> lootTable;
2021-06-11 14:02:28 +02:00
public long lootTableSeed;
2022-06-07 23:48:09 +02:00
+ // Paper start
+ {
+ this.lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperContainerEntityLootableInventory(this));
+ }
+ @Override
+ public Entity getEntity() {
+ return this;
+ }
+
+ @Override
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ return this.lootableData;
+ }
+ // Paper end
2021-06-11 14:02:28 +02:00
// CraftBukkit start
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
2024-04-24 03:25:14 +02:00
@@ -144,12 +158,14 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme
2021-06-11 14:02:28 +02:00
@Override
2021-06-12 06:38:04 +02:00
protected void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
2023-01-05 11:59:10 +01:00
+ this.lootableData.saveNbt(nbt); // Paper
2024-04-24 03:25:14 +02:00
this.addChestVehicleSaveData(nbt, this.registryAccess());
2022-06-07 21:55:39 +02:00
}
2021-06-11 14:02:28 +02:00
@Override
2021-06-12 06:38:04 +02:00
protected void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
+ this.lootableData.loadNbt(nbt); // Paper
2024-04-24 03:25:14 +02:00
this.readChestVehicleSaveData(nbt, this.registryAccess());
2022-06-07 21:55:39 +02:00
}
2021-06-11 14:02:28 +02:00
2022-06-07 21:55:39 +02:00
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
2024-04-24 03:25:14 +02:00
index 025e57993b85402c48db29d65ea3ceaf277ff27a..b04f7ce0805453f6c737fa9dc11c4129ca64e934 100644
2022-06-07 21:55:39 +02:00
--- a/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ChestBoat.java
2024-04-24 03:25:14 +02:00
@@ -70,12 +70,14 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
2022-06-07 21:55:39 +02:00
@Override
protected void addAdditionalSaveData(CompoundTag nbt) {
super.addAdditionalSaveData(nbt);
2023-01-05 11:59:10 +01:00
+ this.lootableData.saveNbt(nbt); // Paper
2024-04-24 03:25:14 +02:00
this.addChestVehicleSaveData(nbt, this.registryAccess());
2021-06-11 14:02:28 +02:00
}
2022-06-07 21:55:39 +02:00
@Override
protected void readAdditionalSaveData(CompoundTag nbt) {
super.readAdditionalSaveData(nbt);
+ this.lootableData.loadNbt(nbt); // Paper
2024-04-24 03:25:14 +02:00
this.readChestVehicleSaveData(nbt, this.registryAccess());
2022-06-07 21:55:39 +02:00
}
2021-06-11 14:02:28 +02:00
2024-04-24 03:25:14 +02:00
@@ -257,6 +259,20 @@ public class ChestBoat extends Boat implements HasCustomInventoryScreen, Contain
this.level().gameEvent((Holder) GameEvent.CONTAINER_CLOSE, this.position(), GameEvent.Context.of((Entity) player));
2022-06-07 23:48:09 +02:00
}
+ // Paper start
+ {
+ this.lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperContainerEntityLootableInventory(this));
+ }
+ @Override
+ public Entity getEntity() {
+ return this;
+ }
+
+ @Override
+ public com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ return this.lootableData;
+ }
+ // Paper end
// CraftBukkit start
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
private int maxStack = MAX_STACK;
2022-06-07 21:55:39 +02:00
diff --git a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
2024-04-24 03:25:14 +02:00
index dbde2402fd46b0d06e8efeb90be6fb98d7ae7798..f33e5cf6d456e615050047e924d9b24268a2c51e 100644
2022-06-07 21:55:39 +02:00
--- a/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
+++ b/src/main/java/net/minecraft/world/entity/vehicle/ContainerEntity.java
2024-04-24 03:25:14 +02:00
@@ -65,9 +65,8 @@ public interface ContainerEntity extends Container, MenuProvider {
2022-06-07 21:55:39 +02:00
if (this.getLootTableSeed() != 0L) {
nbt.putLong("LootTableSeed", this.getLootTableSeed());
2021-06-11 14:02:28 +02:00
}
2022-06-07 21:55:39 +02:00
- } else {
2024-04-24 03:25:14 +02:00
- ContainerHelper.saveAllItems(nbt, this.getItemStacks(), registriesLookup);
2022-06-07 21:55:39 +02:00
}
2024-04-24 03:25:14 +02:00
+ ContainerHelper.saveAllItems(nbt, this.getItemStacks(), registriesLookup); // Paper - always save the items, table may still remain
2023-06-28 20:06:47 +02:00
}
2024-04-24 03:25:14 +02:00
default void readChestVehicleSaveData(CompoundTag nbt, HolderLookup.Provider registriesLookup) {
@@ -75,9 +74,8 @@ public interface ContainerEntity extends Container, MenuProvider {
2022-06-07 21:55:39 +02:00
if (nbt.contains("LootTable", 8)) {
2024-04-24 03:25:14 +02:00
this.setLootTable(ResourceKey.create(Registries.LOOT_TABLE, new ResourceLocation(nbt.getString("LootTable"))));
2022-06-07 21:55:39 +02:00
this.setLootTableSeed(nbt.getLong("LootTableSeed"));
- } else {
2024-04-24 03:25:14 +02:00
- ContainerHelper.loadAllItems(nbt, this.getItemStacks(), registriesLookup);
2022-06-07 21:55:39 +02:00
}
2024-04-24 03:25:14 +02:00
+ ContainerHelper.loadAllItems(nbt, this.getItemStacks(), registriesLookup); // Paper - always save the items, table may still remain
2023-06-28 20:06:47 +02:00
}
default void chestVehicleDestroyed(DamageSource source, Level world, Entity vehicle) {
2024-04-24 03:25:14 +02:00
@@ -99,13 +97,13 @@ public interface ContainerEntity extends Container, MenuProvider {
2022-11-25 00:21:40 +01:00
default void unpackChestVehicleLootTable(@Nullable Player player) {
2023-06-07 21:19:26 +02:00
MinecraftServer minecraftServer = this.level().getServer();
2022-11-25 00:21:40 +01:00
- if (this.getLootTable() != null && minecraftServer != null) {
+ if (this.getLootableData().shouldReplenish(player) && minecraftServer != null) { // Paper
2024-04-24 03:25:14 +02:00
LootTable lootTable = minecraftServer.reloadableRegistries().getLootTable(this.getLootTable());
2022-11-25 00:21:40 +01:00
if (player != null) {
CriteriaTriggers.GENERATE_LOOT.trigger((ServerPlayer)player, this.getLootTable());
}
2024-04-12 21:14:06 +02:00
- this.setLootTable(null);
2022-11-25 00:21:40 +01:00
+ this.getLootableData().processRefill(player); // Paper
2024-04-12 21:14:06 +02:00
LootParams.Builder builder = new LootParams.Builder((ServerLevel)this.level()).withParameter(LootContextParams.ORIGIN, this.position());
2022-11-25 00:21:40 +01:00
if (player != null) {
builder.withLuck(player.getLuck()).withParameter(LootContextParams.THIS_ENTITY, player);
2024-04-24 03:25:14 +02:00
@@ -175,4 +173,13 @@ public interface ContainerEntity extends Container, MenuProvider {
2022-06-07 23:48:09 +02:00
default boolean isChestVehicleStillValid(Player player) {
2024-04-24 03:25:14 +02:00
return !this.isRemoved() && player.canInteractWithEntity(this.getBoundingBox(), 4.0);
2022-06-07 23:48:09 +02:00
}
+ // Paper start
+ default Entity getEntity() {
+ throw new UnsupportedOperationException();
+ }
+
+ default com.destroystokyo.paper.loottable.PaperLootableInventoryData getLootableData() {
+ throw new UnsupportedOperationException();
+ }
+ // Paper end
}
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
2024-04-25 07:16:04 +02:00
index c2493c15d8fe4587d6ee2db100cc13303b66b39b..6a6473ebf03e5b1e502db7e66203783b9980d072 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
2024-04-24 03:25:14 +02:00
@@ -19,6 +19,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
2021-06-11 14:02:28 +02:00
@Nullable
2024-04-24 03:25:14 +02:00
public ResourceKey<LootTable> lootTable;
public long lootTableSeed = 0L;
2021-06-11 14:02:28 +02:00
+ public final com.destroystokyo.paper.loottable.PaperLootableInventoryData lootableData = new com.destroystokyo.paper.loottable.PaperLootableInventoryData(new com.destroystokyo.paper.loottable.PaperTileEntityLootableInventory(this)); // Paper
2021-06-12 06:38:04 +02:00
protected RandomizableContainerBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
2024-04-25 07:16:04 +02:00
@@ -45,6 +46,57 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
2023-12-06 22:17:56 +01:00
this.lootTableSeed = lootTableSeed;
}
+ // Paper start
+ @Override
2023-12-06 22:22:22 +01:00
+ public boolean tryLoadLootTable(final net.minecraft.nbt.CompoundTag nbt) {
2023-12-06 22:17:56 +01:00
+ // Copied from super with changes, always check the original method
+ this.lootableData.loadNbt(nbt); // Paper
+ if (nbt.contains("LootTable", 8)) {
2024-04-25 07:16:04 +02:00
+ final var loc = new net.minecraft.resources.ResourceLocation(nbt.getString("LootTable"));
+ this.setLootTable(ResourceKey.create(net.minecraft.core.registries.Registries.LOOT_TABLE, loc));
+ try { org.bukkit.craftbukkit.util.CraftNamespacedKey.fromMinecraft(this.lootTable.location()); } catch (IllegalArgumentException ex) { this.lootTable = null; } // Paper - validate
+ if (nbt.contains("LootTableSeed", 4)) {
+ this.setLootTableSeed(nbt.getLong("LootTableSeed"));
+ } else {
+ this.setLootTableSeed(0L);
+ }
2023-12-06 22:17:56 +01:00
+ return false; // Paper - always load the items, table may still remain
+ } else {
+ return false;
+ }
+ }
+
+ @Override
2023-12-06 22:22:22 +01:00
+ public boolean trySaveLootTable(final net.minecraft.nbt.CompoundTag nbt) {
2023-12-06 22:17:56 +01:00
+ this.lootableData.saveNbt(nbt);
+ RandomizableContainer.super.trySaveLootTable(nbt);
+ return false;
+ }
+
+ @Override
+ public void unpackLootTable(@org.jetbrains.annotations.Nullable final Player player) {
+ // Copied from super with changes, always check the original method
2023-12-06 22:22:22 +01:00
+ net.minecraft.world.level.Level level = this.getLevel();
2023-12-06 22:17:56 +01:00
+ BlockPos blockPos = this.getBlockPos();
2024-04-25 07:16:04 +02:00
+ ResourceKey<LootTable> resourceKey = this.getLootTable();
+ if (this.lootableData.shouldReplenish(player) && resourceKey != null && level != null && level.getServer() != null) { // Paper
+ net.minecraft.world.level.storage.loot.LootTable lootTable = level.getServer().reloadableRegistries().getLootTable(resourceKey);
2023-12-06 22:22:22 +01:00
+ if (player instanceof net.minecraft.server.level.ServerPlayer) {
2024-04-25 07:16:04 +02:00
+ net.minecraft.advancements.CriteriaTriggers.GENERATE_LOOT.trigger((net.minecraft.server.level.ServerPlayer)player, resourceKey);
2023-12-06 22:17:56 +01:00
+ }
+
+ this.lootableData.processRefill(player); // Paper
2023-12-06 22:22:22 +01:00
+ net.minecraft.world.level.storage.loot.LootParams.Builder builder = (new net.minecraft.world.level.storage.loot.LootParams.Builder((net.minecraft.server.level.ServerLevel)level)).withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.ORIGIN, net.minecraft.world.phys.Vec3.atCenterOf(blockPos));
2023-12-06 22:17:56 +01:00
+ if (player != null) {
2023-12-06 22:22:22 +01:00
+ builder.withLuck(player.getLuck()).withParameter(net.minecraft.world.level.storage.loot.parameters.LootContextParams.THIS_ENTITY, player);
2023-12-06 22:17:56 +01:00
+ }
+
2023-12-06 22:22:22 +01:00
+ lootTable.fill(this, builder.create(net.minecraft.world.level.storage.loot.parameters.LootContextParamSets.CHEST), this.getLootTableSeed());
2023-12-06 22:17:56 +01:00
+ }
+
+ }
+ // Paper end
+
@Override
public boolean isEmpty() {
2024-04-12 21:14:06 +02:00
this.unpackLootTable(null);
2023-06-07 21:19:26 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
2024-04-24 03:25:14 +02:00
index 949e074a32b6593bd8b7405499e686a074e283e5..398ffe274bddee2b01350b9490def3d2fe854917 100644
2023-06-07 21:19:26 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBrushableBlock.java
2024-04-24 03:25:14 +02:00
@@ -58,7 +58,7 @@ public class CraftBrushableBlock extends CraftBlockEntityState<BrushableBlockEnt
2023-06-07 21:19:26 +02:00
this.setLootTable(this.getLootTable(), seed);
}
- private void setLootTable(LootTable table, long seed) {
+ public void setLootTable(LootTable table, long seed) { // Paper - make public since it overrides a public method
2024-04-24 03:25:14 +02:00
this.getSnapshot().setLootTable(CraftLootTable.bukkitToMinecraft(table), seed);
2023-06-07 21:19:26 +02:00
}
2024-04-24 03:25:14 +02:00
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
2024-04-24 03:25:14 +02:00
index 2b6a93a944b27290745278957a3577772b7b8212..29df470d6706a33dad4317a9aa599456d5c7f6ee 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
2024-04-24 03:25:14 +02:00
@@ -13,8 +13,9 @@ import org.bukkit.craftbukkit.CraftWorld;
2021-06-11 14:02:28 +02:00
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest;
import org.bukkit.inventory.Inventory;
+import com.destroystokyo.paper.loottable.PaperLootableBlockInventory; // Paper
-public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest {
+public class CraftChest extends CraftLootable<ChestBlockEntity> implements Chest, PaperLootableBlockInventory { // Paper
2021-10-02 19:21:49 +02:00
public CraftChest(World world, ChestBlockEntity tileEntity) {
super(world, tileEntity);
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
2024-04-24 03:25:14 +02:00
index 74315a46f6101775321b1cf4944c124c69aed182..c3215f15b3088199dcf96f62b58d0ec7c2b4125c 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java
2024-04-24 03:25:14 +02:00
@@ -8,7 +8,7 @@ import org.bukkit.craftbukkit.CraftLootTable;
2021-06-11 14:02:28 +02:00
import org.bukkit.loot.LootTable;
import org.bukkit.loot.Lootable;
-public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable {
+public abstract class CraftLootable<T extends RandomizableContainerBlockEntity> extends CraftContainer<T> implements Nameable, Lootable, com.destroystokyo.paper.loottable.PaperLootableBlockInventory { // Paper
2021-10-02 19:21:49 +02:00
public CraftLootable(World world, T tileEntity) {
super(world, tileEntity);
2022-06-07 23:48:09 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
2024-04-24 03:25:14 +02:00
index cfde210ea9d4b62fe514d3ab0dbab2f43eda0c7a..c0f6939ed782dd3151ebd7ee9d3d7e292154e76c 100644
2022-06-07 23:48:09 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftChestBoat.java
2024-04-24 03:25:14 +02:00
@@ -7,8 +7,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory;
2022-06-07 23:48:09 +02:00
import org.bukkit.inventory.Inventory;
import org.bukkit.loot.LootTable;
-public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat {
-
+public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.ChestBoat, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final Inventory inventory;
public CraftChestBoat(CraftServer server, ChestBoat entity) {
2024-04-24 03:25:14 +02:00
@@ -51,7 +50,7 @@ public class CraftChestBoat extends CraftBoat implements org.bukkit.entity.Chest
2022-06-08 05:12:24 +02:00
return this.getHandle().getLootTableSeed();
}
- private void setLootTable(LootTable table, long seed) {
+ public void setLootTable(LootTable table, long seed) { // Paper - change visibility since it overrides a public method
2024-04-24 03:25:14 +02:00
this.getHandle().setLootTable(CraftLootTable.bukkitToMinecraft(table));
2022-06-08 05:12:24 +02:00
this.getHandle().setLootTableSeed(seed);
2024-04-24 03:25:14 +02:00
}
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
2023-08-14 01:32:51 +02:00
index fd42f0b20132d08039ca7735d31a61806a6b07dc..b1a708de6790bbe336202b13ab862ced78de084f 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
2023-08-14 01:32:51 +02:00
@@ -7,7 +7,7 @@ import org.bukkit.entity.minecart.StorageMinecart;
2021-06-11 14:02:28 +02:00
import org.bukkit.inventory.Inventory;
@SuppressWarnings("deprecation")
-public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart {
+public class CraftMinecartChest extends CraftMinecartContainer implements StorageMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final CraftInventory inventory;
public CraftMinecartChest(CraftServer server, MinecartChest entity) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
2023-10-27 01:34:58 +02:00
index 39427b4f284e9402663be2b160ccb5f03f8b91da..17f5684cba9d3ed22d9925d1951520cc4751dfe2 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
2023-08-14 01:32:51 +02:00
@@ -6,7 +6,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory;
2021-06-11 14:02:28 +02:00
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.inventory.Inventory;
-public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart {
+public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart, com.destroystokyo.paper.loottable.PaperLootableEntityInventory { // Paper
private final CraftInventory inventory;
public CraftMinecartHopper(CraftServer server, MinecartHopper entity) {