Skip to content
Lorenzo Rossi edited this page Nov 30, 2021 · 8 revisions
  1. What is BookApi
  2. Setup
  3. Open book to player
  4. Create book
  5. More

What is BookApi


Books were never used a lot in the plugin-dev community, spigot and bukkit never implemented a good way to edit books to a certain level. Only spigot added a BookMeta#setPages that... didn't offer book interactivity :/

This is what the first part of the API (and the one with more reflection) is all about. The second one is to help the developers to write interactable code in a more user-friendly way. The Chat-Component API is really powerful but in some cases it could be not really dev-friendly. The utility code in the second part of the API is just a Set of Chat-Component builders. That provides complete interoperatibility between the ChatComponent API and the BookApi while providing the developer an easier way to write books.

Setup


The BookApi is on maven central, so you just need to add it to the dependencies:

<dependencies>
  ...
  <dependency>
    <groupId>xyz.upperlevel.spigot.book</groupId>
    <artifactId>spigot-book-api</artifactId>
    <version>1.6</version>
  </dependency>
</dependencies>

The BookApi isn't a plugin in its own so you need to add it to your final jar. One way to do this is creating an uber-jar with maven-shade-plugin, just add this to your pom.xml (if you hadn't already done it):

<build>
    ...
    <plugins>
        ...
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.3</version>
            <executions>
                <!-- Run shade goal on package phase -->
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Open Book to Player


To open an already-created book you just write BookUtil.openPlayer(player, book); and that's all you need to know about BookApi if you already have a way to create books. If you don't have one, or if you want to see how does our API manage it, just hang on and continue to read.

Event

The event CustomBookOpenEvent gets called when a book is opened trough this Util

Create Book


BookUtil has also some utils that help you to create the book, wrapping BookMeta's instance in a more dev-friendly interface. With that we can easily set the book's author, title and generation (do NOT use generation if you want to be compaible with versions <= 1.9!). Apart from the things already settable in the BookMeta there's one other thing that (apart from the chainable methods) discerns the BookBuilder from the spigot's BookMeta: you can set the pages as BaseComponent arrays: pages(BaseComponent[]... pages).

This means that you can set the pages of the book using md_5's ChatComponent API or, if you're not a fan of it, a different API that generates BaseComponent[].

NOTE: you can transform Json strings into BaseComponent arrays using NmsBookHelper.jsonToComponents(jsonString);

The PageBuilder and TextBuilder

There already some built-in tools to create interactable book pages, those are BookUtil's Text and Page Builders. The PageBuilder is a class that joins BaseComponents, those components could be generated from ChatComponent API, TextBuilder or any other BaseComponent creator.

The TextBuilder is a wrapper of the ChatComponent API that helps the developer to create components in an easier way. You can set the text color using builder.color(ChatColor), the styles using builder.style(ChatColor...) (don't mix the colors with the styles, otherwise an error will be thrown), the text using builder.text(String), and the events using builder.onClick(ClickAction) and builder.onHover(HoverAction)

ClickActions

To create the ClickAction instances that the builder wants you must use the methods provided within ClickAction's class:

  • runCommand(command: String) -> runs a command (with the clicker as CommandSender)
  • suggestCommand(command: Strign) -> opens the player's chat and types the command in it (doesn't work in all versions for client-sided bugs)
  • openUrl(url: String) -> opens the url specified as argument, (it must be a valid url and it must begin with "http://" or "https://" or it won't event be clickable)
  • changePage(page: Int) -> changes the page that the player is viewing, 1 is the page while pages.lengrh - 1 is the last

HoverActions

To create the HoverAction instances that the builder wants you must use the methods provided within the HoverAction:

  • showText(String | BaseComponent...) -> Shows the text (or components) to the player, this is the most useful and the most supported of the Hover actions because it permits the developer to set what the user will see
  • showEntity(BaseComponent... | Entity) -> Shows some of the entity's information
  • showEntity(uuid: UUID, type: String, name: String) -> the same of the others, but you specify the entity's details yourself
  • showAchievement(Achievement | String) -> Shows some infos regarding the achievement
  • showStatistic(statisticId: String) -> Shows some infos regarding the statistic (here's the ids)

Some examples

Those are all code snippets taken from the project tests.

private ItemStack createCommandBook(Player p) {
  return BookUtil.writtenBook()
      .author("SnowyCoder")
      .title("Command test")
      .pages(
          new BookUtil.PageBuilder()
              .add(
                  BookUtil.TextBuilder.of("Kill yasself")
                      .onHover(BookUtil.HoverAction.showText("Do it!"))
                      .onClick(BookUtil.ClickAction.runCommand("/kill"))
                      .color(ChatColor.RED)
                      .build()
              )
              .newLine()
              .add(
                  BookUtil.TextBuilder.of("Auto Kick")
                      .onHover(BookUtil.HoverAction.showText("Useful!"))
                      .onClick(BookUtil.ClickAction.runCommand("/kick " + p.getName()))
                      .color(ChatColor.YELLOW)
                      .build()
              )
              .build()
      )
      .build();
}
private ItemStack createGeneralBook(Player p) {
    return BookUtil.writtenBook()
        .author("SnowyCoder")
        .title("The Test-ament")
        .pages(
            new BaseComponent[]{
                new TextComponent("Introduction page")
            },
            new BookUtil.PageBuilder()
                .add(new TextComponent("visit "))
                .add(
                    BookUtil.TextBuilder.of("Spigot")
                        .color(ChatColor.GOLD)
                        .style(ChatColor.BOLD, ChatColor.ITALIC)
                        .onClick(BookUtil.ClickAction.openUrl("https://www.spigotmc.org"))
                        .onHover(BookUtil.HoverAction.showText("Open spigot!"))
                        .build()
                )
                .add(" or ")
                .add(
                    new ComponentBuilder("Bukkit")
                        .color(net.md_5.bungee.api.ChatColor.BLUE)
                        .bold(true)
                        .italic(true)
                        .event(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://bukkit.org"))
                        .event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new BaseComponent[]{new TextComponent("Open bukkit!")}))
                        .create()
                )
                .newLine()
                .add("I think that the ")
                .add(
                    BookUtil.TextBuilder.of("TextBuilder")
                        .color(ChatColor.AQUA)
                        .style(ChatColor.BOLD)
                        .onClick(BookUtil.ClickAction.changePage(3))
                        .onHover(BookUtil.HoverAction.showText("TextBuilder's page"))
                        .build()
                )
                .add(" is really useful to ")
                .add(
                    BookUtil.TextBuilder.of("you")
                        .color(ChatColor.AQUA)
                        .style(ChatColor.BOLD)
                        .onClick(BookUtil.ClickAction.runCommand("/kill"))//lol
                        .onHover(BookUtil.HoverAction.showText("Kill yasself"))
                        .build()
                )
                .build(),
             new BookUtil.PageBuilder()
                .add("TextBuilder's page")
                .newLine().newLine()
                .add("Isn't this amazing?")
                .build()
        )
        .build();
}

Moar


The example works only from MC 1.10 but the rest of the API is compatible with all MC versions down to 1.8 (missing api), The only thing that isn't always compatible is the BookBuilder's generation, but if the developer doesn't call it there's no problem at all.

If you find bugs or if you want to suggest us something use the GitHub's issue-management system