diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 098812de1..4925ced5c 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -29,6 +29,7 @@ import net.minestom.server.inventory.Inventory; import net.minestom.server.inventory.PlayerInventory; import net.minestom.server.item.ItemStack; import net.minestom.server.item.Material; +import net.minestom.server.item.metadata.WrittenBookMeta; import net.minestom.server.listener.PlayerDiggingListener; import net.minestom.server.network.ConnectionManager; import net.minestom.server.network.ConnectionState; @@ -1084,6 +1085,30 @@ public class Player extends LivingEntity implements CommandSender { playerConnection.sendPacket(titlePacket); } + /** + * Opens a book ui for the player with the given book metadata. + * + * @param bookMeta The metadata of the book to open + */ + public void openBook(@NotNull WrittenBookMeta bookMeta) { + // Set book in offhand + final ItemStack writtenBook = new ItemStack(Material.WRITTEN_BOOK, (byte) 1); + writtenBook.setItemMeta(bookMeta); + final SetSlotPacket setSlotPacket = new SetSlotPacket(); + setSlotPacket.windowId = 0; + setSlotPacket.slot = 45; + setSlotPacket.itemStack = writtenBook; + this.playerConnection.sendPacket(setSlotPacket); + + // Open the book + final OpenBookPacket openBookPacket = new OpenBookPacket(); + openBookPacket.hand = Hand.OFF; + this.playerConnection.sendPacket(openBookPacket); + + // Update inventory to remove book (which the actual inventory does not have) + this.inventory.update(); + } + @Override public boolean isImmune(@NotNull DamageType type) { if (!getGameMode().canTakeDamage()) { diff --git a/src/test/java/demo/Main.java b/src/test/java/demo/Main.java index 1a9f0401f..6970eb89a 100644 --- a/src/test/java/demo/Main.java +++ b/src/test/java/demo/Main.java @@ -41,6 +41,7 @@ public class Main { commandManager.register(new PlayersCommand()); commandManager.register(new PotionCommand()); commandManager.register(new TitleCommand()); + commandManager.register(new BookCommand()); commandManager.setUnknownCommandCallback((sender, command) -> sender.sendMessage("unknown command")); diff --git a/src/test/java/demo/commands/BookCommand.java b/src/test/java/demo/commands/BookCommand.java new file mode 100644 index 000000000..ef2a9be7f --- /dev/null +++ b/src/test/java/demo/commands/BookCommand.java @@ -0,0 +1,45 @@ +package demo.commands; + +import net.minestom.server.chat.ChatColor; +import net.minestom.server.chat.ColoredText; +import net.minestom.server.command.CommandSender; +import net.minestom.server.command.builder.Arguments; +import net.minestom.server.command.builder.Command; +import net.minestom.server.entity.Player; +import net.minestom.server.item.metadata.WrittenBookMeta; + +import java.util.List; + +public class BookCommand extends Command { + public BookCommand() { + super("book"); + + setCondition(this::playerCondition); + + setDefaultExecutor(this::execute); + } + + private boolean playerCondition(CommandSender sender, String commandString) { + if (!sender.isPlayer()) { + sender.sendMessage("The command is only available for players"); + return false; + } + return true; + } + + private void execute(CommandSender sender, Arguments args) { + Player player = sender.asPlayer(); + + final WrittenBookMeta bookMeta = new WrittenBookMeta(); + bookMeta.setAuthor(player.getUsername()); + bookMeta.setGeneration(WrittenBookMeta.WrittenBookGeneration.ORIGINAL); + bookMeta.setTitle(player.getUsername() + "'s Book"); + bookMeta.setPages(List.of( + ColoredText.of(ChatColor.RED, "Page one"), + ColoredText.of(ChatColor.BRIGHT_GREEN, "Page two"), + ColoredText.of(ChatColor.BLUE, "Page three") + )); + + player.openBook(bookMeta); + } +}