Moves setlore and setbookprice command code to their own classes

This commit is contained in:
Kristian Knarvik 2021-08-30 22:08:55 +02:00
parent fbee4a90b0
commit 657c7e43fd
7 changed files with 234 additions and 126 deletions

View File

@ -7,7 +7,6 @@ import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -19,6 +18,8 @@ import net.knarcraft.bookswithoutborders.command.CommandDelete;
import net.knarcraft.bookswithoutborders.command.CommandEncrypt; import net.knarcraft.bookswithoutborders.command.CommandEncrypt;
import net.knarcraft.bookswithoutborders.command.CommandGive; import net.knarcraft.bookswithoutborders.command.CommandGive;
import net.knarcraft.bookswithoutborders.command.CommandGroupEncrypt; import net.knarcraft.bookswithoutborders.command.CommandGroupEncrypt;
import net.knarcraft.bookswithoutborders.command.CommandSetBookPrice;
import net.knarcraft.bookswithoutborders.command.CommandSetLore;
import net.knarcraft.bookswithoutborders.command.CommandUnSign; import net.knarcraft.bookswithoutborders.command.CommandUnSign;
import net.knarcraft.bookswithoutborders.command.GiveTabCompleter; import net.knarcraft.bookswithoutborders.command.GiveTabCompleter;
import net.knarcraft.bookswithoutborders.utility.BookFormatter; import net.knarcraft.bookswithoutborders.utility.BookFormatter;
@ -49,14 +50,14 @@ public class BooksWithoutBorders extends JavaPlugin {
protected static int bookDuplicateLimit; protected static int bookDuplicateLimit;
//The separating string between the book title and the book author //The separating string between the book title and the book author
public static String titleAuthorSeparator; public static String titleAuthorSeparator;
protected static String loreSep; public static String loreSeparator;
public static final String SLASH = System.getProperty("file.separator"); public static final String SLASH = System.getProperty("file.separator");
protected static List<String> firstBooks; protected static List<String> firstBooks;
protected static String welcomeMessage; protected static String welcomeMessage;
protected static List<String> existingPlayers; protected static List<String> existingPlayers;
protected static Economy eco; public static Economy eco;
protected static Material bookPriceType = null; public static Material bookPriceType = null;
protected static double bookPriceQuantity; public static double bookPriceQuantity;
public static boolean authorOnlyCopy; public static boolean authorOnlyCopy;
protected static boolean useYml; protected static boolean useYml;
public static boolean adminDecrypt; public static boolean adminDecrypt;
@ -96,6 +97,8 @@ public class BooksWithoutBorders extends JavaPlugin {
this.getCommand("copy").setExecutor(new CommandCopy(this)); this.getCommand("copy").setExecutor(new CommandCopy(this));
this.getCommand("unsign").setExecutor(new CommandUnSign(this)); this.getCommand("unsign").setExecutor(new CommandUnSign(this));
this.getCommand("encrypt").setExecutor(new CommandEncrypt(this)); this.getCommand("encrypt").setExecutor(new CommandEncrypt(this));
this.getCommand("setbookprice").setExecutor(new CommandSetBookPrice(this));
this.getCommand("setlore").setExecutor(new CommandSetLore());
} }
protected boolean init() { protected boolean init() {
@ -117,16 +120,18 @@ public class BooksWithoutBorders extends JavaPlugin {
this.getConfig().set("Options.Save_Books_in_Yaml_Format", useYml); this.getConfig().set("Options.Save_Books_in_Yaml_Format", useYml);
this.getConfig().set("Options.Max_Number_of_Duplicates", bookDuplicateLimit); this.getConfig().set("Options.Max_Number_of_Duplicates", bookDuplicateLimit);
this.getConfig().set("Options.Title-Author_Separator", titleAuthorSeparator); this.getConfig().set("Options.Title-Author_Separator", titleAuthorSeparator);
this.getConfig().set("Options.Lore_line_separator", loreSep); this.getConfig().set("Options.Lore_line_separator", loreSeparator);
this.getConfig().set("Options.Books_for_new_players", firstBooks); this.getConfig().set("Options.Books_for_new_players", firstBooks);
this.getConfig().set("Options.Message_for_new_players", welcomeMessage); this.getConfig().set("Options.Message_for_new_players", welcomeMessage);
if (bookPriceType != null) { if (bookPriceType != null) {
if (bookPriceType != Material.AIR) if (bookPriceType != Material.AIR) {
this.getConfig().set("Options.Price_to_create_book.Item_type", bookPriceType.toString()); this.getConfig().set("Options.Price_to_create_book.Item_type", bookPriceType.toString());
else } else {
this.getConfig().set("Options.Price_to_create_book.Item_type", "Economy"); this.getConfig().set("Options.Price_to_create_book.Item_type", "Economy");
} else }
} else {
this.getConfig().set("Options.Price_to_create_book.Item_type", "Item type name"); this.getConfig().set("Options.Price_to_create_book.Item_type", "Item type name");
}
this.getConfig().set("Options.Price_to_create_book.Required_quantity", bookPriceQuantity); this.getConfig().set("Options.Price_to_create_book.Required_quantity", bookPriceQuantity);
this.getConfig().set("Options.Admin_Auto_Decrypt", adminDecrypt); this.getConfig().set("Options.Admin_Auto_Decrypt", adminDecrypt);
this.getConfig().set("Options.Author_Only_Copy", authorOnlyCopy); this.getConfig().set("Options.Author_Only_Copy", authorOnlyCopy);
@ -183,7 +188,7 @@ public class BooksWithoutBorders extends JavaPlugin {
useYml = this.getConfig().getBoolean("Options.Save_Books_in_Yaml_Format", true); useYml = this.getConfig().getBoolean("Options.Save_Books_in_Yaml_Format", true);
bookDuplicateLimit = this.getConfig().getInt("Options.Max_Number_of_Duplicates", 5); bookDuplicateLimit = this.getConfig().getInt("Options.Max_Number_of_Duplicates", 5);
titleAuthorSeparator = this.getConfig().getString("Options.Title-Author_Separator", ","); titleAuthorSeparator = this.getConfig().getString("Options.Title-Author_Separator", ",");
loreSep = this.getConfig().getString("Options.Lore_line_separator", "~"); loreSeparator = this.getConfig().getString("Options.Lore_line_separator", "~");
adminDecrypt = this.getConfig().getBoolean("Options.Admin_Auto_Decrypt", false); adminDecrypt = this.getConfig().getBoolean("Options.Admin_Auto_Decrypt", false);
authorOnlyCopy = this.getConfig().getBoolean("Options.Author_Only_Copy", false); authorOnlyCopy = this.getConfig().getBoolean("Options.Author_Only_Copy", false);
@ -229,7 +234,7 @@ public class BooksWithoutBorders extends JavaPlugin {
return true; return true;
} }
private boolean setupEconomy() { public boolean setupEconomy() {
Plugin plugin = getServer().getPluginManager().getPlugin("Vault"); Plugin plugin = getServer().getPluginManager().getPlugin("Vault");
if (plugin != null) { if (plugin != null) {
@ -643,41 +648,6 @@ public class BooksWithoutBorders extends JavaPlugin {
sendSuccessMessage(sender, "Book author set to " + author + "!"); sendSuccessMessage(sender, "Book author set to " + author + "!");
return true; return true;
} }
if (args[0].equalsIgnoreCase("setLore")) {
if (!sender.hasPermission("bookswithoutborders.setlore")) {
sendErrorMessage(sender, " You don't have permission to use this command!");
return false;
}
if (args.length < 2) {
sendErrorMessage(sender, "Missing a command argument!");
return false;
}
if (((Player) sender).getItemInHand().getType() == Material.AIR) {
sendErrorMessage(sender, "Must be holding an item to set lore!");
return false;
}
StringBuilder rawlore = new StringBuilder();
for (int x = 1; x < args.length; x++) {
if (x == 1)
rawlore.append(args[x]);
else
rawlore.append(" ").append(args[x]);
}
rawlore = new StringBuilder(ChatColor.translateAlternateColorCodes('&', rawlore.toString()));
String[] lores = rawlore.toString().split(loreSep);
List<String> nulore = new ArrayList<>(Arrays.asList(lores));
ItemMeta meta = ((Player) sender).getItemInHand().getItemMeta();
meta.setLore(nulore);
((Player) sender).getItemInHand().setItemMeta(meta);
sendSuccessMessage(sender, "Added lore to item!");
return true;
}
} }
if (args[0].equalsIgnoreCase("givePublic")) { if (args[0].equalsIgnoreCase("givePublic")) {
@ -774,74 +744,6 @@ public class BooksWithoutBorders extends JavaPlugin {
} }
} }
if (args[0].equalsIgnoreCase("setBookPrice")) {
if (!sender.hasPermission("bookswithoutborders.setbookprice")) {
sendErrorMessage(sender, " You don't have permission to use this command!");
return false;
}
if (args.length == 1) {
bookPriceType = null;
bookPriceQuantity = 0;
this.getConfig().set("Options.Price_to_create_book.Item_type", "Item type name");
this.getConfig().set("Options.Price_to_create_book.Required_quantity", bookPriceQuantity);
this.saveConfig();
sendSuccessMessage(sender, "Price to create books removed!");
return true;
}
if (args.length < 3) {
sendErrorMessage(sender, "[Item/Eco] and [quantity] must be specified!");
return false;
}
if (!args[1].equalsIgnoreCase("Item") && !args[1].equalsIgnoreCase("Eco")) {
sendErrorMessage(sender, "Price type must be \"Item\" or \"Eco\"!");
return false;
}
try {
if (Double.parseDouble(args[2]) <= 0) {
sendErrorMessage(sender, "[quantity] must be greater than 0!");
return false;
}
if (args[1].equalsIgnoreCase("Item")) {
if (((Player) sender).getItemInHand().getType() == Material.AIR) {
sendErrorMessage(sender, "Must be holding an item to set an [Item] price!");
return false;
}
bookPriceType = ((Player) sender).getItemInHand().getType();
bookPriceQuantity = Double.parseDouble(args[2]);
this.getConfig().set("Options.Price_to_create_book.Item_type", bookPriceType.toString());
this.getConfig().set("Options.Price_to_create_book.Required_quantity", bookPriceQuantity);
this.saveConfig();
sendSuccessMessage(sender, "Book creation price set to " + (int) bookPriceQuantity + " " + bookPriceType.toString() + "(s)!");
return true;
} else if (args[1].equalsIgnoreCase("Eco")) {
if (setupEconomy()) {
bookPriceQuantity = Double.parseDouble(args[2]);
bookPriceType = Material.AIR;
this.getConfig().set("Options.Price_to_create_book.Item_type", "Economy");
this.getConfig().set("Options.Price_to_create_book.Required_quantity", bookPriceQuantity);
this.saveConfig();
sendSuccessMessage(sender, "Book creation price set to " + eco.format(bookPriceQuantity) + "!");
return true;
} else {
sendErrorMessage(sender, "BooksWithoutBorders failed to hook into Vault! Book price not set!");
return false;
}
}
} catch (NumberFormatException e) {
sendErrorMessage(sender, "[quantity] must be a number!");
}
}
sendErrorMessage(sender, "Command not recognized! Use " + commandColor + "/BwB" + errorColor + " for more info!"); sendErrorMessage(sender, "Command not recognized! Use " + commandColor + "/BwB" + errorColor + " for more info!");
} }
return false; return false;
@ -1202,7 +1104,7 @@ public class BooksWithoutBorders extends JavaPlugin {
return true; return true;
} }
protected BookMeta groupESave(Player player, BookMeta book, String key, String groupName) { protected BookMeta groupESave(Player player, BookMeta bookMetadata, String key, String groupName) {
String path = bookFolder + "Encrypted" + SLASH + cleanString(groupName) + SLASH; String path = bookFolder + "Encrypted" + SLASH + cleanString(groupName) + SLASH;
File dirTest = new File(path); File dirTest = new File(path);
//Creates group dir //Creates group dir
@ -1218,23 +1120,24 @@ public class BooksWithoutBorders extends JavaPlugin {
} }
} }
//Creates file //Creates file
String fname = (!book.hasTitle()) ? "Untitled," + player.getName() : String fname = (!bookMetadata.hasTitle()) ? "Untitled," + player.getName() :
book.getTitle() + titleAuthorSeparator + book.getAuthor(); bookMetadata.getTitle() + titleAuthorSeparator + bookMetadata.getAuthor();
fname = cleanString(fname); fname = cleanString(fname);
fname = fixName(fname, false); fname = fixName(fname, false);
List<String> nuLore = new ArrayList<>(); List<String> nuLore = new ArrayList<>();
nuLore.add(ChatColor.GRAY + "[" + groupName + " encrypted]"); nuLore.add(ChatColor.GRAY + "[" + groupName + " encrypted]");
if (book.hasLore()) if (bookMetadata.hasLore()) {
nuLore.addAll(book.getLore()); nuLore.addAll(bookMetadata.getLore());
book.setLore(nuLore); }
bookMetadata.setLore(nuLore);
//Save file //Save file
File file = (useYml) ? new File(path + fname + ".yml") : new File(path + fname + ".txt"); File file = (useYml) ? new File(path + fname + ".yml") : new File(path + fname + ".txt");
if (!file.isFile()) { if (!file.isFile()) {
try { try {
bookToYml(path, fname, book); bookToYml(path, fname, bookMetadata);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
sendErrorMessage(player, "Group encrypted failed!"); sendErrorMessage(player, "Group encrypted failed!");
@ -1242,14 +1145,19 @@ public class BooksWithoutBorders extends JavaPlugin {
} }
} }
return book; return bookMetadata;
} }
public ItemStack eLoad(Player player, String key, boolean deleteEncryptedFile) { public ItemStack eLoad(Player player, String key, boolean deleteEncryptedFile) {
BookMeta book = (BookMeta) player.getItemInHand().getItemMeta(); ItemStack heldBook = InventoryHelper.getHeldBook(player);
BookMeta bookMetadata = (BookMeta) heldBook.getItemMeta();
String path = bookFolder + "Encrypted" + SLASH; String path = bookFolder + "Encrypted" + SLASH;
String fname = (!book.hasTitle()) ? "Untitled," + player.getName() : book.getTitle() + titleAuthorSeparator + book.getAuthor(); if (bookMetadata == null) {
return null;
}
String fname = (!bookMetadata.hasTitle()) ? "Untitled," + player.getName() : bookMetadata.getTitle() + titleAuthorSeparator + bookMetadata.getAuthor();
fname = "[" + key + "]" + fname; fname = "[" + key + "]" + fname;
fname = cleanString(fname); fname = cleanString(fname);
fname = fixName(fname, false); fname = fixName(fname, false);
@ -1264,7 +1172,7 @@ public class BooksWithoutBorders extends JavaPlugin {
} }
} else { } else {
try { try {
book = bookFromYml(file, book); bookMetadata = bookFromYml(file, bookMetadata);
} catch (Exception e) { } catch (Exception e) {
sendErrorMessage(player, "Decryption failed!"); sendErrorMessage(player, "Decryption failed!");
return null; return null;
@ -1284,7 +1192,7 @@ public class BooksWithoutBorders extends JavaPlugin {
} }
ItemStack newBook = new ItemStack(Material.WRITTEN_BOOK);//Book(book.getAuthor(), book.getTitle(), pages, 1, 387); ItemStack newBook = new ItemStack(Material.WRITTEN_BOOK);//Book(book.getAuthor(), book.getTitle(), pages, 1, 387);
newBook.setItemMeta(book); newBook.setItemMeta(bookMetadata);
newBook.setAmount(InventoryHelper.getHeldBook(player).getAmount()); newBook.setAmount(InventoryHelper.getHeldBook(player).getAmount());
return newBook; return newBook;
} }

