Skip to content

Commit

Permalink
Prevent passive mobs from picking up PvE death drops (#2071)
Browse files Browse the repository at this point in the history
* Remove deprecated PlayerPickupItemEvent and merge with entity logic
  • Loading branch information
Jikoo committed Jun 22, 2023
1 parent 79e7813 commit 13b57d6
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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<MetadataValue> 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);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<MetadataValue> 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)
Expand Down

0 comments on commit 13b57d6

Please sign in to comment.