From bd87a15cf2d81b8b8e549d8166fc15e26a7a9d68 Mon Sep 17 00:00:00 2001 From: skippyall <121978267+skippyall@users.noreply.github.com> Date: Sat, 2 May 2026 23:33:45 +0200 Subject: [PATCH] You have no choice --- .../skippyall/minions/gui/PaginatedList.java | 22 ++++ .../minions/gui/input/BooleanInput.kt | 71 ++++++++++ .../minions/gui/input/ChoiceInput.java | 122 ------------------ .../skippyall/minions/gui/input/TextInput.kt | 91 ++++++------- .../instruction/ConfigureInstructionGui.java | 4 +- .../minions/registration/ValueTypes.java | 16 ++- .../resources/assets/minions/lang/en_us.json | 2 + 7 files changed, 145 insertions(+), 183 deletions(-) create mode 100644 src/main/java/io/github/skippyall/minions/gui/input/BooleanInput.kt delete mode 100644 src/main/java/io/github/skippyall/minions/gui/input/ChoiceInput.java diff --git a/src/main/java/io/github/skippyall/minions/gui/PaginatedList.java b/src/main/java/io/github/skippyall/minions/gui/PaginatedList.java index 632c5af..8250730 100644 --- a/src/main/java/io/github/skippyall/minions/gui/PaginatedList.java +++ b/src/main/java/io/github/skippyall/minions/gui/PaginatedList.java @@ -8,7 +8,9 @@ import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.Items; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; +import java.util.function.Function; public class PaginatedList extends MinionsGui { private int page = 0; @@ -16,6 +18,7 @@ public class PaginatedList extends MinionsGui { private final Component title; private final int size; private final BiFunction display; + private Runnable onClose = null; public PaginatedList(MinionsGui parent, Component title, int size, BiFunction display) { super(parent); @@ -25,12 +28,20 @@ public class PaginatedList extends MinionsGui { open(); } + public PaginatedList(MinionsGui parent, Component title, int size, BiFunction display, Runnable onClose) { + this(parent, title, size, display); + this.onClose = onClose; + } + @Override protected void open() { gui = new SimpleGui(MenuType.GENERIC_9x6, viewer, false) { @Override public void onPlayerClose(boolean success) { onBackingClosed(); + if(onClose != null) { + onClose.run(); + } } }; gui.setTitle(title); @@ -53,6 +64,17 @@ public class PaginatedList extends MinionsGui { new PaginatedList(parent, title, list.size(), (i, gui) -> display.apply(list.byId(i), gui)); } + public static CompletableFuture createListFuture(MinionsGui parent, Component title, List list, Function display) { + CompletableFuture future = new CompletableFuture<>(); + new PaginatedList(parent, title, list.size(), (i, me) -> display.apply(list.get(i)) + .setCallback(() -> { + future.complete(list.get(i)); + me.goBack(); + }) + ); + return future; + } + private void addItems() { int slot = 9; for(int i = 36 * page; i < Math.min(36 * (page + 1), size); i++) { diff --git a/src/main/java/io/github/skippyall/minions/gui/input/BooleanInput.kt b/src/main/java/io/github/skippyall/minions/gui/input/BooleanInput.kt new file mode 100644 index 0000000..09684a4 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/gui/input/BooleanInput.kt @@ -0,0 +1,71 @@ +package io.github.skippyall.minions.gui.input + +import eu.pb4.sgui.api.elements.GuiElementBuilder +import eu.pb4.sgui.api.gui.SimpleGui +import io.github.skippyall.minions.gui.MinionsGui +import io.github.skippyall.minions.gui.minion.SimpleMinionsGui +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.future.asCompletableFuture +import net.minecraft.network.chat.Component +import net.minecraft.world.inventory.MenuType +import net.minecraft.world.item.Items +import java.util.concurrent.CompletableFuture + +object BooleanInput { + fun confirm( + parent: MinionsGui, + title: Component, + falseText: Component = Component.translatable("minions.gui.abort"), + trueText: Component = Component.translatable("minions.gui.confirm") + ): CompletableDeferred { + val deferred = CompletableDeferred() + + SimpleMinionsGui(parent) { onClose: Runnable, me: SimpleMinionsGui -> + val gui: SimpleGui = object : SimpleGui(MenuType.GENERIC_3x3, parent.viewer, false) { + override fun onPlayerClose(success: Boolean) { + deferred.complete(false) + onClose.run() + } + } + gui.setTitle(title) + + gui.setSlot( + 3, GuiElementBuilder(Items.REDSTONE_BLOCK) + .setName(falseText) + .setCallback(Runnable { + deferred.complete(false) + me.goBack() + }) + ) + + gui.setSlot( + 5, GuiElementBuilder(Items.EMERALD_BLOCK) + .setName(trueText) + .setCallback(Runnable { + deferred.complete(true) + me.goBack() + }) + ) + + gui.open() + gui + } + return deferred + } + + @JvmStatic + @JvmOverloads + fun confirmFuture( + parent: MinionsGui, + title: Component, + falseText: Component = Component.translatable("minions.gui.abort"), + trueText: Component = Component.translatable("minions.gui.confirm") + ): CompletableFuture { + return confirm( + parent, + title, + falseText, + trueText + ).asCompletableFuture() + } +} \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/gui/input/ChoiceInput.java b/src/main/java/io/github/skippyall/minions/gui/input/ChoiceInput.java deleted file mode 100644 index a327252..0000000 --- a/src/main/java/io/github/skippyall/minions/gui/input/ChoiceInput.java +++ /dev/null @@ -1,122 +0,0 @@ -package io.github.skippyall.minions.gui.input; - -import eu.pb4.sgui.api.elements.GuiElementBuilder; -import eu.pb4.sgui.api.gui.SimpleGui; -import io.github.skippyall.minions.gui.Displayable; -import io.github.skippyall.minions.gui.GuiDisplay; -import io.github.skippyall.minions.gui.MinionsGui; -import io.github.skippyall.minions.gui.minion.SimpleMinionsGui; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.Items; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.CompletableFuture; -import java.util.function.BiFunction; -import java.util.function.Function; - -public class ChoiceInput { - public static BiFunction> createDialogOpener(MenuType screen, Component title, Function displayFunction, T[] values, @Nullable T fallback) { - return (player, object) -> { - CompletableFuture future = new CompletableFuture<>(); - - SimpleGui gui = new SimpleGui(screen, player, false) { - @Override - public void onPlayerClose(boolean success) { - if(fallback == null) { - future.cancel(false); - } else { - future.complete(fallback); - } - } - }; - - gui.setTitle(title); - - for(T value : values) { - gui.addSlot(new GuiElementBuilder(displayFunction.apply(value).createItemStack()) - .setCallback(() -> future.complete(value)) - ); - } - gui.open(); - return future; - }; - } - - public static BiFunction> createDialogOpener(T[] values) { - return createDialogOpener(MenuType.GENERIC_9x3, Component.empty(), t -> t != null ? t.getDisplay() : null, values, null); - } - - public static CompletableFuture confirm(ServerPlayer player, Component title) { - CompletableFuture future = new CompletableFuture<>(); - - SimpleGui gui = new SimpleGui(MenuType.GENERIC_3x3, player, false) { - @Override - public void onPlayerClose(boolean success) { - future.cancel(false); - } - }; - - gui.setTitle(title); - - gui.setSlot(3, new GuiElementBuilder(Items.REDSTONE_BLOCK) - .setName(Component.translatable("minions.gui.abort")) - .setCallback(() -> future.cancel(false)) - ); - - gui.setSlot(5, new GuiElementBuilder(Items.EMERALD_BLOCK) - .setName(Component.translatable("minions.gui.confirm")) - .setCallback(() -> future.complete(null)) - ); - - gui.open(); - return future; - } - - public static CompletableFuture confirm(MinionsGui parent, Component title) { - CompletableFuture future = new CompletableFuture<>(); - - new SimpleMinionsGui(parent, (onClose, me) -> { - SimpleGui gui = new SimpleGui(MenuType.GENERIC_3x3, parent.viewer, false) { - @Override - public void onPlayerClose(boolean success) { - future.complete(false); - onClose.run(); - } - }; - - gui.setTitle(title); - - gui.setSlot(3, new GuiElementBuilder(Items.REDSTONE_BLOCK) - .setName(Component.translatable("minions.gui.abort")) - .setCallback(() -> { - future.complete(false); - me.goBack(); - }) - ); - - gui.setSlot(5, new GuiElementBuilder(Items.EMERALD_BLOCK) - .setName(Component.translatable("minions.gui.confirm")) - .setCallback(() -> { - future.complete(true); - me.goBack(); - }) - ); - - gui.open(); - return gui; - }); - return future; - } - - public static BiFunction> inputBoolean(Component title) { - return createDialogOpener(MenuType.GENERIC_3x3, title, value -> { - if(value) { - return new GuiDisplay.ItemBased(Items.EMERALD_BLOCK); - } else { - return new GuiDisplay.ItemBased(Items.REDSTONE_BLOCK); - } - }, new Boolean[]{false, true}, false); - } -} diff --git a/src/main/java/io/github/skippyall/minions/gui/input/TextInput.kt b/src/main/java/io/github/skippyall/minions/gui/input/TextInput.kt index 937fa2f..0442e31 100644 --- a/src/main/java/io/github/skippyall/minions/gui/input/TextInput.kt +++ b/src/main/java/io/github/skippyall/minions/gui/input/TextInput.kt @@ -3,8 +3,8 @@ package io.github.skippyall.minions.gui.input import eu.pb4.sgui.api.elements.GuiElementBuilder import eu.pb4.sgui.api.gui.AnvilInputGui import io.github.skippyall.minions.gui.MinionsGui -import kotlinx.coroutines.Job -import kotlinx.coroutines.async +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.Deferred import kotlinx.coroutines.future.asCompletableFuture import kotlinx.coroutines.launch import net.minecraft.network.chat.Component @@ -29,9 +29,7 @@ class TextInput( private lateinit var gui: AnvilInputGui private var result: Result? = null - private var isConfirm = false - - val job = Job() + val deferred = CompletableDeferred() init { updateConfirmButton(defaultValue) @@ -46,8 +44,8 @@ class TextInput( override fun onPlayerClose(success: Boolean) { onBackingClosed() - if (job.isActive && !isConfirm) { - job.cancel() + if (deferred.isActive) { + deferred.complete(null) } } } @@ -75,20 +73,19 @@ class TextInput( } fun onConfirm() { - result?.ifSuccess { _: T? -> - isConfirm = true + result?.ifSuccess { success: T -> + deferred.complete(success) } - job.complete() } companion object { @JvmStatic - suspend fun input( + fun input( gui: MinionsGui, title: Component, defaultValue: String, parser: suspend (String) -> Result, - ): T? { + ): Deferred { val input = TextInput( parent = gui, title = title, @@ -96,9 +93,7 @@ class TextInput( parser = parser, ) - input.job.join() - - return input.result?.getOrDefault(null) + return input.deferred } @JvmStatic @@ -108,26 +103,20 @@ class TextInput( defaultValue: String, parser: (String) -> Result, ): CompletableFuture { - return gui.scope.async { - val input = TextInput( - parent = gui, - title = title, - defaultValue = defaultValue, - parser = parser, - ) - - input.job.join() - - return@async input.result?.getOrDefault(null) - }.asCompletableFuture() + return input( + gui = gui, + title = title, + defaultValue = defaultValue, + parser = parser + ).asCompletableFuture() } @JvmStatic - suspend fun inputString( + fun inputString( gui: MinionsGui, title: Component, defaultValue: String, - ): String? { + ): Deferred { return input( gui = gui, title = title, @@ -142,21 +131,19 @@ class TextInput( title: Component, defaultValue: String, ): CompletableFuture { - return gui.scope.async { - inputString( - gui, - title, - defaultValue - ) - }.asCompletableFuture() + return inputString( + gui = gui, + title = title, + defaultValue = defaultValue, + ).asCompletableFuture() } @JvmStatic - suspend fun inputLong( + fun inputLong( gui: MinionsGui, title: Component, defaultValue: Long, - ): Long? { + ): Deferred { return input( gui = gui, title = title, @@ -176,21 +163,19 @@ class TextInput( title: Component, defaultValue: Long, ): CompletableFuture { - return gui.scope.async { - inputLong( - gui, - title, - defaultValue - ) - }.asCompletableFuture() + return inputLong( + gui = gui, + title = title, + defaultValue = defaultValue, + ).asCompletableFuture() } @JvmStatic - suspend fun inputDouble( + fun inputDouble( gui: MinionsGui, title: Component, defaultValue: Double, - ): Double? { + ): Deferred { return input( gui = gui, title = title, @@ -210,13 +195,11 @@ class TextInput( title: Component, defaultValue: Double, ): CompletableFuture { - return gui.scope.async { - inputDouble( - gui, - title, - defaultValue - ) - }.asCompletableFuture() + return inputDouble( + gui = gui, + title = title, + defaultValue = defaultValue, + ).asCompletableFuture() } } } diff --git a/src/main/java/io/github/skippyall/minions/gui/instruction/ConfigureInstructionGui.java b/src/main/java/io/github/skippyall/minions/gui/instruction/ConfigureInstructionGui.java index be31cf2..b775811 100644 --- a/src/main/java/io/github/skippyall/minions/gui/instruction/ConfigureInstructionGui.java +++ b/src/main/java/io/github/skippyall/minions/gui/instruction/ConfigureInstructionGui.java @@ -4,7 +4,7 @@ import eu.pb4.sgui.api.elements.GuiElementBuilder; import eu.pb4.sgui.api.gui.SimpleGui; import io.github.skippyall.minions.clipboard.ClipboardItem; import io.github.skippyall.minions.gui.MinionsGui; -import io.github.skippyall.minions.gui.input.ChoiceInput; +import io.github.skippyall.minions.gui.input.BooleanInput; import io.github.skippyall.minions.gui.minion.GuiContext; import io.github.skippyall.minions.minion.MinionListener; import io.github.skippyall.minions.minion.MinionRuntime; @@ -60,7 +60,7 @@ public class ConfigureInstructionGui extends MinionsGui implements ConfiguredIns gui.setSlot(7, new GuiElementBuilder(Items.LAVA_BUCKET) .setName(Component.translatable("minions.gui.instruction.configure.delete")) - .setCallback(() -> ChoiceInput.confirm(this, Component.translatable("minions.gui.instruction.configure.delete.confirm", name)) + .setCallback(() -> BooleanInput.confirmFuture(this, Component.translatable("minions.gui.instruction.configure.delete.confirm", name)) .thenAccept((confirmed) -> { if(confirmed) { minion.getInstructionManager().removeInstruction(name); diff --git a/src/main/java/io/github/skippyall/minions/registration/ValueTypes.java b/src/main/java/io/github/skippyall/minions/registration/ValueTypes.java index 13afdee..202c1e1 100644 --- a/src/main/java/io/github/skippyall/minions/registration/ValueTypes.java +++ b/src/main/java/io/github/skippyall/minions/registration/ValueTypes.java @@ -1,7 +1,10 @@ package io.github.skippyall.minions.registration; import com.mojang.serialization.Codec; +import eu.pb4.sgui.api.elements.GuiElementBuilder; import io.github.skippyall.minions.Minions; +import io.github.skippyall.minions.gui.PaginatedList; +import io.github.skippyall.minions.gui.input.BooleanInput; import io.github.skippyall.minions.gui.input.TextInput; import io.github.skippyall.minions.minion.program.instruction.move.TurnDirection; import io.github.skippyall.minions.program.value.SimpleValueType; @@ -10,7 +13,7 @@ import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; -import java.util.concurrent.CompletableFuture; +import java.util.List; public class ValueTypes { public static ValueType LONG = register( @@ -49,8 +52,7 @@ public class ValueTypes { Codec.BOOL, false, o -> o instanceof Boolean b ? b : null, - //TODO Properly implement ChoiceInput - (gui, value) -> CompletableFuture.completedFuture(value),//ChoiceInput.inputBoolean(Text.literal("")), + (parent, value) -> BooleanInput.confirmFuture(parent, Component.literal(""), Component.translatable("value_type.minions.boolean.false"), Component.translatable("value_type.minions.boolean.true")), value -> Component.literal(value.toString()) ) ); @@ -76,8 +78,12 @@ public class ValueTypes { TurnDirection.CODEC, TurnDirection.RIGHT, o -> o instanceof TurnDirection d ? d : null, - //TODO Properly implement ChoiceInput - (parent, oldValue) -> CompletableFuture.completedFuture(oldValue), // ChoiceInput.createDialogOpener(TurnDirection.values()), + (parent, oldValue) -> PaginatedList.createListFuture( + parent, + Component.translatable("value_type.minions.turn_direction"), + List.of(TurnDirection.values()), + value -> new GuiElementBuilder(value.getDisplay().createItemStack()) + ), value -> Component.literal(value.name) ) ); diff --git a/src/main/resources/assets/minions/lang/en_us.json b/src/main/resources/assets/minions/lang/en_us.json index de6f475..2f00732 100644 --- a/src/main/resources/assets/minions/lang/en_us.json +++ b/src/main/resources/assets/minions/lang/en_us.json @@ -90,6 +90,8 @@ "value_type.minions.long": "Integer", "value_type.minions.double": "Decimal", "value_type.minions.boolean": "Boolean", + "value_type.minions.boolean.true": "True", + "value_type.minions.boolean.false": "False", "value_type.minions.string": "Text", "value_type.minions.turn_direction": "Turn Direction",