diff --git a/pom.xml b/pom.xml index b4d6f30..648d37a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 net.knarcraft - permissionsigns + PermissionSigns 1.0-SNAPSHOT jar diff --git a/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java b/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java index b9e616c..a8d33f4 100644 --- a/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java +++ b/src/main/java/net/knarcraft/permissionsigns/PermissionSigns.java @@ -5,8 +5,10 @@ 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.SignListener; import net.knarcraft.permissionsigns.manager.EconomyManager; import net.knarcraft.permissionsigns.manager.PermissionManager; +import net.knarcraft.permissionsigns.manager.SignManager; import net.knarcraft.permissionsigns.thread.SignCreationRequestTimeoutThread; import net.milkbowl.vault.economy.Economy; import net.milkbowl.vault.permission.Permission; @@ -19,6 +21,7 @@ import org.bukkit.plugin.ServicesManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitScheduler; +import java.io.IOException; import java.util.List; import java.util.PriorityQueue; import java.util.Queue; @@ -94,7 +97,9 @@ public final class PermissionSigns extends JavaPlugin { Stream matchingRequests = signCreationRequests.stream().filter( (item) -> item.getPlayer().getUniqueId().equals(uuid)); List requestList = matchingRequests.toList(); - signCreationRequests.remove(requestList.get(0)); + if (requestList.size() > 0) { + signCreationRequests.remove(requestList.get(0)); + } } @Override @@ -153,11 +158,13 @@ public final class PermissionSigns extends JavaPlugin { } else { throw new IllegalStateException("[PermissionSigns] Error: Vault could not be loaded"); } + getServer().getPluginManager().registerEvents(new SignListener(), this); Translator.loadLanguages("en"); registerCommands(); BukkitScheduler scheduler = Bukkit.getScheduler(); scheduler.runTaskTimer(this, new SignCreationRequestTimeoutThread(signCreationRequests), 0L, 100L); + SignManager.loadSigns(); } /** @@ -173,7 +180,11 @@ public final class PermissionSigns extends JavaPlugin { @Override public void onDisable() { - // Plugin shutdown logic + try { + SignManager.saveSigns(); + } catch (IOException e) { + e.printStackTrace(); + } } } diff --git a/src/main/java/net/knarcraft/permissionsigns/command/CreateCommand.java b/src/main/java/net/knarcraft/permissionsigns/command/CreateCommand.java index 3e63bd2..0adb9b2 100644 --- a/src/main/java/net/knarcraft/permissionsigns/command/CreateCommand.java +++ b/src/main/java/net/knarcraft/permissionsigns/command/CreateCommand.java @@ -21,6 +21,7 @@ public class CreateCommand implements CommandExecutor { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { // /ps create to create a new permission-sign //Name and permission(s) required, but duration and cost optional + String usage = "/ps create [cost] [duration] - Used for creating a new permission sign"; if (!(sender instanceof Player)) { sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.COMMAND_PLAYER_ONLY)); return false; @@ -31,12 +32,14 @@ public class CreateCommand implements CommandExecutor { } if (args.length < 2) { sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.MISSING_CREATION_INFO)); - return false; + sender.sendMessage(usage); + return true; } PermissionSign newSign = parseSign(sender, args); if (newSign == null) { - return false; + sender.sendMessage(usage); + return true; } PermissionSigns.addSignCreationRequest((Player) sender, newSign); @@ -54,19 +57,23 @@ public class CreateCommand implements CommandExecutor { private PermissionSign parseSign(@NotNull CommandSender sender, @NotNull String[] args) { String name = args[0]; String[] permissions = args[1].split(","); - double cost; - int duration; - try { - cost = Double.parseDouble(args[2]); - } catch (NumberFormatException exception) { - sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.COST_INVALID_NUMBER)); - return null; + double cost = 0; + int duration = 0; + if (args.length > 2) { + try { + cost = Double.parseDouble(args[2]); + } catch (NumberFormatException exception) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.COST_INVALID_NUMBER)); + return null; + } } - try { - duration = Integer.parseInt(args[3]); - } catch (NumberFormatException exception) { - sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.DURATION_INVALID_NUMBER)); - return null; + if (args.length > 3) { + try { + duration = Integer.parseInt(args[3]); + } catch (NumberFormatException exception) { + sender.sendMessage(StringFormatter.getTranslatedErrorMessage(TranslatableMessage.DURATION_INVALID_NUMBER)); + return null; + } } return new PermissionSign(name, List.of(permissions), duration, cost); diff --git a/src/main/java/net/knarcraft/permissionsigns/command/CreateTabCompleter.java b/src/main/java/net/knarcraft/permissionsigns/command/CreateTabCompleter.java index e8c8081..e2e13ee 100644 --- a/src/main/java/net/knarcraft/permissionsigns/command/CreateTabCompleter.java +++ b/src/main/java/net/knarcraft/permissionsigns/command/CreateTabCompleter.java @@ -1,20 +1,159 @@ package net.knarcraft.permissionsigns.command; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabCompleter; +import org.bukkit.permissions.Permission; +import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * The tab completer for the create command */ public class CreateTabCompleter implements TabCompleter { + private static List plugins; + private static Map> permissions; + private static List numbers; + private static List empty; + private static List name; + @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { - return null; + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, + @NotNull String[] args) { + //First, display all plugins, filtering on written text + //Second, if a dot has been input, go to the correct branch, + //Might want to save the plugin list, but generate permission lists on the fly as needed + if (plugins == null) { + loadAvailablePermissions(); + numbers = new ArrayList<>(); + numbers.add(String.valueOf(0)); + empty = new ArrayList<>(); + name = new ArrayList<>(); + name.add(""); + } + + if (args.length > 4) { + return empty; + } else if (args.length > 2) { + return numbers; + } else if (args.length > 1) { + return tabCompletePermission(args[1]); + } else { + return name; + } + } + + /** + * Gets the tab complete value for the permission typed + * + * @param typedNode

The full permission node typed by the player

+ * @return

All known valid auto-complete options

+ */ + private List tabCompletePermission(String typedNode) { + StringBuilder permissionListString = new StringBuilder(); + if (typedNode.contains(",")) { + String[] permissionList = typedNode.split(","); + for (int i = 0; i < permissionList.length - 1; i++) { + permissionListString.append(permissionList[i]); + permissionListString.append(","); + } + typedNode = permissionList[permissionList.length - 1]; + } + String permissionPrefix = permissionListString.toString(); + List output; + if (typedNode.contains(".")) { + List matchingPermissions = permissions.get(typedNode.substring(0, typedNode.lastIndexOf("."))); + if (matchingPermissions == null) { + if (permissionPrefix.isEmpty()) { + output = new ArrayList<>(); + } else { + List onlyPrefix = new ArrayList<>(); + onlyPrefix.add(permissionPrefix); + output = onlyPrefix; + } + } else { + //Filter by the typed text + output = filterMatching(matchingPermissions, typedNode); + } + } else { + output = plugins; + } + + //Add previous permissions in the comma-separated lists as a prefix + if (permissionPrefix.isEmpty()) { + return output; + } else { + List prefixed = new ArrayList<>(output.size()); + for (String matchingCompletion : output) { + prefixed.add(permissionPrefix + matchingCompletion); + } + return prefixed; + } + } + + /** + * Find completable strings which match the text typed by the command's sender + * + * @param values

The values to filter

+ * @param typedText

The text the player has started typing

+ * @return

The given string values which start with the player's typed text

+ */ + private List filterMatching(List values, String typedText) { + List configValues = new ArrayList<>(); + for (String value : values) { + if (value.toLowerCase().startsWith(typedText.toLowerCase())) { + configValues.add(value); + } + } + return configValues; + } + + /** + * Loads all permissions available from bukkit plugins + */ + private static void loadAvailablePermissions() { + plugins = new ArrayList<>(); + permissions = new HashMap<>(); + for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { + for (Permission permission : plugin.getDescription().getPermissions()) { + loadPermission(permission); + } + } + } + + /** + * Loads a given permission into the proper lists and maps + * + * @param permission

The permission to load

+ */ + private static void loadPermission(Permission permission) { + String permissionName = permission.getName(); + String[] permissionParts = permissionName.split("\\."); + for (int i = 0; i < permissionParts.length; i++) { + if (i == 0) { + plugins.add(permissionParts[0]); + } else { + StringBuilder pathBuilder = new StringBuilder(); + for (int j = 0; j < i; j++) { + pathBuilder.append("."); + pathBuilder.append(permissionParts[j]); + } + String path = pathBuilder.substring(1); + List permissionList = permissions.get(path); + if (permissionList == null) { + permissionList = new ArrayList<>(); + permissions.put(pathBuilder.substring(1), permissionList); + } + permissionList.add(permissionName); + } + } } } diff --git a/src/main/java/net/knarcraft/permissionsigns/container/PermissionSign.java b/src/main/java/net/knarcraft/permissionsigns/container/PermissionSign.java index d16943f..d123654 100644 --- a/src/main/java/net/knarcraft/permissionsigns/container/PermissionSign.java +++ b/src/main/java/net/knarcraft/permissionsigns/container/PermissionSign.java @@ -165,7 +165,7 @@ public class PermissionSign { return Translator.getTranslatedMessage(TranslatableMessage.SIGN_COST_FREE); } else { String currency = EconomyManager.getCurrency(cost != 1); - return String.format("%f%s", cost, currency); + return String.format("%.2f%s", cost, currency); } } diff --git a/src/main/java/net/knarcraft/permissionsigns/formatting/StringFormatter.java b/src/main/java/net/knarcraft/permissionsigns/formatting/StringFormatter.java index 734b632..0a426ae 100644 --- a/src/main/java/net/knarcraft/permissionsigns/formatting/StringFormatter.java +++ b/src/main/java/net/knarcraft/permissionsigns/formatting/StringFormatter.java @@ -13,10 +13,10 @@ public class StringFormatter { * @param input

The input string to replace in

* @param placeholder

The placeholder to replace

* @param replacement

The replacement value

- * @return

The input string with all placeholder instances replaced

+ * @return

The input string with the placeholder replaced

*/ public static String replacePlaceholder(String input, String placeholder, String replacement) { - return input.replaceAll(placeholder, replacement); + return input.replace(placeholder, replacement); } /** @@ -25,7 +25,7 @@ public class StringFormatter { * @param input

The input string to replace in

* @param placeholders

The placeholders to replace

* @param replacements

The replacement values

- * @return

The input string with all placeholder instances replaced

+ * @return

The input string with placeholders replaced

*/ public static String replacePlaceholders(String input, String[] placeholders, String[] replacements) { for (int i = 0; i < Math.min(placeholders.length, replacements.length); i++) { @@ -61,7 +61,7 @@ public class StringFormatter { * @return

The formatted message

*/ public static String formatInfoMessage(String message) { - return ChatColor.DARK_RED + formatMessage(message); + return ChatColor.DARK_GREEN + formatMessage(message); } /** @@ -71,7 +71,7 @@ public class StringFormatter { * @return

The formatted message

*/ public static String formatErrorMessage(String message) { - return ChatColor.DARK_GREEN + formatMessage(message); + return ChatColor.DARK_RED + formatMessage(message); } /** @@ -82,7 +82,8 @@ public class StringFormatter { */ private static String formatMessage(String message) { return ChatColor.translateAlternateColorCodes('&', - Translator.getTranslatedMessage(TranslatableMessage.PREFIX)) + ChatColor.RESET + message; + Translator.getTranslatedMessage(TranslatableMessage.PREFIX)) + " " + ChatColor.RESET + + ChatColor.translateAlternateColorCodes('&', message); } } diff --git a/src/main/java/net/knarcraft/permissionsigns/listener/SignListener.java b/src/main/java/net/knarcraft/permissionsigns/listener/SignListener.java index 8efe385..86d0f57 100644 --- a/src/main/java/net/knarcraft/permissionsigns/listener/SignListener.java +++ b/src/main/java/net/knarcraft/permissionsigns/listener/SignListener.java @@ -135,7 +135,11 @@ public class SignListener implements Listener { if (!player.hasPermission(permissionNode)) { permissionsBuilder.append(permissionNode); permissionsBuilder.append(", "); - PermissionManager.addPermission(player, permissionNode, permissionSign.getDuration() == 0); + if (permissionSign.getDuration() == 0) { + PermissionManager.addPermission(player, permissionNode); + } else { + PermissionManager.addTemporaryPermission(player, permissionNode, permissionSign.getDuration()); + } } } @@ -144,7 +148,7 @@ public class SignListener implements Listener { grantedPermissions = grantedPermissions.substring(0, grantedPermissions.length() - 2); String timeUnit = Translator.getTranslatedMessage(TranslatableMessage.SIGN_TIME_UNIT); player.sendMessage(StringFormatter.replacePlaceholders(successMessage, new String[]{"{permissions}", "{time}"}, - new String[]{grantedPermissions, permissionSign.getDuration() + timeUnit})); + new String[]{grantedPermissions, permissionSign.getDuration() + " " + timeUnit})); } /** diff --git a/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java b/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java index 7c1be1d..3158a85 100644 --- a/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java +++ b/src/main/java/net/knarcraft/permissionsigns/manager/PermissionManager.java @@ -24,28 +24,13 @@ public class PermissionManager { PermissionManager.permission = permission; } - /** - * Grants a permission to the given player - * - * @param player

The player to grant the permission to

- * @param permissionNode

The permission node to grant the player

- * @param permanent

Whether to permanently grant the permission node

- */ - public static void addPermission(Player player, String permissionNode, boolean permanent) { - if (permanent) { - addPermission(player, permissionNode); - } else { - addTemporaryPermission(player, permissionNode); - } - } - /** * Grants a permanent permission to a player * * @param player

The player to grant the permission to

* @param permissionNode

The permission node to grant to the player

*/ - private static void addPermission(Player player, String permissionNode) { + public static void addPermission(Player player, String permissionNode) { permission.playerAdd(player, permissionNode); } @@ -54,9 +39,11 @@ public class PermissionManager { * * @param player

The player to give the permission to

* @param permissionNode

The temporary permission to grant

+ * @param duration

The duration for which the player should keep the given permission

*/ - private static void addTemporaryPermission(OfflinePlayer player, String permissionNode) { + public static void addTemporaryPermission(OfflinePlayer player, String permissionNode, int duration) { permission.playerAddTransient(player, permissionNode); + temporaryPermissions.add(new TemporaryPermission(player, permissionNode, duration)); //TODO: Create and store a temporary permission // Check all stored temporary permissions on startup: // * Remove expired temporary permissions diff --git a/src/main/java/net/knarcraft/permissionsigns/manager/SignManager.java b/src/main/java/net/knarcraft/permissionsigns/manager/SignManager.java index 7d21a4c..89356b9 100644 --- a/src/main/java/net/knarcraft/permissionsigns/manager/SignManager.java +++ b/src/main/java/net/knarcraft/permissionsigns/manager/SignManager.java @@ -15,6 +15,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.UUID; import java.util.logging.Level; /** @@ -81,10 +82,10 @@ public class SignManager { */ public static void loadSigns() { YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile); - ConfigurationSection signSection = configuration.getConfigurationSection("signs"); managedSigns = new HashMap<>(); if (signSection == null) { + PermissionSigns.getInstance().getLogger().log(Level.WARNING, "Signs section not found in signs.yml"); return; } for (String key : signSection.getKeys(false)) { @@ -95,6 +96,7 @@ public class SignManager { e.getMessage()); } } + PermissionSigns.getInstance().getLogger().log(Level.INFO, "Permission signs finished loading"); //TODO: Might want to re-draw signs here in case any signs have changed } @@ -120,8 +122,9 @@ public class SignManager { String[] locationParts = key.split(","); Location signLocation; try { - signLocation = new Location(Bukkit.getWorld(locationParts[0]), Double.parseDouble(locationParts[1]), - Double.parseDouble(locationParts[2]), Double.parseDouble(locationParts[3])); + signLocation = new Location(Bukkit.getWorld(UUID.fromString(locationParts[0])), + Double.parseDouble(locationParts[1]), Double.parseDouble(locationParts[2]), + Double.parseDouble(locationParts[3])); } catch (NumberFormatException exception) { throw new InvalidConfigurationException("Invalid sign coordinates"); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 90c0f18..4c5ac1a 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: PermissionSigns -version: '${project.version}' -main: net.knarcraft.permissionsigns.Permissionsigns +version: 1.0 +main: net.knarcraft.permissionsigns.PermissionSigns api-version: 1.18 prefix: PermissionSigns depend: [ Vault ]