diff --git a/nms-patches/LootTable.patch b/nms-patches/LootTable.patch new file mode 100644 index 0000000000..817b136172 --- /dev/null +++ b/nms-patches/LootTable.patch @@ -0,0 +1,37 @@ +--- a/net/minecraft/server/LootTable.java ++++ b/net/minecraft/server/LootTable.java +@@ -18,6 +18,12 @@ + import org.apache.commons.lang3.ArrayUtils; + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; ++// CraftBukkit start ++import java.util.stream.Collectors; ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.inventory.CraftItemStack; ++import org.bukkit.event.world.LootGenerateEvent; ++// CraftBukkit end + + public class LootTable { + +@@ -103,8 +109,21 @@ + } + + public void fillInventory(IInventory iinventory, LootTableInfo loottableinfo) { ++ // CraftBukkit start ++ this.fillInventory(iinventory, loottableinfo, false); ++ } ++ ++ public void fillInventory(IInventory iinventory, LootTableInfo loottableinfo, boolean plugin) { ++ // CraftBukkit end + List list = this.populateLoot(loottableinfo); + Random random = loottableinfo.a(); ++ // CraftBukkit start ++ LootGenerateEvent event = CraftEventFactory.callLootGenerateEvent(iinventory, this, loottableinfo, list, plugin); ++ if (event.isCancelled()) { ++ return; ++ } ++ list = event.getLoot().stream().map(CraftItemStack::asNMSCopy).collect(Collectors.toList()); ++ // CraftBukkit end + List list1 = this.a(iinventory, random); + + this.a(list, list1.size(), random); diff --git a/nms-patches/LootTableRegistry.patch b/nms-patches/LootTableRegistry.patch new file mode 100644 index 0000000000..416e31ffde --- /dev/null +++ b/nms-patches/LootTableRegistry.patch @@ -0,0 +1,31 @@ +--- a/net/minecraft/server/LootTableRegistry.java ++++ b/net/minecraft/server/LootTableRegistry.java +@@ -17,6 +17,7 @@ + private static final Logger LOGGER = LogManager.getLogger(); + private static final Gson b = (new GsonBuilder()).registerTypeAdapter(LootValueBounds.class, new LootValueBounds.a()).registerTypeAdapter(LootValueBinomial.class, new LootValueBinomial.a()).registerTypeAdapter(LootValueConstant.class, new LootValueConstant.a()).registerTypeAdapter(LootIntegerLimit.class, new LootIntegerLimit.a()).registerTypeAdapter(LootSelector.class, new LootSelector.b()).registerTypeAdapter(LootTable.class, new LootTable.b()).registerTypeHierarchyAdapter(LootEntryAbstract.class, new LootEntries.a()).registerTypeHierarchyAdapter(LootItemFunction.class, new LootItemFunctions.a()).registerTypeHierarchyAdapter(LootItemCondition.class, new LootItemConditions.a()).registerTypeHierarchyAdapter(LootTableInfo.EntityTarget.class, new LootTableInfo.EntityTarget.a()).create(); + private Map c = ImmutableMap.of(); ++ public Map lootTableToKey = ImmutableMap.of(); // CraftBukkit + private final LootPredicateManager d; + + public LootTableRegistry(LootPredicateManager lootpredicatemanager) { +@@ -52,7 +53,7 @@ + LootPredicateManager lootpredicatemanager = this.d; + + this.d.getClass(); +- Function function = lootpredicatemanager::a; ++ Function function = lootpredicatemanager::a; // CraftBukkit - decompile error + + immutablemap.getClass(); + LootCollector lootcollector = new LootCollector(lootcontextparameterset, function, immutablemap::get); +@@ -64,6 +65,11 @@ + LootTableRegistry.LOGGER.warn("Found validation problem in " + s + ": " + s1); + }); + this.c = immutablemap; ++ // CraftBukkit start - build a reversed registry map ++ ImmutableMap.Builder lootTableToKeyBuilder = ImmutableMap.builder(); ++ this.c.forEach((lootTable, key) -> lootTableToKeyBuilder.put(key, lootTable)); // PAIL rename keyToLootTable ++ this.lootTableToKey = lootTableToKeyBuilder.build(); ++ // CraftBukkit end + } + + public static void a(LootCollector lootcollector, MinecraftKey minecraftkey, LootTable loottable) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java index 396a78b9da..260d54b304 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftLootTable.java @@ -114,6 +114,30 @@ public class CraftLootTable implements org.bukkit.loot.LootTable { return builder.build(nmsBuilder.a()); // PAIL rename build } + public static LootContext convertContext(LootTableInfo info) { + BlockPosition position = info.getContextParameter(LootContextParameters.POSITION); + Location location = new Location(info.c().getWorld(), position.getX(), position.getY(), position.getZ()); // PAIL rename getWorld + LootContext.Builder contextBuilder = new LootContext.Builder(location); + + if (info.hasContextParameter(LootContextParameters.KILLER_ENTITY)) { + CraftEntity killer = info.getContextParameter(LootContextParameters.KILLER_ENTITY).getBukkitEntity(); + if (killer instanceof CraftHumanEntity) { + contextBuilder.killer((CraftHumanEntity) killer); + } + } + + if (info.hasContextParameter(LootContextParameters.THIS_ENTITY)) { + contextBuilder.lootedEntity(info.getContextParameter(LootContextParameters.THIS_ENTITY).getBukkitEntity()); + } + + if (info.hasContextParameter(LootContextParameters.LOOTING_MOD)) { + contextBuilder.lootingModifier(info.getContextParameter(LootContextParameters.LOOTING_MOD)); + } + + contextBuilder.luck(info.b()); // PAIL rename getLuck + return contextBuilder.build(); + } + @Override public String toString() { return getKey().toString(); diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 4602d978a8..59df265924 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -10,6 +10,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import javax.annotation.Nullable; import net.minecraft.server.BlockPosition; import net.minecraft.server.BlockPropertyInstrument; @@ -54,6 +55,9 @@ import net.minecraft.server.IInventory; import net.minecraft.server.ItemActionContext; import net.minecraft.server.ItemStack; import net.minecraft.server.Items; +import net.minecraft.server.LootContextParameters; +import net.minecraft.server.LootTable; +import net.minecraft.server.LootTableInfo; import net.minecraft.server.MinecraftKey; import net.minecraft.server.MobEffect; import net.minecraft.server.MovingObjectPosition; @@ -67,11 +71,13 @@ import net.minecraft.server.World; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.Server; import org.bukkit.Statistic.Type; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; +import org.bukkit.craftbukkit.CraftLootTable; import org.bukkit.craftbukkit.CraftRaid; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftStatistic; @@ -198,6 +204,7 @@ import org.bukkit.event.raid.RaidStopEvent; import org.bukkit.event.raid.RaidTriggerEvent; import org.bukkit.event.server.ServerListPingEvent; import org.bukkit.event.vehicle.VehicleCreateEvent; +import org.bukkit.event.world.LootGenerateEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.meta.BookMeta; @@ -1525,4 +1532,16 @@ public class CraftEventFactory { } return event; } + + public static LootGenerateEvent callLootGenerateEvent(IInventory inventory, LootTable lootTable, LootTableInfo lootInfo, List loot, boolean plugin) { + CraftWorld world = lootInfo.c().getWorld(); // PAIL rename getWorld + Entity entity = lootInfo.getContextParameter(LootContextParameters.THIS_ENTITY); + NamespacedKey key = CraftNamespacedKey.fromMinecraft(world.getHandle().getMinecraftServer().getLootTableRegistry().lootTableToKey.get(lootTable)); + CraftLootTable craftLootTable = new CraftLootTable(key, lootTable); + List bukkitLoot = loot.stream().map(CraftItemStack::asCraftMirror).collect(Collectors.toCollection(ArrayList::new)); + + LootGenerateEvent event = new LootGenerateEvent(world, (entity != null ? entity.getBukkitEntity() : null), inventory.getOwner(), craftLootTable, CraftLootTable.convertContext(lootInfo), bukkitLoot, plugin); + Bukkit.getPluginManager().callEvent(event); + return event; + } }