094bb03a37
- Lots of itemstack cloning removed. Only clone if the item is actually moved - Return true when a plugin cancels inventory move item event instead of false, as false causes pulls to cycle through all items. However, pushes do not exhibit the same behavior, so this is not something plugins could of been relying on. - Add option (Default on) to cooldown hoppers when they fail to move an item due to full inventory - Skip subsequent InventoryMoveItemEvents if a plugin does not use the item after first event fire for an iteration
795 lines
30 KiB
Diff
795 lines
30 KiB
Diff
From 5819a09940af69a152ca201f2d8ad27a19508928 Mon Sep 17 00:00:00 2001
|
|
From: Aikar <aikar@aikar.co>
|
|
Date: Sun, 1 May 2016 21:19:14 -0400
|
|
Subject: [PATCH] LootTable API & Replenishable Lootables Feature
|
|
|
|
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"
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
index d96311f6b..067cb233e 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -303,4 +303,26 @@ public class PaperWorldConfig {
|
|
this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax);
|
|
log("Frosted Ice: " + (this.frostedIceEnabled ? "enabled" : "disabled") + " / delay: min=" + this.frostedIceDelayMin + ", max=" + this.frostedIceDelayMax);
|
|
}
|
|
+
|
|
+ public boolean autoReplenishLootables;
|
|
+ public boolean restrictPlayerReloot;
|
|
+ public boolean changeLootTableSeedOnFill;
|
|
+ public int maxLootableRefills;
|
|
+ public int lootableRegenMin;
|
|
+ public int lootableRegenMax;
|
|
+ private void enhancedLootables() {
|
|
+ autoReplenishLootables = getBoolean("lootables.auto-replenish", false);
|
|
+ restrictPlayerReloot = getBoolean("lootables.restrict-player-reloot", true);
|
|
+ changeLootTableSeedOnFill = getBoolean("lootables.reset-seed-on-fill", true);
|
|
+ maxLootableRefills = getInt("lootables.max-refills", -1);
|
|
+ lootableRegenMin = PaperConfig.getSeconds(getString("lootables.refresh-min", "12h"));
|
|
+ lootableRegenMax = PaperConfig.getSeconds(getString("lootables.refresh-max", "2d"));
|
|
+ if (autoReplenishLootables) {
|
|
+ log("Lootables: Replenishing every " +
|
|
+ PaperConfig.timeSummary(lootableRegenMin) + " to " +
|
|
+ PaperConfig.timeSummary(lootableRegenMax) +
|
|
+ (restrictPlayerReloot ? " (restricting reloot)" : "")
|
|
+ );
|
|
+ }
|
|
+ }
|
|
}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootable.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootable.java
|
|
new file mode 100644
|
|
index 000000000..36c36d158
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootable.java
|
|
@@ -0,0 +1,12 @@
|
|
+package com.destroystokyo.paper.loottable;
|
|
+
|
|
+import net.minecraft.server.World;
|
|
+
|
|
+interface CraftLootable extends Lootable {
|
|
+
|
|
+ World getNMSWorld();
|
|
+
|
|
+ default org.bukkit.World getBukkitWorld() {
|
|
+ return getNMSWorld().getWorld();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableBlockInventory.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableBlockInventory.java
|
|
new file mode 100644
|
|
index 000000000..20d236c45
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableBlockInventory.java
|
|
@@ -0,0 +1,33 @@
|
|
+package com.destroystokyo.paper.loottable;
|
|
+
|
|
+import net.minecraft.server.BlockPosition;
|
|
+import net.minecraft.server.TileEntityLootable;
|
|
+import net.minecraft.server.World;
|
|
+import org.bukkit.Chunk;
|
|
+import org.bukkit.block.Block;
|
|
+
|
|
+public interface CraftLootableBlockInventory extends LootableBlockInventory, CraftLootableInventory {
|
|
+
|
|
+ TileEntityLootable getTileEntity();
|
|
+
|
|
+ @Override
|
|
+ default LootableInventory getAPILootableInventory() {
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default World getNMSWorld() {
|
|
+ return getTileEntity().getWorld();
|
|
+ }
|
|
+
|
|
+ default Block getBlock() {
|
|
+ final BlockPosition position = getTileEntity().getPosition();
|
|
+ final Chunk bukkitChunk = getTileEntity().getWorld().getChunkAtWorldCoords(position).bukkitChunk;
|
|
+ return bukkitChunk.getBlock(position.getX(), position.getY(), position.getZ());
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default CraftLootableInventoryData getLootableData() {
|
|
+ return getTileEntity().getLootableData();
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableEntityInventory.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableEntityInventory.java
|
|
new file mode 100644
|
|
index 000000000..1150dee01
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableEntityInventory.java
|
|
@@ -0,0 +1,31 @@
|
|
+package com.destroystokyo.paper.loottable;
|
|
+
|
|
+import net.minecraft.server.World;
|
|
+import org.bukkit.entity.Entity;
|
|
+
|
|
+public interface CraftLootableEntityInventory extends LootableEntityInventory, CraftLootableInventory {
|
|
+
|
|
+ net.minecraft.server.Entity getHandle();
|
|
+
|
|
+ @Override
|
|
+ default LootableInventory getAPILootableInventory() {
|
|
+ return this;
|
|
+ }
|
|
+
|
|
+ default Entity getEntity() {
|
|
+ return getHandle().getBukkitEntity();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default World getNMSWorld() {
|
|
+ return getHandle().getWorld();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default CraftLootableInventoryData getLootableData() {
|
|
+ if (getHandle() instanceof CraftLootableInventory) {
|
|
+ return ((CraftLootableInventory) getHandle()).getLootableData();
|
|
+ }
|
|
+ return null;
|
|
+ }
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventory.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventory.java
|
|
new file mode 100644
|
|
index 000000000..668097620
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventory.java
|
|
@@ -0,0 +1,88 @@
|
|
+package com.destroystokyo.paper.loottable;
|
|
+
|
|
+import org.apache.commons.lang.Validate;
|
|
+
|
|
+import java.util.UUID;
|
|
+
|
|
+public interface CraftLootableInventory extends CraftLootable, LootableInventory {
|
|
+
|
|
+ CraftLootableInventoryData getLootableData();
|
|
+ LootableInventory getAPILootableInventory();
|
|
+
|
|
+ @Override
|
|
+ default boolean isRefillEnabled() {
|
|
+ return getNMSWorld().paperConfig.autoReplenishLootables;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default boolean hasBeenFilled() {
|
|
+ return getLastFilled() != -1;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default String getLootTableName() {
|
|
+ return getLootableData().getLootable().getLootTableName();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default String setLootTable(String name, long seed) {
|
|
+ Validate.notNull(name);
|
|
+
|
|
+ String prevLootTable = getLootTableName();
|
|
+ getLootableData().getLootable().setLootTable(name, seed);
|
|
+ return prevLootTable;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default long getLootTableSeed() {
|
|
+ return getLootableData().getLootable().getLootTableSeed();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default void clearLootTable() {
|
|
+ getLootableData().getLootable().clearLootTable();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ default boolean hasPlayerLooted(UUID player) {
|
|
+ return getLootableData().hasPlayerLooted(player);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ 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/CraftLootableInventoryData.java b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventoryData.java
|
|
new file mode 100644
|
|
index 000000000..01c2713d3
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/loottable/CraftLootableInventoryData.java
|
|
@@ -0,0 +1,182 @@
|
|
+package com.destroystokyo.paper.loottable;
|
|
+
|
|
+import com.destroystokyo.paper.PaperWorldConfig;
|
|
+import net.minecraft.server.*;
|
|
+import org.bukkit.entity.Player;
|
|
+
|
|
+import javax.annotation.Nullable;
|
|
+import java.util.HashMap;
|
|
+import java.util.Map;
|
|
+import java.util.Random;
|
|
+import java.util.UUID;
|
|
+
|
|
+public class CraftLootableInventoryData {
|
|
+
|
|
+ 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 CraftLootableInventory lootable;
|
|
+
|
|
+ public CraftLootableInventoryData(CraftLootableInventory 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;
|
|
+ }
|
|
+
|
|
+ CraftLootableInventory getLootable() {
|
|
+ return lootable;
|
|
+ }
|
|
+
|
|
+ public boolean shouldReplenish(@Nullable EntityHuman player) {
|
|
+ String tableName = this.lootable.getLootTableName();
|
|
+
|
|
+ // No Loot Table associated
|
|
+ if (tableName == null) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ // ALWAYS process the first fill
|
|
+ if (this.lastFill == -1) {
|
|
+ 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;
|
|
+ }
|
|
+
|
|
+ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig;
|
|
+
|
|
+ // Check if max refills has been hit
|
|
+ if (paperConfig.maxLootableRefills != -1 && this.numRefills >= paperConfig.maxLootableRefills) {
|
|
+ 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());
|
|
+ if (paperConfig.restrictPlayerReloot && hasPlayerLooted(player.getUniqueID())) {
|
|
+ event.setCancelled(true);
|
|
+ }
|
|
+ return event.callEvent();
|
|
+ }
|
|
+ public void processRefill(@Nullable EntityHuman player) {
|
|
+ this.lastFill = System.currentTimeMillis();
|
|
+ final PaperWorldConfig paperConfig = this.lootable.getNMSWorld().paperConfig;
|
|
+ if (paperConfig.autoReplenishLootables) {
|
|
+ int min = paperConfig.lootableRegenMin * 1000;
|
|
+ int max = paperConfig.lootableRegenMax * 1000;
|
|
+ this.nextRefill = this.lastFill + min + RANDOM.nextInt(max - min + 1);
|
|
+ this.numRefills++;
|
|
+ if (paperConfig.changeLootTableSeedOnFill) {
|
|
+ this.lootable.setLootTableSeed(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.getUniqueID(), true);
|
|
+ }
|
|
+ } else {
|
|
+ this.lootable.clearLootTable();
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
+ public void loadNbt(NBTTagCompound base) {
|
|
+ if (!base.hasKeyOfType("Paper.LootableData", 10)) { // 10 = compound
|
|
+ return;
|
|
+ }
|
|
+ NBTTagCompound comp = base.getCompound("Paper.LootableData");
|
|
+ if (comp.hasKey("lastFill")) {
|
|
+ this.lastFill = comp.getLong("lastFill");
|
|
+ }
|
|
+ if (comp.hasKey("nextRefill")) {
|
|
+ this.nextRefill = comp.getLong("nextRefill");
|
|
+ }
|
|
+
|
|
+ if (comp.hasKey("numRefills")) {
|
|
+ this.numRefills = comp.getInt("numRefills");
|
|
+ }
|
|
+ if (comp.hasKeyOfType("lootedPlayers", 9)) { // 9 = list
|
|
+ NBTTagList list = comp.getList("lootedPlayers", 10); // 10 = compound
|
|
+ final int size = list.size();
|
|
+ if (size > 0) {
|
|
+ this.lootedPlayers = new HashMap<>(list.size());
|
|
+ }
|
|
+ for (int i = 0; i < size; i++) {
|
|
+ final NBTTagCompound cmp = list.get(i);
|
|
+ lootedPlayers.put(cmp.getUUID("UUID"), cmp.getLong("Time"));
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ public void saveNbt(NBTTagCompound base) {
|
|
+ NBTTagCompound comp = new NBTTagCompound();
|
|
+ if (this.nextRefill != -1) {
|
|
+ comp.setLong("nextRefill", this.nextRefill);
|
|
+ }
|
|
+ if (this.lastFill != -1) {
|
|
+ comp.setLong("lastFill", this.lastFill);
|
|
+ }
|
|
+ if (this.numRefills != 0) {
|
|
+ comp.setInt("numRefills", this.numRefills);
|
|
+ }
|
|
+ if (this.lootedPlayers != null && !this.lootedPlayers.isEmpty()) {
|
|
+ NBTTagList list = new NBTTagList();
|
|
+ for (Map.Entry<UUID, Long> entry : this.lootedPlayers.entrySet()) {
|
|
+ NBTTagCompound cmp = new NBTTagCompound();
|
|
+ cmp.setUUID("UUID", entry.getKey());
|
|
+ cmp.setLong("Time", entry.getValue());
|
|
+ list.add(cmp);
|
|
+ }
|
|
+ comp.set("lootedPlayers", list);
|
|
+ }
|
|
+
|
|
+ if (!comp.isEmpty()) {
|
|
+ base.set("Paper.LootableData", comp);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ void setPlayerLootedState(UUID player, boolean looted) {
|
|
+ if (looted && this.lootedPlayers == null) {
|
|
+ this.lootedPlayers = new HashMap<>();
|
|
+ }
|
|
+ if (looted) {
|
|
+ if (!this.lootedPlayers.containsKey(player)) {
|
|
+ this.lootedPlayers.put(player, System.currentTimeMillis());
|
|
+ }
|
|
+ } else if (this.lootedPlayers != null) {
|
|
+ this.lootedPlayers.remove(player);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ 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/net/minecraft/server/EntityMinecartContainer.java b/src/main/java/net/minecraft/server/EntityMinecartContainer.java
|
|
index d6afa4aa6..50d7d34b8 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityMinecartContainer.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityMinecartContainer.java
|
|
@@ -6,17 +6,21 @@ import javax.annotation.Nullable;
|
|
// CraftBukkit start
|
|
import java.util.List;
|
|
import org.bukkit.Location;
|
|
+
|
|
+import com.destroystokyo.paper.loottable.CraftLootableInventoryData; // Paper
|
|
+import com.destroystokyo.paper.loottable.CraftLootableInventory; // Paper
|
|
+import com.destroystokyo.paper.loottable.LootableInventory; // Paper
|
|
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
|
import org.bukkit.entity.HumanEntity;
|
|
import org.bukkit.inventory.InventoryHolder;
|
|
// CraftBukkit end
|
|
|
|
-public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory, ILootable {
|
|
+public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory, ILootable, CraftLootableInventory { // Paper
|
|
|
|
private NonNullList<ItemStack> items;
|
|
private boolean b;
|
|
private MinecraftKey c;
|
|
- private long d;
|
|
+ private long d;public long getLootTableSeed() { return d; } // Paper - OBFHELPER
|
|
|
|
// CraftBukkit start
|
|
public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
|
|
@@ -164,12 +168,13 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp
|
|
|
|
protected void b(NBTTagCompound nbttagcompound) {
|
|
super.b(nbttagcompound);
|
|
+ lootableData.saveNbt(nbttagcompound); // Paper
|
|
if (this.c != null) {
|
|
nbttagcompound.setString("LootTable", this.c.toString());
|
|
if (this.d != 0L) {
|
|
nbttagcompound.setLong("LootTableSeed", this.d);
|
|
}
|
|
- } else {
|
|
+ } if (true) { // Paper - Always save the items, Table may stick around
|
|
ContainerUtil.a(nbttagcompound, this.items);
|
|
}
|
|
|
|
@@ -177,11 +182,12 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp
|
|
|
|
protected void a(NBTTagCompound nbttagcompound) {
|
|
super.a(nbttagcompound);
|
|
+ lootableData.loadNbt(nbttagcompound); // Paper
|
|
this.items = NonNullList.a(this.getSize(), ItemStack.a);
|
|
if (nbttagcompound.hasKeyOfType("LootTable", 8)) {
|
|
this.c = new MinecraftKey(nbttagcompound.getString("LootTable"));
|
|
this.d = nbttagcompound.getLong("LootTableSeed");
|
|
- } else {
|
|
+ } if (true) { // Paper - always load the items, table may still remain
|
|
ContainerUtil.b(nbttagcompound, this.items);
|
|
}
|
|
|
|
@@ -230,10 +236,10 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp
|
|
}
|
|
|
|
public void f(@Nullable EntityHuman entityhuman) {
|
|
- if (this.c != null) {
|
|
+ if (lootableData.shouldReplenish(entityhuman)) { // Paper
|
|
LootTable loottable = this.world.getLootTableRegistry().a(this.c);
|
|
|
|
- this.c = null;
|
|
+ lootableData.processRefill(entityhuman); // Paper
|
|
Random random;
|
|
|
|
if (this.d == 0L) {
|
|
@@ -258,12 +264,52 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp
|
|
this.items.clear();
|
|
}
|
|
|
|
+ public void setLootTable(MinecraftKey key, long seed) { a(key, seed);} // Paper - OBFHELPER
|
|
public void a(MinecraftKey minecraftkey, long i) {
|
|
this.c = minecraftkey;
|
|
this.d = i;
|
|
}
|
|
|
|
+
|
|
+ public MinecraftKey getLootTableKey() { return b(); } // Paper - OBFHELPER
|
|
public MinecraftKey b() {
|
|
return this.c;
|
|
}
|
|
+
|
|
+ // Paper start
|
|
+ private final CraftLootableInventoryData lootableData = new CraftLootableInventoryData(this);
|
|
+
|
|
+ @Override
|
|
+ public CraftLootableInventoryData getLootableData() {
|
|
+ return lootableData;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LootableInventory getAPILootableInventory() {
|
|
+ return (LootableInventory) this.getBukkitEntity();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public World getNMSWorld() {
|
|
+ return this.world;
|
|
+ }
|
|
+
|
|
+ public String getLootTableName() {
|
|
+ final MinecraftKey key = getLootTableKey();
|
|
+ return key != null ? key.toString() : null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public String setLootTable(String name, long seed) {
|
|
+ String prev = getLootTableName();
|
|
+ setLootTable(new MinecraftKey(name), seed);
|
|
+ return prev;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clearLootTable() {
|
|
+ //noinspection RedundantCast
|
|
+ this.c = (MinecraftKey) null;
|
|
+ }
|
|
+ // Paper end
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/TileEntityLootable.java b/src/main/java/net/minecraft/server/TileEntityLootable.java
|
|
index a97ad2037..618521304 100644
|
|
--- a/src/main/java/net/minecraft/server/TileEntityLootable.java
|
|
+++ b/src/main/java/net/minecraft/server/TileEntityLootable.java
|
|
@@ -1,44 +1,50 @@
|
|
package net.minecraft.server;
|
|
|
|
+import com.destroystokyo.paper.loottable.CraftLootableInventoryData; // Paper
|
|
+import com.destroystokyo.paper.loottable.CraftLootableInventory; // Paper
|
|
+import com.destroystokyo.paper.loottable.LootableInventory; // Paper
|
|
+
|
|
import java.util.Random;
|
|
import javax.annotation.Nullable;
|
|
|
|
-public abstract class TileEntityLootable extends TileEntityContainer implements ILootable {
|
|
+public abstract class TileEntityLootable extends TileEntityContainer implements ILootable, CraftLootableInventory { // Paper
|
|
|
|
protected MinecraftKey m;
|
|
- protected long n;
|
|
+ protected long n; public long getLootTableSeed() { return n; } // Paper - OBFHELPER
|
|
protected String o;
|
|
|
|
public TileEntityLootable() {}
|
|
|
|
protected boolean c(NBTTagCompound nbttagcompound) {
|
|
+ lootableData.loadNbt(nbttagcompound); // Paper
|
|
if (nbttagcompound.hasKeyOfType("LootTable", 8)) {
|
|
this.m = new MinecraftKey(nbttagcompound.getString("LootTable"));
|
|
this.n = nbttagcompound.getLong("LootTableSeed");
|
|
- return true;
|
|
+ return false; // Paper - always load the items, table may still remain
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
protected boolean d(NBTTagCompound nbttagcompound) {
|
|
+ lootableData.saveNbt(nbttagcompound); // Paper
|
|
if (this.m != null) {
|
|
nbttagcompound.setString("LootTable", this.m.toString());
|
|
if (this.n != 0L) {
|
|
nbttagcompound.setLong("LootTableSeed", this.n);
|
|
}
|
|
|
|
- return true;
|
|
+ return false; // Paper - always save the items, table may still remain
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public void d(@Nullable EntityHuman entityhuman) {
|
|
- if (this.m != null) {
|
|
+ if (lootableData.shouldReplenish(entityhuman)) { // Paper
|
|
LootTable loottable = this.world.getLootTableRegistry().a(this.m);
|
|
|
|
- this.m = null;
|
|
+ lootableData.processRefill(entityhuman); // Paper
|
|
Random random;
|
|
|
|
if (this.n == 0L) {
|
|
@@ -58,10 +64,12 @@ public abstract class TileEntityLootable extends TileEntityContainer implements
|
|
|
|
}
|
|
|
|
+ public MinecraftKey getLootTableKey() { return b(); } // Paper - OBFHELPER
|
|
public MinecraftKey b() {
|
|
return this.m;
|
|
}
|
|
|
|
+ public void setLootTable(MinecraftKey key, long seed) { a(key, seed);} // Paper - OBFHELPER
|
|
public void a(MinecraftKey minecraftkey, long i) {
|
|
this.m = minecraftkey;
|
|
this.n = i;
|
|
@@ -134,4 +142,42 @@ public abstract class TileEntityLootable extends TileEntityContainer implements
|
|
}
|
|
|
|
protected abstract NonNullList<ItemStack> q();
|
|
+
|
|
+ // Paper start - LootTable API
|
|
+ private final CraftLootableInventoryData lootableData = new CraftLootableInventoryData(this);
|
|
+
|
|
+ @Override
|
|
+ public CraftLootableInventoryData getLootableData() {
|
|
+ return lootableData;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public LootableInventory getAPILootableInventory() {
|
|
+ return (LootableInventory) getBukkitWorld().getBlockAt(MCUtil.toLocation(world, getPosition())).getState();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public World getNMSWorld() {
|
|
+ return world;
|
|
+ }
|
|
+
|
|
+ public String getLootTableName() {
|
|
+ final MinecraftKey key = getLootTableKey();
|
|
+ return key != null ? key.toString() : null;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public String setLootTable(String name, long seed) {
|
|
+ String prev = getLootTableName();
|
|
+ setLootTable(new MinecraftKey(name), seed);
|
|
+ return prev;
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void clearLootTable() {
|
|
+ //noinspection RedundantCast
|
|
+ this.m = (MinecraftKey) null;
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
}
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
|
index 8328ed005..266f87d7f 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
|
@@ -60,7 +60,7 @@ public class CraftBlockEntityState<T extends TileEntity> extends CraftBlockState
|
|
}
|
|
|
|
// gets the wrapped TileEntity
|
|
- protected T getTileEntity() {
|
|
+ public T getTileEntity() { // Paper - protected -> public
|
|
return tileEntity;
|
|
}
|
|
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
|
|
index 85f3bb272..733c04ef7 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
|
|
@@ -1,5 +1,6 @@
|
|
package org.bukkit.craftbukkit.block;
|
|
|
|
+import com.destroystokyo.paper.loottable.CraftLootableBlockInventory; // Paper
|
|
import net.minecraft.server.BlockPosition;
|
|
import net.minecraft.server.TileEntityChest;
|
|
|
|
@@ -11,7 +12,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory;
|
|
import org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest;
|
|
import org.bukkit.inventory.Inventory;
|
|
|
|
-public class CraftChest extends CraftLootable<TileEntityChest> implements Chest {
|
|
+public class CraftChest extends CraftLootable<TileEntityChest> implements Chest, CraftLootableBlockInventory { // Paper
|
|
|
|
public CraftChest(final Block block) {
|
|
super(block, TileEntityChest.class);
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java
|
|
index 1dc8bfecd..bfcf9b6c4 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java
|
|
@@ -1,5 +1,6 @@
|
|
package org.bukkit.craftbukkit.block;
|
|
|
|
+import com.destroystokyo.paper.loottable.CraftLootableBlockInventory; // Paper
|
|
import net.minecraft.server.BlockDispenser;
|
|
import net.minecraft.server.BlockPosition;
|
|
import net.minecraft.server.Blocks;
|
|
@@ -14,7 +15,7 @@ import org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource;
|
|
import org.bukkit.inventory.Inventory;
|
|
import org.bukkit.projectiles.BlockProjectileSource;
|
|
|
|
-public class CraftDispenser extends CraftLootable<TileEntityDispenser> implements Dispenser {
|
|
+public class CraftDispenser extends CraftLootable<TileEntityDispenser> implements Dispenser, CraftLootableBlockInventory {
|
|
|
|
public CraftDispenser(final Block block) {
|
|
super(block, TileEntityDispenser.class);
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
|
|
index 6566554ab..df156d0d9 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
|
|
@@ -1,5 +1,6 @@
|
|
package org.bukkit.craftbukkit.block;
|
|
|
|
+import com.destroystokyo.paper.loottable.CraftLootableBlockInventory; // Paper
|
|
import net.minecraft.server.TileEntityHopper;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.block.Block;
|
|
@@ -7,7 +8,7 @@ import org.bukkit.block.Hopper;
|
|
import org.bukkit.craftbukkit.inventory.CraftInventory;
|
|
import org.bukkit.inventory.Inventory;
|
|
|
|
-public class CraftHopper extends CraftLootable<TileEntityHopper> implements Hopper {
|
|
+public class CraftHopper extends CraftLootable<TileEntityHopper> implements Hopper, CraftLootableBlockInventory {
|
|
|
|
public CraftHopper(final Block block) {
|
|
super(block, TileEntityHopper.class);
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java b/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java
|
|
index c029a1244..c26f0b5af 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftShulkerBox.java
|
|
@@ -1,5 +1,6 @@
|
|
package org.bukkit.craftbukkit.block;
|
|
|
|
+import com.destroystokyo.paper.loottable.CraftLootableBlockInventory;
|
|
import net.minecraft.server.BlockShulkerBox;
|
|
import net.minecraft.server.TileEntityShulkerBox;
|
|
import org.bukkit.DyeColor;
|
|
@@ -10,7 +11,7 @@ import org.bukkit.craftbukkit.inventory.CraftInventory;
|
|
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
|
|
import org.bukkit.inventory.Inventory;
|
|
|
|
-public class CraftShulkerBox extends CraftLootable<TileEntityShulkerBox> implements ShulkerBox {
|
|
+public class CraftShulkerBox extends CraftLootable<TileEntityShulkerBox> implements ShulkerBox, CraftLootableBlockInventory {
|
|
|
|
public CraftShulkerBox(final Block block) {
|
|
super(block, TileEntityShulkerBox.class);
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
|
index 69435c457..4291edf25 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
|
@@ -1,5 +1,6 @@
|
|
package org.bukkit.craftbukkit.entity;
|
|
|
|
+import com.destroystokyo.paper.loottable.CraftLootableEntityInventory; // Paper
|
|
import net.minecraft.server.EntityMinecartChest;
|
|
|
|
import org.bukkit.craftbukkit.CraftServer;
|
|
@@ -9,7 +10,7 @@ import org.bukkit.entity.minecart.StorageMinecart;
|
|
import org.bukkit.inventory.Inventory;
|
|
|
|
@SuppressWarnings("deprecation")
|
|
-public class CraftMinecartChest extends CraftMinecart implements StorageMinecart {
|
|
+public class CraftMinecartChest extends CraftMinecart implements StorageMinecart, CraftLootableEntityInventory { // Paper
|
|
private final CraftInventory inventory;
|
|
|
|
public CraftMinecartChest(CraftServer server, EntityMinecartChest entity) {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
|
|
index e9963e21c..acb4dee04 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java
|
|
@@ -1,5 +1,6 @@
|
|
package org.bukkit.craftbukkit.entity;
|
|
|
|
+import com.destroystokyo.paper.loottable.CraftLootableEntityInventory; // Paper
|
|
import net.minecraft.server.EntityMinecartHopper;
|
|
|
|
import org.bukkit.craftbukkit.CraftServer;
|
|
@@ -8,7 +9,7 @@ import org.bukkit.entity.EntityType;
|
|
import org.bukkit.entity.minecart.HopperMinecart;
|
|
import org.bukkit.inventory.Inventory;
|
|
|
|
-final class CraftMinecartHopper extends CraftMinecart implements HopperMinecart {
|
|
+final class CraftMinecartHopper extends CraftMinecart implements HopperMinecart, CraftLootableEntityInventory { // Paper
|
|
private final CraftInventory inventory;
|
|
|
|
CraftMinecartHopper(CraftServer server, EntityMinecartHopper entity) {
|
|
--
|
|
2.16.1
|
|
|