diff --git a/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java b/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java index cceea99..16b9679 100644 --- a/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java +++ b/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java @@ -42,6 +42,7 @@ public final class PermissionSigns extends JavaPlugin { private static String pluginVersion; private static PermissionSigns instance; private static boolean perWorldPermissions; + private static boolean enableExtensiveSignProtection; /** * Instantiates the permission signs class @@ -120,42 +121,60 @@ public final class PermissionSigns extends JavaPlugin { return perWorldPermissions; } + /** + * Gets whether permission signs on falling blocks should be protected + * + * @return
Whether permission signs on falling blocks should be protected
+ */ + public static boolean extensiveSignProtectionEnabled() { + return enableExtensiveSignProtection; + } + @Override public void reloadConfig() { super.reloadConfig(); - FileConfiguration config = this.getConfig(); - String language = config.getString("language"); - perWorldPermissions = config.getBoolean("perWorldPermissions"); - Translator.loadLanguages(language); + Translator.loadLanguages(loadConfig()); } @Override public void onEnable() { - PluginDescriptionFile pluginDescriptionFile = this.getDescription(); - pluginVersion = pluginDescriptionFile.getVersion(); - //TODO: Display a notice in the console if a new version is available - - FileConfiguration config = this.getConfig(); - config.options().copyDefaults(true); - this.saveDefaultConfig(); - - String language = config.getString("language"); - perWorldPermissions = config.getBoolean("perWorldPermissions"); - //Check if vault is loaded setupVault(); + //Get plugin info + PluginDescriptionFile pluginDescriptionFile = this.getDescription(); + pluginVersion = pluginDescriptionFile.getVersion(); + + //TODO: Display a notice in the console if a new version is available (requires Spigot resource first) + + //Load config and write the default config if necessary + FileConfiguration config = this.getConfig(); + config.options().copyDefaults(true); + this.saveDefaultConfig(); + Translator.loadLanguages(loadConfig()); + registerListeners(); - - Translator.loadLanguages(language); registerCommands(); - runThreads(); SignManager.loadSigns(); PermissionManager.loadTemporaryPermissions(); } + /** + * Loads the config file + * + * @returnThe currently selected language
+ */ + private String loadConfig() { + FileConfiguration config = this.getConfig(); + String language = config.getString("language", "en"); + perWorldPermissions = config.getBoolean("perWorldPermissions", false); + enableExtensiveSignProtection = config.getBoolean("enableExtensiveSignProtection", false); + saveConfig(); + return language; + } + /** * Starts all separate threads for executing tasks */ diff --git a/src/main/java/net/knarcraft/permissionsigns/listener/BlockListener.java b/src/main/java/net/knarcraft/permissionsigns/listener/BlockListener.java index e54a49c..0c23a34 100644 --- a/src/main/java/net/knarcraft/permissionsigns/listener/BlockListener.java +++ b/src/main/java/net/knarcraft/permissionsigns/listener/BlockListener.java @@ -12,15 +12,28 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPhysicsEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; + +import static net.knarcraft.permissionsigns.PermissionSigns.extensiveSignProtectionEnabled; /** * A listener for relevant block events such as signs being broken */ public class BlockListener implements Listener { + @EventHandler + public void onBlockPhysics(BlockPhysicsEvent event) { + //Block any physics events from destroying signs + if (SignManager.getSign(event.getBlock().getLocation()) != null) { + event.setCancelled(true); + } + } + @EventHandler public void onBlockBreak(BlockBreakEvent event) { Block block = event.getBlock(); @@ -30,14 +43,48 @@ public class BlockListener implements Listener { return; } - //if (block instanceof FallingBlock) { - //TODO: Search recursively upwards (and downwards if pointed dripstone) until a non-falling block is found. - // If upwards, check the non-falling block, but not downwards. If player does not have the create permission, - // just stop and cancel once a permission sign is found. If it has, all affected signs need to be - // de-registered. Must account for stacks of sand and signs on top of each-other. So if a normal sign is - // found, the recursion upward must also happen. - //} + //Protect the permission sign itself + protectBlockIfPermissionSign(event, block, player); + if (extensiveSignProtectionEnabled()) { + protectSignsInDirection(event, block, player, BlockFace.UP); + if (event.isCancelled()) { + return; + } + protectSignsInDirection(event, block, player, BlockFace.DOWN); + } + } + + /** + * Protects signs on falling blocks in the given direction + * + * @param eventThe triggered block break event
+ * @param blockThe broken block
+ * @param playerThe player breaking the block
+ * @param directionThe direction to check for affected blocks
+ */ + private void protectSignsInDirection(BlockBreakEvent event, Block block, Player player, BlockFace direction) { + Block directionBlock = block; + do { + directionBlock = directionBlock.getRelative(direction); + protectBlockIfPermissionSign(event, directionBlock, player); + if (event.isCancelled()) { + return; + } + } while ((direction == BlockFace.DOWN && directionBlock.getBlockData().getMaterial() == + Material.POINTED_DRIPSTONE) || (direction == BlockFace.UP && + isAffectedByGravity(directionBlock.getBlockData().getMaterial()))); + } + + /** + * Protects the given sign + * + * @param eventThe triggered block break event
+ * @param blockThe block to check if it's a sign
+ * @param playerThe player breaking the block
+ */ + private void protectBlockIfPermissionSign(BlockBreakEvent event, Block block, Player player) { + //Protect the permission sign itself Material material = block.getBlockData().getMaterial(); if (Tag.SIGNS.isTagged(material) || Tag.WALL_SIGNS.isTagged(material)) { checkIfBlockIsPermissionSign(block, player, event); @@ -46,34 +93,24 @@ public class BlockListener implements Listener { } } - Block relativeBlock = block.getRelative(BlockFace.UP); - if (Tag.SIGNS.isTagged(relativeBlock.getBlockData().getMaterial())) { - checkIfBlockIsPermissionSign(relativeBlock, player, event); - if (event.isCancelled()) { - return; - } - } + MapThe material to check
+ * @returnTrue if the material is affected by gravity
+ */ + private boolean isAffectedByGravity(Material material) { + return Tag.SAND.isTagged(material) || Tag.ANVIL.isTagged(material) || material == Material.POINTED_DRIPSTONE || + Tag.SIGNS.isTagged(material) || material == Material.DRAGON_EGG || material == Material.GRAVEL || + material == Material.BLACK_CONCRETE_POWDER || material == Material.BLUE_CONCRETE_POWDER || + material == Material.BROWN_CONCRETE_POWDER || material == Material.CYAN_CONCRETE_POWDER || + material == Material.LIME_CONCRETE_POWDER || material == Material.GRAY_CONCRETE_POWDER || + material == Material.GREEN_CONCRETE_POWDER || material == Material.LIGHT_BLUE_CONCRETE_POWDER || + material == Material.MAGENTA_CONCRETE_POWDER || material == Material.PINK_CONCRETE_POWDER || + material == Material.LIGHT_GRAY_CONCRETE_POWDER || material == Material.ORANGE_CONCRETE_POWDER || + material == Material.RED_CONCRETE_POWDER || material == Material.PURPLE_CONCRETE_POWDER || + material == Material.YELLOW_CONCRETE_POWDER || material == Material.WHITE_CONCRETE_POWDER; + } + } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5c9c577..627c777 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -3,3 +3,7 @@ language: en # Whether to only give permissions for a single world, instead of granting permissions for all worlds perWorldPermissions: false + +# Whether to protect permission signs on falling blocks (sand, gravel, anvil, drip-stone, signs) by preventing breakage +# of the blocks that would cause a sign to be destroyed. +enableExtensiveSignProtection: false \ No newline at end of file