Cleans up sign code quite a lot #14
All checks were successful
EpicKnarvik97/Books-Without-Borders/pipeline/head This commit looks good

This commit is contained in:
2025-09-03 16:49:01 +02:00
parent 12a2cd5a73
commit 6c1094ff98
17 changed files with 258 additions and 178 deletions

View File

@@ -34,7 +34,7 @@ public class CommandAddTitlePage implements TabExecutor {
return true; return true;
} }
// Note: There are two different book checks as an book is accepted normally, but a written book is required for // Note: There are two different book checks as a book is accepted normally, but a written book is required for
// adding an author title page at the beginning. // adding an author title page at the beginning.
ItemStack heldBook = InventoryUtil.getHeldBook(player); ItemStack heldBook = InventoryUtil.getHeldBook(player);
if (heldBook == null) { if (heldBook == null) {

View File

@@ -32,7 +32,8 @@ public class CommandDelete implements TabExecutor {
return true; return true;
} }
return deleteBook(sender, arguments, false, label); deleteBook(sender, arguments, false, label);
return true;
} }
/** /**
@@ -42,25 +43,23 @@ public class CommandDelete implements TabExecutor {
* @param arguments <p>The arguments given</p> * @param arguments <p>The arguments given</p>
* @param deletePublic <p>Whether to delete a public book</p> * @param deletePublic <p>Whether to delete a public book</p>
* @param commandName <p>The name of the command calling this method</p> * @param commandName <p>The name of the command calling this method</p>
* @return <p>True if the book was deleted successfully</p>
*/ */
protected boolean deleteBook(@NotNull CommandSender sender, @NotNull String[] arguments, boolean deletePublic, protected void deleteBook(@NotNull CommandSender sender, @NotNull String[] arguments, boolean deletePublic,
@NotNull String commandName) { @NotNull String commandName) {
if (PagedBookIndex.displayPage(arguments, sender, deletePublic, commandName)) { if (PagedBookIndex.displayPage(arguments, sender, deletePublic, commandName)) {
return true; return;
} }
//Delete the file //Delete the file
List<String> availableBooks = BooksWithoutBorders.getAvailableBooks(sender, deletePublic); List<String> availableBooks = BooksWithoutBorders.getAvailableBooks(sender, deletePublic);
if (availableBooks.isEmpty()) { if (availableBooks.isEmpty()) {
new FormatBuilder(Translatable.ERROR_DELETE_EMPTY).error(sender); new FormatBuilder(Translatable.ERROR_DELETE_EMPTY).error(sender);
return true; return;
} }
performBookDeletion(sender, InputParsingUtil.mergeArguments(arguments, 0), deletePublic); performBookDeletion(sender, InputParsingUtil.mergeArguments(arguments, 0), deletePublic);
//Update the book list //Update the book list
BooksWithoutBorders.updateBooks(sender, deletePublic); BooksWithoutBorders.updateBooks(sender, deletePublic);
return true;
} }
/** /**

View File

@@ -15,7 +15,8 @@ public class CommandDeletePublic extends CommandDelete implements TabExecutor {
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] arguments) { @NotNull String[] arguments) {
return deleteBook(sender, arguments, true, label); deleteBook(sender, arguments, true, label);
return true;
} }
@Override @Override

View File

@@ -22,6 +22,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* Command executor for the encrypt command * Command executor for the encrypt command
@@ -36,7 +37,8 @@ public class CommandEncrypt implements TabExecutor {
return false; return false;
} }
EncryptionStyle encryptionStyle = arguments.length == 2 ? EncryptionStyle.getFromString(arguments[1]) : EncryptionStyle.AES; EncryptionStyle encryptionStyle = arguments.length == 2 ? Objects.requireNonNullElse(
EncryptionStyle.getFromString(arguments[1]), EncryptionStyle.AES) : EncryptionStyle.AES;
// AES is the only reliable method for retaining the plaintext // AES is the only reliable method for retaining the plaintext
BwBConfig config = BooksWithoutBorders.getConfiguration(); BwBConfig config = BooksWithoutBorders.getConfiguration();

View File

@@ -11,6 +11,7 @@ import org.bukkit.inventory.meta.BookMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* Command executor for the group encrypt command * Command executor for the group encrypt command
@@ -39,7 +40,8 @@ public class CommandGroupEncrypt extends CommandEncrypt implements TabExecutor {
return true; return true;
} }
EncryptionStyle encryptionStyle = arguments.length == 3 ? EncryptionStyle.getFromString(arguments[2]) : EncryptionStyle.AES; EncryptionStyle encryptionStyle = arguments.length == 3 ? Objects.requireNonNullElse(
EncryptionStyle.getFromString(arguments[2]), EncryptionStyle.AES) : EncryptionStyle.AES;
return encryptBook(encryptionStyle, player, arguments[1], arguments[0], false); return encryptBook(encryptionStyle, player, arguments[1], arguments[0], false);
} }

View File

@@ -36,7 +36,8 @@ public class CommandSave implements TabExecutor {
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] arguments) { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] arguments) {
return saveHeldBook(sender, arguments, false, label); saveHeldBook(sender, arguments, false, label);
return true;
} }
/** /**
@@ -46,13 +47,12 @@ public class CommandSave implements TabExecutor {
* @param arguments <p>The arguments given</p> * @param arguments <p>The arguments given</p>
* @param savePublic <p>Whether to save the book in the public directory or the player directory</p> * @param savePublic <p>Whether to save the book in the public directory or the player directory</p>
* @param command <p>The command executed to trigger this method</p> * @param command <p>The command executed to trigger this method</p>
* @return <p>True if a book was saved successfully</p>
*/ */
protected boolean saveHeldBook(@NotNull CommandSender sender, @NotNull String[] arguments, boolean savePublic, protected void saveHeldBook(@NotNull CommandSender sender, @NotNull String[] arguments, boolean savePublic,
@NotNull String command) { @NotNull String command) {
if (!(sender instanceof Player player)) { if (!(sender instanceof Player player)) {
new FormatBuilder(Translatable.ERROR_PLAYER_ONLY).error(sender); new FormatBuilder(Translatable.ERROR_PLAYER_ONLY).error(sender);
return true; return;
} }
ItemStack heldBook = InventoryUtil.getHeldBook(player); ItemStack heldBook = InventoryUtil.getHeldBook(player);
@@ -62,7 +62,6 @@ public class CommandSave implements TabExecutor {
} else { } else {
new FormatBuilder(Translatable.ERROR_NOT_HOLDING_ANY_BOOK).error(sender); new FormatBuilder(Translatable.ERROR_NOT_HOLDING_ANY_BOOK).error(sender);
} }
return true;
} }
/** /**

View File

@@ -13,7 +13,8 @@ public class CommandSavePublic extends CommandSave implements TabExecutor {
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
@NotNull String[] arguments) { @NotNull String[] arguments) {
return saveHeldBook(sender, arguments, true, label); saveHeldBook(sender, arguments, true, label);
return true;
} }
} }

View File

@@ -62,7 +62,8 @@ public class CommandSetBookPrice implements TabExecutor {
if (arguments[0].equalsIgnoreCase("item")) { if (arguments[0].equalsIgnoreCase("item")) {
return setItemPrice(sender, price); return setItemPrice(sender, price);
} else if (arguments[0].equalsIgnoreCase(StaticMessage.COST_ECONOMY.toString())) { } else if (arguments[0].equalsIgnoreCase(StaticMessage.COST_ECONOMY.toString())) {
return setEconomyPrice(sender, price); setEconomyPrice(sender, price);
return true;
} else { } else {
new FormatBuilder(CostMessage.ERROR_COST_INVALID_TYPE).error(sender); new FormatBuilder(CostMessage.ERROR_COST_INVALID_TYPE).error(sender);
return false; return false;
@@ -123,9 +124,8 @@ public class CommandSetBookPrice implements TabExecutor {
* *
* @param sender <p>The sender of the command</p> * @param sender <p>The sender of the command</p>
* @param price <p>The new price</p> * @param price <p>The new price</p>
* @return <p>True if the price was changed successfully</p>
*/ */
private boolean setEconomyPrice(@NotNull CommandSender sender, double price) { private void setEconomyPrice(@NotNull CommandSender sender, double price) {
EconomyManager economyManager = BooksWithoutBorders.getConfiguration().getEconomyManager(); EconomyManager economyManager = BooksWithoutBorders.getConfiguration().getEconomyManager();
if (economyManager.getEconomy() != null) { if (economyManager.getEconomy() != null) {
BwBConfig config = BooksWithoutBorders.getConfiguration(); BwBConfig config = BooksWithoutBorders.getConfiguration();
@@ -141,7 +141,6 @@ public class CommandSetBookPrice implements TabExecutor {
} else { } else {
new FormatBuilder(StaticMessage.EXCEPTION_VAULT_PRICE_NOT_CHANGED.toString()).error(sender); new FormatBuilder(StaticMessage.EXCEPTION_VAULT_PRICE_NOT_CHANGED.toString()).error(sender);
} }
return true;
} }
@Override @Override

View File

@@ -50,6 +50,7 @@ public enum StaticMessage {
EXCEPTION_GET_HELD_BOOK_INVALID_MATERIAL("Invalid required material specified for method"), EXCEPTION_GET_HELD_BOOK_INVALID_MATERIAL("Invalid required material specified for method"),
EXCEPTION_ITEM_SLOT_INVALID("Attempting to get item from an invalid item slot"), EXCEPTION_ITEM_SLOT_INVALID("Attempting to get item from an invalid item slot"),
/** /**
* The cost type used to specify economy * The cost type used to specify economy
*/ */

View File

@@ -17,8 +17,6 @@ public enum Placeholder implements TranslatableMessage {
COST, COST,
TITLE, TITLE,
DISPLAY_NAME, DISPLAY_NAME,
LINE,
PASSWORD,
COMMAND, COMMAND,
EXCEPTION, EXCEPTION,
PATH, PATH,

View File

@@ -28,21 +28,6 @@ public enum SignText implements TranslatableMessage {
*/ */
SIGN_GIVE, SIGN_GIVE,
/**
* The format for displaying the password on the sign
*/
SIGN_PASSWORD,
/**
* The format for marking a sign line as invalid
*/
SIGN_INVALID,
/**
* The format for marking a sign line as valid
*/
SIGN_VALID,
/** /**
* The error displayed when a player creates an invalid BwB sign * The error displayed when a player creates an invalid BwB sign
*/ */

View File

@@ -344,11 +344,6 @@ public enum Translatable implements TranslatableMessage {
*/ */
ERROR_BOOK_NOT_FOUND, ERROR_BOOK_NOT_FOUND,
/**
* The error displayed if attempting to list books while no books have been saved
*/
ERROR_NO_BOOKS_TO_LIST,
/** /**
* The error displayed if attempting to decrypt a group encrypted book without the necessary permissions * The error displayed if attempting to decrypt a group encrypted book without the necessary permissions
*/ */
@@ -374,11 +369,6 @@ public enum Translatable implements TranslatableMessage {
*/ */
ERROR_MIGRATION_BOOK_FAILED, ERROR_MIGRATION_BOOK_FAILED,
/**
* The error displayed when an unrecognized book directory is encountered
*/
ERROR_BOOK_DIRECTORY_UNKNOWN,
/** /**
* The error displayed when unable to get blank book metadata from the item factory * The error displayed when unable to get blank book metadata from the item factory
*/ */

View File

@@ -1,6 +1,7 @@
package net.knarcraft.bookswithoutborders.encryption; package net.knarcraft.bookswithoutborders.encryption;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* This enum represents the different available encryption styles * This enum represents the different available encryption styles
@@ -65,14 +66,14 @@ public enum EncryptionStyle {
* @param name <p>The name of the encryption style</p> * @param name <p>The name of the encryption style</p>
* @return <p>An encryption style or null if no match is found</p> * @return <p>An encryption style or null if no match is found</p>
*/ */
@NotNull @Nullable
public static EncryptionStyle getFromString(@NotNull String name) { public static EncryptionStyle getFromString(@NotNull String name) {
for (EncryptionStyle style : EncryptionStyle.values()) { for (EncryptionStyle style : EncryptionStyle.values()) {
if (style.name.equalsIgnoreCase(name)) { if (style.name.equalsIgnoreCase(name)) {
return style; return style;
} }
} }
return AES; return null;
} }
@Override @Override

View File

@@ -1,6 +1,5 @@
package net.knarcraft.bookswithoutborders.listener; package net.knarcraft.bookswithoutborders.listener;
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
import net.knarcraft.bookswithoutborders.config.Permission; import net.knarcraft.bookswithoutborders.config.Permission;
import net.knarcraft.bookswithoutborders.config.translation.GiveMessage; import net.knarcraft.bookswithoutborders.config.translation.GiveMessage;
import net.knarcraft.bookswithoutborders.config.translation.Placeholder; import net.knarcraft.bookswithoutborders.config.translation.Placeholder;
@@ -13,7 +12,6 @@ import net.knarcraft.bookswithoutborders.state.SignType;
import net.knarcraft.bookswithoutborders.utility.BookFileUtil; import net.knarcraft.bookswithoutborders.utility.BookFileUtil;
import net.knarcraft.bookswithoutborders.utility.BookLoaderUtil; import net.knarcraft.bookswithoutborders.utility.BookLoaderUtil;
import net.knarcraft.bookswithoutborders.utility.EncryptedBookUtil; import net.knarcraft.bookswithoutborders.utility.EncryptedBookUtil;
import net.knarcraft.bookswithoutborders.utility.InputCleaningUtil;
import net.knarcraft.knarlib.formatting.FormatBuilder; import net.knarcraft.knarlib.formatting.FormatBuilder;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
@@ -34,13 +32,18 @@ import org.bukkit.inventory.PlayerInventory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import static net.knarcraft.bookswithoutborders.utility.BookFileUtil.isBookListIndex; import java.util.Objects;
/** /**
* A listener for relevant sign events such as clicking a decryption sign * A listener for relevant sign events such as clicking a decryption sign
*/ */
public class SignEventListener implements Listener { public class SignEventListener implements Listener {
private final static ChatColor ERROR_COLOR = ChatColor.DARK_RED;
private final static ChatColor SUCCESS_COLOR = ChatColor.DARK_GREEN;
private final static ChatColor META_COLOR = ChatColor.DARK_BLUE;
private final static ChatColor PASSWORD_COLOR = ChatColor.MAGIC;
@EventHandler @EventHandler
public void onSignChange(@NotNull SignChangeEvent event) { public void onSignChange(@NotNull SignChangeEvent event) {
if (event.isCancelled()) { if (event.isCancelled()) {
@@ -51,34 +54,19 @@ public class SignEventListener implements Listener {
Player player = event.getPlayer(); Player player = event.getPlayer();
//Check if creating a Books Without Borders Sign and if the player has permission //Check if creating a Books Without Borders Sign and if the player has permission
if (SignType.fromString(lines[0]) != SignType.BOOKS_WITHOUT_BORDERS || if (getSignType(lines[0]) != SignType.BOOKS_WITHOUT_BORDERS ||
!player.hasPermission(Permission.SIGNS.toString())) { !player.hasPermission(Permission.SIGNS.toString())) {
return; return;
} }
//Mark the sign as active // Check and mark the sign
event.setLine(0, new FormatBuilder(SignText.SIGN_HEADER).color().toString()); if (isSignInvalid(lines, true)) {
//Check if the sign is of a valid type
SignType type = SignType.fromString(lines[1]);
if (type == null || lines[2].trim().isEmpty()) {
//Mark the second line as invalid
event.setLine(1, new FormatBuilder(SignText.SIGN_INVALID).replace(Placeholder.LINE, lines[1]).color().toString());
new FormatBuilder(SignText.ERROR_SIGN_INVALID).error(player); new FormatBuilder(SignText.ERROR_SIGN_INVALID).error(player);
return;
} }
//Mark the second line as valid // Update any changed lines
event.setLine(1, new FormatBuilder(SignText.SIGN_VALID).replace(Placeholder.LINE, lines[1]).color().toString()); for (int i = 0; i < lines.length; i++) {
lines = event.getLines(); event.setLine(i, lines[i]);
//Mark valid encryption/decryption sign
if (type == SignType.GIVE) {
//Generate book giving sign
generateGiveSign(event, lines, player);
} else {
event.setLine(2, new FormatBuilder(SignText.SIGN_PASSWORD).replace(Placeholder.PASSWORD, lines[2]).color().toString());
event.setLine(3, new FormatBuilder(SignText.SIGN_VALID).replace(Placeholder.LINE, lines[3]).color().toString());
} }
} }
@@ -102,6 +90,11 @@ public class SignEventListener implements Listener {
return; return;
} }
// Return if not a valid sign
if (isSignInvalid(((Sign) event.getClickedBlock().getState()).getSide(Side.FRONT).getLines(), false)) {
return;
}
//The player right-clicked a sign //The player right-clicked a sign
checkSign(event, (Sign) event.getClickedBlock().getState(), heldItemType, hand); checkSign(event, (Sign) event.getClickedBlock().getState(), heldItemType, hand);
} }
@@ -117,22 +110,18 @@ public class SignEventListener implements Listener {
private void checkSign(@NotNull PlayerInteractEvent event, @NotNull Sign sign, @NotNull Material heldItemType, private void checkSign(@NotNull PlayerInteractEvent event, @NotNull Sign sign, @NotNull Material heldItemType,
@NotNull EquipmentSlot hand) { @NotNull EquipmentSlot hand) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (SignType.fromString(sign.getSide(Side.FRONT).getLine(0)) != SignType.BOOKS_WITHOUT_BORDERS) {
return;
}
event.setUseItemInHand(Event.Result.DENY); event.setUseItemInHand(Event.Result.DENY);
event.setCancelled(true); event.setCancelled(true);
SignType signType = SignType.fromString(sign.getSide(Side.FRONT).getLine(1)); SignSide front = sign.getSide(Side.FRONT);
SignType signType = getSignType(front.getLine(1));
if (signType == SignType.ENCRYPT) { if (signType == SignType.ENCRYPT) {
encryptHeldBookUsingSign(sign, heldItemType, player, hand); encryptHeldBookUsingSign(sign, heldItemType, player, hand);
} else if (signType == SignType.DECRYPT) { } else if (signType == SignType.DECRYPT) {
decryptHeldBookUsingSign(sign, heldItemType, player, hand); decryptHeldBookUsingSign(sign, heldItemType, player, hand);
} else if (signType == SignType.GIVE && getSignLine2Color(sign) == ChatColor.DARK_GREEN) { } else if (signType == SignType.GIVE) {
giveBook(sign, player); giveBook(sign, player);
} else { } else {
SignSide front = sign.getSide(Side.FRONT);
new FormatBuilder(SignText.ERROR_SIGN_COMMAND_INVALID).replace(Placeholder.ACTION, front.getLine(1)). new FormatBuilder(SignText.ERROR_SIGN_COMMAND_INVALID).replace(Placeholder.ACTION, front.getLine(1)).
replace(Placeholder.DATA, front.getLine(2)).error(player); replace(Placeholder.DATA, front.getLine(2)).error(player);
} }
@@ -156,12 +145,11 @@ public class SignEventListener implements Listener {
player.closeInventory(); player.closeInventory();
//Converts user supplied key into integer form //Converts user supplied key into integer form
String lineText = InputCleaningUtil.stripColor(sign.getSide(Side.FRONT).getLine(2)); String password = getPassword(sign.getSide(Side.FRONT).getLines());
ItemStack book = EncryptedBookUtil.loadEncryptedBook(player, password, false, false);
ItemStack book = EncryptedBookUtil.loadEncryptedBook(player, lineText, false, false);
if (book == null) { if (book == null) {
book = EncryptedBookUtil.loadEncryptedBookLegacy(player, lineText, false); book = EncryptedBookUtil.loadEncryptedBookLegacy(player, password, false);
} }
if (book != null) { if (book != null) {
@@ -170,63 +158,6 @@ public class SignEventListener implements Listener {
} }
} }
/**
* Gets the color of a line on a sign
*
* @param sign <p>The sign to check</p>
* @return <p>The color of the sign</p>
*/
@Nullable
private ChatColor getSignLine2Color(@NotNull Sign sign) {
String line = sign.getSide(Side.FRONT).getLine(2);
if (!InputCleaningUtil.stripColor(line).equals(line)) {
return ChatColor.getByChar(sign.getSide(Side.FRONT).getLine(2).substring(1, 2).charAt(0));
} else {
return null;
}
}
/**
* Changes an edited sign into a sign to give books
*
* @param event <p>The event caused by changing the sign</p>
* @param lines <p>The lines on the sign</p>
* @param player <p>The player which edited the sign</p>
*/
private void generateGiveSign(@NotNull SignChangeEvent event, @NotNull String[] lines,
@NotNull Player player) {
//Tests if a full file name has been supplied and points to an actual file
String signFile = lines[2] + lines[3];
if (BookFileUtil.getFile(BookDirectory.PUBLIC, null, signFile) != null) {
markGiveSignValidity(event, true);
return;
} else {
if (isBookListIndex(lines[2])) {
BooksWithoutBorders.updateBooks(player, true);
markGiveSignValidity(event, true);
return;
}
}
markGiveSignValidity(event, false);
}
/**
* Marks a give sign as valid or invalid
*
* @param event <p>The event causing the creation of the give sign</p>
* @param isValid <p>Whether the created sign is valid</p>
*/
private void markGiveSignValidity(@NotNull SignChangeEvent event, boolean isValid) {
String[] lines = event.getLines();
if (isValid) {
event.setLine(2, ChatColor.DARK_GREEN + lines[2]);
event.setLine(3, ChatColor.DARK_GREEN + lines[3]);
} else {
event.setLine(2, ChatColor.DARK_RED + lines[2]);
event.setLine(3, ChatColor.DARK_RED + lines[3]);
}
}
/** /**
* Encrypts and replaces the player's used book * Encrypts and replaces the player's used book
* *
@@ -237,15 +168,15 @@ public class SignEventListener implements Listener {
*/ */
private void encryptHeldBookUsingSign(@NotNull Sign sign, @NotNull Material heldItemType, @NotNull Player player, private void encryptHeldBookUsingSign(@NotNull Sign sign, @NotNull Material heldItemType, @NotNull Player player,
@NotNull EquipmentSlot hand) { @NotNull EquipmentSlot hand) {
ItemStack eBook;
String[] lines = sign.getSide(Side.FRONT).getLines(); String[] lines = sign.getSide(Side.FRONT).getLines();
if (heldItemType == Material.WRITTEN_BOOK) { if (heldItemType != Material.WRITTEN_BOOK) {
player.closeInventory(); return;
eBook = EncryptedBookUtil.encryptBook(player, ItemSlot.fromEquipmentSlot(hand), InputCleaningUtil.stripColor(lines[2]), }
EncryptionStyle.getFromString(InputCleaningUtil.stripColor(lines[3])), false); player.closeInventory();
if (eBook != null) { ItemStack eBook = EncryptedBookUtil.encryptBook(player, ItemSlot.fromEquipmentSlot(hand), getPassword(lines),
player.getInventory().setItem(hand, eBook); getEncryptionStyle(lines), false);
} if (eBook != null) {
player.getInventory().setItem(hand, eBook);
} }
} }
@@ -256,23 +187,12 @@ public class SignEventListener implements Listener {
* @param player <p>The player which clicked the sign</p> * @param player <p>The player which clicked the sign</p>
*/ */
private void giveBook(@NotNull Sign sign, @NotNull Player player) { private void giveBook(@NotNull Sign sign, @NotNull Player player) {
String fileName = InputCleaningUtil.stripColor(sign.getSide(Side.FRONT).getLine(2)); String fileName = getBookName(sign.getSide(Side.FRONT).getLines());
boolean isLoadListNumber = false; if (fileName.isBlank()) {
new FormatBuilder(GiveMessage.ERROR_GIVE_LOAD_FAILED).error(player);
try { return;
Integer.parseInt(fileName);
isLoadListNumber = true;
} catch (NumberFormatException ignored) {
} }
//Add the third line to the second line for the full filename
String thirdLine = sign.getSide(Side.FRONT).getLine(3);
if (!isLoadListNumber && thirdLine.length() >= 2) {
fileName += InputCleaningUtil.stripColor(thirdLine);
}
ItemStack newBook = BookLoaderUtil.loadBook(player, fileName, true, BookDirectory.PUBLIC, 1); ItemStack newBook = BookLoaderUtil.loadBook(player, fileName, true, BookDirectory.PUBLIC, 1);
if (newBook != null) { if (newBook != null) {
player.getInventory().addItem(newBook); player.getInventory().addItem(newBook);
new FormatBuilder(SignText.SUCCESS_SIGN_GIVE).success(player); new FormatBuilder(SignText.SUCCESS_SIGN_GIVE).success(player);
@@ -281,4 +201,185 @@ public class SignEventListener implements Listener {
} }
} }
/**
* Checks whether the given sign lines belong to a valid sign
*
* @param lines <p>The lines to verify</p>
* @param markSign <p>Whether to mark the sign's validity after verifying</p>
* @return <p>True if the lines belong to a valid sign</p>
*/
private boolean isSignInvalid(@NotNull String[] lines, boolean markSign) {
// Check and optionally mark the [BwB] header
if (getSignType(lines[0]) != SignType.BOOKS_WITHOUT_BORDERS) {
if (markSign) {
lines[0] = ERROR_COLOR + lines[0];
}
return true;
} else if (markSign) {
lines[0] = SUCCESS_COLOR + lines[0];
}
// Check and optionally mark the sign type
if (lines[1].startsWith(ERROR_COLOR.toString())) {
return true;
}
SignType type = getSignType(lines[1]);
if (type == null || type == SignType.BOOKS_WITHOUT_BORDERS) {
if (markSign) {
lines[1] = ERROR_COLOR + lines[1];
}
return true;
} else if (markSign) {
lines[1] = META_COLOR + lines[1];
}
// Check and optionally mark
if (type == SignType.GIVE) {
return !isValidBook(lines, markSign);
} else if (type == SignType.DECRYPT || type == SignType.ENCRYPT) {
return !isValidPassword(lines, markSign);
}
throw new IllegalStateException();
}
/**
* Gets the sign type from the given sign line
*
* @param line <p>The line to get sign type from</p>
* @return <p>The sign type</p>
*/
@Nullable
private SignType getSignType(@NotNull String line) {
return SignType.fromString(getCleanLine(line));
}
/**
* Gets a cleaned valid sign line
*
* @param line <p>The line to clean initial color code from</p>
* @return <p>The cleaned line</p>
*/
@NotNull
private String getCleanLine(@NotNull String line) {
if (line.startsWith(META_COLOR.toString())) {
return line.replaceFirst(META_COLOR.toString(), "");
} else if (line.startsWith(SUCCESS_COLOR.toString())) {
return line.replaceFirst(SUCCESS_COLOR.toString(), "");
} else if (line.startsWith(PASSWORD_COLOR.toString())) {
return line.replaceFirst(PASSWORD_COLOR.toString(), "");
} else {
return line;
}
}
/**
* Checks whether the given sign lines specify a valid book
*
* @param lines <p>The lines to check</p>
* @param markSign <p>Whether to mark the sign's validity after verifying</p>
* @return <p>True if the lines point to a valid book</p>
*/
private boolean isValidBook(@NotNull String[] lines, boolean markSign) {
if (isInvalid(lines)) {
return false;
}
String bookName = getBookName(lines);
boolean isValid = BookFileUtil.getFile(BookDirectory.PUBLIC, null, bookName) != null ||
BookFileUtil.isBookListIndex(bookName);
if (markSign) {
if (isValid) {
markLine(lines, 2, SUCCESS_COLOR);
markLine(lines, 3, SUCCESS_COLOR);
} else {
markLine(lines, 2, ERROR_COLOR);
markLine(lines, 3, ERROR_COLOR);
}
}
return true;
}
/**
* Checks whether the given sign lines specify a valid password
*
* @param lines <p>The lines to check</p>
* @param markSign <p>Whether to mark the sign's validity after verifying</p>
* @return <p>True if the lines specify a valid password</p>
*/
private boolean isValidPassword(@NotNull String[] lines, boolean markSign) {
if (isInvalid(lines)) {
return false;
}
boolean isValid = !getPassword(lines).isBlank() && (lines[3].isBlank() ||
EncryptionStyle.getFromString(getCleanLine(lines[3])) != null);
if (markSign) {
if (isValid) {
markLine(lines, 2, PASSWORD_COLOR);
markLine(lines, 3, META_COLOR);
} else {
markLine(lines, 2, ERROR_COLOR);
markLine(lines, 3, ERROR_COLOR);
}
}
return isValid;
}
/**
* Gets the encryption style specified on the given sign
*
* @param lines <p>The lines to parse</p>
* @return <p>The encryption style</p>
*/
@NotNull
private EncryptionStyle getEncryptionStyle(@NotNull String[] lines) {
return Objects.requireNonNullElse(EncryptionStyle.getFromString(getCleanLine(lines[3])), EncryptionStyle.AES);
}
/**
* Gets the password specified on the given sign
*
* @param lines <p>The lines to parse</p>
* @return <p>The password</p>
*/
private String getPassword(@NotNull String[] lines) {
return getCleanLine(lines[2]);
}
/**
* Gets the book name specified in the given lines
*
* @param lines <p>The lines to parse</p>
* @return <p>The name of the book</p>
*/
@NotNull
private String getBookName(@NotNull String[] lines) {
String bookSpecifier = getCleanLine(lines[2]) + getCleanLine(lines[3]);
if (bookSpecifier.contains(":")) {
return bookSpecifier.split(":")[1];
} else {
return bookSpecifier;
}
}
/**
* Checks whether the specified sign lines are marked as invalid
*
* @param lines <p>The lines to check</p>
* @return <p>True if the lines belong to an invalid sign</p>
*/
private boolean isInvalid(@NotNull String[] lines) {
return lines[2].startsWith(ERROR_COLOR.toString()) || lines[3].startsWith(ERROR_COLOR.toString()) ||
lines[2].isBlank();
}
/**
* Marks the specified line by prepending the specified chat color
*
* @param lines <p>The lines to mark an index of</p>
* @param index <p>The index to mark</p>
* @param chatColor <p>The color to mark with</p>
*/
private void markLine(@NotNull String[] lines, int index, @NotNull ChatColor chatColor) {
lines[index] = chatColor + lines[index];
}
} }

View File

@@ -20,6 +20,7 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.logging.Level; import java.util.logging.Level;
/** /**
@@ -152,7 +153,8 @@ public final class BookFileReaderWriterUtil {
if (encryptionStyleName == null) { if (encryptionStyleName == null) {
return null; return null;
} }
EncryptionStyle encryptionStyle = EncryptionStyle.getFromString(encryptionStyleName); EncryptionStyle encryptionStyle = Objects.requireNonNullElse(EncryptionStyle.getFromString(encryptionStyleName),
EncryptionStyle.AES);
AESConfiguration aesConfiguration = null; AESConfiguration aesConfiguration = null;
if (encryptionStyle == EncryptionStyle.AES) { if (encryptionStyle == EncryptionStyle.AES) {

View File

@@ -38,6 +38,9 @@ public final class BookFileUtil {
* @return <p>True if the number is a book index</p> * @return <p>True if the number is a book index</p>
*/ */
public static boolean isBookListIndex(@NotNull String possibleIndex) { public static boolean isBookListIndex(@NotNull String possibleIndex) {
if (possibleIndex.isBlank()) {
return false;
}
File bookDirectory = new File(BooksWithoutBorders.getConfiguration().getBookFolder().replaceAll("[\\\\/]$", "")); File bookDirectory = new File(BooksWithoutBorders.getConfiguration().getBookFolder().replaceAll("[\\\\/]$", ""));
try { try {

View File

@@ -104,13 +104,11 @@ en:
An encrypted version of this book is already saved. An encrypted version of this book is already saved.
Please decrypt your previously encrypted copy first. Please decrypt your previously encrypted copy first.
ERROR_BOOK_NOT_FOUND: "Could not find a book to replace!" ERROR_BOOK_NOT_FOUND: "Could not find a book to replace!"
ERROR_NO_BOOKS_TO_LIST: "No books have been saved!"
ERROR_GROUP_DECRYPT_NO_PERMISSION: "You are not allowed to decrypt that book" ERROR_GROUP_DECRYPT_NO_PERMISSION: "You are not allowed to decrypt that book"
ERROR_GROUP_DECRYPT_NOT_FOUND: "Unable to find encrypted book" ERROR_GROUP_DECRYPT_NOT_FOUND: "Unable to find encrypted book"
ERROR_GROUP_DECRYPT_LOAD_FAILED: "Unable to load the unencrypted book!" ERROR_GROUP_DECRYPT_LOAD_FAILED: "Unable to load the unencrypted book!"
ERROR_MIGRATION_FAILED: "Failed to migrate all books" ERROR_MIGRATION_FAILED: "Failed to migrate all books"
ERROR_MIGRATION_BOOK_FAILED: "Failed to migrate book: {file} Cause: {exception}" ERROR_MIGRATION_BOOK_FAILED: "Failed to migrate book: {file} Cause: {exception}"
ERROR_BOOK_DIRECTORY_UNKNOWN: "Unrecognized book directory!"
ERROR_METADATA_CREATION_FAILED: "Unable to create blank book metadata!" ERROR_METADATA_CREATION_FAILED: "Unable to create blank book metadata!"
ERROR_LOAD_BOOK_EMPTY: "File was blank!!" ERROR_LOAD_BOOK_EMPTY: "File was blank!!"
ERROR_AUTHOR_ONLY: "You must be the author of this book to use this command!" ERROR_AUTHOR_ONLY: "You must be the author of this book to use this command!"
@@ -173,16 +171,16 @@ en:
# -----------------------------------------# # -----------------------------------------#
NEUTRAL_UNKNOWN_AUTHOR: "Unknown" NEUTRAL_UNKNOWN_AUTHOR: "Unknown"
NEUTRAL_UNKNOWN_TITLE: "Untitled" NEUTRAL_UNKNOWN_TITLE: "Untitled"
# ---------------------- # # --------------------------- #
# Sign text and messages # # Sign headers and specifiers #
# ---------------------- # # --------------------------- #
SIGN_HEADER: "&2[BwB]" SIGN_HEADER: "[BwB]"
SIGN_ENCRYPT: "[Encrypt]" SIGN_ENCRYPT: "[Encrypt]"
SIGN_DECRYPT: "[Decrypt]" SIGN_DECRYPT: "[Decrypt]"
SIGN_GIVE: "[Give]" SIGN_GIVE: "[Give]"
SIGN_PASSWORD: "&k{password}" # -------------- #
SIGN_INVALID: "&4{line}" # Sign responses #
SIGN_VALID: "&1{line}" # -------------- #
ERROR_SIGN_INVALID: "Invalid sign!" ERROR_SIGN_INVALID: "Invalid sign!"
ERROR_SIGN_COMMAND_INVALID: "Sign command {action} {data} is invalid" ERROR_SIGN_COMMAND_INVALID: "Sign command {action} {data} is invalid"
SUCCESS_SIGN_GIVE: "Received book!" SUCCESS_SIGN_GIVE: "Received book!"
@@ -202,8 +200,6 @@ en:
COST: "{cost}" COST: "{cost}"
TITLE: "{title}" TITLE: "{title}"
DISPLAY_NAME: "{displayName}" DISPLAY_NAME: "{displayName}"
LINE: "{line}"
PASSWORD: "{password}"
COMMAND: "{command}" COMMAND: "{command}"
EXCEPTION: "{exception}" EXCEPTION: "{exception}"
PATH: "{path}" PATH: "{path}"