Tested and working on 1.9~1.11.2. Originally invented by MysteX [here] (NMS version, does not require ProtocolLib). Intro Yes there is a way. You may force a player to open a book server side. The key to the problem is that server can ask a client to open a book on his hand. If you want the player to open any book, just set that book on his hand briefly and put the original item back. Prerequisite 1. ProtocolLib 2. You have a book as an ItemStack. The following code will have a book ItemStack defined as "bookitem". Code Code (Text): int slot = p.getInventory().getHeldItemSlot(); ItemStack old = p.getInventory().getItem(slot); p.getInventory().setItem(slot, bookitem); try { PacketContainer pc = ProtocolLibrary.getProtocolManager(). createPacket(PacketType.Play.Server.CUSTOM_PAYLOAD); pc.getModifier().writeDefaults(); ByteBuf bf = Unpooled.buffer(256); // note 1 bf.setByte(0, (byte)0); // note 2 bf.writerIndex(1); pc.getModifier().write(1, MinecraftReflection.getPacketDataSerializer(bf)); pc.getStrings().write(0, "MC|BOpen"); ProtocolLibrary.getProtocolManager().sendServerPacket(p, pc); } catch (Exception e) { e.printStackTrace(); } p.getInventory().setItem(slot, old); * note 1: ButeBuf is a class from Netty. * note 2: The second argument, (byte)0 refers to open the book on which hand. If you want the player to open the book on his offhand for any reason, use (byte)1.
i dont see a reason to use protocollib, here's the one i use, without: Code (Java): int slot = player.getInventory().getHeldItemSlot(); ItemStack original = player.getInventory().getItem(slot); player.getInventory().setItem(slot, ItemStack); ByteBuf buf = Unpooled.buffer(256); buf.setByte(0, (byte) 0); buf.writerIndex(1); PacketPlayOutCustomPayload packet = new PacketPlayOutCustomPayload("MC|BOpen", new PacketDataSerializer(buf)); ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet); player.getInventory().setItem(slot, original);