mirror of
https://github.com/GeyserMC/Geyser.git
synced 2026-01-06 15:41:50 +00:00
Work on dialog inputs and dynamic actions
This commit is contained in:
@@ -28,10 +28,8 @@ 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.dialog.action.DialogAction;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ConfirmationDialog extends DialogWithButtons {
|
||||
@@ -43,7 +41,7 @@ public class ConfirmationDialog extends DialogWithButtons {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<DialogAction> onCancel() {
|
||||
return buttons.get(1).action(); // "no" button
|
||||
protected Optional<DialogButton> 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ package org.geysermc.geyser.session.dialog;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.cumulus.form.CustomForm;
|
||||
import org.geysermc.cumulus.form.Form;
|
||||
import org.geysermc.cumulus.form.SimpleForm;
|
||||
@@ -36,7 +37,8 @@ import org.geysermc.cumulus.response.FormResponse;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistries;
|
||||
import org.geysermc.geyser.session.cache.registry.RegistryEntryContext;
|
||||
import org.geysermc.geyser.session.dialog.action.DialogAction;
|
||||
import org.geysermc.geyser.session.dialog.input.DialogInput;
|
||||
import org.geysermc.geyser.session.dialog.input.ParsedInputs;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
@@ -46,7 +48,6 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.ToIntFunction;
|
||||
|
||||
public abstract class Dialog {
|
||||
@@ -55,9 +56,9 @@ public abstract class Dialog {
|
||||
|
||||
private final String title;
|
||||
private final String externalTitle;
|
||||
protected final AfterAction afterAction;
|
||||
private final AfterAction afterAction;
|
||||
private final List<String> labels;
|
||||
private final List<Object> inputs; // TODO
|
||||
private final List<DialogInput<?>> inputs = new ArrayList<>();
|
||||
|
||||
protected Dialog(GeyserSession session, NbtMap map) {
|
||||
title = MessageTranslator.convertFromNullableNbtTag(session, map.get("title"));
|
||||
@@ -70,20 +71,22 @@ public abstract class Dialog {
|
||||
} else if (bodyTag instanceof NbtMap bodyMap) {
|
||||
labels = readBody(session, bodyMap).map(List::of).orElse(List.of());
|
||||
} else if (bodyTag instanceof List<?> bodyList) {
|
||||
List<String> bodies = new ArrayList<>();
|
||||
labels = new ArrayList<>();
|
||||
for (Object tag : bodyList) {
|
||||
if (tag instanceof NbtMap bodyMap) {
|
||||
readBody(session, bodyMap).ifPresent(bodies::add);
|
||||
readBody(session, bodyMap).ifPresent(labels::add);
|
||||
} else {
|
||||
throw new IllegalStateException("Found non-NBT map in list of bodies, was: " + tag);
|
||||
}
|
||||
}
|
||||
labels = List.copyOf(bodies);
|
||||
} else {
|
||||
throw new IllegalStateException("Expected body tag to either be a NBT map or list thereof, was: " + bodyTag);
|
||||
}
|
||||
|
||||
inputs = List.of();
|
||||
List<NbtMap> inputTag = map.getList("inputs", NbtType.COMPOUND);
|
||||
for (NbtMap input : inputTag) {
|
||||
inputs.add(DialogInput.read(session, input));
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<String> readBody(GeyserSession session, NbtMap tag) {
|
||||
@@ -95,7 +98,7 @@ public abstract class Dialog {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
protected abstract Optional<DialogAction> onCancel();
|
||||
protected abstract Optional<DialogButton> onCancel();
|
||||
|
||||
protected FormBuilder<? extends FormBuilder<?,?,?>, ? extends Form, ? extends FormResponse> createForm(GeyserSession session) {
|
||||
if (inputs.isEmpty()) {
|
||||
@@ -103,14 +106,15 @@ public abstract class Dialog {
|
||||
.title(title);
|
||||
builder.content(String.join("\n", labels));
|
||||
|
||||
builder.closedOrInvalidResultHandler(actionResult(session, onCancel()));
|
||||
builder.closedOrInvalidResultHandler(() -> runButton(session, onCancel(), ParsedInputs.EMPTY));
|
||||
addCustomComponents(session, builder);
|
||||
return builder;
|
||||
} else {
|
||||
CustomForm.Builder builder = CustomForm.builder()
|
||||
.title(title);
|
||||
|
||||
builder.closedOrInvalidResultHandler(actionResult(session, onCancel())); // TODO parse input
|
||||
inputs.forEach(input -> input.addComponent(builder, Optional.empty()));
|
||||
builder.closedOrInvalidResultHandler(response -> runButton(session, onCancel(), new ParsedInputs(inputs)));
|
||||
addCustomComponents(session, builder);
|
||||
return builder;
|
||||
}
|
||||
@@ -124,17 +128,12 @@ public abstract class Dialog {
|
||||
return createForm(session).build();
|
||||
}
|
||||
|
||||
protected Object parseInput(CustomFormResponse response) {
|
||||
return 0; // TODO
|
||||
protected ParsedInputs parseInput(CustomFormResponse response) {
|
||||
return new ParsedInputs(inputs, response);
|
||||
}
|
||||
|
||||
protected Runnable actionResult(GeyserSession session, Optional<DialogAction> action) {
|
||||
return () -> action.ifPresent(present -> present.run(session, afterAction));
|
||||
}
|
||||
|
||||
protected Consumer<CustomFormResponse> validResultAction(GeyserSession session, Optional<DialogAction> action) {
|
||||
Runnable runnable = actionResult(session, action);
|
||||
return response -> runnable.run();
|
||||
protected void runButton(GeyserSession session, Optional<DialogButton> button, ParsedInputs inputs) {
|
||||
button.flatMap(DialogButton::action).ifPresent(action -> action.run(session, inputs));
|
||||
}
|
||||
|
||||
public static Dialog readDialog(RegistryEntryContext context) {
|
||||
@@ -161,7 +160,7 @@ public abstract class Dialog {
|
||||
protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder) {}
|
||||
|
||||
@Override
|
||||
protected Optional<DialogAction> onCancel() {
|
||||
protected Optional<DialogButton> onCancel() {
|
||||
return Optional.empty();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.geysermc.cumulus.component.DropdownComponent;
|
||||
import org.geysermc.cumulus.form.CustomForm;
|
||||
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;
|
||||
@@ -54,9 +55,9 @@ public abstract class DialogWithButtons extends Dialog {
|
||||
builder.dropdown(dropdown);
|
||||
|
||||
builder.validResultHandler(response -> {
|
||||
parseInput(response); // TODO
|
||||
ParsedInputs inputs = parseInput(response);
|
||||
int selection = response.asDropdown();
|
||||
buttons.get(selection).action().ifPresent(action -> action.run(session, afterAction)); // TODO check size?
|
||||
runButton(session, Optional.of(buttons.get(selection)), inputs);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -66,9 +67,7 @@ public abstract class DialogWithButtons extends Dialog {
|
||||
builder.button(button.label());
|
||||
}
|
||||
|
||||
builder.validResultHandler(response -> {
|
||||
buttons.get(response.clickedButtonId()).action().ifPresent(action -> action.run(session, afterAction)); // TODO maybe button press method
|
||||
});
|
||||
builder.validResultHandler(response -> runButton(session, Optional.of(buttons.get(response.clickedButtonId())), ParsedInputs.EMPTY));
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
|
||||
@@ -29,7 +29,6 @@ import net.kyori.adventure.key.Key;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.dialog.action.DialogAction;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -46,7 +45,7 @@ public class MultiActionDialog extends DialogWithButtons {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<DialogAction> onCancel() {
|
||||
return exit.flatMap(DialogButton::action);
|
||||
protected Optional<DialogButton> onCancel() {
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.cumulus.form.CustomForm;
|
||||
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.util.MinecraftKey;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -47,17 +47,17 @@ public class NoticeDialog extends Dialog {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<DialogAction> onCancel() {
|
||||
return button.flatMap(DialogButton::action);
|
||||
protected Optional<DialogButton> onCancel() {
|
||||
return button;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addCustomComponents(GeyserSession session, CustomForm.Builder builder) {
|
||||
builder.validResultHandler(validResultAction(session, button.flatMap(DialogButton::action))); // TODO parse input
|
||||
builder.validResultHandler(response -> runButton(session, button, parseInput(response)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addCustomComponents(GeyserSession session, SimpleForm.Builder builder) {
|
||||
builder.validResultHandler(response -> button.flatMap(DialogButton::action).ifPresent(action -> action.run(session, afterAction)));
|
||||
builder.validResultHandler(response -> runButton(session, button, ParsedInputs.EMPTY));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ package org.geysermc.geyser.session.dialog;
|
||||
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.dialog.action.DialogAction;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -39,7 +38,7 @@ public class ServerLinksDialog extends DialogWithButtons {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<DialogAction> onCancel() {
|
||||
protected Optional<DialogButton> onCancel() {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,13 @@ 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;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomClickActionPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface DialogAction {
|
||||
@@ -50,22 +53,29 @@ public interface DialogAction {
|
||||
} else if (type.equals(RunCommand.TYPE)) {
|
||||
return Optional.of(new RunCommand(map.getString("command")));
|
||||
} else if (type.equals(ShowDialog.TYPE)) {
|
||||
return Optional.of(ShowDialog.readDialog(map.get("dialog"), idGetter));
|
||||
return Optional.of(ShowDialog.read(map.get("dialog"), idGetter));
|
||||
} else if (type.equals(Custom.TYPE)) {
|
||||
return Optional.of(new Custom(MinecraftKey.key(map.getString("id")), map.getCompound("payload")));
|
||||
} else if (type.equals(DynamicRunCommand.TYPE)) {
|
||||
return Optional.of(DynamicRunCommand.read(map.getString("template")));
|
||||
} else if (type.equals(DynamicCustom.TYPE)) {
|
||||
return Optional.of(new DynamicCustom(MinecraftKey.key(map.getString("id")), map.getCompound("additions")));
|
||||
}
|
||||
// TODO the dynamic types
|
||||
|
||||
// Unknown or unsupported type
|
||||
// Currently unsupported types are: suggest_command, change_page, copy_to_clipboard
|
||||
// open_file is not supported by Java in dialogs
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
void run(GeyserSession session, Dialog.AfterAction after);
|
||||
void run(GeyserSession session, ParsedInputs inputs);
|
||||
|
||||
record OpenUrl(String url) implements DialogAction {
|
||||
|
||||
public static final Key TYPE = MinecraftKey.key("open_url");
|
||||
|
||||
@Override
|
||||
public void run(GeyserSession session, Dialog.AfterAction after) {
|
||||
public void run(GeyserSession session, ParsedInputs inputs) {
|
||||
session.sendForm(SimpleForm.builder().title("Open URL").content(url));
|
||||
}
|
||||
}
|
||||
@@ -75,7 +85,7 @@ public interface DialogAction {
|
||||
public static final Key TYPE = MinecraftKey.key("run_command");
|
||||
|
||||
@Override
|
||||
public void run(GeyserSession session, Dialog.AfterAction after) {
|
||||
public void run(GeyserSession session, ParsedInputs inputs) {
|
||||
session.sendCommand(command);
|
||||
}
|
||||
}
|
||||
@@ -84,7 +94,7 @@ public interface DialogAction {
|
||||
|
||||
public static final Key TYPE = MinecraftKey.key("show_dialog");
|
||||
|
||||
private static ShowDialog readDialog(Object dialog, Dialog.IdGetter idGetter) {
|
||||
private static ShowDialog read(Object dialog, Dialog.IdGetter idGetter) {
|
||||
if (dialog instanceof NbtMap map) {
|
||||
return new ShowDialog(Holder.ofCustom(map));
|
||||
} else if (dialog instanceof String string) {
|
||||
@@ -94,7 +104,7 @@ public interface DialogAction {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(GeyserSession session, Dialog.AfterAction after) {
|
||||
public void run(GeyserSession session, ParsedInputs inputs) {
|
||||
// TODO figure out parent dialog
|
||||
Dialog.showDialog(session, dialog);
|
||||
}
|
||||
@@ -106,8 +116,83 @@ public interface DialogAction {
|
||||
public static final Key TYPE = MinecraftKey.key("custom");
|
||||
|
||||
@Override
|
||||
public void run(GeyserSession session, Dialog.AfterAction after) {
|
||||
public void run(GeyserSession session, ParsedInputs inputs) {
|
||||
session.sendDownstreamPacket(new ServerboundCustomClickActionPacket(id, tag));
|
||||
}
|
||||
}
|
||||
|
||||
record DynamicRunCommand(List<String> segments, List<String> variables) implements DialogAction {
|
||||
|
||||
public static final Key TYPE = MinecraftKey.key("dynamic/run_command");
|
||||
|
||||
private static DynamicRunCommand read(String command) {
|
||||
// Inspired by StringTemplate in mojmap
|
||||
// Reads commands with 'macros', variables that are replaced with inputs, in a format like this:
|
||||
// /say hey everyone, $(your_name) is super cool!
|
||||
|
||||
int length = command.length();
|
||||
int lastVariable = 0;
|
||||
int nextVariable = command.indexOf('$');
|
||||
|
||||
List<String> segments = new ArrayList<>();
|
||||
List<String> variables = new ArrayList<>();
|
||||
while (nextVariable != -1) {
|
||||
if (nextVariable != length - 1 && command.charAt(nextVariable + 1) == '(') {
|
||||
segments.add(command.substring(lastVariable, nextVariable));
|
||||
int variableEnd = command.indexOf(')', nextVariable + 1);
|
||||
if (variableEnd == -1) {
|
||||
throw new IllegalArgumentException("Command ended with an open variable");
|
||||
}
|
||||
|
||||
variables.add(command.substring(nextVariable + 2, variableEnd));
|
||||
lastVariable = variableEnd + 1;
|
||||
nextVariable = command.indexOf('$', lastVariable);
|
||||
} else {
|
||||
// If this $ was just an $ without a (, so no variable, which can occur in e.g. text components, just go to the next one
|
||||
nextVariable = command.indexOf('$', nextVariable + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (lastVariable == 0) {
|
||||
throw new IllegalArgumentException("No variables in command template");
|
||||
} else {
|
||||
// Append the remaining segment if there is one
|
||||
if (lastVariable != length) {
|
||||
segments.add(command.substring(lastVariable));
|
||||
}
|
||||
|
||||
return new DynamicRunCommand(segments, variables);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(GeyserSession session, ParsedInputs inputs) {
|
||||
StringBuilder command = new StringBuilder();
|
||||
|
||||
List<String> parsedVariables = variables.stream().map(inputs::getSubstitution).toList();
|
||||
|
||||
for (int i = 0; i < variables.size(); i++) {
|
||||
command.append(segments.get(i)).append(parsedVariables.get(i));
|
||||
}
|
||||
|
||||
// Append the remaining segment if there is one
|
||||
if (segments.size() > variables.size()) {
|
||||
command.append(segments.get(segments.size() - 1));
|
||||
}
|
||||
|
||||
session.sendCommand(command.toString());
|
||||
}
|
||||
}
|
||||
|
||||
record DynamicCustom(Key id, NbtMap additions) implements DialogAction {
|
||||
|
||||
public static final Key TYPE = MinecraftKey.key("dynamic/custom");
|
||||
|
||||
@Override
|
||||
public void run(GeyserSession session, ParsedInputs inputs) {
|
||||
NbtMap map = inputs.asNbtMap();
|
||||
map.putAll(additions); // Can be optional on Java. We just read an empty map when it doesn't exist.
|
||||
session.sendDownstreamPacket(new ServerboundCustomClickActionPacket(id, map));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.input;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||
import org.geysermc.cumulus.form.CustomForm;
|
||||
import org.geysermc.cumulus.response.CustomFormResponse;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class BooleanInput extends DialogInput<Boolean> {
|
||||
|
||||
public static final Key TYPE = MinecraftKey.key("boolean");
|
||||
|
||||
private final boolean initial;
|
||||
private final String onTrue;
|
||||
private final String onFalse;
|
||||
|
||||
public BooleanInput(GeyserSession session, NbtMap map) {
|
||||
super(session, map);
|
||||
initial = map.getBoolean("initial", false);
|
||||
onTrue = map.getString("on_true", "true");
|
||||
onFalse = map.getString("on_false", "false");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addComponent(CustomForm.Builder builder, Optional<Boolean> restored) {
|
||||
builder.toggle(label, restored.orElse(initial));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean read(CustomFormResponse response) {
|
||||
return response.asToggle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String asSubstitution(Boolean value) {
|
||||
return value ? onTrue : onFalse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToMap(NbtMapBuilder builder, Boolean value) {
|
||||
builder.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean defaultValue() {
|
||||
return initial;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.input;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||
import org.geysermc.cumulus.form.CustomForm;
|
||||
import org.geysermc.cumulus.response.CustomFormResponse;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class DialogInput<T> {
|
||||
protected final String key;
|
||||
protected final String label;
|
||||
|
||||
protected DialogInput(GeyserSession session, NbtMap map) {
|
||||
this.key = map.getString("key");
|
||||
this.label = MessageTranslator.convertFromNullableNbtTag(session, map.get("label"));
|
||||
}
|
||||
|
||||
public abstract void addComponent(CustomForm.Builder builder, Optional<T> restored);
|
||||
|
||||
public abstract T read(CustomFormResponse response);
|
||||
|
||||
public abstract String asSubstitution(T value);
|
||||
|
||||
public abstract void addToMap(NbtMapBuilder builder, T value);
|
||||
|
||||
public abstract T defaultValue();
|
||||
|
||||
public static DialogInput<?> read(GeyserSession session, NbtMap tag) {
|
||||
Key type = MinecraftKey.key(tag.getString("type"));
|
||||
if (type.equals(BooleanInput.TYPE)) {
|
||||
return new BooleanInput(session, tag);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException("Unknown dialog input type " + type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.input;
|
||||
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||
import org.geysermc.cumulus.form.CustomForm;
|
||||
import org.geysermc.cumulus.response.CustomFormResponse;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ParsedInputs {
|
||||
public static final ParsedInputs EMPTY = new ParsedInputs(List.of(), null);
|
||||
|
||||
private final Map<DialogInput<?>, Object> values = new LinkedHashMap<>();
|
||||
|
||||
public ParsedInputs(List<DialogInput<?>> inputs, CustomFormResponse response) {
|
||||
for (DialogInput<?> input : inputs) {
|
||||
values.put(input, input.read(response));
|
||||
}
|
||||
}
|
||||
|
||||
public ParsedInputs(List<DialogInput<?>> inputs) {
|
||||
for (DialogInput<?> input : inputs) {
|
||||
values.put(input, input.defaultValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void restore(CustomForm.Builder builder) {
|
||||
for (Map.Entry<DialogInput<?>, Object> entry : values.entrySet()) {
|
||||
// Can't be a Geyser update without eclipse dealing with generics
|
||||
((DialogInput) entry.getKey()).addComponent(builder, Optional.of(entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
public String getSubstitution(String key) {
|
||||
for (Map.Entry<DialogInput<?>, Object> entry : values.entrySet()) {
|
||||
if (entry.getKey().key.equals(key)) {
|
||||
return ((DialogInput) entry.getKey()).asSubstitution(entry.getValue());
|
||||
}
|
||||
}
|
||||
return ""; // Java defaults to empty strings when a key was not in the inputs
|
||||
}
|
||||
|
||||
public NbtMap asNbtMap() {
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
for (Map.Entry<DialogInput<?>, Object> entry : values.entrySet()) {
|
||||
((DialogInput) entry.getKey()).addToMap(builder, entry.getValue());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user