Adds a command for editing all options, and removes /setBookPrice #17
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:
59
README.md
59
README.md
@@ -62,35 +62,35 @@ Books without Borders has got your back!
|
||||
|
||||
An in-game description of available commands is available through the /bwb command.
|
||||
|
||||
| Command | Alias | Arguments | Permission | Description |
|
||||
|----------------------|---------------|----------------------------------------------------------------------------------|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| /addbooktitlepage | bwbTitlePage | \[page index] \[title~description] | bookswithoutborders.addtitlepage | Adds a blank page, title page or chapter page depending on input and whether the book is signed. The title author separator (default `~`) is used to separate the input into title,paragraph1,paragraph2,... |
|
||||
| /bookswithoutborders | bwb | None | | Displays information about commands (and permissions if the user has bookswithoutborders.admin) |
|
||||
| /clearbook | bwbClear | None | bookswithoutborders.clear | Removes all text from the held un-signed book |
|
||||
| /copybook | bwbCopy | \<# of copies> | bookswithoutborders.copy | Copies the book the player is holding |
|
||||
| /createbwbsign | bwbSign | \<give/encrypt/decrypt> \[book identifier/password] \[encryption style] | bookswithoutborders.signs | Creates a books without borders sign, as specified. This command is not restricted by the normal sign line text limit, and can load books with any name length for give signs. Encrypt and decrypts signs can be created manually just fine, but using this avoids manual formatting. |
|
||||
| /decryptbook | bwbDecrypt | \<key> | bookswithoutborders.decrypt | Decrypts the book the player is holding. "key" is required and MUST be IDENTICAL to the key used to encrypt the held book |
|
||||
| /deletebook | bwbDelete | \<file name or number> | bookswithoutborders.delete | Deletes the specified file in the player's directory |
|
||||
| /deletebookpage | bwbDeletePage | \<page> | bookswithoutborders.deletepage | Deletes one page from a book |
|
||||
| /deletepublicbook | bwbDeleteP | \<file name or number> | bookswithoutborders.admin | Same as deletebook, but deletes files in the public directory |
|
||||
| /encryptbook | bwbEncrypt | \<key> \[encryption style] | bookswithoutborders.encrypt | Encrypts the book the player is holding. "key" is required and can be any phrase or number excluding spaces. "style" is not required. Possible values are "dna", "substitution", "aes", "onetimepad" and "magic", unless real encryption is enabled, which limits available algorithms. |
|
||||
| /formatbook | bwbFormat | None | bookswithoutborders.format | Formats the held written book (converts color and formatting codes to the corresponding formatted text) |
|
||||
| /givebook | bwbGive | \<file name or number> \<playername> \[# of copies (num)] \[signed (true/false)] | bookswithoutborders.give | Gives the selected player a book from your personal directory |
|
||||
| /givepublicbook | bwbGiveP | \<file name or number> \<playername> \[# of copies (num)] \[signed (true/false)] | bookswithoutborders.givepublic | Same as givebook, but uses books from the public directory |
|
||||
| /groupencryptbook | bwbGEncrypt | \<group name> \<key> \[encryption style] | bookswithoutborders.groupencrypt | Makes an encrypted book that only players with the "bookswithoutborders.decrypt.<group>" permission can decrypt. It's always auto-decrypted, so the key only matters for scrambling the contents. |
|
||||
| /loadbook | bwbLoad | \<file name or number> \[# of copies] \[signed (true/false)] | bookswithoutborders.load | Creates a book from the specified file and gives it to the player. If no file is specified, a list of available files is returned. If true is specified, the book will be signed, if false it will be unsigned |
|
||||
| /loadpublicbook | bwbLoadP | \<file name or number> \[# of copies] \[signed (true/false)] | bookswithoutborders.loadpublic | Same as loadbook, but views files in the public directory |
|
||||
| /migratebooks | bwbMigrate | None | bookswithoutborders.admin | Migrates all txt books to yml, and fixes any incorrect filenames. |
|
||||
| /reload | bwbReload | None | bookswithoutborders.reload | Reloads BwB's configuration file |
|
||||
| /savebook | bwbSave | \[overwrite (true/false)] | bookswithoutborders.save | Saves the book the player is holding to a text file in a private directory. If true is specified, a book of the same name by the same author will be overwritten by the new book |
|
||||
| /savepublicbook | bwbSaveP | \[overwrite (true/false)] | bookswithoutborders.savepublic | Same as savebook, but saves files in the public directory |
|
||||
| /setbookauthor | bwbAuthor | \<author> | bookswithoutborders.setauthor | Sets the author of the book the player is holding |
|
||||
| /setbookgeneration | bwbGeneration | \<generation> | bookswithoutborders.setgeneration | Sets the generation of the held book (ORIGINAL, COPY_OF_ORIGINAL, COPY_OF_COPY, TATTERED) |
|
||||
| /setbookprice | bwbPrice | \<item/eco> \<quantity> | bookswithoutborders.setbookprice | Sets the per-book price to create a book via commands. If "Item", the item in the player's hand in the amount of \<quantity> will be the price. If "Eco", a Vault based economy will be used for price. If neither \<Item/Eco> nor \<quantity> are specified, the current price to create books will be removed. |
|
||||
| /setbookshelfdata | bwbShelfData | \<delete/name/lore> \text> \[more text] | bookswithoutborders.editbookshelf | Sets the name/lore for a bookshelf which is shown when peeking at its contents. |
|
||||
| /setlore | bwbLore | \<new lore> | bookswithoutborders.setlore | Sets the lore of the item the player is holding. Insert the lore_line_separator character to force a new line ("~" by default) |
|
||||
| /settitle | bwbTitle | \<title> \[title] ... \[setDisplayName (true/false)] | bookswithoutborders.settitle | Sets the title of the book or the display name of the item the player is holding. Add a true at the end (`/settitle some title true`) to set a book's display name instead of its title. |
|
||||
| /unsignbook | bwbUnsign | None | bookswithoutborders.unsign | Un-signs the book the player is holding |
|
||||
| Command | Alias | Arguments | Permission | Description |
|
||||
|----------------------|---------------|----------------------------------------------------------------------------------|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| /addbooktitlepage | bwbTitlePage | \[page index] \[title~description] | bookswithoutborders.addtitlepage | Adds a blank page, title page or chapter page depending on input and whether the book is signed. The title author separator (default `~`) is used to separate the input into title,paragraph1,paragraph2,... |
|
||||
| /bookswithoutborders | bwb | None | | Displays information about commands (and permissions if the user has bookswithoutborders.admin) |
|
||||
| /clearbook | bwbClear | None | bookswithoutborders.clear | Removes all text from the held un-signed book |
|
||||
| /copybook | bwbCopy | \<# of copies> | bookswithoutborders.copy | Copies the book the player is holding |
|
||||
| /createbwbsign | bwbSign | \<give/encrypt/decrypt> \[book identifier/password] \[encryption style] | bookswithoutborders.signs | Creates a books without borders sign, as specified. This command is not restricted by the normal sign line text limit, and can load books with any name length for give signs. Encrypt and decrypts signs can be created manually just fine, but using this avoids manual formatting. |
|
||||
| /decryptbook | bwbDecrypt | \<key> | bookswithoutborders.decrypt | Decrypts the book the player is holding. "key" is required and MUST be IDENTICAL to the key used to encrypt the held book |
|
||||
| /deletebook | bwbDelete | \<file name or number> | bookswithoutborders.delete | Deletes the specified file in the player's directory |
|
||||
| /deletebookpage | bwbDeletePage | \<page> | bookswithoutborders.deletepage | Deletes one page from a book |
|
||||
| /deletepublicbook | bwbDeleteP | \<file name or number> | bookswithoutborders.admin | Same as deletebook, but deletes files in the public directory |
|
||||
| /editbwbconfig | bwbConfig | \<option> \[value] \[value] ... | bookswithoutborders.admin | Edits a configuration option in the config file. Correct usage heavily depends on the specific value you want to change. |
|
||||
| /encryptbook | bwbEncrypt | \<key> \[encryption style] | bookswithoutborders.encrypt | Encrypts the book the player is holding. "key" is required and can be any phrase or number excluding spaces. "style" is not required. Possible values are "dna", "substitution", "aes", "onetimepad" and "magic", unless real encryption is enabled, which limits available algorithms. |
|
||||
| /formatbook | bwbFormat | None | bookswithoutborders.format | Formats the held written book (converts color and formatting codes to the corresponding formatted text) |
|
||||
| /givebook | bwbGive | \<file name or number> \<playername> \[# of copies (num)] \[signed (true/false)] | bookswithoutborders.give | Gives the selected player a book from your personal directory |
|
||||
| /givepublicbook | bwbGiveP | \<file name or number> \<playername> \[# of copies (num)] \[signed (true/false)] | bookswithoutborders.givepublic | Same as givebook, but uses books from the public directory |
|
||||
| /groupencryptbook | bwbGEncrypt | \<group name> \<key> \[encryption style] | bookswithoutborders.groupencrypt | Makes an encrypted book that only players with the "bookswithoutborders.decrypt.<group>" permission can decrypt. It's always auto-decrypted, so the key only matters for scrambling the contents. |
|
||||
| /loadbook | bwbLoad | \<file name or number> \[# of copies] \[signed (true/false)] | bookswithoutborders.load | Creates a book from the specified file and gives it to the player. If no file is specified, a list of available files is returned. If true is specified, the book will be signed, if false it will be unsigned |
|
||||
| /loadpublicbook | bwbLoadP | \<file name or number> \[# of copies] \[signed (true/false)] | bookswithoutborders.loadpublic | Same as loadbook, but views files in the public directory |
|
||||
| /migratebooks | bwbMigrate | None | bookswithoutborders.admin | Migrates all txt books to yml, and fixes any incorrect filenames. |
|
||||
| /reload | bwbReload | None | bookswithoutborders.reload | Reloads BwB's configuration file |
|
||||
| /savebook | bwbSave | \[overwrite (true/false)] | bookswithoutborders.save | Saves the book the player is holding to a text file in a private directory. If true is specified, a book of the same name by the same author will be overwritten by the new book |
|
||||
| /savepublicbook | bwbSaveP | \[overwrite (true/false)] | bookswithoutborders.savepublic | Same as savebook, but saves files in the public directory |
|
||||
| /setbookauthor | bwbAuthor | \<author> | bookswithoutborders.setauthor | Sets the author of the book the player is holding |
|
||||
| /setbookgeneration | bwbGeneration | \<generation> | bookswithoutborders.setgeneration | Sets the generation of the held book (ORIGINAL, COPY_OF_ORIGINAL, COPY_OF_COPY, TATTERED) |
|
||||
| /setbookshelfdata | bwbShelfData | \<delete/name/lore> \text> \[more text] | bookswithoutborders.editbookshelf | Sets the name/lore for a bookshelf which is shown when peeking at its contents. |
|
||||
| /setlore | bwbLore | \<new lore> | bookswithoutborders.setlore | Sets the lore of the item the player is holding. Insert the lore_line_separator character to force a new line ("~" by default) |
|
||||
| /settitle | bwbTitle | \<title> \[title] ... \[setDisplayName (true/false)] | bookswithoutborders.settitle | Sets the title of the book or the display name of the item the player is holding. Add a true at the end (`/settitle some title true`) to set a book's display name instead of its title. |
|
||||
| /unsignbook | bwbUnsign | None | bookswithoutborders.unsign | Un-signs the book the player is holding |
|
||||
|
||||
### Permissions:
|
||||
|
||||
@@ -131,7 +131,6 @@ An in-game description of available commands is available through the /bwb comma
|
||||
| bookswithoutborders.save | Allows a player to save books to their personal directory |
|
||||
| bookswithoutborders.savepublic | Allows player to save to the public directory |
|
||||
| bookswithoutborders.setauthor | Allows player to set the author of the currently held book |
|
||||
| bookswithoutborders.setbookprice | Allows player to set the cost of creating a book |
|
||||
| bookswithoutborders.setgeneration | Allows player to change the generation of a book (Original, Copy, Copy of Copy) |
|
||||
| bookswithoutborders.settitle | Allows player to set the title of the currently held book |
|
||||
| bookswithoutborders.signs | Allows player to create signs that give/encrypt/decrypt books |
|
||||
|
2
pom.xml
2
pom.xml
@@ -125,7 +125,7 @@
|
||||
<dependency>
|
||||
<groupId>net.knarcraft</groupId>
|
||||
<artifactId>knarlib</artifactId>
|
||||
<version>1.2.14</version>
|
||||
<version>1.2.14-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@@ -9,6 +9,7 @@ import net.knarcraft.bookswithoutborders.command.CommandDecrypt;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandDelete;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandDeletePage;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandDeletePublic;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandEditConfig;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandEncrypt;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandFormat;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandGive;
|
||||
@@ -21,7 +22,6 @@ import net.knarcraft.bookswithoutborders.command.CommandReload;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandSave;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandSavePublic;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandSetAuthor;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandSetBookPrice;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandSetBookshelfData;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandSetGeneration;
|
||||
import net.knarcraft.bookswithoutborders.command.CommandSetLore;
|
||||
@@ -276,7 +276,6 @@ public class BooksWithoutBorders extends ConfigCommentPlugin {
|
||||
registerCommand(BwBCommand.COPY_BOOK.toString(), new CommandCopy());
|
||||
registerCommand(BwBCommand.UNSIGN_BOOK.toString(), new CommandUnSign());
|
||||
registerCommand(BwBCommand.ENCRYPT_BOOK.toString(), new CommandEncrypt());
|
||||
registerCommand(BwBCommand.SET_BOOK_PRICE.toString(), new CommandSetBookPrice());
|
||||
registerCommand(BwBCommand.SET_LORE.toString(), new CommandSetLore());
|
||||
registerCommand(BwBCommand.SAVE_PUBLIC_BOOK.toString(), new CommandSavePublic());
|
||||
registerCommand(BwBCommand.SAVE_BOOK.toString(), new CommandSave());
|
||||
@@ -294,6 +293,7 @@ public class BooksWithoutBorders extends ConfigCommentPlugin {
|
||||
registerCommand(BwBCommand.DELETE_PAGE.toString(), new CommandDeletePage());
|
||||
registerCommand(BwBCommand.MIGRATE.toString(), new CommandMigrate());
|
||||
registerCommand(BwBCommand.CREATE_BWB_SIGN.toString(), new CommandCreateBwBSign());
|
||||
registerCommand(BwBCommand.EDIT_BWB_CONFIG.toString(), new CommandEditConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -90,7 +90,7 @@ public class CommandCreateBwBSign implements TabExecutor {
|
||||
List<String> books = BooksWithoutBorders.getAvailableBooks(sender, true);
|
||||
String merged = InputParsingUtil.mergeArguments(1, arguments);
|
||||
List<String> filtered = TabCompletionHelper.filterMatchingContains(books, merged);
|
||||
return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 1);
|
||||
return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 1, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -121,7 +121,7 @@ public class CommandDelete implements TabExecutor {
|
||||
BooksWithoutBorders.getAvailableBooks(sender, deletePublic),
|
||||
InputParsingUtil.mergeArguments(arguments, 0));
|
||||
if (arguments.length > 1) {
|
||||
return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0);
|
||||
return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0, "");
|
||||
} else {
|
||||
return filtered;
|
||||
}
|
||||
|
@@ -0,0 +1,427 @@
|
||||
package net.knarcraft.bookswithoutborders.command;
|
||||
|
||||
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||
import net.knarcraft.bookswithoutborders.config.ConfigOption;
|
||||
import net.knarcraft.bookswithoutborders.config.StaticMessage;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.CostMessage;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.Placeholder;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.Translatable;
|
||||
import net.knarcraft.bookswithoutborders.manager.EconomyManager;
|
||||
import net.knarcraft.bookswithoutborders.state.BookDirectory;
|
||||
import net.knarcraft.bookswithoutborders.state.ItemSlot;
|
||||
import net.knarcraft.bookswithoutborders.utility.BookFileUtil;
|
||||
import net.knarcraft.bookswithoutborders.utility.InputParsingUtil;
|
||||
import net.knarcraft.bookswithoutborders.utility.InventoryUtil;
|
||||
import net.knarcraft.bookswithoutborders.utility.TabCompletionTypeUtil;
|
||||
import net.knarcraft.knarlib.formatting.FormatBuilder;
|
||||
import net.knarcraft.knarlib.util.TabCompletionHelper;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The command for altering configuration values
|
||||
*/
|
||||
public class CommandEditConfig implements TabExecutor {
|
||||
|
||||
private final static @NotNull String BOOK_SEPARATOR = "|";
|
||||
private final static @NotNull String CLEAR = "clear";
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String s,
|
||||
@NotNull String[] arguments) {
|
||||
if (arguments.length < 1) {
|
||||
return false;
|
||||
}
|
||||
ConfigOption option = ConfigOption.getByString(arguments[0]);
|
||||
if (option == null) {
|
||||
return false;
|
||||
}
|
||||
if (arguments.length == 1) {
|
||||
printCurrentValue(option, sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean success = switch (option) {
|
||||
case ADMIN_AUTO_DECRYPT, USE_REAL_ENCRYPTION, ENABLE_BOOKSHELF_PEEKING, AUTHOR_ONLY_COPY,
|
||||
AUTHOR_ONLY_UNSIGN, AUTHOR_ONLY_SAVE, CHANGE_GENERATION_ON_COPY, FORMAT_AFTER_SIGNING,
|
||||
ALLOW_PREVENT_ADMIN_DECRYPTION -> {
|
||||
setBoolean(option, arguments[1]);
|
||||
yield true;
|
||||
}
|
||||
case TITLE_AUTHOR_SEPARATOR, LORE_LINE_SEPARATOR -> setSeparator(option, arguments[1], sender);
|
||||
case LANGUAGE -> setString(option, arguments[1]);
|
||||
case MESSAGE_FOR_NEW_PLAYERS -> setString(option, InputParsingUtil.mergeArguments(0, arguments));
|
||||
case MAX_DUPLICATES -> setMaxDuplicates(arguments[1], sender);
|
||||
case BOOKS_FOR_NEW_PLAYERS -> setBooks(InputParsingUtil.mergeArguments(1, arguments), sender);
|
||||
case PRICE_ITEM_TYPE, PRICE_QUANTITY -> setCost(arguments, sender);
|
||||
};
|
||||
|
||||
if (success) {
|
||||
new FormatBuilder(Translatable.SUCCESS_CONFIGURATION_UPDATED).
|
||||
replace(Placeholder.OPTION, option.getConfigNode()).success(sender);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
|
||||
@NotNull String[] arguments) {
|
||||
if (arguments.length == 1) {
|
||||
List<String> configOptions = new ArrayList<>();
|
||||
for (ConfigOption option : ConfigOption.values()) {
|
||||
configOptions.add(option.getOptionName());
|
||||
}
|
||||
return TabCompletionHelper.filterMatchingContains(configOptions, arguments[0]);
|
||||
}
|
||||
|
||||
ConfigOption option = ConfigOption.getByString(arguments[0]);
|
||||
if (option == null) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
if (option == ConfigOption.BOOKS_FOR_NEW_PLAYERS) {
|
||||
return getBookTabCompletions(arguments, commandSender);
|
||||
}
|
||||
|
||||
if (arguments.length == 2) {
|
||||
switch (option) {
|
||||
case FORMAT_AFTER_SIGNING, ENABLE_BOOKSHELF_PEEKING, AUTHOR_ONLY_COPY, AUTHOR_ONLY_SAVE,
|
||||
AUTHOR_ONLY_UNSIGN, ADMIN_AUTO_DECRYPT, USE_REAL_ENCRYPTION, ALLOW_PREVENT_ADMIN_DECRYPTION,
|
||||
CHANGE_GENERATION_ON_COPY:
|
||||
return TabCompletionHelper.filterMatchingContains(List.of("true", "false"), arguments[1]);
|
||||
case PRICE_QUANTITY, PRICE_ITEM_TYPE:
|
||||
return TabCompletionHelper.filterMatchingContains(List.of(
|
||||
StaticMessage.COST_ECONOMY.toString().toLowerCase(),
|
||||
StaticMessage.COST_ITEM.toString(), CLEAR), arguments[1]);
|
||||
case LORE_LINE_SEPARATOR, LANGUAGE:
|
||||
return TabCompletionHelper.filterMatchingStartsWith(List.of(String.valueOf(option.getDefaultValue())), arguments[1]);
|
||||
case MAX_DUPLICATES:
|
||||
return TabCompletionHelper.filterMatchingStartsWith(List.of("1", "2", "3", "4", "5"), arguments[1]);
|
||||
case MESSAGE_FOR_NEW_PLAYERS:
|
||||
return List.of("Text text text", CLEAR);
|
||||
case TITLE_AUTHOR_SEPARATOR:
|
||||
return TabCompletionHelper.filterMatchingStartsWith(List.of(",", "¤"), arguments[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (arguments.length == 3 && (option == ConfigOption.PRICE_QUANTITY || option == ConfigOption.PRICE_ITEM_TYPE)) {
|
||||
return TabCompletionHelper.filterMatchingStartsWith(List.of("0", "1", "5", "10"), arguments[2]);
|
||||
}
|
||||
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets tab-completions for available books
|
||||
*
|
||||
* @param arguments <p>The arguments to parse book selection from</p>
|
||||
* @param commandSender <p>The sender attempting to get tab-completions</p>
|
||||
* @return <p>The tab-completions</p>
|
||||
*/
|
||||
@NotNull
|
||||
private List<String> getBookTabCompletions(@NotNull String[] arguments, @NotNull CommandSender commandSender) {
|
||||
List<String> availableBooks = BooksWithoutBorders.getAvailableBooks(commandSender, true);
|
||||
String booksString = InputParsingUtil.mergeArguments(1, arguments);
|
||||
String prefix = "";
|
||||
if (booksString.contains(BOOK_SEPARATOR)) {
|
||||
String[] parts = booksString.split(Pattern.quote(BOOK_SEPARATOR), -1);
|
||||
String[] newArguments = parts[parts.length - 1].split(" ", -1);
|
||||
|
||||
if (arguments[arguments.length - 1].contains(BOOK_SEPARATOR)) {
|
||||
prefix = arguments[arguments.length - 1].split(Pattern.quote(BOOK_SEPARATOR), -1)[0] + BOOK_SEPARATOR;
|
||||
}
|
||||
booksString = parts[parts.length - 1];
|
||||
|
||||
List<String> filtered = TabCompletionHelper.filterMatchingContains(availableBooks, booksString);
|
||||
return TabCompletionTypeUtil.getCleanedTabCompletions(newArguments, filtered, 0, prefix);
|
||||
} else {
|
||||
if (arguments.length == 2) {
|
||||
availableBooks.add(CLEAR);
|
||||
}
|
||||
List<String> filtered = TabCompletionHelper.filterMatchingContains(availableBooks, booksString);
|
||||
return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 1, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the current value of the given configuration option
|
||||
*
|
||||
* @param option <p>The option to show the current value of</p>
|
||||
* @param sender <p>The command sender to display the value to.</p>
|
||||
*/
|
||||
private void printCurrentValue(@NotNull ConfigOption option, @NotNull CommandSender sender) {
|
||||
FileConfiguration configuration = BooksWithoutBorders.getInstance().getConfig();
|
||||
if (option == ConfigOption.PRICE_QUANTITY || option == ConfigOption.PRICE_ITEM_TYPE) {
|
||||
new FormatBuilder(Translatable.SUCCESS_CONFIGURATION_PRICE_CURRENT_VALUE).
|
||||
replace(Placeholder.QUANTITY, String.valueOf(configuration.getDouble(ConfigOption.PRICE_QUANTITY.getConfigNode()))).
|
||||
replace(Placeholder.TYPE, configuration.getString(ConfigOption.PRICE_ITEM_TYPE.getConfigNode(), "")).
|
||||
replace(Placeholder.DEFAULT_COST, String.valueOf(ConfigOption.PRICE_ITEM_TYPE.getDefaultValue())).
|
||||
replace(Placeholder.DEFAULT_QUANTITY, String.valueOf(ConfigOption.PRICE_QUANTITY.getDefaultValue())).success(sender);
|
||||
} else {
|
||||
String node = option.getConfigNode();
|
||||
new FormatBuilder(Translatable.SUCCESS_CONFIGURATION_CURRENT_VALUE).replace(Placeholder.OPTION, node).
|
||||
replace(Placeholder.VALUE, String.valueOf(configuration.get(node))).
|
||||
replace(Placeholder.DEFAULT, String.valueOf(option.getDefaultValue())).success(sender);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates books for new players
|
||||
*
|
||||
* @param newValue <p>The name of the book(s) to set</p>
|
||||
* @param sender <p>The sender setting books</p>
|
||||
* @return <p>True if successful</p>
|
||||
*/
|
||||
private boolean setBooks(@NotNull String newValue, @NotNull CommandSender sender) {
|
||||
if (newValue.equalsIgnoreCase(CLEAR)) {
|
||||
updateValueAndReload(ConfigOption.BOOKS_FOR_NEW_PLAYERS, "", true);
|
||||
return true;
|
||||
} else if (newValue.contains(BOOK_SEPARATOR)) {
|
||||
String[] books = newValue.split(Pattern.quote(BOOK_SEPARATOR));
|
||||
for (int i = 0; i < books.length; i++) {
|
||||
books[i] = books[i].trim();
|
||||
if (!verifyBook(books[i], sender)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
updateValueAndReload(ConfigOption.BOOKS_FOR_NEW_PLAYERS, books, true);
|
||||
return true;
|
||||
} else {
|
||||
if (verifyBook(newValue, sender)) {
|
||||
updateValueAndReload(ConfigOption.BOOKS_FOR_NEW_PLAYERS, newValue, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to verify a book name
|
||||
*
|
||||
* @param bookName <p>The book name to verify</p>
|
||||
* @param sender <p>The sender giving the book name</p>
|
||||
* @return <p>True if the book exists</p>
|
||||
*/
|
||||
private boolean verifyBook(@NotNull String bookName, @NotNull CommandSender sender) {
|
||||
BooksWithoutBorders.log(Level.INFO, "Book: '" + bookName + "'");
|
||||
File file = BookFileUtil.getFile(BookDirectory.PUBLIC, null, bookName);
|
||||
if (file != null) {
|
||||
return true;
|
||||
} else {
|
||||
new FormatBuilder(Translatable.ERROR_INCORRECT_FILE_NAME).error(sender);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a string configuration value as-is with no validation
|
||||
*
|
||||
* @param configOption <p>The configuration option to set</p>
|
||||
* @param newValue <p>The new value</p>
|
||||
* @return <p>True if the new value is valid</p>
|
||||
*/
|
||||
private boolean setString(@NotNull ConfigOption configOption, @NotNull String newValue) {
|
||||
if (configOption == ConfigOption.MESSAGE_FOR_NEW_PLAYERS && newValue.equalsIgnoreCase(CLEAR)) {
|
||||
newValue = "";
|
||||
} else if (newValue.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
updateValueAndReload(configOption, newValue, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max duplicates option, if the input is valid
|
||||
*
|
||||
* @param newValue <p>The value given</p>
|
||||
* @param sender <p>The command sender altering the value</p>
|
||||
* @return <p>True if successful</p>
|
||||
*/
|
||||
private boolean setMaxDuplicates(@NotNull String newValue, @NotNull CommandSender sender) {
|
||||
try {
|
||||
int value = Integer.parseInt(newValue);
|
||||
if (value >= 0) {
|
||||
updateValueAndReload(ConfigOption.MAX_DUPLICATES, value, true);
|
||||
return true;
|
||||
} else {
|
||||
new FormatBuilder(Translatable.ERROR_DUPLICATE_LIMIT_INVALID).error(sender);
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException exception) {
|
||||
new FormatBuilder(Translatable.ERROR_DUPLICATE_LIMIT_INVALID).error(sender);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a boolean configuration option, and updates the configuration
|
||||
*
|
||||
* @param configOption <p>The configuration option to set</p>
|
||||
* @param newValue <p>The value given</p>
|
||||
*/
|
||||
private void setBoolean(@NotNull ConfigOption configOption, @NotNull String newValue) {
|
||||
updateValueAndReload(configOption, Boolean.parseBoolean(newValue), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a separator configuration option, after validating it
|
||||
*
|
||||
* @param configOption <p>The separator configuration option to set</p>
|
||||
* @param newValue <p>The value given</p>
|
||||
* @param sender <p>The command sender altering the value</p>
|
||||
* @return <p>True if successful</p>
|
||||
*/
|
||||
private boolean setSeparator(@NotNull ConfigOption configOption, @NotNull String newValue,
|
||||
@NotNull CommandSender sender) {
|
||||
switch (configOption) {
|
||||
case LORE_LINE_SEPARATOR:
|
||||
if (newValue.isEmpty()) {
|
||||
new FormatBuilder(Translatable.ERROR_LORE_LINE_SEPARATOR_INVALID).error(sender);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case TITLE_AUTHOR_SEPARATOR:
|
||||
if (newValue.trim().length() != 1) {
|
||||
new FormatBuilder(Translatable.ERROR_TITLE_AUTHOR_SEPARATOR_INVALID).error(sender);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected value: " + configOption);
|
||||
}
|
||||
updateValueAndReload(configOption, newValue, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a configuration option, and reloads the BwB configuration
|
||||
*
|
||||
* @param configOption <p>The configuration to update</p>
|
||||
* @param newValue <p>The new value of the option</p>
|
||||
* @param reload <p>Save and reload after setting the value</p>
|
||||
*/
|
||||
private void updateValueAndReload(@NotNull ConfigOption configOption, @NotNull Object newValue, boolean reload) {
|
||||
Plugin instance = BooksWithoutBorders.getInstance();
|
||||
FileConfiguration configuration = instance.getConfig();
|
||||
configuration.set(configOption.getConfigNode(), newValue);
|
||||
if (reload) {
|
||||
instance.saveConfig();
|
||||
BooksWithoutBorders.getConfiguration().loadConfig();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets cost for creating books
|
||||
*
|
||||
* @param arguments <p>The arguments given</p>
|
||||
* @param sender <p>The sender attempting to change the cost</p>
|
||||
* @return <p>True if successful</p>
|
||||
*/
|
||||
private boolean setCost(@NotNull String[] arguments, @NotNull CommandSender sender) {
|
||||
if (arguments[1].equalsIgnoreCase(CLEAR)) {
|
||||
// Clear current price
|
||||
clearItemPrice(sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
//Warn about missing arguments
|
||||
if (arguments.length < 3) {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_NOT_SPECIFIED).error(sender);
|
||||
return false;
|
||||
}
|
||||
|
||||
double price;
|
||||
try {
|
||||
price = Double.parseDouble(arguments[2]);
|
||||
if (price <= 0) {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_INVALID_QUANTITY).error(sender);
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException exception) {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_INVALID_QUANTITY).error(sender);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arguments[1].equalsIgnoreCase(StaticMessage.COST_ITEM.toString())) {
|
||||
return setItemPrice(sender, price);
|
||||
} else if (arguments[1].equalsIgnoreCase(StaticMessage.COST_ECONOMY.toString())) {
|
||||
return setEconomyPrice(sender, price);
|
||||
} else {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_INVALID_TYPE).error(sender);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the book price
|
||||
*
|
||||
* @param sender <p>The sender of the command</p>
|
||||
*/
|
||||
private void clearItemPrice(@NotNull CommandSender sender) {
|
||||
updateValueAndReload(ConfigOption.PRICE_ITEM_TYPE, StaticMessage.COST_NONE.toString(), false);
|
||||
updateValueAndReload(ConfigOption.PRICE_QUANTITY, 0, true);
|
||||
new FormatBuilder(CostMessage.SUCCESS_COST_REMOVED).success(sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(@NotNull CommandSender sender, double price) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
new FormatBuilder(Translatable.ERROR_PLAYER_ONLY).error(sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
ItemStack heldItem = InventoryUtil.getHeldItem(player, ItemSlot.MAIN_HAND);
|
||||
if (heldItem.getType() == Material.AIR) {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_ITEM_MISSING).error(sender);
|
||||
return false;
|
||||
}
|
||||
|
||||
updateValueAndReload(ConfigOption.PRICE_ITEM_TYPE, heldItem.getType(), false);
|
||||
updateValueAndReload(ConfigOption.PRICE_QUANTITY, price, true);
|
||||
new FormatBuilder(CostMessage.SUCCESS_COST_ITEM_SET).replace(Placeholder.QUANTITY,
|
||||
String.valueOf((int) price)).replace(Placeholder.COST, heldItem.getType().toString()).success(sender);
|
||||
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>
|
||||
*/
|
||||
private boolean setEconomyPrice(@NotNull CommandSender sender, double price) {
|
||||
EconomyManager economyManager = BooksWithoutBorders.getConfiguration().getEconomyManager();
|
||||
if (economyManager.getEconomy() != null) {
|
||||
updateValueAndReload(ConfigOption.PRICE_ITEM_TYPE, StaticMessage.COST_ECONOMY.toString(), false);
|
||||
updateValueAndReload(ConfigOption.PRICE_QUANTITY, price, true);
|
||||
new FormatBuilder(CostMessage.SUCCESS_COST_ECONOMY_SET).replace(Placeholder.COST,
|
||||
economyManager.getEconomy().format(price)).success(sender);
|
||||
return true;
|
||||
} else {
|
||||
new FormatBuilder(StaticMessage.EXCEPTION_VAULT_PRICE_NOT_CHANGED.toString()).error(sender);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -97,7 +97,7 @@ public class CommandGive implements TabExecutor {
|
||||
List<String> filtered = TabCompletionHelper.filterMatchingContains(books, mergeArguments(arguments, 0));
|
||||
|
||||
if (!filtered.isEmpty()) {
|
||||
List<String> cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0);
|
||||
List<String> cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0, "");
|
||||
if (!books.contains(mergeArguments(arguments, 1))) {
|
||||
return cleaned;
|
||||
} else {
|
||||
|
@@ -92,7 +92,7 @@ public class CommandLoad implements TabExecutor {
|
||||
mergeArguments(arguments, 0));
|
||||
|
||||
if (!filtered.isEmpty()) {
|
||||
List<String> cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0);
|
||||
List<String> cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0, "");
|
||||
if (!books.contains(mergeArguments(arguments, 1))) {
|
||||
return cleaned;
|
||||
} else {
|
||||
|
@@ -1,171 +0,0 @@
|
||||
package net.knarcraft.bookswithoutborders.command;
|
||||
|
||||
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||
import net.knarcraft.bookswithoutborders.config.BwBConfig;
|
||||
import net.knarcraft.bookswithoutborders.config.ConfigOption;
|
||||
import net.knarcraft.bookswithoutborders.config.StaticMessage;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.CostMessage;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.Placeholder;
|
||||
import net.knarcraft.bookswithoutborders.config.translation.Translatable;
|
||||
import net.knarcraft.bookswithoutborders.manager.EconomyManager;
|
||||
import net.knarcraft.bookswithoutborders.state.ItemSlot;
|
||||
import net.knarcraft.bookswithoutborders.utility.InventoryUtil;
|
||||
import net.knarcraft.bookswithoutborders.utility.TabCompletionTypeUtil;
|
||||
import net.knarcraft.knarlib.formatting.FormatBuilder;
|
||||
import net.knarcraft.knarlib.util.TabCompletionHelper;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabExecutor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Command executor for the set book price command
|
||||
*/
|
||||
public class CommandSetBookPrice implements TabExecutor {
|
||||
|
||||
private final BooksWithoutBorders booksWithoutBorders = BooksWithoutBorders.getInstance();
|
||||
private List<String> paymentTypes;
|
||||
|
||||
@Override
|
||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
||||
@NotNull String[] arguments) {
|
||||
//Clear the current price
|
||||
if (arguments.length == 0) {
|
||||
clearItemPrice(sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
//Warn about missing arguments
|
||||
if (arguments.length < 2) {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_NOT_SPECIFIED).error(sender);
|
||||
return false;
|
||||
}
|
||||
|
||||
double price;
|
||||
try {
|
||||
price = Double.parseDouble(arguments[1]);
|
||||
if (price <= 0) {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_INVALID_QUANTITY).error(sender);
|
||||
return false;
|
||||
}
|
||||
} catch (NumberFormatException exception) {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_INVALID_QUANTITY).error(sender);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arguments[0].equalsIgnoreCase("item")) {
|
||||
return setItemPrice(sender, price);
|
||||
} else if (arguments[0].equalsIgnoreCase(StaticMessage.COST_ECONOMY.toString())) {
|
||||
setEconomyPrice(sender, price);
|
||||
return true;
|
||||
} else {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_INVALID_TYPE).error(sender);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the book price
|
||||
*
|
||||
* @param sender <p>The sender of the command</p>
|
||||
*/
|
||||
private void clearItemPrice(@NotNull CommandSender sender) {
|
||||
BwBConfig config = BooksWithoutBorders.getConfiguration();
|
||||
config.setBookPriceType(null);
|
||||
config.setBookPriceQuantity(0);
|
||||
booksWithoutBorders.getConfig().set(ConfigOption.PRICE_ITEM_TYPE.getConfigNode(), StaticMessage.COST_NONE.toString());
|
||||
booksWithoutBorders.getConfig().set(ConfigOption.PRICE_QUANTITY.getConfigNode(), config.getBookPriceQuantity());
|
||||
booksWithoutBorders.saveConfig();
|
||||
|
||||
new FormatBuilder(CostMessage.SUCCESS_COST_REMOVED).success(sender);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(@NotNull CommandSender sender, double price) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
new FormatBuilder(Translatable.ERROR_PLAYER_ONLY).error(sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
ItemStack heldItem = InventoryUtil.getHeldItem(player, ItemSlot.MAIN_HAND);
|
||||
if (heldItem.getType() == Material.AIR) {
|
||||
new FormatBuilder(CostMessage.ERROR_COST_ITEM_MISSING).error(sender);
|
||||
return false;
|
||||
}
|
||||
|
||||
BwBConfig config = BooksWithoutBorders.getConfiguration();
|
||||
config.setBookPriceType(heldItem.getType());
|
||||
config.setBookPriceQuantity(price);
|
||||
String newPriceType = config.getBookPriceType().toString();
|
||||
double newPriceQuantity = config.getBookPriceQuantity();
|
||||
booksWithoutBorders.getConfig().set(ConfigOption.PRICE_ITEM_TYPE.getConfigNode(), newPriceType);
|
||||
booksWithoutBorders.getConfig().set(ConfigOption.PRICE_QUANTITY.getConfigNode(), newPriceQuantity);
|
||||
booksWithoutBorders.saveConfig();
|
||||
|
||||
new FormatBuilder(CostMessage.SUCCESS_COST_ITEM_SET).replace(Placeholder.QUANTITY,
|
||||
String.valueOf((int) newPriceQuantity)).replace(Placeholder.COST, newPriceType).success(sender);
|
||||
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>
|
||||
*/
|
||||
private void setEconomyPrice(@NotNull CommandSender sender, double price) {
|
||||
EconomyManager economyManager = BooksWithoutBorders.getConfiguration().getEconomyManager();
|
||||
if (economyManager.getEconomy() != null) {
|
||||
BwBConfig config = BooksWithoutBorders.getConfiguration();
|
||||
config.setBookPriceQuantity(price);
|
||||
config.setBookPriceType(Material.AIR);
|
||||
double newPriceQuantity = config.getBookPriceQuantity();
|
||||
booksWithoutBorders.getConfig().set(ConfigOption.PRICE_ITEM_TYPE.getConfigNode(), StaticMessage.COST_ECONOMY.toString());
|
||||
booksWithoutBorders.getConfig().set(ConfigOption.PRICE_QUANTITY.getConfigNode(), newPriceQuantity);
|
||||
booksWithoutBorders.saveConfig();
|
||||
|
||||
new FormatBuilder(CostMessage.SUCCESS_COST_ECONOMY_SET).replace(Placeholder.COST,
|
||||
economyManager.getEconomy().format(newPriceQuantity)).success(sender);
|
||||
} else {
|
||||
new FormatBuilder(StaticMessage.EXCEPTION_VAULT_PRICE_NOT_CHANGED.toString()).error(sender);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
||||
@NotNull String[] arguments) {
|
||||
if (paymentTypes == null) {
|
||||
initializeTabCompleteLists();
|
||||
}
|
||||
|
||||
int argumentCount = arguments.length;
|
||||
if (argumentCount == 1) {
|
||||
return TabCompletionHelper.filterMatchingStartsWith(paymentTypes, arguments[0]);
|
||||
} else if (argumentCount == 2) {
|
||||
return TabCompletionHelper.filterMatchingStartsWith(TabCompletionTypeUtil.getNumbers(1, 3), arguments[1]);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the lists of tab complete values
|
||||
*/
|
||||
private void initializeTabCompleteLists() {
|
||||
paymentTypes = new ArrayList<>();
|
||||
paymentTypes.add("item");
|
||||
paymentTypes.add(StaticMessage.COST_ECONOMY.toString().toLowerCase());
|
||||
}
|
||||
|
||||
}
|
@@ -120,11 +120,6 @@ public enum BwBCommand {
|
||||
*/
|
||||
SET_BOOK_GENERATION("setBookGeneration", true, "Set held book generation"),
|
||||
|
||||
/**
|
||||
* Sets the price of copying, loading and giving books
|
||||
*/
|
||||
SET_BOOK_PRICE("setBookPrice", false, "Set book creation price"),
|
||||
|
||||
/**
|
||||
* Sets the name/lore for the chiseled bookshelf in front of the player, displayed when peeking the bookshelf
|
||||
*/
|
||||
@@ -149,7 +144,11 @@ public enum BwBCommand {
|
||||
* Creates a BwB sign from the input
|
||||
*/
|
||||
CREATE_BWB_SIGN("createBwBSign", true, "Create a BwB sign"),
|
||||
;
|
||||
|
||||
/**
|
||||
* Edits the configuration file
|
||||
*/
|
||||
EDIT_BWB_CONFIG("editBwBConfig", false, "Edit configuration");
|
||||
|
||||
private final @NotNull String commandName;
|
||||
private final boolean requiresPlayer;
|
||||
|
@@ -126,15 +126,6 @@ public class BwBConfig {
|
||||
return this.adminDecrypt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the quantity of items/currency necessary for copying books
|
||||
*
|
||||
* @param newQuantity <p>The new quantity necessary for payment</p>
|
||||
*/
|
||||
public void setBookPriceQuantity(double newQuantity) {
|
||||
this.bookPriceQuantity = newQuantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the quantity of items/currency necessary for copying books
|
||||
*
|
||||
@@ -144,18 +135,6 @@ public class BwBConfig {
|
||||
return this.bookPriceQuantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item type used for book pricing
|
||||
*
|
||||
* <p>This item is the one a player has to pay for copying books. AIR is used to denote economy. null is used if
|
||||
* payment is disabled. Otherwise, any item can be used.</p>
|
||||
*
|
||||
* @param newType <p>The new item type to use for book pricing</p>
|
||||
*/
|
||||
public void setBookPriceType(Material newType) {
|
||||
this.bookPriceType = newType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item type used for book pricing
|
||||
*
|
||||
@@ -351,6 +330,11 @@ public class BwBConfig {
|
||||
this.bookPriceQuantity = config.getDouble(ConfigOption.PRICE_QUANTITY.getConfigNode(),
|
||||
(Double) ConfigOption.PRICE_QUANTITY.getDefaultValue());
|
||||
|
||||
if (this.loreSeparator.trim().isEmpty()) {
|
||||
this.loreSeparator = (String) ConfigOption.LORE_LINE_SEPARATOR.getDefaultValue();
|
||||
config.set(ConfigOption.LORE_LINE_SEPARATOR.getConfigNode(), this.loreSeparator);
|
||||
}
|
||||
|
||||
//Make sure titleAuthorSeparator is a valid value
|
||||
this.titleAuthorSeparator = cleanString(this.titleAuthorSeparator);
|
||||
if (this.titleAuthorSeparator.length() != 1) {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package net.knarcraft.bookswithoutborders.config;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A representation of the different available config options
|
||||
@@ -10,100 +11,103 @@ public enum ConfigOption {
|
||||
/**
|
||||
* The max duplicates of a book that can be saved
|
||||
*/
|
||||
MAX_DUPLICATES("limit.maxDuplicates", 5),
|
||||
MAX_DUPLICATES("limit.maxDuplicates", "maxDuplicates", 5),
|
||||
|
||||
/**
|
||||
* The separator used to separate book title and book author
|
||||
*/
|
||||
TITLE_AUTHOR_SEPARATOR("separator.titleAuthor", ","),
|
||||
TITLE_AUTHOR_SEPARATOR("separator.titleAuthor", "titleAuthorSeparator", ","),
|
||||
|
||||
/**
|
||||
* The separator used to specify a new line in an item's lore
|
||||
*/
|
||||
LORE_LINE_SEPARATOR("separator.loreLine", "~"),
|
||||
LORE_LINE_SEPARATOR("separator.loreLine", "loreSeparator", "~"),
|
||||
|
||||
/**
|
||||
* The books given to new players when they first join
|
||||
*/
|
||||
BOOKS_FOR_NEW_PLAYERS("firstJoin.booksToGive", "[]"),
|
||||
BOOKS_FOR_NEW_PLAYERS("firstJoin.booksToGive", "firstJoinBooks", "[]"),
|
||||
|
||||
/**
|
||||
* The message to display to new players when they first join
|
||||
*/
|
||||
MESSAGE_FOR_NEW_PLAYERS("firstJoin.welcomeMessage", ""),
|
||||
MESSAGE_FOR_NEW_PLAYERS("firstJoin.welcomeMessage", "firstJoinMessage", ""),
|
||||
|
||||
/**
|
||||
* The item type used to pay for book copying
|
||||
*/
|
||||
PRICE_ITEM_TYPE("bookPrice.itemType", ""),
|
||||
PRICE_ITEM_TYPE("bookPrice.itemType", "bookPrice", ""),
|
||||
|
||||
/**
|
||||
* The amount of items used to pay for book copying
|
||||
*/
|
||||
PRICE_QUANTITY("bookPrice.quantity", 0.0),
|
||||
PRICE_QUANTITY("bookPrice.quantity", "bookPrice", 0.0),
|
||||
|
||||
/**
|
||||
* Whether admins should be able to decrypt books for all groups
|
||||
*/
|
||||
ADMIN_AUTO_DECRYPT("encryption.allowAdminBypass", false),
|
||||
ADMIN_AUTO_DECRYPT("encryption.allowAdminBypass", "allowEncryptionBypass", false),
|
||||
|
||||
/**
|
||||
* Whether only the book author should be able to copy a book
|
||||
*/
|
||||
AUTHOR_ONLY_COPY("authorRestricted.copy", false),
|
||||
AUTHOR_ONLY_COPY("authorRestricted.copy", "restrictCopyToAuthor", false),
|
||||
|
||||
/**
|
||||
* Whether only the book author should be able to unsign a book
|
||||
*/
|
||||
AUTHOR_ONLY_UNSIGN("authorRestricted.unsign", false),
|
||||
AUTHOR_ONLY_UNSIGN("authorRestricted.unsign", "restrictUnSigningToAuthor", false),
|
||||
|
||||
/**
|
||||
* Whether a player can only save their own books with /saveBook
|
||||
*/
|
||||
AUTHOR_ONLY_SAVE("authorRestricted.save", false),
|
||||
AUTHOR_ONLY_SAVE("authorRestricted.save", "restrictSavingToAuthor", false),
|
||||
|
||||
/**
|
||||
* Whether to turn Original into Copy when copying books
|
||||
*/
|
||||
CHANGE_GENERATION_ON_COPY("functionality.changeBookGenerationOnCopy", false),
|
||||
CHANGE_GENERATION_ON_COPY("functionality.changeBookGenerationOnCopy", "changeBookGenerationOnCopy", false),
|
||||
|
||||
/**
|
||||
* Whether to automatically format every signed book
|
||||
*/
|
||||
FORMAT_AFTER_SIGNING("functionality.formatBookOnSigning", true),
|
||||
FORMAT_AFTER_SIGNING("functionality.formatBookOnSigning", "formatBookOnSigning", true),
|
||||
|
||||
/**
|
||||
* Whether hitting a bookshelf should display information about the contained books
|
||||
*/
|
||||
ENABLE_BOOKSHELF_PEEKING("functionality.enableBookPeeking", true),
|
||||
ENABLE_BOOKSHELF_PEEKING("functionality.enableBookPeeking", "enableBookPeeking", true),
|
||||
|
||||
/**
|
||||
* Whether to use real AES encryption instead of storing garbled book text, while the full plaintext is stored in a file
|
||||
*/
|
||||
USE_REAL_ENCRYPTION("encryption.useRealEncryption", false),
|
||||
USE_REAL_ENCRYPTION("encryption.useRealEncryption", "useRealEncryption", false),
|
||||
|
||||
/**
|
||||
* Whether to allow disabling admin encryption for a real encrypted book
|
||||
*/
|
||||
ALLOW_PREVENT_ADMIN_DECRYPTION("encryption.allowAdminBypassBlocking", false),
|
||||
ALLOW_PREVENT_ADMIN_DECRYPTION("encryption.allowAdminBypassBlocking", "allowEncryptionBypassBlocking", false),
|
||||
|
||||
/**
|
||||
* The language to load from strings.yml
|
||||
*/
|
||||
LANGUAGE("language", "en"),
|
||||
LANGUAGE("language", "language", "en"),
|
||||
;
|
||||
|
||||
private final String configNode;
|
||||
private final String optionName;
|
||||
private final Object defaultValue;
|
||||
|
||||
/**
|
||||
* Instantiates a new config option
|
||||
*
|
||||
* @param configNode <p>The config node in the config file this option represents</p>
|
||||
* @param optionName <p>The name of this option, used when referring to it in commands</p>
|
||||
* @param defaultValue <p>The default value for this config option</p>
|
||||
*/
|
||||
ConfigOption(@NotNull String configNode, @NotNull Object defaultValue) {
|
||||
ConfigOption(@NotNull String configNode, @NotNull String optionName, @NotNull Object defaultValue) {
|
||||
this.configNode = configNode;
|
||||
this.optionName = optionName;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
@@ -125,4 +129,30 @@ public enum ConfigOption {
|
||||
return this.defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of this configuration option
|
||||
*
|
||||
* @return <p>The name of this option</p>
|
||||
*/
|
||||
@NotNull
|
||||
public String getOptionName() {
|
||||
return this.optionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a config option from its name
|
||||
*
|
||||
* @param input <p>The name of a config option</p>
|
||||
* @return <p>The config option, or null if not matched</p>
|
||||
*/
|
||||
@Nullable
|
||||
public static ConfigOption getByString(@NotNull String input) {
|
||||
for (ConfigOption option : ConfigOption.values()) {
|
||||
if (option.optionName.equalsIgnoreCase(input)) {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -38,7 +38,6 @@ public enum StaticMessage {
|
||||
EXCEPTION_ENCRYPTED_LOAD_FAILED("Book encryption failed!"),
|
||||
EXCEPTION_ENCRYPTED_GROUP_FOLDER_CREATION_FAILED("Unable to create encryption group folder!"),
|
||||
EXCEPTION_GROUP_ENCRYPT_SAVE_FAILED("Unable to save group encrypted book"),
|
||||
EXCEPTION_COMMAND_REGISTRATION_FAILED("Failed to register command {command}"),
|
||||
EXCEPTION_ITEM_FACTORY_INIT_FAILED("""
|
||||
Warning! [BooksWithoutBorders] failed to initialize!
|
||||
Please confirm the correct version of [BooksWithoutBorders] is
|
||||
@@ -56,6 +55,11 @@ public enum StaticMessage {
|
||||
*/
|
||||
COST_ECONOMY("Economy"),
|
||||
|
||||
/**
|
||||
* The cost when choosing item cost
|
||||
*/
|
||||
COST_ITEM("item"),
|
||||
|
||||
/**
|
||||
* The cost type to specify no cost
|
||||
*/
|
||||
|
@@ -42,6 +42,11 @@ public enum Placeholder implements TranslatableMessage {
|
||||
LORE,
|
||||
COPIES,
|
||||
BALANCE,
|
||||
OPTION,
|
||||
VALUE,
|
||||
DEFAULT,
|
||||
DEFAULT_QUANTITY,
|
||||
DEFAULT_COST,
|
||||
;
|
||||
|
||||
@Override
|
||||
|
@@ -413,6 +413,36 @@ public enum Translatable implements TranslatableMessage {
|
||||
* The error displayed when attempting to select an invalid book for a give sign
|
||||
*/
|
||||
ERROR_SIGN_BOOK_FOUND_BUT_INVALID,
|
||||
|
||||
/**
|
||||
* The error displayed when supplied with an invalid duplicate limit
|
||||
*/
|
||||
ERROR_DUPLICATE_LIMIT_INVALID,
|
||||
|
||||
/**
|
||||
* The error displayed when supplied with an invalid lore line separator
|
||||
*/
|
||||
ERROR_LORE_LINE_SEPARATOR_INVALID,
|
||||
|
||||
/**
|
||||
* The error displayed when supplied with an invalid title author separator
|
||||
*/
|
||||
ERROR_TITLE_AUTHOR_SEPARATOR_INVALID,
|
||||
|
||||
/**
|
||||
* The success message displayed when displaying the current value of a configuration option
|
||||
*/
|
||||
SUCCESS_CONFIGURATION_CURRENT_VALUE,
|
||||
|
||||
/**
|
||||
* The success message displayed when a configuration option is successfully updated
|
||||
*/
|
||||
SUCCESS_CONFIGURATION_UPDATED,
|
||||
|
||||
/**
|
||||
* The success message displayed when displaying the current value of book cost
|
||||
*/
|
||||
SUCCESS_CONFIGURATION_PRICE_CURRENT_VALUE,
|
||||
;
|
||||
|
||||
@Override
|
||||
|
@@ -65,16 +65,28 @@ public final class TabCompletionTypeUtil {
|
||||
* @param arguments <p>The arguments given by the user</p>
|
||||
* @param filtered <p>Tab-completions filtered by user input</p>
|
||||
* @param offset <p>The offset to use, if other arguments are preceding the book specification</p>
|
||||
* @param prefix <p>The prefix to use before each tab-completion</p>
|
||||
* @return <p>The cleaned tab-completions</p>
|
||||
*/
|
||||
public static @NotNull List<String> getCleanedTabCompletions(@NotNull String[] arguments,
|
||||
@NotNull List<String> filtered, int offset) {
|
||||
@NotNull
|
||||
public static List<String> getCleanedTabCompletions(@NotNull String[] arguments, @NotNull List<String> filtered,
|
||||
int offset, @NotNull String prefix) {
|
||||
List<String> cleaned = new ArrayList<>();
|
||||
int offsetCount = arguments.length - offset;
|
||||
for (String name : filtered) {
|
||||
String[] parts = name.split(" ");
|
||||
if (parts[arguments.length - 2 - offset].equalsIgnoreCase(arguments[arguments.length - 2])) {
|
||||
StringBuilder builder = new StringBuilder(parts[arguments.length - 1 - offset]);
|
||||
for (int i = arguments.length; i < parts.length; i++) {
|
||||
int startIndex = arguments.length == 0 ? 0 : (offsetCount > 1 ? offsetCount - 1 : 0);
|
||||
String[] parts = name.split(" ", -1);
|
||||
// Skip non-matching entries
|
||||
if ((offsetCount > 1 && !parts[offsetCount - 2].equalsIgnoreCase(arguments[offsetCount - 2 + offset])) ||
|
||||
startIndex >= parts.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (startIndex == 0) {
|
||||
cleaned.add(prefix + name);
|
||||
} else {
|
||||
StringBuilder builder = new StringBuilder(prefix).append(parts[startIndex]);
|
||||
for (int i = startIndex + 1; i < parts.length; i++) {
|
||||
builder.append(" ").append(parts[i]);
|
||||
}
|
||||
cleaned.add(builder.toString());
|
||||
|
@@ -1,4 +1,5 @@
|
||||
# Books Without Borders configuration file
|
||||
# You can change these values with the /editbwbconfig command.
|
||||
|
||||
# The language to use. Only "en" is built-in, but custom languages can be added.
|
||||
language: "en"
|
||||
@@ -35,8 +36,6 @@ firstJoin:
|
||||
# +-------------------------------------------------+ #
|
||||
# | Book creation price | #
|
||||
# +-------------------------------------------------+ #
|
||||
# You can set the price with the "/setBookPrice" command.
|
||||
# +-------------------------------------------------+ #
|
||||
bookPrice:
|
||||
# The item type used as currency for copying books. Use "Economy" to use money instead of items.
|
||||
itemType: ""
|
||||
|
@@ -114,16 +114,6 @@ commands:
|
||||
- bwbGeneration
|
||||
usage: /<command> <generation>
|
||||
permission: bookswithoutborders.setgeneration
|
||||
setBookPrice:
|
||||
description: |
|
||||
Sets the per-book-price to create a book via commands. If "Item", the item in the player's hand in the amount
|
||||
of [quantity] will be the price.
|
||||
If "Eco", a Vault based economy will be used for price.
|
||||
If neither <Item/Eco> or <quantity> are specified, the current price to create books will be removed.
|
||||
aliases:
|
||||
- bwbPrice
|
||||
usage: /<command> <item/eco> <quantity>
|
||||
permission: bookswithoutborders.setbookprice
|
||||
setLore:
|
||||
description: |
|
||||
Sets the lore of your held item. Insert the lore_line_separator character to force a new line ("~" by default).
|
||||
@@ -251,6 +241,17 @@ commands:
|
||||
- bwbSign
|
||||
usage: /<command> <give/encrypt/decrypt> [book identifier/password] [encryption style]
|
||||
permission: bookswithoutborders.signs
|
||||
editBwBConfig:
|
||||
description: |
|
||||
Edits a configuration option in the config file
|
||||
Every option expects one value, except setting the price, which expects the type followed by the new price.
|
||||
If specifying an option, but not a value, the current value of the option will be printed.
|
||||
For options that support a blank/missing value, use "clear" as the new value to clear the existing value.
|
||||
When specifying new player books, use "|" to separate between different books.
|
||||
aliases:
|
||||
- bwbConfig
|
||||
usage: /<command> <option> [value] [value] ...
|
||||
permission: bookswithoutborders.admin
|
||||
permissions:
|
||||
bookswithoutborders.*:
|
||||
description: Grants all permissions
|
||||
@@ -276,7 +277,6 @@ permissions:
|
||||
bookswithoutborders.bypassauthoronlyunsign: true
|
||||
bookswithoutborders.bypassauthoronlysave: true
|
||||
bookswithoutborders.bypassbookprice: true
|
||||
bookswithoutborders.setbookprice: true
|
||||
bookswithoutborders.reload: true
|
||||
bookswithoutborders.setgeneration: true
|
||||
bookswithoutborders.editbookshelf: true
|
||||
@@ -344,8 +344,6 @@ permissions:
|
||||
description: Allows player to ignore Author_Only_Save config setting
|
||||
bookswithoutborders.bypassbookprice:
|
||||
description: Allows player to ignore Price_to_create_book config setting
|
||||
bookswithoutborders.setbookprice:
|
||||
description: Allows player to set the cost of creating a book
|
||||
bookswithoutborders.reload:
|
||||
description: Allows player to reload this plugin
|
||||
bookswithoutborders.setgeneration:
|
||||
|
@@ -166,6 +166,21 @@ en:
|
||||
ACTION_CHANGE_GENERATION: "change generation"
|
||||
ERROR_GENERATION_NOT_SPECIFIED: "You must specify the new generation for your book!"
|
||||
ERROR_GENERATION_INVALID: "Invalid book generation specified!"
|
||||
# ------------- #
|
||||
# editBwBConfig #
|
||||
# ------------- #
|
||||
ERROR_DUPLICATE_LIMIT_INVALID: "Duplicate limit must be a number not lower than 0."
|
||||
ERROR_LORE_LINE_SEPARATOR_INVALID: "The lore line separator must be non-empty."
|
||||
ERROR_TITLE_AUTHOR_SEPARATOR_INVALID: "The title author separator must be exactly one character!"
|
||||
SUCCESS_CONFIGURATION_CURRENT_VALUE: |
|
||||
No value supplied.
|
||||
Current value of option "{option}" is "{value}"
|
||||
Default value: {default}
|
||||
SUCCESS_CONFIGURATION_PRICE_CURRENT_VALUE: |
|
||||
No value supplied.
|
||||
Current value of book cost is "{quantity} {type}"
|
||||
Default value: "{defaultQuantity} {defaultCost}"
|
||||
SUCCESS_CONFIGURATION_UPDATED: "Configuration option \"{option}\" was successfully updated"
|
||||
# ------- #
|
||||
# setLore #
|
||||
# ------- #
|
||||
@@ -302,3 +317,8 @@ en:
|
||||
LORE: "{lore}"
|
||||
COPIES: "{copies}"
|
||||
BALANCE: "{balance}"
|
||||
OPTION: "{option}"
|
||||
VALUE: "{value}"
|
||||
DEFAULT: "{default}"
|
||||
DEFAULT_QUANTITY: "{defaultQuantity}"
|
||||
DEFAULT_COST: "{defaultCost}"
|
Reference in New Issue
Block a user