From 5686c4db9d287f878528cf8e4e2fe561f5200ace Mon Sep 17 00:00:00 2001 From: Brettflan Date: Wed, 20 Jul 2011 12:22:03 -0500 Subject: [PATCH] Piston movement is now prevented if it encroaches across into territories which have the relevant DenyBuild option set (whether faction territory, safe zone, or war zone). This covers piston extension if it pushes across unacceptable borders or even if the piston head itself would cross over, and also prevents sticky pistons from pulling blocks back across such borders. There is also a new conf.json option "pistonProtectionThroughDenyBuild" (default true) which can be disabled to turn off piston protection. This option is available due to the (untested) potential that a world with many pistons constantly repeatedly firing could result in additional lag from these piston protection events --- src/com/massivecraft/factions/Conf.java | 4 +- src/com/massivecraft/factions/Factions.java | 2 + .../listeners/FactionsBlockListener.java | 91 ++++++++++++++++++- 3 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/com/massivecraft/factions/Conf.java b/src/com/massivecraft/factions/Conf.java index 70fb2cdc..877c49e3 100644 --- a/src/com/massivecraft/factions/Conf.java +++ b/src/com/massivecraft/factions/Conf.java @@ -109,7 +109,9 @@ public class Conf { public static boolean wildernessBlockFireballs = false; public static boolean wildernessBlockTNT = false; public static boolean wildernessPowerLoss = true; - + + public static boolean pistonProtectionThroughDenyBuild = true; + public static Set territoryProtectedMaterials = EnumSet.noneOf(Material.class); public static Set territoryDenyUseageMaterials = EnumSet.noneOf(Material.class); public static Set territoryProtectedMaterialsWhenOffline = EnumSet.noneOf(Material.class); diff --git a/src/com/massivecraft/factions/Factions.java b/src/com/massivecraft/factions/Factions.java index be3eee40..06dc81f6 100644 --- a/src/com/massivecraft/factions/Factions.java +++ b/src/com/massivecraft/factions/Factions.java @@ -143,6 +143,8 @@ public class Factions extends JavaPlugin { pm.registerEvent(Event.Type.BLOCK_BREAK, this.blockListener, Event.Priority.Normal, this); pm.registerEvent(Event.Type.BLOCK_DAMAGE, this.blockListener, Event.Priority.Normal, this); pm.registerEvent(Event.Type.BLOCK_PLACE, this.blockListener, Event.Priority.Normal, this); + pm.registerEvent(Event.Type.BLOCK_PISTON_EXTEND, this.blockListener, Event.Priority.Normal, this); + pm.registerEvent(Event.Type.BLOCK_PISTON_RETRACT, this.blockListener, Event.Priority.Normal, this); // Register recurring tasks long saveTicks = 20 * 60 * 30; // Approximately every 30 min diff --git a/src/com/massivecraft/factions/listeners/FactionsBlockListener.java b/src/com/massivecraft/factions/listeners/FactionsBlockListener.java index f9afd467..384010c2 100644 --- a/src/com/massivecraft/factions/listeners/FactionsBlockListener.java +++ b/src/com/massivecraft/factions/listeners/FactionsBlockListener.java @@ -1,5 +1,6 @@ package com.massivecraft.factions.listeners; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -7,6 +8,8 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockDamageEvent; import org.bukkit.event.block.BlockListener; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; import com.massivecraft.factions.Board; import com.massivecraft.factions.Conf; @@ -57,7 +60,93 @@ public class FactionsBlockListener extends BlockListener { event.setCancelled(true); } } - + + @Override + public void onBlockPistonExtend(BlockPistonExtendEvent event) { + if (event.isCancelled() || !Conf.pistonProtectionThroughDenyBuild) { + return; + } + + Faction pistonFaction = Board.getFactionAt(new FLocation(event.getBlock())); + + // target end-of-the-line empty (air) block which is being pushed into, including if piston itself would extend into air + Block targetBlock = event.getBlock().getRelative(event.getDirection(), event.getLength() + 1); + + // if potentially pushing into air in another territory, we need to check it out + if (targetBlock.isEmpty() && !canPistonMoveBlock(pistonFaction, targetBlock.getLocation())) { + event.setCancelled(true); + return; + } + + /* + * note that I originally was testing the territory of each affected block, but since I found that pistons can only push + * up to 12 blocks and the width of any territory is 16 blocks, it should be safe (and much more lightweight) to test + * only the final target block as done above + */ + } + + @Override + public void onBlockPistonRetract(BlockPistonRetractEvent event) { + // if not a sticky piston, retraction should be fine + if (event.isCancelled() || !event.isSticky() || !Conf.pistonProtectionThroughDenyBuild) { + return; + } + + Location targetLoc = event.getRetractLocation(); + + // if potentially retracted block is just air, no worries + if (targetLoc.getBlock().isEmpty()) { + return; + } + + Faction pistonFaction = Board.getFactionAt(new FLocation(event.getBlock())); + + if (!canPistonMoveBlock(pistonFaction, targetLoc)) { + event.setCancelled(true); + return; + } + } + + private boolean canPistonMoveBlock(Faction pistonFaction, Location target) { + + Faction otherFaction = Board.getFactionAt(new FLocation(target)); + + if (pistonFaction == otherFaction) { + return true; + } + + if (otherFaction.isNone()) { + if (!Conf.wildernessDenyBuild) { + return true; + } + return false; + } + else if (otherFaction.isSafeZone()) { + if (!Conf.safeZoneDenyBuild) { + return true; + } + return false; + } + else if (otherFaction.isWarZone()) { + if (!Conf.warZoneDenyBuild) { + return true; + } + return false; + } + + boolean areEnemies = pistonFaction.getRelation(otherFaction).isEnemy(); + boolean online = otherFaction.hasPlayersOnline(); + + if ( + (online && (areEnemies ? Conf.territoryEnemyDenyBuild : Conf.territoryDenyBuild)) + || (!online && (areEnemies ? Conf.territoryEnemyDenyBuildWhenOffline : Conf.territoryDenyBuildWhenOffline)) + ) { + return false; + } + + return true; + } + public boolean playerCanBuildDestroyBlock(Player player, Block block, String action) { if (Conf.adminBypassPlayers.contains(player.getName())) {