From 13b57d693e347e9d5c964089f2014c55b15ecfca Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 22 Jun 2023 16:41:19 -0400 Subject: [PATCH] Prevent passive mobs from picking up PvE death drops (#2071) * Remove deprecated PlayerPickupItemEvent and merge with entity logic --- .../GriefPrevention/EntityEventHandler.java | 91 +++++++++++++++++++ .../GriefPrevention/PlayerEventHandler.java | 69 -------------- 2 files changed, 91 insertions(+), 69 deletions(-) diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java index 02ae8f823..118baa74a 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/EntityEventHandler.java @@ -22,6 +22,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.World.Environment; import org.bukkit.block.Block; @@ -30,6 +31,7 @@ import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Item; import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Monster; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; import org.bukkit.entity.Vehicle; @@ -45,6 +47,7 @@ import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityInteractEvent; +import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.entity.EntityPortalEnterEvent; import org.bukkit.event.entity.EntityPortalExitEvent; import org.bukkit.event.entity.ExpBottleEvent; @@ -54,15 +57,19 @@ import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.event.hanging.HangingBreakEvent.RemoveCause; import org.bukkit.event.hanging.HangingPlaceEvent; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.metadata.MetadataValue; import org.bukkit.projectiles.BlockProjectileSource; import org.bukkit.projectiles.ProjectileSource; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; +import java.util.Objects; import java.util.UUID; import java.util.function.Supplier; @@ -680,4 +687,88 @@ else if (GriefPrevention.instance.creativeRulesApply(event.getEntity().getLocati } } + @EventHandler + public void onEntityPickUpItem(@NotNull EntityPickupItemEvent event) + { + // Hostiles are allowed to equip death drops to preserve the challenge of item retrieval. + if (event.getEntity() instanceof Monster) return; + + Player player = null; + if (event.getEntity() instanceof Player) + { + player = (Player) event.getEntity(); + } + + //FEATURE: Lock dropped items to player who dropped them. + protectLockedDrops(event, player); + + // FEATURE: Protect freshly-spawned players from PVP. + preventPvpSpawnCamp(event, player); + } + + private void protectLockedDrops(@NotNull EntityPickupItemEvent event, @Nullable Player player) + { + Item item = event.getItem(); + List data = item.getMetadata("GP_ITEMOWNER"); + + // Ignore absent or invalid data. + if (data.isEmpty() || !(data.get(0).value() instanceof UUID ownerID)) return; + + // Get owner from stored UUID. + OfflinePlayer owner = instance.getServer().getOfflinePlayer(ownerID); + + // Owner must be online and can pick up their own drops. + if (!owner.isOnline() || Objects.equals(player, owner)) return; + + PlayerData playerData = this.dataStore.getPlayerData(ownerID); + + // If drops are unlocked, allow pick up. + if (playerData.dropsAreUnlocked) return; + + // Block pick up. + event.setCancelled(true); + + // Non-players (dolphins, allays) do not need to generate prompts. + if (player == null) + { + return; + } + + // If the owner hasn't been instructed how to unlock, send explanatory messages. + if (!playerData.receivedDropUnlockAdvertisement) + { + GriefPrevention.sendMessage(owner.getPlayer(), TextMode.Instr, Messages.DropUnlockAdvertisement); + GriefPrevention.sendMessage(player, TextMode.Err, Messages.PickupBlockedExplanation, GriefPrevention.lookupPlayerName(ownerID)); + playerData.receivedDropUnlockAdvertisement = true; + } + } + + private void preventPvpSpawnCamp(@NotNull EntityPickupItemEvent event, @Nullable Player player) + { + // This is specific to players in pvp worlds. + if (player == null || !instance.pvpRulesApply(player.getWorld())) return; + + //if we're preventing spawn camping and the player was previously empty handed... + if (instance.config_pvp_protectFreshSpawns && (instance.getItemInHand(player, EquipmentSlot.HAND).getType() == Material.AIR)) + { + //if that player is currently immune to pvp + PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); + if (playerData.pvpImmune) + { + //if it's been less than 10 seconds since the last time he spawned, don't pick up the item + long now = Calendar.getInstance().getTimeInMillis(); + long elapsedSinceLastSpawn = now - playerData.lastSpawn; + if (elapsedSinceLastSpawn < 10000) + { + event.setCancelled(true); + return; + } + + //otherwise take away his immunity. he may be armed now. at least, he's worth killing for some loot + playerData.pvpImmune = false; + GriefPrevention.sendMessage(player, TextMode.Warn, Messages.PvPImmunityEnd); + } + } + } + } diff --git a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java index 582bba2f1..65f89d82b 100644 --- a/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java +++ b/src/main/java/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java @@ -47,7 +47,6 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Fish; import org.bukkit.entity.Hanging; -import org.bukkit.entity.Item; import org.bukkit.entity.Llama; import org.bukkit.entity.Mule; import org.bukkit.entity.Player; @@ -78,7 +77,6 @@ import org.bukkit.event.player.PlayerKickEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; -import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerRespawnEvent; @@ -89,7 +87,6 @@ import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; @@ -1426,72 +1423,6 @@ public void onPlayerFish(PlayerFishEvent event) } } - //when a player picks up an item... - @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) - public void onPlayerPickupItem(PlayerPickupItemEvent event) - { - Player player = event.getPlayer(); - - //FEATURE: lock dropped items to player who dropped them - - //who owns this stack? - Item item = event.getItem(); - List data = item.getMetadata("GP_ITEMOWNER"); - if (data != null && data.size() > 0) - { - UUID ownerID = (UUID) data.get(0).value(); - - //has that player unlocked his drops? - OfflinePlayer owner = instance.getServer().getOfflinePlayer(ownerID); - String ownerName = GriefPrevention.lookupPlayerName(ownerID); - if (owner.isOnline() && !player.equals(owner)) - { - PlayerData playerData = this.dataStore.getPlayerData(ownerID); - - //if locked, don't allow pickup - if (!playerData.dropsAreUnlocked) - { - event.setCancelled(true); - - //if hasn't been instructed how to unlock, send explanatory messages - if (!playerData.receivedDropUnlockAdvertisement) - { - GriefPrevention.sendMessage(owner.getPlayer(), TextMode.Instr, Messages.DropUnlockAdvertisement); - GriefPrevention.sendMessage(player, TextMode.Err, Messages.PickupBlockedExplanation, ownerName); - playerData.receivedDropUnlockAdvertisement = true; - } - - return; - } - } - } - - //the rest of this code is specific to pvp worlds - if (!instance.pvpRulesApply(player.getWorld())) return; - - //if we're preventing spawn camping and the player was previously empty handed... - if (instance.config_pvp_protectFreshSpawns && (instance.getItemInHand(player, EquipmentSlot.HAND).getType() == Material.AIR)) - { - //if that player is currently immune to pvp - PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getUniqueId()); - if (playerData.pvpImmune) - { - //if it's been less than 10 seconds since the last time he spawned, don't pick up the item - long now = Calendar.getInstance().getTimeInMillis(); - long elapsedSinceLastSpawn = now - playerData.lastSpawn; - if (elapsedSinceLastSpawn < 10000) - { - event.setCancelled(true); - return; - } - - //otherwise take away his immunity. he may be armed now. at least, he's worth killing for some loot - playerData.pvpImmune = false; - GriefPrevention.sendMessage(player, TextMode.Warn, Messages.PvPImmunityEnd); - } - } - } - //when a player switches in-hand items @EventHandler(ignoreCancelled = true) public void onItemHeldChange(PlayerItemHeldEvent event)