From 336edd85be498ca2bdf9fb9dfd0e54d2cf021a3b Mon Sep 17 00:00:00 2001 From: Brettflan Date: Sun, 15 Jan 2012 11:41:13 -0600 Subject: [PATCH] when redstone torches or TNT were attempted to be placed in protected territory but prevented, it could previously still trigger a TNT explosion due to a longstanding unfixed CraftBukkit exploit. A workaround is now in place to prevent this, and any such attempts are logged and announced to everyone on the server. For reference: https://bukkit.atlassian.net/browse/BUKKIT-89 also, added missed new java file for chat spy --- .../massivecraft/factions/cmd/CmdChatSpy.java | 40 ++++++ .../listeners/FactionsBlockListener.java | 7 + .../listeners/FactionsChatEarlyListener.java | 4 +- .../listeners/FactionsEntityListener.java | 136 ++++++++++++++---- 4 files changed, 155 insertions(+), 32 deletions(-) create mode 100644 src/com/massivecraft/factions/cmd/CmdChatSpy.java diff --git a/src/com/massivecraft/factions/cmd/CmdChatSpy.java b/src/com/massivecraft/factions/cmd/CmdChatSpy.java new file mode 100644 index 00000000..b05c1aa7 --- /dev/null +++ b/src/com/massivecraft/factions/cmd/CmdChatSpy.java @@ -0,0 +1,40 @@ +package com.massivecraft.factions.cmd; + +import com.massivecraft.factions.P; +import com.massivecraft.factions.struct.Permission; + +public class CmdChatSpy extends FCommand +{ + public CmdChatSpy() + { + super(); + this.aliases.add("chatspy"); + + this.optionalArgs.put("on/off", "flip"); + + this.permission = Permission.CHATSPY.node; + this.disableOnLock = false; + + senderMustBePlayer = true; + senderMustBeMember = false; + senderMustBeModerator = false; + senderMustBeAdmin = false; + } + + @Override + public void perform() + { + fme.setSpyingChat(this.argAsBool(0, ! fme.isSpyingChat())); + + if ( fme.isSpyingChat()) + { + fme.msg("You have enabled chat spying mode."); + P.p.log(fme.getName() + " has ENABLED chat spying mode."); + } + else + { + fme.msg("You have disabled chat spying mode."); + P.p.log(fme.getName() + " DISABLED chat spying mode."); + } + } +} \ No newline at end of file diff --git a/src/com/massivecraft/factions/listeners/FactionsBlockListener.java b/src/com/massivecraft/factions/listeners/FactionsBlockListener.java index 6d3285b2..020d1b44 100644 --- a/src/com/massivecraft/factions/listeners/FactionsBlockListener.java +++ b/src/com/massivecraft/factions/listeners/FactionsBlockListener.java @@ -45,6 +45,13 @@ public class FactionsBlockListener extends BlockListener if ( ! playerCanBuildDestroyBlock(event.getPlayer(), event.getBlock().getLocation(), "build", false)) { event.setCancelled(true); + + Material handItem = event.getPlayer().getItemInHand().getType(); + if (handItem == Material.TNT || handItem == Material.REDSTONE_TORCH_ON) + { + Faction targetFaction = Board.getFactionAt(new FLocation(event.getBlock())); + FactionsEntityListener.trackPotentialExplosionExploit(event.getPlayer().getName(), targetFaction, handItem, event.getBlock().getLocation()); + } } } diff --git a/src/com/massivecraft/factions/listeners/FactionsChatEarlyListener.java b/src/com/massivecraft/factions/listeners/FactionsChatEarlyListener.java index 0a074ead..2148094d 100644 --- a/src/com/massivecraft/factions/listeners/FactionsChatEarlyListener.java +++ b/src/com/massivecraft/factions/listeners/FactionsChatEarlyListener.java @@ -50,13 +50,13 @@ public class FactionsChatEarlyListener extends PlayerListener String message = String.format(Conf.factionChatFormat, me.describeTo(myFaction), msg); myFaction.sendMessage(message); - P.p.log(Level.INFO, ChatColor.stripColor("FactionChat "+me.getFaction().getTag()+": "+message)); + P.p.log(Level.INFO, ChatColor.stripColor("FactionChat "+myFaction.getTag()+": "+message)); //Send to any players who are spying chat for (FPlayer fplayer : FPlayers.i.getOnline()) { if(fplayer.isSpyingChat() && fplayer.getFaction() != myFaction) - fplayer.sendMessage("[FCspy] "+me.getFaction().getTag()+": "+message); + fplayer.sendMessage("[FCspy] "+myFaction.getTag()+": "+message); } event.setCancelled(true); diff --git a/src/com/massivecraft/factions/listeners/FactionsEntityListener.java b/src/com/massivecraft/factions/listeners/FactionsEntityListener.java index b30bd91b..ccb3ad87 100644 --- a/src/com/massivecraft/factions/listeners/FactionsEntityListener.java +++ b/src/com/massivecraft/factions/listeners/FactionsEntityListener.java @@ -1,8 +1,11 @@ package com.massivecraft.factions.listeners; import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.logging.Level; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.entity.Creeper; import org.bukkit.entity.Entity; import org.bukkit.entity.Fireball; @@ -39,7 +42,9 @@ public class FactionsEntityListener extends EntityListener { this.p = p; } - + + private static ArrayList exploitExplosions = new ArrayList(); + @Override public void onEntityDeath(EntityDeathEvent event) { @@ -164,39 +169,76 @@ public class FactionsEntityListener extends EntityListener // ghast fireball which needs prevention event.setCancelled(true); } - else if - ( + else + { // TNT + if (exploitExplosions.size() > 0) + { // make sure this isn't a TNT explosion exploit attempt + int locX = event.getLocation().getBlockX(); + int locZ = event.getLocation().getBlockZ(); + + for (int i = exploitExplosions.size() - 1; i >= 0; i--) + { + PotentialExplosionExploit ex = exploitExplosions.get(i); + + // remove anything from the list older than 10 seconds (TNT takes 4 seconds to trigger; provide some leeway) + if (ex.timeMillis + 10000 < System.currentTimeMillis()) + { + exploitExplosions.remove(i); + continue; + } + + int absX = Math.abs(ex.X - locX); + int absZ = Math.abs(ex.Z - locZ); + if (absX < 5 && absZ < 5) + { // it sure looks like an exploit attempt + // let's tattle on him to everyone + String msg = "NOTICE: Player \""+ex.playerName+"\" attempted to exploit a TNT bug in the territory of \""+ex.faction.getTag()+"\" at "+ex.X+","+ex.Z+" (X,Z) using "+ex.item.name(); + P.p.log(Level.WARNING, msg); + for (FPlayer fplayer : FPlayers.i.getOnline()) + { + fplayer.sendMessage(msg); + } + event.setCancelled(true); + exploitExplosions.remove(i); + return; + } + } + } + + if ( - faction.isNone() - && - Conf.wildernessBlockTNT - && - ! Conf.worldsNoWildernessProtection.contains(loc.getWorld().getName()) - ) - || - ( - faction.isNormal() - && ( - online ? Conf.territoryBlockTNT : Conf.territoryBlockTNTWhenOffline + faction.isNone() + && + Conf.wildernessBlockTNT + && + ! Conf.worldsNoWildernessProtection.contains(loc.getWorld().getName()) + ) + || + ( + faction.isNormal() + && + ( + online ? Conf.territoryBlockTNT : Conf.territoryBlockTNTWhenOffline + ) + ) + || + ( + faction.isWarZone() + && + Conf.warZoneBlockTNT + ) + || + ( + faction.isSafeZone() + && + Conf.safeZoneBlockTNT ) ) - || - ( - faction.isWarZone() - && - Conf.warZoneBlockTNT - ) - || - ( - faction.isSafeZone() - && - Conf.safeZoneBlockTNT - ) - ) - { - // we'll assume it's TNT, which needs prevention - event.setCancelled(true); + { + // we'll assume it's TNT, which needs prevention + event.setCancelled(true); + } } } @@ -506,4 +548,38 @@ public class FactionsEntityListener extends EntityListener return false; } + + + /** + * Since the Bukkit team still don't seem to be in any hurry to fix the problem after at least half a year, + * we'll track potential explosion exploits ourselves and try to prevent them + * For reference, canceled TNT placement next to redstone power is bugged and triggers a free explosion + * Same thing happens for canceled redstone torch placement next to existing TNT + * https://bukkit.atlassian.net/browse/BUKKIT-89 + */ + + public static void trackPotentialExplosionExploit(String playerName, Faction faction, Material item, Location location) + { + exploitExplosions.add(new PotentialExplosionExploit(playerName, faction, item, location)); + } + + public static class PotentialExplosionExploit + { + public String playerName; + public Faction faction; + public Material item; + public long timeMillis; + public int X; + public int Z; + + public PotentialExplosionExploit(String playerName, Faction faction, Material item, Location location) + { + this.playerName = playerName; + this.faction = faction; + this.item = item; + this.timeMillis = System.currentTimeMillis(); + this.X = location.getBlockX(); + this.Z = location.getBlockZ(); + } + } }