Added pet protections. Tweaked drop protections.

This commit is contained in:
ryanhamshire 2014-12-16 21:00:42 -08:00
parent 2d94e6fdc7
commit 528fda95ff
5 changed files with 180 additions and 72 deletions

View File

@ -18,11 +18,14 @@
package me.ryanhamshire.GriefPrevention;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
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;
@ -32,10 +35,12 @@ import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Explosive;
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.Tameable;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler;
@ -58,6 +63,7 @@ import org.bukkit.event.hanging.HangingBreakEvent.RemoveCause;
import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.vehicle.VehicleDamageEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.FixedMetadataValue;
//handles events related to entities
class EntityEventHandler implements Listener
@ -181,6 +187,49 @@ class EntityEventHandler implements Listener
{
event.setCancelled(true);
}
//if item is on watch list, apply protection
ArrayList<PendingItemProtection> watchList = GriefPrevention.instance.pendingItemWatchList;
Item newItem = event.getEntity();
Long now = null;
for(int i = 0; i < watchList.size(); i++)
{
PendingItemProtection pendingProtection = watchList.get(i);
//ignore and remove any expired pending protections
if(now == null) now = System.currentTimeMillis();
if(pendingProtection.expirationTimestamp < now)
{
watchList.remove(i--);
continue;
}
//skip if item stack doesn't match
if(pendingProtection.itemStack.getAmount() != newItem.getItemStack().getAmount() ||
pendingProtection.itemStack.getType() != newItem.getItemStack().getType())
{
continue;
}
//skip if new item location isn't near the expected spawn area
Location spawn = event.getLocation();
Location expected = pendingProtection.location;
if(!spawn.getWorld().equals(expected.getWorld()) ||
spawn.getX() < expected.getX() - 5 ||
spawn.getX() > expected.getX() + 5 ||
spawn.getZ() < expected.getZ() - 5 ||
spawn.getZ() > expected.getZ() + 5 ||
spawn.getY() < expected.getY() - 15 ||
spawn.getY() > expected.getY() + 3)
{
continue;
}
//otherwise, mark item with protection information
newItem.setMetadata("GP_ITEMOWNER", new FixedMetadataValue(GriefPrevention.instance, pendingProtection.owner));
//and remove pending protection data
watchList.remove(i);
break;
}
}
//when an experience bottle explodes...
@ -219,36 +268,11 @@ class EntityEventHandler implements Listener
}
//when an entity dies...
@EventHandler
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent event)
{
LivingEntity entity = event.getEntity();
//FEATURE: lock dropped items to player who dropped them
if(entity instanceof Player)
{
Player player = (Player)entity;
World world = entity.getWorld();
//decide whether or not to apply this feature to this situation (depends on the world wher it happens)
boolean isPvPWorld = GriefPrevention.instance.config_pvp_enabledWorlds.contains(world);
if((isPvPWorld && GriefPrevention.instance.config_lockDeathDropsInPvpWorlds) ||
(!isPvPWorld && GriefPrevention.instance.config_lockDeathDropsInNonPvpWorlds))
{
//mark the dropped stacks with player's UUID
List<ItemStack> drops = event.getDrops();
for(ItemStack stack : drops)
{
GriefPrevention.instance.itemStackOwnerMap.put(stack, new ItemStackOwnerInfo(player.getUniqueId(), player.getLocation()));
}
//allow the player to receive a message about how to unlock any drops
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.receivedDropUnlockAdvertisement = false;
}
}
//don't do the rest in worlds where claims are not enabled
if(!GriefPrevention.instance.claimsEnabledForWorld(entity.getWorld())) return;
@ -276,6 +300,31 @@ class EntityEventHandler implements Listener
//end it, with the dieing player being the loser
this.dataStore.endSiege(playerData.siegeData, null, player.getName(), true /*ended due to death*/);
}
//FEATURE: lock dropped items to player who dropped them
World world = entity.getWorld();
//decide whether or not to apply this feature to this situation (depends on the world where it happens)
boolean isPvPWorld = GriefPrevention.instance.config_pvp_enabledWorlds.contains(world);
if((isPvPWorld && GriefPrevention.instance.config_lockDeathDropsInPvpWorlds) ||
(!isPvPWorld && GriefPrevention.instance.config_lockDeathDropsInNonPvpWorlds))
{
//remember information about these drops so that they can be marked when they spawn as items
long expirationTime = System.currentTimeMillis() + 3000; //now + 3 seconds
Location deathLocation = player.getLocation();
UUID playerID = player.getUniqueId();
List<ItemStack> drops = event.getDrops();
for(ItemStack stack : drops)
{
GriefPrevention.instance.pendingItemWatchList.add(
new PendingItemProtection(deathLocation, playerID, expirationTime, stack));
}
//allow the player to receive a message about how to unlock any drops
playerData.dropsAreUnlocked = false;
playerData.receivedDropUnlockAdvertisement = false;
}
}
//when an entity picks up an item
@ -527,6 +576,33 @@ class EntityEventHandler implements Listener
//if the entity is an non-monster creature (remember monsters disqualified above), or a vehicle
if ((subEvent.getEntity() instanceof Creature && GriefPrevention.instance.config_claims_protectCreatures))
{
//if entity is tameable and has an owner, apply special rules
if(subEvent.getEntity() instanceof Tameable)
{
Tameable tameable = (Tameable)subEvent.getEntity();
if(tameable.isTamed() && tameable.getOwner() != null)
{
UUID ownerID = tameable.getOwner().getUniqueId();
//if the player interacting is the owner, always allow
if(attacker.getUniqueId().equals(ownerID)) return;
//otherwise disallow in non-pvp worlds
if(!GriefPrevention.instance.config_pvp_enabledWorlds.contains(subEvent.getEntity().getLocation().getWorld()))
{
OfflinePlayer owner = GriefPrevention.instance.getServer().getOfflinePlayer(ownerID);
String ownerName = owner.getName();
if(ownerName == null) ownerName = "someone";
String message = GriefPrevention.instance.dataStore.getMessage(Messages.NoDamageClaimedEntity, ownerName);
if(attacker.hasPermission("griefprevention.ignoreclaims"))
message += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
GriefPrevention.sendMessage(attacker, TextMode.Err, message);
event.setCancelled(true);
return;
}
}
}
Claim cachedClaim = null;
PlayerData playerData = null;

View File

@ -42,6 +42,7 @@ import org.bukkit.block.Block;
import org.bukkit.command.*;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
@ -60,9 +61,6 @@ public class GriefPrevention extends JavaPlugin
//this handles data storage, like player and region data
public DataStore dataStore;
//this remembers which item stacks dropped in the world belong to which players
ConcurrentHashMap<ItemStack, ItemStackOwnerInfo> itemStackOwnerMap = new ConcurrentHashMap<ItemStack, ItemStackOwnerInfo>();
//configuration variables, loaded/saved from a config.yml
//claim mode for each world
@ -2292,8 +2290,8 @@ public class GriefPrevention extends JavaPlugin
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.pvpImmune = true;
//inform the player
GriefPrevention.sendMessage(player, TextMode.Success, Messages.PvPImmunityStart);
//inform the player after he finishes respawning
GriefPrevention.sendMessage(player, TextMode.Success, Messages.PvPImmunityStart, 5L);
}
//checks whether players siege in a world
@ -2558,4 +2556,7 @@ public class GriefPrevention extends JavaPlugin
return overrideValue;
}
}
//this tracks item stacks expected to drop which will need protection
ArrayList<PendingItemProtection> pendingItemWatchList = new ArrayList<PendingItemProtection>();
}

