Convert even more

This commit is contained in:
skippyall
2026-04-05 01:17:53 +02:00
parent 7acd083e79
commit 324fea04a9
34 changed files with 858 additions and 278 deletions
@@ -0,0 +1,54 @@
package io.github.skippyall.minions.gui;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
public abstract class MinionsGui {
protected final @Nullable MinionsGui parent;
protected final ServerPlayerEntity viewer;
private @Nullable MinionsGui child = null;
private boolean open = true;
public MinionsGui(MinionsGui parent) {
this.viewer = parent.viewer;
this.parent = parent;
parent.child = this;
open();
}
public MinionsGui(ServerPlayerEntity viewer) {
this.viewer = viewer;
this.parent = null;
open();
}
protected void open() {}
protected void reopen() {
open();
}
public void onBackingClosed() {
if(child != null && child.open) {
return;
}
close();
}
public void close() {
if(open) {
if(child != null) {
child.close();
}
if(parent != null) {
parent.child = null;
parent.reopen();
}
onClose();
open = false;
}
}
protected void onClose() {}
}
@@ -0,0 +1,59 @@
package io.github.skippyall.minions.gui;
import eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SlotGuiInterface;
import io.github.skippyall.minions.gui.minion.MinionGui;
import net.minecraft.item.Items;
import net.minecraft.text.Text;
import net.minecraft.util.collection.IndexedIterable;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
public class PaginatedList {
public static void createList(SlotGuiInterface gui, int size, Function<Integer, GuiElementBuilder> display, Runnable onBack) {
AtomicInteger page = new AtomicInteger(0);
addItems(page, gui, size, display);
gui.setSlot(27, MinionGui.backButton(onBack));
}
public static <T> void createList(SlotGuiInterface gui, List<T> list, Function<T, GuiElementBuilder> display, Runnable onBack) {
createList(gui, list.size(), i -> display.apply(list.get(i)), onBack);
}
public static <T> void createList(SlotGuiInterface gui, IndexedIterable<T> list, Function<T, GuiElementBuilder> display, Runnable onBack) {
createList(gui, list.size(), i -> display.apply(list.get(i)), onBack);
}
private static void addItems(AtomicInteger page, SlotGuiInterface gui, int size, Function<Integer, GuiElementBuilder> display) {
for(int i = 27 * page.get(); i < Math.min(27 * (page.get() + 1), size); i++) {
gui.addSlot(display.apply(i));
}
if(page.get() > 0) {
gui.setSlot(30, new GuiElementBuilder(Items.SPECTRAL_ARROW)
.setItemName(Text.translatable("book.page_button.previous"))
.setCallback(() -> {
page.decrementAndGet();
addItems(page, gui, size, display);
})
);
} else {
gui.clearSlot(30);
}
if(27 * (page.get() + 1) < size) {
gui.setSlot(32, new GuiElementBuilder(Items.ARROW)
.setItemName(Text.translatable("book.page_button.next"))
.setCallback(() -> {
page.incrementAndGet();
addItems(page, gui, size, display);
})
);
} else {
gui.clearSlot(32);
}
}
}
@@ -25,11 +25,11 @@ public interface Result<T, E> {
boolean isSuccess();
@NotNull T getOrDefault(@NotNull T defaultValue);
T getOrDefault(T defaultValue);
@NotNull T getOrThrow();
T getOrThrow();
@NotNull E getErrorOrThrow();
E getErrorOrThrow();
@NotNull Optional<T> getOptional();
@@ -37,24 +37,24 @@ public interface Result<T, E> {
void ifError(@NotNull Consumer<Error<T, E>> handler);
record Success<T, E>(@NotNull T result) implements Result<T, E> {
record Success<T, E>(T result) implements Result<T, E> {
@Override
public boolean isSuccess() {
return true;
}
@Override
public @NotNull T getOrDefault(@NotNull T defaultValue) {
public T getOrDefault(T defaultValue) {
return result;
}
@Override
public @NotNull T getOrThrow() {
public T getOrThrow() {
return result;
}
@Override
public @NotNull E getErrorOrThrow() {
public E getErrorOrThrow() {
throw new RuntimeException("Result was not an Error");
}
@@ -74,24 +74,25 @@ public interface Result<T, E> {
}
}
record Error<T, E>(@NotNull E message) implements Result<T, E> {
record Error<T, E>(E message) implements Result<T, E> {
@Override
public boolean isSuccess() {
return false;
}
@Override
public @NotNull T getOrDefault(@NotNull T defaultValue) {
public T getOrDefault(
T defaultValue) {
return defaultValue;
}
@Override
public @NotNull T getOrThrow() {
public T getOrThrow() {
throw new RuntimeException("Result was an error: " + message);
}
@Override
public @NotNull E getErrorOrThrow() {
public E getErrorOrThrow() {
return message;
}
@@ -0,0 +1,81 @@
package io.github.skippyall.minions.gui.instruction;
import eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SimpleGui;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction;
import io.github.skippyall.minions.program.supplier.Parameter;
import io.github.skippyall.minions.program.supplier.ValueSupplier;
import io.github.skippyall.minions.program.supplier.ValueSupplierType;
import io.github.skippyall.minions.registration.MinionRegistries;
import io.github.skippyall.minions.util.TranslationUtil;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
public class ArgumentGui {
public static <T, A extends ValueSupplier<T, MinionRuntime>> void configureArgumentMenu(String instructionName, ConfiguredInstruction<MinionRuntime> instruction, Parameter<?> parameter, MinionFakePlayer minion, ServerPlayerEntity player) {
if (!InstructionGui.checkInstructionExists(instructionName, instruction, minion, player)) {
return;
}
@Nullable ValueSupplier<?, MinionRuntime> argument = instruction.getArguments().getArgument(parameter);
if(argument == null) {
configureTypeAndValue(instructionName, instruction, parameter, minion, player);
return;
}
configureArgumentHelper(instructionName, instruction, parameter, argument, minion, player);
}
private static <F, T> void configureArgumentHelper(String instructionName, ConfiguredInstruction<MinionRuntime> instruction, Parameter<T> parameter, ValueSupplier<F, MinionRuntime> argument, MinionFakePlayer minion, ServerPlayerEntity player) {
SimpleGui gui = new InstructionBoundSimpleGui(ScreenHandlerType.GENERIC_3X3, player, minion, instruction);
ItemStack displayStack = GuiDisplay.getDisplayStack(MinionRegistries.VALUE_SUPPLIER_TYPES, argument.getType(), player.getRegistryManager());
gui.setSlot(3, new GuiElementBuilder(displayStack)
.setName(Text.translatable("minions.gui.instruction.argument.configure.type", Text.translatable(TranslationUtil.getTranslationKey(argument.getType(), MinionRegistries.VALUE_SUPPLIER_TYPES, "minions.gui.instruction.argument.configure.type.unset"))))
.setCallback(() -> configureTypeAndValue(instructionName, instruction, parameter, minion, player))
);
gui.setSlot(5, new GuiElementBuilder(Items.STRUCTURE_VOID)
.setName(Text.literal("Configure"))
.setCallback(() -> argument.getType().openConfiguration(player, argument.getValueType(), argument)
.thenAccept(newArgument -> {
instruction.getArguments().setArgument(parameter, newArgument);
configureArgumentMenu(instructionName, instruction, parameter, minion, player);
})
)
);
gui.open();
}
public static CompletableFuture<ValueSupplierType<MinionRuntime>> selectArgumentType(ServerPlayerEntity player, MinionFakePlayer minion, ConfiguredInstruction<MinionRuntime> instruction) {
CompletableFuture<ValueSupplierType<MinionRuntime>> future = new CompletableFuture<>();
SimpleGui gui = new InstructionBoundSimpleGui(ScreenHandlerType.GENERIC_9X3, player, minion, instruction);
for (ValueSupplierType<MinionRuntime> type : MinionRegistries.VALUE_SUPPLIER_TYPES) {
gui.addSlot(new GuiElementBuilder(GuiDisplay.getDisplayStackWithName(MinionRegistries.VALUE_SUPPLIER_TYPES, type, player.getRegistryManager()))
.setCallback(() -> future.complete(type))
);
}
gui.open();
return future;
}
public static <T> void configureTypeAndValue(String name, ConfiguredInstruction<MinionRuntime> instruction, Parameter<T> parameter, MinionFakePlayer minion, ServerPlayerEntity player) {
selectArgumentType(player, minion, instruction)
.thenApply(type -> type.openConfiguration(player, parameter.type(), null)
.thenAccept(v -> {
instruction.getArguments().setArgument(parameter, v);
configureArgumentMenu(name, instruction, parameter, minion, player);
})
);
}
}
@@ -1,4 +1,4 @@
package io.github.skippyall.minions.gui;
package io.github.skippyall.minions.gui.instruction;
import eu.pb4.sgui.api.elements.GuiElementBuilder;
import io.github.skippyall.minions.gui.input.ChoiceInput;
@@ -108,7 +108,7 @@ public class ConfigureInstructionGui extends InstructionBoundSimpleGui {
int slot = 12;
for(Parameter<?> parameter : instruction.getInstruction().getParameters().reversed()) {
setSlot(slot, InstructionGui.createParameterElement(parameter, instruction.getArguments().getArgument(parameter), player.getRegistryManager())
.setCallback(() -> InstructionGui.configureArgumentMenu(name, instruction, parameter, minion, player))
.setCallback(() -> ArgumentGui.configureArgumentMenu(name, instruction, parameter, minion, player))
);
slot--;
}
@@ -0,0 +1,71 @@
package io.github.skippyall.minions.gui.instruction;
import eu.pb4.sgui.api.elements.GuiElementBuilder;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.gui.PaginatedList;
import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.conversion.ValueConverter;
import io.github.skippyall.minions.program.conversion.ValueConverterType;
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction;
import io.github.skippyall.minions.program.supplier.Parameter;
import io.github.skippyall.minions.program.supplier.ValueSupplierList;
import io.github.skippyall.minions.program.value.ValueType;
import io.github.skippyall.minions.registration.MinionRegistries;
import net.minecraft.item.Items;
import net.minecraft.registry.DynamicRegistryManager;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
public class ConverterGui {
public static void configureConvertersMenu(ServerPlayerEntity player, MinionFakePlayer minion, ConfiguredInstruction<MinionRuntime> instruction, Parameter<?> parameter, Runnable back) {
InstructionBoundSimpleGui gui = new InstructionBoundSimpleGui(ScreenHandlerType.GENERIC_9X4, player, minion, instruction);
ValueSupplierList.ValueSupplierEntry<?,?,MinionRuntime> entry = instruction.getArguments().getEntry(parameter);
PaginatedList.createList(
gui,
entry.getConverters(),
converter -> createConverterElement(converter, player.getRegistryManager())
.setCallback(() -> configureConverter(player, minion, instruction, parameter, entry, converter)),
back
);
gui.open();
}
public static GuiElementBuilder createConverterElement(ValueConverter<?,?> converter, DynamicRegistryManager manager) {
GuiElementBuilder builder = new GuiElementBuilder(GuiDisplay.getDisplayStack(MinionRegistries.VALUE_CONVERTER_TYPES, converter.getType(), manager));
builder.addLoreLine(converter.getDisplayText());
return builder;
}
public static void configureConverter(ServerPlayerEntity player, MinionFakePlayer minion, ConfiguredInstruction<MinionRuntime> instruction, Parameter<?> parameter, ValueSupplierList.ValueSupplierEntry<?,?,MinionRuntime> entry, @Nullable ValueConverter<?,?> converter) {
InstructionBoundSimpleGui gui = new InstructionBoundSimpleGui(ScreenHandlerType.GENERIC_3X3, player, minion, instruction);
gui.setSlot(3, new GuiElementBuilder(GuiDisplay.getDisplayStackWithName(MinionRegistries.VALUE_CONVERTER_TYPES, converter.getType(), player.getRegistryManager()))
.setCallback(() -> {
InstructionBoundSimpleGui chooseTypeGui = new InstructionBoundSimpleGui(ScreenHandlerType.GENERIC_9X4, player, minion, instruction);
PaginatedList.createList(
chooseTypeGui,
MinionRegistries.VALUE_CONVERTER_TYPES,
type -> new GuiElementBuilder(GuiDisplay.getDisplayStackWithName(MinionRegistries.VALUE_CONVERTER_TYPES, type, player.getRegistryManager()))
.setCallback(() -> {
entry.set
}),
() -> configureConverter(player, minion, instruction, parameter, entry, converter)
);
}));
gui.setSlot(5, new GuiElementBuilder(Items.STRUCTURE_VOID));
gui.open();
}
public static <F,T> void selectConverterMenu(ValueType<F> from, ValueType<T> to, ServerPlayerEntity player, MinionFakePlayer minion, ConfiguredInstruction<MinionRuntime> instruction) {
InstructionBoundSimpleGui gui = new InstructionBoundSimpleGui(ScreenHandlerType.GENERIC_9X3, player, minion, instruction);
for(ValueConverterType<?> valueConverterType : MinionRegistries.VALUE_CONVERTER_TYPES) {
gui.addSlot(new GuiElementBuilder(GuiDisplay.getDisplayStackWithName(MinionRegistries.VALUE_CONVERTER_TYPES, valueConverterType, player.getRegistryManager()))
.setCallback(() -> valueConverterType.configure(player, from, to, null).thenAccept(c -> )));
}
gui.open();
}
}
@@ -1,5 +1,6 @@
package io.github.skippyall.minions.gui;
package io.github.skippyall.minions.gui.instruction;
import io.github.skippyall.minions.gui.MinionBoundSimpleGui;
import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction;
@@ -1,7 +1,9 @@
package io.github.skippyall.minions.gui;
package io.github.skippyall.minions.gui.instruction;
import eu.pb4.sgui.api.elements.GuiElementBuilder;
import eu.pb4.sgui.api.gui.SimpleGui;
import io.github.skippyall.minions.gui.GuiDisplay;
import io.github.skippyall.minions.gui.MinionBoundSimpleGui;
import io.github.skippyall.minions.registration.MinionComponentTypes;
import io.github.skippyall.minions.registration.MinionRegistries;
import io.github.skippyall.minions.gui.input.Result;
@@ -10,7 +12,6 @@ import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.module.MinionModule;
import io.github.skippyall.minions.program.supplier.ValueSupplier;
import io.github.skippyall.minions.program.supplier.ValueSupplierType;
import io.github.skippyall.minions.program.instruction.ConfiguredInstruction;
import io.github.skippyall.minions.program.instruction.InstructionType;
import io.github.skippyall.minions.program.supplier.Parameter;
@@ -99,62 +100,6 @@ public class InstructionGui {
return stillExists;
}
public static <T, A extends ValueSupplier<T, MinionRuntime>> void configureArgumentMenu(String instructionName, ConfiguredInstruction<MinionRuntime> instruction, Parameter<?> parameter, MinionFakePlayer minion, ServerPlayerEntity player) {
if (!checkInstructionExists(instructionName, instruction, minion, player)) {
return;
}
@Nullable ValueSupplier<?, MinionRuntime> argument = instruction.getArguments().getArgument(parameter);
if(argument == null) {
configureTypeAndValue(instructionName, instruction, parameter, minion, player);
return;
}
configureArgumentHelper(instructionName, instruction, parameter, argument, minion, player);
}
private static <T> void configureArgumentHelper(String instructionName, ConfiguredInstruction<MinionRuntime> instruction, Parameter<?> parameter, ValueSupplier<T, MinionRuntime> argument, MinionFakePlayer minion, ServerPlayerEntity player) {
SimpleGui gui = new InstructionBoundSimpleGui(ScreenHandlerType.GENERIC_3X3, player, minion, instruction);
ItemStack displayStack = GuiDisplay.getDisplayStack(MinionRegistries.VALUE_SUPPLIER_TYPES, argument.getType(), player.getRegistryManager());
gui.setSlot(3, new GuiElementBuilder(displayStack)
.setName(Text.translatable("minions.gui.instruction.argument.configure.type", Text.translatable(TranslationUtil.getTranslationKey(argument.getType(), MinionRegistries.VALUE_SUPPLIER_TYPES, "minions.gui.instruction.argument.configure.type.unset"))))
.setCallback(() -> configureTypeAndValue(instructionName, instruction, parameter, minion, player))
);
gui.setSlot(5, new GuiElementBuilder(Items.STRUCTURE_VOID)
.setName(Text.literal("Configure"))
.setCallback(() -> argument.getType().openConfiguration(player, argument.getValueType(), argument)
.thenAccept(newArgument -> instruction.getArguments().setArgument(parameter, newArgument))
)
);
gui.open();
}
public static CompletableFuture<ValueSupplierType<MinionRuntime>> selectArgumentType(ServerPlayerEntity player, MinionFakePlayer minion, ConfiguredInstruction<MinionRuntime> instruction) {
CompletableFuture<ValueSupplierType<MinionRuntime>> future = new CompletableFuture<>();
SimpleGui gui = new InstructionBoundSimpleGui(ScreenHandlerType.GENERIC_9X3, player, minion, instruction);
for (ValueSupplierType<MinionRuntime> type : MinionRegistries.VALUE_SUPPLIER_TYPES) {
gui.addSlot(new GuiElementBuilder(GuiDisplay.getDisplayStackWithName(MinionRegistries.VALUE_SUPPLIER_TYPES, type, player.getRegistryManager()))
.setCallback(() -> future.complete(type))
);
}
gui.open();
return future;
}
public static <T> void configureTypeAndValue(String name, ConfiguredInstruction<MinionRuntime> instruction, Parameter<T> parameter, MinionFakePlayer minion, ServerPlayerEntity player) {
selectArgumentType(player, minion, instruction)
.thenApply(type -> type.openConfiguration(player, parameter.type(), null)
.thenAccept(newArgument -> {
instruction.getArguments().setArgument(parameter, newArgument);
configureArgumentMenu(name, instruction, parameter, minion, player);
})
);
}
public static CompletableFuture<InstructionType<MinionRuntime>> selectInstructionModuleMenu(MinionFakePlayer minion, ServerPlayerEntity player) {
if (minion.getModuleInventory().getModules().isEmpty()) {
player.sendMessage(Text.translatable("minions.gui.instruction.no_modules"));
@@ -0,0 +1,93 @@
package io.github.skippyall.minions.gui.minion;
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.instruction.InstructionGui;
import io.github.skippyall.minions.minion.MinionListener;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.module.ModuleInventory;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.screen.slot.ArmorSlot;
import net.minecraft.screen.slot.Slot;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class MinionGui extends MinionsGui implements MinionListener {
private final MinionFakePlayer minion;
private SimpleGui gui;
public MinionGui(ServerPlayerEntity viewer, MinionFakePlayer minion) {
super(viewer);
this.minion = minion;
minion.addMinionListener(this);
}
public MinionFakePlayer getMinion() {
return minion;
}
@Override
protected void open() {
gui = new SimpleGui(ScreenHandlerType.GENERIC_3X3, viewer, false) {
@Override
public void onClose() {
onBackingClosed();
}
};
gui.setTitle(minion.getName());
gui.setSlot(1, new GuiElementBuilder()
.setItem(Items.COMMAND_BLOCK)
.setName(Text.translatable("minions.gui.main.instructions"))
.setCallback(() -> {
InstructionGui.openInstructionMainMenu(minion, viewer);
})
);
gui.setSlot(3, new GuiElementBuilder()
.setItem(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE)
.setName(Text.translatable("minions.gui.main.modules"))
.setCallback(() -> {
ModuleInventory.openModuleInventory(viewer, minion);
})
);
gui.setSlot(5, new GuiElementBuilder()
.setItem(Items.CHEST)
.setName(Text.translatable("minions.gui.main.inventory"))
.setCallback(() -> new MinionInventoryGui(this))
);
gui.setSlot(7, new GuiElementBuilder()
.setItem(Items.BARRIER)
.setName(Text.translatable("minions.gui.main.pickup"))
.setCallback(() -> minion.kill(minion.getWorld()))
);
gui.open();
}
@Override
protected void reopen() {
gui.open();
}
@Override
protected void onClose() {
gui.close();
minion.removeMinionListener(this);
}
@Override
public void onMinionRemove(MinionFakePlayer minion) {
close();
}
public static GuiElementBuilder backButton(Runnable onBack) {
return new GuiElementBuilder(Items.COMPASS)
.setItemName(Text.translatable("gui.back"))
.setCallback(onBack);
}
}
@@ -1,9 +1,8 @@
package io.github.skippyall.minions.gui;
package io.github.skippyall.minions.gui.minion;
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.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.module.ModuleInventory;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.ItemStack;
@@ -11,51 +10,28 @@ import net.minecraft.item.Items;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.screen.slot.ArmorSlot;
import net.minecraft.screen.slot.Slot;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
public class MinionGui {
public static void openInventory(ServerPlayerEntity player, MinionFakePlayer minion) {
openServerSideInventory(player, minion);
public class MinionInventoryGui extends MinionsGui {
protected final MinionGui parent;
private final MinionFakePlayer minion;
private SimpleGui gui;
public MinionInventoryGui(MinionGui parent) {
super(parent);
this.parent = parent;
this.minion = parent.getMinion();
}
public static void openServerSideInventory(ServerPlayerEntity player, MinionFakePlayer minion) {
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_3X3, player, false);
gui.setTitle(minion.getName());
gui.setSlot(1, new GuiElementBuilder()
.setItem(Items.COMMAND_BLOCK)
.setName(Text.translatable("minions.gui.main.instructions"))
.setCallback((i, clickType, slotActionType) -> {
InstructionGui.openInstructionMainMenu(minion, player);
})
);
gui.setSlot(3, new GuiElementBuilder()
.setItem(Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE)
.setName(Text.translatable("minions.gui.main.modules"))
.setCallback(() -> {
ModuleInventory.openModuleInventory(player, minion);
})
);
gui.setSlot(5, new GuiElementBuilder()
.setItem(Items.CHEST)
.setName(Text.translatable("minions.gui.main.inventory"))
.setCallback(() -> {
openMinionInventory(player, minion);
})
);
gui.setSlot(7, new GuiElementBuilder()
.setItem(Items.BARRIER)
.setName(Text.translatable("minions.gui.main.pickup"))
.setCallback(() -> {
minion.kill(minion.getWorld());
})
);
gui.open();
@Override
protected void open() {
gui = new SimpleGui(ScreenHandlerType.GENERIC_9X6, viewer, false) {
@Override
public void onClose() {
onBackingClosed();
}
public static void openMinionInventory(ServerPlayerEntity player, MinionFakePlayer minion) {
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_9X6, player, false);
};
gui.setTitle(Text.translatable("minions.gui.inventory.title"));
for(int i = 0; i < 18; i++) {
@@ -83,4 +59,9 @@ public class MinionGui {
}
gui.open();
}
@Override
protected void onClose() {
gui.close();
}
}
@@ -7,7 +7,7 @@ import io.github.skippyall.minions.registration.MinionConfigOptions;
import io.github.skippyall.minions.registration.MinionItems;
import io.github.skippyall.minions.minion.MinionListener;
import io.github.skippyall.minions.minion.MinionData;
import io.github.skippyall.minions.gui.MinionGui;
import io.github.skippyall.minions.gui.minion.MinionGui;
import io.github.skippyall.minions.minion.MinionRuntime;
import io.github.skippyall.minions.minion.MinionItem;
import io.github.skippyall.minions.minion.MinionPersistentState;
@@ -24,7 +24,6 @@ import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.HungerManager;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.vehicle.AbstractBoatEntity;
import net.minecraft.entity.vehicle.BoatEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.DisconnectionInfo;
import net.minecraft.network.NetworkSide;
@@ -156,7 +155,7 @@ public class MinionFakePlayer extends ServerPlayerEntity {
@Override
public ActionResult interact(PlayerEntity player, Hand hand) {
if(player instanceof ServerPlayerEntity spe) {
MinionGui.openInventory(spe, this);
new MinionGui(spe, this);
}
return ActionResult.CONSUME;
}
@@ -62,7 +62,7 @@ public class AnalogInputSupplier implements ValueSupplier<Long, MinionRuntime> {
@Override
public Text getDisplayText() {
return Text.translatable("value_supplier_type.minions.analog_input.display", analogInputPos.toString(), analogInputWorld.getValue());
return Text.translatable("value_supplier_type.minions.analog_input.display", analogInputPos.toString(), analogInputWorld.getValue().toString());
}
public static class AnalogInputSupplierType extends ValueSupplierType<MinionRuntime> {
@@ -75,12 +75,8 @@ public class AnalogInputSupplier implements ValueSupplier<Long, MinionRuntime> {
}
@Override
public <T> CompletableFuture<ValueSupplier<T, MinionRuntime>> openConfiguration(ServerPlayerEntity player, ValueType<T> valueType, @Nullable ValueSupplier<T, MinionRuntime> previous) {
if(valueType != ValueTypes.LONG) {
return CompletableFuture.failedFuture(new IllegalArgumentException("Value type " + valueType + " not allowed"));
}
CompletableFuture<ValueSupplier<T, MinionRuntime>> future = new CompletableFuture<>();
public <T> CompletableFuture<ValueSupplier<?, MinionRuntime>> openConfiguration(ServerPlayerEntity player, ValueType<T> valueType, @Nullable ValueSupplier<T, MinionRuntime> previous) {
CompletableFuture<ValueSupplier<?, MinionRuntime>> future = new CompletableFuture<>();
SimpleGui gui = new SimpleGui(ScreenHandlerType.GENERIC_3X3, player, false);
gui.setTitle(Text.translatable("value_supplier_type.minions.analog_input"));
@@ -89,11 +85,12 @@ public class AnalogInputSupplier implements ValueSupplier<Long, MinionRuntime> {
.setCallback(() -> {
ItemStack cursor = player.currentScreenHandler.getCursorStack();
if(cursor.isOf(MinionItems.REFERENCE_ITEM) && cursor.get(MinionComponentTypes.REFERENCE) instanceof BlockPosClipboard pos) {
future.complete(new AnalogInputSupplier(pos.world(), pos.pos()).cast(valueType));
future.complete(new AnalogInputSupplier(pos.world(), pos.pos()));
}
})
.setItemName(Text.translatable("value_supplier_type.minions.analog_input.config.click_with_reference"))
);
gui.open();
return future;
}
}
@@ -1,4 +1,6 @@
package io.github.skippyall.minions.program.value;
package io.github.skippyall.minions.program.conversion;
import io.github.skippyall.minions.program.value.ValueType;
public class Cast<F, T> {
private final ValueType<F> from;
@@ -0,0 +1,64 @@
package io.github.skippyall.minions.program.conversion;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.github.skippyall.minions.program.value.ValueType;
import io.github.skippyall.minions.registration.MinionRegistries;
import io.github.skippyall.minions.registration.ValueConverters;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
public class CastConverter<F,T> implements ValueConverter<F,T> {
private static final MapCodec<CastConverter<?,?>> CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group(
MinionRegistries.VALUE_TYPES.getCodec().fieldOf("from").forGetter(CastConverter::getFrom),
MinionRegistries.VALUE_TYPES.getCodec().fieldOf("to").forGetter(CastConverter::getTo)
).apply(instance, CastConverter::new)
);
private final ValueType<F> from;
private final ValueType<T> to;
public CastConverter(ValueType<F> from, ValueType<T> to) {
this.from = from;
this.to = to;
}
@Override
public T convert(F fromValue) {
return Casts.getCast(from, to).cast(fromValue);
}
@Override
public ValueType<F> getFrom() {
return from;
}
@Override
public ValueType<T> getTo() {
return to;
}
@Override
public ValueConverterType<?> getType() {
return ValueConverters.CAST_CONVERTER;
}
public static class Type implements ValueConverterType<CastConverter<?,?>> {
@Override
public MapCodec<CastConverter<?, ?>> getCodec() {
return CastConverter.CODEC;
}
@Override
public boolean isSupportedConversion(ValueType<?> from, ValueType<?> to) {
return Casts.getCast(from, to) != null;
}
@Override
public <F,T> CompletableFuture<CastConverter<?,?>> configure(ServerPlayerEntity player, ValueType<F> from, ValueType<T> to, @Nullable CastConverter<?, ?> old) {
return CompletableFuture.completedFuture(new CastConverter<>(from, to));
}
}
}
@@ -1,5 +1,6 @@
package io.github.skippyall.minions.program.value;
package io.github.skippyall.minions.program.conversion;
import io.github.skippyall.minions.program.value.ValueType;
import io.github.skippyall.minions.registration.ValueTypes;
import org.jetbrains.annotations.Nullable;
@@ -0,0 +1,73 @@
package io.github.skippyall.minions.program.conversion;
import com.mojang.serialization.MapCodec;
import io.github.skippyall.minions.program.value.ValueType;
import io.github.skippyall.minions.registration.MinionRegistries;
import io.github.skippyall.minions.registration.ValueTypes;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
public class EqualityConverter<F> implements ValueConverter<F, Boolean> {
public static final MapCodec<EqualityConverter<?>> CODEC = MinionRegistries.VALUE_TYPES.getCodec().dispatchMap(
EqualityConverter::getFrom,
EqualityConverter::getCodec
);
private ValueType<F> fromType;
private F compareValue;
public EqualityConverter(ValueType<F> fromType, F compareValue) {
this.fromType = fromType;
this.compareValue = compareValue;
}
@Override
public Boolean convert(F from) {
return compareValue.equals(from);
}
@Override
public ValueType<F> getFrom() {
return fromType;
}
@Override
public ValueType<Boolean> getTo() {
return ValueTypes.BOOLEAN;
}
@Override
public ValueConverterType<?> getType() {
return null;
}
private static <F> MapCodec<EqualityConverter<F>> getCodec(ValueType<F> fromType) {
return fromType.codec().fieldOf("compareValue")
.xmap(compareValue -> new EqualityConverter<>(fromType, compareValue), converter -> converter.compareValue);
}
public static class EqualityConverterType implements ValueConverterType<EqualityConverter<?>> {
@Override
public MapCodec<EqualityConverter<?>> getCodec() {
return CODEC;
}
@Override
public boolean isSupportedConversion(ValueType<?> from, ValueType<?> to) {
return to == ValueTypes.BOOLEAN;
}
@Override
public <F,T> CompletableFuture<EqualityConverter<?>> configure(ServerPlayerEntity player, ValueType<F> from, ValueType<T> to, @Nullable EqualityConverter<?> old) {
if(to == ValueTypes.BOOLEAN) {
//noinspection unchecked
return from.openValueDialog(player, old != null && old.fromType == from ? (F) old.compareValue : null)
.thenApply(compareValue -> new EqualityConverter<>(from, compareValue));
} else {
return CompletableFuture.failedFuture(new IllegalArgumentException("EqualityConverter does not support converting to " + to));
}
}
}
}
@@ -0,0 +1,29 @@
package io.github.skippyall.minions.program.conversion;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.value.ValueType;
import io.github.skippyall.minions.registration.MinionRegistries;
import net.minecraft.text.Text;
public interface ValueConverter<F,T> {
Codec<ValueConverter<?,?>> CODEC = MinionRegistries.VALUE_CONVERTER_TYPES.getCodec().dispatch(ValueConverter::getType, ValueConverterType::getCodec);
T convert(F from);
ValueType<F> getFrom();
ValueType<T> getTo();
ValueConverterType<?> getType();
Text getDisplayText();
default <F2,T2> ValueConverter<F2,T2> cast(ValueType<F2> from, ValueType<T2> to) {
if(from == getFrom() && to == getTo()) {
//noinspection unchecked
return (ValueConverter<F2, T2>) this;
} else {
return null;
}
}
}
@@ -0,0 +1,16 @@
package io.github.skippyall.minions.program.conversion;
import com.mojang.serialization.MapCodec;
import io.github.skippyall.minions.program.value.ValueType;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
public interface ValueConverterType<C extends ValueConverter<?,?>> {
MapCodec<C> getCodec();
boolean isSupportedConversion(ValueType<?> from, ValueType<?> to);
<F,T> CompletableFuture<C> configure(ServerPlayerEntity player, ValueType<F> from, ValueType<T> to, @Nullable C old);
}
@@ -11,6 +11,10 @@ import net.minecraft.storage.ReadView;
import net.minecraft.storage.WriteView;
import org.jetbrains.annotations.Nullable;
/**
* Holds an instruction, its configuration and is responsible for executing the instruction
* @param <R> The runtime holding this object
*/
public class ConfiguredInstruction<R extends InstructionRuntime<R>> {
private final InstructionType<R> instruction;
private final ValueSupplierList<R> arguments;
@@ -48,7 +52,7 @@ public class ConfiguredInstruction<R extends InstructionRuntime<R>> {
}
public boolean canRun() {
return instruction != null && arguments != null && arguments.hasArgumentForAll(instruction.getParameters());
return instruction != null && arguments != null && arguments.checkRun(instruction).isSuccess();
}
public boolean isRunning() {
@@ -9,6 +9,11 @@ import java.util.Collection;
import java.util.List;
import java.util.function.Supplier;
/**
* Defines the semantics of an instruction and creates {@link InstructionExecution}
* InstructionTypes for minions can be registered to {@link io.github.skippyall.minions.registration.MinionRegistries#INSTRUCTION_TYPES}
* @param <R> The runtime that this instruction can be executed in
*/
public class InstructionType<R extends InstructionRuntime<R>> {
private final List<Parameter<?>> parameters;
private final List<Parameter<?>> returnParameters;
@@ -1,6 +1,7 @@
package io.github.skippyall.minions.program.supplier;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.github.skippyall.minions.program.value.SimpleValueType;
import io.github.skippyall.minions.registration.MinionRegistries;
@@ -8,11 +9,12 @@ import io.github.skippyall.minions.program.value.ValueType;
import org.jetbrains.annotations.Nullable;
public record Parameter<T>(String name, ValueType<T> type) {
public static final Codec<Parameter<?>> CODEC = RecordCodecBuilder.create(instance ->
public static final MapCodec<Parameter<?>> MAP_CODEC = RecordCodecBuilder.mapCodec(instance ->
instance.group(
Codec.STRING.fieldOf("name").forGetter(Parameter::name),
MinionRegistries.VALUE_TYPES.getCodec().fieldOf("type").forGetter(Parameter::type)
).apply(instance, Parameter::new));
public static final Codec<Parameter<?>> CODEC = MAP_CODEC.codec();
public <U> @Nullable Parameter<U> cast(ValueType<U> type) {
if(this.type == type) {
@@ -1,69 +1,100 @@
package io.github.skippyall.minions.program.supplier;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import io.github.skippyall.minions.gui.input.Result;
import io.github.skippyall.minions.program.InstructionRuntime;
import io.github.skippyall.minions.program.value.Cast;
import io.github.skippyall.minions.program.value.Casts;
import io.github.skippyall.minions.program.conversion.Cast;
import io.github.skippyall.minions.program.conversion.Casts;
import io.github.skippyall.minions.program.conversion.ValueConverter;
import io.github.skippyall.minions.program.instruction.InstructionType;
import io.github.skippyall.minions.program.value.ValueType;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
public class ValueSupplierList<R extends InstructionRuntime<R>> {
private final Map<String, ValueSupplier<?, R>> arguments;
private final Map<Parameter<?>, ValueSupplierEntry<?,?,R>> arguments = new HashMap<>();
private final List<Consumer<Parameter<?>>> changeListeners = new ArrayList<>();
public ValueSupplierList() {
arguments = new HashMap<>();
}
public ValueSupplierList(Map<String, ValueSupplier<?,R>> arguments) {
this.arguments = new HashMap<>(arguments);
private ValueSupplierList(List<ValueSupplierEntry<?,?,R>> arguments) {
for(ValueSupplierEntry<?,?,R> argument : arguments) {
this.arguments.put(argument.parameter, argument);
}
}
public <F, T> T getValue(Parameter<T> parameter, R runtime) {
//noinspection unchecked
ValueSupplier<F,R> valueSupplier = (ValueSupplier<F, R>) getArgument(parameter);
if(valueSupplier == null) {
return null;
private List<ValueSupplierEntry<?,?,R>> toCodecList() {
return List.copyOf(arguments.values());
}
if(valueSupplier.getValueType() == parameter.type()) {
return valueSupplier.cast(parameter.type()).resolve(runtime);
} else {
Cast<F,T> cast = Casts.getCast(valueSupplier.getValueType(), parameter.type());
if(cast != null) {
return cast.cast(valueSupplier.resolve(runtime));
}
}
return null;
public <T> T getValue(Parameter<T> parameter, R runtime) {
ValueSupplierEntry<?,?,R> entry = getEntry(parameter);
return parameter.type().checkedCast(entry.getValue(runtime));
}
public ValueSupplier<?,R> getArgument(Parameter<?> parameter) {
return arguments.get(parameter.name());
if(arguments.containsKey(parameter)) {
return arguments.get(parameter).supplier;
} else {
return null;
}
}
public <T> void setArgument(Parameter<T> parameter, ValueSupplier<?,R> valueSupplier) {
arguments.put(parameter.name(), valueSupplier);
public <P> ValueSupplierEntry<P,?,R> getEntry(Parameter<P> parameter) {
//noinspection unchecked
return (ValueSupplierEntry<P, ?, R>) arguments.get(parameter);
}
public void setArgument(Parameter<?> parameter, ValueSupplier<?,R> valueSupplier) {
arguments.put(parameter, new ValueSupplierEntry<>(parameter, valueSupplier, List.of()));
onChange(parameter);
}
public void setArgument(Parameter<?> parameter, ValueSupplier<?,R> valueSupplier, List<ValueConverter<?, ?>> converter) {
arguments.put(parameter, new ValueSupplierEntry<>(parameter, valueSupplier, converter));
onChange(parameter);
}
public boolean hasArgumentFor(Parameter<?> parameter) {
return arguments.containsKey(parameter.name());
return arguments.containsKey(parameter);
}
public boolean hasArgumentForAll(Collection<Parameter<?>> checkParameters) {
public Result<@Nullable Void, Text> checkHasArguments(Collection<Parameter<?>> checkParameters) {
for(Parameter<?> parameter : checkParameters) {
if(!hasArgumentFor(parameter)) {
return false;
return new Result.Error<>(Text.translatable("minions.gui.instruction.check.argument_not_set", parameter.name()));
}
}
return true;
return new Result.Success<>(null);
}
public Result<@Nullable Void, Text> checkRun(InstructionType<R> instructionType) {
Result<@Nullable Void, Text> checkResult = checkHasArguments(instructionType.getParameters());
if(!checkResult.isSuccess()) {
return checkResult;
}
for(ValueSupplierEntry<?,?,R> entry : arguments.values()) {
checkResult = entry.check();
if(!checkResult.isSuccess()) {
return checkResult;
}
}
return new Result.Success<>(null);
}
private void onChange(Parameter<?> parameter) {
for (Consumer<Parameter<?>> listener : changeListeners) {
@@ -80,7 +111,98 @@ public class ValueSupplierList<R extends InstructionRuntime<R>> {
}
public static <R extends InstructionRuntime<R>> Codec<ValueSupplierList<R>> getCodec(Codec<ValueSupplier<?,R>> argumentCodec) {
return Codec.unboundedMap(Codec.STRING, argumentCodec)
.xmap(ValueSupplierList::new, list -> list.arguments);
return ValueSupplierEntry.getCodec(argumentCodec)
.codec()
.listOf()
.xmap(ValueSupplierList::new, ValueSupplierList::toCodecList);
}
public static class ValueSupplierEntry<S, P, R extends InstructionRuntime<R>> {
private Parameter<P> parameter;
private ValueSupplier<S,R> supplier;
private List<ValueConverter<?,?>> converters;
public ValueSupplierEntry(Parameter<P> parameter, ValueSupplier<S, R> supplier, Collection<ValueConverter<?, ?>> converters) {
this.parameter = parameter;
this.supplier = supplier;
this.converters = new LinkedList<>(converters);
}
public List<ValueConverter<?,?>> getConverters() {
return converters;
}
public Parameter<P> getParameter() {
return parameter;
}
public ValueSupplier<S, R> getSupplier() {
return supplier;
}
public void setParameter(Parameter<P> parameter) {
this.parameter = parameter;
}
public void setSupplier(ValueSupplier<S, R> supplier) {
this.supplier = supplier;
}
public void setConverters(List<ValueConverter<?, ?>> converters) {
this.converters = converters;
}
public @Nullable P getValue(R runtime) {
S value = supplier.resolve(runtime);
Iterator<ValueConverter<?,?>> iterator = converters.iterator();
Object convertedValue = convert(supplier.getValueType(), value, iterator.next(), iterator);
return finalCast(convertedValue);
}
private <F> @Nullable P finalCast(Object value) {
//noinspection unchecked
ValueType<F> lastConvertedType = (ValueType<F>) converters.getLast().getTo();
F convertedValue = lastConvertedType.checkedCast(value);
if(convertedValue == null) {
return null;
}
Cast<F,P> cast = Casts.getCast(lastConvertedType, parameter.type());
if(cast != null) {
return cast.cast(convertedValue);
}
return null;
}
private <F,I,T> @Nullable Object convert(ValueType<F> fromType, F from, ValueConverter<I,T> converter, Iterator<ValueConverter<?,?>> iterator) {
Cast<F, I> cast = Casts.getCast(fromType, converter.getFrom());
if(cast == null) {
return null;
}
I inter = cast.cast(from);
if(inter == null) {
return null;
}
T to = converter.convert(inter);
if(iterator.hasNext() && to != null) {
return convert(converter.getTo(), to, iterator.next(), iterator);
} else {
return to;
}
}
public Result<@Nullable Void, Text> check() {
return new Result.Success<>(null);
}
public static <R extends InstructionRuntime<R>> MapCodec<ValueSupplierEntry<?,?,R>> getCodec(Codec<ValueSupplier<?,R>> argumentCodec) {
return RecordCodecBuilder.mapCodec(instance -> instance.group(
Parameter.CODEC.fieldOf("parameter").forGetter(e -> e.parameter),
argumentCodec.fieldOf("argument").forGetter(e -> e.supplier),
ValueConverter.CODEC.listOf().optionalFieldOf("converter", List.of()).forGetter(e -> e.converters)
).apply(instance, ValueSupplierEntry::new));
}
}
}
@@ -11,5 +11,5 @@ import java.util.concurrent.CompletableFuture;
public abstract class ValueSupplierType<R extends InstructionRuntime<R>> {
public abstract <T> Codec<? extends ValueSupplier<T,R>> getCodec(ValueType<T> type);
public abstract <T> CompletableFuture<? extends ValueSupplier<T,R>> openConfiguration(ServerPlayerEntity player, ValueType<T> valueType, @Nullable ValueSupplier<T,R> previous);
public abstract <T> CompletableFuture<? extends ValueSupplier<?,R>> openConfiguration(ServerPlayerEntity player, ValueType<T> valueType, @Nullable ValueSupplier<T,R> previous);
}
@@ -1,29 +0,0 @@
package io.github.skippyall.minions.program.value;
import com.mojang.serialization.Codec;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import java.util.concurrent.CompletableFuture;
public class LongValueType implements ValueType<Long> {
@Override
public CompletableFuture<Long> openValueDialog(ServerPlayerEntity player, Long previousValue) {
return null;
}
@Override
public Text getDisplayText(Long value) {
return null;
}
@Override
public Codec<Long> codec() {
return null;
}
@Override
public Long defaultValue() {
return 0L;
}
}
@@ -9,7 +9,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Function;
public record SimpleValueType<T>(Codec<T> codec, T defaultValue, BiFunction<ServerPlayerEntity, T, CompletableFuture<T>> valueDialogOpener, Function<T, Text> textDisplay) implements ValueType<T> {
public record SimpleValueType<T>(Codec<T> codec, T defaultValue, Function<Object, T> checkedCast, BiFunction<ServerPlayerEntity, T, CompletableFuture<T>> valueDialogOpener, Function<T, Text> textDisplay) implements ValueType<T> {
@Override
public CompletableFuture<T> openValueDialog(ServerPlayerEntity player, T previousValue) {
return valueDialogOpener.apply(player, previousValue);
@@ -19,4 +19,9 @@ public record SimpleValueType<T>(Codec<T> codec, T defaultValue, BiFunction<Serv
public Text getDisplayText(T value) {
return textDisplay.apply(value);
}
@Override
public T checkedCast(Object value) {
return checkedCast.apply(value);
}
}
@@ -17,4 +17,10 @@ public interface ValueType<T> {
Codec<T> codec();
T defaultValue();
@Nullable T checkedCast(Object value);
default boolean isOf(Object value) {
return checkedCast(value) != null;
}
}
@@ -1,13 +0,0 @@
package io.github.skippyall.minions.program.value.conversion;
import io.github.skippyall.minions.program.value.ValueType;
public interface ValueConverter<F,T> {
T convert(F from);
ValueType<F> getFrom();
ValueType<T> getTo();
ValueConverterType<?> getType();
}
@@ -1,18 +0,0 @@
package io.github.skippyall.minions.program.value.conversion;
import com.mojang.serialization.Codec;
import io.github.skippyall.minions.program.value.ValueType;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.CompletableFuture;
public interface ValueConverterType<C extends ValueConverter<?,?>> {
Codec<C> getCodec(ValueType<?> from, ValueType<?> to);
boolean isSupportedFromType(ValueType<?> type);
boolean isSupportedToType(ValueType<?> type);
CompletableFuture<C> configure(ServerPlayerEntity player, ValueType<?> from, ValueType<?> to, @Nullable C old);
}
@@ -16,7 +16,7 @@ import java.util.UUID;
public class MinionComponentTypes {
public static final ComponentType<UUID> MINION_DATA = register("minion_data", ComponentType.<UUID>builder().codec(Uuids.CODEC).build());
public static final ComponentType<MinionModule> MODULE = register("minion_module", ComponentType.<MinionModule>builder().codec(MinionModule.CODEC).build());
public static final ComponentType<Clipboard> REFERENCE = ComponentType.<Clipboard>builder().codec(Clipboard.CODEC).build();
public static final ComponentType<Clipboard> REFERENCE = register("reference", ComponentType.<Clipboard>builder().codec(Clipboard.CODEC).build());
private static <T extends ComponentType<?>> T register(String name, T type) {
Registry.register(Registries.DATA_COMPONENT_TYPE, Identifier.of(Minions.MOD_ID, name), type);
@@ -15,6 +15,7 @@ public class MinionRegistration {
MinionListeners.register();
SkinProviders.register();
SpecialAbilities.register();
ValueConverters.register();
ValueSuppliers.register();
ValueTypes.register();
@@ -17,6 +17,7 @@ import io.github.skippyall.minions.program.instruction.InstructionType;
import io.github.skippyall.minions.program.consumer.ValueConsumerType;
import io.github.skippyall.minions.program.value.ValueType;
import io.github.skippyall.minions.clipboard.Clipboard;
import io.github.skippyall.minions.program.conversion.ValueConverterType;
import net.fabricmc.fabric.api.event.registry.DynamicRegistries;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import net.fabricmc.fabric.api.event.registry.RegistryAttribute;
@@ -29,6 +30,8 @@ public class MinionRegistries {
public static final Registry<ValueSupplierType<MinionRuntime>> VALUE_SUPPLIER_TYPES = registry("value_supplier_type");
public static final Registry<ValueConsumerType<MinionRuntime>> VALUE_CONSUMER_TYPES = registry("value_consumer_type");
public static final Registry<InstructionType<MinionRuntime>> INSTRUCTION_TYPES = registry("instruction_type");
public static final Registry<ValueConverterType<?>> VALUE_CONVERTER_TYPES = registry("value_converter_type");
public static final Registry<SkinProvider> SKIN_PROVIDERS = registry("skin_provider");
public static final Registry<Codec<? extends GuiDisplay>> GUI_DISPLAY_TYPE = registry("gui_display_type");
public static final Registry<Codec<? extends ConfiguredInstructionListener>> INSTRUCTION_LISTENER_CODECS = registry("instruction_listener_codec");
@@ -0,0 +1,19 @@
package io.github.skippyall.minions.registration;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.program.conversion.CastConverter;
import io.github.skippyall.minions.program.conversion.EqualityConverter;
import io.github.skippyall.minions.program.conversion.ValueConverterType;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
public class ValueConverters {
public static final EqualityConverter.EqualityConverterType EQUALITY_CONVERTER = register("equality_converter", new EqualityConverter.EqualityConverterType());
public static final CastConverter.Type CAST_CONVERTER = register("cast_converter", new CastConverter.Type());
private static <T extends ValueConverterType<?>> T register(String name, T type) {
return Registry.register(MinionRegistries.VALUE_CONVERTER_TYPES, Identifier.of(Minions.MOD_ID, name), type);
}
public static void register() {}
}
@@ -8,85 +8,88 @@ import io.github.skippyall.minions.gui.input.ChoiceInput;
import io.github.skippyall.minions.gui.input.TextInput;
import io.github.skippyall.minions.minion.program.instruction.move.TurnDirection;
import net.minecraft.registry.Registry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Function;
public class ValueTypes {
public static ValueType<Long> LONG = registerSimple(
public static ValueType<Long> LONG = register(
"long",
new SimpleValueType<>(
Codec.LONG,
0L,
o -> o instanceof Long l ? l : null,
(player, oldValue) -> TextInput.inputLong(
player,
Text.literal("Integer"),
String.valueOf(oldValue)
),
value -> Text.literal(value.toString())
)
);
public static ValueType<Double> DOUBLE = registerSimple(
public static ValueType<Double> DOUBLE = register(
"double",
new SimpleValueType<>(
Codec.DOUBLE,
0D,
o -> o instanceof Double d ? d : null,
(player, oldValue) -> TextInput.inputDouble(
player,
Text.literal("Number"),
String.valueOf(oldValue)
),
value -> Text.literal(value.toString())
)
);
public static ValueType<Boolean> BOOLEAN = registerSimple(
public static ValueType<Boolean> BOOLEAN = register(
"boolean",
new SimpleValueType<>(
Codec.BOOL,
false,
o -> o instanceof Boolean b ? b : null,
ChoiceInput.inputBoolean(Text.literal("")),
value -> Text.literal(value.toString())
)
);
public static ValueType<String> STRING = registerSimple(
public static ValueType<String> STRING = register(
"string",
new SimpleValueType<>(
Codec.STRING,
"",
o -> o instanceof String s ? s : null,
((player, oldValue) -> TextInput.inputString(
player,
Text.literal("Text"),
oldValue)
),
value -> Text.literal("\"" + value + "\"")
);
public static ValueType<TurnDirection> TURN_DIRECTION = registerSimple(
"turn_direction",
TurnDirection.CODEC,
TurnDirection.RIGHT,
ChoiceInput.createDialogOpener(TurnDirection.values()),
value -> Text.literal(value.name)
);
private static <T> ValueType<T> registerSimple(
String id,
Codec<T> codec,
T defaultValue,
BiFunction<ServerPlayerEntity, T, CompletableFuture<T>> valueDialogOpener,
Function<T, Text> textDisplay
) {
Identifier identifier = Identifier.of(Minions.MOD_ID, id);
return Registry.register(
MinionRegistries.VALUE_TYPES,
identifier,
new SimpleValueType<>(
codec,
defaultValue,
valueDialogOpener,
textDisplay
)
);
public static ValueType<TurnDirection> TURN_DIRECTION = register(
"turn_direction",
new SimpleValueType<>(
TurnDirection.CODEC,
TurnDirection.RIGHT,
o -> o instanceof TurnDirection d ? d : null,
ChoiceInput.createDialogOpener(TurnDirection.values()),
value -> Text.literal(value.name)
)
);
private static <T extends ValueType<?>> T register(
String id,
T type
) {
Identifier identifier = Identifier.of(Minions.MOD_ID, id);
Registry.register(
MinionRegistries.VALUE_TYPES,
identifier,
type
);
return type;
}
public static void register() {}
@@ -8,6 +8,7 @@
"minions.gui.ok": "OK",
"minions.gui.confirm": "Confirm",
"minions.gui.abort": "Abort",
"minions.gui.back": "Back",
"minions.gui.look.skin.name": "Name",
"minions.gui.look.skin.name.title": "Enter a player name",
@@ -39,6 +40,8 @@
"minions.gui.instruction.parameter": "%s: %s",
"minions.gui.instruction.argument": "Argument: %s",
"minions.gui.instruction.check.argument_not_set": "Argument %s is not set",
"minions.command.input.int.fail": "Not an integer",
"minions.command.input.float.fail": "Not a number",
"minions.command.action.details": "Set how to %s",