From c0df4b82d380bea4fd66cc887a1476468e2301c4 Mon Sep 17 00:00:00 2001 From: Senmori Date: Sun, 12 Aug 2018 18:39:51 +1000 Subject: [PATCH] SPIGOT-1936: LootTable API --- nms-patches/EntityInsentient.patch | 36 ++++-- nms-patches/EntityMinecartContainer.patch | 12 +- nms-patches/LootEnchantFunction.patch | 26 +++++ ...ItemConditionRandomChanceWithLooting.patch | 23 ++++ nms-patches/LootTableInfo.patch | 67 +++++++++++ .../bukkit/craftbukkit/CraftLootTable.java | 109 ++++++++++++++++++ .../org/bukkit/craftbukkit/CraftServer.java | 8 ++ .../craftbukkit/block/CraftLootable.java | 40 ++++++- .../entity/CraftMinecartChest.java | 2 +- .../entity/CraftMinecartContainer.java | 54 +++++++++ .../entity/CraftMinecartHopper.java | 4 +- .../bukkit/craftbukkit/entity/CraftMob.java | 29 +++++ src/test/java/org/bukkit/LootTablesTest.java | 22 ++++ .../bukkit/support/AbstractTestingBase.java | 11 +- .../java/org/bukkit/support/DummyServer.java | 12 ++ 15 files changed, 434 insertions(+), 21 deletions(-) create mode 100644 nms-patches/LootEnchantFunction.patch create mode 100644 nms-patches/LootItemConditionRandomChanceWithLooting.patch create mode 100644 nms-patches/LootTableInfo.patch create mode 100644 src/main/java/org/bukkit/craftbukkit/CraftLootTable.java create mode 100644 src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java create mode 100644 src/test/java/org/bukkit/LootTablesTest.java diff --git a/nms-patches/EntityInsentient.patch b/nms-patches/EntityInsentient.patch index a93da20511..d315fadb31 100644 --- a/nms-patches/EntityInsentient.patch +++ b/nms-patches/EntityInsentient.patch @@ -19,7 +19,7 @@ public abstract class EntityInsentient extends EntityLiving { private static final DataWatcherObject a = DataWatcher.a(EntityInsentient.class, DataWatcherRegistry.a); -@@ -27,7 +39,7 @@ +@@ -27,11 +39,11 @@ public float[] dropChanceHand; private final NonNullList bE; public float[] dropChanceArmor; @@ -27,7 +27,13 @@ + // public boolean canPickUpLoot; // CraftBukkit - moved up to EntityLiving public boolean persistent; private final Map bH; - private MinecraftKey bI; +- private MinecraftKey bI; +- private long bJ; ++ public MinecraftKey bI; // CraftBukkit private -> public ++ public long bJ; // CraftBukkit private -> public + private boolean bK; + private Entity leashHolder; + private NBTTagCompound bM; @@ -57,6 +69,9 @@ this.n(); } @@ -100,7 +106,19 @@ NBTTagList nbttaglist; int i; -@@ -470,11 +525,21 @@ +@@ -394,6 +449,11 @@ + protected MinecraftKey G() { + return null; + } ++ // CraftBukkit - start ++ public MinecraftKey getLootTable() { ++ return G(); ++ } ++ // CraftBukkit - end + + protected void a(boolean flag, int i, DamageSource damagesource) { + MinecraftKey minecraftkey = this.bI; +@@ -470,11 +530,21 @@ ItemStack itemstack1 = this.getEquipment(enumitemslot); boolean flag = this.a(itemstack, itemstack1, enumitemslot); @@ -123,7 +141,7 @@ } this.setSlot(enumitemslot, itemstack); -@@ -554,11 +619,11 @@ +@@ -554,11 +624,11 @@ double d2 = entityhuman.locZ - this.locZ; double d3 = d0 * d0 + d1 * d1 + d2 * d2; @@ -137,7 +155,7 @@ this.die(); } else if (d3 < 1024.0D) { this.ticksFarFromPlayer = 0; -@@ -946,12 +1011,24 @@ +@@ -946,12 +1016,24 @@ public final boolean b(EntityHuman entityhuman, EnumHand enumhand) { if (this.isLeashed() && this.getLeashHolder() == entityhuman) { @@ -162,7 +180,7 @@ this.setLeashHolder(entityhuman, true); itemstack.subtract(1); return true; -@@ -972,10 +1049,12 @@ +@@ -972,10 +1054,12 @@ if (this.bK) { if (!this.isAlive()) { @@ -175,7 +193,7 @@ this.unleash(true, true); } } -@@ -986,7 +1065,9 @@ +@@ -986,7 +1070,9 @@ this.bK = false; this.leashHolder = null; if (!this.world.isClientSide && flag1) { @@ -185,7 +203,7 @@ } if (!this.world.isClientSide && flag && this.world instanceof WorldServer) { -@@ -1056,6 +1137,7 @@ +@@ -1056,6 +1142,7 @@ this.setLeashHolder(entityleash, true); } else { @@ -193,7 +211,7 @@ this.unleash(false, true); } } -@@ -1151,7 +1233,14 @@ +@@ -1151,7 +1238,14 @@ int j = EnchantmentManager.getFireAspectEnchantmentLevel(this); if (j > 0) { diff --git a/nms-patches/EntityMinecartContainer.patch b/nms-patches/EntityMinecartContainer.patch index 11d6d77e04..b17c7c9785 100644 --- a/nms-patches/EntityMinecartContainer.patch +++ b/nms-patches/EntityMinecartContainer.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/server/EntityMinecartContainer.java +++ b/net/minecraft/server/EntityMinecartContainer.java -@@ -3,6 +3,13 @@ +@@ -3,23 +3,66 @@ import java.util.Iterator; import java.util.Random; import javax.annotation.Nullable; @@ -14,10 +14,12 @@ public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory, ILootable { -@@ -11,15 +18,51 @@ + private NonNullList items; + private boolean b; private MinecraftKey c; - private long d; - +- private long d; ++ public long d; // CraftBukkit private -> public ++ + // CraftBukkit start + public List transaction = new java.util.ArrayList(); + private int maxStack = MAX_STACK; @@ -53,7 +55,7 @@ + return getBukkitEntity().getLocation(); + } + // CraftBukkit end -+ + protected EntityMinecartContainer(EntityTypes entitytypes, World world) { super(entitytypes, world); - this.items = NonNullList.a(36, ItemStack.a); diff --git a/nms-patches/LootEnchantFunction.patch b/nms-patches/LootEnchantFunction.patch new file mode 100644 index 0000000000..af3c6d1cd4 --- /dev/null +++ b/nms-patches/LootEnchantFunction.patch @@ -0,0 +1,26 @@ +--- a/net/minecraft/server/LootEnchantFunction.java ++++ b/net/minecraft/server/LootEnchantFunction.java +@@ -21,8 +21,13 @@ + + if (entity instanceof EntityLiving) { + int i = EnchantmentManager.g((EntityLiving) entity); ++ // CraftBukkit start - use lootingModifier if set by plugin ++ if (loottableinfo.lootingMod > org.bukkit.loot.LootContext.DEFAULT_LOOT_MODIFIER) { ++ i = loottableinfo.lootingMod; ++ } ++ // CraftBukkit end + +- if (i == 0) { ++ if (i <= 0) { // CraftBukkit - account for possible negative looting values from Bukkit + return itemstack; + } + +@@ -57,7 +62,7 @@ + return new LootEnchantFunction(alootitemcondition, (LootValueBounds) ChatDeserializer.a(jsonobject, "count", jsondeserializationcontext, LootValueBounds.class), i); + } + +- public LootItemFunction b(JsonObject jsonobject, JsonDeserializationContext jsondeserializationcontext, LootItemCondition[] alootitemcondition) { ++ public LootEnchantFunction b(JsonObject jsonobject, JsonDeserializationContext jsondeserializationcontext, LootItemCondition[] alootitemcondition) { // CraftBukkit - decompile error + return this.a(jsonobject, jsondeserializationcontext, alootitemcondition); + } + } diff --git a/nms-patches/LootItemConditionRandomChanceWithLooting.patch b/nms-patches/LootItemConditionRandomChanceWithLooting.patch new file mode 100644 index 0000000000..078a868454 --- /dev/null +++ b/nms-patches/LootItemConditionRandomChanceWithLooting.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/server/LootItemConditionRandomChanceWithLooting.java ++++ b/net/minecraft/server/LootItemConditionRandomChanceWithLooting.java +@@ -21,6 +21,11 @@ + if (loottableinfo.c() instanceof EntityLiving) { + i = EnchantmentManager.g((EntityLiving) loottableinfo.c()); + } ++ // CraftBukkit start - only use lootingModifier if set by Bukkit ++ if (loottableinfo.lootingMod > org.bukkit.loot.LootContext.DEFAULT_LOOT_MODIFIER) { ++ i = loottableinfo.lootingMod; ++ } ++ // CraftBukkit end + + return random.nextFloat() < this.a + (float) i * this.b; + } +@@ -40,7 +45,7 @@ + return new LootItemConditionRandomChanceWithLooting(ChatDeserializer.l(jsonobject, "chance"), ChatDeserializer.l(jsonobject, "looting_multiplier")); + } + +- public LootItemCondition b(JsonObject jsonobject, JsonDeserializationContext jsondeserializationcontext) { ++ public LootItemConditionRandomChanceWithLooting b(JsonObject jsonobject, JsonDeserializationContext jsondeserializationcontext) { // CraftBukkit - decompile error + return this.a(jsonobject, jsondeserializationcontext); + } + } diff --git a/nms-patches/LootTableInfo.patch b/nms-patches/LootTableInfo.patch new file mode 100644 index 0000000000..21221c0ca7 --- /dev/null +++ b/nms-patches/LootTableInfo.patch @@ -0,0 +1,67 @@ +--- a/net/minecraft/server/LootTableInfo.java ++++ b/net/minecraft/server/LootTableInfo.java +@@ -11,6 +11,7 @@ + public class LootTableInfo { + + private final float a; ++ public final int lootingMod; // CraftBukkit - add field + private final WorldServer b; + private final LootTableRegistry c; + @Nullable +@@ -23,7 +24,8 @@ + private final BlockPosition g; + private final Set h = Sets.newLinkedHashSet(); + +- public LootTableInfo(float f, WorldServer worldserver, LootTableRegistry loottableregistry, @Nullable Entity entity, @Nullable EntityHuman entityhuman, @Nullable DamageSource damagesource, @Nullable BlockPosition blockposition) { ++ // CraftBukkit - add looting modifier to constructor ++ public LootTableInfo(float f, WorldServer worldserver, LootTableRegistry loottableregistry, @Nullable Entity entity, @Nullable EntityHuman entityhuman, @Nullable DamageSource damagesource, @Nullable BlockPosition blockposition, int lootingModifier) { + this.a = f; + this.b = worldserver; + this.c = loottableregistry; +@@ -31,6 +33,7 @@ + this.e = entityhuman; + this.f = damagesource; + this.g = blockposition; ++ this.lootingMod = lootingModifier; // CraftBukkit + } + + @Nullable +@@ -127,11 +130,11 @@ + return LootTableInfo.EntityTarget.a(jsonreader.nextString()); + } + +- public Object read(JsonReader jsonreader) throws IOException { ++ public LootTableInfo.EntityTarget read(JsonReader jsonreader) throws IOException { // CraftBukkit - decompile error + return this.a(jsonreader); + } + +- public void write(JsonWriter jsonwriter, Object object) throws IOException { ++ public void write(JsonWriter jsonwriter, LootTableInfo.EntityTarget object) throws IOException { // CraftBukkit - decompile error + this.a(jsonwriter, (LootTableInfo.EntityTarget) object); + } + } +@@ -141,6 +144,7 @@ + + private final WorldServer a; + private float b; ++ private int lootingMod; // CraftBukkit + private Entity c; + private EntityHuman d; + private DamageSource e; +@@ -175,8 +179,15 @@ + return this; + } + ++ // CraftBukkit start - add looting modifier ++ public LootTableInfo.a lootingModifier(int modifier) { ++ this.lootingMod = modifier; ++ return this; ++ } ++ // CraftBukkit end ++ + public LootTableInfo a() { +- return new LootTableInfo(this.b, this.a, this.a.getMinecraftServer().aP(), this.c, this.d, this.e, this.f); ++ return new LootTableInfo(this.b, this.a, this.a.getMinecraftServer().aP(), this.c, this.d, this.e, this.f, this.lootingMod); // CraftBukkit add looting modifier + } + } + } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java new file mode 100644 index 0000000000..0740c56551 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java @@ -0,0 +1,109 @@ +package org.bukkit.craftbukkit; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; +import net.minecraft.server.BlockPosition; +import net.minecraft.server.DamageSource; +import net.minecraft.server.Entity; +import net.minecraft.server.EntityHuman; +import net.minecraft.server.IInventory; +import net.minecraft.server.LootTable; +import net.minecraft.server.LootTableInfo; +import net.minecraft.server.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftHumanEntity; +import org.bukkit.craftbukkit.inventory.CraftInventory; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.loot.LootContext; + +public class CraftLootTable implements org.bukkit.loot.LootTable { + + private final LootTable handle; + private final NamespacedKey key; + + public CraftLootTable(NamespacedKey key, LootTable handle) { + this.handle = handle; + this.key = key; + } + + public LootTable getHandle() { + return handle; + } + + @Override + public Collection populateLoot(Random random, LootContext context) { + LootTableInfo nmsContext = convertContext(context); + List nmsItems = handle.a(random, nmsContext); // PAIL rename populateLoot + Collection bukkit = new ArrayList<>(nmsItems.size()); + + for (net.minecraft.server.ItemStack item : nmsItems) { + if (item.isEmpty()) { + continue; + } + bukkit.add(CraftItemStack.asBukkitCopy(item)); + } + + return bukkit; + } + + @Override + public void fillInventory(Inventory inventory, Random random, LootContext context) { + LootTableInfo nmsContext = convertContext(context); + CraftInventory craftInventory = (CraftInventory) inventory; + IInventory handle = craftInventory.getInventory(); + + // TODO: When events are added, call event here w/ custom reason? + getHandle().a(handle, random, nmsContext); // PAIL rename fillInventory + } + + @Override + public NamespacedKey getKey() { + return key; + } + + private LootTableInfo convertContext(LootContext context) { + Location loc = context.getLocation(); + WorldServer handle = ((CraftWorld) loc.getWorld()).getHandle(); + + LootTableInfo.a builder = new LootTableInfo.a(handle); // PAIL rename Builder + builder.a(context.getLuck()); // PAIL rename withLuck, luck + + if (context.getLootedEntity() != null) { + Entity nmsLootedEntity = ((CraftEntity) context.getLootedEntity()).getHandle(); + builder.a(nmsLootedEntity); // PAIL Rename withLootedEntity, lootedEntity + builder.a(DamageSource.GENERIC); // PAIL rename withDamageSource, damageSource + builder.a(new BlockPosition(nmsLootedEntity)); // PAIL rename withPosition, position + } + + if (context.getKiller() != null) { + EntityHuman nmsKiller = ((CraftHumanEntity) context.getKiller()).getHandle(); + builder.a(nmsKiller); // PAIL rename withKiller, killer + // If there is a player killer, damage source should reflect that in case loot tables use that information + builder.a(DamageSource.playerAttack(nmsKiller)); // PAIL rename withDamageSource, damageSource + } + + return builder.a(); // PAIL rename build + } + + @Override + public String toString() { + return getKey().toString(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof org.bukkit.loot.LootTable)) { + return false; + } + + org.bukkit.loot.LootTable table = (org.bukkit.loot.LootTable) obj; + return table.getKey().equals(this.getKey()); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index abc08ed39f..9bb0ceb20b 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -95,6 +95,7 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.ShapedRecipe; import org.bukkit.inventory.ShapelessRecipe; +import org.bukkit.loot.LootTable; import org.bukkit.permissions.Permissible; import org.bukkit.permissions.Permission; import org.bukkit.plugin.Plugin; @@ -1765,6 +1766,13 @@ public final class CraftServer implements Server { } } + public LootTable getLootTable(NamespacedKey key) { + Validate.notNull(key, "NamespacedKey cannot be null"); + + LootTableRegistry registry = getServer().aP(); // PAIL getLootTableRegistry + return new CraftLootTable(key, registry.a(CraftNamespacedKey.toMinecraft(key))); // PAIL rename getLootTable + } + @Deprecated @Override public UnsafeValues getUnsafe() { diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java index d7677192fa..34bcc49cf9 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftLootable.java @@ -1,12 +1,17 @@ package org.bukkit.craftbukkit.block; +import net.minecraft.server.MinecraftKey; import net.minecraft.server.TileEntityLootable; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Nameable; import org.bukkit.block.Block; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.loot.LootTable; +import org.bukkit.loot.Lootable; -public abstract class CraftLootable extends CraftContainer implements Nameable { +public abstract class CraftLootable extends CraftContainer implements Nameable, Lootable { public CraftLootable(Block block, Class tileEntityClass) { super(block, tileEntityClass); @@ -34,5 +39,38 @@ public abstract class CraftLootable extends CraftC if (!this.getSnapshot().hasCustomName()) { lootable.setCustomName(null); } + if (this.getSnapshot().Q_() == null) { + lootable.a((MinecraftKey) null, 0L); // PAIL rename setLootTable + } + } + + @Override + public LootTable getLootTable() { + if (getSnapshot().Q_() == null) { + return null; + } + + MinecraftKey key = getSnapshot().Q_(); + return Bukkit.getLootTable(CraftNamespacedKey.fromMinecraft(key)); + } + + @Override + public void setLootTable(LootTable table) { + setLootTable(table, getSeed()); + } + + @Override + public long getSeed() { + return getSnapshotNBT().getLong("LootTableSeed"); // returns OL if an error occurred + } + + @Override + public void setSeed(long seed) { + setLootTable(getLootTable(), seed); + } + + private void setLootTable(LootTable table, long seed) { + MinecraftKey key = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey()); + getSnapshot().a(key, seed); // PAIL setLootTable } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java index 69435c4576..1b5b266c05 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartChest.java @@ -9,7 +9,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 CraftMinecartContainer implements StorageMinecart { private final CraftInventory inventory; public CraftMinecartChest(CraftServer server, EntityMinecartChest entity) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java new file mode 100644 index 0000000000..8ce9737451 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartContainer.java @@ -0,0 +1,54 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityMinecartAbstract; +import net.minecraft.server.EntityMinecartContainer; +import net.minecraft.server.MinecraftKey; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.loot.LootTable; +import org.bukkit.loot.Lootable; + +public abstract class CraftMinecartContainer extends CraftMinecart implements Lootable { + + public CraftMinecartContainer(CraftServer server, EntityMinecartAbstract entity) { + super(server, entity); + } + + @Override + public EntityMinecartContainer getHandle() { + return (EntityMinecartContainer) entity; + } + + @Override + public void setLootTable(LootTable table) { + setLootTable(table, getSeed()); + } + + @Override + public LootTable getLootTable() { + MinecraftKey nmsTable = getHandle().Q_(); // PAIL getLootTable + if (nmsTable == null) { + return null; // return empty loot table? + } + + NamespacedKey key = CraftNamespacedKey.fromMinecraft(nmsTable); + return Bukkit.getLootTable(key); + } + + @Override + public void setSeed(long seed) { + setLootTable(getLootTable(), seed); + } + + @Override + public long getSeed() { + return getHandle().d; // PAIL rename lootTableSeed + } + + private void setLootTable(LootTable table, long seed) { + MinecraftKey newKey = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey()); + getHandle().a(newKey, seed); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java index e9963e21cd..f29365c948 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMinecartHopper.java @@ -8,10 +8,10 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.minecart.HopperMinecart; import org.bukkit.inventory.Inventory; -final class CraftMinecartHopper extends CraftMinecart implements HopperMinecart { +public final class CraftMinecartHopper extends CraftMinecartContainer implements HopperMinecart { private final CraftInventory inventory; - CraftMinecartHopper(CraftServer server, EntityMinecartHopper entity) { + public CraftMinecartHopper(CraftServer server, EntityMinecartHopper entity) { super(server, entity); inventory = new CraftInventory(entity); } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java index 43178db810..eb643cff3a 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftMob.java @@ -1,9 +1,13 @@ package org.bukkit.craftbukkit.entity; import net.minecraft.server.EntityInsentient; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Mob; +import org.bukkit.loot.LootTable; public abstract class CraftMob extends CraftLivingEntity implements Mob { public CraftMob(CraftServer server, EntityInsentient entity) { @@ -36,4 +40,29 @@ public abstract class CraftMob extends CraftLivingEntity implements Mob { public String toString() { return "CraftMob"; } + + @Override + public void setLootTable(LootTable table) { + getHandle().bI = (table == null) ? null : CraftNamespacedKey.toMinecraft(table.getKey()); // PAIL rename lootTableKey + } + + @Override + public LootTable getLootTable() { + if (getHandle().bI == null) { + getHandle().bI = getHandle().getLootTable(); // Restore to entity default + } + + NamespacedKey key = CraftNamespacedKey.fromMinecraft(getHandle().bI); // PAIL rename lootTableKey + return Bukkit.getLootTable(key); + } + + @Override + public void setSeed(long seed) { + getHandle().bJ = seed; // PAIL rename lootTableSeed + } + + @Override + public long getSeed() { + return getHandle().bJ; // PAIL rename lootTableSeed + } } diff --git a/src/test/java/org/bukkit/LootTablesTest.java b/src/test/java/org/bukkit/LootTablesTest.java new file mode 100644 index 0000000000..8d2cbb44cc --- /dev/null +++ b/src/test/java/org/bukkit/LootTablesTest.java @@ -0,0 +1,22 @@ +package org.bukkit; + +import org.bukkit.loot.LootTable; +import org.bukkit.loot.LootTables; +import org.bukkit.support.AbstractTestingBase; +import org.junit.Assert; +import org.junit.Test; + +public class LootTablesTest extends AbstractTestingBase { + + @Test + public void testLootTablesEnumExists() { + LootTables[] tables = LootTables.values(); + + for (LootTables table : tables) { + LootTable lootTable = Bukkit.getLootTable(table.getKey()); + + Assert.assertNotNull("Unknown LootTable " + table.getKey(), lootTable); + Assert.assertEquals(lootTable.getKey(), table.getKey()); + } + } +} diff --git a/src/test/java/org/bukkit/support/AbstractTestingBase.java b/src/test/java/org/bukkit/support/AbstractTestingBase.java index b6bc6641cb..53cbb525e4 100644 --- a/src/test/java/org/bukkit/support/AbstractTestingBase.java +++ b/src/test/java/org/bukkit/support/AbstractTestingBase.java @@ -5,6 +5,7 @@ import java.util.Collections; import java.util.List; import net.minecraft.server.DispenserRegistry; import net.minecraft.server.EnumResourcePackType; +import net.minecraft.server.LootTableRegistry; import net.minecraft.server.ResourceManager; import net.minecraft.server.ResourcePackVanilla; import net.minecraft.server.TagRegistry; @@ -24,12 +25,16 @@ public abstract class AbstractTestingBase { // Materials that only exist in block form (or are legacy) public static final List INVALIDATED_MATERIALS; + public static final LootTableRegistry LOOT_TABLE_REGISTRY; + public static final TagRegistry TAG_REGISTRY; + static { DispenserRegistry.c(); // Set up resource manager ResourceManager resourceManager = new ResourceManager(EnumResourcePackType.SERVER_DATA); - // add tags for unit tests - resourceManager.a(new TagRegistry()); + // add tags and loot tables for unit tests + resourceManager.a(TAG_REGISTRY = new TagRegistry()); + resourceManager.a(LOOT_TABLE_REGISTRY = new LootTableRegistry()); // Register vanilla pack resourceManager.a(Collections.singletonList(new ResourcePackVanilla("minecraft"))); @@ -43,6 +48,6 @@ public abstract class AbstractTestingBase { } } INVALIDATED_MATERIALS = builder.build(); - Assert.assertTrue("Expected 543 invalidated materials (got " + INVALIDATED_MATERIALS.size() + ")", INVALIDATED_MATERIALS.size() == 543); + Assert.assertEquals("Expected 543 invalidated materials (got " + INVALIDATED_MATERIALS.size() + ")", 543, INVALIDATED_MATERIALS.size()); } } diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java index a6e7651a29..02a31f09c2 100644 --- a/src/test/java/org/bukkit/support/DummyServer.java +++ b/src/test/java/org/bukkit/support/DummyServer.java @@ -8,10 +8,13 @@ import java.util.logging.Logger; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.Server; +import org.bukkit.craftbukkit.CraftLootTable; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.inventory.CraftItemFactory; import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Versioning; public class DummyServer implements InvocationHandler { @@ -79,6 +82,15 @@ public class DummyServer implements InvocationHandler { } } ); + methods.put(Server.class.getMethod("getLootTable", NamespacedKey.class), + new MethodHandler() { + @Override + public Object handle(DummyServer server, Object[] args) { + NamespacedKey key = (NamespacedKey) args[0]; + return new CraftLootTable(key, AbstractTestingBase.LOOT_TABLE_REGISTRY.a(CraftNamespacedKey.toMinecraft(key))); + } + } + ); Bukkit.setServer(Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(new DummyServer())); } catch (Throwable t) { throw new Error(t);