diff --git a/README.md b/README.md index 3f3ec96..d6e6c0c 100644 --- a/README.md +++ b/README.md @@ -64,13 +64,14 @@ An in-game description of available commands is available through the /bwb comma | Command | Alias | Arguments | Permission | Description | |----------------------|---------------|----------------------------------------------------------------------------------|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| /addBookTitlePage | bwbtitlepage | \[page index] \[title~description] | bookswithoutborders.addtitlepage | Adds a blank page, title page or chapter page depending on input and whether the book is signed. The title author separator (default `~`) is used to separate the input into title,paragraph1,paragraph2,... | +| /addBooktitlepage | bwbtitlepage | \[page index] \[title~description] | bookswithoutborders.addtitlepage | Adds a blank page, title page or chapter page depending on input and whether the book is signed. The title author separator (default `~`) is used to separate the input into title,paragraph1,paragraph2,... | | /bookswithoutborders | bwb | None | | Displays information about commands (and permissions if the user has bookswithoutborders.admin) | | /clearbook | bwbclear | None | bookswithoutborders.clear | Removes all text from the held un-signed book | | /copybook | bwbcopy | \<# of copies> | bookswithoutborders.copy | Copies the book the player is holding | +| /createbwbSign | bwbsign | \ \[book identifier/password] \[encryption style] | bookswithoutborders.signs | Creates a books without borders sign, as specified. This command is not restricted by the normal sign line text limit, and can load books with any name length for give signs. Encrypt and decrypts signs can be created manually just fine, but using this avoids manual formatting. | | /decryptbook | bwbdecrypt | \ | bookswithoutborders.decrypt | Decrypts the book the player is holding. "key" is required and MUST be IDENTICAL to the key used to encrypt the held book | | /deletebook | bwbdelete | \ | bookswithoutborders.delete | Deletes the specified file in the player's directory | -| /deleteBookPage | bwbdeletepage | \ | bookswithoutborders.deletepage | Deletes one page from a book | +| /deletebookpage | bwbdeletepage | \ | bookswithoutborders.deletepage | Deletes one page from a book | | /deletepublicbook | bwbdeletep | \ | bookswithoutborders.admin | Same as deletebook, but deletes files in the public directory | | /encryptbook | bwbencrypt | \ \[encryption style] | bookswithoutborders.encrypt | Encrypts the book the player is holding. "key" is required and can be any phrase or number excluding spaces. "style" is not required. Possible values are "dna", "substitution", "aes", "onetimepad" and "magic", unless real encryption is enabled, which limits available algorithms. | | /formatbook | bwbformat | None | bookswithoutborders.format | Formats the held written book (converts color and formatting codes to the corresponding formatted text) | @@ -142,12 +143,15 @@ An in-game description of available commands is available through the /bwb comma This plugin supports several custom signs with special functionality. Each plugin sign must have \[BwB] on its first line. +It is recommended to use the `createbwbsign` command over manual creation for give signs, as it bypasses the text +limit, and specifying books by index is really unstable. If you have some other plugin for editing sign lines, you can +first specify the visual text on the sign's third and fourth line, then add a `:` and put the full book name after that. #### Give sign The **_give_**-sign must have **\[Give]** on its second line. The third and fourth line contains the book to be loaded. This can either be a numerical id pointing to a publicly saved book, or the full text identifier of the book (book name, -author). +author). Use the `createbwbsign` command in order to specify book names of any length. #### Encrypt sign diff --git a/pom.xml b/pom.xml index c872ed7..e5bebeb 100644 --- a/pom.xml +++ b/pom.xml @@ -125,7 +125,7 @@ net.knarcraft knarlib - 1.2.10 + 1.2.11 compile diff --git a/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java b/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java index 25da909..a45b99e 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/BooksWithoutBorders.java @@ -4,6 +4,7 @@ import net.knarcraft.bookswithoutborders.command.CommandAddTitlePage; import net.knarcraft.bookswithoutborders.command.CommandBooksWithoutBorders; import net.knarcraft.bookswithoutborders.command.CommandClear; import net.knarcraft.bookswithoutborders.command.CommandCopy; +import net.knarcraft.bookswithoutborders.command.CommandCreateBwBSign; import net.knarcraft.bookswithoutborders.command.CommandDecrypt; import net.knarcraft.bookswithoutborders.command.CommandDelete; import net.knarcraft.bookswithoutborders.command.CommandDeletePage; @@ -291,6 +292,7 @@ public class BooksWithoutBorders extends JavaPlugin { registerCommand(BwBCommand.ADD_TITLE_PAGE.toString(), new CommandAddTitlePage()); registerCommand(BwBCommand.DELETE_PAGE.toString(), new CommandDeletePage()); registerCommand(BwBCommand.MIGRATE.toString(), new CommandMigrate()); + registerCommand(BwBCommand.CREATE_BWB_SIGN.toString(), new CommandCreateBwBSign()); } /** diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandCreateBwBSign.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandCreateBwBSign.java new file mode 100644 index 0000000..17eba46 --- /dev/null +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandCreateBwBSign.java @@ -0,0 +1,210 @@ +package net.knarcraft.bookswithoutborders.command; + +import net.knarcraft.bookswithoutborders.BooksWithoutBorders; +import net.knarcraft.bookswithoutborders.config.translation.SignText; +import net.knarcraft.bookswithoutborders.config.translation.Translatable; +import net.knarcraft.bookswithoutborders.encryption.EncryptionStyle; +import net.knarcraft.bookswithoutborders.gui.PagedBookIndex; +import net.knarcraft.bookswithoutborders.state.BookDirectory; +import net.knarcraft.bookswithoutborders.utility.BookFileUtil; +import net.knarcraft.bookswithoutborders.utility.InputCleaningUtil; +import net.knarcraft.bookswithoutborders.utility.InputParsingUtil; +import net.knarcraft.bookswithoutborders.utility.TabCompletionTypeUtil; +import net.knarcraft.knarlib.formatting.FormatBuilder; +import net.knarcraft.knarlib.util.SignHelper; +import net.knarcraft.knarlib.util.TabCompletionHelper; +import net.md_5.bungee.api.ChatColor; +import org.bukkit.block.Sign; +import org.bukkit.block.sign.SignSide; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * A command for creating a valid BooksWithoutBorders sign without all the hassle + */ +public class CommandCreateBwBSign implements TabExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String commandName, + @NotNull String[] arguments) { + if (!(sender instanceof Player player)) { + new FormatBuilder(Translatable.ERROR_PLAYER_ONLY).error(sender); + return true; + } + + if (arguments.length < 1) { + return false; + } + + if (arguments[0].equalsIgnoreCase("give") && + PagedBookIndex.displayPage(arguments, player, true, commandName + " give", 1)) { + return true; + } + + Sign clickedSign = SignHelper.getLookedAtSign(player); + if (clickedSign == null) { + new FormatBuilder(SignText.ERROR_SIGN_NOT_FOUND).error(player); + return true; + } + SignSide side = clickedSign.getSide(SignHelper.getSide(clickedSign, player)); + boolean success = switch (arguments[0].toLowerCase()) { + case "give" -> createGiveSign(arguments, side, player); + case "encrypt" -> createEncryptSign(arguments, side); + case "decrypt" -> createDecryptSign(arguments, side); + default -> false; + }; + + if (success) { + side.setLine(0, ChatColor.DARK_GREEN + new FormatBuilder(SignText.SIGN_HEADER).toString()); + clickedSign.setWaxed(true); + clickedSign.update(); + new FormatBuilder(SignText.SUCCESS_SIGN_CREATED).success(player); + return true; + } else { + return false; + } + } + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, + @NotNull String commandName, @NotNull String[] arguments) { + if (arguments.length == 1) { + List signTypes = List.of("give", "encrypt", "decrypt"); + return TabCompletionHelper.filterMatchingStartsWith(signTypes, arguments[0]); + } + + // Show available books + if (arguments[0].equalsIgnoreCase("give")) { + if (arguments.length == 2) { + return TabCompletionHelper.filterMatchingContains(BooksWithoutBorders.getAvailableBooks(sender, true), arguments[1]); + } else { + List books = BooksWithoutBorders.getAvailableBooks(sender, true); + String merged = InputParsingUtil.mergeArguments(1, arguments); + List filtered = TabCompletionHelper.filterMatchingContains(books, merged); + return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 1); + } + } + + if (arguments.length == 2) { + if (arguments[0].equalsIgnoreCase("encrypt") || arguments[0].equalsIgnoreCase("decrypt")) { + return List.of(""); + } else { + return List.of(); + } + } else if (arguments.length == 3 && arguments[0].equalsIgnoreCase("encrypt")) { + boolean useRealEncryption = BooksWithoutBorders.getConfiguration().useRealEncryption(); + List encryptionStyles = new ArrayList<>(); + for (EncryptionStyle encryptionStyle : EncryptionStyle.values()) { + if (!useRealEncryption || encryptionStyle.isRealEncryptionSupported()) { + encryptionStyles.add(encryptionStyle.toString()); + } + } + return TabCompletionHelper.filterMatchingStartsWith(encryptionStyles, arguments[2]); + } + return List.of(); + } + + /** + * Creates an encrypt sign from the player's input + * + * @param arguments

