Adds a command for creating BwB signs
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
Adds the createBwBSign command Alters some methods for supporting offsets during argument counting Adds differentiation between the two sign sides when creating and testing BwB signs
This commit is contained in:
10
README.md
10
README.md
@@ -64,13 +64,14 @@ An in-game description of available commands is available through the /bwb comma
|
|||||||
|
|
||||||
| Command | Alias | Arguments | Permission | Description |
|
| 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,... |
|
| /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) |
|
| /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 |
|
| /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 |
|
| /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 |
|
| /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 |
|
| /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 |
|
| /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 |
|
| /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. |
|
| /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) |
|
| /formatbook | bwbformat | None | bookswithoutborders.format | Formats the held written book (converts color and formatting codes to the corresponding formatted text) |
|
||||||
@@ -142,12 +143,15 @@ An in-game description of available commands is available through the /bwb comma
|
|||||||
|
|
||||||
This plugin supports several custom signs with special functionality. Each plugin sign must have \[BwB] on its first
|
This plugin supports several custom signs with special functionality. Each plugin sign must have \[BwB] on its first
|
||||||
line.
|
line.
|
||||||
|
It is recommended to use the `createbwbsign` command over manual creation for give signs, as it bypasses the text
|
||||||
|
limit, and specifying books by index is really unstable. If you have some other plugin for editing sign lines, you can
|
||||||
|
first specify the visual text on the sign's third and fourth line, then add a `:` and put the full book name after that.
|
||||||
|
|
||||||
#### Give sign
|
#### Give sign
|
||||||
|
|
||||||
The **_give_**-sign must have **\[Give]** on its second line. The third and fourth line contains the book to be loaded.
|
The **_give_**-sign must have **\[Give]** on its second line. The third and fourth line contains the book to be loaded.
|
||||||
This can either be a numerical id pointing to a publicly saved book, or the full text identifier of the book (book name,
|
This can either be a numerical id pointing to a publicly saved book, or the full text identifier of the book (book name,
|
||||||
author).
|
author). Use the `createbwbsign` command in order to specify book names of any length.
|
||||||
|
|
||||||
#### Encrypt sign
|
#### Encrypt sign
|
||||||
|
|
||||||
|
2
pom.xml
2
pom.xml
@@ -125,7 +125,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.knarcraft</groupId>
|
<groupId>net.knarcraft</groupId>
|
||||||
<artifactId>knarlib</artifactId>
|
<artifactId>knarlib</artifactId>
|
||||||
<version>1.2.10</version>
|
<version>1.2.11</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@@ -4,6 +4,7 @@ import net.knarcraft.bookswithoutborders.command.CommandAddTitlePage;
|
|||||||
import net.knarcraft.bookswithoutborders.command.CommandBooksWithoutBorders;
|
import net.knarcraft.bookswithoutborders.command.CommandBooksWithoutBorders;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandClear;
|
import net.knarcraft.bookswithoutborders.command.CommandClear;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandCopy;
|
import net.knarcraft.bookswithoutborders.command.CommandCopy;
|
||||||
|
import net.knarcraft.bookswithoutborders.command.CommandCreateBwBSign;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandDecrypt;
|
import net.knarcraft.bookswithoutborders.command.CommandDecrypt;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandDelete;
|
import net.knarcraft.bookswithoutborders.command.CommandDelete;
|
||||||
import net.knarcraft.bookswithoutborders.command.CommandDeletePage;
|
import net.knarcraft.bookswithoutborders.command.CommandDeletePage;
|
||||||
@@ -291,6 +292,7 @@ public class BooksWithoutBorders extends JavaPlugin {
|
|||||||
registerCommand(BwBCommand.ADD_TITLE_PAGE.toString(), new CommandAddTitlePage());
|
registerCommand(BwBCommand.ADD_TITLE_PAGE.toString(), new CommandAddTitlePage());
|
||||||
registerCommand(BwBCommand.DELETE_PAGE.toString(), new CommandDeletePage());
|
registerCommand(BwBCommand.DELETE_PAGE.toString(), new CommandDeletePage());
|
||||||
registerCommand(BwBCommand.MIGRATE.toString(), new CommandMigrate());
|
registerCommand(BwBCommand.MIGRATE.toString(), new CommandMigrate());
|
||||||
|
registerCommand(BwBCommand.CREATE_BWB_SIGN.toString(), new CommandCreateBwBSign());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -0,0 +1,210 @@
|
|||||||
|
package net.knarcraft.bookswithoutborders.command;
|
||||||
|
|
||||||
|
import net.knarcraft.bookswithoutborders.BooksWithoutBorders;
|
||||||
|
import net.knarcraft.bookswithoutborders.config.translation.SignText;
|
||||||
|
import net.knarcraft.bookswithoutborders.config.translation.Translatable;
|
||||||
|
import net.knarcraft.bookswithoutborders.encryption.EncryptionStyle;
|
||||||
|
import net.knarcraft.bookswithoutborders.gui.PagedBookIndex;
|
||||||
|
import net.knarcraft.bookswithoutborders.state.BookDirectory;
|
||||||
|
import net.knarcraft.bookswithoutborders.utility.BookFileUtil;
|
||||||
|
import net.knarcraft.bookswithoutborders.utility.InputCleaningUtil;
|
||||||
|
import net.knarcraft.bookswithoutborders.utility.InputParsingUtil;
|
||||||
|
import net.knarcraft.bookswithoutborders.utility.TabCompletionTypeUtil;
|
||||||
|
import net.knarcraft.knarlib.formatting.FormatBuilder;
|
||||||
|
import net.knarcraft.knarlib.util.SignHelper;
|
||||||
|
import net.knarcraft.knarlib.util.TabCompletionHelper;
|
||||||
|
import net.md_5.bungee.api.ChatColor;
|
||||||
|
import org.bukkit.block.Sign;
|
||||||
|
import org.bukkit.block.sign.SignSide;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A command for creating a valid BooksWithoutBorders sign without all the hassle
|
||||||
|
*/
|
||||||
|
public class CommandCreateBwBSign implements TabExecutor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String commandName,
|
||||||
|
@NotNull String[] arguments) {
|
||||||
|
if (!(sender instanceof Player player)) {
|
||||||
|
new FormatBuilder(Translatable.ERROR_PLAYER_ONLY).error(sender);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments.length < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments[0].equalsIgnoreCase("give") &&
|
||||||
|
PagedBookIndex.displayPage(arguments, player, true, commandName + " give", 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sign clickedSign = SignHelper.getLookedAtSign(player);
|
||||||
|
if (clickedSign == null) {
|
||||||
|
new FormatBuilder(SignText.ERROR_SIGN_NOT_FOUND).error(player);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
SignSide side = clickedSign.getSide(SignHelper.getSide(clickedSign, player));
|
||||||
|
boolean success = switch (arguments[0].toLowerCase()) {
|
||||||
|
case "give" -> createGiveSign(arguments, side, player);
|
||||||
|
case "encrypt" -> createEncryptSign(arguments, side);
|
||||||
|
case "decrypt" -> createDecryptSign(arguments, side);
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
side.setLine(0, ChatColor.DARK_GREEN + new FormatBuilder(SignText.SIGN_HEADER).toString());
|
||||||
|
clickedSign.setWaxed(true);
|
||||||
|
clickedSign.update();
|
||||||
|
new FormatBuilder(SignText.SUCCESS_SIGN_CREATED).success(player);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command,
|
||||||
|
@NotNull String commandName, @NotNull String[] arguments) {
|
||||||
|
if (arguments.length == 1) {
|
||||||
|
List<String> signTypes = List.of("give", "encrypt", "decrypt");
|
||||||
|
return TabCompletionHelper.filterMatchingStartsWith(signTypes, arguments[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show available books
|
||||||
|
if (arguments[0].equalsIgnoreCase("give")) {
|
||||||
|
if (arguments.length == 2) {
|
||||||
|
return TabCompletionHelper.filterMatchingContains(BooksWithoutBorders.getAvailableBooks(sender, true), arguments[1]);
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arguments.length == 2) {
|
||||||
|
if (arguments[0].equalsIgnoreCase("encrypt") || arguments[0].equalsIgnoreCase("decrypt")) {
|
||||||
|
return List.of("<password>");
|
||||||
|
} else {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
} else if (arguments.length == 3 && arguments[0].equalsIgnoreCase("encrypt")) {
|
||||||
|
boolean useRealEncryption = BooksWithoutBorders.getConfiguration().useRealEncryption();
|
||||||
|
List<String> encryptionStyles = new ArrayList<>();
|
||||||
|
for (EncryptionStyle encryptionStyle : EncryptionStyle.values()) {
|
||||||
|
if (!useRealEncryption || encryptionStyle.isRealEncryptionSupported()) {
|
||||||
|
encryptionStyles.add(encryptionStyle.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TabCompletionHelper.filterMatchingStartsWith(encryptionStyles, arguments[2]);
|
||||||
|
}
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an encrypt sign from the player's input
|
||||||
|
*
|
||||||
|
* @param arguments <p>The arguments given</p>
|
||||||
|
* @param side <p>The side of the sign to make into a BwB sign</p>
|
||||||
|
* @return <p>True if the command was used correctly</p>
|
||||||
|
*/
|
||||||
|
private boolean createEncryptSign(@NotNull String[] arguments, @NotNull SignSide side) {
|
||||||
|
if (arguments.length < 2 || arguments.length > 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String password = arguments[1];
|
||||||
|
|
||||||
|
EncryptionStyle encryptionStyle = null;
|
||||||
|
if (arguments.length == 3) {
|
||||||
|
encryptionStyle = EncryptionStyle.getFromString(arguments[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alter sign text
|
||||||
|
side.setLine(1, ChatColor.DARK_BLUE + new FormatBuilder(SignText.SIGN_ENCRYPT).toString());
|
||||||
|
side.setLine(2, ChatColor.MAGIC + password);
|
||||||
|
if (encryptionStyle == null) {
|
||||||
|
side.setLine(3, "");
|
||||||
|
} else {
|
||||||
|
side.setLine(3, ChatColor.DARK_BLUE + encryptionStyle.toString());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a decrypt sign from the player's input
|
||||||
|
*
|
||||||
|
* @param arguments <p>The arguments given</p>
|
||||||
|
* @param side <p>The side of the sign to make into a BwB sign</p>
|
||||||
|
* @return <p>True if the command was used correctly</p>
|
||||||
|
*/
|
||||||
|
private boolean createDecryptSign(@NotNull String[] arguments, @NotNull SignSide side) {
|
||||||
|
if (arguments.length != 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String password = arguments[1];
|
||||||
|
|
||||||
|
// Alter sign text
|
||||||
|
side.setLine(1, ChatColor.DARK_BLUE + new FormatBuilder(SignText.SIGN_DECRYPT).toString());
|
||||||
|
side.setLine(2, ChatColor.MAGIC + password);
|
||||||
|
side.setLine(3, "");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a give sign from the player's input
|
||||||
|
*
|
||||||
|
* @param arguments <p>The arguments given</p>
|
||||||
|
* @param side <p>The side of the sign to make into a BwB sign</p>
|
||||||
|
* @param player <p>The player to alert if anything goes wrong</p>
|
||||||
|
* @return <p>True if the player's arguments were correct</p>
|
||||||
|
*/
|
||||||
|
private boolean createGiveSign(@NotNull String[] arguments, @NotNull SignSide side, @NotNull Player player) {
|
||||||
|
File bookFile = BookFileUtil.getFile(BookDirectory.PUBLIC, null,
|
||||||
|
InputParsingUtil.mergeArguments(1, arguments));
|
||||||
|
if (bookFile == null) {
|
||||||
|
new FormatBuilder(Translatable.ERROR_LOAD_FAILED).error(player);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String separator = BooksWithoutBorders.getConfiguration().getTitleAuthorSeparator();
|
||||||
|
String bookName = bookFile.getName();
|
||||||
|
if (!bookName.contains(separator)) {
|
||||||
|
new FormatBuilder(Translatable.ERROR_SIGN_BOOK_FOUND_BUT_INVALID).error(player);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alter sign text
|
||||||
|
side.setLine(1, ChatColor.DARK_BLUE + new FormatBuilder(SignText.SIGN_GIVE).toString());
|
||||||
|
String[] parts = InputCleaningUtil.stripColor(bookName).split(separator);
|
||||||
|
String title = parts[0];
|
||||||
|
String author = BookFileUtil.stripExtensionFromPath(parts[1]);
|
||||||
|
addBookPath(side, title, 2);
|
||||||
|
addBookPath(side, author, 3);
|
||||||
|
side.setLine(3, side.getLine(3) + ":" + bookName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds part of a book path with proper formatting
|
||||||
|
*
|
||||||
|
* @param side <p>The sign side to alter</p>
|
||||||
|
* @param text <p>The text to add</p>
|
||||||
|
* @param index <p>The index of the line to alter</p>
|
||||||
|
*/
|
||||||
|
private void addBookPath(@NotNull SignSide side, @NotNull String text, int index) {
|
||||||
|
side.setLine(index, ChatColor.DARK_GREEN + text.substring(0, Math.min(text.length(), 15)) + " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -46,7 +46,7 @@ public class CommandDelete implements TabExecutor {
|
|||||||
*/
|
*/
|
||||||
protected void 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, 0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ public class CommandDelete implements TabExecutor {
|
|||||||
BooksWithoutBorders.getAvailableBooks(sender, deletePublic),
|
BooksWithoutBorders.getAvailableBooks(sender, deletePublic),
|
||||||
InputParsingUtil.mergeArguments(arguments, 0));
|
InputParsingUtil.mergeArguments(arguments, 0));
|
||||||
if (arguments.length > 1) {
|
if (arguments.length > 1) {
|
||||||
return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered);
|
return TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0);
|
||||||
} else {
|
} else {
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
@@ -58,7 +58,7 @@ public class CommandGive implements TabExecutor {
|
|||||||
*/
|
*/
|
||||||
boolean giveBook(@NotNull CommandSender sender, @NotNull String[] arguments, boolean givePublic,
|
boolean giveBook(@NotNull CommandSender sender, @NotNull String[] arguments, boolean givePublic,
|
||||||
@NotNull BookDirectory folder, @NotNull String commandName) {
|
@NotNull BookDirectory folder, @NotNull String commandName) {
|
||||||
if (PagedBookIndex.displayPage(arguments, sender, givePublic, commandName)) {
|
if (PagedBookIndex.displayPage(arguments, sender, givePublic, commandName, 0)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,11 +94,10 @@ public class CommandGive implements TabExecutor {
|
|||||||
|
|
||||||
List<String> output = new ArrayList<>();
|
List<String> output = new ArrayList<>();
|
||||||
List<String> books = BooksWithoutBorders.getAvailableBooks(sender, listPublic);
|
List<String> books = BooksWithoutBorders.getAvailableBooks(sender, listPublic);
|
||||||
List<String> filtered = TabCompletionHelper.filterMatchingContains(books,
|
List<String> filtered = TabCompletionHelper.filterMatchingContains(books, mergeArguments(arguments, 0));
|
||||||
mergeArguments(arguments, 0));
|
|
||||||
|
|
||||||
if (!filtered.isEmpty()) {
|
if (!filtered.isEmpty()) {
|
||||||
List<String> cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered);
|
List<String> cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0);
|
||||||
if (!books.contains(mergeArguments(arguments, 1))) {
|
if (!books.contains(mergeArguments(arguments, 1))) {
|
||||||
return cleaned;
|
return cleaned;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -57,7 +57,7 @@ public class CommandLoad implements TabExecutor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PagedBookIndex.displayPage(arguments, sender, loadPublic, commandName)) {
|
if (PagedBookIndex.displayPage(arguments, sender, loadPublic, commandName, 0)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ public class CommandLoad implements TabExecutor {
|
|||||||
mergeArguments(arguments, 0));
|
mergeArguments(arguments, 0));
|
||||||
|
|
||||||
if (!filtered.isEmpty()) {
|
if (!filtered.isEmpty()) {
|
||||||
List<String> cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered);
|
List<String> cleaned = TabCompletionTypeUtil.getCleanedTabCompletions(arguments, filtered, 0);
|
||||||
if (!books.contains(mergeArguments(arguments, 1))) {
|
if (!books.contains(mergeArguments(arguments, 1))) {
|
||||||
return cleaned;
|
return cleaned;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -144,6 +144,11 @@ public enum BwBCommand {
|
|||||||
* Un-signs the held signed book
|
* Un-signs the held signed book
|
||||||
*/
|
*/
|
||||||
UNSIGN_BOOK("unsignBook", true, "Unsign held book"),
|
UNSIGN_BOOK("unsignBook", true, "Unsign held book"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BwB sign from the input
|
||||||
|
*/
|
||||||
|
CREATE_BWB_SIGN("createBwBSign", true, "Create a BwB sign"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final @NotNull String commandName;
|
private final @NotNull String commandName;
|
||||||
|
@@ -38,10 +38,20 @@ public enum SignText implements TranslatableMessage {
|
|||||||
*/
|
*/
|
||||||
ERROR_SIGN_COMMAND_INVALID,
|
ERROR_SIGN_COMMAND_INVALID,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The error displayed when attempting to perform a command requiring looking at a sign, but no sign is in sight
|
||||||
|
*/
|
||||||
|
ERROR_SIGN_NOT_FOUND,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The success message displayed when successfully getting a book from a give sign
|
* The success message displayed when successfully getting a book from a give sign
|
||||||
*/
|
*/
|
||||||
SUCCESS_SIGN_GIVE,
|
SUCCESS_SIGN_GIVE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The success message displayed when a BwB sign is successfully created
|
||||||
|
*/
|
||||||
|
SUCCESS_SIGN_CREATED,
|
||||||
;
|
;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -408,6 +408,11 @@ public enum Translatable implements TranslatableMessage {
|
|||||||
* The error displayed when encryption fails
|
* The error displayed when encryption fails
|
||||||
*/
|
*/
|
||||||
ERROR_ENCRYPT_FAILED,
|
ERROR_ENCRYPT_FAILED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The error displayed when attempting to select an invalid book for a give sign
|
||||||
|
*/
|
||||||
|
ERROR_SIGN_BOOK_FOUND_BUT_INVALID,
|
||||||
;
|
;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -27,23 +27,24 @@ public abstract class BookIndex {
|
|||||||
* @param sender <p>The sender executing the command</p>
|
* @param sender <p>The sender executing the command</p>
|
||||||
* @param selectPublic <p>Whether to display public books, or only those available to the command sender</p>
|
* @param selectPublic <p>Whether to display public books, or only those available to the command sender</p>
|
||||||
* @param command <p>The command used for changing pages and making the final selection</p>
|
* @param command <p>The command used for changing pages and making the final selection</p>
|
||||||
|
* @param offset <p>The offset of arguments if other arguments exist before the book specifier</p>
|
||||||
* @return <p>True if the GUI was displayed</p>
|
* @return <p>True if the GUI was displayed</p>
|
||||||
*/
|
*/
|
||||||
public static boolean displayPage(@NotNull String[] arguments, @NotNull CommandSender sender, boolean selectPublic,
|
public static boolean displayPage(@NotNull String[] arguments, @NotNull CommandSender sender, boolean selectPublic,
|
||||||
@NotNull String command) {
|
@NotNull String command, int offset) {
|
||||||
if (arguments.length == 0) {
|
if (arguments.length == offset) {
|
||||||
PagedBookIndex.printBooks(sender, selectPublic, command, 1);
|
PagedBookIndex.printBooks(sender, selectPublic, command, 1);
|
||||||
return true;
|
return true;
|
||||||
} else if (arguments.length == 1) {
|
} else if (arguments.length == 1 + offset) {
|
||||||
int page = InputParsingUtil.parsePageNumber(arguments[0]);
|
int page = InputParsingUtil.parsePageNumber(arguments[offset]);
|
||||||
if (page > 0) {
|
if (page > 0) {
|
||||||
PagedBookIndex.printBooks(sender, selectPublic, command, page);
|
PagedBookIndex.printBooks(sender, selectPublic, command, page);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (arguments.length == 2) {
|
} else if (arguments.length == 2 + offset) {
|
||||||
String author = InputParsingUtil.parseAuthorSpecifier(arguments[0]);
|
String author = InputParsingUtil.parseAuthorSpecifier(arguments[offset]);
|
||||||
if (author != null) {
|
if (author != null) {
|
||||||
int page = InputParsingUtil.parsePageNumber(arguments[1]);
|
int page = InputParsingUtil.parsePageNumber(arguments[1 + offset]);
|
||||||
if (page > 0) {
|
if (page > 0) {
|
||||||
AuthorBookIndex.printBooks(sender, selectPublic, command, page, author);
|
AuthorBookIndex.printBooks(sender, selectPublic, command, page, author);
|
||||||
}
|
}
|
||||||
@@ -52,7 +53,7 @@ public abstract class BookIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse book author from input
|
// Parse book author from input
|
||||||
for (int authorIndex = 0; authorIndex < arguments.length; authorIndex++) {
|
for (int authorIndex = offset; authorIndex < arguments.length; authorIndex++) {
|
||||||
String author = InputParsingUtil.parseAuthorSpecifier(arguments[authorIndex]);
|
String author = InputParsingUtil.parseAuthorSpecifier(arguments[authorIndex]);
|
||||||
if (author == null) {
|
if (author == null) {
|
||||||
continue;
|
continue;
|
||||||
|
@@ -13,12 +13,12 @@ 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.knarlib.formatting.FormatBuilder;
|
import net.knarcraft.knarlib.formatting.FormatBuilder;
|
||||||
|
import net.knarcraft.knarlib.util.SignHelper;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Tag;
|
import org.bukkit.Tag;
|
||||||
import org.bukkit.block.Sign;
|
import org.bukkit.block.Sign;
|
||||||
import org.bukkit.block.sign.Side;
|
import org.bukkit.block.sign.Side;
|
||||||
import org.bukkit.block.sign.SignSide;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.Event;
|
import org.bukkit.event.Event;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@@ -68,6 +68,7 @@ public class SignEventListener implements Listener {
|
|||||||
for (int i = 0; i < lines.length; i++) {
|
for (int i = 0; i < lines.length; i++) {
|
||||||
event.setLine(i, lines[i]);
|
event.setLine(i, lines[i]);
|
||||||
}
|
}
|
||||||
|
new FormatBuilder(SignText.SUCCESS_SIGN_CREATED).success(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@@ -85,58 +86,59 @@ public class SignEventListener implements Listener {
|
|||||||
Material heldItemType = heldItem.getType();
|
Material heldItemType = heldItem.getType();
|
||||||
|
|
||||||
if (event.getClickedBlock() == null || (event.getAction() != Action.RIGHT_CLICK_BLOCK ||
|
if (event.getClickedBlock() == null || (event.getAction() != Action.RIGHT_CLICK_BLOCK ||
|
||||||
(!Tag.SIGNS.isTagged(event.getClickedBlock().getType()) &&
|
!Tag.ALL_SIGNS.isTagged(event.getClickedBlock().getType()))) {
|
||||||
!Tag.WALL_SIGNS.isTagged(event.getClickedBlock().getType())))) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return if not a valid sign
|
// Return if not a valid sign
|
||||||
if (isSignInvalid(((Sign) event.getClickedBlock().getState()).getSide(Side.FRONT).getLines(), false)) {
|
Sign sign = (Sign) event.getClickedBlock().getState();
|
||||||
|
Side side = SignHelper.getSide(sign, player);
|
||||||
|
String[] lines = sign.getSide(side).getLines();
|
||||||
|
if (isSignInvalid(lines, false)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//The player right-clicked a sign
|
//The player right-clicked a sign
|
||||||
checkSign(event, (Sign) event.getClickedBlock().getState(), heldItemType, hand);
|
checkSign(event, heldItemType, hand, lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the clicked sign is a BwB sign, and which action to take
|
* Checks if the clicked sign is a BwB sign, and which action to take
|
||||||
*
|
*
|
||||||
* @param event <p>The triggered interact event</p>
|
* @param event <p>The triggered interact event</p>
|
||||||
* @param sign <p>The clicked sign</p>
|
|
||||||
* @param heldItemType <p>The type of the held item</p>
|
* @param heldItemType <p>The type of the held item</p>
|
||||||
* @param hand <p>The hand the held item is in</p>
|
* @param hand <p>The hand the held item is in</p>
|
||||||
|
* @param lines <p>The lines of the sign</p>
|
||||||
*/
|
*/
|
||||||
private void checkSign(@NotNull PlayerInteractEvent event, @NotNull Sign sign, @NotNull Material heldItemType,
|
private void checkSign(@NotNull PlayerInteractEvent event, @NotNull Material heldItemType,
|
||||||
@NotNull EquipmentSlot hand) {
|
@NotNull EquipmentSlot hand, @NotNull String[] lines) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
event.setUseItemInHand(Event.Result.DENY);
|
event.setUseItemInHand(Event.Result.DENY);
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
|
|
||||||
SignSide front = sign.getSide(Side.FRONT);
|
SignType signType = getSignType(lines[1]);
|
||||||
SignType signType = getSignType(front.getLine(1));
|
|
||||||
if (signType == SignType.ENCRYPT) {
|
if (signType == SignType.ENCRYPT) {
|
||||||
encryptHeldBookUsingSign(sign, heldItemType, player, hand);
|
encryptHeldBookUsingSign(heldItemType, player, hand, lines);
|
||||||
} else if (signType == SignType.DECRYPT) {
|
} else if (signType == SignType.DECRYPT) {
|
||||||
decryptHeldBookUsingSign(sign, heldItemType, player, hand);
|
decryptHeldBookUsingSign(heldItemType, player, hand, lines);
|
||||||
} else if (signType == SignType.GIVE) {
|
} else if (signType == SignType.GIVE) {
|
||||||
giveBook(sign, player);
|
giveBook(player, lines);
|
||||||
} else {
|
} else {
|
||||||
new FormatBuilder(SignText.ERROR_SIGN_COMMAND_INVALID).replace(Placeholder.ACTION, front.getLine(1)).
|
new FormatBuilder(SignText.ERROR_SIGN_COMMAND_INVALID).replace(Placeholder.ACTION, lines[1]).
|
||||||
replace(Placeholder.DATA, front.getLine(2)).error(player);
|
replace(Placeholder.DATA, lines[2]).error(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts and replaces the player's used book
|
* Decrypts and replaces the player's used book
|
||||||
*
|
*
|
||||||
* @param sign <p>The clicked sign</p>
|
|
||||||
* @param heldItemType <p>The item type used to click the sign</p>
|
* @param heldItemType <p>The item type used to click the sign</p>
|
||||||
* @param player <p>The player which clicked the sign</p>
|
* @param player <p>The player which clicked the sign</p>
|
||||||
* @param hand <p>The EquipmentSlot of the used hand</p>
|
* @param hand <p>The EquipmentSlot of the used hand</p>
|
||||||
|
* @param lines <p>The lines of the sign</p>
|
||||||
*/
|
*/
|
||||||
private void decryptHeldBookUsingSign(@NotNull Sign sign, @NotNull Material heldItemType, @NotNull Player player,
|
private void decryptHeldBookUsingSign(@NotNull Material heldItemType, @NotNull Player player,
|
||||||
@NotNull EquipmentSlot hand) {
|
@NotNull EquipmentSlot hand, @NotNull String[] lines) {
|
||||||
//Decrypt the held book and replace it
|
//Decrypt the held book and replace it
|
||||||
if (heldItemType != Material.WRITTEN_BOOK) {
|
if (heldItemType != Material.WRITTEN_BOOK) {
|
||||||
return;
|
return;
|
||||||
@@ -145,7 +147,7 @@ public class SignEventListener implements Listener {
|
|||||||
player.closeInventory();
|
player.closeInventory();
|
||||||
|
|
||||||
//Converts user supplied key into integer form
|
//Converts user supplied key into integer form
|
||||||
String password = getPassword(sign.getSide(Side.FRONT).getLines());
|
String password = getPassword(lines);
|
||||||
|
|
||||||
ItemStack book = EncryptedBookUtil.loadEncryptedBook(player, password, false, false);
|
ItemStack book = EncryptedBookUtil.loadEncryptedBook(player, password, false, false);
|
||||||
if (book == null) {
|
if (book == null) {
|
||||||
@@ -161,14 +163,13 @@ public class SignEventListener implements Listener {
|
|||||||
/**
|
/**
|
||||||
* Encrypts and replaces the player's used book
|
* Encrypts and replaces the player's used book
|
||||||
*
|
*
|
||||||
* @param sign <p>The clicked sign</p>
|
|
||||||
* @param heldItemType <p>The item type used to click the sign</p>
|
* @param heldItemType <p>The item type used to click the sign</p>
|
||||||
* @param player <p>The player which clicked the sign</p>
|
* @param player <p>The player which clicked the sign</p>
|
||||||
* @param hand <p>The EquipmentSlot of the used hand</p>
|
* @param hand <p>The EquipmentSlot of the used hand</p>
|
||||||
|
* @param lines <p>The lines of the sign</p>
|
||||||
*/
|
*/
|
||||||
private void encryptHeldBookUsingSign(@NotNull Sign sign, @NotNull Material heldItemType, @NotNull Player player,
|
private void encryptHeldBookUsingSign(@NotNull Material heldItemType, @NotNull Player player,
|
||||||
@NotNull EquipmentSlot hand) {
|
@NotNull EquipmentSlot hand, @NotNull String[] lines) {
|
||||||
String[] lines = sign.getSide(Side.FRONT).getLines();
|
|
||||||
if (heldItemType != Material.WRITTEN_BOOK) {
|
if (heldItemType != Material.WRITTEN_BOOK) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -183,11 +184,11 @@ public class SignEventListener implements Listener {
|
|||||||
/**
|
/**
|
||||||
* Gives a player the book specified on a sign
|
* Gives a player the book specified on a sign
|
||||||
*
|
*
|
||||||
* @param sign <p>The sign the user clicked</p>
|
|
||||||
* @param player <p>The player which clicked the sign</p>
|
* @param player <p>The player which clicked the sign</p>
|
||||||
|
* @param lines <p>The lines of the sign</p>
|
||||||
*/
|
*/
|
||||||
private void giveBook(@NotNull Sign sign, @NotNull Player player) {
|
private void giveBook(@NotNull Player player, @NotNull String[] lines) {
|
||||||
String fileName = getBookName(sign.getSide(Side.FRONT).getLines());
|
String fileName = getBookName(lines);
|
||||||
if (fileName.isBlank()) {
|
if (fileName.isBlank()) {
|
||||||
new FormatBuilder(GiveMessage.ERROR_GIVE_LOAD_FAILED).error(player);
|
new FormatBuilder(GiveMessage.ERROR_GIVE_LOAD_FAILED).error(player);
|
||||||
return;
|
return;
|
||||||
|
@@ -40,9 +40,34 @@ public final class InputParsingUtil {
|
|||||||
* @return <p>The merged arguments</p>
|
* @return <p>The merged arguments</p>
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
public static String mergeArguments(String[] arguments, int stripLastN) {
|
public static String mergeArguments(@NotNull String[] arguments, int stripLastN) {
|
||||||
StringBuilder builder = new StringBuilder(arguments[0]);
|
return mergeArguments(0, arguments, stripLastN);
|
||||||
for (int i = 1; i < arguments.length - stripLastN; i++) {
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges all arguments to a string with spaces
|
||||||
|
*
|
||||||
|
* @param stripFirstN <p>How many of the first arguments to ignore</p>
|
||||||
|
* @param arguments <p>The arguments to merge</p>
|
||||||
|
* @return <p>The merged arguments</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static String mergeArguments(int stripFirstN, @NotNull String[] arguments) {
|
||||||
|
return mergeArguments(stripFirstN, arguments, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges all arguments to a string with spaces
|
||||||
|
*
|
||||||
|
* @param stripFirstN <p>How many of the first arguments to ignore</p>
|
||||||
|
* @param arguments <p>The arguments to merge</p>
|
||||||
|
* @param stripLastN <p>How many of the last arguments to ignore</p>
|
||||||
|
* @return <p>The merged arguments</p>
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public static String mergeArguments(int stripFirstN, @NotNull String[] arguments, int stripLastN) {
|
||||||
|
StringBuilder builder = new StringBuilder(arguments[stripFirstN]);
|
||||||
|
for (int i = stripFirstN + 1; i < arguments.length - stripLastN; i++) {
|
||||||
builder.append(" ").append(arguments[i]);
|
builder.append(" ").append(arguments[i]);
|
||||||
}
|
}
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
|
@@ -64,15 +64,16 @@ public final class TabCompletionTypeUtil {
|
|||||||
*
|
*
|
||||||
* @param arguments <p>The arguments given by the user</p>
|
* @param arguments <p>The arguments given by the user</p>
|
||||||
* @param filtered <p>Tab-completions filtered by user input</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>
|
||||||
* @return <p>The cleaned tab-completions</p>
|
* @return <p>The cleaned tab-completions</p>
|
||||||
*/
|
*/
|
||||||
public static @NotNull List<String> getCleanedTabCompletions(@NotNull String[] arguments,
|
public static @NotNull List<String> getCleanedTabCompletions(@NotNull String[] arguments,
|
||||||
@NotNull List<String> filtered) {
|
@NotNull List<String> filtered, int offset) {
|
||||||
List<String> cleaned = new ArrayList<>();
|
List<String> cleaned = new ArrayList<>();
|
||||||
for (String name : filtered) {
|
for (String name : filtered) {
|
||||||
String[] parts = name.split(" ");
|
String[] parts = name.split(" ");
|
||||||
if (parts[arguments.length - 2].equalsIgnoreCase(arguments[arguments.length - 2])) {
|
if (parts[arguments.length - 2 - offset].equalsIgnoreCase(arguments[arguments.length - 2])) {
|
||||||
StringBuilder builder = new StringBuilder(parts[arguments.length - 1]);
|
StringBuilder builder = new StringBuilder(parts[arguments.length - 1 - offset]);
|
||||||
for (int i = arguments.length; i < parts.length; i++) {
|
for (int i = arguments.length; i < parts.length; i++) {
|
||||||
builder.append(" ").append(parts[i]);
|
builder.append(" ").append(parts[i]);
|
||||||
}
|
}
|
||||||
|
@@ -239,6 +239,18 @@ commands:
|
|||||||
- bwbmigrate
|
- bwbmigrate
|
||||||
usage: /<command>
|
usage: /<command>
|
||||||
permission: bookswithoutborders.admin
|
permission: bookswithoutborders.admin
|
||||||
|
createBwBSign:
|
||||||
|
description: |
|
||||||
|
Creates a books without borders sign without having to manually create correct formatting
|
||||||
|
If creating a give sign, the second argument and so on will be treated as the book path. Use with no arguments
|
||||||
|
after give to see the book list.
|
||||||
|
If creating an encrypt or a decrypt sign, the second argument will be treated as the encryption/decryption password
|
||||||
|
If creating an encrypt sign, the optional third argument is the encryption style to use. Possible values are
|
||||||
|
"dna", "substitution", "aes", "onetimepad" and "magic"
|
||||||
|
aliases:
|
||||||
|
- bwbsign
|
||||||
|
usage: /<command> <give/encrypt/decrypt> [book identifier/password] [encryption style]
|
||||||
|
permission: bookswithoutborders.signs
|
||||||
permissions:
|
permissions:
|
||||||
bookswithoutborders.*:
|
bookswithoutborders.*:
|
||||||
description: Grants all permissions
|
description: Grants all permissions
|
||||||
|
@@ -183,7 +183,10 @@ en:
|
|||||||
# -------------- #
|
# -------------- #
|
||||||
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"
|
||||||
|
ERROR_SIGN_NOT_FOUND: "You are not looking at a sign!"
|
||||||
|
ERROR_SIGN_BOOK_FOUND_BUT_INVALID: "The book was found, but does not contain the title author separator"
|
||||||
SUCCESS_SIGN_GIVE: "Received book!"
|
SUCCESS_SIGN_GIVE: "Received book!"
|
||||||
|
SUCCESS_SIGN_CREATED: "BwB sign created successfully!"
|
||||||
# ------------ #
|
# ------------ #
|
||||||
# Placeholders #
|
# Placeholders #
|
||||||
# -------------¤
|
# -------------¤
|
||||||
|
Reference in New Issue
Block a user