Makes a lot of formatting customizable, and fixes some problems caused by splitting Translatable
All checks were successful
EpicKnarvik97/Books-Without-Borders/pipeline/head This commit looks good
All checks were successful
EpicKnarvik97/Books-Without-Borders/pipeline/head This commit looks good
This commit is contained in:
@@ -145,7 +145,7 @@ public class CommandBooksWithoutBorders implements TabExecutor {
|
||||
PluginCommand pluginCommand = BooksWithoutBorders.getInstance().getCommand(bwBCommand.toString());
|
||||
if (pluginCommand == null) {
|
||||
BooksWithoutBorders.log(Level.SEVERE, StringFormatter.replacePlaceholder(
|
||||
StaticMessage.COMMAND_NOT_REGISTERED.toString(), "{command}", bwBCommand.toString()));
|
||||
StaticMessage.EXCEPTION_COMMAND_NOT_REGISTERED.toString(), "{command}", bwBCommand.toString()));
|
||||
return "";
|
||||
}
|
||||
|
||||
|
@@ -40,7 +40,7 @@ public class CommandSetLore implements TabExecutor {
|
||||
|
||||
ItemStack heldItem = InventoryHelper.getHeldItem(player, true);
|
||||
if (heldItem.getType() == Material.AIR) {
|
||||
stringFormatter.displayErrorMessage(player, Translatable.ERROR_LORE_NO_ITEM);
|
||||
stringFormatter.displayErrorMessage(player, Translatable.ERROR_NO_ITEM);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@@ -40,7 +40,7 @@ public class CommandSetTitle implements TabExecutor {
|
||||
|
||||
ItemStack heldItem = InventoryHelper.getHeldItem(player, true);
|
||||
if (heldItem.getType() == Material.AIR) {
|
||||
BooksWithoutBorders.sendErrorMessage(sender, "You must be holding an item to set title!");
|
||||
stringFormatter.displayErrorMessage(sender, Translatable.ERROR_NO_ITEM);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ public class CommandSetTitle implements TabExecutor {
|
||||
|
||||
ItemMeta itemMetadata = heldItem.getItemMeta();
|
||||
if (itemMetadata == null) {
|
||||
BooksWithoutBorders.sendErrorMessage(sender, "Unable to get metadata for your held item!");
|
||||
stringFormatter.displayErrorMessage(sender, Translatable.ERROR_METADATA_MISSING);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class CommandSetTitle implements TabExecutor {
|
||||
ItemMeta newMetaData;
|
||||
if (heldItem.getType() == Material.WRITTEN_BOOK) {
|
||||
if (title.length() > 32) {
|
||||
BooksWithoutBorders.sendErrorMessage(sender, "Book titles are capped at 32 characters!");
|
||||
stringFormatter.displayErrorMessage(sender, Translatable.ERROR_TITLE_LENGTH);
|
||||
return false;
|
||||
}
|
||||
BookMeta bookMetadata = (BookMeta) itemMetadata;
|
||||
@@ -70,7 +70,8 @@ public class CommandSetTitle implements TabExecutor {
|
||||
|
||||
//Set the new metadata
|
||||
heldItem.setItemMeta(newMetaData);
|
||||
BooksWithoutBorders.sendSuccessMessage(sender, "Title set to " + title + "!");
|
||||
stringFormatter.displaySuccessMessage(sender,
|
||||
stringFormatter.replacePlaceholder(Translatable.SUCCESS_TITLE_SET, "{title}", title));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,12 @@
|
||||
package net.knarcraft.bookswithoutborders.command;
|
||||
|
||||
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||
import net.knarcraft.bookswithoutborders.config.Permission;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.Translatable;
|
||||
import net.knarcraft.bookswithoutborders.state.ItemSlot;
|
||||
import net.knarcraft.bookswithoutborders.utility.BookHelper;
|
||||
import net.knarcraft.bookswithoutborders.utility.InventoryHelper;
|
||||
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
@@ -24,13 +27,17 @@ public class CommandUnSign 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 signed book to unsign it!",
|
||||
"You cannot unsign two books at once. Please un-equip one of the books you're holding!")) {
|
||||
if (InventoryHelper.notHoldingOneWrittenBookCheck(player,
|
||||
stringFormatter.replacePlaceholder(Translatable.ERROR_NOT_HOLDING_WRITTEN_BOOK, "{action}",
|
||||
stringFormatter.getUnFormattedColoredMessage(Translatable.ACTION_UNSIGN)),
|
||||
stringFormatter.replacePlaceholder(Translatable.ERROR_ONLY_ONE_BOOK, "{action}",
|
||||
stringFormatter.getUnFormattedColoredMessage(Translatable.ACTION_UNSIGN)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -50,14 +57,14 @@ public class CommandUnSign implements TabExecutor {
|
||||
//Get the old book
|
||||
BookMeta oldMetadata = InventoryHelper.getHeldBookMetadata(player, mainHand);
|
||||
if (oldMetadata == null) {
|
||||
BooksWithoutBorders.sendErrorMessage(player, "Unable to get metadata from the held book!");
|
||||
BooksWithoutBorders.getStringFormatter().displayErrorMessage(player, Translatable.ERROR_METADATA_MISSING);
|
||||
return;
|
||||
}
|
||||
ItemStack heldBook = InventoryHelper.getHeldBook(player, mainHand);
|
||||
|
||||
//Only allow the owner to un-sign the book
|
||||
if (BooksWithoutBorders.getConfiguration().getAuthorOnlyUnsign() &&
|
||||
!player.hasPermission("bookswithoutborders.bypassAuthorOnlyUnsign")) {
|
||||
!player.hasPermission(Permission.AUTHOR_ONLY_UNSIGN.toString())) {
|
||||
if (BookHelper.isNotAuthor(player, Objects.requireNonNull(oldMetadata))) {
|
||||
return;
|
||||
}
|
||||
|
@@ -37,6 +37,10 @@ public enum Permission {
|
||||
*/
|
||||
BYPASS_AUTHOR_ONLY_SAVE("bypassAuthorOnlySave"),
|
||||
|
||||
/**
|
||||
* The permission for bypassing author only un-signing
|
||||
*/
|
||||
AUTHOR_ONLY_UNSIGN("bypassAuthorOnlyUnsign"),
|
||||
;
|
||||
|
||||
private final @NotNull String node;
|
||||
|
@@ -9,7 +9,7 @@ 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!"),
|
||||
EXCEPTION_COMMAND_NOT_REGISTERED("Command {command} has not been registered!"),
|
||||
EXCEPTION_VAULT_NOT_AVAILABLE("Vault is unavailable, but book price is set to economy. Unsetting book cost!"),
|
||||
EXCEPTION_VAULT_PRICE_NOT_CHANGED("BooksWithoutBorders failed to hook into Vault! Book price not set!"),
|
||||
EXCEPTION_ENCRYPTED_FILE_DELETE_FAILED("Book encryption data failed to delete upon decryption!\nFile location: {path}"),
|
||||
@@ -17,6 +17,14 @@ public enum StaticMessage {
|
||||
EXCEPTION_SAVE_BOOK_FAILED("Unable to save book"),
|
||||
EXCEPTION_BOOKSHELF_SAVING_FAILED("Unable to save bookshelves!"),
|
||||
NOTICE_NO_BOOKSHELVES("BooksWithoutBorders found no bookshelves to load"),
|
||||
EXCEPTION_BOOKSHELF_NAME_EMPTY("Bookshelves cannot have empty titles!"),
|
||||
DEBUG_AES_INVALID_KEY("Invalid AES key given!"),
|
||||
DEBUG_AES_INVALID_PARAMETERS("Invalid AES parameters given!"),
|
||||
DEBUG_AES_INVALID_BLOCK_SIZE("Invalid AES block size during finalization"),
|
||||
DEBUG_AES_INVALID_PADDING_FINALIZATION("Invalid AES padding during finalization"),
|
||||
DEBUG_AES_INVALID_ALGORITHM("Invalid AES algorithm"),
|
||||
DEBUG_AES_INVALID_PADDING_CIPHER("Invalid AES padding during Cipher generation"),
|
||||
DEBUG_AES_INVALID_KEY_SPECIFICATION("Invalid AES key specification"),
|
||||
;
|
||||
|
||||
private final @NotNull String messageString;
|
||||
|
@@ -41,7 +41,7 @@ public enum BookshelfMessage implements TranslatableMessage {
|
||||
|
||||
@Override
|
||||
public @NotNull TranslatableMessage[] getAllMessages() {
|
||||
return Translatable.values();
|
||||
return BookshelfMessage.values();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -51,7 +51,7 @@ public enum CostMessage implements TranslatableMessage {
|
||||
|
||||
@Override
|
||||
public @NotNull TranslatableMessage[] getAllMessages() {
|
||||
return Translatable.values();
|
||||
return CostMessage.values();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -67,11 +67,91 @@ public enum Formatting implements TranslatableMessage {
|
||||
* The format used when formatting text on a title page
|
||||
*/
|
||||
NEUTRAL_TITLE_PAGE_TEXT_FORMAT,
|
||||
|
||||
/**
|
||||
* The format used when showing the header for public books by a specific author
|
||||
*/
|
||||
NEUTRAL_AUTHOR_PUBLIC_BOOKS_HEADER,
|
||||
|
||||
/**
|
||||
* The format used when showing the header for player books by a specific author
|
||||
*/
|
||||
NEUTRAL_AUTHOR_PLAYER_BOOKS_HEADER,
|
||||
|
||||
/**
|
||||
* The format used when showing the hover action for selecting a book by its path
|
||||
*/
|
||||
NEUTRAL_AUTHOR_BOOKS_PATH,
|
||||
|
||||
/**
|
||||
* The format used when displaying an empty author books page
|
||||
*/
|
||||
NEUTRAL_AUTHOR_BOOKS_INVALID_PAGE,
|
||||
|
||||
/**
|
||||
* The format used when showing current ant total pages in the book list
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_TOTAL_PAGES,
|
||||
|
||||
/**
|
||||
* The format used when showing the previous button in the book list
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_PREVIOUS_PAGE,
|
||||
|
||||
/**
|
||||
* The format used when showing the next button in the book list
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_NEXT_PAGE,
|
||||
|
||||
/**
|
||||
* The separator between book and author in the book list
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_AUTHOR_SEPARATOR,
|
||||
|
||||
/**
|
||||
* The format used when showing the page a link goes to in the book list
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_TO_PAGE,
|
||||
|
||||
/**
|
||||
* The format used when showing the hover hint on the book index
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_INDEX_HOVER,
|
||||
|
||||
/**
|
||||
* The format used when showing the header of the public book list
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_PUBLIC_BOOKS_HEADER,
|
||||
|
||||
/**
|
||||
* The format used when showing the header of the player book list
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_PLAYER_BOOKS_HEADER,
|
||||
|
||||
/**
|
||||
* The format used when showing the books by hover text
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_AUTHOR_HOVER,
|
||||
|
||||
/**
|
||||
* The format used when showing the book path hover text
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_PATH_HOVER,
|
||||
|
||||
/**
|
||||
* The format used when showing the book list select by index hover text
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_BOOK_INDEX_HOVER,
|
||||
|
||||
/**
|
||||
* The format used when showing book int index in the book list
|
||||
*/
|
||||
NEUTRAL_BOOK_LIST_BOOK_INDEX_NUMBER,
|
||||
;
|
||||
|
||||
@Override
|
||||
public @NotNull TranslatableMessage[] getAllMessages() {
|
||||
return Translatable.values();
|
||||
return Formatting.values();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ public enum GiveMessage implements TranslatableMessage {
|
||||
|
||||
@Override
|
||||
public @NotNull TranslatableMessage[] getAllMessages() {
|
||||
return Translatable.values();
|
||||
return GiveMessage.values();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ public enum SaveMessage implements TranslatableMessage {
|
||||
|
||||
@Override
|
||||
public @NotNull TranslatableMessage[] getAllMessages() {
|
||||
return Translatable.values();
|
||||
return SaveMessage.values();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -78,6 +78,11 @@ public enum Translatable implements TranslatableMessage {
|
||||
*/
|
||||
SUCCESS_LORE_SET,
|
||||
|
||||
/**
|
||||
* The success message displayed when an item's title is successfully set
|
||||
*/
|
||||
SUCCESS_TITLE_SET,
|
||||
|
||||
/**
|
||||
* The error to display when the console attempts to run a player-only command
|
||||
*/
|
||||
@@ -128,6 +133,11 @@ public enum Translatable implements TranslatableMessage {
|
||||
*/
|
||||
ACTION_CHANGE_GENERATION,
|
||||
|
||||
/**
|
||||
* The translation of the unsign action
|
||||
*/
|
||||
ACTION_UNSIGN,
|
||||
|
||||
/**
|
||||
* The error displayed when running a relevant command while holding one book in each hand
|
||||
*/
|
||||
@@ -291,12 +301,17 @@ public enum Translatable implements TranslatableMessage {
|
||||
/**
|
||||
* The error displayed when attempting to change the lore of an item without holding an item
|
||||
*/
|
||||
ERROR_LORE_NO_ITEM,
|
||||
ERROR_NO_ITEM,
|
||||
|
||||
/**
|
||||
* The error displayed when attempting to change an item's title/display name without specifying the new title/display name
|
||||
*/
|
||||
ERROR_TITLE_EMPTY,
|
||||
|
||||
/**
|
||||
* The error displayed when attempting to change a book's title with a title that's too long
|
||||
*/
|
||||
ERROR_TITLE_LENGTH,
|
||||
;
|
||||
|
||||
@Override
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package net.knarcraft.bookswithoutborders.container;
|
||||
|
||||
import net.knarcraft.bookswithoutborders.config.StaticMessage;
|
||||
import org.bukkit.Location;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -64,7 +65,7 @@ public class Bookshelf {
|
||||
*/
|
||||
public void setTitle(@NotNull String title) {
|
||||
if (title.isBlank()) {
|
||||
throw new IllegalArgumentException("Bookshelves cannot have empty titles!");
|
||||
throw new IllegalArgumentException(StaticMessage.EXCEPTION_BOOKSHELF_NAME_EMPTY.toString());
|
||||
}
|
||||
this.title = title;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package net.knarcraft.bookswithoutborders.encryption;
|
||||
|
||||
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||
import net.knarcraft.bookswithoutborders.config.StaticMessage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -97,8 +98,11 @@ public class AES implements Encryptor {
|
||||
//Initialize cipher
|
||||
try {
|
||||
aes.init(mode, secretKeySpec, ivParameterSpec);
|
||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException exception) {
|
||||
BooksWithoutBorders.log(Level.SEVERE, "Invalid AES input given!");
|
||||
} catch (InvalidKeyException exception) {
|
||||
BooksWithoutBorders.log(Level.FINE, StaticMessage.DEBUG_AES_INVALID_KEY.toString());
|
||||
return null;
|
||||
} catch (InvalidAlgorithmParameterException exception) {
|
||||
BooksWithoutBorders.log(Level.FINE, StaticMessage.DEBUG_AES_INVALID_PARAMETERS.toString());
|
||||
return null;
|
||||
}
|
||||
//Perform encryption/decryption and output result
|
||||
@@ -106,10 +110,10 @@ public class AES implements Encryptor {
|
||||
byte[] output = aes.doFinal(getInputBytes(input, encrypt));
|
||||
return createResult(output, encrypt);
|
||||
} catch (IllegalBlockSizeException exception) {
|
||||
BooksWithoutBorders.log(Level.SEVERE, "Invalid AES block size during finalization");
|
||||
BooksWithoutBorders.log(Level.FINE, StaticMessage.DEBUG_AES_INVALID_BLOCK_SIZE.toString());
|
||||
return null;
|
||||
} catch (BadPaddingException exception) {
|
||||
BooksWithoutBorders.log(Level.SEVERE, "Invalid AES padding during finalization");
|
||||
BooksWithoutBorders.log(Level.FINE, StaticMessage.DEBUG_AES_INVALID_PADDING_FINALIZATION.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -156,10 +160,10 @@ public class AES implements Encryptor {
|
||||
try {
|
||||
aes = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
} catch (NoSuchAlgorithmException exception) {
|
||||
BooksWithoutBorders.log(Level.SEVERE, "Invalid AES algorithm during Cipher generation");
|
||||
BooksWithoutBorders.log(Level.SEVERE, StaticMessage.DEBUG_AES_INVALID_ALGORITHM.toString());
|
||||
return null;
|
||||
} catch (NoSuchPaddingException exception) {
|
||||
BooksWithoutBorders.log(Level.SEVERE, "Invalid AES padding during Cipher generation");
|
||||
BooksWithoutBorders.log(Level.SEVERE, StaticMessage.DEBUG_AES_INVALID_PADDING_CIPHER.toString());
|
||||
return null;
|
||||
}
|
||||
return aes;
|
||||
@@ -178,14 +182,14 @@ public class AES implements Encryptor {
|
||||
try {
|
||||
keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
|
||||
} catch (NoSuchAlgorithmException exception) {
|
||||
BooksWithoutBorders.log(Level.SEVERE, "Invalid AES algorithm");
|
||||
BooksWithoutBorders.log(Level.SEVERE, StaticMessage.DEBUG_AES_INVALID_ALGORITHM.toString());
|
||||
return null;
|
||||
}
|
||||
SecretKey tmp;
|
||||
try {
|
||||
tmp = keyFactory.generateSecret(spec);
|
||||
} catch (InvalidKeySpecException exception) {
|
||||
BooksWithoutBorders.log(Level.SEVERE, "Invalid AES key specification");
|
||||
BooksWithoutBorders.log(Level.SEVERE, StaticMessage.DEBUG_AES_INVALID_KEY_SPECIFICATION.toString());
|
||||
return null;
|
||||
}
|
||||
return new SecretKeySpec(tmp.getEncoded(), "AES");
|
||||
|
@@ -12,6 +12,8 @@ import java.util.Random;
|
||||
*
|
||||
* <p>Not sure where this was gotten from, but it does exist at
|
||||
* <a href="https://crypto.stackexchange.com/questions/11614/how-do-i-test-my-encryption-absolute-amateur">Stack Exchange</a>.</p>
|
||||
*
|
||||
* @author AkiraAkiba
|
||||
*/
|
||||
public class GenenCrypt implements Encryptor {
|
||||
|
||||
@@ -58,11 +60,12 @@ public class GenenCrypt implements Encryptor {
|
||||
originalCodonList.remove(index);
|
||||
}
|
||||
|
||||
// define the characters that can be encoded, 64 in total
|
||||
// 26 capital letters
|
||||
// 10 digits
|
||||
// space, newline, and tab
|
||||
// the symbols . , ? " ! @ # $ % ^ & * ( ) - + = / _ \ : ; < >
|
||||
/* define the characters that can be encoded, 64 in total
|
||||
26 capital letters
|
||||
10 digits
|
||||
space, newline, and tab
|
||||
the symbols . , ? " ! @ # $ % ^ & * ( ) - + = / _ \ : ; < >
|
||||
*/
|
||||
availableCharacters = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
|
||||
"R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", " ",
|
||||
"\t", "\n", ".", ",", "?", "\"", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "+", "=", "/",
|
||||
|
@@ -5,6 +5,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* So-called "Magic" encryption which simply makes the contents unreadable
|
||||
*
|
||||
* @author AkiraAkiba
|
||||
*/
|
||||
public class Magic implements Encryptor {
|
||||
|
||||
|
@@ -10,6 +10,8 @@ import java.util.Base64;
|
||||
|
||||
/**
|
||||
* A one-time pad implementation
|
||||
*
|
||||
* @author AkiraAkiba
|
||||
*/
|
||||
public class OneTimePad implements Encryptor {
|
||||
|
||||
|
@@ -8,6 +8,8 @@ import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* A simple substitution cipher
|
||||
*
|
||||
* @author AkiraAkiba
|
||||
*/
|
||||
public class SubstitutionCipher implements Encryptor {
|
||||
|
||||
|
@@ -1,8 +1,10 @@
|
||||
package net.knarcraft.bookswithoutborders.gui;
|
||||
|
||||
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.Formatting;
|
||||
import net.knarcraft.bookswithoutborders.utility.BookFileHelper;
|
||||
import net.knarcraft.bookswithoutborders.utility.BookFormatter;
|
||||
import net.knarcraft.knarlib.formatting.TranslatableMessage;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
@@ -33,9 +35,9 @@ public class AuthorBookIndex extends BookIndex {
|
||||
|
||||
int totalPages = (int) Math.ceil((double) availableBooks.size() / booksPerPage);
|
||||
if (page > totalPages) {
|
||||
sender.sendMessage(ChatColor.GRAY + "No such page");
|
||||
BooksWithoutBorders.getStringFormatter().displayErrorMessage(sender, Formatting.NEUTRAL_AUTHOR_BOOKS_INVALID_PAGE);
|
||||
} else {
|
||||
showAuthorBooks(sender, command, page, totalPages, availableBooks, authorName);
|
||||
showAuthorBooks(sender, command, page, totalPages, availableBooks, authorName, listPublic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,19 +50,16 @@ public class AuthorBookIndex extends BookIndex {
|
||||
* @param totalPages <p>The total amount of pages</p>
|
||||
* @param availableBooks <p>All books available to the sender</p>
|
||||
* @param authorName <p>The name of the author currently shown</p>
|
||||
* @param listPublic <p>Whether to display public books</p>
|
||||
*/
|
||||
private static void showAuthorBooks(@NotNull CommandSender sender, @NotNull String command, int page,
|
||||
int totalPages, @NotNull List<String> availableBooks, @NotNull String authorName) {
|
||||
int totalPages, @NotNull List<String> availableBooks,
|
||||
@NotNull String authorName, boolean listPublic) {
|
||||
ComponentBuilder componentBuilder = new ComponentBuilder();
|
||||
String navigationCommand = command + " author" + authorName;
|
||||
|
||||
componentBuilder.append("--- ");
|
||||
if (command.toLowerCase().contains("public")) {
|
||||
componentBuilder.append("Publicly saved books by: ").color(ChatColor.GREEN).append(authorName).color(ChatColor.AQUA);
|
||||
} else {
|
||||
componentBuilder.append("Your saved books by: ").color(ChatColor.GREEN).append(authorName).color(ChatColor.AQUA);
|
||||
}
|
||||
componentBuilder.append(" ---", ComponentBuilder.FormatRetention.NONE).append("\n");
|
||||
TranslatableMessage message = listPublic ? Formatting.NEUTRAL_AUTHOR_PUBLIC_BOOKS_HEADER : Formatting.NEUTRAL_AUTHOR_PLAYER_BOOKS_HEADER;
|
||||
componentBuilder.append(color(message, "{author}", authorName));
|
||||
|
||||
|
||||
displayBookList(componentBuilder, command, page, availableBooks);
|
||||
@@ -84,10 +83,15 @@ public class AuthorBookIndex extends BookIndex {
|
||||
@NotNull List<String> availableBooks) {
|
||||
int startIndex = (page - 1) * booksPerPage;
|
||||
for (int bookIndex = startIndex; bookIndex < Math.min(startIndex + booksPerPage, availableBooks.size()); bookIndex++) {
|
||||
componentBuilder.append(getNiceName(availableBooks.get(bookIndex))).color(ChatColor.WHITE).event(
|
||||
String title = BookFileHelper.getBookTitleFromPath(availableBooks.get(bookIndex));
|
||||
String author = BookFileHelper.getBookAuthorFromPath(availableBooks.get(bookIndex));
|
||||
String niceName = color(title) + color(Formatting.NEUTRAL_BOOK_LIST_AUTHOR_SEPARATOR) + color(author);
|
||||
|
||||
componentBuilder.append(niceName).color(ChatColor.WHITE).event(
|
||||
new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " +
|
||||
availableBooks.get(bookIndex))).event(
|
||||
new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Select book by path")));
|
||||
new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(BooksWithoutBorders.getStringFormatter().
|
||||
getUnFormattedColoredMessage(Formatting.NEUTRAL_AUTHOR_BOOKS_PATH))));
|
||||
componentBuilder.append("\n");
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,12 @@
|
||||
package net.knarcraft.bookswithoutborders.gui;
|
||||
|
||||
import net.knarcraft.bookswithoutborders.utility.BookFileHelper;
|
||||
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.Formatting;
|
||||
import net.knarcraft.bookswithoutborders.utility.InputCleaningHelper;
|
||||
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||
import net.knarcraft.knarlib.formatting.TranslatableMessage;
|
||||
import net.knarcraft.knarlib.property.ColorConversion;
|
||||
import net.knarcraft.knarlib.util.ColorHelper;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
@@ -9,7 +14,9 @@ import net.md_5.bungee.api.chat.HoverEvent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class BookIndex {
|
||||
@@ -80,8 +87,11 @@ public abstract class BookIndex {
|
||||
* @param page <p>The current page</p>
|
||||
* @param totalPages <p>The total amount of pages</p>
|
||||
*/
|
||||
protected static void displayTotalPages(@NotNull ComponentBuilder componentBuilder, @NotNull String command, int page, int totalPages) {
|
||||
componentBuilder.append("Page " + page + " of " + totalPages,
|
||||
protected static void displayTotalPages(@NotNull ComponentBuilder componentBuilder, @NotNull String command,
|
||||
int page, int totalPages) {
|
||||
String pageDisplay = color(Formatting.NEUTRAL_BOOK_LIST_TOTAL_PAGES, List.of("{current}", "{total}"),
|
||||
List.of(String.valueOf(page), String.valueOf(totalPages)));
|
||||
componentBuilder.append(pageDisplay,
|
||||
ComponentBuilder.FormatRetention.NONE).color(interactColor).event(new HoverEvent(
|
||||
HoverEvent.Action.SHOW_TEXT, new Text("/" + command + " page" + page))).event(
|
||||
new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " page" + page));
|
||||
@@ -101,10 +111,12 @@ public abstract class BookIndex {
|
||||
char character = (char) ('a' + characterIndex);
|
||||
if (firstInstances.containsKey(character)) {
|
||||
int pageIndex = (firstInstances.get(character) / booksPerPage) + 1;
|
||||
componentBuilder.append(character + "").color(interactColor).event(
|
||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND,
|
||||
"/" + command + " page" + pageIndex)).event(new HoverEvent(
|
||||
HoverEvent.Action.SHOW_TEXT, new Text("Books starting with " + character)));
|
||||
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(
|
||||
color(Formatting.NEUTRAL_BOOK_LIST_INDEX_HOVER, "{character}", "" + character)));
|
||||
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.RUN_COMMAND,
|
||||
"/" + command + " page" + pageIndex);
|
||||
|
||||
componentBuilder.append(character + "").color(interactColor).event(clickEvent).event(hoverEvent);
|
||||
} else {
|
||||
componentBuilder.append(character + "", ComponentBuilder.FormatRetention.NONE).color(inactiveColor);
|
||||
}
|
||||
@@ -121,14 +133,16 @@ public abstract class BookIndex {
|
||||
*/
|
||||
protected static void displayPreviousButton(@NotNull ComponentBuilder componentBuilder,
|
||||
@NotNull String command, int page) {
|
||||
String previousPage = color(Formatting.NEUTRAL_BOOK_LIST_PREVIOUS_PAGE);
|
||||
if (page > 1) {
|
||||
String fullCommand = "/" + command + " page" + (page - 1);
|
||||
HoverEvent prevPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("To page " + (page - 1)));
|
||||
HoverEvent prevPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(
|
||||
color(Formatting.NEUTRAL_BOOK_LIST_TO_PAGE, "{page}", String.valueOf(page - 1))));
|
||||
ClickEvent prevPageClick = new ClickEvent(ClickEvent.Action.RUN_COMMAND, fullCommand);
|
||||
componentBuilder.append("[<] Previous", ComponentBuilder.FormatRetention.NONE).color(interactColor)
|
||||
.event(prevPagePreview).event(prevPageClick);
|
||||
componentBuilder.append(previousPage, ComponentBuilder.FormatRetention.NONE).color(interactColor).
|
||||
event(prevPagePreview).event(prevPageClick);
|
||||
} else {
|
||||
componentBuilder.append("[<] Previous", ComponentBuilder.FormatRetention.NONE).color(inactiveColor);
|
||||
componentBuilder.append(previousPage, ComponentBuilder.FormatRetention.NONE).color(inactiveColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,29 +156,73 @@ public abstract class BookIndex {
|
||||
*/
|
||||
protected static void displayNextButton(@NotNull ComponentBuilder componentBuilder,
|
||||
@NotNull String command, int page, int totalPages) {
|
||||
String nextPage = color(Formatting.NEUTRAL_BOOK_LIST_NEXT_PAGE);
|
||||
if (page < totalPages) {
|
||||
String fullCommand = "/" + command + " page" + (page + 1);
|
||||
HoverEvent nextPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("To page " + (page + 1)));
|
||||
HoverEvent nextPagePreview = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(
|
||||
color(Formatting.NEUTRAL_BOOK_LIST_TO_PAGE, "{page}", String.valueOf(page + 1))));
|
||||
ClickEvent nextPageClick = new ClickEvent(ClickEvent.Action.RUN_COMMAND, fullCommand);
|
||||
componentBuilder.append("Next [>]", ComponentBuilder.FormatRetention.NONE).color(interactColor)
|
||||
componentBuilder.append(nextPage, ComponentBuilder.FormatRetention.NONE).color(interactColor)
|
||||
.event(nextPagePreview).event(nextPageClick);
|
||||
} else {
|
||||
componentBuilder.append("Next [>]", ComponentBuilder.FormatRetention.NONE).color(inactiveColor);
|
||||
componentBuilder.append(nextPage, ComponentBuilder.FormatRetention.NONE).color(inactiveColor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a nice name from a book's path
|
||||
* Colors a translatable message
|
||||
*
|
||||
* @param bookPath <p>The path of a book</p>
|
||||
* @return <p>The prettified book name</p>
|
||||
* @param translatableMessage <p>The message to color</p>
|
||||
* @return <p>The colored message</p>
|
||||
*/
|
||||
@NotNull
|
||||
protected static String getNiceName(@NotNull String bookPath) {
|
||||
String title = BookFileHelper.getBookTitleFromPath(bookPath);
|
||||
String author = BookFileHelper.getBookAuthorFromPath(bookPath);
|
||||
return ChatColor.translateAlternateColorCodes('&',
|
||||
title + ChatColor.RESET + " by " + author + ChatColor.RESET);
|
||||
protected static String color(@NotNull TranslatableMessage translatableMessage) {
|
||||
return color(translatableMessage, (List<String>) null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Colors a translatable message
|
||||
*
|
||||
* @param translatableMessage <p>The message to color</p>
|
||||
* @param placeholder <p>Placeholder to replace</p>
|
||||
* @param replacement <p>Replacement value</p>
|
||||
* @return <p>The colored message</p>
|
||||
*/
|
||||
@NotNull
|
||||
protected static String color(@NotNull TranslatableMessage translatableMessage, @NotNull String placeholder,
|
||||
@NotNull String replacement) {
|
||||
return color(translatableMessage, List.of(placeholder), List.of(replacement));
|
||||
}
|
||||
|
||||
/**
|
||||
* Colors a translatable message
|
||||
*
|
||||
* @param translatableMessage <p>The message to color</p>
|
||||
* @param placeholders <p>Placeholders to replace</p>
|
||||
* @param replacements <p>Replacement values</p>
|
||||
* @return <p>The colored message</p>
|
||||
*/
|
||||
@NotNull
|
||||
protected static String color(@NotNull TranslatableMessage translatableMessage, @Nullable List<String> placeholders,
|
||||
@Nullable List<String> replacements) {
|
||||
StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter();
|
||||
if (placeholders == null || replacements == null) {
|
||||
return stringFormatter.getUnFormattedColoredMessage(translatableMessage);
|
||||
} else {
|
||||
return ColorHelper.translateColorCodes(stringFormatter.replacePlaceholders(translatableMessage,
|
||||
placeholders, replacements), ColorConversion.RGB);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Colors a message
|
||||
*
|
||||
* @param input <p>The message to color</p>
|
||||
* @return <p>The colored message</p>
|
||||
*/
|
||||
@NotNull
|
||||
protected static String color(@NotNull String input) {
|
||||
return ColorHelper.translateColorCodes(input, ColorConversion.RGB);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package net.knarcraft.bookswithoutborders.gui;
|
||||
|
||||
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.Formatting;
|
||||
import net.knarcraft.bookswithoutborders.utility.BookFileHelper;
|
||||
import net.knarcraft.bookswithoutborders.utility.BookFormatter;
|
||||
import net.knarcraft.knarlib.formatting.TranslatableMessage;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
@@ -42,9 +45,9 @@ public class PagedBookIndex extends BookIndex {
|
||||
|
||||
int totalPages = (int) Math.ceil((double) availableBooks.size() / booksPerPage);
|
||||
if (page > totalPages) {
|
||||
sender.sendMessage(ChatColor.GRAY + "No such page");
|
||||
BooksWithoutBorders.getStringFormatter().displayErrorMessage(sender, Formatting.NEUTRAL_AUTHOR_BOOKS_INVALID_PAGE);
|
||||
} else {
|
||||
showBookMenu(sender, command, page, totalPages, availableBooks, firstInstances);
|
||||
showBookMenu(sender, command, page, totalPages, availableBooks, firstInstances, listPublic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,19 +60,15 @@ public class PagedBookIndex extends BookIndex {
|
||||
* @param totalPages <p>The total amount of pages</p>
|
||||
* @param availableBooks <p>All books available to the sender</p>
|
||||
* @param firstInstances <p>The map between a character, and the index of the first instance of that character in the book list</p>
|
||||
* @param listPublic <p>Whether to display public books</p>
|
||||
*/
|
||||
private static void showBookMenu(@NotNull CommandSender sender, @NotNull String command, int page,
|
||||
int totalPages, @NotNull List<String> availableBooks,
|
||||
@NotNull Map<Character, Integer> firstInstances) {
|
||||
@NotNull Map<Character, Integer> firstInstances, boolean listPublic) {
|
||||
ComponentBuilder componentBuilder = new ComponentBuilder();
|
||||
|
||||
componentBuilder.append("--- ");
|
||||
if (command.toLowerCase().contains("public")) {
|
||||
componentBuilder.append("Publicly saved books").color(ChatColor.GREEN);
|
||||
} else {
|
||||
componentBuilder.append("Your saved books").color(ChatColor.GREEN);
|
||||
}
|
||||
componentBuilder.append(" ---", ComponentBuilder.FormatRetention.NONE).append("\n");
|
||||
TranslatableMessage message = listPublic ? Formatting.NEUTRAL_BOOK_LIST_PUBLIC_BOOKS_HEADER : Formatting.NEUTRAL_BOOK_LIST_PLAYER_BOOKS_HEADER;
|
||||
componentBuilder.append(color(message));
|
||||
|
||||
displayBookList(componentBuilder, command, page, availableBooks);
|
||||
displayPreviousButton(componentBuilder, command, page);
|
||||
@@ -94,24 +93,23 @@ public class PagedBookIndex extends BookIndex {
|
||||
@NotNull List<String> availableBooks) {
|
||||
int startIndex = (page - 1) * booksPerPage;
|
||||
for (int bookIndex = startIndex; bookIndex < Math.min(startIndex + booksPerPage, availableBooks.size()); bookIndex++) {
|
||||
componentBuilder.append("[" + (bookIndex + 1) + "]").color(interactColor).event(
|
||||
new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " +
|
||||
(bookIndex + 1))).event(new HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||
new Text("Select book by index")));
|
||||
String title = color(BookFileHelper.getBookTitleFromPath(availableBooks.get(bookIndex)));
|
||||
String author = color(BookFileHelper.getBookAuthorFromPath(availableBooks.get(bookIndex)));
|
||||
|
||||
ClickEvent indexClick = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " + (bookIndex + 1));
|
||||
HoverEvent indexHover = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(color(Formatting.NEUTRAL_BOOK_LIST_BOOK_INDEX_HOVER)));
|
||||
ClickEvent pathClick = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " + availableBooks.get(bookIndex));
|
||||
HoverEvent pathHover = new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(color(Formatting.NEUTRAL_BOOK_LIST_PATH_HOVER)));
|
||||
ClickEvent authorClick = new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/" + command + " author" + BookFormatter.stripColor(author) + " page1");
|
||||
HoverEvent authorHover = new HoverEvent(HoverEvent.Action.SHOW_TEXT,
|
||||
new Text(color(Formatting.NEUTRAL_BOOK_LIST_AUTHOR_HOVER, "{author}", BookFormatter.stripColor(author))));
|
||||
|
||||
componentBuilder.append(color(Formatting.NEUTRAL_BOOK_LIST_BOOK_INDEX_NUMBER, "{index}",
|
||||
String.valueOf(bookIndex + 1))).color(interactColor).event(indexClick).event(indexHover);
|
||||
componentBuilder.append(" ", ComponentBuilder.FormatRetention.NONE);
|
||||
|
||||
String[] parts = getNiceName(availableBooks.get(bookIndex)).split(" by ");
|
||||
componentBuilder.append(parts[0]).color(ChatColor.WHITE).event(
|
||||
new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + command + " " +
|
||||
availableBooks.get(bookIndex))).event(
|
||||
new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Select book by path")));
|
||||
componentBuilder.append(" by ", ComponentBuilder.FormatRetention.NONE).color(ChatColor.WHITE);
|
||||
componentBuilder.append(parts[1]).color(ChatColor.WHITE).event(
|
||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/" + command + " author" +
|
||||
BookFormatter.stripColor(parts[1]) + " page1")).event(
|
||||
new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Books by " +
|
||||
BookFormatter.stripColor(parts[1]))));
|
||||
componentBuilder.append(title).color(ChatColor.WHITE).event(pathClick).event(pathHover);
|
||||
componentBuilder.append(color(Formatting.NEUTRAL_BOOK_LIST_AUTHOR_SEPARATOR), ComponentBuilder.FormatRetention.NONE).color(ChatColor.WHITE);
|
||||
componentBuilder.append(author).color(ChatColor.WHITE).event(authorClick).event(authorHover);
|
||||
componentBuilder.append("\n");
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package net.knarcraft.bookswithoutborders.utility;
|
||||
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||
import net.knarcraft.bookswithoutborders.state.BookHoldingState;
|
||||
import net.knarcraft.bookswithoutborders.state.ItemSlot;
|
||||
import net.knarcraft.knarlib.formatting.StringFormatter;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -79,16 +80,17 @@ public final class InventoryHelper {
|
||||
*/
|
||||
public static boolean notHoldingOneWritableBookCheck(@NotNull Player player, @NotNull String noBookMessage,
|
||||
@NotNull String twoBooksMessage) {
|
||||
StringFormatter stringFormatter = BooksWithoutBorders.getStringFormatter();
|
||||
BookHoldingState holdingState = getBookHoldingState(player);
|
||||
|
||||
if (holdingState == BookHoldingState.NONE || holdingState == BookHoldingState.SIGNED_BOTH_HANDS ||
|
||||
holdingState == BookHoldingState.SIGNED_MAIN_HAND || holdingState == BookHoldingState.SIGNED_OFF_HAND) {
|
||||
BooksWithoutBorders.sendErrorMessage(player, noBookMessage);
|
||||
stringFormatter.displayErrorMessage(player, noBookMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (holdingState == BookHoldingState.UNSIGNED_BOTH_HANDS) {
|
||||
BooksWithoutBorders.sendErrorMessage(player, twoBooksMessage);
|
||||
stringFormatter.displayErrorMessage(player, twoBooksMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,7 @@ en:
|
||||
SUCCESS_BOOKSHELF_LORE_SET: "Lore successfully saved!"
|
||||
SUCCESS_GENERATION_CHANGED: "Book generation successfully changed!"
|
||||
SUCCESS_LORE_SET: "Added lore to item!"
|
||||
SUCCESS_TITLE_SET: "Title set to {title}!"
|
||||
ACTION_COPY: "copy"
|
||||
ACTION_CLEAR: "clear"
|
||||
ACTION_DECRYPT: "decrypt"
|
||||
@@ -30,6 +31,7 @@ en:
|
||||
ACTION_ADD_TITLE_AUTHOR_PAGE: "add an author title page to"
|
||||
ACTION_SET_AUTHOR: "set author"
|
||||
ACTION_CHANGE_GENERATION: "change generation"
|
||||
ACTION_UNSIGN: "unsign"
|
||||
ERROR_PLAYER_ONLY: "This command can only be used by a player!"
|
||||
ERROR_NOT_HOLDING_WRITTEN_BOOK: "You must be holding a written book to {action} it!"
|
||||
ERROR_NOT_HOLDING_WRITABLE_BOOK: "You must be holding a writable book to {action} it!"
|
||||
@@ -86,8 +88,12 @@ en:
|
||||
ERROR_GENERATION_NOT_SPECIFIED: "You must specify the new generation for your book!"
|
||||
ERROR_GENERATION_INVALID: "Invalid book generation specified!"
|
||||
ERROR_LORE_EMPTY: "You must specify the new lore to set!"
|
||||
ERROR_LORE_NO_ITEM: "Must be holding an item to set lore!"
|
||||
ERROR_NO_ITEM: "You must be holding an item to use this command!"
|
||||
ERROR_TITLE_EMPTY: "You must specify the new title/display name to set!"
|
||||
ERROR_TITLE_LENGTH: "Book titles are capped at 32 characters!"
|
||||
# ---------------------------------- #
|
||||
# Custom formatting for some output #
|
||||
# ---------------------------------- #
|
||||
NEUTRAL_COMMANDS_HEADER: |
|
||||
&nBooks without Borders help page&r
|
||||
&e[] = optional, <> = required (see each description for exceptions)
|
||||
@@ -100,8 +106,28 @@ en:
|
||||
NEUTRAL_COMMANDS_COMMAND_NO_PERMISSION_REQUIRED: "None"
|
||||
NEUTRAL_COMMANDS_COMMAND_PERMISSION: " &7{{permission}}"
|
||||
NEUTRAL_COMMANDS_ALIASES: " &f(&b{aliases}&f)"
|
||||
NEUTRAL_UNKNOWN_AUTHOR: "Unknown"
|
||||
NEUTRAL_UNKNOWN_TITLE: "Untitled"
|
||||
NEUTRAL_TITLE_PAGE_TITLE_AUTHOR_FORMAT: "{title}{separator}By: {author}"
|
||||
NEUTRAL_TITLE_PAGE_HEADER_FORMAT: "\n&n&l{header}&r"
|
||||
NEUTRAL_TITLE_PAGE_TEXT_FORMAT: "\n\n&o{text}&r"
|
||||
NEUTRAL_TITLE_PAGE_TEXT_FORMAT: "\n\n&o{text}&r"
|
||||
NEUTRAL_AUTHOR_PUBLIC_BOOKS_HEADER: "--- &aPublicly saved books by: &b{author}&r ---\n"
|
||||
NEUTRAL_AUTHOR_PLAYER_BOOKS_HEADER: "--- &aYour saved books by: &b{author}&r ---\n"
|
||||
NEUTRAL_AUTHOR_BOOKS_PATH: "Select book by path"
|
||||
NEUTRAL_AUTHOR_BOOKS_INVALID_PAGE: "&7No such page"
|
||||
NEUTRAL_BOOK_LIST_TOTAL_PAGES: "Page {current} of {total}"
|
||||
NEUTRAL_BOOK_LIST_PREVIOUS_PAGE: "[<] Previous"
|
||||
NEUTRAL_BOOK_LIST_NEXT_PAGE: "Next [>]"
|
||||
NEUTRAL_BOOK_LIST_AUTHOR_SEPARATOR: "&r by "
|
||||
NEUTRAL_BOOK_LIST_TO_PAGE: "To page {page}"
|
||||
NEUTRAL_BOOK_LIST_INDEX_HOVER: "Books starting with {character}"
|
||||
NEUTRAL_BOOK_LIST_PUBLIC_BOOKS_HEADER: "--- &aPublicly saved books&r ---\n"
|
||||
NEUTRAL_BOOK_LIST_PLAYER_BOOKS_HEADER: "--- &aYour saved books&r ---\n"
|
||||
NEUTRAL_BOOK_LIST_AUTHOR_HOVER: "Books by {author}"
|
||||
NEUTRAL_BOOK_LIST_PATH_HOVER: "Select book by path"
|
||||
NEUTRAL_BOOK_LIST_BOOK_INDEX_HOVER: "Select book by index"
|
||||
NEUTRAL_BOOK_LIST_BOOK_INDEX_NUMBER: "[{index}]"
|
||||
# -----------------------------------------#
|
||||
# Translations of unknown/untitled author. #
|
||||
# Altering this might cause problems. #
|
||||
# -----------------------------------------#
|
||||
NEUTRAL_UNKNOWN_AUTHOR: "Unknown"
|
||||
NEUTRAL_UNKNOWN_TITLE: "Untitled"
|
Reference in New Issue
Block a user