mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-12-28 19:29:14 +00:00
Implement dialog_list type, small refactors with button dialogs
This commit is contained in:
@@ -128,6 +128,8 @@ public final class GeyserHolderSet<T> {
|
||||
/**
|
||||
* Reads a HolderSet from a NBT object. Does not support reading HolderSets that can hold inline values.
|
||||
*
|
||||
* <p>Uses {@link JavaRegistryKey#keyToNetworkId(GeyserSession, Key)} to resolve registry keys to network IDs.</p>
|
||||
*
|
||||
* @param session the Geyser session.
|
||||
* @param registry the registry the HolderSet contains IDs from.
|
||||
* @param holderSet the HolderSet as a NBT object.
|
||||
@@ -136,6 +138,13 @@ public final class GeyserHolderSet<T> {
|
||||
return readHolderSet(registry, holderSet, key -> registry.keyToNetworkId(session, key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a HolderSet from a NBT object. Does not support reading HolderSets that can hold inline values.
|
||||
*
|
||||
* @param registry the registry the HolderSet contains IDs from.
|
||||
* @param holderSet the HolderSet as a NBT object.
|
||||
* @param idMapper a function that maps a key in this registry to its respective network ID.
|
||||
*/
|
||||
public static <T> GeyserHolderSet<T> readHolderSet(JavaRegistryKey<T> registry, @Nullable Object holderSet, ToIntFunction<Key> idMapper) {
|
||||
return readHolderSet(registry, holderSet, idMapper, null);
|
||||
}
|
||||
|
||||
@@ -30,13 +30,29 @@ import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ConfirmationDialog extends DialogWithButtons {
|
||||
|
||||
public static final Key TYPE = MinecraftKey.key("confirmation");
|
||||
|
||||
private final DialogButton yes;
|
||||
private final DialogButton no;
|
||||
|
||||
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)), Optional.empty());
|
||||
super(session, map, Optional.empty());
|
||||
yes = DialogButton.read(session, map.get("yes"), idGetter).orElseThrow();
|
||||
no = DialogButton.read(session, map.get("no"), idGetter).orElseThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DialogButton> buttons(DialogHolder holder) {
|
||||
return List.of(yes, no);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<DialogButton> onCancel() {
|
||||
return Optional.of(no);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,10 @@ public abstract class Dialog {
|
||||
|
||||
private static final Key PLAIN_MESSAGE_BODY = MinecraftKey.key("plain_message");
|
||||
|
||||
@Getter
|
||||
private final String title;
|
||||
private final String externalTitle;
|
||||
@Getter
|
||||
private final Optional<String> externalTitle;
|
||||
@Getter
|
||||
private final boolean canCloseWithEscape;
|
||||
@Getter
|
||||
@@ -72,7 +74,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"));
|
||||
externalTitle = Optional.ofNullable(MessageTranslator.convertFromNullableNbtTag(session, map.get("external_title")));
|
||||
canCloseWithEscape = map.getBoolean("can_close_with_escape", true);
|
||||
afterAction = AfterAction.fromString(map.getString("after_action"));
|
||||
|
||||
@@ -167,6 +169,8 @@ public abstract class Dialog {
|
||||
Key type = MinecraftKey.key(map.getString("type"));
|
||||
if (type.equals(NoticeDialog.TYPE)) {
|
||||
return new NoticeDialog(session, map, idGetter);
|
||||
} else if (type.equals(DialogListDialog.TYPE)) {
|
||||
return new DialogListDialog(session, map, idGetter);
|
||||
} else if (type.equals(ConfirmationDialog.TYPE)) {
|
||||
return new ConfirmationDialog(session, map, idGetter);
|
||||
} else if (type.equals(MultiActionDialog.TYPE)) {
|
||||
|
||||
@@ -42,7 +42,7 @@ public record DialogButton(String label, Optional<DialogAction> action) {
|
||||
}
|
||||
List<DialogButton> buttons = new ArrayList<>();
|
||||
for (NbtMap map : tag) {
|
||||
buttons.add(read(session, map, idGetter).orElseThrow()); // Should never throw
|
||||
buttons.add(read(session, map, idGetter).orElseThrow()); // Should never throw because we know map is a NbtMap
|
||||
}
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 net.kyori.adventure.key.Key;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.session.cache.tags.GeyserHolderSet;
|
||||
import org.geysermc.geyser.session.dialog.action.DialogAction;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class DialogListDialog extends DialogWithButtons {
|
||||
|
||||
public static final Key TYPE = MinecraftKey.key("dialog_list");
|
||||
|
||||
private final GeyserHolderSet<Dialog> dialogs;
|
||||
|
||||
public DialogListDialog(GeyserSession session, NbtMap map, IdGetter idGetter) {
|
||||
super(session, map, readDefaultExitAction(session, map, idGetter));
|
||||
dialogs = GeyserHolderSet.readHolderSet(JavaRegistries.DIALOG, map.get("dialogs"), idGetter, dialog -> Dialog.readDialogFromNbt(session, dialog, idGetter));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DialogButton> buttons(DialogHolder holder) {
|
||||
return dialogs.resolve(holder.session()).stream()
|
||||
.map(dialog -> new DialogButton(dialog.externalTitle().orElseGet(dialog::title),
|
||||
Optional.of(new DialogAction.ShowDialog(dialog))))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -32,23 +32,24 @@ import org.geysermc.cumulus.form.SimpleForm;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.dialog.input.ParsedInputs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class DialogWithButtons extends Dialog {
|
||||
|
||||
protected final List<DialogButton> buttons;
|
||||
protected final Optional<DialogButton> exitAction;
|
||||
|
||||
protected DialogWithButtons(GeyserSession session, NbtMap map, List<DialogButton> buttons, Optional<DialogButton> exitAction) {
|
||||
protected DialogWithButtons(GeyserSession session, NbtMap map, Optional<DialogButton> exitAction) {
|
||||
super(session, map);
|
||||
this.buttons = buttons;
|
||||
this.exitAction = exitAction;
|
||||
}
|
||||
|
||||
protected abstract List<DialogButton> buttons(DialogHolder holder);
|
||||
|
||||
@Override
|
||||
protected void addCustomComponents(DialogHolder holder, CustomForm.Builder builder) {
|
||||
List<DialogButton> buttons = buttons(holder);
|
||||
|
||||
DropdownComponent.Builder dropdown = DropdownComponent.builder();
|
||||
dropdown.text("Please select an option:");
|
||||
for (DialogButton button : buttons) {
|
||||
@@ -69,6 +70,7 @@ public abstract class DialogWithButtons extends Dialog {
|
||||
|
||||
@Override
|
||||
protected void addCustomComponents(DialogHolder holder, SimpleForm.Builder builder) {
|
||||
List<DialogButton> buttons = buttons(holder);
|
||||
for (DialogButton button : buttons) {
|
||||
builder.button(button.label());
|
||||
}
|
||||
@@ -88,12 +90,7 @@ public abstract class DialogWithButtons extends Dialog {
|
||||
return exitAction;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
protected static List<DialogButton> parseOptionalList(Optional<DialogButton>... buttons) {
|
||||
List<DialogButton> checked = new ArrayList<>();
|
||||
for (Optional<DialogButton> button : buttons) {
|
||||
checked.add(button.orElseThrow());
|
||||
}
|
||||
return checked;
|
||||
protected static Optional<DialogButton> readDefaultExitAction(GeyserSession session, NbtMap map, IdGetter idGetter) {
|
||||
return DialogButton.read(session, map.get("exit_action"), idGetter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,21 @@ import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class MultiActionDialog extends DialogWithButtons {
|
||||
|
||||
public static final Key TYPE = MinecraftKey.key("multi_action");
|
||||
|
||||
private final List<DialogButton> buttons;
|
||||
|
||||
protected MultiActionDialog(GeyserSession session, NbtMap map, IdGetter idGetter) {
|
||||
super(session, map, DialogButton.readList(session, map.getList("actions", NbtType.COMPOUND), idGetter), DialogButton.read(session, map.get("exit_action"), idGetter));
|
||||
super(session, map, readDefaultExitAction(session, map, idGetter));
|
||||
buttons = DialogButton.readList(session, map.getList("actions", NbtType.COMPOUND), idGetter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DialogButton> buttons(DialogHolder holder) {
|
||||
return buttons;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,11 @@ import java.util.Optional;
|
||||
public class ServerLinksDialog extends DialogWithButtons {
|
||||
|
||||
protected ServerLinksDialog(GeyserSession session, NbtMap map, List<DialogButton> buttons) {
|
||||
super(session, map, buttons, Optional.empty());
|
||||
super(session, map, Optional.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DialogButton> buttons(DialogHolder holder) {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,22 +108,26 @@ public interface DialogAction {
|
||||
}
|
||||
}
|
||||
|
||||
record ShowDialog(Holder<NbtMap> dialog) implements DialogAction {
|
||||
record ShowDialog(Optional<Dialog> dialog, Holder<NbtMap> holder) implements DialogAction {
|
||||
|
||||
public static final Key TYPE = MinecraftKey.key("show_dialog");
|
||||
|
||||
public ShowDialog(Dialog dialog) {
|
||||
this(Optional.of(dialog), null);
|
||||
}
|
||||
|
||||
private static ShowDialog read(Object dialog, Dialog.IdGetter idGetter) {
|
||||
if (dialog instanceof NbtMap map) {
|
||||
return new ShowDialog(Holder.ofCustom(map));
|
||||
return new ShowDialog(Optional.empty(), Holder.ofCustom(map));
|
||||
} else if (dialog instanceof String string) {
|
||||
return new ShowDialog(Holder.ofId(idGetter.applyAsInt(MinecraftKey.key(string))));
|
||||
return new ShowDialog(Optional.empty(), Holder.ofId(idGetter.applyAsInt(MinecraftKey.key(string))));
|
||||
}
|
||||
throw new IllegalArgumentException("Expected dialog in show_dialog action to be a NBT map or a resource location");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(GeyserSession session, ParsedInputs inputs) {
|
||||
session.getDialogManager().openDialog(dialog);
|
||||
dialog.ifPresentOrElse(normal -> session.getDialogManager().openDialog(normal), () -> session.getDialogManager().openDialog(holder));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user