From 4be023bd63e8cd633e5e4137c67ac20ecf48dee6 Mon Sep 17 00:00:00 2001 From: EpicKnarvik97 Date: Fri, 1 Aug 2025 20:59:16 +0200 Subject: [PATCH] Adds a ChatComponent-enhanced book list --- .../command/CommandDelete.java | 10 ++- .../command/CommandGive.java | 17 +++-- .../command/CommandLoad.java | 13 +++- .../utility/BookFileHelper.java | 73 ++++++++++++++++--- .../utility/InputCleaningHelper.java | 24 ++++++ 5 files changed, 116 insertions(+), 21 deletions(-) diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java index f95afbb..c3e9458 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandDelete.java @@ -4,6 +4,7 @@ import net.knarcraft.bookswithoutborders.BooksWithoutBorders; import net.knarcraft.bookswithoutborders.state.BookDirectory; import net.knarcraft.bookswithoutborders.utility.BookFileHelper; import net.knarcraft.bookswithoutborders.utility.BookHelper; +import net.knarcraft.bookswithoutborders.utility.InputCleaningHelper; import net.knarcraft.knarlib.util.TabCompletionHelper; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -39,13 +40,20 @@ public class CommandDelete implements TabExecutor { * @return

True if the book was deleted successfully

*/ boolean deleteBook(CommandSender sender, String[] args, boolean deletePublic) { + String command = deletePublic ? "deletepublicbook" : "deletebook"; //List deletable files if (args.length == 0) { - BookFileHelper.printBooks(sender, deletePublic); + BookFileHelper.printBooks(sender, deletePublic, command, 1); return true; } //Delete the file if (args.length == 1) { + int page = InputCleaningHelper.parsePageNumber(args[0]); + if (page > 0) { + BookFileHelper.printBooks(sender, deletePublic, command, page); + return true; + } + List availableBooks = BooksWithoutBorders.getAvailableBooks(sender, deletePublic); if (!availableBooks.isEmpty()) { performBookDeletion(sender, args[0], deletePublic); diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java index 3a2062c..38390f5 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandGive.java @@ -44,16 +44,23 @@ public class CommandGive implements TabExecutor { * @return

True if the book was given successfully

*/ boolean giveBook(CommandSender sender, String[] args, boolean givePublic, String folder) { + String command = givePublic ? "givepublicbook" : "givebook"; + if (args.length == 0) { + BookFileHelper.printBooks(sender, givePublic, command, 1); + return true; + } else if (args.length == 1) { + int page = InputCleaningHelper.parsePageNumber(args[0]); + if (page > 0) { + BookFileHelper.printBooks(sender, givePublic, command, page); + return true; + } + } + if (args.length == 1 || args.length > 4) { BooksWithoutBorders.sendErrorMessage(sender, "Incorrect number of arguments for this command!"); return false; } - if (args.length == 0) { - BookFileHelper.printBooks(sender, givePublic); - return true; - } - //Organize and parse input String bookIdentifier = args[0]; String receivingPlayerName = args[1]; diff --git a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java index 7f81681..122666d 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/command/CommandLoad.java @@ -49,19 +49,26 @@ public class CommandLoad implements TabExecutor { int argumentCount = args.length; //Show books available to the player + String command = loadPublic ? "loadpublicbook" : "loadbook"; if (argumentCount == 0) { - BookFileHelper.printBooks(sender, loadPublic); + BookFileHelper.printBooks(sender, loadPublic, command, 1); return true; + } else if (argumentCount == 1) { + int page = InputCleaningHelper.parsePageNumber(args[0]); + if (page > 0) { + BookFileHelper.printBooks(sender, loadPublic, command, page); + return true; + } } //Organize and parse input String bookIdentifier = args[0]; String copies = "1"; String isSigned = "true"; - if (args.length == 3) { + if (argumentCount == 3) { copies = args[1]; isSigned = args[2]; - } else if (args.length == 2) { + } else if (argumentCount == 2) { if (args[1].equalsIgnoreCase("true") || args[1].equalsIgnoreCase("false")) { isSigned = args[1]; } else { diff --git a/src/main/java/net/knarcraft/bookswithoutborders/utility/BookFileHelper.java b/src/main/java/net/knarcraft/bookswithoutborders/utility/BookFileHelper.java index 79a7254..098c77b 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/utility/BookFileHelper.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/utility/BookFileHelper.java @@ -4,7 +4,13 @@ import net.knarcraft.bookswithoutborders.BooksWithoutBorders; import net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig; import net.knarcraft.bookswithoutborders.state.BookDirectory; import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Text; import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.util.ArrayList; @@ -19,6 +25,8 @@ import static net.knarcraft.bookswithoutborders.config.BooksWithoutBordersConfig */ public final class BookFileHelper { + private final static int booksPerPage = 10; + private BookFileHelper() { } @@ -106,27 +114,68 @@ public final class BookFileHelper { * * @param sender

The sender to display the books to

* @param listPublic

Whether to display public books

+ * @param command

The base command causing this to be called

+ * @param page

The page of the book list to display

*/ - public static void printBooks(CommandSender sender, boolean listPublic) { + public static void printBooks(@NotNull CommandSender sender, boolean listPublic, @NotNull String command, int page) { List availableBooks = BooksWithoutBorders.getAvailableBooks(sender, listPublic); - BookFileHelper.printFiles(sender, availableBooks); + int totalPages = (int) Math.ceil((double) availableBooks.size() / booksPerPage); + if (page > totalPages) { + sender.sendMessage(ChatColor.GRAY + "No such page"); + } else { + showBookMenu(sender, command, page, totalPages, availableBooks); + } } /** - * Prints a list of files + * Shows a menu listing available books * - * @param sender

The command sender to show the list to

- * @param fileList

The files to list

+ * @param sender

The sender wanting to see the book menu

+ * @param command

The main command used to trigger display of the book menu

+ * @param page

The currently selected page

+ * @param totalPages

The total amount of pages

+ * @param availableBooks

All books available to the sender

*/ - public static void printFiles(CommandSender sender, List fileList) { - BooksWithoutBorders.sendSuccessMessage(sender, "Available Books:"); - if (fileList == null) { - return; + private static void showBookMenu(@NotNull CommandSender sender, @NotNull String command, int page, + int totalPages, @NotNull List availableBooks) { + // Print the previous page button + ComponentBuilder previousComponent = new ComponentBuilder(); + if (page > 1) { + HoverEvent prevPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("To page " + (page - 1))); + ClickEvent prevPageClick = new ClickEvent(ClickEvent.Action.RUN_COMMAND, command + " page" + (page - 1)); + previousComponent.append("Previous [<]").event(prevPagePreview).event(prevPageClick); + } else { + previousComponent.append("Previous [<]").color(ChatColor.GRAY); } - int listSize = fileList.size(); - for (int fileIndex = 0; fileIndex < listSize; fileIndex++) { - sender.sendMessage(ChatColor.GRAY + "[" + (fileIndex + 1) + "] " + fileList.get(fileIndex)); + sender.spigot().sendMessage(previousComponent.create()); + + // Print the main list of all book indexes and titles + HoverEvent interactSuggestion = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Click me")); + int startIndex = (page - 1) * booksPerPage; + for (int bookIndex = startIndex; bookIndex < Math.min(startIndex + booksPerPage, availableBooks.size()); bookIndex++) { + ComponentBuilder bookComponent = new ComponentBuilder(); + TextComponent indexComponent = new TextComponent("[" + (bookIndex + 1) + "] "); + indexComponent.setColor(ChatColor.GOLD); + bookComponent.append(indexComponent).event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, + "/" + command + " " + (bookIndex + 1))).event(interactSuggestion); + + TextComponent bookNameComponent = new TextComponent(availableBooks.get(bookIndex)); + bookNameComponent.setColor(ChatColor.WHITE); + bookComponent.append(bookNameComponent).event(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, + "/" + command + " " + availableBooks.get(bookIndex))).event(interactSuggestion); + sender.spigot().sendMessage(bookComponent.create()); } + + // Print the next page button + ComponentBuilder nextComponent = new ComponentBuilder(); + if (page < totalPages) { + HoverEvent nextPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("To page " + (page + 1))); + ClickEvent nextPageClick = new ClickEvent(ClickEvent.Action.RUN_COMMAND, command + " page" + (page + 1)); + nextComponent.append("Next [>]").event(nextPagePreview).event(nextPageClick); + } else { + nextComponent.append("Next [>]").color(ChatColor.GRAY).reset(); + } + sender.spigot().sendMessage(nextComponent.create()); } /** diff --git a/src/main/java/net/knarcraft/bookswithoutborders/utility/InputCleaningHelper.java b/src/main/java/net/knarcraft/bookswithoutborders/utility/InputCleaningHelper.java index 6c026ba..ae4ae9a 100644 --- a/src/main/java/net/knarcraft/bookswithoutborders/utility/InputCleaningHelper.java +++ b/src/main/java/net/knarcraft/bookswithoutborders/utility/InputCleaningHelper.java @@ -1,7 +1,11 @@ package net.knarcraft.bookswithoutborders.utility; +import org.jetbrains.annotations.NotNull; + import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Helper class for cleaning input and names @@ -58,4 +62,24 @@ public final class InputCleaningHelper { return fileName; } + /** + * Parses a page number for a string like "page1" + * + * @param input

The input to parse

+ * @return

The page number, or 0 if not valid

+ */ + public static int parsePageNumber(@NotNull String input) { + try { + Pattern pattern = Pattern.compile("page([0-9])+"); + Matcher matcher = pattern.matcher(input); + if (matcher.matches()) { + return Integer.parseInt(matcher.group(1)); + } else { + return 0; + } + } catch (NumberFormatException exception) { + return 0; + } + } + }