The arguments given

+ * @param side

The side of the sign to make into a BwB sign

+ * @return

True if the command was used correctly

+ */ + private boolean createEncryptSign(@NotNull String[] arguments, @NotNull SignSide side) { + if (arguments.length < 2 || arguments.length > 3) { + return false; + } + String password = arguments[1]; + + EncryptionStyle encryptionStyle = null; + if (arguments.length == 3) { + encryptionStyle = EncryptionStyle.getFromString(arguments[2]); + } + + // Alter sign text + side.setLine(1, ChatColor.DARK_BLUE + new FormatBuilder(SignText.SIGN_ENCRYPT).toString()); + side.setLine(2, ChatColor.MAGIC + password); + if (encryptionStyle == null) { + side.setLine(3, ""); + } else { + side.setLine(3, ChatColor.DARK_BLUE + encryptionStyle.toString()); + } + return true; + } + + /** + * Creates a decrypt sign from the player's input + * + * @param arguments

The arguments given

+ * @param side

The side of the sign to make into a BwB sign

+ * @return

True if the command was used correctly

+ */ + private boolean createDecryptSign(@NotNull String[] arguments, @NotNull SignSide side) { + if (arguments.length != 2) { + return false; + } + String password = arguments[1]; + + // Alter sign text + side.setLine(1, ChatColor.DARK_BLUE + new FormatBuilder(SignText.SIGN_DECRYPT).toString()); + side.setLine(2, ChatColor.MAGIC + password); + side.setLine(3, ""); + return true; + } + + /** + * Creates a give sign from the player's input + * + * @param arguments

The arguments given

+ * @param side

The side of the sign to make into a BwB sign

+ * @param player

The player to alert if anything goes wrong

+ * @return

True if the player's arguments were correct

+ */ + private boolean createGiveSign(@NotNull String[] arguments, @NotNull SignSide side, @NotNull Player player) { + File bookFile = BookFileUtil.getFile(BookDirectory.PUBLIC, null, + InputParsingUtil.mergeArguments(1, arguments)); + if (bookFile == null) { + new FormatBuilder(Translatable.ERROR_LOAD_FAILED).error(player); + return false; + } + + String separator = BooksWithoutBorders.getConfiguration().getTitleAuthorSeparator(); + String bookName = bookFile.getName(); + if (!bookName.contains(separator)) { + new FormatBuilder(Translatable.ERROR_SIGN_BOOK_FOUND_BUT_INVALID).error(player); + return false; + } + + // Alter sign text + side.setLine(1, ChatColor.DARK_BLUE + new FormatBuilder(SignText.SIGN_GIVE).toString()); + String[] parts = InputCleaningUtil.stripColor(bookName).split(separator); + String title = parts[0]; + String author = BookFileUtil.stripExtensionFromPath(parts[1]); + addBookPath(side, title, 2); + addBookPath(side, author, 3); + side.setLine(3, side.getLine(3) + ":" + bookName); + return true; + } + + /** + * Adds part of a book path with proper formatting + * + * @param side

The sign side to alter

+ * @param text

The text to add

+ * @param index

The index of the line to alter

+ */ + private void addBookPath(@NotNull SignSide side, @NotNull String text, int index) { + side.setLine(index, ChatColor.DARK_GREEN + text.substring(0, Math.min(text.length(), 15)) + " "); + } + +} diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java index b69844c..6b039d7 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java @@ -46,7 +46,7 @@ public class CommandDelete implements TabExecutor { */ protected void deleteBook(@NotNull CommandSender sender, @NotNull String[] arguments, boolean deletePublic, @NotNull String commandName) { - if (PagedBookIndex.displayPage(arguments, sender, deletePublic, commandName)) { + if (PagedBookIndex.displayPage(arguments, sender, deletePublic, commandName, 0)) { return; } @@ -121,7 +121,7 @@ public class CommandDelete implements TabExecutor { BooksWithoutBorders.getAvailableBooks(sender, deletePublic), InputParsingUtil.mergeArguments(arguments, 0)); if (arguments.length > 1) { - return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered); + return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0); } else { return filtered; } diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java index a325eeb..42e9250 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java @@ -58,7 +58,7 @@ public class CommandGive implements TabExecutor { */ boolean giveBook(@NotNull CommandSender sender, @NotNull String[] arguments, boolean givePublic, @NotNull BookDirectory folder, @NotNull String commandName) { - if (PagedBookIndex.displayPage(arguments, sender, givePublic, commandName)) { + if (PagedBookIndex.displayPage(arguments, sender, givePublic, commandName, 0)) { return true; } @@ -94,11 +94,10 @@ public class CommandGive implements TabExecutor { List output = new ArrayList<>(); List books = BooksWithoutBorders.getAvailableBooks(sender, listPublic); - List filtered = TabCompletionHelper.filterMatchingContains(books, - mergeArguments(arguments, 0)); + List filtered = TabCompletionHelper.filterMatchingContains(books, mergeArguments(arguments, 0)); if (!filtered.isEmpty()) { - List cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered); + List cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0); if (!books.contains(mergeArguments(arguments, 1))) { return cleaned; } else { diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java index dcd1015..8e381ce 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java @@ -57,7 +57,7 @@ public class CommandLoad implements TabExecutor { return true; } - if (PagedBookIndex.displayPage(arguments, sender, loadPublic, commandName)) { + if (PagedBookIndex.displayPage(arguments, sender, loadPublic, commandName, 0)) { return true; } @@ -92,7 +92,7 @@ public class CommandLoad implements TabExecutor { mergeArguments(arguments, 0)); if (!filtered.isEmpty()) { - List cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered); + List cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0); if (!books.contains(mergeArguments(arguments, 1))) { return cleaned; } else { diff --git a/src/main/java/net/knarcraft/bookswithoutborders/config/BwBCommand.java b/src/main/java/net/knarcraft/bookswithoutborders/config/BwBCommand.java index b0098ca..eccd24b 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/config/BwBCommand.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/config/BwBCommand.java @@ -144,6 +144,11 @@ public enum BwBCommand { * Un-signs the held signed book */ UNSIGN_BOOK("unsignBook", true, "Unsign held book"), + + /** + * Creates a BwB sign from the input + */ + CREATE_BWB_SIGN("createBwBSign", true, "Create a BwB sign"), ; private final @NotNull String commandName; diff --git a/src/main/java/net/knarcraft/bookswithoutborders/config/translation/SignText.java b/src/main/java/net/knarcraft/bookswithoutborders/config/translation/SignText.java index b9a6ab3..cf625c4 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/config/translation/SignText.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/config/translation/SignText.java @@ -38,10 +38,20 @@ public enum SignText implements TranslatableMessage { */ ERROR_SIGN_COMMAND_INVALID, + /** + * The error displayed when attempting to perform a command requiring looking at a sign, but no sign is in sight + */ + ERROR_SIGN_NOT_FOUND, + /** * The success message displayed when successfully getting a book from a give sign */ SUCCESS_SIGN_GIVE, + + /** + * The success message displayed when a BwB sign is successfully created + */ + SUCCESS_SIGN_CREATED, ; @Override diff --git a/src/main/java/net/knarcraft/bookswithoutborders/config/translation/Translatable.java b/src/main/java/net/knarcraft/bookswithoutborders/config/translation/Translatable.java index f3ec09a..77d8564 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/config/translation/Translatable.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/config/translation/Translatable.java @@ -408,6 +408,11 @@ public enum Translatable implements TranslatableMessage { * The error displayed when encryption fails */ ERROR_ENCRYPT_FAILED, + + /** + * The error displayed when attempting to select an invalid book for a give sign + */ + ERROR_SIGN_BOOK_FOUND_BUT_INVALID, ; @Override diff --git a/src/main/java/net/knarcraft/bookswithoutborders/gui/BookIndex.java b/src/main/java/net/knarcraft/bookswithoutborders/gui/BookIndex.java index c548c72..32d5e83 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/gui/BookIndex.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/gui/BookIndex.java @@ -27,23 +27,24 @@ public abstract class BookIndex { * @param sender

The sender executing the command

* @param selectPublic

Whether to display public books, or only those available to the command sender

* @param command

The command used for changing pages and making the final selection

+ * @param offset

The offset of arguments if other arguments exist before the book specifier

* @return

True if the GUI was displayed

*/ public static boolean displayPage(@NotNull String[] arguments, @NotNull CommandSender sender, boolean selectPublic, - @NotNull String command) { - if (arguments.length == 0) { + @NotNull String command, int offset) { + if (arguments.length == offset) { PagedBookIndex.printBooks(sender, selectPublic, command, 1); return true; - } else if (arguments.length == 1) { - int page = InputParsingUtil.parsePageNumber(arguments[0]); + } else if (arguments.length == 1 + offset) { + int page = InputParsingUtil.parsePageNumber(arguments[offset]); if (page > 0) { PagedBookIndex.printBooks(sender, selectPublic, command, page); return true; } - } else if (arguments.length == 2) { - String author = InputParsingUtil.parseAuthorSpecifier(arguments[0]); + } else if (arguments.length == 2 + offset) { + String author = InputParsingUtil.parseAuthorSpecifier(arguments[offset]); if (author != null) { - int page = InputParsingUtil.parsePageNumber(arguments[1]); + int page = InputParsingUtil.parsePageNumber(arguments[1 + offset]); if (page > 0) { AuthorBookIndex.printBooks(sender, selectPublic, command, page, author); } @@ -52,7 +53,7 @@ public abstract class BookIndex { } // Parse book author from input - for (int authorIndex = 0; authorIndex < arguments.length; authorIndex++) { + for (int authorIndex = offset; authorIndex < arguments.length; authorIndex++) { String author = InputParsingUtil.parseAuthorSpecifier(arguments[authorIndex]); if (author == null) { continue; diff --git a/src/main/java/net/knarcraft/bookswithoutborders/listener/SignEventListener.java b/src/main/java/net/knarcraft/bookswithoutborders/listener/SignEventListener.java index 22a240d..f8dabe1 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/listener/SignEventListener.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/listener/SignEventListener.java @@ -13,12 +13,12 @@ import net.knarcraft.bookswithoutborders.utility.BookFileUtil; import net.knarcraft.bookswithoutborders.utility.BookLoaderUtil; import net.knarcraft.bookswithoutborders.utility.EncryptedBookUtil; import net.knarcraft.knarlib.formatting.FormatBuilder; +import net.knarcraft.knarlib.util.SignHelper; import net.md_5.bungee.api.ChatColor; import org.bukkit.Material; import org.bukkit.Tag; import org.bukkit.block.Sign; import org.bukkit.block.sign.Side; -import org.bukkit.block.sign.SignSide; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; @@ -68,6 +68,7 @@ public class SignEventListener implements Listener { for (int i = 0; i < lines.length; i++) { event.setLine(i, lines[i]); } + new FormatBuilder(SignText.SUCCESS_SIGN_CREATED).success(player); } @EventHandler @@ -85,58 +86,59 @@ public class SignEventListener implements Listener { Material heldItemType = heldItem.getType(); if (event.getClickedBlock() == null || (event.getAction() != Action.RIGHT_CLICK_BLOCK || - (!Tag.SIGNS.isTagged(event.getClickedBlock().getType()) && - !Tag.WALL_SIGNS.isTagged(event.getClickedBlock().getType())))) { + !Tag.ALL_SIGNS.isTagged(event.getClickedBlock().getType()))) { return; } // Return if not a valid sign - if (isSignInvalid(((Sign) event.getClickedBlock().getState()).getSide(Side.FRONT).getLines(), false)) { + Sign sign = (Sign) event.getClickedBlock().getState(); + Side side = SignHelper.getSide(sign, player); + String[] lines = sign.getSide(side).getLines(); + if (isSignInvalid(lines, false)) { return; } //The player right-clicked a sign - checkSign(event, (Sign) event.getClickedBlock().getState(), heldItemType, hand); + checkSign(event, heldItemType, hand, lines); } /** * Checks if the clicked sign is a BwB sign, and which action to take * * @param event

The triggered interact event

- * @param sign

The clicked sign

* @param heldItemType

The type of the held item

* @param hand

The hand the held item is in

+ * @param lines

The lines of the sign

*/ - private void checkSign(@NotNull PlayerInteractEvent event, @NotNull Sign sign, @NotNull Material heldItemType, - @NotNull EquipmentSlot hand) { + private void checkSign(@NotNull PlayerInteractEvent event, @NotNull Material heldItemType, + @NotNull EquipmentSlot hand, @NotNull String[] lines) { Player player = event.getPlayer(); event.setUseItemInHand(Event.Result.DENY); event.setCancelled(true); - SignSide front = sign.getSide(Side.FRONT); - SignType signType = getSignType(front.getLine(1)); + SignType signType = getSignType(lines[1]); if (signType == SignType.ENCRYPT) { - encryptHeldBookUsingSign(sign, heldItemType, player, hand); + encryptHeldBookUsingSign(heldItemType, player, hand, lines); } else if (signType == SignType.DECRYPT) { - decryptHeldBookUsingSign(sign, heldItemType, player, hand); + decryptHeldBookUsingSign(heldItemType, player, hand, lines); } else if (signType == SignType.GIVE) { - giveBook(sign, player); + giveBook(player, lines); } else { - new FormatBuilder(SignText.ERROR_SIGN_COMMAND_INVALID).replace(Placeholder.ACTION, front.getLine(1)). - replace(Placeholder.DATA, front.getLine(2)).error(player); + new FormatBuilder(SignText.ERROR_SIGN_COMMAND_INVALID).replace(Placeholder.ACTION, lines[1]). + replace(Placeholder.DATA, lines[2]).error(player); } } /** * Decrypts and replaces the player's used book * - * @param sign

The clicked sign

* @param heldItemType

The item type used to click the sign

* @param player

The player which clicked the sign

* @param hand

The EquipmentSlot of the used hand

+ * @param lines

The lines of the sign

*/ - private void decryptHeldBookUsingSign(@NotNull Sign sign, @NotNull Material heldItemType, @NotNull Player player, - @NotNull EquipmentSlot hand) { + private void decryptHeldBookUsingSign(@NotNull Material heldItemType, @NotNull Player player, + @NotNull EquipmentSlot hand, @NotNull String[] lines) { //Decrypt the held book and replace it if (heldItemType != Material.WRITTEN_BOOK) { return; @@ -145,7 +147,7 @@ public class SignEventListener implements Listener { player.closeInventory(); //Converts user supplied key into integer form - String password = getPassword(sign.getSide(Side.FRONT).getLines()); + String password = getPassword(lines); ItemStack book = EncryptedBookUtil.loadEncryptedBook(player, password, false, false); if (book == null) { @@ -161,14 +163,13 @@ public class SignEventListener implements Listener { /** * Encrypts and replaces the player's used book * - * @param sign

The clicked sign

* @param heldItemType

The item type used to click the sign

* @param player

The player which clicked the sign

* @param hand

The EquipmentSlot of the used hand

+ * @param lines

The lines of the sign

*/ - private void encryptHeldBookUsingSign(@NotNull Sign sign, @NotNull Material heldItemType, @NotNull Player player, - @NotNull EquipmentSlot hand) { - String[] lines = sign.getSide(Side.FRONT).getLines(); + private void encryptHeldBookUsingSign(@NotNull Material heldItemType, @NotNull Player player, + @NotNull EquipmentSlot hand, @NotNull String[] lines) { if (heldItemType != Material.WRITTEN_BOOK) { return; } @@ -183,11 +184,11 @@ public class SignEventListener implements Listener { /** * Gives a player the book specified on a sign * - * @param sign

The sign the user clicked

* @param player

The player which clicked the sign

+ * @param lines

The lines of the sign

*/ - private void giveBook(@NotNull Sign sign, @NotNull Player player) { - String fileName = getBookName(sign.getSide(Side.FRONT).getLines()); + private void giveBook(@NotNull Player player, @NotNull String[] lines) { + String fileName = getBookName(lines); if (fileName.isBlank()) { new FormatBuilder(GiveMessage.ERROR_GIVE_LOAD_FAILED).error(player); return; diff --git a/src/main/java/net/knarcraft/bookswithoutborders/utility/InputParsingUtil.java b/src/main/java/net/knarcraft/bookswithoutborders/utility/InputParsingUtil.java index 59a2bdd..662cf21 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/utility/InputParsingUtil.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/utility/InputParsingUtil.java @@ -40,9 +40,34 @@ public final class InputParsingUtil { * @return

The merged arguments

*/ @NotNull - public static String mergeArguments(String[] arguments, int stripLastN) { - StringBuilder builder = new StringBuilder(arguments[0]); - for (int i = 1; i < arguments.length - stripLastN; i++) { + public static String mergeArguments(@NotNull String[] arguments, int stripLastN) { + return mergeArguments(0, arguments, stripLastN); + } + + /** + * Merges all arguments to a string with spaces + * + * @param stripFirstN

How many of the first arguments to ignore

+ * @param arguments

The arguments to merge

+ * @return

The merged arguments

+ */ + @NotNull + public static String mergeArguments(int stripFirstN, @NotNull String[] arguments) { + return mergeArguments(stripFirstN, arguments, 0); + } + + /** + * Merges all arguments to a string with spaces + * + * @param stripFirstN

How many of the first arguments to ignore

+ * @param arguments

The arguments to merge

+ * @param stripLastN

How many of the last arguments to ignore

+ * @return

The merged arguments

+ */ + @NotNull + public static String mergeArguments(int stripFirstN, @NotNull String[] arguments, int stripLastN) { + StringBuilder builder = new StringBuilder(arguments[stripFirstN]); + for (int i = stripFirstN + 1; i < arguments.length - stripLastN; i++) { builder.append(" ").append(arguments[i]); } return builder.toString(); diff --git a/src/main/java/net/knarcraft/bookswithoutborders/utility/TabCompletionTypeUtil.java b/src/main/java/net/knarcraft/bookswithoutborders/utility/TabCompletionTypeUtil.java index be1fb97..1aa12e8 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/utility/TabCompletionTypeUtil.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/utility/TabCompletionTypeUtil.java @@ -64,15 +64,16 @@ public final class TabCompletionTypeUtil { * * @param arguments

The arguments given by the user

* @param filtered

Tab-completions filtered by user input

+ * @param offset

The offset to use, if other arguments are preceding the book specification

* @return

The cleaned tab-completions

*/ public static @NotNull List getCleanedTabCompletions(@NotNull String[] arguments, - @NotNull List filtered) { + @NotNull List filtered, int offset) { List cleaned = new ArrayList<>(); for (String name : filtered) { String[] parts = name.split(" "); - if (parts[arguments.length - 2].equalsIgnoreCase(arguments[arguments.length - 2])) { - StringBuilder builder = new StringBuilder(parts[arguments.length - 1]); + if (parts[arguments.length - 2 - offset].equalsIgnoreCase(arguments[arguments.length - 2])) { + StringBuilder builder = new StringBuilder(parts[arguments.length - 1 - offset]); for (int i = arguments.length; i < parts.length; i++) { builder.append(" ").append(parts[i]); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index bc4a354..7163516 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -239,6 +239,18 @@ commands: - bwbmigrate usage: / permission: bookswithoutborders.admin + createBwBSign: + description: | + Creates a books without borders sign without having to manually create correct formatting + If creating a give sign, the second argument and so on will be treated as the book path. Use with no arguments + after give to see the book list. + If creating an encrypt or a decrypt sign, the second argument will be treated as the encryption/decryption password + If creating an encrypt sign, the optional third argument is the encryption style to use. Possible values are + "dna", "substitution", "aes", "onetimepad" and "magic" + aliases: + - bwbsign + usage: / [book identifier/password] [encryption style] + permission: bookswithoutborders.signs permissions: bookswithoutborders.*: description: Grants all permissions diff --git a/src/main/resources/strings.yml b/src/main/resources/strings.yml index 7de305c..714cd7d 100644 --- a/src/main/resources/strings.yml +++ b/src/main/resources/strings.yml @@ -183,7 +183,10 @@ en: # -------------- # ERROR_SIGN_INVALID: "Invalid sign!" ERROR_SIGN_COMMAND_INVALID: "Sign command {action} {data} is invalid" + ERROR_SIGN_NOT_FOUND: "You are not looking at a sign!" + ERROR_SIGN_BOOK_FOUND_BUT_INVALID: "The book was found, but does not contain the title author separator" SUCCESS_SIGN_GIVE: "Received book!" + SUCCESS_SIGN_CREATED: "BwB sign created successfully!" # ------------ # # Placeholders # # -------------ยค