diff options
9 files changed, 688 insertions, 16 deletions
diff --git a/Essentials/src/com/earth2me/essentials/signs/EssentialsSign.java b/Essentials/src/com/earth2me/essentials/signs/EssentialsSign.java index a6f17c8bb..12966d668 100644 --- a/Essentials/src/com/earth2me/essentials/signs/EssentialsSign.java +++ b/Essentials/src/com/earth2me/essentials/signs/EssentialsSign.java @@ -6,19 +6,24 @@ import com.earth2me.essentials.IEssentials; import com.earth2me.essentials.ItemDb; import com.earth2me.essentials.User; import com.earth2me.essentials.Util; +import java.util.HashSet; +import java.util.Set; +import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; import org.bukkit.craftbukkit.block.CraftSign; -import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.entity.Player; import org.bukkit.event.block.SignChangeEvent; -import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; public class EssentialsSign { + private static final Set<Material> EMPTY_SET = new HashSet<Material>(); protected transient final String signName; private static final String FORMAT_SUCCESS = "§1[%s]"; + private static final String FORMAT_TEMPLATE = "[%s]"; private static final String FORMAT_FAIL = "§4[%s]"; public EssentialsSign(final String signName) @@ -41,7 +46,7 @@ public class EssentialsSign final boolean ret = onSignCreate(sign, user, getUsername(user), ess); if (ret) { - sign.setLine(0, String.format(FORMAT_SUCCESS, this.signName)); + sign.setLine(0, getSuccessName()); } return ret; } @@ -56,15 +61,25 @@ public class EssentialsSign return false; } + public String getSuccessName() + { + return String.format(FORMAT_SUCCESS, this.signName); + } + + public String getTemplateName() + { + return String.format(FORMAT_TEMPLATE, this.signName); + } + private String getUsername(final User user) { return user.getName().substring(0, user.getName().length() > 14 ? 14 : user.getName().length()); } - public final boolean onSignInteract(final PlayerInteractEvent event, final IEssentials ess) + public final boolean onSignInteract(final Block block, final Player player, final IEssentials ess) { - final ISign sign = new BlockSign(event.getClickedBlock()); - final User user = ess.getUser(event.getPlayer()); + final ISign sign = new BlockSign(block); + final User user = ess.getUser(player); try { return (user.isAuthorized("essentials.signs." + signName.toLowerCase() + ".use") @@ -83,10 +98,10 @@ public class EssentialsSign } } - public final boolean onSignBreak(final BlockBreakEvent event, final IEssentials ess) + public final boolean onSignBreak(final Block block, final Player player, final IEssentials ess) { - final ISign sign = new BlockSign(event.getBlock()); - final User user = ess.getUser(event.getPlayer()); + final ISign sign = new BlockSign(block); + final User user = ess.getUser(player); try { return (user.isAuthorized("essentials.signs." + signName.toLowerCase() + ".break") @@ -115,6 +130,114 @@ public class EssentialsSign return true; } + public final boolean onBlockPlace(final Block block, final Player player, final IEssentials ess) + { + User user = ess.getUser(player); + try + { + return onBlockPlace(block, user, getUsername(user), ess); + } + catch (ChargeException ex) + { + ess.showError(user, ex, signName); + } + catch (SignException ex) + { + ess.showError(user, ex, signName); + } + return false; + } + + public final boolean onBlockInteract(final Block block, final Player player, final IEssentials ess) + { + User user = ess.getUser(player); + try + { + return onBlockInteract(block, user, getUsername(user), ess); + } + catch (ChargeException ex) + { + ess.showError(user, ex, signName); + } + catch (SignException ex) + { + ess.showError(user, ex, signName); + } + return false; + } + + public final boolean onBlockBreak(final Block block, final Player player, final IEssentials ess) + { + User user = ess.getUser(player); + try + { + return onBlockBreak(block, user, getUsername(user), ess); + } + catch (SignException ex) + { + ess.showError(user, ex, signName); + } + return false; + } + + public boolean onBlockExplode(final Block block, final IEssentials ess) + { + return true; + } + + public boolean onBlockBurn(final Block block, final IEssentials ess) + { + return true; + } + + public static boolean checkIfBlockBreaksSigns(final Block block) + { + if (block.getFace(BlockFace.UP).getType() == Material.SIGN_POST) + { + return false; + } + final BlockFace[] directions = new BlockFace[] + { + BlockFace.NORTH, + BlockFace.EAST, + BlockFace.SOUTH, + BlockFace.WEST + }; + for (BlockFace blockFace : directions) + { + final Block signblock = block.getFace(blockFace); + if (signblock.getType() == Material.WALL_SIGN) + { + final org.bukkit.material.Sign sign = (org.bukkit.material.Sign)signblock.getState().getData(); + if (sign.getFacing() == blockFace) + { + return false; + } + } + } + return true; + } + + protected boolean onBlockPlace(final Block block, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + return true; + } + + protected boolean onBlockInteract(final Block block, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + return true; + } + + protected boolean onBlockBreak(final Block block, final User player, final String username, final IEssentials ess) throws SignException + { + return true; + } + + public Set<Material> getBlocks() + { + return EMPTY_SET; + } + protected final void validateTrade(final ISign sign, final int index, final IEssentials ess) throws SignException { final String line = sign.getLine(index).trim(); @@ -130,8 +253,6 @@ public class EssentialsSign } } - - protected final void validateTrade(final ISign sign, final int amountIndex, final int itemIndex, final User player, final IEssentials ess) throws SignException { @@ -266,10 +387,12 @@ public class EssentialsSign static class EventSign implements ISign { private final transient SignChangeEvent event; + private final transient Block block; public EventSign(final SignChangeEvent event) { this.event = event; + this.block = event.getBlock(); } public final String getLine(final int index) @@ -281,15 +404,22 @@ public class EssentialsSign { event.setLine(index, text); } + + public Block getBlock() + { + return block; + } } static class BlockSign implements ISign { private final transient Sign sign; + private final transient Block block; public BlockSign(final Block block) { + this.block = block; this.sign = new CraftSign(block); } @@ -302,6 +432,11 @@ public class EssentialsSign { sign.setLine(index, text); } + + public final Block getBlock() + { + return block; + } } @@ -310,5 +445,7 @@ public class EssentialsSign String getLine(final int index); void setLine(final int index, final String text); + + public Block getBlock(); } } diff --git a/Essentials/src/com/earth2me/essentials/signs/SignBlockListener.java b/Essentials/src/com/earth2me/essentials/signs/SignBlockListener.java new file mode 100644 index 000000000..543df7fc5 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignBlockListener.java @@ -0,0 +1,133 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.IEssentials; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.craftbukkit.block.CraftSign; +import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockListener; +import org.bukkit.event.block.SignChangeEvent; + + +public class SignBlockListener extends BlockListener +{ + private final transient IEssentials ess; + + public SignBlockListener(IEssentials ess) + { + this.ess = ess; + } + + @Override + public void onBlockBreak(final BlockBreakEvent event) + { + if (event.isCancelled() || ess.getSettings().areSignsDisabled()) + { + return; + } + + if (protectSignsAndBlocks(event.getBlock(), event.getPlayer())) + { + event.setCancelled(true); + } + } + + public boolean protectSignsAndBlocks(final Block block, final Player player) + { + final int mat = block.getTypeId(); + if (mat == Material.SIGN_POST.getId() || mat == Material.WALL_SIGN.getId()) + { + final Sign csign = new CraftSign(block); + for (Signs signs : Signs.values()) + { + final EssentialsSign sign = signs.getSign(); + if (csign.getLine(0).equalsIgnoreCase(sign.getSuccessName()) + && !sign.onSignBreak(block, player, ess)) + { + return true; + } + } + } + else + { + // prevent any signs be broken by destroying the block they are attached to + if (EssentialsSign.checkIfBlockBreaksSigns(block)) + { + return true; + } + for (Signs signs : Signs.values()) + { + final EssentialsSign sign = signs.getSign(); + if (sign.getBlocks().contains(block.getType()) + && !sign.onBlockBreak(block, player, ess)) + { + return true; + } + } + } + return false; + } + + @Override + public void onSignChange(final SignChangeEvent event) + { + if (event.isCancelled() || ess.getSettings().areSignsDisabled()) + { + return; + } + for (Signs signs : Signs.values()) + { + final EssentialsSign sign = signs.getSign(); + if (event.getLine(0).equalsIgnoreCase(sign.getTemplateName())) + { + event.setCancelled(!sign.onSignCreate(event, ess)); + return; + } + } + } + + @Override + public void onBlockBurn(final BlockBurnEvent event) + { + if (event.isCancelled() || ess.getSettings().areSignsDisabled()) + { + return; + } + + Block block = event.getBlock(); + if ((block.getType() == Material.WALL_SIGN + || block.getType() == Material.SIGN_POST + || EssentialsSign.checkIfBlockBreaksSigns(block))) + { + event.setCancelled(true); + return; + } + for (Signs signs : Signs.values()) + { + final EssentialsSign sign = signs.getSign(); + if (sign.getBlocks().contains(block.getType())) + { + event.setCancelled(!sign.onBlockBurn(block, ess)); + return; + } + } + } + + @Override + public void onBlockIgnite(final BlockIgniteEvent event) + { + if (event.isCancelled() || ess.getSettings().areSignsDisabled()) + { + return; + } + + if (protectSignsAndBlocks(event.getBlock(), event.getPlayer())) + { + event.setCancelled(true); + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignEntityListener.java b/Essentials/src/com/earth2me/essentials/signs/SignEntityListener.java new file mode 100644 index 000000000..8b59c7aba --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignEntityListener.java @@ -0,0 +1,44 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.IEssentials; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.EntityListener; + + +public class SignEntityListener extends EntityListener +{ + private final transient IEssentials ess; + + public SignEntityListener(IEssentials ess) + { + this.ess = ess; + } + + + @Override + public void onEntityExplode(EntityExplodeEvent event) + { + for (Block block : event.blockList()) + { + if ((block.getType() == Material.WALL_SIGN + || block.getType() == Material.SIGN_POST + || EssentialsSign.checkIfBlockBreaksSigns(block))) + { + event.setCancelled(true); + return; + } + for (Signs signs : Signs.values()) + { + final EssentialsSign sign = signs.getSign(); + if (sign.getBlocks().contains(block.getType())) + { + event.setCancelled(!sign.onBlockExplode(block, ess)); + return; + } + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignFree.java b/Essentials/src/com/earth2me/essentials/signs/SignFree.java index 6c45c8b07..51d232b5d 100644 --- a/Essentials/src/com/earth2me/essentials/signs/SignFree.java +++ b/Essentials/src/com/earth2me/essentials/signs/SignFree.java @@ -1,8 +1,6 @@ package com.earth2me.essentials.signs; -import com.earth2me.essentials.Trade; import com.earth2me.essentials.IEssentials; -import com.earth2me.essentials.ItemDb; import com.earth2me.essentials.User; import net.minecraft.server.InventoryPlayer; import org.bukkit.craftbukkit.inventory.CraftInventoryPlayer; diff --git a/Essentials/src/com/earth2me/essentials/signs/SignPlayerListener.java b/Essentials/src/com/earth2me/essentials/signs/SignPlayerListener.java new file mode 100644 index 000000000..ba94868af --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignPlayerListener.java @@ -0,0 +1,60 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.IEssentials; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.craftbukkit.block.CraftSign; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerListener; + + +public class SignPlayerListener extends PlayerListener +{ + private final transient IEssentials ess; + + public SignPlayerListener(IEssentials ess) + { + this.ess = ess; + } + + @Override + public void onPlayerInteract(PlayerInteractEvent event) + { + if (event.isCancelled() || ess.getSettings().areSignsDisabled()) + { + return; + } + + final Block block = event.getClickedBlock(); + final int mat = block.getTypeId(); + if (mat == Material.SIGN_POST.getId() || mat == Material.WALL_SIGN.getId()) + { + final Sign csign = new CraftSign(block); + for (Signs signs : Signs.values()) + { + final EssentialsSign sign = signs.getSign(); + if (csign.getLine(0).equalsIgnoreCase(sign.getSuccessName()) + && !sign.onSignInteract(block, event.getPlayer(), ess)) + { + event.setCancelled(true); + return; + } + } + } + else + { + for (Signs signs : Signs.values()) + { + final EssentialsSign sign = signs.getSign(); + if (sign.getBlocks().contains(block.getType()) + && !sign.onBlockInteract(block, event.getPlayer(), ess)) + { + event.setCancelled(true); + return; + + } + } + } + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignProtection.java b/Essentials/src/com/earth2me/essentials/signs/SignProtection.java new file mode 100644 index 000000000..02a811c78 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/SignProtection.java @@ -0,0 +1,273 @@ +package com.earth2me.essentials.signs; + +import com.earth2me.essentials.ChargeException; +import com.earth2me.essentials.IEssentials; +import com.earth2me.essentials.Trade; +import com.earth2me.essentials.User; +import com.earth2me.essentials.Util; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Sign; +import org.bukkit.craftbukkit.block.CraftSign; +import org.bukkit.inventory.ItemStack; + + +public class SignProtection extends EssentialsSign +{ + private final transient Set<Material> protectedBlocks = EnumSet.noneOf(Material.class); + + public SignProtection() + { + super("Protection"); + protectedBlocks.add(Material.CHEST); + protectedBlocks.add(Material.BURNING_FURNACE); + protectedBlocks.add(Material.FURNACE); + protectedBlocks.add(Material.DISPENSER); + } + + @Override + protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException + { + sign.setLine(3, "§4" + username); + if (hasAdjacentBlock(sign.getBlock()) && isBlockProtected(sign.getBlock(), player, username) != SignProtectionState.NOT_ALLOWED) + { + sign.setLine(3, "§1" + username); + } + return true; + } + + @Override + protected boolean onSignBreak(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException + { + final SignProtectionState state = checkProtectionSign(sign, player, username); + return state == SignProtectionState.OWNER; + } + + public boolean hasAdjacentBlock(final Block block, final Block... ignoredBlocks) + { + final Block[] faces = getAdjacentBlocks(block); + for (Block b : faces) + { + for (Block ignoredBlock : ignoredBlocks) + { + if (b.getLocation().equals(ignoredBlock.getLocation())) + { + continue; + } + } + if (protectedBlocks.contains(b.getType())) + { + return true; + } + } + return false; + } + + private void checkIfSignsAreBroken(final Block block, final User player, final String username, final IEssentials ess) + { + final Map<Location, SignProtectionState> signs = getConnectedSigns(block, player, username); + for (Map.Entry<Location, SignProtectionState> entry : signs.entrySet()) + { + if (entry.getValue() != SignProtectionState.NOSIGN) + { + final Block sign = entry.getKey().getBlock(); + if (!hasAdjacentBlock(sign, block)) + { + block.setType(Material.AIR); + final Trade trade = new Trade(new ItemStack(Material.SIGN, 1), ess); + trade.pay(player); + } + } + } + } + + private Map<Location, SignProtectionState> getConnectedSigns(final Block block, final User user, final String username) + { + final Map<Location, SignProtectionState> signs = new HashMap<Location, SignProtectionState>(); + getConnectedSigns(block, signs, user, username, 2); + return signs; + } + + private void getConnectedSigns(final Block block, final Map<Location, SignProtectionState> signs, final User user, final String username, final int depth) + { + final Block[] faces = getAdjacentBlocks(block); + for (Block b : faces) + { + final Location loc = b.getLocation(); + if (signs.containsKey(loc)) + { + continue; + } + final SignProtectionState check = checkProtectionSign(b, user, username); + signs.put(loc, check); + + if (protectedBlocks.contains(b.getType()) && depth > 0) + { + getConnectedSigns(b, signs, user, username, depth - 1); + } + } + } + + + public enum SignProtectionState + { + NOT_ALLOWED, ALLOWED, NOSIGN, OWNER + } + + private SignProtectionState checkProtectionSign(final Block block, final User user, final String username) + { + if (block.getType() == Material.SIGN_POST || block.getType() == Material.WALL_SIGN) + { + final BlockSign sign = new BlockSign(block); + if (sign.getLine(0).equalsIgnoreCase(this.getSuccessName())) + { + return checkProtectionSign(sign, user, username); + } + } + return SignProtectionState.NOSIGN; + } + + private SignProtectionState checkProtectionSign(final ISign sign, final User user, final String username) + { + if (user == null || username == null) + { + return SignProtectionState.NOT_ALLOWED; + } + if (user.isAuthorized("essentials.signs.protection.override")) + { + return SignProtectionState.OWNER; + } + for (int i = 1; i <= 2; i++) + { + final String line = sign.getLine(i); + if (line.startsWith("(") && line.endsWith(")") && user.inGroup(line.substring(1, line.length() - 1))) + { + return SignProtectionState.ALLOWED; + } + else if (line.equalsIgnoreCase(username)) + { + return SignProtectionState.ALLOWED; + } + } + if (sign.getLine(3).equalsIgnoreCase(username)) + { + return SignProtectionState.OWNER; + } + return SignProtectionState.NOT_ALLOWED; + } + + private Block[] getAdjacentBlocks(final Block block) + { + return new Block[] + { + block.getFace(BlockFace.NORTH), + block.getFace(BlockFace.SOUTH), + block.getFace(BlockFace.EAST), + block.getFace(BlockFace.WEST), + block.getFace(BlockFace.DOWN), + block.getFace(BlockFace.UP) + }; + } + + public SignProtectionState isBlockProtected(final Block block, final User user, final String username) + { + final Map<Location, SignProtectionState> signs = getConnectedSigns(block, user, username); + SignProtectionState retstate = SignProtectionState.NOSIGN; + for (SignProtectionState state : signs.values()) + { + if (state == SignProtectionState.OWNER || state == SignProtectionState.ALLOWED) + { + return state; + } + if (state == SignProtectionState.NOT_ALLOWED) + { + retstate = state; + } + } + return retstate; + } + + public boolean isBlockProtected(final Block block) + { + final Block[] faces = getAdjacentBlocks(block); + for (Block b : faces) + { + if (b.getType() == Material.SIGN_POST || b.getType() == Material.WALL_SIGN) + { + final Sign sign = new CraftSign(b); + if (sign.getLine(0).equalsIgnoreCase("§1[Protection]")) + { + return true; + } + } + if (protectedBlocks.contains(b.getType())) + { + final Block[] faceChest = getAdjacentBlocks(b); + + for (Block a : faceChest) + { + if (a.getType() == Material.SIGN_POST || a.getType() == Material.WALL_SIGN) + { + final Sign sign = new CraftSign(a); + if (sign.getLine(0).equalsIgnoreCase("§1[Protection]")) + { + return true; + } + } + } + } + } + return false; + } + + @Override + public Set<Material> getBlocks() + { + return protectedBlocks; + } + + @Override + protected boolean onBlockBreak(final Block block, final User player, final String username, final IEssentials ess) throws SignException + { + final SignProtectionState state = isBlockProtected(block, player, username); + + if (state == SignProtectionState.OWNER || state == SignProtectionState.NOSIGN) + { + checkIfSignsAreBroken(block, player, username, ess); + return true; + } + + if ((state == SignProtectionState.ALLOWED || state == SignProtectionState.NOT_ALLOWED) + && player.isAuthorized("essentials.signs.protection.override")) + { + checkIfSignsAreBroken(block, player, username, ess); + return true; + } + + + player.sendMessage(Util.format("noDestroyPermission", block.getType().toString().toLowerCase())); + return false; + } + + @Override + public boolean onBlockExplode(final Block block, final IEssentials ess) + { + final SignProtectionState state = isBlockProtected(block, null, null); + + return state == SignProtectionState.NOSIGN; + } + + @Override + public boolean onBlockBurn(final Block block, final IEssentials ess) + { + final SignProtectionState state = isBlockProtected(block, null, null); + + return state == SignProtectionState.NOSIGN; + } +} diff --git a/Essentials/src/com/earth2me/essentials/signs/SignSell.java b/Essentials/src/com/earth2me/essentials/signs/SignSell.java index 2b74a78e6..d35a83518 100644 --- a/Essentials/src/com/earth2me/essentials/signs/SignSell.java +++ b/Essentials/src/com/earth2me/essentials/signs/SignSell.java @@ -12,7 +12,7 @@ public class SignSell extends EssentialsSign { super("Sell"); } - + @Override protected boolean onSignCreate(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException { @@ -20,7 +20,7 @@ public class SignSell extends EssentialsSign validateTrade(sign, 3, ess); return true; } - + @Override protected boolean onSignInteract(final ISign sign, final User player, final String username, final IEssentials ess) throws SignException, ChargeException { diff --git a/Essentials/src/com/earth2me/essentials/signs/SignTrade.java b/Essentials/src/com/earth2me/essentials/signs/SignTrade.java index dd82bd09d..c8a0d4d0d 100644 --- a/Essentials/src/com/earth2me/essentials/signs/SignTrade.java +++ b/Essentials/src/com/earth2me/essentials/signs/SignTrade.java @@ -65,7 +65,7 @@ public class SignTrade extends EssentialsSign return false; } } - + protected final void validateTrade(final ISign sign, final int index, final boolean amountNeeded, final IEssentials ess) throws SignException { final String line = sign.getLine(index).trim(); diff --git a/Essentials/src/com/earth2me/essentials/signs/Signs.java b/Essentials/src/com/earth2me/essentials/signs/Signs.java new file mode 100644 index 000000000..1f20ed737 --- /dev/null +++ b/Essentials/src/com/earth2me/essentials/signs/Signs.java @@ -0,0 +1,27 @@ +package com.earth2me.essentials.signs; + + +public enum Signs +{ + BUY(new SignBuy()), + DISPOSAL(new SignDisposal()), + FREE(new SignFree()), + HEAL(new SignHeal()), + MAIL(new SignMail()), + PROTECTION(new SignProtection()), + SELL(new SignSell()), + TIME(new SignTime()), + TRADE(new SignTrade()), + WARP(new SignWarp()); + private final EssentialsSign sign; + + private Signs(final EssentialsSign sign) + { + this.sign = sign; + } + + public EssentialsSign getSign() + { + return sign; + } +} |