> ## Documentation Index
> Fetch the complete documentation index at: https://wiki.refineryteam.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Interaction Prompts

> Capturing free-text input from players via chat or an anvil GUI.

`xyz.refineryteam.refinerycore.api.interaction` provides two ways to capture free-text input from a player without them leaving the flow of your plugin: chat-based prompts and anvil-based prompts. (For a fixed yes/no choice instead of free text, see [`ConfirmationGUI`](/refinerycore/gui#confirmation-dialogs-confirmationgui).)

## Chat prompts — `ChatPrompt`

Captures the player's next chat message instead of letting it reach public chat — useful for ban reasons, custom amounts, search terms, and similar.

<Note>
  Call `PromptRegistry.install(plugin)` once during your plugin's `onEnable()` before using `ChatPrompt` anywhere. This registers the shared chat/quit listener exactly once per JVM, even if multiple plugins depend on RefineryCore.
</Note>

```java BanCommand.java icon="java" theme={"system"}
ChatPrompt.of(plugin, player)
    .prompt("<gray>Type a reason for the ban, or 'cancel' to abort:")
    .timeoutSeconds(30)
    .onInput(reason -> banPlayer(target, reason))
    .onCancel(() -> player.sendMessage(EasyMiniMessage.format("<red>Cancelled.")))
    .onTimeout(() -> player.sendMessage(EasyMiniMessage.format("<red>Timed out.")))
    .send();
```

Builder methods:

| Method                      | Description                                                                         |
| --------------------------- | ----------------------------------------------------------------------------------- |
| `prompt(String)`            | MiniMessage message sent immediately when the prompt is registered                  |
| `cancelKeyword(String)`     | The word a player can type to back out (default `"cancel"`). Pass `null` to disable |
| `timeoutSeconds(long)`      | How long to wait before the prompt expires (default 30s)                            |
| `noTimeout()`               | Disables the timeout entirely                                                       |
| `onInput(Consumer<String>)` | Called with the player's raw message text (cancel keyword excluded)                 |
| `onCancel(Runnable)`        | Called if the player types the cancel keyword                                       |
| `onTimeout(Runnable)`       | Called if the timeout elapses before input is given                                 |
| `send()`                    | Registers the prompt and sends the prompt message                                   |

Only one prompt can be pending per player at a time — registering a new one cancels any previous pending prompt's timeout task (without invoking its cancel callback). If the player disconnects while a prompt is pending, it's silently discarded (no cancel callback fires, since there's no one left to message).

## Anvil prompts — `AnvilPrompt`

Captures single-line text via a real anvil GUI instead of chat — useful when you don't want to leave the inventory UI (renaming an item, entering a numeric amount, naming a kit) or don't want the answer flashing through public chat.

```java EconomyGiveCommand.java icon="java" theme={"system"}
AnvilPrompt.builder(plugin)
    .title("<gray>Enter amount")
    .initialText("64")
    .validate(text -> text.matches("\\d+"), "<red>Numbers only.")
    .onInput((player, text) -> giveAmount(player, Integer.parseInt(text)))
    .onCancel(player -> player.sendMessage("Cancelled."))
    .open(player);
```

Builder methods:

| Method                                            | Description                                                                                           |
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `title(String)`                                   | MiniMessage anvil GUI title                                                                           |
| `initialText(String)`                             | Pre-filled text in the rename field                                                                   |
| `validate(Predicate<String>, String failMessage)` | If the predicate fails on submit, the anvil stays open and `failMessage` is sent instead of resolving |
| `onInput(BiConsumer<Player, String>)`             | Called with the player and their submitted text                                                       |
| `onCancel(Consumer<Player>)`                      | Called if the player closes the anvil without submitting                                              |
| `open(Player)`                                    | Opens the anvil for the given player                                                                  |

Internally, `AnvilPrompt`:

* Intercepts clicks on the anvil's result slot (2) as "submit" rather than letting the player take an item
* Blocks taking the input item out of slots 0/1 entirely, since this inventory only exists to capture text
* Zeroes out the repair cost/result icon so it never visually resembles a real item combine
* Treats closing without submitting as a cancel

<Warning>
  `AnvilPrompt` registers itself as a Bukkit listener per-instance and unregisters on close/submit — you don't need to manage its lifecycle manually, but avoid holding onto a single `AnvilPrompt` instance across multiple `open()` calls for different players.
</Warning>
