Clickable TEXT in Written Books

Discussion in 'Spigot Plugin Development' started by yhl, Apr 17, 2018.

  1. yhl

    yhl

    Hey! I'm currently working on a small server and I need a way to make clickable text in written books. I did this a while ago but what ended up happening was the whole page was clickable and I didn't really like that. I know this is possible, because I've seen it on some servers. If you know how to do this please help me out! Also, I haven't coded in Spigot in a while so I might be a complete noob in some areas (sorry!).
     
  2. Optic_Fusion1

    Resource Staff

    Give me a bit, i think i have something for this :eek:
     
    • Funny Funny x 1
  3. Optic_Fusion1

    Resource Staff

    You'll need NMS and such for this however this is taken directly out of my private plugin
    There's a method to view the book, as well as two examples ^.^
    This could probably be done better however xD

    Code (Text):

    package opticscore.Core.utils;

    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import java.util.List;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import net.md_5.bungee.api.chat.BaseComponent;
    import net.md_5.bungee.api.chat.ClickEvent;
    import net.md_5.bungee.api.chat.ComponentBuilder;
    import net.md_5.bungee.api.chat.HoverEvent;
    import net.md_5.bungee.api.chat.TextComponent;
    import net.md_5.bungee.chat.ComponentSerializer;
    import org.bukkit.Material;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.BookMeta;
    import net.minecraft.server.v1_12_R1.PacketPlayOutCustomPayload;
    import net.minecraft.server.v1_12_R1.PacketDataSerializer;
    import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
    import net.minecraft.server.v1_12_R1.IChatBaseComponent;
    import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftMetaBook;
    import org.bukkit.entity.Player;

    public class Books {

        public static ItemStack getRuleBook() {
            try {
                ItemStack book = new ItemStack(Material.WRITTEN_BOOK);
                BookMeta meta = (BookMeta) book.getItemMeta();
                List<IChatBaseComponent> pages = (List<IChatBaseComponent>) CraftMetaBook.class.getDeclaredField("pages").get(meta);
                TextComponent text = new TextComponent(Utils.bookColorize("&l&cRules (Hover over the Rule to see what it is)&r\n\n"));
                TextComponent rules = new TextComponent(new ComponentBuilder("Rule 1").event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("No Swearing").create())).create());
                IChatBaseComponent page = IChatBaseComponent.ChatSerializer.a(ComponentSerializer.toString(new BaseComponent[]{text, rules}));
                pages.add(page);
                meta.setTitle("Example");
                meta.setAuthor("Optics Server");
                book.setItemMeta(meta);
                return book;
            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
                Logger.getLogger(Books.class.getName()).log(Level.SEVERE, null, ex);
            }
            return null;
        }


        //These are the two you'll want
        public static void openBook(ItemStack book, Player p) {
            int slot = p.getInventory().getHeldItemSlot();
            ItemStack old = p.getInventory().getItem(slot);
            p.getInventory().setItem(slot, book);

            ByteBuf buf = Unpooled.buffer(256);
            buf.setByte(0, (byte) 0);
            buf.writerIndex(1);

            PacketPlayOutCustomPayload packet = new PacketPlayOutCustomPayload("MC|BOpen", new PacketDataSerializer(buf));
            ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet);
            p.getInventory().setItem(slot, old);
        }

        public static ItemStack getExampleBook() {
            try {
                ItemStack book = new ItemStack(Material.WRITTEN_BOOK);
                BookMeta meta = (BookMeta) book.getItemMeta();
                List<IChatBaseComponent> pages = (List<IChatBaseComponent>) CraftMetaBook.class.getDeclaredField("pages").get(meta);
                TextComponent text = new TextComponent("§l§cExample\n");
                TextComponent msg = new TextComponent("§l§bClick me to go to spigotmc.org!\n");
                msg.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "http://www.spigotmc.org"));
                msg.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder("HI").create()));
                TextComponent msg2 = new TextComponent("§l§aClick me to go to spawn");
                msg2.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/spawn"));
                IChatBaseComponent page = IChatBaseComponent.ChatSerializer.a(ComponentSerializer.toString(new BaseComponent[]{text, msg, msg2}));
                pages.add(page);
                meta.setTitle("Example");
                meta.setAuthor("Optics Server");
                book.setItemMeta(meta);
                return book;
            } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
                Logger.getLogger(Books.class.getName()).log(Level.SEVERE, null, ex);
            }
            return null;
        }
    }

     
    Edit: https://www.spigotmc.org/wiki/the-chat-component-api/
     
    • Friendly Friendly x 1
  4. yhl

    yhl

    It won't open ;(

    EDIT: NVM @Optic_Fusion1 ILY <3
     
    • Friendly Friendly x 1
  5. Optic_Fusion1

    Resource Staff

    What's the error?
     
  6. yhl

    yhl

    read the edit :3
     
  7. Optic_Fusion1

    Resource Staff

    :3