View File

@ -11,6 +11,9 @@ import org.bukkit.inventory.meta.BookMeta;
import java.util.Objects; import java.util.Objects;
/**
* Command executor for the copy command
*/
public class CommandCopy implements CommandExecutor { public class CommandCopy implements CommandExecutor {
private final BooksWithoutBorders booksWithoutBorders; private final BooksWithoutBorders booksWithoutBorders;

View File

@ -6,6 +6,9 @@ import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
/**
* Command executor for the delete command
*/
public class CommandDelete implements CommandExecutor { public class CommandDelete implements CommandExecutor {
private final BooksWithoutBorders booksWithoutBorders; private final BooksWithoutBorders booksWithoutBorders;

View File

@ -12,6 +12,9 @@ import org.bukkit.inventory.meta.BookMeta;
import java.util.Objects; import java.util.Objects;
/**
* Command executor for the encrypt command
*/
public class CommandEncrypt implements CommandExecutor { public class CommandEncrypt implements CommandExecutor {
private final BooksWithoutBorders booksWithoutBorders; private final BooksWithoutBorders booksWithoutBorders;

View File

@ -1,12 +1,130 @@
package net.knarcraft.bookswithoutborders.command; package net.knarcraft.bookswithoutborders.command;
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
import net.knarcraft.bookswithoutborders.utility.InventoryHelper;
import org.bukkit.Material;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
/**
* Command executor for the set book price command
*/
public class CommandSetBookPrice implements CommandExecutor { public class CommandSetBookPrice implements CommandExecutor {
private final BooksWithoutBorders booksWithoutBorders;
public CommandSetBookPrice(BooksWithoutBorders booksWithoutBorders) {
this.booksWithoutBorders = booksWithoutBorders;
}
@Override @Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
//Clear the current price
if (args.length == 0) {
return clearItemPrice(sender);
}
//Warn about missing arguments
if (args.length < 2) {
BooksWithoutBorders.sendErrorMessage(sender, "[Item/Eco] and [quantity] must be specified!");
return false; return false;
} }
//Warn about invalid argument
if (!args[0].equalsIgnoreCase("Item") && !args[0].equalsIgnoreCase("Eco")) {
BooksWithoutBorders. sendErrorMessage(sender, "Price type must be \"Item\" or \"Eco\"!");
return false;
}
try {
double price = Double.parseDouble(args[1]);
if (price <= 0) {
BooksWithoutBorders.sendErrorMessage(sender, "[quantity] must be greater than 0!");
return false;
}
if (args[0].equalsIgnoreCase("Item")) {
return setItemPrice(sender, price);
} else if (args[0].equalsIgnoreCase("Eco")) {
return setEconomyPrice(sender, price);
}
} catch (NumberFormatException e) {
BooksWithoutBorders.sendErrorMessage(sender, "[quantity] must be a number!");
}
return false;
}
/**
* Removes the book price
* @param sender <p>The sender of the command</p>
* @return <p>True if the price was changed successfully</p>
*/
private boolean clearItemPrice(CommandSender sender) {
BooksWithoutBorders.bookPriceType = null;
BooksWithoutBorders.bookPriceQuantity = 0;
booksWithoutBorders.getConfig().set("Options.Price_to_create_book.Item_type", "Item type name");
booksWithoutBorders.getConfig().set("Options.Price_to_create_book.Required_quantity", BooksWithoutBorders.bookPriceQuantity);
booksWithoutBorders.saveConfig();
BooksWithoutBorders.sendSuccessMessage(sender, "Price to create books removed!");
return true;
}
/**
* Sets the book price to use items, and updates book price
* @param sender <p>The sender of the command</p>
* @param price <p>The new price</p>
* @return <p>True if the price was changed successfully</p>
*/
private boolean setItemPrice(CommandSender sender, double price) {
if (!(sender instanceof Player player)) {
BooksWithoutBorders.sendErrorMessage(sender, "[Item] price can only be used by a player!");
return false;
}
ItemStack heldItem = InventoryHelper.getHeldItem(player, true);
if (heldItem.getType() == Material.AIR) {
BooksWithoutBorders.sendErrorMessage(sender, "Must be holding an item to set an [Item] price!");
return false;
}
BooksWithoutBorders.bookPriceType = heldItem.getType();
BooksWithoutBorders.bookPriceQuantity = price;
booksWithoutBorders.getConfig().set("Options.Price_to_create_book.Item_type",
BooksWithoutBorders.bookPriceType.toString());
booksWithoutBorders.getConfig().set("Options.Price_to_create_book.Required_quantity",
BooksWithoutBorders.bookPriceQuantity);
booksWithoutBorders.saveConfig();
BooksWithoutBorders.sendSuccessMessage(sender, "Book creation price set to " +
(int) BooksWithoutBorders.bookPriceQuantity + " " + BooksWithoutBorders.bookPriceType.toString() + "(s)!");
return true;
}
/**
* Sets the book price to use economy, and updates book price
* @param sender <p>The sender of the command</p>
* @param price <p>The new price</p>
* @return <p>True if the price was changed successfully</p>
*/
private boolean setEconomyPrice(CommandSender sender, double price) {
if (booksWithoutBorders.setupEconomy()) {
BooksWithoutBorders.bookPriceQuantity = price;
BooksWithoutBorders.bookPriceType = Material.AIR;
booksWithoutBorders.getConfig().set("Options.Price_to_create_book.Item_type", "Economy");
booksWithoutBorders.getConfig().set("Options.Price_to_create_book.Required_quantity",
BooksWithoutBorders.bookPriceQuantity);
booksWithoutBorders.saveConfig();
BooksWithoutBorders.sendSuccessMessage(sender, "Book creation price set to " +
BooksWithoutBorders.eco.format(BooksWithoutBorders.bookPriceQuantity) + "!");
return true;
} else {
BooksWithoutBorders.sendErrorMessage(sender, "BooksWithoutBorders failed to hook into Vault! Book price not set!");
return false;
}
}
} }

View File

@ -0,0 +1,65 @@
package net.knarcraft.bookswithoutborders.command;
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
import net.knarcraft.bookswithoutborders.utility.InventoryHelper;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Command executor for the set lore command
*/
public class CommandSetLore implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
BooksWithoutBorders.sendErrorMessage(sender, "This command can only be used by a player!");
return false;
}
if (args.length < 1) {
BooksWithoutBorders.sendErrorMessage(player, "Missing a command argument!");
return false;
}
ItemStack heldItem = InventoryHelper.getHeldItem(player, true);
if (heldItem.getType() == Material.AIR) {
BooksWithoutBorders.sendErrorMessage(player, "Must be holding an item to set lore!");
return false;
}
//Treat all arguments as lore input
StringBuilder rawLore = new StringBuilder();
rawLore.append(args[0]);
for (int x = 1; x < args.length; x++) {
rawLore.append(" ").append(args[x]);
}
//Format lore
rawLore = new StringBuilder(ChatColor.translateAlternateColorCodes('&', rawLore.toString()));
String[] loreParts = rawLore.toString().split(BooksWithoutBorders.loreSeparator);
List<String> newLore = new ArrayList<>(Arrays.asList(loreParts));
//Update lore
ItemMeta meta = heldItem.getItemMeta();
if (meta == null) {
BooksWithoutBorders.sendErrorMessage(player, "Could not get metadata from the held item!");
return false;
}
meta.setLore(newLore);
heldItem.setItemMeta(meta);
BooksWithoutBorders.sendSuccessMessage(player, "Added lore to item!");
return true;
}
}

View File

@ -41,6 +41,14 @@ commands:
description: Encrypts the held book description: Encrypts the held book
usage: /<command> <key> [encryption style] usage: /<command> <key> [encryption style]
permission: bookswithoutborders.encrypt permission: bookswithoutborders.encrypt
setbookprice:
description: Sets the price for copying books to a money sum or the held item
usage: /<command> <item/eco> <quantity>
permission: bookswithoutborders.setbookprice
setlore:
description: Sets the lore of the held item
usage: /<command> <new lore>
permission: bookswithoutborders.setlore
permissions: permissions:
bookswithoutborders.admin: bookswithoutborders.admin:
description: Grants all permissions description: Grants all permissions