View File

@ -1,17 +0,0 @@
package me.ryanhamshire.GriefPrevention;
import java.util.UUID;
import org.bukkit.Location;
//tracks an item stack's owner. ownership is limited to a locality due to problems with hash overlaps overprotecting item stacks
class ItemStackOwnerInfo
{
public UUID ownerID;
public Location locality;
public ItemStackOwnerInfo(UUID ownerID, Location location)
{
this.ownerID = ownerID;
this.locality = location;
}
}

View File

@ -0,0 +1,21 @@
package me.ryanhamshire.GriefPrevention;
import java.util.UUID;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
class PendingItemProtection
{
public Location location;
public UUID owner;
long expirationTimestamp;
ItemStack itemStack;
public PendingItemProtection(Location location, UUID owner, long expirationTimestamp, ItemStack itemStack)
{
this.location = location;
this.owner = owner;
this.expirationTimestamp = expirationTimestamp;
this.itemStack = itemStack;
}
}

View File

@ -44,7 +44,9 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Horse;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.entity.Tameable;
import org.bukkit.entity.Vehicle;
import org.bukkit.entity.minecart.PoweredMinecart;
import org.bukkit.entity.minecart.StorageMinecart;
@ -58,6 +60,7 @@ import org.bukkit.event.player.PlayerLoginEvent.Result;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.util.BlockIterator;
class PlayerEventHandler implements Listener
@ -596,7 +599,6 @@ class PlayerEventHandler implements Listener
Player player = event.getPlayer();
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId());
playerData.lastSpawn = Calendar.getInstance().getTimeInMillis();
GriefPrevention.instance.checkPvpProtectionNeeded(player);
//also send him any messaged from grief prevention he would have received while dead
if(playerData.messageOnRespawn != null)
@ -604,6 +606,8 @@ class PlayerEventHandler implements Listener
GriefPrevention.sendMessage(player, ChatColor.RESET /*color is alrady embedded in message in this case*/, playerData.messageOnRespawn, 40L);
playerData.messageOnRespawn = null;
}
GriefPrevention.instance.checkPvpProtectionNeeded(player);
}
//when a player dies...
@ -806,8 +810,11 @@ class PlayerEventHandler implements Listener
public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event)
{
//treat it the same as interacting with an entity in general
if(event.getRightClicked().getType() == EntityType.ARMOR_STAND)
{
this.onPlayerInteractEntity((PlayerInteractEntityEvent)event);
}
}
//when a player interacts with an entity...
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
@ -835,6 +842,9 @@ class PlayerEventHandler implements Listener
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
//always allow interactions when player is in ignore claims mode
if(playerData.ignoreClaims) return;
//don't allow container access during pvp combat
if((entity instanceof StorageMinecart || entity instanceof PoweredMinecart))
{
@ -853,6 +863,30 @@ class PlayerEventHandler implements Listener
}
}
//if entity is tameable and has an owner, apply special rules
if(entity instanceof Tameable && !GriefPrevention.instance.config_pvp_enabledWorlds.contains(entity.getLocation().getWorld()))
{
Tameable tameable = (Tameable)entity;
if(tameable.isTamed() && tameable.getOwner() != null)
{
UUID ownerID = tameable.getOwner().getUniqueId();
//if the player interacting is the owner, always allow
if(player.getUniqueId().equals(ownerID)) return;
//otherwise disallow
OfflinePlayer owner = GriefPrevention.instance.getServer().getOfflinePlayer(ownerID);
String ownerName = owner.getName();
if(ownerName == null) ownerName = "someone";
String message = GriefPrevention.instance.dataStore.getMessage(Messages.NoDamageClaimedEntity, ownerName);
if(player.hasPermission("griefprevention.ignoreclaims"))
message += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
GriefPrevention.sendMessage(player, TextMode.Err, message);
event.setCancelled(true);
return;
}
}
//if the entity is a vehicle and we're preventing theft in claims
if(GriefPrevention.instance.config_claims_preventTheft && entity instanceof Vehicle)
{
@ -868,6 +902,7 @@ class PlayerEventHandler implements Listener
{
GriefPrevention.sendMessage(player, TextMode.Err, noContainersReason);
event.setCancelled(true);
return;
}
}
@ -879,6 +914,7 @@ class PlayerEventHandler implements Listener
{
player.sendMessage(noAccessReason);
event.setCancelled(true);
return;
}
}
}
@ -898,6 +934,7 @@ class PlayerEventHandler implements Listener
message += " " + GriefPrevention.instance.dataStore.getMessage(Messages.IgnoreClaimsAdvertisement);
GriefPrevention.sendMessage(player, TextMode.Err, message);
event.setCancelled(true);
return;
}
}
}
@ -928,25 +965,21 @@ class PlayerEventHandler implements Listener
//FEATURE: lock dropped items to player who dropped them
//who owns this stack?
ItemStack stack = event.getItem().getItemStack();
ItemStackOwnerInfo ownerInfo = GriefPrevention.instance.itemStackOwnerMap.get(stack);
if(ownerInfo != null)
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 = GriefPrevention.instance.getServer().getOfflinePlayer(ownerInfo.ownerID);
String ownerName = GriefPrevention.lookupPlayerName(ownerInfo.ownerID);
OfflinePlayer owner = GriefPrevention.instance.getServer().getOfflinePlayer(ownerID);
String ownerName = GriefPrevention.lookupPlayerName(ownerID);
if(owner.isOnline() && !player.equals(owner))
{
PlayerData playerData = this.dataStore.getPlayerData(ownerInfo.ownerID);
Location location = event.getItem().getLocation();
PlayerData playerData = this.dataStore.getPlayerData(ownerID);
//if locked and in locality of protection, don't allow pickup
if(!playerData.dropsAreUnlocked
&& location.getX() > ownerInfo.locality.getX() - 10
&& location.getX() < ownerInfo.locality.getX() + 10
&& location.getZ() < ownerInfo.locality.getZ() + 10
&& location.getZ() > ownerInfo.locality.getZ() - 10
&& location.getY() < ownerInfo.locality.getY() + 5)
//if locked, don't allow pickup
if(!playerData.dropsAreUnlocked)
{
event.setCancelled(true);
@ -959,12 +992,6 @@ class PlayerEventHandler implements Listener
}
}
}
//if allowed to pick up, remove from ownership map
if(!event.isCancelled())
{
GriefPrevention.instance.itemStackOwnerMap.remove(stack);
}
}
//the rest of this code is specific to pvp worlds