diff --git a/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java b/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java index df80a24..a574afa 100644 --- a/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java +++ b/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java @@ -420,22 +420,36 @@ public class BlockEventHandler implements Listener block.getY() > GriefPrevention.instance.getSeaLevel(block.getWorld()) - 5) { GriefPrevention.sendMessage(player, TextMode.Warn, Messages.NoTNTDamageAboveSeaLevel); - } + } + + //warn players about disabled pistons outside of land claims + if( GriefPrevention.instance.config_pistonsInClaimsOnly && + (block.getType() == Material.PISTON_BASE || block.getType() == Material.PISTON_STICKY_BASE) && + claim == null ) + { + GriefPrevention.sendMessage(player, TextMode.Warn, Messages.NoPistonsOutsideClaims); + } } //blocks "pushing" other players' blocks around (pistons) @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onBlockPistonExtend (BlockPistonExtendEvent event) { - List blocks = event.getBlocks(); + //pushing down is ALWAYS safe + if(event.getDirection() == BlockFace.DOWN) return; + + Block pistonBlock = event.getBlock(); + List blocks = event.getBlocks(); //if no blocks moving, then only check to make sure we're not pushing into a claim from outside //this avoids pistons breaking non-solids just inside a claim, like torches, doors, and touchplates if(blocks.size() == 0) { - Block pistonBlock = event.getBlock(); Block invadedBlock = pistonBlock.getRelative(event.getDirection()); + //pushing "air" is harmless + if(invadedBlock.getType() == Material.AIR) return; + if( this.dataStore.getClaimAt(pistonBlock.getLocation(), false, null) == null && this.dataStore.getClaimAt(invadedBlock.getLocation(), false, null) != null) { @@ -450,68 +464,81 @@ public class BlockEventHandler implements Listener Claim claim = this.dataStore.getClaimAt(event.getBlock().getLocation(), false, null); if(claim != null) pistonClaimOwnerName = claim.getOwnerName(); - //which blocks are being pushed? - for(int i = 0; i < blocks.size(); i++) + //if pistons are limited to same-claim block movement + if(GriefPrevention.instance.config_pistonsInClaimsOnly) { - //if ANY of the pushed blocks are owned by someone other than the piston owner, cancel the event - Block block = blocks.get(i); - claim = this.dataStore.getClaimAt(block.getLocation(), false, null); - if(claim != null && !claim.getOwnerName().equals(pistonClaimOwnerName)) - { - event.setCancelled(true); - event.getBlock().getWorld().createExplosion(event.getBlock().getLocation(), 0); - event.getBlock().getWorld().dropItem(event.getBlock().getLocation(), new ItemStack(event.getBlock().getType())); - event.getBlock().setType(Material.AIR); - return; - } + //if piston is not in a land claim, cancel event + if(claim == null) + { + event.setCancelled(true); + return; + } + + for(Block pushedBlock : event.getBlocks()) + { + //if pushing blocks located outside the land claim it lives in, cancel the event + if(!claim.contains(pushedBlock.getLocation(), false, false)) + { + event.setCancelled(true); + return; + } + + //if pushing a block inside the claim out of the claim, cancel the event + //reason: could push into another land claim, don't want to spend CPU checking for that + //reason: push ice out, place torch, get water outside the claim + if(!claim.contains(pushedBlock.getRelative(event.getDirection()).getLocation(), false, false)) + { + event.setCancelled(true); + return; + } + } } - //which direction? note we're ignoring vertical push - int xchange = 0; - int zchange = 0; - - Block piston = event.getBlock(); - Block firstBlock = blocks.get(0); - - if(firstBlock.getX() > piston.getX()) + //otherwise, consider ownership of piston and EACH pushed block + else { - xchange = 1; - } - else if(firstBlock.getX() < piston.getX()) - { - xchange = -1; - } - else if(firstBlock.getZ() > piston.getZ()) - { - zchange = 1; - } - else if(firstBlock.getZ() < piston.getZ()) - { - zchange = -1; - } - - //if horizontal movement - if(xchange != 0 || zchange != 0) - { - for(int i = 0; i < blocks.size(); i++) + //which blocks are being pushed? + Claim cachedClaim = claim; + for(int i = 0; i < blocks.size(); i++) + { + //if ANY of the pushed blocks are owned by someone other than the piston owner, cancel the event + Block block = blocks.get(i); + claim = this.dataStore.getClaimAt(block.getLocation(), false, cachedClaim); + if(claim != null) + { + cachedClaim = claim; + if(!claim.getOwnerName().equals(pistonClaimOwnerName)) + { + event.setCancelled(true); + event.getBlock().getWorld().createExplosion(event.getBlock().getLocation(), 0); + event.getBlock().getWorld().dropItem(event.getBlock().getLocation(), new ItemStack(event.getBlock().getType())); + event.getBlock().setType(Material.AIR); + return; + } + } + } + + //if any of the blocks are being pushed into a claim from outside, cancel the event + for(int i = 0; i < blocks.size(); i++) { Block block = blocks.get(i); - Claim originalClaim = this.dataStore.getClaimAt(block.getLocation(), false, null); + Claim originalClaim = this.dataStore.getClaimAt(block.getLocation(), false, cachedClaim); String originalOwnerName = ""; if(originalClaim != null) { - originalOwnerName = originalClaim.getOwnerName(); + cachedClaim = originalClaim; + originalOwnerName = originalClaim.getOwnerName(); } - Claim newClaim = this.dataStore.getClaimAt(block.getLocation().add(xchange, 0, zchange), false, null); + Claim newClaim = this.dataStore.getClaimAt(block.getRelative(event.getDirection()).getLocation(), false, cachedClaim); String newOwnerName = ""; if(newClaim != null) { - newOwnerName = newClaim.getOwnerName(); + newOwnerName = newClaim.getOwnerName(); } //if pushing this block will change ownership, cancel the event and take away the piston (for performance reasons) - if(!newOwnerName.equals(originalOwnerName)) + if(!newOwnerName.equals(originalOwnerName) && !newOwnerName.isEmpty()) { event.setCancelled(true); event.getBlock().getWorld().createExplosion(event.getBlock().getLocation(), 0); @@ -519,7 +546,6 @@ public class BlockEventHandler implements Listener event.getBlock().setType(Material.AIR); return; } - } } } @@ -528,26 +554,55 @@ public class BlockEventHandler implements Listener @EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST) public void onBlockPistonRetract (BlockPistonRetractEvent event) { - //we only care about sticky pistons + //we only care about sticky pistons retracting if(!event.isSticky()) return; - - //who owns the moving block, if anyone? - String movingBlockOwnerName = "_"; - Claim movingBlockClaim = this.dataStore.getClaimAt(event.getRetractLocation(), false, null); - if(movingBlockClaim != null) movingBlockOwnerName = movingBlockClaim.getOwnerName(); - //who owns the piston, if anyone? - String pistonOwnerName = "_"; - Location pistonLocation = event.getBlock().getLocation(); - Claim pistonClaim = this.dataStore.getClaimAt(pistonLocation, false, null); - if(pistonClaim != null) pistonOwnerName = pistonClaim.getOwnerName(); + //pulling up is always safe + if(event.getDirection() == BlockFace.UP) return; - //if there are owners for the blocks, they must be the same player - //otherwise cancel the event - if(!pistonOwnerName.equals(movingBlockOwnerName)) + //if pulling "air", always safe + if(event.getRetractLocation().getBlock().getType() == Material.AIR) return; + + //if pistons limited to only pulling blocks which are in the same claim the piston is in + if(GriefPrevention.instance.config_pistonsInClaimsOnly) { - event.setCancelled(true); - } + //if piston not in a land claim, cancel event + Claim pistonClaim = this.dataStore.getClaimAt(event.getBlock().getLocation(), false, null); + if(pistonClaim == null) + { + event.setCancelled(true); + return; + } + + //if pulled block isn't in the same land claim, cancel the event + if(!pistonClaim.contains(event.getRetractLocation(), false, false)) + { + event.setCancelled(true); + return; + } + } + + //otherwise, consider ownership of both piston and block + else + { + //who owns the moving block, if anyone? + String movingBlockOwnerName = "_"; + Claim movingBlockClaim = this.dataStore.getClaimAt(event.getRetractLocation(), false, null); + if(movingBlockClaim != null) movingBlockOwnerName = movingBlockClaim.getOwnerName(); + + //who owns the piston, if anyone? + String pistonOwnerName = "_"; + Location pistonLocation = event.getBlock().getLocation(); + Claim pistonClaim = this.dataStore.getClaimAt(pistonLocation, false, movingBlockClaim); + if(pistonClaim != null) pistonOwnerName = pistonClaim.getOwnerName(); + + //if there are owners for the blocks, they must be the same player + //otherwise cancel the event + if(!pistonOwnerName.equals(movingBlockOwnerName)) + { + event.setCancelled(true); + } + } } //blocks are ignited ONLY by flint and steel (not by being near lava, open flames, etc), unless configured otherwise diff --git a/src/me/ryanhamshire/GriefPrevention/DataStore.java b/src/me/ryanhamshire/GriefPrevention/DataStore.java index 1f5c6a2..18b7dff 100644 --- a/src/me/ryanhamshire/GriefPrevention/DataStore.java +++ b/src/me/ryanhamshire/GriefPrevention/DataStore.java @@ -1007,6 +1007,7 @@ public abstract class DataStore this.addDefault(defaults, Messages.ExplosivesEnabled, "This claim is now vulnerable to explosions. Use /ClaimExplosions again to re-enable protections.", null); this.addDefault(defaults, Messages.ClaimExplosivesAdvertisement, "To allow explosives to destroy blocks in this land claim, use /ClaimExplosions.", null); this.addDefault(defaults, Messages.PlayerInPvPSafeZone, "That player is in a PvP safe zone.", null); + this.addDefault(defaults, Messages.NoPistonsOutsideClaims, "Warning: Pistons won't move blocks outside land claims.", null); //load the config file FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath)); diff --git a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java index 15dd1e9..2af6a93 100644 --- a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -154,6 +154,7 @@ public class GriefPrevention extends JavaPlugin public HashMap config_seaLevelOverride; //override for sea level, because bukkit doesn't report the right value for all situations public boolean config_limitTreeGrowth; //whether trees should be prevented from growing into a claim from outside + public boolean config_pistonsInClaimsOnly; //whether pistons are limited to only move blocks located within the piston's land claim //reference to the economy plugin, if economy integration is enabled public static Economy economy = null; @@ -354,6 +355,7 @@ public class GriefPrevention extends JavaPlugin this.config_blockWildernessWaterBuckets = config.getBoolean("GriefPrevention.LimitSurfaceWaterBuckets", true); this.config_blockSkyTrees = config.getBoolean("GriefPrevention.LimitSkyTrees", true); this.config_limitTreeGrowth = config.getBoolean("GriefPrevention.LimitTreeGrowth", false); + this.config_pistonsInClaimsOnly = config.getBoolean("GriefPrevention.LimitPistonsToLandClaims", true); this.config_fireSpreads = config.getBoolean("GriefPrevention.FireSpreads", false); this.config_fireDestroys = config.getBoolean("GriefPrevention.FireDestroys", false); @@ -601,6 +603,7 @@ public class GriefPrevention extends JavaPlugin outConfig.set("GriefPrevention.LimitSurfaceWaterBuckets", this.config_blockWildernessWaterBuckets); outConfig.set("GriefPrevention.LimitSkyTrees", this.config_blockSkyTrees); outConfig.set("GriefPrevention.LimitTreeGrowth", this.config_limitTreeGrowth); + outConfig.set("GriefPrevention.LimitPistonsToLandClaims", this.config_pistonsInClaimsOnly); outConfig.set("GriefPrevention.FireSpreads", this.config_fireSpreads); outConfig.set("GriefPrevention.FireDestroys", this.config_fireDestroys); diff --git a/src/me/ryanhamshire/GriefPrevention/Messages.java b/src/me/ryanhamshire/GriefPrevention/Messages.java index 727da36..e7e7efd 100644 --- a/src/me/ryanhamshire/GriefPrevention/Messages.java +++ b/src/me/ryanhamshire/GriefPrevention/Messages.java @@ -20,5 +20,5 @@ package me.ryanhamshire.GriefPrevention; public enum Messages { - RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionVideo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsVideo, SurvivalBasicsVideo, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, UntrustOwnerOnly, HowToClaimRegex, NoBuildOutsideClaims, PlayerOfflineTime, BuildingOutsideClaims, TrappedWontWorkHere, CommandBannedInPvP, UnclaimCleanupWarning, BuySellNotConfigured, NoTeleportPvPCombat, NoTNTDamageAboveSeaLevel, NoTNTDamageClaims, IgnoreClaimsAdvertisement, NoPermissionForCommand, ClaimsListNoPermission, ExplosivesDisabled, ExplosivesEnabled, ClaimExplosivesAdvertisement, PlayerInPvPSafeZone + RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionVideo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsVideo, SurvivalBasicsVideo, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, UntrustOwnerOnly, HowToClaimRegex, NoBuildOutsideClaims, PlayerOfflineTime, BuildingOutsideClaims, TrappedWontWorkHere, CommandBannedInPvP, UnclaimCleanupWarning, BuySellNotConfigured, NoTeleportPvPCombat, NoTNTDamageAboveSeaLevel, NoTNTDamageClaims, IgnoreClaimsAdvertisement, NoPermissionForCommand, ClaimsListNoPermission, ExplosivesDisabled, ExplosivesEnabled, ClaimExplosivesAdvertisement, PlayerInPvPSafeZone, NoPistonsOutsideClaims }