diff --git a/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java b/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java index a6f59ab..fd4d8a4 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java @@ -24,16 +24,22 @@ import net.knarcraft.bookswithoutborders.command.CommandSetLore; import net.knarcraft.bookswithoutborders.command.CommandSetTitle; import net.knarcraft.bookswithoutborders.command.CommandUnSign; import net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig; +import net.knarcraft.bookswithoutborders.config.BwBCommand; +import net.knarcraft.bookswithoutborders.config.StaticMessage; +import net.knarcraft.bookswithoutborders.config.Translatable; import net.knarcraft.bookswithoutborders.handler.BookshelfHandler; import net.knarcraft.bookswithoutborders.listener.BookEventListener; import net.knarcraft.bookswithoutborders.listener.BookshelfListener; import net.knarcraft.bookswithoutborders.listener.PlayerEventListener; import net.knarcraft.bookswithoutborders.listener.SignEventListener; import net.knarcraft.bookswithoutborders.utility.BookFileHelper; +import net.knarcraft.knarlib.formatting.StringFormatter; +import net.knarcraft.knarlib.formatting.Translator; +import net.knarcraft.knarlib.property.ColorConversion; import net.knarcraft.knarlib.util.UpdateChecker; +import net.md_5.bungee.api.ChatColor; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; @@ -69,17 +75,16 @@ public class BooksWithoutBorders extends JavaPlugin { private static Map publicLetterIndex; private static Map> playerLetterIndex; private static BooksWithoutBorders booksWithoutBorders; - private static ConsoleCommandSender consoleSender; private static BookshelfHandler bookshelfHandler; + private static StringFormatter stringFormatter; /** - * Gets the console sender for printing to the console + * Gets the string formatter * - * @return

The console's console sender

+ * @return

The string formatter

*/ - @NotNull - public static ConsoleCommandSender getConsoleSender() { - return consoleSender; + public static StringFormatter getStringFormatter() { + return stringFormatter; } /** @@ -163,12 +168,18 @@ public class BooksWithoutBorders extends JavaPlugin { PluginDescriptionFile pluginDescriptionFile = this.getDescription(); String pluginVersion = pluginDescriptionFile.getVersion(); + Translator translator = new Translator(); + translator.registerMessageCategory(Translatable.PREFIX); + stringFormatter = new StringFormatter(this.getDescription().getName(), translator); + stringFormatter.setColorConversion(ColorConversion.RGB); + stringFormatter.setSuccessColor(ChatColor.of("#A9FF84")); + stringFormatter.setErrorColor(ChatColor.of("#FF84A9")); + booksWithoutBorders = this; - consoleSender = this.getServer().getConsoleSender(); playerBooksList = new HashMap<>(); playerLetterIndex = new HashMap<>(); - BooksWithoutBordersConfig.initialize(this); - @Nullable List files = BookFileHelper.listFiles(consoleSender, true); + BooksWithoutBordersConfig.initialize(this, translator); + @Nullable List files = BookFileHelper.listFiles(this.getServer().getConsoleSender(), true); if (files != null) { publicBooksList = files; publicLetterIndex = BookFileHelper.populateLetterIndices(files); @@ -207,29 +218,29 @@ public class BooksWithoutBorders extends JavaPlugin { * Registers all commands used by this plugin */ private void registerCommands() { - registerCommand("giveBook", new CommandGive()); - registerCommand("givePublicBook", new CommandGivePublic()); - registerCommand("decryptBook", new CommandDecrypt()); - registerCommand("groupEncryptBook", new CommandGroupEncrypt()); - registerCommand("deleteBook", new CommandDelete()); - registerCommand("deletePublicBook", new CommandDeletePublic()); - registerCommand("copyBook", new CommandCopy()); - registerCommand("unSignBook", new CommandUnSign()); - registerCommand("encryptBook", new CommandEncrypt()); - registerCommand("setBookPrice", new CommandSetBookPrice()); - registerCommand("setLore", new CommandSetLore()); - registerCommand("savePublicBook", new CommandSavePublic()); - registerCommand("saveBook", new CommandSave()); - registerCommand("setBookAuthor", new CommandSetAuthor()); - registerCommand("setTitle", new CommandSetTitle()); - registerCommand("loadBook", new CommandLoad()); - registerCommand("loadPublicBook", new CommandLoadPublic()); - registerCommand("booksWithoutBorders", new CommandBooksWithoutBorders()); - registerCommand("reload", new CommandReload()); - registerCommand("formatBook", new CommandFormat()); - registerCommand("setBookGeneration", new CommandSetGeneration()); - registerCommand("clearBook", new CommandClear()); - registerCommand("setBookshelfData", new CommandSetBookshelfData()); + registerCommand(BwBCommand.GIVE_BOOK.toString(), new CommandGive()); + registerCommand(BwBCommand.GIVE_PUBLIC_BOOK.toString(), new CommandGivePublic()); + registerCommand(BwBCommand.DECRYPT_BOOK.toString(), new CommandDecrypt()); + registerCommand(BwBCommand.GROUP_ENCRYPT_BOOK.toString(), new CommandGroupEncrypt()); + registerCommand(BwBCommand.DELETE_BOOK.toString(), new CommandDelete()); + registerCommand(BwBCommand.DELETE_PUBLIC_BOOK.toString(), new CommandDeletePublic()); + registerCommand(BwBCommand.COPY_BOOK.toString(), new CommandCopy()); + registerCommand(BwBCommand.UNSIGN_BOOK.toString(), new CommandUnSign()); + registerCommand(BwBCommand.ENCRYPT_BOOK.toString(), new CommandEncrypt()); + registerCommand(BwBCommand.SET_BOOK_PRICE.toString(), new CommandSetBookPrice()); + registerCommand(BwBCommand.SET_LORE.toString(), new CommandSetLore()); + registerCommand(BwBCommand.SAVE_PUBLIC_BOOK.toString(), new CommandSavePublic()); + registerCommand(BwBCommand.SAVE_BOOK.toString(), new CommandSave()); + registerCommand(BwBCommand.SET_BOOK_AUTHOR.toString(), new CommandSetAuthor()); + registerCommand(BwBCommand.SET_TITLE.toString(), new CommandSetTitle()); + registerCommand(BwBCommand.LOAD_BOOK.toString(), new CommandLoad()); + registerCommand(BwBCommand.LOAD_PUBLIC_BOOK.toString(), new CommandLoadPublic()); + registerCommand(BwBCommand.BOOKS_WITHOUT_BORDERS.toString(), new CommandBooksWithoutBorders()); + registerCommand(BwBCommand.RELOAD.toString(), new CommandReload()); + registerCommand(BwBCommand.FORMAT_BOOK.toString(), new CommandFormat()); + registerCommand(BwBCommand.SET_BOOK_GENERATION.toString(), new CommandSetGeneration()); + registerCommand(BwBCommand.CLEAR_BOOK.toString(), new CommandClear()); + registerCommand(BwBCommand.SET_BOOKSHELF_DATA.toString(), new CommandSetBookshelfData()); } /** @@ -243,7 +254,7 @@ public class BooksWithoutBorders extends JavaPlugin { if (pluginCommand != null) { pluginCommand.setExecutor(executor); } else { - sendErrorMessage(consoleSender, "Failed to register command " + commandName); + getLogger().log(Level.SEVERE, "Failed to register command " + commandName); } } @@ -256,10 +267,11 @@ public class BooksWithoutBorders extends JavaPlugin { //Initialize Item Factory try { itemFactory = this.getServer().getItemFactory(); - } catch (java.lang.NoSuchMethodError nsmE) { - sendErrorMessage(consoleSender, "Warning! [BooksWithoutBorders] failed to initialize!"); - sendErrorMessage(consoleSender, "Please confirm the correct version of [BooksWithoutBorders] is"); - sendErrorMessage(consoleSender, "being run for this version of bukkit!"); + } catch (java.lang.NoSuchMethodError noSuchMethodError) { + getLogger().log(Level.SEVERE, """ + Warning! [BooksWithoutBorders] failed to initialize! + Please confirm the correct version of [BooksWithoutBorders] is + being run for this version of spigot!"""); return false; } @@ -304,22 +316,22 @@ public class BooksWithoutBorders extends JavaPlugin { if (!fileTest.exists()) { try { if (!fileTest.mkdir()) { - sendErrorMessage(consoleSender, "Saving failed! Aborting..."); + getLogger().log(Level.SEVERE, StaticMessage.BOOK_SAVING_FAILED.toString()); return false; } } catch (Exception exception) { - BooksWithoutBorders.getInstance().getLogger().log(Level.SEVERE, "Unable to create necessary folders"); + getLogger().log(Level.SEVERE, StaticMessage.BOOK_FOLDER_CREATE_FAILED.toString()); return false; } } if (!encryptedFileTest.exists()) { try { if (!encryptedFileTest.mkdir()) { - sendErrorMessage(consoleSender, "Saving failed! Aborting..."); + getLogger().log(Level.SEVERE, StaticMessage.BOOK_SAVING_FAILED.toString()); return false; } } catch (Exception exception) { - BooksWithoutBorders.getInstance().getLogger().log(Level.SEVERE, "Unable to create necessary folders"); + getLogger().log(Level.SEVERE, StaticMessage.BOOK_FOLDER_CREATE_FAILED.toString()); return false; } } diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandBooksWithoutBorders.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandBooksWithoutBorders.java index f20923a..3c6b345 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandBooksWithoutBorders.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandBooksWithoutBorders.java @@ -2,7 +2,12 @@ package net.knarcraft.bookswithoutborders.command; import net.knarcraft.bookswithoutborders.BooksWithoutBorders; import net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig; +import net.knarcraft.bookswithoutborders.config.BwBCommand; +import net.knarcraft.bookswithoutborders.config.Permission; +import net.knarcraft.bookswithoutborders.config.StaticMessage; +import net.knarcraft.bookswithoutborders.config.Translatable; import net.knarcraft.bookswithoutborders.utility.EconomyHelper; +import net.knarcraft.knarlib.formatting.StringFormatter; import org.bukkit.Material; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -13,10 +18,7 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; - -import static net.knarcraft.bookswithoutborders.BooksWithoutBorders.sendErrorMessage; -import static net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig.getCommandColor; -import static net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig.getSuccessColor; +import java.util.logging.Level; /** * Command executor for the books without borders (bwb) command @@ -24,29 +26,68 @@ import static net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig public class CommandBooksWithoutBorders implements TabExecutor { @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - sender.sendMessage(getCommandColor() + "[] denote optional parameters"); - sender.sendMessage(getCommandColor() + "<> denote required parameters"); - sender.sendMessage(getCommandColor() + "{} denote required permission"); - sender.sendMessage(getCommandColor() + "In some cases, commands with required parameters can be called with no parameters"); - if (sender instanceof Player) { - showPlayerCommands(sender); - } else { - showConsoleCommands(sender); - } + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, + @NotNull String[] arguments) { + StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter(); + String header = stringFormatter.replacePlaceholders(Translatable.NEUTRAL_COMMANDS_HEADER, + List.of("{bookPrice}", "{commands}"), List.of(getBookPrice(), getCommands(sender))); + sender.sendMessage(header); return true; } + /** + * Gets the list of commands + * + * @param sender

The command sender trying to see available commands

+ * @return

The string representation of all commands

+ */ + @NotNull + private String getCommands(@NotNull CommandSender sender) { + if (sender instanceof Player) { + return showPlayerCommands(sender); + } else { + return showConsoleCommands(sender); + } + } + + /** + * Gets the price of duplicating a book + * + * @return

The book price

+ */ + @NotNull + private String getBookPrice() { + if (!BooksWithoutBordersConfig.booksHavePrice()) { + return ""; + } + + StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter(); + Material bookPriceType = BooksWithoutBordersConfig.getBookPriceType(); + double bookPriceQuantity = BooksWithoutBordersConfig.getBookPriceQuantity(); + if (bookPriceType != Material.AIR) { + return stringFormatter.replacePlaceholders(Translatable.NEUTRAL_COMMANDS_BOOK_PRICE_ITEM, + List.of("{quantity}", "{type}"), + List.of(String.valueOf((int) bookPriceQuantity), bookPriceType.toString())); + } else { + return stringFormatter.replacePlaceholder(Translatable.NEUTRAL_COMMANDS_BOOK_PRICE_ECO, + "{price}", EconomyHelper.getEconomy().format(bookPriceQuantity)); + } + } + /** * Shows all commands available to the console * * @param sender

The console which sent the command

*/ - private void showConsoleCommands(@NotNull CommandSender sender) { - sender.sendMessage(getCommandColor() + "Commands:"); - showCommandInfo("deletePublicBook", sender); - showCommandInfo("givePublicBook", sender); - showCommandInfo("reload", sender); + @NotNull + private String showConsoleCommands(@NotNull CommandSender sender) { + StringBuilder builder = new StringBuilder(); + for (BwBCommand command : BwBCommand.values()) { + if (!command.requiresPlayer()) { + builder.append(showCommandInfo(command.toString(), sender)); + } + } + return builder.toString(); } /** @@ -54,44 +95,13 @@ public class CommandBooksWithoutBorders implements TabExecutor { * * @param sender

The player which sent the command

*/ - private void showPlayerCommands(@NotNull CommandSender sender) { - //Lists all commands - Material bookPriceType = BooksWithoutBordersConfig.getBookPriceType(); - double bookPriceQuantity = BooksWithoutBordersConfig.getBookPriceQuantity(); - if (BooksWithoutBordersConfig.booksHavePrice()) { - if (bookPriceType != Material.AIR) { - sendErrorMessage(sender, "[" + (int) bookPriceQuantity + " " + bookPriceType.toString() + - "(s) are required to create a book]"); - } else { - sendErrorMessage(sender, "[" + EconomyHelper.getEconomy().format(bookPriceQuantity) + - " is required to create a book]"); - } + @NotNull + private String showPlayerCommands(@NotNull CommandSender sender) { + StringBuilder builder = new StringBuilder(); + for (BwBCommand command : BwBCommand.values()) { + builder.append(showCommandInfo(command.toString(), sender)); } - sender.sendMessage(getCommandColor() + "Commands:"); - - showCommandInfo("booksWithoutBorders", sender); - showCommandInfo("copyBook", sender); - showCommandInfo("decryptBook", sender); - showCommandInfo("deleteBook", sender); - showCommandInfo("deletePublicBook", sender); - showCommandInfo("encryptBook", sender); - showCommandInfo("formatBook", sender); - showCommandInfo("giveBook", sender); - showCommandInfo("givePublicBook", sender); - showCommandInfo("groupEncryptBook", sender); - showCommandInfo("loadBook", sender); - showCommandInfo("loadPublicBook", sender); - showCommandInfo("reload", sender); - showCommandInfo("saveBook", sender); - showCommandInfo("savePublicBook", sender); - showCommandInfo("setAuthor", sender); - showCommandInfo("setBookGeneration", sender); - showCommandInfo("setBookPrice", sender); - showCommandInfo("setLore", sender); - showCommandInfo("setTitle", sender); - showCommandInfo("unsignBook", sender); - showCommandInfo("clearBook", sender); - showCommandInfo("setBookshelfData", sender); + return builder.toString(); } /** @@ -100,22 +110,32 @@ public class CommandBooksWithoutBorders implements TabExecutor { * @param command

The command to get information about

* @param sender

The sender asking to see command info

*/ - private void showCommandInfo(@NotNull String command, @NotNull CommandSender sender) { + @NotNull + private String showCommandInfo(@NotNull String command, @NotNull CommandSender sender) { PluginCommand pluginCommand = BooksWithoutBorders.getInstance().getCommand(command); - if (pluginCommand != null) { - String permission = pluginCommand.getPermission(); - if (permission == null || sender.hasPermission(permission)) { - String commandInfo = "\n" + getCommandColor() + pluginCommand.getUsage().replace("", - pluginCommand.getName()) + ": " + getSuccessColor() + pluginCommand.getDescription(); - if (sender.hasPermission("bookswithoutborders.admin")) { - if (permission == null) { - permission = "None"; - } - commandInfo += getCommandColor() + " {" + permission + "}"; - } - sender.sendMessage(commandInfo); - } + if (pluginCommand == null) { + BooksWithoutBorders.getInstance().getLogger().log(Level.SEVERE, StringFormatter.replacePlaceholder( + StaticMessage.COMMAND_NOT_REGISTERED.toString(), "{command}", command)); + return ""; } + + String permission = pluginCommand.getPermission(); + if (permission != null && !sender.hasPermission(permission)) { + return ""; + } + + StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter(); + String commandDescription = stringFormatter.replacePlaceholders(Translatable.NEUTRAL_COMMANDS_COMMAND, + List.of("{usage}", "{description}"), List.of(pluginCommand.getUsage().replace("", + pluginCommand.getName()), pluginCommand.getDescription())); + + if (sender.hasPermission(Permission.ADMIN.toString())) { + if (permission == null) { + permission = stringFormatter.getUnFormattedColoredMessage(Translatable.NEUTRAL_COMMANDS_COMMAND_NO_PERMISSION_REQUIRED); + } + commandDescription += stringFormatter.replacePlaceholder(Translatable.NEUTRAL_COMMANDS_COMMAND_PERMISSION, "{permission}", permission); + } + return commandDescription; } @Override diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandClear.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandClear.java index a1eba8d..68645f4 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandClear.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandClear.java @@ -1,6 +1,7 @@ package net.knarcraft.bookswithoutborders.command; import net.knarcraft.bookswithoutborders.BooksWithoutBorders; +import net.knarcraft.bookswithoutborders.config.Translatable; import net.knarcraft.bookswithoutborders.utility.InventoryHelper; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -23,7 +24,7 @@ public class CommandClear implements TabExecutor { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { if (!(sender instanceof Player player)) { - BooksWithoutBorders.sendErrorMessage(sender, "This command can only be used by a player!"); + BooksWithoutBorders.getStringFormatter().displayErrorMessage(sender, Translatable.ERROR_PLAYER_ONLY); return false; } diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandCopy.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandCopy.java index 706343b..93fbbb3 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandCopy.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandCopy.java @@ -2,10 +2,13 @@ package net.knarcraft.bookswithoutborders.command; import net.knarcraft.bookswithoutborders.BooksWithoutBorders; import net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig; +import net.knarcraft.bookswithoutborders.config.Permission; +import net.knarcraft.bookswithoutborders.config.Translatable; import net.knarcraft.bookswithoutborders.utility.BookHelper; import net.knarcraft.bookswithoutborders.utility.EconomyHelper; import net.knarcraft.bookswithoutborders.utility.InventoryHelper; import net.knarcraft.bookswithoutborders.utility.TabCompletionTypeHelper; +import net.knarcraft.knarlib.formatting.StringFormatter; import net.knarcraft.knarlib.util.TabCompletionHelper; import org.bukkit.Material; import org.bukkit.command.Command; @@ -28,18 +31,21 @@ public class CommandCopy implements TabExecutor { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] arguments) { + StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter(); + if (!(sender instanceof Player player)) { - BooksWithoutBorders.sendErrorMessage(sender, "This command can only be used by a player!"); + stringFormatter.displayErrorMessage(sender, Translatable.ERROR_PLAYER_ONLY); return false; } - if (InventoryHelper.notHoldingOneWrittenBookCheck(player, "You must be holding a written book to copy it!", - "You cannot copy two books at once!")) { + if (InventoryHelper.notHoldingOneWrittenBookCheck(player, + stringFormatter.getUnFormattedColoredMessage(Translatable.ERROR_NOT_HOLDING_BOOK_COPY), + stringFormatter.getUnFormattedColoredMessage(Translatable.ERROR_ONLY_ONE_BOOK_COPY))) { return false; } if (arguments.length < 1) { - BooksWithoutBorders.sendErrorMessage(player, "You must specify the number of copies to be made!"); + stringFormatter.displayErrorMessage(player, Translatable.ERROR_COPY_COUNT_NOT_SPECIFIED); return false; } @@ -47,12 +53,12 @@ public class CommandCopy implements TabExecutor { ItemStack heldBook = InventoryHelper.getHeldBook(player, true); int copies = Integer.parseInt(arguments[0]); if (copies <= 0) { - throw new NumberFormatException("Number of copies must be larger than 0"); + stringFormatter.displayErrorMessage(player, Translatable.ERROR_COPY_NEGATIVE_AMOUNT); + return false; } return performCopy(copies, player, heldBook); } catch (NumberFormatException ignored) { - BooksWithoutBorders.sendErrorMessage(player, "Book not copied!"); - BooksWithoutBorders.sendErrorMessage(player, "Number specified was invalid!"); + stringFormatter.displayErrorMessage(player, Translatable.ERROR_COPY_INVALID_AMOUNT); return false; } } @@ -68,7 +74,7 @@ public class CommandCopy implements TabExecutor { private boolean performCopy(int copies, @NotNull Player player, @NotNull ItemStack heldBook) { //Make sure the player owns the book if authorOnlyCopy is enabled if (BooksWithoutBordersConfig.getAuthorOnlyCopy() && - !player.hasPermission("bookswithoutborders.bypassAuthorOnlyCopy")) { + !player.hasPermission(Permission.BYPASS_AUTHOR_ONLY_COPY.toString())) { if (BookHelper.isNotAuthor(player, (BookMeta) Objects.requireNonNull(heldBook.getItemMeta()))) { return false; } @@ -84,7 +90,7 @@ public class CommandCopy implements TabExecutor { } heldBook.setAmount(heldBook.getAmount() + copies); - BooksWithoutBorders.sendSuccessMessage(player, "Book copied!"); + BooksWithoutBorders.getStringFormatter().displaySuccessMessage(player, Translatable.SUCCESS_COPY); return true; } } @@ -98,7 +104,7 @@ public class CommandCopy implements TabExecutor { */ private boolean paymentUnSuccessful(@NotNull Player player, int copies) { return BooksWithoutBordersConfig.booksHavePrice() && - !player.hasPermission("bookswithoutborders.bypassBookPrice") && + !player.hasPermission(Permission.BYPASS_BOOK_PRICE.toString()) && EconomyHelper.cannotPayForBookPrinting(player, copies); } @@ -114,14 +120,13 @@ public class CommandCopy implements TabExecutor { //Copy the vanilla behavior of refusing copying any further if (bookMeta.getGeneration() == BookMeta.Generation.COPY_OF_COPY || bookMeta.getGeneration() == BookMeta.Generation.TATTERED) { - BooksWithoutBorders.sendErrorMessage(player, "You cannot copy this book any further. " + - "You must have the original or a direct copy."); + BooksWithoutBorders.getStringFormatter().displayErrorMessage(player, Translatable.ERROR_BOOK_COPIED_TOO_FAR); return false; } //Make sure the player can fit the book in their inventory int nextAvailableSlot = player.getInventory().firstEmpty(); if (nextAvailableSlot == -1) { - BooksWithoutBorders.sendErrorMessage(player, "You need an available slot in your inventory."); + BooksWithoutBorders.getStringFormatter().displayErrorMessage(player, Translatable.ERROR_INVENTORY_FULL); return false; } //Make sure the player can pay for the copying diff --git a/src/main/java/net/knarcraft/bookswithoutborders/config/BooksWithoutBordersConfig.java b/src/main/java/net/knarcraft/bookswithoutborders/config/BooksWithoutBordersConfig.java index c4a975c..c261c19 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/config/BooksWithoutBordersConfig.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/config/BooksWithoutBordersConfig.java @@ -2,18 +2,18 @@ package net.knarcraft.bookswithoutborders.config; import net.knarcraft.bookswithoutborders.BooksWithoutBorders; import net.knarcraft.bookswithoutborders.utility.EconomyHelper; +import net.knarcraft.knarlib.formatting.Translator; import net.md_5.bungee.api.ChatColor; import org.bukkit.Material; -import org.bukkit.command.ConsoleCommandSender; import org.bukkit.configuration.Configuration; import org.jetbrains.annotations.NotNull; import java.nio.file.FileSystems; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; -import static net.knarcraft.bookswithoutborders.BooksWithoutBorders.sendErrorMessage; -import static net.knarcraft.bookswithoutborders.BooksWithoutBorders.sendSuccessMessage; import static net.knarcraft.bookswithoutborders.utility.InputCleaningHelper.cleanString; /** @@ -44,15 +44,18 @@ public class BooksWithoutBordersConfig { private static boolean changeGenerationOnCopy; private static boolean enableBookshelfPeeking; + private static Translator translator; + /** * Initializes the books without borders settings class * * @param booksWithoutBorders

The books without borders object used for getting required data

*/ - public static void initialize(@NotNull BooksWithoutBorders booksWithoutBorders) { + public static void initialize(@NotNull BooksWithoutBorders booksWithoutBorders, @NotNull Translator translator) { if (isInitialized) { throw new IllegalArgumentException("Settings class initialized twice. This should not happen!"); } + BooksWithoutBordersConfig.translator = translator; isInitialized = true; bookFolder = booksWithoutBorders.getDataFolder().getAbsolutePath() + getSlash() + "Books" + getSlash(); loadConfig(); @@ -275,7 +278,7 @@ public class BooksWithoutBordersConfig { * Saves the config */ public static void saveConfigValues() { - ConsoleCommandSender consoleSender = BooksWithoutBorders.getInstance().getServer().getConsoleSender(); + Logger logger = BooksWithoutBorders.getInstance().getLogger(); Configuration config = BooksWithoutBorders.getInstance().getConfig(); config.set(ConfigOption.USE_YAML.getConfigNode(), useYml); config.set(ConfigOption.MAX_DUPLICATES.getConfigNode(), bookDuplicateLimit); @@ -306,9 +309,8 @@ public class BooksWithoutBordersConfig { //Handles old book and quill settings if (config.contains("Options.Require_book_and_quill_to_create_book")) { - sendSuccessMessage(consoleSender, "[BooksWithoutBorders] Found old config setting " + - "\"Require_book_and_quill_to_create_book\""); - sendSuccessMessage(consoleSender, "Updating to \"Price_to_create_book\" settings"); + logger.log(Level.INFO, "[BooksWithoutBorders] Found old config setting " + + "\"Require_book_and_quill_to_create_book\"\nUpdating to \"Price_to_create_book\" settings"); if (config.getBoolean("Options.Require_book_and_quill_to_create_book")) { bookPriceType = Material.WRITABLE_BOOK; @@ -327,7 +329,7 @@ public class BooksWithoutBordersConfig { * @return

True if the config was loaded successfully

*/ public static boolean loadConfig() { - ConsoleCommandSender consoleSender = BooksWithoutBorders.getInstance().getServer().getConsoleSender(); + Logger logger = BooksWithoutBorders.getInstance().getLogger(); BooksWithoutBorders.getInstance().reloadConfig(); Configuration config = BooksWithoutBorders.getInstance().getConfig(); try { @@ -345,6 +347,8 @@ public class BooksWithoutBordersConfig { formatBooks = getBoolean(config, ConfigOption.FORMAT_AFTER_SIGNING); changeGenerationOnCopy = getBoolean(config, ConfigOption.CHANGE_GENERATION_ON_COPY); enableBookshelfPeeking = getBoolean(config, ConfigOption.ENABLE_BOOKSHELF_PEEKING); + String language = config.getString("language", "en"); + translator.loadLanguages(BooksWithoutBorders.getInstance().getDataFolder(), "en", language); //Convert string into material String paymentMaterial = getString(config, ConfigOption.PRICE_ITEM_TYPE); @@ -352,8 +356,7 @@ public class BooksWithoutBordersConfig { if (EconomyHelper.setupEconomy()) { bookPriceType = Material.AIR; } else { - sendErrorMessage(consoleSender, - "BooksWithoutBorders failed to hook into Vault! Book price not set!"); + logger.log(Level.SEVERE, "BooksWithoutBorders failed to hook into Vault! Book price not set!"); bookPriceType = null; } } else if (!paymentMaterial.trim().isEmpty()) { @@ -368,14 +371,14 @@ public class BooksWithoutBordersConfig { //Make sure titleAuthorSeparator is a valid value titleAuthorSeparator = cleanString(titleAuthorSeparator); if (titleAuthorSeparator.length() != 1) { - sendErrorMessage(consoleSender, "Title-Author_Separator is set to an invalid value!"); - sendErrorMessage(consoleSender, "Reverting to default value of \",\""); + logger.log(Level.SEVERE, "Title-Author_Separator is set to an invalid value!\n" + + "Reverting to default value of \",\""); titleAuthorSeparator = ","; config.set("Options.Title-Author_Separator", titleAuthorSeparator); } } catch (Exception e) { - sendErrorMessage(consoleSender, "Warning! Config.yml failed to load!"); - sendErrorMessage(consoleSender, "Try Looking for settings that are missing values!"); + logger.log(Level.SEVERE, "Warning! Config.yml failed to load!\n" + + "Try Looking for settings that are missing values!"); return false; } diff --git a/src/main/java/net/knarcraft/bookswithoutborders/config/BwBCommand.java b/src/main/java/net/knarcraft/bookswithoutborders/config/BwBCommand.java new file mode 100644 index 0000000..2a4610c --- /dev/null +++ b/src/main/java/net/knarcraft/bookswithoutborders/config/BwBCommand.java @@ -0,0 +1,160 @@ +package net.knarcraft.bookswithoutborders.config; + +import org.jetbrains.annotations.NotNull; + +/** + * A representation of a BwB command + */ +public enum BwBCommand { + + /** + * The help command + */ + BOOKS_WITHOUT_BORDERS("booksWithoutBorders", false), + + /** + * Clears the contents of a book + */ + CLEAR_BOOK("clearBook", true), + + /** + * Copies the held book + */ + COPY_BOOK("copyBook", true), + + /** + * Decrypts the held encrypted book + */ + DECRYPT_BOOK("decryptBook", true), + + /** + * Deletes a book from a player's private collection + */ + DELETE_BOOK("deleteBook", true), + + /** + * Deletes a book from the public collection + */ + DELETE_PUBLIC_BOOK("deletePublicBook", false), + + /** + * Encrypts the held book + */ + ENCRYPT_BOOK("encryptBook", true), + + /** + * Executes formatting codes in the held book + */ + FORMAT_BOOK("formatBook", true), + + /** + * Gives a book from a player's private collection to another player + */ + GIVE_BOOK("giveBook", true), + + /** + * Gives a book from the public collection to a player + */ + GIVE_PUBLIC_BOOK("givePublicBook", false), + + /** + * Encrypts a book for specific group + */ + GROUP_ENCRYPT_BOOK("groupEncryptBook", true), + + /** + * Loads a book from a player's private collection + */ + LOAD_BOOK("loadBook", true), + + /** + * Loads a book from the public collection + */ + LOAD_PUBLIC_BOOK("loadPublicBook", true), + + /** + * Reloads the plugin's configuration and the book lists + */ + RELOAD("reload", false), + + /** + * Saves a book to a player's private collection + */ + SAVE_BOOK("saveBook", true), + + /** + * Saves a book to the public collection + */ + SAVE_PUBLIC_BOOK("savePublicBook", true), + + /** + * Sets the author of the held book + */ + SET_BOOK_AUTHOR("setBookAuthor", true), + + /** + * Sets the generation of the held book + */ + SET_BOOK_GENERATION("setBookGeneration", true), + + /** + * Sets the price of copying, loading and giving books + */ + SET_BOOK_PRICE("setBookPrice", false), + + /** + * Sets the name/lore for the chiseled bookshelf in front of the player, displayed when peeking the bookshelf + */ + SET_BOOKSHELF_DATA("setBookshelfData", true), + + /** + * Sets the lore of the held book/item + */ + SET_LORE("setLore", true), + + /** + * Sets the book title of the held signed book, or the display name of the held item + */ + SET_TITLE("setTitle", true), + + /** + * Un-signs the held signed book + */ + UNSIGN_BOOK("unsignBook", true), + ; + + private final @NotNull String commandName; + private final boolean requiresPlayer; + + /** + * Instantiates a new command + * + * @param commandName

The name of the command

+ * @param requiresPlayer

Whether the command requires to be run by a player

+ */ + BwBCommand(@NotNull String commandName, boolean requiresPlayer) { + this.commandName = commandName; + this.requiresPlayer = requiresPlayer; + } + + /** + * Gets whether this command can only be used by a player + * + * @return

True if this command must be run by a player

+ */ + public boolean requiresPlayer() { + return this.requiresPlayer; + } + + /** + * Return name instead of enum when displayed as a string + * + * @return

The command name

+ */ + @Override + @NotNull + public String toString() { + return this.commandName; + } + +} diff --git a/src/main/java/net/knarcraft/bookswithoutborders/config/Permission.java b/src/main/java/net/knarcraft/bookswithoutborders/config/Permission.java new file mode 100644 index 0000000..05a6a3b --- /dev/null +++ b/src/main/java/net/knarcraft/bookswithoutborders/config/Permission.java @@ -0,0 +1,59 @@ +package net.knarcraft.bookswithoutborders.config; + +import org.jetbrains.annotations.NotNull; + +/** + * A representation of a BwB permission + */ +public enum Permission { + + /** + * The permission for bypassing paying the set book printing price + */ + BYPASS_BOOK_PRICE("bypassBookPrice"), + + /** + * The admin permission, giving most/all other permissions + */ + ADMIN("admin"), + + /** + * The permission for bypassing the setting making sure a book can only be copied by its author + */ + BYPASS_AUTHOR_ONLY_COPY("bypassAuthorOnlyCopy"), + + ; + + private final @NotNull String node; + + /** + * Instantiates a new permission + * + * @param node

The permission's permission node

+ */ + Permission(@NotNull String node) { + this.node = node; + } + + /** + * Gets the node of this permission + * + * @return

The permission node

+ */ + @NotNull + public String getNode() { + return "bookswithoutborders." + this.node; + } + + /** + * Return node instead of enum when displayed as a string + * + * @return

The permission node string

+ */ + @Override + @NotNull + public String toString() { + return getNode(); + } + +} diff --git a/src/main/java/net/knarcraft/bookswithoutborders/config/StaticMessage.java b/src/main/java/net/knarcraft/bookswithoutborders/config/StaticMessage.java new file mode 100644 index 0000000..c811db6 --- /dev/null +++ b/src/main/java/net/knarcraft/bookswithoutborders/config/StaticMessage.java @@ -0,0 +1,31 @@ +package net.knarcraft.bookswithoutborders.config; + +import org.jetbrains.annotations.NotNull; + +/** + * Messages shown in the console that cannot be altered by users + */ +public enum StaticMessage { + + BOOK_SAVING_FAILED("Saving failed! Aborting..."), + BOOK_FOLDER_CREATE_FAILED("Unable to create necessary folders"), + COMMAND_NOT_REGISTERED("Command {command} has not been registered!"); + + private final @NotNull String messageString; + + /** + * Instantiates a new static message + * + * @param messageString

The message string

+ */ + StaticMessage(@NotNull String messageString) { + this.messageString = messageString; + } + + @Override + @NotNull + public String toString() { + return this.messageString; + } + +} diff --git a/src/main/java/net/knarcraft/bookswithoutborders/config/Translatable.java b/src/main/java/net/knarcraft/bookswithoutborders/config/Translatable.java new file mode 100644 index 0000000..949a122 --- /dev/null +++ b/src/main/java/net/knarcraft/bookswithoutborders/config/Translatable.java @@ -0,0 +1,97 @@ +package net.knarcraft.bookswithoutborders.config; + +import net.knarcraft.knarlib.formatting.TranslatableMessage; +import org.jetbrains.annotations.NotNull; + +/** + * An enum representing all translatable messages + */ +public enum Translatable implements TranslatableMessage { + + /** + * The prefix to display in messages + */ + PREFIX, + + /** + * The success message displayed when the copy command succeeds + */ + SUCCESS_COPY, + + /** + * The error to display when the console attempts to run a player-only command + */ + ERROR_PLAYER_ONLY, + + /** + * The error displayed when running the copy command without holding a written book + */ + ERROR_NOT_HOLDING_BOOK_COPY, + + /** + * The error displayed when running the copy command while holding one book in each hand + */ + ERROR_ONLY_ONE_BOOK_COPY, + + /** + * The error displayed when running the copy command without specifying the amount of copies + */ + ERROR_COPY_COUNT_NOT_SPECIFIED, + + /** + * The error displayed when supplying the copy command with a negative number + */ + ERROR_COPY_NEGATIVE_AMOUNT, + + /** + * The error displayed when supplying the copy command with a non-number + */ + ERROR_COPY_INVALID_AMOUNT, + + /** + * The error displayed when trying to copy a tattered book or a copy of a copy + */ + ERROR_BOOK_COPIED_TOO_FAR, + + /** + * The error displayed when trying to receive a book with a full inventory + */ + ERROR_INVENTORY_FULL, + + /** + * The header displayed before printing all commands + */ + NEUTRAL_COMMANDS_HEADER, + + /** + * The format used when displaying a book's economy price + */ + NEUTRAL_COMMANDS_BOOK_PRICE_ECO, + + /** + * The format used when displaying a book's item price + */ + NEUTRAL_COMMANDS_BOOK_PRICE_ITEM, + + /** + * The format used when displaying one command entry + */ + NEUTRAL_COMMANDS_COMMAND, + + /** + * The string used when displaying that a command requires no permission + */ + NEUTRAL_COMMANDS_COMMAND_NO_PERMISSION_REQUIRED, + + /** + * The format used when displaying a command's required permission + */ + NEUTRAL_COMMANDS_COMMAND_PERMISSION, + ; + + @Override + public @NotNull TranslatableMessage[] getAllMessages() { + return Translatable.values(); + } + +} diff --git a/src/main/java/net/knarcraft/bookswithoutborders/utility/EncryptionHelper.java b/src/main/java/net/knarcraft/bookswithoutborders/utility/EncryptionHelper.java index abb8eb5..b1c88fc 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/utility/EncryptionHelper.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/utility/EncryptionHelper.java @@ -7,7 +7,6 @@ import net.knarcraft.bookswithoutborders.encryption.SubstitutionCipher; import net.knarcraft.bookswithoutborders.state.EncryptionStyle; import net.md_5.bungee.api.ChatColor; import org.bukkit.Material; -import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; @@ -19,6 +18,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; +import java.util.logging.Logger; import static net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig.getBookFolder; import static net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig.getSlash; @@ -238,19 +238,18 @@ public final class EncryptionHelper { } if (deleteEncryptedFile) { - ConsoleCommandSender consoleSender = BooksWithoutBorders.getConsoleSender(); + Logger logger = BooksWithoutBorders.getInstance().getLogger(); try { if (!file.delete()) { - BooksWithoutBorders.sendErrorMessage(consoleSender, "Book encryption data failed to delete upon decryption!"); - BooksWithoutBorders.sendErrorMessage(consoleSender, "File location:" + file.getPath()); + logger.log(Level.SEVERE, "Book encryption data failed to delete upon decryption!\n" + + "File location:" + file.getPath()); } } catch (Exception e) { - BooksWithoutBorders.sendErrorMessage(consoleSender, "Book encryption data failed to delete upon decryption!"); - BooksWithoutBorders.sendErrorMessage(consoleSender, "File location:" + file.getPath()); + logger.log(Level.SEVERE, "Book encryption data failed to delete upon decryption!\nFile location:" + file.getPath()); } } - ItemStack newBook = new ItemStack(Material.WRITTEN_BOOK);//Book(book.getAuthor(), book.getTitle(), pages, 1, 387); + ItemStack newBook = new ItemStack(Material.WRITTEN_BOOK); newBook.setItemMeta(bookMetadata); newBook.setAmount(InventoryHelper.getHeldBook(player, true).getAmount()); return newBook; @@ -273,7 +272,7 @@ public final class EncryptionHelper { if (!dirTest.exists()) { try { if (!dirTest.mkdir()) { - BooksWithoutBorders.sendErrorMessage(BooksWithoutBorders.getConsoleSender(), "Unable to create encryption group folder!"); + BooksWithoutBorders.getInstance().getLogger().log(Level.SEVERE, "Unable to create encryption group folder!"); return null; } } catch (Exception exception) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e413897..f36f47b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,4 +1,6 @@ Options: + # The language to use. Only "en" is built-in, but custom languages can be added + Language: "en" # Whether to use YAML for saved books instead of just storing them as text Save_Books_in_Yaml_Format: true # The maximum number of duplicates of a saved book allowed diff --git a/src/main/resources/strings.yml b/src/main/resources/strings.yml new file mode 100644 index 0000000..1930038 --- /dev/null +++ b/src/main/resources/strings.yml @@ -0,0 +1,25 @@ +en: + PREFIX: "[BwB]" + SUCCESS_COPY: "Book copied!" + ERROR_PLAYER_ONLY: "This command can only be used by a player!" + ERROR_NOT_HOLDING_BOOK_COPY: "You must be holding a written book to copy it!" + ERROR_ONLY_ONE_BOOK_COPY: "You cannot copy two books at once!" + ERROR_COPY_COUNT_NOT_SPECIFIED: "You must specify the number of copies to be made!" + ERROR_COPY_NEGATIVE_AMOUNT: "Number of copies must be larger than 0!" + ERROR_COPY_INVALID_AMOUNT: | + Book not copied! + Number specified was invalid! + ERROR_BOOK_COPIED_TOO_FAR: "You cannot copy this book any further. You must have the original or a direct copy." + ERROR_INVENTORY_FULL: "You need an available slot in your inventory." + NEUTRAL_COMMANDS_HEADER: | + &e[] denote optional parameters + <> denote required parameters + {} denote required permission + In some cases, commands with required parameters can be called with no parameters + {bookPrice}&eCommands: + {commands} + NEUTRAL_COMMANDS_BOOK_PRICE_ECO: "\n&c[{price} is required to create a book]" + NEUTRAL_COMMANDS_BOOK_PRICE_ITEM: "&c[{quantity} {type} (s) are required to create a book]\n" + NEUTRAL_COMMANDS_COMMAND: "\n \n&e{usage}: &a{description}" + NEUTRAL_COMMANDS_COMMAND_NO_PERMISSION_REQUIRED: "None" + NEUTRAL_COMMANDS_COMMAND_PERMISSION: " &7{{permission}}" \ No newline at end of file