AnvilGUI Documentation

repository·master·Indexed 20 days ago

https://github.com/wesjd/anvilgui

A Minecraft Java Edition library that allows developers to capture user input via an anvil inventory interface without writing version-specific code. It provides a builder-based API to configure titles, input text, click handlers (synchronous and asynchronous), and inventory behavior, including Geyser compatibility and support for Folia servers.

Tokens
3.1K
Snippets
7
Records
10
Agent score
19%

What's inside AnvilGUI

  1. Install AnvilGUI via Maven

    master

    To use AnvilGUI, add the mvn-wesjd-net repository and the anvilgui dependency to your pom.xml.

    Note: As of version 1.10.11-SNAPSHOT, the Maven repository has moved from CodeMC to https://mvn.wesjd.net/.

    <repository>
        <id>mvn-wesjd-net</id>
        <url>https://mvn.wesjd.net/</url>
    </repository>
    
    <dependency>
      <groupId>net.wesjd</groupId>
      <artifactId>anvilgui</artifactId>
      <version>1.10.13-SNAPSHOT</version>
      <scope>compile</scope>
    </dependency>
  2. Configure AnvilGUI using AnvilGUI.Builder

    master

    The AnvilGUI.Builder class is the primary interface for configuring an anvil inventory and opening it for a player. You use the builder to define how the GUI responds to clicks, what items are displayed, the title, and other behavioral constraints before calling .open(Player).

    new AnvilGUI.Builder()
        .onClose(stateSnapshot -> {
            stateSnapshot.getPlayer().sendMessage("You closed the inventory.");
        })
        .onClick((slot, stateSnapshot) -> {
            if(slot != AnvilGUI.Slot.OUTPUT) {
                return Collections.emptyList();
            }
    
            if(stateSnapshot.getText().equalsIgnoreCase("you")) {
                stateSnapshot.getPlayer().sendMessage("You have magical powers!");
                return Arrays.asList(AnvilGUI.ResponseAction.close());
            } else {
                return Arrays.asList(AnvilGUI.ResponseAction.replaceInputText("Try again"));
            }
        })
        .preventClose()
        .text("What is the meaning of life?")
        .title("Enter your answer.")
        .plugin(myPluginInstance)
        .open(myPlayer);
  3. Shade and Relocate AnvilGUI in your plugin

    master

    AnvilGUI is a library and must be shaded into your plugin JAR. To prevent classpath conflicts with other plugins using different versions of AnvilGUI, you should relocate the library to your plugin's namespace.

    Additionally, because AnvilGUI loads its implementation via reflection, you must configure the maven-shade-plugin to include the entire library to prevent the 'minimize JAR' feature from omitting necessary classes.

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>${shade.version}</version> <!-- Must be at least 3.5.0 -->
      <executions>
        <execution>
          <phase>package</phase>
          <goals>
            <goal>shade</goal>
          </goals>
          <configuration>
            <relocations>
              <relocation>
                <pattern>net.wesjd.anvilgui</pattern>
                <shadedPattern>[YOUR_PLUGIN_PACKAGE].anvilgui</shadedPattern>
              </relocation>
            </relocations>
            <filters>
              <filter>
                <artifact>*:*</artifact>
                <excludeDefaults>false</excludeDefaults>
                <includes>
                  <include>net/wesjd/anvilgui/**</include>
                </includes>
              </filter>
            </filters>
          </configuration>
        </execution>
      </executions>
    </plugin>
  4. Configure Spigot mappings for Paper plugins

    master

    AnvilGUI is compiled against Spigot mappings. Mojang mappings are not supported at runtime.

    • Bukkit Plugins: Use Spigot mappings by default. No extra configuration is needed.
    • Paper Plugins: These do not use Spigot mappings by default. If your plugin contains a paper-plugin.yml, you must explicitly enable Spigot mappings via your manifest or use the reobfArtifactConfiguration option in the Paperweight Userdev toolchain to reobfuscate your plugin to Spigot mappings.
  5. Quickstart: Create an AnvilGUI instance

    master

    Use the AnvilGUI.Builder to create an interactive anvil interface. You can define behavior for when the inventory is closed (onClose), what happens when slots are clicked (onClick), and set the initial text and title.

    Common ResponseAction methods include close() and replaceInputText(String).

    new AnvilGUI.Builder()
        .onClose(stateSnapshot -> {
            stateSnapshot.getPlayer().sendMessage("You closed the inventory.");
        })
        .onClick((slot, stateSnapshot) -> {
            if(slot != AnvilGUI.Slot.OUTPUT) {
                return Collections.emptyList();
            }
    
            if(stateSnapshot.getText().equalsIgnoreCase("you")) {
                stateSnapshot.getPlayer().sendMessage("You have magical powers!");
                return Arrays.asList(AnvilGUI.ResponseAction.close());
            } else {
                return Arrays.asList(AnvilGUI.ResponseAction.replaceInputText("Try again"));
            }
        })
        .preventClose()
        .text("What is the meaning of life?")
        .title("Enter your answer")
        .plugin(plugin)
        .open(player);
  6. Configure AnvilGUI lifecycle and execution environment

    master

    Methods for managing the plugin integration and thread execution:

    • onClose(Consumer<StateSnapshot>): A callback triggered when the player closes the GUI. The StateSnapshot provides access to the Player.
    • plugin(Plugin): Requires the Plugin instance that is creating the GUI to register necessary listeners.
    • mainThreadExecutor(Executor): Specifies the Executor used to run code on the main server thread. This is required for Folia servers where the standard Bukkit scheduler may not be accessible.
    • open(Player): Opens the configured GUI for the specified player. This can be called multiple times on the same builder instance.
  7. Control AnvilGUI behavior and restrictions

    master

    Customize how the player interacts with the GUI:

    • preventClose(): Prevents the user from closing the inventory by pressing Escape. Useful for mandatory inputs like passwords.
    • interactableSlots(int... slots): Defines which slots the user is allowed to input items into or take items from. Useful for creating custom input systems.
    • allowConcurrentClickHandlerExecution(): Disables the mechanism that prevents concurrent execution of the onClickAsync handler.
    • geyserCompat(): Toggles compatibility with Geyser (enabled by default), allowing AnvilGUI usage with 0 experience level on Bedrock Edition.
  8. Handle click events with onClick() and onClickAsync()

    master

    You can intercept player clicks using two methods. Note that you should use either the synchronous onClick() or the asynchronous onClickAsync(), but not both.

    onClick(BiFunction<Integer, AnvilGUI.StateSnapshot, List<AnvilGUI.ResponseAction>>)

    Called when a player clicks any slot. It receives the clicked slot index and a StateSnapshot. You must return a List of AnvilGUI.ResponseActions.

    onClickAsync(ClickHandler)

    Identical to onClick(), but returns a CompletableFuture<AnvilGUI.ResponseAction>. This allows you to perform asynchronous calculations (like database lookups) before returning the actions. The resulting actions will be executed on the main server thread.

    Available AnvilGUI.ResponseActions:

    • AnvilGUI.ResponseAction.close(): Closes the inventory.
    • AnvilGUI.ResponseAction.replaceInputText(String): Replaces the current input text.
    • AnvilGUI.ResponseAction.updateTitle(String, boolean): Updates the inventory title.
    • AnvilGUI.ResponseAction.openInventory(Inventory): Opens a different inventory.
    • AnvilGUI.ResponseAction.run(Runnable): Executes generic code.
    • Collections.emptyList(): Performs no action.
    // Synchronous example
    builder.onClick((slot, stateSnapshot) -> {
        if (slot != AnvilGUI.Slot.OUTPUT) {
            return Collections.emptyList();
        }
    
        if (stateSnapshot.getText().equalsIgnoreCase("you")) {
            return Arrays.asList(AnvilGUI.ResponseAction.close());
        } else {
            return Arrays.asList(AnvilGUI.ResponseAction.replaceInputText("Try again"));
        }
    });
    
    // Asynchronous example
    builder.onClickAsync((slot, stateSnapshot) -> CompletedFuture.supplyAsync(() -> {
        if (database.isMagical(stateSnapshot.getText())) {
            return Arrays.asList(AnvilGUI.ResponseAction.close());
        } else {
            return Arrays.asList(AnvilGUI.ResponseAction.replaceInputText("Try again"));
        }
    }));
  9. Configure AnvilGUI inventory contents and text

    master

    Use the following methods to set the initial state of the anvil slots and the text field:

    • text(String): Sets the initial text in the renaming field. If itemLeft is not provided, a piece of paper is used as the base item. If itemLeft is provided, the display name is set to this text.
    • itemLeft(ItemStack): Places a custom ItemStack in the left input slot.
    • itemRight(ItemStack): Places a custom ItemStack in the right input slot.
    builder.text("Initial text")
           .itemLeft(new ItemStack(Material.IRON_SWORD))
           .itemRight(new ItemStack(Material.IRON_INGOT));
  10. Set AnvilGUI title and JSON title

    master

    For Minecraft 1.14 and above, you can customize the inventory title:

    • title(String): Sets a literal string as the inventory title.
    • jsonTitle(String): Sets a title using a JSON-serialized rich text component. This is useful for using hex colors or Adventure Component interop.
    builder.title("Enter your answer");
    builder.jsonTitle("{\"text\":\"Enter your answer\",\"color\":\"green\"}");