geforkt von Mirrors/Paper
758 Zeilen
28 KiB
Diff
758 Zeilen
28 KiB
Diff
From 6f5b71b26d1b422006ec176d1f343df159bf418b 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 75260d4..4d6a309 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -311,4 +311,26 @@ public class PaperWorldConfig {
|
|
this.frostedIceDelayMax = this.getInt("frosted-ice.delay.max", this.frostedIceDelayMax);
|
|
this.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 0000000..36c36d1
|
|
--- /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 0000000..20d236c
|
|
--- /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 0000000..1150dee
|
|
--- /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 0000000..6680976
|
|
--- /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 0000000..01c2713
|
|
--- /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 a799196..965aa5c 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);
|
|
}
|
|
|
|
@@ -181,7 +186,7 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract imp
|
|
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 +235,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.ak().a(this.c);
|
|
|
|
- this.c = null;
|
|
+ lootableData.processRefill(entityhuman); // Paper
|
|
Random random;
|
|
|
|
if (this.d == 0L) {
|
|
@@ -258,12 +263,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 5632f2e..01d0d80 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.ak().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/CraftChest.java b/src/main/java/org/bukkit/craftbukkit/block/CraftChest.java
|
|
index f15c26b..9c43cbe 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 CraftContainer implements Chest {
|
|
+public class CraftChest extends CraftContainer implements Chest, CraftLootableBlockInventory { // Paper
|
|
private final CraftWorld world;
|
|
private final TileEntityChest chest;
|
|
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java b/src/main/java/org/bukkit/craftbukkit/block/CraftDispenser.java
|
|
index 003381a..d70281d 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 CraftContainer implements Dispenser {
|
|
+public class CraftDispenser extends CraftContainer implements Dispenser, CraftLootableBlockInventory { // Paper
|
|
private final CraftWorld world;
|
|
private final TileEntityDispenser dispenser;
|
|
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java b/src/main/java/org/bukkit/craftbukkit/block/CraftHopper.java
|
|
index f155790..acad8bc 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;
|
|
@@ -8,7 +9,7 @@ import org.bukkit.craftbukkit.CraftWorld;
|
|
import org.bukkit.craftbukkit.inventory.CraftInventory;
|
|
import org.bukkit.inventory.Inventory;
|
|
|
|
-public class CraftHopper extends CraftContainer implements Hopper {
|
|
+public class CraftHopper extends CraftContainer implements Hopper, CraftLootableBlockInventory { // Paper
|
|
private final TileEntityHopper hopper;
|
|
|
|
public CraftHopper(final Block block) {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java
|
|
index 69435c4..4291edf 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 e9963e2..acb4dee 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.10.2
|
|
|