diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 59b309659..041dc68e0 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -176,6 +176,7 @@ import org.geysermc.geyser.session.cache.TeleportCache; import org.geysermc.geyser.session.cache.WorldBorder; import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.session.cache.registry.JavaRegistries; +import org.geysermc.geyser.session.dialog.DialogManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -307,6 +308,9 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private @Nullable InventoryHolder inventoryHolder; + @Getter + private final DialogManager dialogManager = new DialogManager(this); + /** * Whether the client is currently closing an inventory. * Used to open new inventories while another one is currently open. @@ -1515,6 +1519,19 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Override public boolean sendForm(@NonNull Form form) { + // First close any dialogs that are open. This won't execute the dialog's closing action. + dialogManager.close(); + return doSendForm(form); + } + + /** + * Sends a form without first closing any open dialog. This should only be used by {@link org.geysermc.geyser.session.dialog.Dialog}s. + */ + public boolean sendDialogForm(@NonNull Form form) { + return doSendForm(form); + } + + private boolean doSendForm(@NonNull Form form) { formCache.showForm(form); return true; } diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/ConfirmationDialog.java b/core/src/main/java/org/geysermc/geyser/session/dialog/ConfirmationDialog.java index 5c522206a..9ec9be3b3 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/ConfirmationDialog.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/ConfirmationDialog.java @@ -37,11 +37,6 @@ public class ConfirmationDialog extends DialogWithButtons { public static final Key TYPE = MinecraftKey.key("confirmation"); public ConfirmationDialog(GeyserSession session, NbtMap map, IdGetter idGetter) { - super(session, map, parseOptionalList(DialogButton.read(session, map.get("yes"), idGetter), DialogButton.read(session, map.get("no"), idGetter))); - } - - @Override - protected Optional onCancel() { - return buttons.size() > 1 ? Optional.of(buttons.get(1)) : Optional.empty(); // "no" button, there should always be 2 buttons but check just to be sure + super(session, map, parseOptionalList(DialogButton.read(session, map.get("yes"), idGetter), DialogButton.read(session, map.get("no"), idGetter)), Optional.empty()); } } 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 8c8098258..00011c523 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 @@ -25,7 +25,10 @@ package org.geysermc.geyser.session.dialog; +import lombok.Getter; +import lombok.experimental.Accessors; import net.kyori.adventure.key.Key; +import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtType; import org.geysermc.cumulus.form.CustomForm; @@ -50,12 +53,16 @@ import java.util.Objects; import java.util.Optional; import java.util.function.ToIntFunction; +@Accessors(fluent = true) public abstract class Dialog { private static final Key PLAIN_MESSAGE_BODY = MinecraftKey.key("plain_message"); private final String title; private final String externalTitle; + @Getter + private final boolean canCloseWithEscape; + @Getter private final AfterAction afterAction; private final List labels; private final List> inputs = new ArrayList<>(); @@ -63,6 +70,7 @@ public abstract class Dialog { protected Dialog(GeyserSession session, NbtMap map) { title = MessageTranslator.convertFromNullableNbtTag(session, map.get("title")); externalTitle = MessageTranslator.convertFromNullableNbtTag(session, map.get("title")); + canCloseWithEscape = map.getBoolean("can_close_with_escape", true); afterAction = AfterAction.fromString(map.getString("after_action")); Object bodyTag = map.get("body"); @@ -100,42 +108,42 @@ public abstract class Dialog { protected abstract Optional onCancel(); - protected FormBuilder, ? extends Form, ? extends FormResponse> createForm(GeyserSession session) { + protected FormBuilder, ? extends Form, ? extends FormResponse> createForm(GeyserSession session, Optional restored, DialogHolder holder) { if (inputs.isEmpty()) { SimpleForm.Builder builder = SimpleForm.builder() .title(title); - builder.content(String.join("\n", labels)); + builder.content(String.join("\n\n", labels)); - builder.closedOrInvalidResultHandler(() -> runButton(session, onCancel(), ParsedInputs.EMPTY)); - addCustomComponents(session, builder); + builder.closedOrInvalidResultHandler(() -> holder.closeDialog(onCancel())); + addCustomComponents(session, builder, holder); return builder; } else { CustomForm.Builder builder = CustomForm.builder() .title(title); - inputs.forEach(input -> input.addComponent(builder, Optional.empty())); - builder.closedOrInvalidResultHandler(response -> runButton(session, onCancel(), new ParsedInputs(inputs))); - addCustomComponents(session, builder); + restored.ifPresentOrElse(last -> last.restore(builder), () -> inputs.forEach(input -> input.addComponent(builder))); + builder.closedOrInvalidResultHandler(response -> holder.closeDialog(onCancel())); + addCustomComponents(session, builder, holder); return builder; } } - protected abstract void addCustomComponents(GeyserSession session, CustomForm.Builder builder); + protected abstract void addCustomComponents(GeyserSession session, CustomForm.Builder builder, DialogHolder holder); - protected abstract void addCustomComponents(GeyserSession session, SimpleForm.Builder builder); + protected abstract void addCustomComponents(GeyserSession session, SimpleForm.Builder builder, DialogHolder holder); - public Form buildForm(GeyserSession session) { - return createForm(session).build(); + public void sendForm(GeyserSession session, DialogHolder holder) { + session.sendDialogForm(createForm(session, Optional.empty(), holder).build()); + } + + public void restoreForm(GeyserSession session, @NonNull ParsedInputs inputs, DialogHolder holder) { + session.sendDialogForm(createForm(session, Optional.of(inputs), holder).build()); } protected ParsedInputs parseInput(CustomFormResponse response) { return new ParsedInputs(inputs, response); } - protected void runButton(GeyserSession session, Optional button, ParsedInputs inputs) { - button.flatMap(DialogButton::action).ifPresent(action -> action.run(session, inputs)); - } - public static Dialog readDialog(RegistryEntryContext context) { return readDialogFromNbt(context.session(), context.data(), context::getNetworkId); } @@ -154,10 +162,10 @@ public abstract class Dialog { return new Dialog(session, map) { @Override - protected void addCustomComponents(GeyserSession session, CustomForm.Builder builder) {} + protected void addCustomComponents(GeyserSession session, CustomForm.Builder builder, DialogHolder holder) {} @Override - protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder) {} + protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder, DialogHolder holder) {} @Override protected Optional onCancel() { @@ -167,14 +175,12 @@ public abstract class Dialog { // throw new UnsupportedOperationException("Unable to read unknown dialog type " + type + "!"); // TODO put this here once all types are implemented } - public static void showDialog(GeyserSession session, Holder holder) { - Dialog dialog; + public static Dialog getDialogFromHolder(GeyserSession session, Holder holder) { if (holder.isId()) { - dialog = JavaRegistries.DIALOG.fromNetworkId(session, holder.id()); + return Objects.requireNonNull(JavaRegistries.DIALOG.fromNetworkId(session, holder.id())); } else { - dialog = Dialog.readDialogFromNbt(session, holder.custom(), key -> JavaRegistries.DIALOG.keyToNetworkId(session, key)); + return Dialog.readDialogFromNbt(session, holder.custom(), key -> JavaRegistries.DIALOG.keyToNetworkId(session, key)); } - session.sendForm(Objects.requireNonNull(dialog).buildForm(session)); } public enum AfterAction { @@ -188,7 +194,7 @@ public abstract class Dialog { return action; } } - return null; + return CLOSE; } } 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 new file mode 100644 index 000000000..b24cbfd98 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/DialogHolder.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.session.dialog; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.session.dialog.action.DialogAction; +import org.geysermc.geyser.session.dialog.input.ParsedInputs; + +import java.util.Optional; + +public class DialogHolder { + private final DialogManager manager; + private final Dialog dialog; + private ParsedInputs lastInputs; + + public DialogHolder(DialogManager manager, Dialog dialog) { + this.manager = manager; + this.dialog = dialog; + } + + + // Dialog action behaviour: + // When running an action, if the action: + // - opens a new dialog: the new dialog is opened, the old one is closed, its closing action not executed. [ ] + // - executes with "none" as after action: the dialog is kept open. The dialog can only be closed by pressing "escape" (when allowed by the dialog), or on bedrock, the X in the corner of the form. [ ] (TODO note about multi action exit) + // - executes with "close" as after action: the dialog is closed, its closing action not executed. + // A dialogs closing action (onCancel()) is only executed when the dialog is closed by pressing "escape" (when allowed by the dialog). [ ] + // If a new dialog is opened by the server when a dialog is already open, that dialog is closed, its closing action not executed. [ ] + + public void runButton(Optional button, @NonNull ParsedInputs inputs) { + lastInputs = inputs; + + boolean stillValid = runAction(button, lastInputs); + switch (dialog.afterAction()) { + case NONE -> { + // If no new dialog was opened, reopen this one + if (stillValid) { + dialog.restoreForm(manager.session(), lastInputs, this); + } + } + case CLOSE -> { + // If no new dialog was opened, tell the manager this one is now closed + if (stillValid) { + manager.close(); + } + } + case WAIT_FOR_RESPONSE -> {} // TODO + } + } + + // Called when clicking the X in the corner on a form, which we interpret as clicking escape + // Note that this method is called from the "closedOrInvalidResultHandler", + // meaning it can also be called when e.g. the bedrock client opens another form or is unable to open the form sent to it + public void closeDialog(Optional onCancel) { + if (dialog.canCloseWithEscape()) { + if (runAction(onCancel, lastInputs == null ? ParsedInputs.EMPTY : lastInputs)) { + manager.close(); + } + } else if (manager.open() == this) { // Check if this is still the currently open dialog + // If player should not have been able to close the dialog, reopen it with the last inputs + + // lastInputs might be null here since it's possible none were sent yet, and bedrock doesn't send them when just closing the form + if (lastInputs == null) { + dialog.sendForm(manager.session(), this); + } else { + dialog.restoreForm(manager.session(), lastInputs, this); + } + } + } + + // Returns true if this dialog is still regarded open by the DialogManager + // When returning false, that means a new dialog has been opened, possibly by the action, which takes this dialog's place + private boolean runAction(Optional button, ParsedInputs inputs) { + // Don't run any action if a new dialog has already been opened + if (manager.open() != this) { + return false; + } + + DialogAction action = button.flatMap(DialogButton::action).orElse(null); + if (action != null) { + action.run(manager.session(), inputs); + if (action instanceof DialogAction.ShowDialog) { + return false; + } + // TODO command warning screen + } + return true; + } +} 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 new file mode 100644 index 000000000..b0e50c190 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/DialogManager.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.session.dialog; + +import lombok.Getter; +import lombok.experimental.Accessors; +import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.Holder; + +/** + * Small class to manage the currently open dialog. + */ +@Accessors(fluent = true) +public class DialogManager { + @Getter + private final GeyserSession session; + @Getter + private DialogHolder open; + + public DialogManager(GeyserSession session) { + this.session = session; + } + + public void openDialog(Holder dialog) { + openDialog(Dialog.getDialogFromHolder(session, dialog)); + } + + /** + * 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); + session.closeForm(); + dialog.sendForm(session, open); + } + + /** + * Closes the currently open dialog, if any. The dialog's closing action will not be executed. + */ + public void close() { + if (open != null) { + open = null; + // The form could already have been closed by now, but in the case it wasn't, close it anyway + // This won't run a closing dialog action, because the manager already regards the dialog as closed + session.closeForm(); + } + } +} 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 fdf6b47f4..4ac0add5b 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 @@ -39,35 +39,55 @@ import java.util.Optional; public abstract class DialogWithButtons extends Dialog { protected final List buttons; + protected final Optional exitAction; - protected DialogWithButtons(GeyserSession session, NbtMap map, List buttons) { + protected DialogWithButtons(GeyserSession session, NbtMap map, List buttons, Optional exitAction) { super(session, map); this.buttons = buttons; + this.exitAction = exitAction; } @Override - protected void addCustomComponents(GeyserSession session, CustomForm.Builder builder) { + protected void addCustomComponents(GeyserSession session, CustomForm.Builder builder, DialogHolder holder) { DropdownComponent.Builder dropdown = DropdownComponent.builder(); dropdown.text("Please select an option:"); for (DialogButton button : buttons) { dropdown.option(button.label()); } + exitAction.ifPresent(button -> dropdown.option(button.label())); builder.dropdown(dropdown); builder.validResultHandler(response -> { ParsedInputs inputs = parseInput(response); int selection = response.asDropdown(); - runButton(session, Optional.of(buttons.get(selection)), inputs); + 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) { + protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder, DialogHolder holder) { for (DialogButton button : buttons) { builder.button(button.label()); } + exitAction.ifPresent(button -> builder.button(button.label())); - builder.validResultHandler(response -> runButton(session, Optional.of(buttons.get(response.clickedButtonId())), ParsedInputs.EMPTY)); + builder.validResultHandler(response -> { + if (response.clickedButtonId() == buttons.size()) { + holder.runButton(exitAction, ParsedInputs.EMPTY); + } else { + + holder.runButton(Optional.of(buttons.get(response.clickedButtonId())), ParsedInputs.EMPTY); + } + }); + } + + @Override + protected Optional onCancel() { + return exitAction; } @SafeVarargs diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/MultiActionDialog.java b/core/src/main/java/org/geysermc/geyser/session/dialog/MultiActionDialog.java index c8a4d53fa..c8c2e1f50 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/MultiActionDialog.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/MultiActionDialog.java @@ -31,21 +31,11 @@ import org.cloudburstmc.nbt.NbtType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.MinecraftKey; -import java.util.Optional; - public class MultiActionDialog extends DialogWithButtons { public static final Key TYPE = MinecraftKey.key("multi_action"); - private final Optional exit; - protected MultiActionDialog(GeyserSession session, NbtMap map, IdGetter idGetter) { - super(session, map, DialogButton.readList(session, map.getList("actions", NbtType.COMPOUND), idGetter)); - exit = DialogButton.read(session, map.get("exit_action"), idGetter); - } - - @Override - protected Optional onCancel() { - return exit; + super(session, map, DialogButton.readList(session, map.getList("actions", NbtType.COMPOUND), idGetter), DialogButton.read(session, map.get("exit_action"), idGetter)); } } 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 d9e32ca62..10fc1942c 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) { - builder.validResultHandler(response -> runButton(session, button, parseInput(response))); + protected void addCustomComponents(GeyserSession session, CustomForm.Builder builder, DialogHolder holder) { + builder.validResultHandler(response -> holder.runButton(onCancel(), parseInput(response))); } @Override - protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder) { - builder.validResultHandler(response -> runButton(session, button, ParsedInputs.EMPTY)); + protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder, DialogHolder holder) { + builder.validResultHandler(response -> holder.runButton(onCancel(), ParsedInputs.EMPTY)); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/ServerLinksDialog.java b/core/src/main/java/org/geysermc/geyser/session/dialog/ServerLinksDialog.java index 1c1666892..c33c81941 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/ServerLinksDialog.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/ServerLinksDialog.java @@ -34,11 +34,6 @@ import java.util.Optional; public class ServerLinksDialog extends DialogWithButtons { protected ServerLinksDialog(GeyserSession session, NbtMap map, List buttons) { - super(session, map, buttons); - } - - @Override - protected Optional onCancel() { - return Optional.empty(); + super(session, map, buttons, Optional.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 6c75f71da..8f834b012 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 @@ -28,7 +28,6 @@ package org.geysermc.geyser.session.dialog.action; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; -import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.dialog.Dialog; import org.geysermc.geyser.session.dialog.input.ParsedInputs; @@ -76,7 +75,8 @@ public interface DialogAction { @Override public void run(GeyserSession session, ParsedInputs inputs) { - session.sendForm(SimpleForm.builder().title("Open URL").content(url)); + //session.sendForm(SimpleForm.builder().title("Open URL").content(url)); + // TODO if we use form here we need a connection in dialog stack } } @@ -105,8 +105,7 @@ public interface DialogAction { @Override public void run(GeyserSession session, ParsedInputs inputs) { - // TODO figure out parent dialog - Dialog.showDialog(session, dialog); + session.getDialogManager().openDialog(dialog); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/dialog/input/DialogInput.java b/core/src/main/java/org/geysermc/geyser/session/dialog/input/DialogInput.java index ad0f92984..9b3817e79 100644 --- a/core/src/main/java/org/geysermc/geyser/session/dialog/input/DialogInput.java +++ b/core/src/main/java/org/geysermc/geyser/session/dialog/input/DialogInput.java @@ -45,6 +45,10 @@ public abstract class DialogInput { this.label = MessageTranslator.convertFromNullableNbtTag(session, map.get("label")); } + public void addComponent(CustomForm.Builder builder) { + addComponent(builder, Optional.empty()); + } + public abstract void addComponent(CustomForm.Builder builder, Optional restored); public abstract T read(CustomFormResponse response); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/dialogues/JavaShowDialogGameTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/dialogues/JavaShowDialogGameTranslator.java index 9aea5fb89..1d0c911fd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/dialogues/JavaShowDialogGameTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/dialogues/JavaShowDialogGameTranslator.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.translator.protocol.java.dialogues; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.dialog.Dialog; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundShowDialogGamePacket; @@ -36,6 +35,6 @@ public class JavaShowDialogGameTranslator extends PacketTranslator