Adds optional extensive sign protection which accounts for signs on gravity-affected blocks

This commit is contained in:
Kristian Knarvik 2022-01-21 21:49:11 +01:00
parent 1c64e8813d
commit 3bb5970a57
3 changed files with 125 additions and 46 deletions

View File

@ -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
*/ */

View File

@ -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;
}
} }

View File

@ -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