Adds optional extensive sign protection which accounts for signs on gravity-affected blocks
This commit is contained in:
		@@ -42,6 +42,7 @@ public final class PermissionSigns extends JavaPlugin {
 | 
				
			|||||||
    private static String pluginVersion;
 | 
					    private static String pluginVersion;
 | 
				
			||||||
    private static PermissionSigns instance;
 | 
					    private static PermissionSigns instance;
 | 
				
			||||||
    private static boolean perWorldPermissions;
 | 
					    private static boolean perWorldPermissions;
 | 
				
			||||||
 | 
					    private static boolean enableExtensiveSignProtection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Instantiates the permission signs class
 | 
					     * Instantiates the permission signs class
 | 
				
			||||||
@@ -120,42 +121,60 @@ public final class PermissionSigns extends JavaPlugin {
 | 
				
			|||||||
        return perWorldPermissions;
 | 
					        return perWorldPermissions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets whether permission signs on falling blocks should be protected
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>Whether permission signs on falling blocks should be protected</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static boolean extensiveSignProtectionEnabled() {
 | 
				
			||||||
 | 
					        return enableExtensiveSignProtection;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void reloadConfig() {
 | 
					    public void reloadConfig() {
 | 
				
			||||||
        super.reloadConfig();
 | 
					        super.reloadConfig();
 | 
				
			||||||
        FileConfiguration config = this.getConfig();
 | 
					        Translator.loadLanguages(loadConfig());
 | 
				
			||||||
        String language = config.getString("language");
 | 
					 | 
				
			||||||
        perWorldPermissions = config.getBoolean("perWorldPermissions");
 | 
					 | 
				
			||||||
        Translator.loadLanguages(language);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public void onEnable() {
 | 
					    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
 | 
					        //Check if vault is loaded
 | 
				
			||||||
        setupVault();
 | 
					        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();
 | 
					        registerListeners();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        Translator.loadLanguages(language);
 | 
					 | 
				
			||||||
        registerCommands();
 | 
					        registerCommands();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        runThreads();
 | 
					        runThreads();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SignManager.loadSigns();
 | 
					        SignManager.loadSigns();
 | 
				
			||||||
        PermissionManager.loadTemporaryPermissions();
 | 
					        PermissionManager.loadTemporaryPermissions();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Loads the config file
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The currently selected language</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    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
 | 
					     * Starts all separate threads for executing tasks
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,15 +12,28 @@ import org.bukkit.entity.Player;
 | 
				
			|||||||
import org.bukkit.event.EventHandler;
 | 
					import org.bukkit.event.EventHandler;
 | 
				
			||||||
import org.bukkit.event.Listener;
 | 
					import org.bukkit.event.Listener;
 | 
				
			||||||
import org.bukkit.event.block.BlockBreakEvent;
 | 
					import org.bukkit.event.block.BlockBreakEvent;
 | 
				
			||||||
 | 
					import org.bukkit.event.block.BlockPhysicsEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.util.ArrayList;
 | 
					import java.util.ArrayList;
 | 
				
			||||||
 | 
					import java.util.HashMap;
 | 
				
			||||||
import java.util.List;
 | 
					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
 | 
					 * A listener for relevant block events such as signs being broken
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public class BlockListener implements Listener {
 | 
					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
 | 
					    @EventHandler
 | 
				
			||||||
    public void onBlockBreak(BlockBreakEvent event) {
 | 
					    public void onBlockBreak(BlockBreakEvent event) {
 | 
				
			||||||
        Block block = event.getBlock();
 | 
					        Block block = event.getBlock();
 | 
				
			||||||
@@ -30,14 +43,48 @@ public class BlockListener implements Listener {
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //if (block instanceof FallingBlock) {
 | 
					        //Protect the permission sign itself
 | 
				
			||||||
        //TODO: Search recursively upwards (and downwards if pointed dripstone) until a non-falling block is found.
 | 
					        protectBlockIfPermissionSign(event, block, player);
 | 
				
			||||||
        // 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.
 | 
					 | 
				
			||||||
        //}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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 event     <p>The triggered block break event</p>
 | 
				
			||||||
 | 
					     * @param block     <p>The broken block</p>
 | 
				
			||||||
 | 
					     * @param player    <p>The player breaking the block</p>
 | 
				
			||||||
 | 
					     * @param direction <p>The direction to check for affected blocks</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    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 event  <p>The triggered block break event</p>
 | 
				
			||||||
 | 
					     * @param block  <p>The block to check if it's a sign</p>
 | 
				
			||||||
 | 
					     * @param player <p>The player breaking the block</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void protectBlockIfPermissionSign(BlockBreakEvent event, Block block, Player player) {
 | 
				
			||||||
 | 
					        //Protect the permission sign itself
 | 
				
			||||||
        Material material = block.getBlockData().getMaterial();
 | 
					        Material material = block.getBlockData().getMaterial();
 | 
				
			||||||
        if (Tag.SIGNS.isTagged(material) || Tag.WALL_SIGNS.isTagged(material)) {
 | 
					        if (Tag.SIGNS.isTagged(material) || Tag.WALL_SIGNS.isTagged(material)) {
 | 
				
			||||||
            checkIfBlockIsPermissionSign(block, player, event);
 | 
					            checkIfBlockIsPermissionSign(block, player, event);
 | 
				
			||||||
@@ -46,34 +93,24 @@ public class BlockListener implements Listener {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Block relativeBlock = block.getRelative(BlockFace.UP);
 | 
					        Map<Block, Tag<Material>> blocksToCheck = new HashMap<>();
 | 
				
			||||||
        if (Tag.SIGNS.isTagged(relativeBlock.getBlockData().getMaterial())) {
 | 
					 | 
				
			||||||
            checkIfBlockIsPermissionSign(relativeBlock, player, event);
 | 
					 | 
				
			||||||
            if (event.isCancelled()) {
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (block.getBlockData().getMaterial() == Material.POINTED_DRIPSTONE) {
 | 
					        //Protect any block with a permission sign on it
 | 
				
			||||||
            relativeBlock = block.getRelative(BlockFace.DOWN);
 | 
					        blocksToCheck.put(block.getRelative(BlockFace.UP), Tag.SIGNS);
 | 
				
			||||||
            if (Tag.WALL_SIGNS.isTagged(relativeBlock.getBlockData().getMaterial())) {
 | 
					
 | 
				
			||||||
                checkIfBlockIsPermissionSign(relativeBlock, player, event);
 | 
					        //Protect any permission signs attached to the block
 | 
				
			||||||
                if (event.isCancelled()) {
 | 
					 | 
				
			||||||
                    return;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        for (BlockFace blockFace : getRelevantBlockFaces()) {
 | 
					        for (BlockFace blockFace : getRelevantBlockFaces()) {
 | 
				
			||||||
            relativeBlock = block.getRelative(blockFace);
 | 
					            blocksToCheck.put(block.getRelative(blockFace), Tag.WALL_SIGNS);
 | 
				
			||||||
            if (Tag.WALL_SIGNS.isTagged(relativeBlock.getBlockData().getMaterial())) {
 | 
					        }
 | 
				
			||||||
                checkIfBlockIsPermissionSign(relativeBlock, player, event);
 | 
					
 | 
				
			||||||
 | 
					        for (Block blockToCheck : blocksToCheck.keySet()) {
 | 
				
			||||||
 | 
					            if (blocksToCheck.get(blockToCheck).isTagged(blockToCheck.getBlockData().getMaterial())) {
 | 
				
			||||||
 | 
					                checkIfBlockIsPermissionSign(blockToCheck, player, event);
 | 
				
			||||||
                if (event.isCancelled()) {
 | 
					                if (event.isCancelled()) {
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        //TODO: Need to protect against other things that might damage the sign, such as explosions
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -117,4 +154,23 @@ public class BlockListener implements Listener {
 | 
				
			|||||||
        return relevantBlockFaces;
 | 
					        return relevantBlockFaces;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks whether the given material is affected by gravity
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param material <p>The material to check</p>
 | 
				
			||||||
 | 
					     * @return <p>True if the material is affected by gravity</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,3 +3,7 @@ language: en
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Whether to only give permissions for a single world, instead of granting permissions for all worlds
 | 
					# Whether to only give permissions for a single world, instead of granting permissions for all worlds
 | 
				
			||||||
perWorldPermissions: false
 | 
					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
 | 
				
			||||||
		Reference in New Issue
	
	Block a user