From 2ce73c6e2cc3dc95a10b2337d2010adc0c141355 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 25 Mar 2025 16:57:49 +0800 Subject: [PATCH] add entity loots --- .../bukkit/api/CraftEngineBlocks.java | 2 +- .../bukkit/api/CraftEngineFurniture.java | 2 +- .../bukkit/block/BlockEventListener.java | 4 +- .../bukkit/loot/BukkitVanillaLootManager.java | 78 ++++++++++++++++++- .../craftengine/core/loot/VanillaLoot.java | 3 +- .../core/loot/VanillaLootManager.java | 2 + .../craftengine/core/plugin/CraftEngine.java | 2 + 7 files changed, 84 insertions(+), 9 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java index a48dbd85c..46cb7fc86 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineBlocks.java @@ -178,7 +178,7 @@ public final class CraftEngineBlocks { BukkitServerPlayer serverPlayer = BukkitCraftEngine.instance().adapt(player); if (player != null) { builder.withParameter(LootParameters.PLAYER, serverPlayer); - builder.withParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); + builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); } for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java index fdec29803..ddef57af8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineFurniture.java @@ -246,7 +246,7 @@ public class CraftEngineFurniture { builder.withParameter(LootParameters.WORLD, world); if (player != null) { builder.withParameter(LootParameters.PLAYER, player); - builder.withParameter(LootParameters.TOOL, player.getItemInHand(InteractionHand.MAIN_HAND)); + builder.withOptionalParameter(LootParameters.TOOL, player.getItemInHand(InteractionHand.MAIN_HAND)); } List> items = lootTable.getRandomItems(builder.build(), world); for (Item item : items) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java index ec1436b9d..f935288c9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BlockEventListener.java @@ -138,7 +138,7 @@ public class BlockEventListener implements Listener { builder.withParameter(LootParameters.WORLD, world); builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.PLAYER, serverPlayer); - builder.withParameter(LootParameters.TOOL, itemInHand); + builder.withOptionalParameter(LootParameters.TOOL, itemInHand); for (Item item : state.getDrops(builder, world)) { world.dropItemNaturally(vec3d, item); } @@ -159,7 +159,7 @@ public class BlockEventListener implements Listener { builder.withParameter(LootParameters.WORLD, world); builder.withParameter(LootParameters.LOCATION, vec3d); builder.withParameter(LootParameters.PLAYER, serverPlayer); - builder.withParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); + builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); ContextHolder contextHolder = builder.build(); for (LootTable lootTable : it.lootTables()) { for (Item item : lootTable.getRandomItems(contextHolder, world)) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java index 67c68b9c9..b477c47bc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/loot/BukkitVanillaLootManager.java @@ -1,32 +1,63 @@ package net.momirealms.craftengine.bukkit.loot; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.Reflections; +import net.momirealms.craftengine.bukkit.world.BukkitWorld; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.loot.VanillaLoot; import net.momirealms.craftengine.core.loot.VanillaLootManager; +import net.momirealms.craftengine.core.loot.parameter.LootParameters; import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.PreConditions; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.util.context.ContextHolder; +import net.momirealms.craftengine.core.world.Vec3d; import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDeathEvent; import java.nio.file.Path; import java.util.*; -public class BukkitVanillaLootManager implements VanillaLootManager { - private final CraftEngine plugin; +// note: block listeners are in BlockEventListener to reduce performance cost +public class BukkitVanillaLootManager implements VanillaLootManager, Listener { + private final BukkitCraftEngine plugin; private final Map blockLoots; + private final Map entityLoots; - public BukkitVanillaLootManager(CraftEngine plugin) { + public BukkitVanillaLootManager(BukkitCraftEngine plugin) { this.plugin = plugin; this.blockLoots = new HashMap<>(); + this.entityLoots = new HashMap<>(); + } + + @Override + public void delayedInit() { + Bukkit.getPluginManager().registerEvents(this, plugin.bootstrap()); + } + + @Override + public void disable() { + HandlerList.unregisterAll(this); } @Override public void unload() { this.blockLoots.clear(); + this.entityLoots.clear(); } @Override @@ -34,6 +65,37 @@ public class BukkitVanillaLootManager implements VanillaLootManager { return Optional.ofNullable(this.blockLoots.get(vanillaBlockState)); } + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onEntityDeath(EntityDeathEvent event) { + Entity entity = event.getEntity(); + Key key = KeyUtils.namespacedKey2Key(entity.getType().getKey()); + Optional.ofNullable(this.entityLoots.get(key)).ifPresent(loot -> { + if (loot.override()) { + event.getDrops().clear(); + event.setDroppedExp(0); + } + Location location = entity.getLocation(); + net.momirealms.craftengine.core.world.World world = new BukkitWorld(entity.getWorld()); + Vec3d vec3d = new Vec3d(location.getBlockX() + 0.5, location.getBlockY() + 0.5, location.getBlockZ() + 0.5); + ContextHolder.Builder builder = ContextHolder.builder(); + builder.withParameter(LootParameters.WORLD, world); + builder.withParameter(LootParameters.LOCATION, vec3d); + if (VersionHelper.isVersionNewerThan1_20_5()) { + if (event.getDamageSource().getCausingEntity() instanceof Player player) { + BukkitServerPlayer serverPlayer = this.plugin.adapt(player); + builder.withParameter(LootParameters.PLAYER, serverPlayer); + builder.withOptionalParameter(LootParameters.TOOL, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)); + } + } + ContextHolder contextHolder = builder.build(); + for (LootTable lootTable : loot.lootTables()) { + for (Item item : lootTable.getRandomItems(contextHolder, world)) { + world.dropItemNaturally(vec3d, item); + } + } + }); + } + @Override public void parseSection(Pack pack, Path path, Key id, Map section) { String type = (String) section.get("type"); @@ -68,6 +130,14 @@ public class BukkitVanillaLootManager implements VanillaLootManager { } } } + case ENTITY -> { + for (String target : targets) { + Key key = Key.of(target); + VanillaLoot vanillaLoot = this.entityLoots.computeIfAbsent(key, k -> new VanillaLoot(VanillaLoot.Type.ENTITY)); + vanillaLoot.addLootTable(lootTable); + if (override) vanillaLoot.override(true); + } + } } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLoot.java b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLoot.java index caf3bd6cc..3d9d75870 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLoot.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLoot.java @@ -35,6 +35,7 @@ public class VanillaLoot { } public enum Type { - BLOCK + BLOCK, + ENTITY } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java index f0f4eff95..4fc6d33ee 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/VanillaLootManager.java @@ -19,5 +19,7 @@ public interface VanillaLootManager extends ConfigSectionParser, Reloadable { return CONFIG_SECTION_NAME; } + void delayedInit(); + Optional getBlockLoot(int blockState); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java index d31706cac..7937e1da9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/CraftEngine.java @@ -134,6 +134,7 @@ public abstract class CraftEngine implements Plugin { this.packManager.delayedInit(); this.furnitureManager.delayedInit(); this.imageManager.delayedInit(); + this.vanillaLootManager.delayedInit(); }); } @@ -153,6 +154,7 @@ public abstract class CraftEngine implements Plugin { if (this.itemBrowserManager != null) this.itemBrowserManager.disable(); if (this.guiManager != null) this.guiManager.disable(); if (this.soundManager != null) this.soundManager.disable(); + if (this.vanillaLootManager != null) this.vanillaLootManager.disable(); if (this.scheduler != null) this.scheduler.shutdownScheduler(); if (this.scheduler != null) this.scheduler.shutdownExecutor(); ResourcePackHost.instance().disable();