diff --git a/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java b/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java index 637f6e4..e9d9890 100644 --- a/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java +++ b/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java @@ -5,6 +5,7 @@ import net.knarcraft.permissionsigns.command.PermissionSignsTabCompleter; import net.knarcraft.permissionsigns.container.PermissionSign; import net.knarcraft.permissionsigns.container.SignCreationRequest; import net.knarcraft.permissionsigns.formatting.Translator; +import net.knarcraft.permissionsigns.listener.BlockListener; import net.knarcraft.permissionsigns.listener.PlayerListener; import net.knarcraft.permissionsigns.listener.SignListener; import net.knarcraft.permissionsigns.manager.EconomyManager; @@ -16,8 +17,10 @@ import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; import org.bukkit.command.PluginCommand; +import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.ServicesManager; import org.bukkit.plugin.java.JavaPlugin; @@ -35,6 +38,7 @@ public final class PermissionSigns extends JavaPlugin { private static final Queue signCreationRequests = new PriorityQueue<>(); private static String pluginVersion; private static PermissionSigns instance; + private static boolean perWorldPermissions; /** * Instantiates the permission signs class @@ -104,57 +108,74 @@ public final class PermissionSigns extends JavaPlugin { } } + /** + * Checks whether permissions should always be set for the world the sign belongs to + * + * @return

Whether permissions should be set for the current world

+ */ + public static boolean usePerWorldPermissions() { + return perWorldPermissions; + } + + @Override + public void reloadConfig() { + super.reloadConfig(); + FileConfiguration config = this.getConfig(); + String language = config.getString("language"); + perWorldPermissions = config.getBoolean("perWorldPermissions"); + Translator.loadLanguages(language); + } + @Override public void onEnable() { PluginDescriptionFile pluginDescriptionFile = this.getDescription(); pluginVersion = pluginDescriptionFile.getVersion(); - - // Plugin startup logic - - //TODO: Add commands create, add and remove - // /ps create, /ps add, and /ps remove - // create initiates the creation, and add adds properties - // On creation, write "Creating PermissionSign", first asked for the name - // Then asked for the permission. Allow several comma-separated permissions - // Then asked for duration - // Then asked for cost - // Say "Sign completed! Right-click a sign to enable it." - // Then asked to right-click a sign to create the new permission-sign - // Perhaps ignore the old ways, and just have one command for creating permission signs: - // /ps create to create a new permission-sign - // Right-click a sign to create it - // /ps cancel to cancel the sing creation - // Break the sign to remove it, check for permission first - // The name thing is probably useless, as the sign's location works as its id - - //TODO: Display and register the permission-sign - // Start with [PermSign] in red - // Next line is the permission node. Last child, upper-cased - // Third line is n seconds - // Last line is the cost, including the unit - // Need to store any temporary permissions in a list/queue and have a thread which searches for expired - // permissions to de-register them - - //Not persistent, but might work as things shouldn't persist anyway - //player.addAttachment(this, "essentials.fly", true, seconds * 20); - //Vault probably has some API to add permissions - - //TODO: Store all temporary permissions with the time they were assigned and the time they should be granted. - // Set the permissions as permanent and remove when the timer expires? Might cause problems for players that has - // the permission inherited, unless we make sure the player does not have the permission before - // Alternatively: Manage all permissions ourselves, for temporary permissions, and add permission attachments - // on startup I guess. - - //TODO: Start sign creation when the create command is used and save the data until an empty sign is right-clicked - - //TODO: Check for existence of old permission signs when clicked and register them as new permission signs. If - // it has the permissionSigns header and a name matching contents in signs.yml, add it. - - //TODO: Implement config file - //TODO: Account for per-world permissions if enabled (perhaps allow world specification as world:permission?) //TODO: Allow for custom language files. Perhaps just look for strings.yml in the folder + 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(); + + registerListeners(); + + Translator.loadLanguages(language); + registerCommands(); + + runThreads(); + + SignManager.loadSigns(); + PermissionManager.loadTemporaryPermissions(); + } + + /** + * Starts all separate threads for executing tasks + */ + private void runThreads() { + BukkitScheduler scheduler = Bukkit.getScheduler(); + scheduler.runTaskTimer(this, new SignCreationRequestTimeoutThread(signCreationRequests), 0L, 100L); + scheduler.runTaskTimer(this, new PermissionTimeoutThread(), 0L, 25L); + } + + /** + * Registers all necessary listeners + */ + private void registerListeners() { + PluginManager pluginManager = getServer().getPluginManager(); + pluginManager.registerEvents(new SignListener(), this); + pluginManager.registerEvents(new PlayerListener(), this); + pluginManager.registerEvents(new BlockListener(), this); + } + + /** + * Sets up Vault by getting plugins from their providers + */ + private void setupVault() { ServicesManager servicesManager = this.getServer().getServicesManager(); RegisteredServiceProvider permissionProvider = servicesManager.getRegistration(Permission.class); RegisteredServiceProvider economyProvider = servicesManager.getRegistration(Economy.class); @@ -164,16 +185,6 @@ public final class PermissionSigns extends JavaPlugin { } else { throw new IllegalStateException("[PermissionSigns] Error: Vault could not be loaded"); } - getServer().getPluginManager().registerEvents(new SignListener(), this); - getServer().getPluginManager().registerEvents(new PlayerListener(), this); - - Translator.loadLanguages("en"); - registerCommands(); - BukkitScheduler scheduler = Bukkit.getScheduler(); - scheduler.runTaskTimer(this, new SignCreationRequestTimeoutThread(signCreationRequests), 0L, 100L); - scheduler.runTaskTimer(this, new PermissionTimeoutThread(), 0L, 25L); - SignManager.loadSigns(); - PermissionManager.loadTemporaryPermissions(); } /** diff --git a/src/main/java/net/knarcraft/permissionsigns/command/CreateCommand.java b/src/main/java/net/knarcraft/permissionsigns/command/CreateCommand.java index 0adb9b2..48cf117 100644 --- a/src/main/java/net/knarcraft/permissionsigns/command/CreateCommand.java +++ b/src/main/java/net/knarcraft/permissionsigns/command/CreateCommand.java @@ -4,6 +4,7 @@ import net.knarcraft.permissionsigns.PermissionSigns; import net.knarcraft.permissionsigns.container.PermissionSign; import net.knarcraft.permissionsigns.formatting.StringFormatter; import net.knarcraft.permissionsigns.formatting.TranslatableMessage; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -57,6 +58,18 @@ public class CreateCommand implements CommandExecutor { private PermissionSign parseSign(@NotNull CommandSender sender, @NotNull String[] args) { String name = args[0]; String[] permissions = args[1].split(","); + for (String permission : permissions) { + if (permission.contains(":")) { + //TODO: Might need to account for world names with spaces in the name + String world = permission.split(":")[0]; + if (!world.equalsIgnoreCase("all") && Bukkit.getWorld(world) == null) { + sender.sendMessage(StringFormatter.replacePlaceholder(StringFormatter.getTranslatedErrorMessage( + TranslatableMessage.PERMISSION_WORLD_INVALID), "{world}", world)); + return null; + } + } + } + double cost = 0; int duration = 0; if (args.length > 2) { diff --git a/src/main/java/net/knarcraft/permissionsigns/command/ReloadCommand.java b/src/main/java/net/knarcraft/permissionsigns/command/ReloadCommand.java index 34c677d..baf0461 100644 --- a/src/main/java/net/knarcraft/permissionsigns/command/ReloadCommand.java +++ b/src/main/java/net/knarcraft/permissionsigns/command/ReloadCommand.java @@ -1,7 +1,9 @@ package net.knarcraft.permissionsigns.command; +import net.knarcraft.permissionsigns.PermissionSigns; import net.knarcraft.permissionsigns.formatting.StringFormatter; import net.knarcraft.permissionsigns.formatting.TranslatableMessage; +import net.knarcraft.permissionsigns.manager.PermissionManager; import net.knarcraft.permissionsigns.manager.SignManager; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -16,8 +18,9 @@ public class ReloadCommand implements CommandExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { if (sender.hasPermission("permissionsigns.admin.reload")) { - //TODO: Perform a reload from disk SignManager.loadSigns(); + PermissionManager.loadTemporaryPermissions(); + PermissionSigns.getInstance().reloadConfig(); } else { sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.COMMAND_PERMISSION_DENIED)); } diff --git a/src/main/java/net/knarcraft/permissionsigns/container/TemporaryPermission.java b/src/main/java/net/knarcraft/permissionsigns/container/TemporaryPermission.java index 2b854ac..5fef274 100644 --- a/src/main/java/net/knarcraft/permissionsigns/container/TemporaryPermission.java +++ b/src/main/java/net/knarcraft/permissionsigns/container/TemporaryPermission.java @@ -13,6 +13,7 @@ public class TemporaryPermission implements Comparable { private final OfflinePlayer grantedPlayer; private final String permissionNode; private final int duration; + private final String world; /** * Instantiates a new temporary permission @@ -20,14 +21,14 @@ public class TemporaryPermission implements Comparable { * @param player

The player the temporary permission was assigned to

* @param permissionNode

The permission node granted to the player

* @param duration

The duration, in seconds, the temporary permission should last

+ * @param world

The world the permission should be added to

*/ - public TemporaryPermission(Player player, String permissionNode, int duration) { + public TemporaryPermission(Player player, String permissionNode, int duration, String world) { grantedTime = System.currentTimeMillis(); this.grantedPlayer = player; this.permissionNode = permissionNode; this.duration = duration; - //TODO: Need to account for world. Perhaps have a config option to choose between setting permissions for all - // worlds, or just the world the sign and player is in + this.world = world; } /** @@ -37,12 +38,14 @@ public class TemporaryPermission implements Comparable { * @param permissionNode

The permission node granted to the player

* @param grantedTime

The time this temporary permission was granted

* @param duration

The duration, in seconds, the temporary permission should last

+ * @param world

The world the permission should be added to

*/ - public TemporaryPermission(OfflinePlayer player, String permissionNode, long grantedTime, int duration) { + public TemporaryPermission(OfflinePlayer player, String permissionNode, long grantedTime, int duration, String world) { this.grantedPlayer = player; this.permissionNode = permissionNode; this.grantedTime = grantedTime; this.duration = duration; + this.world = world; } /** @@ -81,6 +84,14 @@ public class TemporaryPermission implements Comparable { return permissionNode; } + /** + * Gets the world the permission node should be added to + * + * @return

The world the permission node should be added to

+ */ + public String getWorld() { + return world; + } @Override public int compareTo(@NotNull TemporaryPermission other) { diff --git a/src/main/java/net/knarcraft/permissionsigns/formatting/TranslatableMessage.java b/src/main/java/net/knarcraft/permissionsigns/formatting/TranslatableMessage.java index 3bbff5e..19c4228 100644 --- a/src/main/java/net/knarcraft/permissionsigns/formatting/TranslatableMessage.java +++ b/src/main/java/net/knarcraft/permissionsigns/formatting/TranslatableMessage.java @@ -90,6 +90,16 @@ public enum TranslatableMessage { */ PERMISSIONS_GRANTED, + /** + * The message to display if a player has specified an invalid world to set a permission for + */ + PERMISSION_WORLD_INVALID, + + /** + * The message to display if a player is missing the permission required for interacting with permission signs + */ + INTERACT_PERMISSION_MISSING, + /** * The message to display when a permission sign has been successfully created */ diff --git a/src/main/java/net/knarcraft/permissionsigns/listener/BlockListener.java b/src/main/java/net/knarcraft/permissionsigns/listener/BlockListener.java new file mode 100644 index 0000000..f598caa --- /dev/null +++ b/src/main/java/net/knarcraft/permissionsigns/listener/BlockListener.java @@ -0,0 +1,48 @@ +package net.knarcraft.permissionsigns.listener; + +import net.knarcraft.permissionsigns.formatting.StringFormatter; +import net.knarcraft.permissionsigns.formatting.TranslatableMessage; +import net.knarcraft.permissionsigns.manager.SignManager; +import org.bukkit.Material; +import org.bukkit.Tag; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; + +public class BlockListener implements Listener { + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) { + Block block = event.getBlock(); + Player player = event.getPlayer(); + + if (event.isCancelled()) { + return; + } + + Material material = block.getBlockData().getMaterial(); + if (!Tag.SIGNS.isTagged(material) && !Tag.WALL_SIGNS.isTagged(material)) { + return; + } + + Sign sign = (Sign) block.getState(); + boolean registered = SignManager.getSign(sign.getLocation()) != null; + if (!registered) { + return; + } + if (!player.hasPermission("permissionsigns.admin.create")) { + event.setCancelled(true); + player.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.PERMISSION_SIGN_DESTROY_DENY)); + } else { + SignManager.removeSign(sign.getLocation()); + player.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.PERMISSION_SIGN_REMOVED)); + } + + //TODO: Need to protect against other things that might damage the sign, such as explosions + //TODO: Only allow the sign to be broken if shift-clicking? + } + +} diff --git a/src/main/java/net/knarcraft/permissionsigns/listener/PlayerListener.java b/src/main/java/net/knarcraft/permissionsigns/listener/PlayerListener.java index fc22c28..19d177a 100644 --- a/src/main/java/net/knarcraft/permissionsigns/listener/PlayerListener.java +++ b/src/main/java/net/knarcraft/permissionsigns/listener/PlayerListener.java @@ -20,7 +20,7 @@ public class PlayerListener implements Listener { Queue temporaryPermissions = new PriorityQueue<>(PermissionManager.getTemporaryPermissions()); temporaryPermissions.removeIf((item) -> !item.getGrantedPlayer().getUniqueId().equals(event.getPlayer().getUniqueId())); temporaryPermissions.forEach((item) -> PermissionManager.grantTemporaryPermission(event.getPlayer(), - item.getPermissionNode())); + item.getPermissionNode(), item.getWorld())); } } diff --git a/src/main/java/net/knarcraft/permissionsigns/listener/SignListener.java b/src/main/java/net/knarcraft/permissionsigns/listener/SignListener.java index 86d0f57..b555627 100644 --- a/src/main/java/net/knarcraft/permissionsigns/listener/SignListener.java +++ b/src/main/java/net/knarcraft/permissionsigns/listener/SignListener.java @@ -16,7 +16,6 @@ import org.bukkit.block.Sign; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import java.util.Arrays; @@ -46,32 +45,7 @@ public class SignListener implements Listener { } Sign sign = (Sign) block.getState(); - if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { - handleSignRightClick(sign, player); - } else if (event.getAction() == Action.LEFT_CLICK_BLOCK) { - handleSignLeftClick(sign, player, event); - } - } - - /** - * Handles the left click of a sign that might be a permission sign - * - * @param sign

The clicked sign

- * @param player

The player that clicked the sign

- * @param event

The triggered interaction event

- */ - private void handleSignLeftClick(Sign sign, Player player, PlayerInteractEvent event) { - boolean registered = SignManager.getSign(sign.getLocation()) != null; - if (!registered) { - return; - } - if (!player.hasPermission("permissionsigns.admin")) { - event.setCancelled(true); - player.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.PERMISSION_SIGN_DESTROY_DENY)); - } else { - SignManager.removeSign(sign.getLocation()); - player.sendMessage(StringFormatter.getTranslatedInfoMessage(TranslatableMessage.PERMISSION_SIGN_REMOVED)); - } + handleSignClick(sign, player); } /** @@ -80,13 +54,18 @@ public class SignListener implements Listener { * @param sign

The clicked sign

* @param player

The player that clicked the sign

*/ - private void handleSignRightClick(Sign sign, Player player) { + private void handleSignClick(Sign sign, Player player) { //Check if the sign is a registered permission sign PermissionSign permissionSign = SignManager.getSign(sign.getLocation()); if (permissionSign != null) { + if (!player.hasPermission("permissionsigns.use")) { + player.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.INTERACT_PERMISSION_MISSING)); + return; + } handlePermissionSignInteract(permissionSign, player); return; } + //TODO: Display information about granted permissions when shift-clicking? //Check if the player has a creation request that can be fulfilled SignCreationRequest request = PermissionSigns.getSignCreationRequest(player.getUniqueId()); @@ -105,7 +84,12 @@ public class SignListener implements Listener { //Don't allow players to pay for permissions they already own boolean hasAllPermissions = true; for (String permissionNode : permissionSign.getPermissionNodes()) { - if (!player.hasPermission(permissionNode)) { + if (permissionNode.contains(":")) { + String[] permissionParts = permissionNode.split(":"); + if (!PermissionManager.hasPermission(player, permissionParts[1], permissionParts[0])) { + hasAllPermissions = false; + } + } else if (!player.hasPermission(permissionNode)) { hasAllPermissions = false; } } @@ -132,7 +116,14 @@ public class SignListener implements Listener { StringBuilder permissionsBuilder = new StringBuilder(); for (String permissionNode : permissionSign.getPermissionNodes()) { //Only grant the permission if not already owned - if (!player.hasPermission(permissionNode)) { + boolean hasPermission; + if (permissionNode.contains(":")) { + String[] permissionParts = permissionNode.split(":"); + hasPermission = PermissionManager.hasPermission(player, permissionParts[1], permissionParts[0]); + } else { + hasPermission = player.hasPermission(permissionNode); + } + if (!hasPermission) { permissionsBuilder.append(permissionNode); permissionsBuilder.append(", "); if (permissionSign.getDuration() == 0) { diff --git a/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java b/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java index d980f42..3cb4429 100644 --- a/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java +++ b/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java @@ -12,6 +12,7 @@ import org.bukkit.entity.Player; import java.io.File; import java.io.IOException; import java.util.Queue; +import java.util.Random; import java.util.UUID; import java.util.concurrent.PriorityBlockingQueue; import java.util.logging.Level; @@ -50,8 +51,13 @@ public class PermissionManager { * @param permissionNode

The permission node to grant to the player

*/ public static void addPermission(Player player, String permissionNode) { - //TODO: Account for world when granting permissions, if wanted - permission.playerAdd(null, player, permissionNode); + //Allow world:permission syntax + if (permissionNode.contains(":")) { + grantWorldPermission(player, permissionNode, false); + } else { + boolean perWorldPermissions = PermissionSigns.usePerWorldPermissions(); + permission.playerAdd(perWorldPermissions ? player.getWorld().getName() : null, player, permissionNode); + } } /** @@ -59,9 +65,36 @@ public class PermissionManager { * * @param player

The player to add the temporary permission to

* @param permissionNode

The permission node to grant

+ * @param worldName

The world to add the permission node to

*/ - public static void grantTemporaryPermission(Player player, String permissionNode) { - permission.playerAddTransient(null, player, permissionNode); + public static void grantTemporaryPermission(Player player, String permissionNode, String worldName) { + //Allow world:permission syntax + if (permissionNode.contains(":")) { + grantWorldPermission(player, permissionNode, true); + } else { + boolean perWorldPermissions = PermissionSigns.usePerWorldPermissions(); + permission.playerAddTransient(perWorldPermissions ? worldName : null, player, permissionNode); + } + } + + /** + * Grants a permission for the world specified in the permission node + * + * @param player

The player to grant the permission node to

+ * @param permissionNode

The permission node to grant

+ * @param temporary

Whether the permission node should be set temporarily

+ */ + private static void grantWorldPermission(Player player, String permissionNode, boolean temporary) { + String[] permissionParts = permissionNode.split(":"); + String world = permissionParts[0]; + if (world.equalsIgnoreCase("all")) { + world = null; + } + if (temporary) { + permission.playerAddTransient(world, player, permissionParts[1]); + } else { + permission.playerAdd(world, player, permissionParts[1]); + } } /** @@ -72,8 +105,9 @@ public class PermissionManager { * @param duration

The duration for which the player should keep the given permission

*/ public static void addTemporaryPermission(Player player, String permissionNode, int duration) { - grantTemporaryPermission(player, permissionNode); - temporaryPermissions.add(new TemporaryPermission(player, permissionNode, duration)); + String world = player.getWorld().getName(); + grantTemporaryPermission(player, permissionNode, world); + temporaryPermissions.add(new TemporaryPermission(player, permissionNode, duration, world)); try { saveTemporaryPermissions(); } catch (IOException e) { @@ -95,6 +129,18 @@ public class PermissionManager { } } + /** + * Checks whether the given player has the given permission + * + * @param player

The player to check

+ * @param permissionNode

The permission node to check for

+ * @param world

The world to check for the permission

+ * @return

True if the player has the permission

+ */ + public static boolean hasPermission(Player player, String permissionNode, String world) { + return permission.playerHas(world, player, permissionNode); + } + /** * Saves all temporary permissions to a file * @@ -103,11 +149,14 @@ public class PermissionManager { public static void saveTemporaryPermissions() throws IOException { YamlConfiguration configuration = YamlConfiguration.loadConfiguration(permissionsFile); ConfigurationSection permissionSection = configuration.createSection("permissions"); + Random random = new Random(); temporaryPermissions.forEach((item) -> { - String key = item.getGrantedPlayer().getUniqueId() + "," + item.getGrantedTime(); + //A random long is added to prevent any conflicts + String key = item.getGrantedPlayer().getUniqueId() + "," + item.getGrantedTime() + "," + random.nextLong(); permissionSection.set(key + ".permissionNode", item.getPermissionNode()); permissionSection.set(key + ".duration", item.getGrantedDuration()); + permissionSection.set(key + ".world", item.getWorld()); }); configuration.save(permissionsFile); } @@ -131,13 +180,13 @@ public class PermissionManager { String permissionNode = permissionSection.getString(key + ".permissionNode"); long granted = Long.parseLong(identifierParts[1]); int duration = permissionSection.getInt(key + ".duration", 1); + String world = permissionSection.getString(key + ".world", null); //Skip any expired temporary permissions if (currentTime > granted + (1000L * duration)) { continue; } - //TODO: Need to wait for the player to join the server before allocating transient permissions - temporaryPermissions.add(new TemporaryPermission(player, permissionNode, granted, duration)); + temporaryPermissions.add(new TemporaryPermission(player, permissionNode, granted, duration, world)); } try { saveTemporaryPermissions(); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 4c5ac1a..f42d657 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -18,6 +18,12 @@ commands: description: Used for all permission sign commands usage: / - Used for all permission sign commands permissions: + permissionsigns.*: + description: Grants all PermissionSigns permissions + default: false + children: + permissionsigns.use: true + permissionsigns.admin: true permissionsigns.use: description: Allows players to use the permission signs default: true diff --git a/src/main/resources/strings.yml b/src/main/resources/strings.yml index 7e22542..732cbff 100644 --- a/src/main/resources/strings.yml +++ b/src/main/resources/strings.yml @@ -16,4 +16,6 @@ en: ALREADY_HAS_PERMISSIONS: "&7You already have all permissions given by this permission sign" PERMISSIONS_GRANTED: "&7You have been granted the following permission nodes: {permissions} for {time}" PERMISSION_SIGN_CREATED: "&7Permission sign successfully created!" + PERMISSION_WORLD_INVALID: "&7The world {world} is not a valid world name on this server!" + INTERACT_PERMISSION_MISSING: "&7You do not have the necessary permissions required to use permission signs" CREATION_REQUEST_CANCELLED: "&7Your last permission sign creation request has been cancelled" \ No newline at end of file