{"id":13775160,"url":"https://github.com/WesJD/AnvilGUI","last_synced_at":"2025-05-11T07:32:03.955Z","repository":{"id":38550165,"uuid":"58323423","full_name":"WesJD/AnvilGUI","owner":"WesJD","description":"Capture user input in Minecraft through an anvil GUI in under 20 lines of code","archived":false,"fork":false,"pushed_at":"2025-04-13T11:51:19.000Z","size":36246,"stargazers_count":502,"open_issues_count":13,"forks_count":124,"subscribers_count":17,"default_branch":"master","last_synced_at":"2025-05-10T00:02:18.688Z","etag":null,"topics":["anvil-guis","bukkit","bukkit-plugin","gui","java","minecraft","papermc","spigot","spigot-plugin","spigotmc"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WesJD.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-05-08T17:34:04.000Z","updated_at":"2025-04-29T06:39:12.000Z","dependencies_parsed_at":"2023-01-30T04:15:36.700Z","dependency_job_id":"9815a3c5-fbaf-4fa2-89b7-23baa68af8c3","html_url":"https://github.com/WesJD/AnvilGUI","commit_stats":{"total_commits":216,"total_committers":35,"mean_commits":6.171428571428572,"dds":0.4722222222222222,"last_synced_commit":"9444848bbdde313ee1bf2ae35369469a9fa65425"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WesJD%2FAnvilGUI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WesJD%2FAnvilGUI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WesJD%2FAnvilGUI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WesJD%2FAnvilGUI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WesJD","download_url":"https://codeload.github.com/WesJD/AnvilGUI/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253533780,"owners_count":21923514,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anvil-guis","bukkit","bukkit-plugin","gui","java","minecraft","papermc","spigot","spigot-plugin","spigotmc"],"created_at":"2024-08-03T17:01:34.669Z","updated_at":"2025-05-11T07:32:03.935Z","avatar_url":"https://github.com/WesJD.png","language":"Java","readme":"# AnvilGUI [![Build Status](https://ci.codemc.io/job/WesJD/job/AnvilGUI/badge/icon)](https://ci.codemc.io/job/WesJD/job/AnvilGUI/)\nAnvilGUI is a library to capture user input in Minecraft through an anvil inventory. Anvil inventories within the realm\nof the Minecraft / Bukkit / Spigot / Paper API are extremely finnicky and ultimately don't support the ability to use them fully for\nthe task of user input. As a result, the only way to achieve user input with an anvil inventory requires interaction with obfuscated,\ndecompiled code. AnvilGUI provides a straightforward, versatile, and easy-to-use solution without having your project\ndepend on version specific code.\n\n## Requirements\n- Java 8 and Bukkit / Spigot. Most server versions in the [Spigot Repository](https://hub.spigotmc.org/nexus/) are supported.\n- Your plugin must be using Spigot mappings, Mojang mappings are not supported. This is because AnvilGUI is compiled against Spigot mappings.\n    - Note that you can still use Mojang mappings during development, if you are using the [Paperweight Userdev](https://docs.papermc.io/paper/dev/userdev) toolchain. But make sure to read the instructions below so that you enable Spigot mappings for your plugin.\n\n### How to make sure you are using Spigot mappings\n\nYou need to be using Spigot mappings in order for AnvilGUI to work, but how can you be sure that you are? The questions below will help you clear things out.\n\n1. Is your plugin a [Bukkit plugin](https://docs.papermc.io/paper/dev/plugin-yml)? Your plugin is a Bukkit plugin if it contains a `plugin.yml` file and ***does not*** contain a `paper-plugin.yml` file. In that case, by default, you are using Spigot mappings.\n    - Note that you can still use the Paper API even if your plugin is a Bukkit plugin. The Paper plugin system provides some additional features on top of the Paper API, but is not needed in order to use the Paper API.\n\n2. Is your plugin a [Paper plugin](https://docs.papermc.io/paper/dev/getting-started/paper-plugins)? Your plugin is always a Paper plugin if it contains a `paper-plugin.yml` file, even if it also contains a `plugin.yml` file. In that case, by default, you ***are not*** using Spigot mappings, but can enable them via a manifest entry [according to these instructions](https://docs.papermc.io/paper/dev/project-setup#spigot-mappings).\n\n3. Are you using the [Paperweight Userdev](https://docs.papermc.io/paper/dev/userdev) toolchain? In that case, by default, you ***are not*** using Spigot mappings, but can enable them using [the reobfArtifactConfiguration option](https://docs.papermc.io/paper/dev/userdev#compiling-to-spigot-mappings).\n\n### My version isn't supported\nIf you are a developer, submit a pull request adding a wrapper module for your version. Otherwise, please create an issue\non the issues tab.\n\n## Usage\n\n### As a dependency\n\nAnvilGUI requires the usage of Maven or a Maven compatible build system.\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003enet.wesjd\u003c/groupId\u003e\n    \u003cartifactId\u003eanvilgui\u003c/artifactId\u003e\n    \u003cversion\u003e1.10.5-SNAPSHOT\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003crepository\u003e\n    \u003cid\u003ecodemc-snapshots\u003c/id\u003e\n    \u003curl\u003ehttps://repo.codemc.io/repository/maven-snapshots/\u003c/url\u003e\n\u003c/repository\u003e\n```\n\nIt is best to be a good citizen and relocate the dependency to within your namespace in order\nto prevent conflicts with other plugins. Here is an example of how to relocate the dependency:\n```xml\n\u003cbuild\u003e\n    \u003cplugins\u003e\n        \u003cplugin\u003e\n            \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n            \u003cartifactId\u003emaven-shade-plugin\u003c/artifactId\u003e\n            \u003cversion\u003e${shade.version}\u003c/version\u003e \u003c!-- The version must be at least 3.5.0 --\u003e\n            \u003cexecutions\u003e\n                \u003cexecution\u003e\n                    \u003cphase\u003epackage\u003c/phase\u003e\n                    \u003cgoals\u003e\n                        \u003cgoal\u003eshade\u003c/goal\u003e\n                    \u003c/goals\u003e\n                    \u003cconfiguration\u003e\n                        \u003crelocations\u003e\n                            \u003crelocation\u003e\n                                \u003cpattern\u003enet.wesjd.anvilgui\u003c/pattern\u003e\n                                \u003cshadedPattern\u003e[YOUR_PLUGIN_PACKAGE].anvilgui\u003c/shadedPattern\u003e \u003c!-- Replace [YOUR_PLUGIN_PACKAGE] with your namespace --\u003e\n                            \u003c/relocation\u003e\n                        \u003c/relocations\u003e\n                        \u003cfilters\u003e\n                            \u003cfilter\u003e\n                                \u003cartifact\u003e*:*\u003c/artifact\u003e\n                                \u003cexcludeDefaults\u003efalse\u003c/excludeDefaults\u003e\n                                \u003cincludes\u003e\n                                    \u003cinclude\u003enet/wesjd/anvilgui/**\u003c/include\u003e\n                                \u003c/includes\u003e\n                            \u003c/filter\u003e\n                        \u003c/filters\u003e\n                    \u003c/configuration\u003e\n                \u003c/execution\u003e\n            \u003c/executions\u003e\n        \u003c/plugin\u003e\n    \u003c/plugins\u003e\n\u003c/build\u003e\n```\nNote: In order to solve `\u003cminimizeJar\u003e` removing AnvilGUI `VerionWrapper`s from the final jar and making the library unusable,\nensure that your `\u003cfilters\u003e` section contains the example `\u003cfilter\u003e` as seen above.\n\n### In your plugin\n\nThe `AnvilGUI.Builder` class is how you build an AnvilGUI.\nThe following methods allow you to modify various parts of the displayed GUI. Javadocs are available [here](http://docs.wesjd.net/AnvilGUI/).\n\n#### `onClose(Consumer\u003cStateSnapshot\u003e)`\nTakes a `Consumer\u003cStateSnapshot\u003e` argument that is called when a player closes the anvil gui.\n```java\nbuilder.onClose(stateSnapshot -\u003e {\n    stateSnapshot.getPlayer().sendMessage(\"You closed the inventory.\");\n});\n```\n\n#### `onClick(BiFunction\u003cInteger, AnvilGUI.StateSnapshot, AnvilGUI.ResponseAction\u003e)`\nTakes a `BiFunction` with the slot that was clicked and a snapshot of the current gui state.\nThe function is called when a player clicks any slots in the inventory.\nYou must return a `List\u003cAnvilGUI.ResponseAction\u003e`, which could include:\n- Closing the inventory (`AnvilGUI.ResponseAction.close()`)\n- Replacing the input text (`AnvilGUI.ResponseAction.replaceInputText(String)`)\n- Updating the title of the inventory (`AnvilGUI.ResponseAction.updateTitle(String, boolean)`)\n- Opening another inventory (`AnvilGUI.ResponseAction.openInventory(Inventory)`)\n- Running generic code (`AnvilGUI.ResponseAction.run(Runnable)`)\n- Nothing! (`Collections.emptyList()`)\n\nThe list of actions are ran in the order they are supplied.\n```java\nbuilder.onClick((slot, stateSnapshot) -\u003e {\n    if (slot != AnvilGUI.Slot.OUTPUT) {\n        return Collections.emptyList();\n    }\n\n    if (stateSnapshot.getText().equalsIgnoreCase(\"you\")) {\n        stateSnapshot.getPlayer().sendMessage(\"You have magical powers!\");\n        return Arrays.asList(\n            AnvilGUI.ResponseAction.close(),\n            AnvilGUI.ResponseAction.run(() -\u003e myCode(stateSnapshot.getPlayer()))\n        );\n    } else {\n        return Arrays.asList(AnvilGUI.ResponseAction.replaceInputText(\"Try again\"));\n    }\n});\n```\n\n#### `onClickAsync(ClickHandler)`\nTakes a `ClickHandler`, a shorthand for `BiFunction\u003cInteger, AnvilGui.StateSnapshot, CompletableFuture\u003cAnvilGUI.ResponseAction\u003e\u003e`,\nthat behaves exactly like `onClick()` with the difference that it returns a `CompletableFuture` and therefore allows for\nasynchronous calculation of the `ResponseAction`s.\n\n```java\nbuilder.onClickAsync((slot, stateSnapshot) -\u003e CompletedFuture.supplyAsync(() -\u003e {\n    // this code is now running async\n    if (slot != AnvilGUI.Slot.OUTPUT) {\n        return Collections.emptyList();\n    }\n\n    if (database.isMagical(stateSnapshot.getText())) {\n        // the `ResponseAction`s will run on the main server thread\n        return Arrays.asList(\n            AnvilGUI.ResponseAction.close(),\n            AnvilGUI.ResponseAction.run(() -\u003e myCode(stateSnapshot.getPlayer()))\n        );\n    } else {\n        return Arrays.asList(AnvilGUI.ResponseAction.replaceInputText(\"Try again\"));\n    }\n}));\n```\n\n#### `allowConcurrentClickHandlerExecution()`\nTells the AnvilGUI to disable the mechanism that is put into place to prevent concurrent execution of the\nclick handler set by `onClickAsync(ClickHandler)`.\n```java\nbuilder.allowConcurrentClickHandlerExecution();\n```\n\n#### `interactableSlots(int... slots)`\nThis allows or denies users to take / input items in the anvil slots that are provided. This feature is useful when you try to make a inputting system using an anvil gui.\n```java\nbuilder.interactableSlots(Slot.INPUT_LEFT, Slot.INPUT_RIGHT);\n```\n\n#### `preventClose()`\nTells the AnvilGUI to prevent the user from pressing escape to close the inventory.\nUseful for situations like password input to play.\n```java\nbuilder.preventClose();\n```\n\n#### `geyserCompat()`\nThis toggles compatibility with Geyser software, specifically being able to use AnvilGUI with 0 experience level on Bedrock.\nEnabled by default.\n```java\nbuilder.geyserCompat();\n```\n\n#### `text(String)`\nTakes a `String` that contains what the initial text in the renaming field should be set to.\nIf `itemLeft` is provided, then the display name is set to the provided text. If no `itemLeft`\nis set, then a piece of paper will be used.\n```java\nbuilder.text(\"What is the meaning of life?\");\n```\n\n#### `itemLeft(ItemStack)`\nTakes a custom `ItemStack` to be placed in the left input slot.\n```java\nItemStack stack = new ItemStack(Material.IRON_SWORD);\nItemMeta meta = stack.getItemMeta();\nmeta.setLore(Arrays.asList(\"Sharp iron sword\"));\nstack.setItemMeta(meta);\nbuilder.itemLeft(stack);\n```\n\n#### `itemRight(ItemStack)`\nTakes a custom `ItemStack` to be placed in the right input slot.\n```java\nItemStack stack = new ItemStack(Material.IRON_INGOT);\nItemMeta meta = stack.getItemMeta();\nmeta.setLore(Arrays.asList(\"A piece of metal\"));\nstack.setItemMeta(meta);\nbuilder.itemRight(stack);\n```\n\n#### `title(String)`\nTakes a `String` that will be used literally as the inventory title. Only displayed in Minecraft 1.14 and above.\n```java\nbuilder.title(\"Enter your answer\");\n```\n\n#### `jsonTitle(String)`\nTakes a `String` which contains rich text components serialized as JSON.\nUseful for settings titles with hex color codes or Adventure Component interop.\nOnly displayed in Minecraft 1.14 and above.\n```java\nbuilder.jsonTitle(\"{\\\"text\\\":\\\"Enter your answer\\\",\\\"color\\\":\\\"green\\\"}\")\n```\n\n#### `plugin(Plugin)`\nTakes the `Plugin` object that is making this anvil gui. It is needed to register listeners.\n```java\nbuilder.plugin(pluginInstance);\n```\n\n#### `mainThreadExecutor(Executor)`\nTakes an `Executor` that must execute on the main server thread.\nIf the main server thread is not accessible via the Bukkit scheduler, like on Folia servers, it can be swapped for a\nFolia aware executor.\n```java\nbuilder.mainThreadExecutor(executor);\n```\n\n#### `open(Player)`\nTakes a `Player` that the anvil gui should be opened for. This method can be called multiple times without needing to create\na new `AnvilGUI.Builder` object.\n```java\nbuilder.open(player);\n```\n\n### A Common Use Case Example\n```java\nnew AnvilGUI.Builder()\n    .onClose(stateSnapshot -\u003e {\n        stateSnapshot.getPlayer().sendMessage(\"You closed the inventory.\");\n    })\n    .onClick((slot, stateSnapshot) -\u003e { // Either use sync or async variant, not both\n        if(slot != AnvilGUI.Slot.OUTPUT) {\n            return Collections.emptyList();\n        }\n\n        if(stateSnapshot.getText().equalsIgnoreCase(\"you\")) {\n            stateSnapshot.getPlayer().sendMessage(\"You have magical powers!\");\n            return Arrays.asList(AnvilGUI.ResponseAction.close());\n        } else {\n            return Arrays.asList(AnvilGUI.ResponseAction.replaceInputText(\"Try again\"));\n        }\n    })\n    .preventClose()                                                    //prevents the inventory from being closed\n    .text(\"What is the meaning of life?\")                              //sets the text the GUI should start with\n    .title(\"Enter your answer.\")                                       //set the title of the GUI (only works in 1.14+)\n    .plugin(myPluginInstance)                                          //set the plugin instance\n    .open(myPlayer);                                                   //opens the GUI for the player provided\n```\n\n\n## Development\nWe use Maven to handle our dependencies. Run `mvn clean install` using Java 21 to build the project.\n\n### Spotless\nThe project utilizes the [Spotless Maven Plugin](https://github.com/diffplug/spotless/tree/main/plugin-maven) to\nenforce style guidelines. You will not be able to build the project if your code does not meet the guidelines.\nTo fix all code formatting issues, simply run `mvn spotless:apply`.\n\n## License\nThis project is licensed under the [MIT License](LICENSE).\n","funding_links":[],"categories":["Inventories"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWesJD%2FAnvilGUI","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FWesJD%2FAnvilGUI","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FWesJD%2FAnvilGUI/lists"}