diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/Dialog.java b/core/src/main/java/org/geysermc/geyser/session/dialog/Dialog.java index 394478e0d..9f19996b3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/Dialog.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/Dialog.java @@ -112,19 +112,19 @@ public abstract class Dialog { protected abstract Optional onCancel(); - protected FormBuilder, ? extends Form, ? extends FormResponse> createForm(GeyserSession session, Optional restored, DialogHolder holder) { + protected FormBuilder, ? extends Form, ? extends FormResponse> createForm(DialogHolder holder, Optional restored) { if (inputs.isEmpty()) { SimpleForm.Builder builder = SimpleForm.builder() - .translator(MinecraftLocale::getLocaleString, session.locale()) + .translator(MinecraftLocale::getLocaleString, holder.session().locale()) .title(title); builder.content(String.join("\n\n", labels)); builder.closedOrInvalidResultHandler(() -> holder.closeDialog(onCancel())); - addCustomComponents(session, builder, holder); + addCustomComponents(holder, builder); return builder; } else { CustomForm.Builder builder = CustomForm.builder() - .translator(MinecraftLocale::getLocaleString, session.locale()) + .translator(MinecraftLocale::getLocaleString, holder.session().locale()) .title(title); for (String label : labels) { builder.label(label); @@ -132,27 +132,27 @@ public abstract class Dialog { restored.ifPresentOrElse(last -> last.restore(builder), () -> inputs.forEach(input -> input.addComponent(builder))); builder.closedOrInvalidResultHandler(response -> holder.closeDialog(onCancel())); - addCustomComponents(session, builder, holder); + addCustomComponents(holder, builder); return builder; } } - protected abstract void addCustomComponents(GeyserSession session, CustomForm.Builder builder, DialogHolder holder); + protected abstract void addCustomComponents(DialogHolder holder, CustomForm.Builder builder); - protected abstract void addCustomComponents(GeyserSession session, SimpleForm.Builder builder, DialogHolder holder); + protected abstract void addCustomComponents(DialogHolder holder, SimpleForm.Builder builder); - public void sendForm(GeyserSession session, DialogHolder holder) { - session.sendDialogForm(createForm(session, Optional.empty(), holder).build()); + public void sendForm(DialogHolder holder) { + holder.session().sendDialogForm(createForm(holder, Optional.empty()).build()); } - public void restoreForm(GeyserSession session, @NonNull ParsedInputs inputs, DialogHolder holder) { - session.sendDialogForm(createForm(session, Optional.of(inputs), holder).build()); + public void restoreForm(DialogHolder holder, @NonNull ParsedInputs inputs) { + holder.session().sendDialogForm(createForm(holder, Optional.of(inputs)).build()); } - protected Optional parseInput(GeyserSession session, CustomFormResponse response, DialogHolder holder) { + protected Optional parseInput(DialogHolder holder, CustomFormResponse response) { ParsedInputs parsed = new ParsedInputs(inputs, response); if (parsed.hasErrors()) { - restoreForm(session, parsed, holder); + restoreForm(holder, parsed); return Optional.empty(); } return Optional.of(parsed); @@ -176,10 +176,10 @@ public abstract class Dialog { return new Dialog(session, map) { @Override - protected void addCustomComponents(GeyserSession session, CustomForm.Builder builder, DialogHolder holder) {} + protected void addCustomComponents(DialogHolder holder, CustomForm.Builder builder) {} @Override - protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder, DialogHolder holder) {} + protected void addCustomComponents(DialogHolder holder, SimpleForm.Builder builder) {} @Override protected Optional onCancel() { diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/DialogHolder.java b/core/src/main/java/org/geysermc/geyser/session/dialog/DialogHolder.java index b12a761e6..ff617b150 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/DialogHolder.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/DialogHolder.java @@ -25,11 +25,14 @@ package org.geysermc.geyser.session.dialog; +import lombok.Getter; +import lombok.experimental.Accessors; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; import org.geysermc.cumulus.form.ModalForm; import org.geysermc.cumulus.form.SimpleForm; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.dialog.action.DialogAction; import org.geysermc.geyser.session.dialog.input.ParsedInputs; import org.geysermc.geyser.text.MinecraftLocale; @@ -82,7 +85,10 @@ import java.util.Optional; * *

Final note: when reading through this code, a dialog is "valid" when it is still considered open.

*/ +@Accessors(fluent = true) public class DialogHolder { + @Getter + private final GeyserSession session; private final DialogManager manager; private final Dialog dialog; @@ -100,7 +106,8 @@ public class DialogHolder { private boolean shouldClose = false; private ParsedInputs lastInputs; - public DialogHolder(DialogManager manager, Dialog dialog) { + public DialogHolder(GeyserSession session, DialogManager manager, Dialog dialog) { + this.session = session; this.manager = manager; this.dialog = dialog; } @@ -125,7 +132,7 @@ public class DialogHolder { // Replace wait form with one with a back button if no replacement dialog was given if (responseWaitTime > 0 && !sendBackButton && System.currentTimeMillis() - responseWaitTime > 5000) { sendBackButton = true; - manager.session().closeForm(); // Automatically reopens with a back button + session.closeForm(); // Automatically reopens with a back button } } @@ -170,9 +177,9 @@ public class DialogHolder { // lastInputs might be null here since it's possible none were sent yet // Bedrock doesn't send them when just closing the form if (lastInputs == null) { - dialog.sendForm(manager.session(), this); + dialog.sendForm(this); } else { - dialog.restoreForm(manager.session(), lastInputs, this); + dialog.restoreForm(this, lastInputs); } } } @@ -185,7 +192,7 @@ public class DialogHolder { switch (dialog.afterAction()) { case NONE -> { // If no new dialog was opened, reopen this one - dialog.restoreForm(manager.session(), lastInputs, this); + dialog.restoreForm(this, lastInputs); } case CLOSE -> { // If no new dialog was opened, tell the manager this one is now closed @@ -212,8 +219,8 @@ public class DialogHolder { content += " If no new dialog is shown within 5 seconds, a button will appear to go back to the game."; } - manager.session().sendDialogForm(SimpleForm.builder() - .translator(MinecraftLocale::getLocaleString, manager.session().locale()) + session.sendDialogForm(SimpleForm.builder() + .translator(MinecraftLocale::getLocaleString, session.locale()) .title("gui.waitingForResponse.title") .content(content) .optionalButton("gui.back", sendBackButton) @@ -240,22 +247,22 @@ public class DialogHolder { if (action != null) { // Ask the user for confirmation if the dialog wants to run an unknown command or a command that requires operator permissions if (action instanceof DialogAction.CommandAction runCommand) { - String command = runCommand.trimmedCommand(manager.session(), inputs); + String command = runCommand.trimmedCommand(session, inputs); String root = command.split(" ")[0]; // This check is not perfect. Ideally we'd check the entire command and see if any of its arguments require operator permissions, but, that's complicated - if (manager.session().getRestrictedCommands().contains(root)) { + if (session.getRestrictedCommands().contains(root)) { showCommandConfirmation(command, false); return false; - } else if (!manager.session().getKnownCommands().contains(root)) { + } else if (!session.getKnownCommands().contains(root)) { showCommandConfirmation(command, true); return false; } - manager.session().sendCommand(command); + session.sendCommand(command); return true; } else { - action.run(manager.session(), inputs); + action.run(session, inputs); return !(action instanceof DialogAction.ShowDialog); } } @@ -269,10 +276,10 @@ public class DialogHolder { Component content = Component.translatable(unknown ? "multiplayer.confirm_command.parse_errors" : "multiplayer.confirm_command.permissions_required", Component.text(trimmedCommand).color(NamedTextColor.YELLOW)); - manager.session().sendDialogForm(ModalForm.builder() - .translator(MinecraftLocale::getLocaleString, manager.session().locale()) + session.sendDialogForm(ModalForm.builder() + .translator(MinecraftLocale::getLocaleString, session.locale()) .title("multiplayer.confirm_command.title") - .content(MessageTranslator.convertMessage(manager.session(), content)) + .content(MessageTranslator.convertMessage(session, content)) .button1("gui.yes") .button2("gui.no") .closedOrInvalidResultHandler(() -> { @@ -282,7 +289,7 @@ public class DialogHolder { }) .validResultHandler(response -> { if (response.clickedFirst()) { - manager.session().sendCommand(trimmedCommand); + session.sendCommand(trimmedCommand); if (shouldClose) { manager.close(); } else { diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/DialogManager.java b/core/src/main/java/org/geysermc/geyser/session/dialog/DialogManager.java index c7d70bac5..a3ed4064f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/DialogManager.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/DialogManager.java @@ -36,7 +36,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.Holder; */ @Accessors(fluent = true) public class DialogManager { - @Getter private final GeyserSession session; @Getter private DialogHolder open; @@ -53,9 +52,9 @@ public class DialogManager { * Opens a new dialog. If a dialog was already open, this one will be closed. Its closing action will not be executed. This matches Java behaviour. */ public void openDialog(Dialog dialog) { - open = new DialogHolder(this, dialog); + open = new DialogHolder(session, this, dialog); session.closeForm(); - dialog.sendForm(session, open); + dialog.sendForm(open); } public void tick() { diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/DialogWithButtons.java b/core/src/main/java/org/geysermc/geyser/session/dialog/DialogWithButtons.java index 789dbfceb..b676ea43b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/DialogWithButtons.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/DialogWithButtons.java @@ -48,7 +48,7 @@ public abstract class DialogWithButtons extends Dialog { } @Override - protected void addCustomComponents(GeyserSession session, CustomForm.Builder builder, DialogHolder holder) { + protected void addCustomComponents(DialogHolder holder, CustomForm.Builder builder) { DropdownComponent.Builder dropdown = DropdownComponent.builder(); dropdown.text("Please select an option:"); for (DialogButton button : buttons) { @@ -57,20 +57,18 @@ public abstract class DialogWithButtons extends Dialog { exitAction.ifPresent(button -> dropdown.option(button.label())); builder.dropdown(dropdown); - builder.validResultHandler(response -> { - parseInput(session, response, holder).ifPresent(inputs -> { - int selection = response.asDropdown(); - if (selection == buttons.size()) { - holder.runButton(exitAction, inputs); - } else { - holder.runButton(Optional.of(buttons.get(selection)), inputs); - } - }); - }); + builder.validResultHandler(response -> parseInput(holder, response).ifPresent(inputs -> { + int selection = response.asDropdown(); + if (selection == buttons.size()) { + holder.runButton(exitAction, inputs); + } else { + holder.runButton(Optional.of(buttons.get(selection)), inputs); + } + })); } @Override - protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder, DialogHolder holder) { + protected void addCustomComponents(DialogHolder holder, SimpleForm.Builder builder) { for (DialogButton button : buttons) { builder.button(button.label()); } diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/NoticeDialog.java b/core/src/main/java/org/geysermc/geyser/session/dialog/NoticeDialog.java index 2c0804133..589f24ac4 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/NoticeDialog.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/NoticeDialog.java @@ -52,12 +52,12 @@ public class NoticeDialog extends Dialog { } @Override - protected void addCustomComponents(GeyserSession session, CustomForm.Builder builder, DialogHolder holder) { - builder.validResultHandler(response -> parseInput(session, response, holder).ifPresent(inputs -> holder.runButton(button, inputs))); + protected void addCustomComponents(DialogHolder holder, CustomForm.Builder builder) { + builder.validResultHandler(response -> parseInput(holder, response).ifPresent(inputs -> holder.runButton(button, inputs))); } @Override - protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder, DialogHolder holder) { + protected void addCustomComponents(DialogHolder holder, SimpleForm.Builder builder) { builder.button(button.map(DialogButton::label).orElse("gui.ok")) .validResultHandler(response -> holder.runButton(button, ParsedInputs.EMPTY)); } diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/action/DialogAction.java b/core/src/main/java/org/geysermc/geyser/session/dialog/action/DialogAction.java index 7b40e6ca7..6487bd363 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/action/DialogAction.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/action/DialogAction.java @@ -67,6 +67,8 @@ public interface DialogAction { return Optional.empty(); } + void run(GeyserSession session, ParsedInputs inputs); + interface CommandAction extends DialogAction { String command(GeyserSession session, ParsedInputs inputs); @@ -85,8 +87,6 @@ public interface DialogAction { } } - void run(GeyserSession session, ParsedInputs inputs); - record OpenUrl(String url) implements DialogAction { public static final Key TYPE = MinecraftKey.key("open_url");