24package com.dreamfirestudios.dreamcore.DreamPrompt;
26import com.dreamfirestudios.dreamcore.DreamChat.DreamMessageFormatter;
27import com.dreamfirestudios.dreamcore.DreamChat.DreamMessageSettings;
28import com.dreamfirestudios.dreamcore.DreamCore;
29import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
30import org.bukkit.Bukkit;
31import org.bukkit.conversations.*;
32import org.bukkit.entity.Player;
33import org.jetbrains.annotations.NotNull;
35import java.util.HashMap;
37import java.util.Objects;
38import java.util.function.Consumer;
63 public static final String
END_KEY =
"DreamfirePrompt::END";
65 private static final int CLEAR_LINES = 100;
67 private final String promptText;
68 private final boolean clearOnRestart;
69 private final boolean clearOnEnd;
71 private final Consumer<DreamPromptTriplet<Player, String, ConversationContext>> onResponse;
72 private final Consumer<DreamPromptTriplet<Player, String, ConversationContext>> onRestart;
73 private final Consumer<DreamPromptTriplet<Player, String, ConversationContext>> onEnd;
85 @NotNull String promptText,
86 boolean clearOnRestart,
88 @NotNull Consumer<DreamPromptTriplet<Player, String, ConversationContext>> onResponse,
89 @NotNull Consumer<DreamPromptTriplet<Player, String, ConversationContext>> onRestart,
90 @NotNull Consumer<DreamPromptTriplet<Player, String, ConversationContext>> onEnd
92 this.promptText = Objects.requireNonNull(promptText,
"promptText");
93 this.clearOnRestart = clearOnRestart;
94 this.clearOnEnd = clearOnEnd;
95 this.onResponse = Objects.requireNonNull(onResponse,
"onResponse");
96 this.onRestart = Objects.requireNonNull(onRestart,
"onRestart");
97 this.onEnd = Objects.requireNonNull(onEnd,
"onEnd");
107 return PlainTextComponentSerializer.plainText()
108 .serialize(DreamMessageFormatter.format(promptText, DreamMessageSettings.all()));
119 public Prompt
acceptInput(ConversationContext context, String input) {
120 if (!(context.getForWhom() instanceof Player player))
return END_OF_CONVERSATION;
123 DreamPromptTriplet<Player, String, ConversationContext> payload =
124 new DreamPromptTriplet<>(player, input, context);
125 onResponse.accept(payload);
129 boolean endNow = Boolean.TRUE.equals(getSessionFlag(context.getAllSessionData(),
END_KEY));
131 if (clearOnEnd) clearChat(context);
132 onEnd.accept(payload);
135 return END_OF_CONVERSATION;
139 if (clearOnRestart) clearChat(context);
140 onRestart.accept(payload);
148 private static Object getSessionFlag(Map<Object, Object> data, String key) {
149 return data ==
null ? null : data.get(key);
155 private static void clearChat(ConversationContext ctx) {
156 for (
int i = 0; i < CLEAR_LINES; i++) {
157 ctx.getForWhom().sendRawMessage(
"");
177 Objects.requireNonNull(player,
"player");
178 Objects.requireNonNull(prompt,
"prompt");
181 var existing = DreamCore.Conversations.get(player.getUniqueId());
182 if (existing != null && !overrideExisting) return;
184 PromptStartedEvent startEvent = new PromptStartedEvent(player);
185 if (startEvent.isCancelled()) return;
187 if (existing != null) existing.abandon();
189 if (prompt.clearPlayerChatOnStart(player)) {
190 for (int i = 0; i < CLEAR_LINES; i++) player.sendMessage(
"");
202 .withInitialSessionData(
new HashMap<>(prompt.
defaultData(player)))
204 .withLocalEcho(
false)
205 .withEscapeSequence(
null)
206 .addConversationAbandonedListener(abandonedEvent -> {
208 if (abandonedEvent.getContext() != null
209 && abandonedEvent.getContext().getForWhom() instanceof Player p) {
210 DreamCore.Conversations.remove(p.getUniqueId());
212 new PromptEndedEvent(p,
"", abandonedEvent.getContext(),
213 abandonedEvent.gracefulExit() ? PromptEndedEvent.EndReason.NORMAL
214 : PromptEndedEvent.EndReason.ABANDONED);
218 Conversation conversation = factory.buildConversation(player);
219 conversation.begin();
238 private final HashMap<Object, Object> defaultData =
new HashMap<>();
239 private Consumer<DreamPromptTriplet<Player, String, ConversationContext>> onResponse = t -> {};
240 private Consumer<DreamPromptTriplet<Player, String, ConversationContext>> onRestart = t -> {};
241 private Consumer<DreamPromptTriplet<Player, String, ConversationContext>> onEnd = t -> {};
242 private String promptText =
"|Enter text: |";
243 private boolean clearOnStart =
true;
244 private boolean clearOnRestart =
true;
245 private boolean clearOnEnd =
true;
252 public Builder onResponse(Consumer<DreamPromptTriplet<Player, String, ConversationContext>> c) { this.onResponse = c;
return this; }
254 public Builder onRestart(Consumer<DreamPromptTriplet<Player, String, ConversationContext>> c) { this.onRestart = c;
return this; }
256 public Builder onEnd(Consumer<DreamPromptTriplet<Player, String, ConversationContext>> c) { this.onEnd = c;
return this; }
278 Objects.requireNonNull(player,
"player");
281 var existing = DreamCore.Conversations.get(player.getUniqueId());
282 if (existing != null && !overrideExisting) return;
284 PromptStartedEvent startEvent = new PromptStartedEvent(player);
285 if (startEvent.isCancelled()) return;
287 if (existing != null) existing.abandon();
290 for (int i = 0; i < CLEAR_LINES; i++) player.sendMessage(
"");
302 .withInitialSessionData(
new HashMap<>(defaultData))
304 .withLocalEcho(
false)
305 .withEscapeSequence(
null)
306 .addConversationAbandonedListener(abandonedEvent -> {
307 if (abandonedEvent.getContext() !=
null
308 && abandonedEvent.getContext().getForWhom() instanceof Player p) {
309 DreamCore.Conversations.remove(p.getUniqueId());
310 new PromptEndedEvent(p,
"", abandonedEvent.getContext(),
311 abandonedEvent.gracefulExit() ? PromptEndedEvent.EndReason.NORMAL
312 : PromptEndedEvent.EndReason.ABANDONED);
316 Conversation c = factory.buildConversation(player);
327 Objects.requireNonNull(player,
"player");
329 if (current !=
null) current.abandon();
static final LinkedHashMap< UUID, Conversation > Conversations
static DreamCore DreamCore
Builder for ad-hoc prompts not using IDreamPrompt.
Builder onResponse(Consumer< DreamPromptTriplet< Player, String, ConversationContext > > c)
Sets response callback.
Builder clearOnEnd(boolean v)
Clears chat when ending.
Builder clearOnRestart(boolean v)
Clears chat when repeating.
void cancelConversation(@NotNull Player player)
Cancels a running conversation for a player (if any).
Builder promptText(String text)
Sets prompt text (MiniMessage supported).
void startConversation(@NotNull Player player, boolean overrideExisting)
Starts the conversation for a player.
Builder addDefaultData(Object key, Object value)
Adds default session data key/value.
Builder onEnd(Consumer< DreamPromptTriplet< Player, String, ConversationContext > > c)
Sets end callback.
Builder onRestart(Consumer< DreamPromptTriplet< Player, String, ConversationContext > > c)
Sets restart callback.
Builder clearOnStart(boolean v)
Clears chat when starting.
Single-step string prompt with start/response/restart/end events and safe cleanup.
DreamPrompt( @NotNull String promptText, boolean clearOnRestart, boolean clearOnEnd, @NotNull Consumer< DreamPromptTriplet< Player, String, ConversationContext > > onResponse, @NotNull Consumer< DreamPromptTriplet< Player, String, ConversationContext > > onRestart, @NotNull Consumer< DreamPromptTriplet< Player, String, ConversationContext > > onEnd)
Creates a prompt instance (normally constructed through the Builder or IDreamPrompt wrapper).
static Builder PulsePromptBuilder()
Backwards-compat alias (kept for older call sites).
String getPromptText(ConversationContext context)
Formats the visible prompt line (MiniMessage → Component → plain text).
static final String END_KEY
SessionData key that signals the prompt to end on next input cycle.
Prompt acceptInput(ConversationContext context, String input)
Handles user input for this step.
static void start(Player player, IDreamPrompt prompt, boolean overrideExisting)
Launches a conversation for the given player using an IDreamPrompt provider.
static Builder builder()
Creates a new Builder.
Fired when the conversation ends, either normally or via abandon.
Fired after a player's message is received and before restart/end logic is applied.
Fired when the prompt continues (chat may be cleared, same step repeats).
Adapters supply text and behavior for DreamPrompt.start(Player, IDreamPrompt, boolean) flows.
default boolean clearPlayerChatOnRestart(Player player)
Whether to clear the player's chat when the step repeats.
String promptText(Player player)
Returns the prompt text to display for the player.
default HashMap< Object, Object > defaultData(Player player)
Default session data inserted when the prompt begins.
Consumer< DreamPromptTriplet< Player, String, ConversationContext > > onEndConversationCallback()
Called when the prompt ends normally or via abandon.
Consumer< DreamPromptTriplet< Player, String, ConversationContext > > onResponseCallback()
Called when the player submits input for this prompt.
default boolean clearPlayerChatOnEnd(Player player)
Whether to clear the player's chat on end.
default Consumer< DreamPromptTriplet< Player, String, ConversationContext > > onConversationRestartCallback()
Called if the prompt continues (same step repeats).