diff --git a/src/main/java/io/github/skippyall/minions/MinionMixinConfigPlugin.java b/src/main/java/io/github/skippyall/minions/MinionMixinConfigPlugin.java index 7528226..6ec26ee 100644 --- a/src/main/java/io/github/skippyall/minions/MinionMixinConfigPlugin.java +++ b/src/main/java/io/github/skippyall/minions/MinionMixinConfigPlugin.java @@ -1,6 +1,7 @@ package io.github.skippyall.minions; import net.fabricmc.loader.api.FabricLoader; +import org.jspecify.annotations.Nullable; import org.objectweb.asm.tree.ClassNode; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; @@ -15,6 +16,7 @@ public class MinionMixinConfigPlugin implements IMixinConfigPlugin { } @Override + @Nullable public String getRefMapperConfig() { return null; } @@ -34,6 +36,7 @@ public class MinionMixinConfigPlugin implements IMixinConfigPlugin { public void acceptTargets(Set myTargets, Set otherTargets) {} @Override + @Nullable public List getMixins() { return null; } diff --git a/src/main/java/io/github/skippyall/minions/Minions.java b/src/main/java/io/github/skippyall/minions/Minions.java index 4231b3c..d259d2a 100644 --- a/src/main/java/io/github/skippyall/minions/Minions.java +++ b/src/main/java/io/github/skippyall/minions/Minions.java @@ -10,7 +10,8 @@ import io.github.skippyall.minions.registration.MinionRegistration; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; -import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.fabric.api.resource.v1.ResourceLoader; +import net.minecraft.resources.Identifier; import net.minecraft.server.packs.PackType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,6 +41,6 @@ public class Minions implements ModInitializer { PolymerResourcePackUtils.addModAssets(Minions.MOD_ID); - ResourceManagerHelper.get(PackType.SERVER_DATA).registerReloadListener(new DocsManager()); + ResourceLoader.get(PackType.SERVER_DATA).registerReloadListener(Identifier.fromNamespaceAndPath(Minions.MOD_ID, "docs"), new DocsManager()); } } diff --git a/src/main/java/io/github/skippyall/minions/MinionsConfig.java b/src/main/java/io/github/skippyall/minions/MinionsConfig.java index fb05f23..10b5d40 100644 --- a/src/main/java/io/github/skippyall/minions/MinionsConfig.java +++ b/src/main/java/io/github/skippyall/minions/MinionsConfig.java @@ -11,13 +11,14 @@ import com.electronwill.nightconfig.core.serde.annotations.SerdeComment; import com.electronwill.nightconfig.toml.TomlFormat; import com.electronwill.nightconfig.toml.TomlParser; import net.fabricmc.loader.api.FabricLoader; +import org.jspecify.annotations.Nullable; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; public class MinionsConfig { - private static MinionsConfig INSTANCE; + private static @Nullable MinionsConfig INSTANCE; public Minion minion = new Minion(); diff --git a/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlockItem.java b/src/main/java/io/github/skippyall/minions/block/MinionsBlockItem.java similarity index 59% rename from src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlockItem.java rename to src/main/java/io/github/skippyall/minions/block/MinionsBlockItem.java index d6c6838..3a7a0c8 100644 --- a/src/main/java/io/github/skippyall/minions/block/miniontrigger/MinionTriggerBlockItem.java +++ b/src/main/java/io/github/skippyall/minions/block/MinionsBlockItem.java @@ -1,20 +1,30 @@ -package io.github.skippyall.minions.block.miniontrigger; +package io.github.skippyall.minions.block; import eu.pb4.polymer.core.api.item.PolymerBlockItem; import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils; +import io.github.skippyall.minions.polymer.VersionSync; import net.fabricmc.fabric.api.networking.v1.context.PacketContext; import net.minecraft.core.HolderLookup; import net.minecraft.resources.Identifier; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; -public class MinionTriggerBlockItem extends PolymerBlockItem { - public MinionTriggerBlockItem(Block block, Properties settings, Item polymerItem) { +public class MinionsBlockItem extends PolymerBlockItem { + public MinionsBlockItem(Block block, Properties settings, Item polymerItem) { super(block, settings, polymerItem, true); } + @Override + public Item getPolymerItem(ItemStack itemStack, PacketContext context) { + if(VersionSync.isOnClient(context)) { + return this; + } else { + return super.getPolymerItem(itemStack, context); + } + } + @Override public @Nullable Identifier getPolymerItemModel(ItemStack stack, PacketContext context, HolderLookup.Provider lookup) { if(PolymerResourcePackUtils.hasMainPack(context)) { diff --git a/src/main/java/io/github/skippyall/minions/block/input/package-info.java b/src/main/java/io/github/skippyall/minions/block/input/package-info.java new file mode 100644 index 0000000..c2a72cd --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/block/input/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.block.input; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/block/instruction_bound/InstructionBoundBlockEntity.java b/src/main/java/io/github/skippyall/minions/block/instruction_bound/InstructionBoundBlockEntity.java index bb76dbd..6d21c99 100644 --- a/src/main/java/io/github/skippyall/minions/block/instruction_bound/InstructionBoundBlockEntity.java +++ b/src/main/java/io/github/skippyall/minions/block/instruction_bound/InstructionBoundBlockEntity.java @@ -9,12 +9,13 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.UUID; public abstract class InstructionBoundBlockEntity> extends BlockEntity { - protected UUID minionUuid; + protected @Nullable UUID minionUuid; protected String instructionName = ""; public InstructionBoundBlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { @@ -56,7 +57,7 @@ public abstract class InstructionBoundBlockEntity CODEC = simpleCodec(MinionTriggerBlock::new); @@ -70,6 +71,7 @@ public class MinionTriggerBlock extends InstructionBoundBlock implements Polymer } @Override + @NullMarked protected void neighborChanged(BlockState state, Level world, BlockPos pos, Block sourceBlock, @Nullable Orientation wireOrientation, boolean notify) { if(!canSurvive(state, world, pos)) { dropResources(state, world, pos); @@ -105,7 +107,7 @@ public class MinionTriggerBlock extends InstructionBoundBlock implements Polymer } @Override - public BlockState getPolymerBlockState(BlockState state, PacketContext context) { + public BlockState getPolymerBlockState(BlockState state, @Nullable PacketContext context) { return VersionSync.isOnClient(context) ? state : net.minecraft.world.level.block.Blocks.COMPARATOR.defaultBlockState().setValue(DiodeBlock.POWERED, state.getValue(POWERED)); } diff --git a/src/main/java/io/github/skippyall/minions/block/miniontrigger/package-info.java b/src/main/java/io/github/skippyall/minions/block/miniontrigger/package-info.java new file mode 100644 index 0000000..8d4d90d --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/block/miniontrigger/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.block.miniontrigger; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/block/package-info.java b/src/main/java/io/github/skippyall/minions/block/package-info.java new file mode 100644 index 0000000..2b522e0 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/block/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.block; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/clipboard/ClipboardItem.java b/src/main/java/io/github/skippyall/minions/clipboard/ClipboardItem.java index 66aaef9..06ba9d1 100644 --- a/src/main/java/io/github/skippyall/minions/clipboard/ClipboardItem.java +++ b/src/main/java/io/github/skippyall/minions/clipboard/ClipboardItem.java @@ -14,7 +14,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; public class ClipboardItem extends Item implements PolymerItem { public ClipboardItem(Properties settings) { diff --git a/src/main/java/io/github/skippyall/minions/clipboard/package-info.java b/src/main/java/io/github/skippyall/minions/clipboard/package-info.java new file mode 100644 index 0000000..524a40e --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/clipboard/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.clipboard; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/command/SpawnSubcommand.java b/src/main/java/io/github/skippyall/minions/command/SpawnSubcommand.java index 1c1c822..c631e16 100644 --- a/src/main/java/io/github/skippyall/minions/command/SpawnSubcommand.java +++ b/src/main/java/io/github/skippyall/minions/command/SpawnSubcommand.java @@ -10,6 +10,7 @@ import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.arguments.coordinates.Coordinates; import net.minecraft.commands.arguments.coordinates.Vec3Argument; import net.minecraft.server.permissions.Permissions; +import org.jspecify.annotations.Nullable; import static net.minecraft.commands.Commands.argument; import static net.minecraft.commands.Commands.literal; @@ -48,7 +49,7 @@ public class SpawnSubcommand { )) ); - public static int spawnCommand(CommandSourceStack source, String minion, Coordinates pos, boolean force) throws CommandSyntaxException { + public static int spawnCommand(CommandSourceStack source, String minion, @Nullable Coordinates pos, boolean force) throws CommandSyntaxException { MinionData data = MinionArgument.parse(source.getServer(), minion); MinionFakePlayer.spawnMinion(data, source.getLevel(), pos != null ? pos.getPosition(source) : null, pos != null ? pos.getRotation(source) : null, force); return 0; diff --git a/src/main/java/io/github/skippyall/minions/command/package-info.java b/src/main/java/io/github/skippyall/minions/command/package-info.java new file mode 100644 index 0000000..46bac1b --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/command/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.command; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/docs/DocsManager.java b/src/main/java/io/github/skippyall/minions/docs/DocsManager.java index a7a422e..b50e729 100644 --- a/src/main/java/io/github/skippyall/minions/docs/DocsManager.java +++ b/src/main/java/io/github/skippyall/minions/docs/DocsManager.java @@ -3,7 +3,7 @@ package io.github.skippyall.minions.docs; import com.google.gson.JsonParseException; import com.mojang.serialization.JsonOps; import io.github.skippyall.minions.Minions; -import net.fabricmc.fabric.api.resource.SimpleResourceReloadListener; +import net.fabricmc.fabric.api.resource.v1.reloader.SimpleReloadListener; import net.minecraft.core.Holder; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; @@ -16,9 +16,10 @@ import net.minecraft.server.dialog.MultiActionDialog; import net.minecraft.server.dialog.action.StaticAction; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.packs.resources.Resource; -import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.util.StrictJsonParser; import net.minecraft.util.Tuple; +import org.jspecify.annotations.Nullable; + import java.io.IOException; import java.io.Reader; import java.util.ArrayList; @@ -27,14 +28,12 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -public class DocsManager implements SimpleResourceReloadListener, DocsTree>> { - private static Map docs; - private static DocsTree tree; +public class DocsManager extends SimpleReloadListener, DocsTree>> { + private static @Nullable Map docs; + private static @Nullable DocsTree tree; - public static DocsTree getTree() { + public static @Nullable DocsTree getTree() { return tree; } @@ -87,57 +86,55 @@ public class DocsManager implements SimpleResourceReloadListener getDocsEntryIds() { - return docs.keySet(); - } - - @Override - public CompletableFuture, DocsTree>> load(ResourceManager resourceManager, Executor executor) { - return CompletableFuture.supplyAsync(() -> { - Map resources = resourceManager.listResources("docs", id -> id.getNamespace().equals(Minions.MOD_ID) && id.getPath().endsWith(".json")); - - final DocsTree.BranchElement[] root = {null}; - Map docsEntries = new HashMap<>(); - resources.forEach((id, resource) -> { - try(Reader reader = resource.openAsReader()) { - if(id.getPath().equals("docs/tree.json")) { - DocsTree.BranchElement.CODEC.decode(JsonOps.INSTANCE, StrictJsonParser.parse(reader)) - .ifSuccess(entry -> root[0] = entry.getFirst()) - .ifError(error -> Minions.LOGGER.warn("Could not parse docs tree {}: {}", id, error.message())); - } else { - Identifier docId = Identifier.fromNamespaceAndPath(id.getNamespace(), id.getPath().substring("docs/".length(), id.getPath().length() - ".json".length())); - DocsEntry.CODEC.decode(JsonOps.INSTANCE, StrictJsonParser.parse(reader)) - .ifSuccess(entry -> docsEntries.put(docId, entry.getFirst())) - .ifError(error -> Minions.LOGGER.warn("Could not parse docs entry {}: {}", id, error.message())); - } - } catch (IOException | JsonParseException e) { - Minions.LOGGER.warn("Could not read file {}", id, e); - } - }); - if(root[0] != null) { - DocsTree tree = new DocsTree(root[0]); - return new Tuple<>(docsEntries, tree); - } else { - return new Tuple<>(docsEntries, null); - } - }, executor); - } - - @Override - public CompletableFuture apply(Tuple, DocsTree> o, ResourceManager resourceManager, Executor executor) { - return CompletableFuture.supplyAsync(() -> { - docs = o.getA(); - tree = o.getB(); + public static @Nullable DocsEntry getDocsEntry(Identifier id) { + if(docs != null) { + return docs.get(id); + } else { return null; - }); + } + } + + public static @Nullable Collection getDocsEntryIds() { + if (docs != null) { + return docs.keySet(); + } else { + return null; + } } @Override - public Identifier getFabricId() { - return Identifier.fromNamespaceAndPath(Minions.MOD_ID, "docs"); + public Tuple, DocsTree> prepare(SharedState state) { + Map resources = state.resourceManager().listResources("docs", id -> id.getNamespace().equals(Minions.MOD_ID) && id.getPath().endsWith(".json")); + + final DocsTree. @Nullable BranchElement[] root = {null}; + Map docsEntries = new HashMap<>(); + resources.forEach((id, resource) -> { + try(Reader reader = resource.openAsReader()) { + if(id.getPath().equals("docs/tree.json")) { + DocsTree.BranchElement.CODEC.decode(JsonOps.INSTANCE, StrictJsonParser.parse(reader)) + .ifSuccess(entry -> root[0] = entry.getFirst()) + .ifError(error -> Minions.LOGGER.warn("Could not parse docs tree {}: {}", id, error.message())); + } else { + Identifier docId = Identifier.fromNamespaceAndPath(id.getNamespace(), id.getPath().substring("docs/".length(), id.getPath().length() - ".json".length())); + DocsEntry.CODEC.decode(JsonOps.INSTANCE, StrictJsonParser.parse(reader)) + .ifSuccess(entry -> docsEntries.put(docId, entry.getFirst())) + .ifError(error -> Minions.LOGGER.warn("Could not parse docs entry {}: {}", id, error.message())); + } + } catch (IOException | JsonParseException e) { + Minions.LOGGER.warn("Could not read file {}", id, e); + } + }); + if(root[0] != null) { + DocsTree tree = new DocsTree(root[0]); + return new Tuple<>(docsEntries, tree); + } else { + return new Tuple<>(docsEntries, null); + } + } + + @Override + public void apply(Tuple, DocsTree> o, SharedState state) { + docs = o.getA(); + tree = o.getB(); } } diff --git a/src/main/java/io/github/skippyall/minions/docs/DocsTree.java b/src/main/java/io/github/skippyall/minions/docs/DocsTree.java index aadac12..eb1eab8 100644 --- a/src/main/java/io/github/skippyall/minions/docs/DocsTree.java +++ b/src/main/java/io/github/skippyall/minions/docs/DocsTree.java @@ -3,6 +3,7 @@ package io.github.skippyall.minions.docs; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import net.minecraft.resources.Identifier; +import org.jspecify.annotations.Nullable; import java.util.HashMap; import java.util.List; @@ -35,9 +36,9 @@ public class DocsTree { } public static abstract sealed class Element { - private BranchElement parent; + private @Nullable BranchElement parent; - public BranchElement getParent() { + public @Nullable BranchElement getParent() { return parent; } @@ -45,12 +46,20 @@ public class DocsTree { this.parent = parent; } - public DocElement next() { - return parent.next(this); + public @Nullable DocElement next() { + if (parent != null) { + return parent.next(this); + } else { + return null; + } } - public DocElement previous() { - return parent.previous(this); + public @Nullable DocElement previous() { + if (parent != null) { + return parent.previous(this); + } else { + return null; + } } } @@ -101,7 +110,7 @@ public class DocsTree { }; } - public DocElement next(Element current) { + public @Nullable DocElement next(Element current) { int nextIndex = e.indexOf(current) + 1; if(nextIndex < e.size()) { return switch (e.get(nextIndex)) { @@ -117,7 +126,7 @@ public class DocsTree { } } - public DocElement previous(Element current) { + public @Nullable DocElement previous(Element current) { int previousIndex = e.indexOf(current) - 1; if(previousIndex >= 0) { return switch (e.get(previousIndex)) { diff --git a/src/main/java/io/github/skippyall/minions/docs/ReferenceEntry.java b/src/main/java/io/github/skippyall/minions/docs/ReferenceEntry.java index feee32f..6de5d7d 100644 --- a/src/main/java/io/github/skippyall/minions/docs/ReferenceEntry.java +++ b/src/main/java/io/github/skippyall/minions/docs/ReferenceEntry.java @@ -15,6 +15,7 @@ import net.minecraft.server.dialog.body.DialogBody; import net.minecraft.server.dialog.body.ItemBody; import net.minecraft.server.dialog.body.PlainMessage; import net.minecraft.world.item.Item; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -55,7 +56,7 @@ public record ReferenceEntry(Metadata metadata, ResourceKey object, Component return bodyElements; } - public GuiDisplay getObjectDisplay(RegistryAccess manager) { + public @Nullable GuiDisplay getObjectDisplay(RegistryAccess manager) { GuiDisplay display = GuiDisplay.DEFAULT_DISPLAY; if(object.isFor(Registries.ITEM) || object.isFor(Registries.BLOCK)) { Item item; diff --git a/src/main/java/io/github/skippyall/minions/docs/package-info.java b/src/main/java/io/github/skippyall/minions/docs/package-info.java new file mode 100644 index 0000000..3bf4089 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/docs/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.docs; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/gui/MinionLookGui.kt b/src/main/java/io/github/skippyall/minions/gui/MinionLookGui.kt index c4cde8f..a2075e9 100644 --- a/src/main/java/io/github/skippyall/minions/gui/MinionLookGui.kt +++ b/src/main/java/io/github/skippyall/minions/gui/MinionLookGui.kt @@ -20,7 +20,7 @@ import net.minecraft.world.inventory.MenuType import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items import net.minecraft.world.item.component.ResolvableProfile -import java.util.Optional +import java.util.* class MinionLookGui( viewer: ServerPlayer, @@ -93,7 +93,7 @@ class MinionLookGui( fun openSkinGui() { scope.launch { val profile = currentSkinProvider.openSkinMenu(this@MinionLookGui).await() - val skin = profile.resolveProfile(viewer.level().server.services().profileResolver()).await() + val skin = profile?.resolveProfile(viewer.level().server.services().profileResolver())?.await() data.skin = Optional.ofNullable(skin?.properties()) 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 8250730..443604d 100644 --- a/src/main/java/io/github/skippyall/minions/gui/PaginatedList.java +++ b/src/main/java/io/github/skippyall/minions/gui/PaginatedList.java @@ -6,6 +6,7 @@ import net.minecraft.core.IdMap; import net.minecraft.network.chat.Component; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.Items; +import org.jspecify.annotations.Nullable; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -18,7 +19,7 @@ public class PaginatedList extends MinionsGui { private final Component title; private final int size; private final BiFunction display; - private Runnable onClose = null; + private @Nullable Runnable onClose = null; public PaginatedList(MinionsGui parent, Component title, int size, BiFunction display) { super(parent); diff --git a/src/main/java/io/github/skippyall/minions/gui/input/Result.java b/src/main/java/io/github/skippyall/minions/gui/input/Result.java index ffb31bd..4bba1be 100644 --- a/src/main/java/io/github/skippyall/minions/gui/input/Result.java +++ b/src/main/java/io/github/skippyall/minions/gui/input/Result.java @@ -1,7 +1,6 @@ package io.github.skippyall.minions.gui.input; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.function.Consumer; @@ -27,7 +26,7 @@ public sealed interface Result permits Result.Success, Result.Error { static Result ofNullable(@Nullable T value, E error) { if(value != null) { - return new Success<>(value); + return new Success(value); } else { return new Error<>(error); } @@ -35,7 +34,7 @@ public sealed interface Result permits Result.Success, Result.Error { static Result ofNullable(@Nullable T value, Supplier error) { if(value != null) { - return new Success<>(value); + return new Success(value); } else { return new Error<>(error.get()); } @@ -49,13 +48,13 @@ public sealed interface Result permits Result.Success, Result.Error { E getErrorOrThrow(); - @NotNull Optional getOptional(); + Optional getOptional(); - @NotNull Optional getOptionalError(); + Optional getOptionalError(); - void ifSuccess(@NotNull Consumer handler); + void ifSuccess(Consumer handler); - void ifError(@NotNull Consumer> handler); + void ifError(Consumer> handler); Result map(Function mapper); @@ -75,7 +74,7 @@ public sealed interface Result permits Result.Success, Result.Error { } @Override - public @NotNull Optional getOptionalError() { + public Optional getOptionalError() { return Optional.empty(); } @@ -90,17 +89,17 @@ public sealed interface Result permits Result.Success, Result.Error { } @Override - public @NotNull Optional getOptional() { + public Optional getOptional() { return Optional.ofNullable(result); } @Override - public void ifSuccess(@NotNull Consumer handler) { + public void ifSuccess(Consumer handler) { handler.accept(result); } @Override - public void ifError(@NotNull Consumer> handler) { + public void ifError(Consumer> handler) { } @@ -143,22 +142,22 @@ public sealed interface Result permits Result.Success, Result.Error { } @Override - public @NotNull Optional getOptional() { + public Optional getOptional() { return Optional.empty(); } @Override - public @NotNull Optional getOptionalError() { + public Optional getOptionalError() { return Optional.ofNullable(message); } @Override - public void ifSuccess(@NotNull Consumer handler) { + public void ifSuccess(Consumer handler) { } @Override - public void ifError(@NotNull Consumer> handler) { + public void ifError(Consumer> handler) { handler.accept(this); } 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 ab7085a..497893e 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 @@ -9,7 +9,7 @@ import net.minecraft.world.inventory.AnvilMenu import net.minecraft.world.item.Items import java.util.concurrent.CompletableFuture -class TextInput( +class TextInput( parent: MinionsGui, val title: Component, val defaultValue: String, @@ -78,7 +78,7 @@ class TextInput( companion object { @JvmStatic - fun input( + fun input( gui: MinionsGui, title: Component, defaultValue: String, @@ -104,7 +104,7 @@ class TextInput( gui = gui, title = title, defaultValue = defaultValue, - parser = { result: String? -> Result.Success(result) }, + parser = { result -> Result.Success(result) }, ) } @@ -121,7 +121,7 @@ class TextInput( parser = { string -> Result.wrapCustomError( { string.toLong() }, - Component.translatable("minions.command.input.int.fail") + Component.translatable("value_type.minions.long.not_long") ) }, ) @@ -140,7 +140,7 @@ class TextInput( parser = { string -> Result.wrapCustomError( { string.toDouble() }, - Component.translatable("minions.command.input.int.fail") + Component.translatable("value_type.minions.long.not_long") ) }, ) diff --git a/src/main/java/io/github/skippyall/minions/gui/input/package-info.java b/src/main/java/io/github/skippyall/minions/gui/input/package-info.java new file mode 100644 index 0000000..3340665 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/gui/input/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.gui.input; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/gui/instruction/ArgumentGui.java b/src/main/java/io/github/skippyall/minions/gui/instruction/ArgumentGui.java index 67da642..0c88519 100644 --- a/src/main/java/io/github/skippyall/minions/gui/instruction/ArgumentGui.java +++ b/src/main/java/io/github/skippyall/minions/gui/instruction/ArgumentGui.java @@ -18,7 +18,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; public class ArgumentGui extends MinionsGui { private final GuiContext.ValueSupplier context; @@ -28,7 +28,7 @@ public class ArgumentGui extends MinionsGui { private SimpleGui gui; private @Nullable ValueSupplierType argumentType; - private @Nullable ValueSupplierList.ValueSupplierEntry entry; + private ValueSupplierList. @Nullable ValueSupplierEntry entry; public ArgumentGui(MinionsGui parent, GuiContext.ValueSupplier context) { super(parent); @@ -37,9 +37,7 @@ public class ArgumentGui extends MinionsGui { this.context = context; this.entry = instruction.getArguments().getEntry(parameter); - if(entry != null) { - this.argumentType = entry.getSupplier().getType(); - } + this.argumentType = entry.getSupplier().getType(); open(); } 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 f45d507..74ca975 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 @@ -19,6 +19,8 @@ import net.minecraft.sounds.SoundSource; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.Items; +import java.util.List; + public class ConfigureInstructionGui extends MinionsGui implements ConfiguredInstructionListener, MinionListener { private String name; private final ConfiguredInstruction instruction; @@ -53,7 +55,9 @@ public class ConfigureInstructionGui extends MinionsGui implements ConfiguredIns gui.setSlot(6, new GuiElementBuilder(Items.ANVIL) .setName(Component.translatable("minions.gui.instruction.configure.rename")) .setCallback(() -> InstructionGui.inputInstructionName(this, context, name).thenAccept(newName -> { - minion.getInstructionManager().setInstructionName(name, newName); + if(newName != null) { + minion.getInstructionManager().setInstructionName(name, newName); + } reopen(); })) ); @@ -84,6 +88,7 @@ public class ConfigureInstructionGui extends MinionsGui implements ConfiguredIns }) ); + updateLastError(); updateRunSlot(); gui.open(); } @@ -105,6 +110,7 @@ public class ConfigureInstructionGui extends MinionsGui implements ConfiguredIns @Override public void onRun(ConfiguredInstruction instruction) { updateRunSlot(); + updateLastError(); } @Override @@ -131,6 +137,18 @@ public class ConfigureInstructionGui extends MinionsGui implements ConfiguredIns } } + private void updateLastError() { + List errors = instruction.getLastErrors(); + if(!errors.isEmpty()) { + GuiElementBuilder builder = new GuiElementBuilder(Items.RED_WOOL) + .setName(Component.translatable("minions.gui.instruction.last_errors")); + for(Component error : errors) { + builder.addLoreLine(error); + } + gui.setSlot(17, builder); + } + } + private void updateSuppliers() { int slot = 12; for(Parameter parameter : instruction.getInstruction().getParameters().reversed()) { diff --git a/src/main/java/io/github/skippyall/minions/gui/instruction/ConverterGui.java b/src/main/java/io/github/skippyall/minions/gui/instruction/ConverterGui.java index 5b65721..2861fd7 100644 --- a/src/main/java/io/github/skippyall/minions/gui/instruction/ConverterGui.java +++ b/src/main/java/io/github/skippyall/minions/gui/instruction/ConverterGui.java @@ -14,7 +14,7 @@ import net.minecraft.core.RegistryAccess; import net.minecraft.network.chat.Component; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.Items; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; public class ConverterGui extends MinionsGui { private @Nullable ValueConverterType valueConverterType; diff --git a/src/main/java/io/github/skippyall/minions/gui/instruction/ConverterListGui.java b/src/main/java/io/github/skippyall/minions/gui/instruction/ConverterListGui.java index acb18ac..e119997 100644 --- a/src/main/java/io/github/skippyall/minions/gui/instruction/ConverterListGui.java +++ b/src/main/java/io/github/skippyall/minions/gui/instruction/ConverterListGui.java @@ -12,6 +12,7 @@ import io.github.skippyall.minions.util.TranslationUtil; import net.minecraft.network.chat.Component; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.Items; +import org.jspecify.annotations.Nullable; public class ConverterListGui extends MinionsGui { private ConverterList converters; @@ -61,53 +62,117 @@ public class ConverterListGui extends MinionsGui { }) ); - gui.setSlot(8, backButton()); + gui.setSlot(26, backButton()); gui.open(); } + private ValueType getInputTypeOfConverter(int converterIndex) { + if(converterIndex < converters.getConverters().size() && converterIndex >= 0) { + return converters.getConverters().get(converterIndex).getFrom(); + } else if(converterIndex == converters.getConverters().size()) { + return outputType; + } else { + throw new IndexOutOfBoundsException("Can't get input type of converter " + converterIndex + ", list size " + converters.getConverters().size()); + } + } + + private ValueType getOutputTypeOfConverter(int converterIndex) { + if(converterIndex < converters.getConverters().size() && converterIndex >= 0) { + return converters.getConverters().get(converterIndex).getTo(); + } else if(converterIndex == -1) { + return inputType; + } else { + throw new IndexOutOfBoundsException("Can't get output type of converter " + converterIndex + ", list size " + converters.getConverters().size()); + } + } + public void updateConverters() { - for(int slot = 9; slot < 18; slot++) { + for(int slot = 0; slot < 18; slot++) { gui.clearSlot(slot); } int lastConverter = Math.min(5, converters.getConverters().size() + 2 - page * 4); for(int i = 0; i < lastConverter; i++) { //Each page has 5 converters, but the last is displayed on the next page as well - int converterIndex = page * 4 + i; - //without input element - int actualConverterIndex = converterIndex - 1; + //The input element index is -1, the output element index is the list size + int converterIndex = page * 4 + i - 1; int slot = 9 + 2 * i; - if(converterIndex == 0) { - gui.setSlot(slot, new GuiElementBuilder(Items.DROPPER)); - } else if(converterIndex == converters.getConverters().size() + 1) { + + if(converterIndex == converters.getConverters().size()) { gui.setSlot(slot, new GuiElementBuilder(Items.HOPPER)); } else { - ValueConverter converter = converters.getConverters().get(actualConverterIndex); - ValueType fromType = actualConverterIndex >= 1 ? converters.getConverters().get(actualConverterIndex - 1).getTo() : inputType; - ValueType toType = actualConverterIndex < converters.getConverters().size() - 1 ? converters.getConverters().get(actualConverterIndex + 1).getFrom() : outputType; + ValueType thisConverterOutput = getOutputTypeOfConverter(converterIndex); + ValueType nextConverterInput = getInputTypeOfConverter(converterIndex + 1); - gui.setSlot(slot, new GuiElementBuilder(GuiDisplay.getDisplayStackWithName(MinionRegistries.VALUE_CONVERTER_TYPES, converter.getType(), viewer.registryAccess())) - .addLoreLine(converter.getDisplayText()) - .setCallback(() -> new ConverterGui(this, converter, fromType, toType, converters, false, actualConverterIndex)) - ); - } - if(i != 4 && actualConverterIndex != converters.getConverters().size()) { - ValueType fromType = actualConverterIndex >= 0 ? converters.getConverters().get(actualConverterIndex).getTo() : inputType; - ValueType toType = actualConverterIndex < converters.getConverters().size() - 1 ? converters.getConverters().get(actualConverterIndex + 1).getFrom() : outputType; + //What should be shown at the converter's slot + if (converterIndex == -1) { + gui.setSlot(slot, new GuiElementBuilder(Items.DROPPER)); + } else { + ValueType previousConverterOutput = getOutputTypeOfConverter(converterIndex - 1); - gui.setSlot(slot + 1, new GuiElementBuilder(Items.MAGENTA_GLAZED_TERRACOTTA) - .setName(Component.translatable( - "minions.gui.instruction.converters.cast", - Component.translatable(TranslationUtil.getTranslationKey(fromType, MinionRegistries.VALUE_TYPES)), - Component.translatable(TranslationUtil.getTranslationKey(toType, MinionRegistries.VALUE_TYPES)) - )) - .setCallback(() -> new ConverterGui(this, null, fromType, toType, converters, true, actualConverterIndex + 1)) - ); + ValueConverter converter = converters.getConverters().get(converterIndex); + gui.setSlot(slot, createConverterDisplay(converter, previousConverterOutput, nextConverterInput, converterIndex)); + + GuiElementBuilder warning = createConverterWarning(converter); + if (warning != null) { + gui.setSlot(slot - 8, warning); + } + } + + //show cast in the next slot + if (i != 4 && converterIndex != converters.getConverters().size()) { + gui.setSlot(slot + 1, createCastDisplay(thisConverterOutput, nextConverterInput, converterIndex + 1)); + + GuiElementBuilder warning = createCastWarning(thisConverterOutput, nextConverterInput); + if (warning != null) { + gui.setSlot(slot - 8, warning); + } + } } } } + private GuiElementBuilder createConverterDisplay(ValueConverter converter, ValueType fromType, ValueType toType, int converterIndex) { + return new GuiElementBuilder(GuiDisplay.getDisplayStackWithName(MinionRegistries.VALUE_CONVERTER_TYPES, converter.getType(), viewer.registryAccess())) + .addLoreLine(converter.getDisplayText()) + .setCallback(() -> new ConverterGui(this, converter, fromType, toType, converters, false, converterIndex)); + } + + private GuiElementBuilder createCastDisplay(ValueType fromType, ValueType toType, int newConverterIndex) { + return new GuiElementBuilder(Items.MAGENTA_GLAZED_TERRACOTTA) + .setName(Component.translatable( + "minions.gui.instruction.converters.cast", + Component.translatable(TranslationUtil.getTranslationKey(fromType, MinionRegistries.VALUE_TYPES)), + Component.translatable(TranslationUtil.getTranslationKey(toType, MinionRegistries.VALUE_TYPES)) + )) + .setCallback(() -> new ConverterGui(this, null, fromType, toType, converters, true, newConverterIndex)); + } + + private @Nullable GuiElementBuilder createCastWarning(ValueType fromType, ValueType toType) { + Component warning = ConverterList.createCastWarning(fromType, toType); + + if(warning != null) { + return new GuiElementBuilder(Items.RED_BANNER) + .setName(Component.translatable("minions.generic.error")) + .addLoreLine(warning); + } else { + return null; + } + } + + private @Nullable GuiElementBuilder createConverterWarning(ValueConverter converter) { + Component warning = ConverterList.createConverterWarning(converter); + + if(warning != null) { + return new GuiElementBuilder(Items.RED_BANNER) + .setName(Component.translatable("minions.generic.error")) + .addLoreLine(warning); + } else { + return null; + } + } + @Override protected void closeBacking() { gui.close(); diff --git a/src/main/java/io/github/skippyall/minions/gui/instruction/InstructionGui.java b/src/main/java/io/github/skippyall/minions/gui/instruction/InstructionGui.java index a899e2b..a738fe8 100644 --- a/src/main/java/io/github/skippyall/minions/gui/instruction/InstructionGui.java +++ b/src/main/java/io/github/skippyall/minions/gui/instruction/InstructionGui.java @@ -24,7 +24,7 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.NoSuchElementException; import java.util.concurrent.CompletableFuture; @@ -64,7 +64,7 @@ public class InstructionGui { ServerPlayer viewer = parent.viewer; selectInstructionModuleMenu(parent, context).thenAccept(instructionType -> inputInstructionName(parent, context, "Instruction").thenAccept(name -> { - if (!minion.isRemoved() && !minion.hasDisconnected()) { + if (!minion.isRemoved() && !minion.hasDisconnected() && name != null) { ConfiguredInstruction configuredInstruction = minion.getInstructionManager().createInstruction(name, instructionType); new ConfigureInstructionGui(parent, GuiContext.Instruction.create(context, configuredInstruction, name)); } @@ -72,7 +72,7 @@ public class InstructionGui { ); } - public static CompletableFuture inputInstructionName(MinionsGui parent, GuiContext.Minion context, String defaultValue) { + public static CompletableFuture<@Nullable String> inputInstructionName(MinionsGui parent, GuiContext.Minion context, String defaultValue) { return TextInput.input(parent, Component.translatable("minions.gui.instruction.enter_name"), defaultValue, (name, _) -> { if (context.getMinion().getInstructionManager().hasInstruction(name)) { return new Result.Error<>(Component.translatable("minions.gui.instruction.name_already_used")); @@ -163,7 +163,7 @@ public class InstructionGui { return future; } - public static GuiElementBuilder createInstructionElement(InstructionType instructionType, RegistryAccess manager) { + public static GuiElementBuilder createInstructionElement(@Nullable InstructionType instructionType, RegistryAccess manager) { GuiElementBuilder instructionBuilder; if (instructionType != null) { instructionBuilder = new GuiElementBuilder(GuiDisplay.getDisplayStackWithName(MinionRegistries.INSTRUCTION_TYPES, instructionType, manager)); diff --git a/src/main/java/io/github/skippyall/minions/gui/instruction/package-info.java b/src/main/java/io/github/skippyall/minions/gui/instruction/package-info.java new file mode 100644 index 0000000..c31b2e2 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/gui/instruction/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.gui.instruction; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/gui/minion/GuiContext.kt b/src/main/java/io/github/skippyall/minions/gui/minion/GuiContext.kt index c8e57fd..f14996b 100644 --- a/src/main/java/io/github/skippyall/minions/gui/minion/GuiContext.kt +++ b/src/main/java/io/github/skippyall/minions/gui/minion/GuiContext.kt @@ -1,6 +1,8 @@ package io.github.skippyall.minions.gui.minion -import io.github.skippyall.minions.gui.minion.GuiContextImpl.* +import io.github.skippyall.minions.gui.minion.GuiContextImpl.InstructionImpl +import io.github.skippyall.minions.gui.minion.GuiContextImpl.MinionImpl +import io.github.skippyall.minions.gui.minion.GuiContextImpl.ValueSupplierImpl import io.github.skippyall.minions.minion.MinionRuntime import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer import io.github.skippyall.minions.program.instruction.ConfiguredInstruction diff --git a/src/main/java/io/github/skippyall/minions/gui/minion/package-info.java b/src/main/java/io/github/skippyall/minions/gui/minion/package-info.java new file mode 100644 index 0000000..13d5f58 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/gui/minion/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.gui.minion; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/gui/package-info.java b/src/main/java/io/github/skippyall/minions/gui/package-info.java new file mode 100644 index 0000000..a7e49b0 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/gui/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.gui; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/listener/BlockEntityMinionListener.java b/src/main/java/io/github/skippyall/minions/listener/BlockEntityMinionListener.java index 46bbd3a..0dc21b0 100644 --- a/src/main/java/io/github/skippyall/minions/listener/BlockEntityMinionListener.java +++ b/src/main/java/io/github/skippyall/minions/listener/BlockEntityMinionListener.java @@ -13,7 +13,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.UUID; @@ -45,7 +45,7 @@ public abstract class BlockEntityMinionListener implement this.minion = null; } - public static > T getListener(Level world, BlockPos pos, UUID minionUuid, Class clazz) { + public static > @Nullable T getListener(Level world, BlockPos pos, @Nullable UUID minionUuid, Class clazz) { if(minionUuid != null) { for (MinionListener listener : MinionPersistentState.get(world.getServer()).getMinionData(minionUuid).getListeners()) { if (listener instanceof BlockEntityMinionListener tl && tl.pos.equals(pos) && tl.worldKey.equals(world.dimension()) && clazz.isInstance(tl)) { diff --git a/src/main/java/io/github/skippyall/minions/listener/SerializableListenerManager.kt b/src/main/java/io/github/skippyall/minions/listener/SerializableListenerManager.kt index c5b9b63..dfca6f6 100644 --- a/src/main/java/io/github/skippyall/minions/listener/SerializableListenerManager.kt +++ b/src/main/java/io/github/skippyall/minions/listener/SerializableListenerManager.kt @@ -5,7 +5,7 @@ import com.mojang.serialization.MapCodec import io.github.skippyall.minions.listener.SerializableListenerManager.SerializableListener import net.minecraft.core.Registry import net.minecraft.resources.Identifier -import java.util.Optional +import java.util.* import java.util.concurrent.CopyOnWriteArraySet class SerializableListenerManager( diff --git a/src/main/java/io/github/skippyall/minions/listener/package-info.java b/src/main/java/io/github/skippyall/minions/listener/package-info.java new file mode 100644 index 0000000..179a694 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/listener/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.listener; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionData.kt b/src/main/java/io/github/skippyall/minions/minion/MinionData.kt index d535a1c..3bd4fbb 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionData.kt +++ b/src/main/java/io/github/skippyall/minions/minion/MinionData.kt @@ -8,8 +8,7 @@ import io.github.skippyall.minions.registration.MinionRegistries import net.minecraft.core.UUIDUtil import net.minecraft.server.MinecraftServer import net.minecraft.util.ExtraCodecs -import java.util.Optional -import java.util.UUID +import java.util.* import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionItem.java b/src/main/java/io/github/skippyall/minions/minion/MinionItem.java index 97c78f8..98b9d14 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionItem.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionItem.java @@ -7,7 +7,6 @@ import io.github.skippyall.minions.registration.MinionComponentTypes; import net.fabricmc.fabric.api.networking.v1.context.PacketContext; import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponents; -import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -19,13 +18,10 @@ import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.item.component.TooltipDisplay; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec2; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Consumer; +import org.jspecify.annotations.Nullable; public class MinionItem extends Item implements PolymerItem { public MinionItem(Properties settings) { @@ -49,13 +45,13 @@ public class MinionItem extends Item implements PolymerItem { return out; } - @Override + /*@Override public void appendHoverText(ItemStack stack, TooltipContext context, TooltipDisplay component, Consumer tooltip, TooltipFlag type) { //MinionData data = getData(stack); //if(data != null) { // tooltip.accept(Component.translatable("minions.minion_item.tooltip", data.name())); //} - } + }*/ @Override public InteractionResult use(Level world, Player user, InteractionHand hand) { diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionListener.java b/src/main/java/io/github/skippyall/minions/minion/MinionListener.java index 0c14d3e..d5e6a3a 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionListener.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionListener.java @@ -3,7 +3,7 @@ package io.github.skippyall.minions.minion; import io.github.skippyall.minions.listener.SerializableListenerManager; import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import io.github.skippyall.minions.program.instruction.ConfiguredInstruction; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; public interface MinionListener extends SerializableListenerManager.SerializableListener { default void onMinionSpawn(MinionFakePlayer minion) {} diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionPersistentState.java b/src/main/java/io/github/skippyall/minions/minion/MinionPersistentState.java index 8eac4ca..f5d1322 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionPersistentState.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionPersistentState.java @@ -7,6 +7,8 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.Level; import net.minecraft.world.level.saveddata.SavedData; import net.minecraft.world.level.saveddata.SavedDataType; +import org.jspecify.annotations.Nullable; + import java.util.HashMap; import java.util.List; import java.util.Map; @@ -36,7 +38,7 @@ public class MinionPersistentState extends SavedData { } } - public MinionData getMinionData(UUID uuid) { + public @Nullable MinionData getMinionData(UUID uuid) { return minionData.get(uuid); } diff --git a/src/main/java/io/github/skippyall/minions/minion/MinionProfileUtils.java b/src/main/java/io/github/skippyall/minions/minion/MinionProfileUtils.java index 09937bd..1521dcc 100644 --- a/src/main/java/io/github/skippyall/minions/minion/MinionProfileUtils.java +++ b/src/main/java/io/github/skippyall/minions/minion/MinionProfileUtils.java @@ -8,6 +8,8 @@ import io.github.skippyall.minions.gui.input.Result; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import net.minecraft.util.StringUtil; +import org.jspecify.annotations.Nullable; + import java.util.UUID; import static io.github.skippyall.minions.Minions.LOGGER; @@ -17,7 +19,7 @@ public class MinionProfileUtils { return MinionsConfig.get().minion.minionPrefix; } - public static GameProfile makeNewMinionProfile(UUID uuidMinion, String username, PropertyMap skin) { + public static GameProfile makeNewMinionProfile(@Nullable UUID uuidMinion, String username, @Nullable PropertyMap skin) { if(uuidMinion == null) { uuidMinion = UUID.randomUUID(); } diff --git a/src/main/java/io/github/skippyall/minions/minion/fakeplayer/MinionFakePlayer.java b/src/main/java/io/github/skippyall/minions/minion/fakeplayer/MinionFakePlayer.java index ca0f73e..ed3279a 100644 --- a/src/main/java/io/github/skippyall/minions/minion/fakeplayer/MinionFakePlayer.java +++ b/src/main/java/io/github/skippyall/minions/minion/fakeplayer/MinionFakePlayer.java @@ -51,7 +51,7 @@ import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.Optional; import java.util.Set; diff --git a/src/main/java/io/github/skippyall/minions/minion/package-info.java b/src/main/java/io/github/skippyall/minions/minion/package-info.java new file mode 100644 index 0000000..fd2a3e4 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.minion; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/minion/program/instruction/MineBlockExecution.java b/src/main/java/io/github/skippyall/minions/minion/program/instruction/MineBlockExecution.java index 8eb999c..8ef3d67 100644 --- a/src/main/java/io/github/skippyall/minions/minion/program/instruction/MineBlockExecution.java +++ b/src/main/java/io/github/skippyall/minions/minion/program/instruction/MineBlockExecution.java @@ -16,9 +16,10 @@ import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; +import org.jspecify.annotations.Nullable; public class MineBlockExecution implements InstructionExecution { - private BlockPos currentBlock; + private @Nullable BlockPos currentBlock; private float currentBlockDamage = 0; private boolean first = true; private boolean done = false; @@ -38,7 +39,6 @@ public class MineBlockExecution implements InstructionExecution { } if (player.blockActionRestricted(player.level(), hit.getBlockPos(), player.gameMode.getGameModeForPlayer())) { done = true; - return; } } else { done = true; diff --git a/src/main/java/io/github/skippyall/minions/minion/program/instruction/inventory/package-info.java b/src/main/java/io/github/skippyall/minions/minion/program/instruction/inventory/package-info.java new file mode 100644 index 0000000..8b4b11d --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/program/instruction/inventory/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.minion.program.instruction.inventory; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/minion/program/instruction/move/package-info.java b/src/main/java/io/github/skippyall/minions/minion/program/instruction/move/package-info.java new file mode 100644 index 0000000..bd015f7 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/program/instruction/move/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.minion.program.instruction.move; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/minion/program/instruction/package-info.java b/src/main/java/io/github/skippyall/minions/minion/program/instruction/package-info.java new file mode 100644 index 0000000..34b1288 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/program/instruction/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.minion.program.instruction; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/minion/program/supplier/AnalogInputSupplier.java b/src/main/java/io/github/skippyall/minions/minion/program/supplier/AnalogInputSupplier.java index 20bae3c..e3ee8fd 100644 --- a/src/main/java/io/github/skippyall/minions/minion/program/supplier/AnalogInputSupplier.java +++ b/src/main/java/io/github/skippyall/minions/minion/program/supplier/AnalogInputSupplier.java @@ -22,7 +22,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/io/github/skippyall/minions/minion/program/supplier/package-info.java b/src/main/java/io/github/skippyall/minions/minion/program/supplier/package-info.java new file mode 100644 index 0000000..afd83d6 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/program/supplier/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.minion.program.supplier; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/minion/skin/NameSkinProvider.java b/src/main/java/io/github/skippyall/minions/minion/skin/NameSkinProvider.java index e4eee78..8fe92a9 100644 --- a/src/main/java/io/github/skippyall/minions/minion/skin/NameSkinProvider.java +++ b/src/main/java/io/github/skippyall/minions/minion/skin/NameSkinProvider.java @@ -4,12 +4,13 @@ import io.github.skippyall.minions.gui.MinionsGui; import io.github.skippyall.minions.gui.input.TextInput; import net.minecraft.network.chat.Component; import net.minecraft.world.item.component.ResolvableProfile; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; public class NameSkinProvider implements SkinProvider { @Override - public CompletableFuture openSkinMenu(MinionsGui parent) { + public CompletableFuture<@Nullable ResolvableProfile> openSkinMenu(MinionsGui parent) { return TextInput.inputString(parent, Component.translatable("minions.gui.look.skin.name.title"), "") .thenApply(name -> name != null ? ResolvableProfile.createUnresolved(name) : null); } diff --git a/src/main/java/io/github/skippyall/minions/minion/skin/SkinProvider.java b/src/main/java/io/github/skippyall/minions/minion/skin/SkinProvider.java index 321885a..a35a98a 100644 --- a/src/main/java/io/github/skippyall/minions/minion/skin/SkinProvider.java +++ b/src/main/java/io/github/skippyall/minions/minion/skin/SkinProvider.java @@ -3,11 +3,12 @@ package io.github.skippyall.minions.minion.skin; import io.github.skippyall.minions.gui.MinionsGui; import net.minecraft.network.chat.Component; import net.minecraft.world.item.component.ResolvableProfile; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; public interface SkinProvider { - CompletableFuture openSkinMenu(MinionsGui parent); + CompletableFuture<@Nullable ResolvableProfile> openSkinMenu(MinionsGui parent); Component getDisplayName(); } diff --git a/src/main/java/io/github/skippyall/minions/minion/skin/UUIDSkinProvider.java b/src/main/java/io/github/skippyall/minions/minion/skin/UUIDSkinProvider.java index b71ff4a..e077896 100644 --- a/src/main/java/io/github/skippyall/minions/minion/skin/UUIDSkinProvider.java +++ b/src/main/java/io/github/skippyall/minions/minion/skin/UUIDSkinProvider.java @@ -4,12 +4,13 @@ import io.github.skippyall.minions.gui.MinionsGui; import io.github.skippyall.minions.gui.input.TextInput; import net.minecraft.network.chat.Component; import net.minecraft.world.item.component.ResolvableProfile; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; public class UUIDSkinProvider implements SkinProvider { @Override - public CompletableFuture openSkinMenu(MinionsGui parent) { + public CompletableFuture<@Nullable ResolvableProfile> openSkinMenu(MinionsGui parent) { return TextInput.inputString(parent, Component.translatable("minions.gui.look.skin.uuid.title"), "") .thenApply(name -> name != null ? ResolvableProfile.createUnresolved(name) : null); } diff --git a/src/main/java/io/github/skippyall/minions/minion/skin/package-info.java b/src/main/java/io/github/skippyall/minions/minion/skin/package-info.java new file mode 100644 index 0000000..53ca45e --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/minion/skin/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.minion.skin; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/mixins/EntityGetterMixin.java b/src/main/java/io/github/skippyall/minions/mixins/EntityGetterMixin.java index e9cf3a4..0fe3fb5 100644 --- a/src/main/java/io/github/skippyall/minions/mixins/EntityGetterMixin.java +++ b/src/main/java/io/github/skippyall/minions/mixins/EntityGetterMixin.java @@ -3,7 +3,7 @@ package io.github.skippyall.minions.mixins; import io.github.skippyall.minions.mixinhelper.EntityViewMixinHelper; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.EntityGetter; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.ModifyArg; diff --git a/src/main/java/io/github/skippyall/minions/mixins/EntityMixin.java b/src/main/java/io/github/skippyall/minions/mixins/EntityMixin.java index 7d7ab73..2f64097 100644 --- a/src/main/java/io/github/skippyall/minions/mixins/EntityMixin.java +++ b/src/main/java/io/github/skippyall/minions/mixins/EntityMixin.java @@ -4,7 +4,7 @@ import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.Level; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/io/github/skippyall/minions/module/package-info.java b/src/main/java/io/github/skippyall/minions/module/package-info.java new file mode 100644 index 0000000..25d471b --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/module/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.module; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/package-info.java b/src/main/java/io/github/skippyall/minions/package-info.java new file mode 100644 index 0000000..fe5ca93 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/polymer/VersionSync.java b/src/main/java/io/github/skippyall/minions/polymer/VersionSync.java index aeab49b..8d2faec 100644 --- a/src/main/java/io/github/skippyall/minions/polymer/VersionSync.java +++ b/src/main/java/io/github/skippyall/minions/polymer/VersionSync.java @@ -8,11 +8,12 @@ import net.minecraft.network.codec.StreamCodec; import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.resources.Identifier; import net.minecraft.server.network.ServerGamePacketListenerImpl; +import org.jspecify.annotations.Nullable; public class VersionSync { public static final int NETWORK_VERSION = 1; - public static boolean isOnClient(PacketContext context) { + public static boolean isOnClient(@Nullable PacketContext context) { if(context != null && context.get(PacketContext.CONNECTION).getPacketListener() instanceof ServerGamePacketListenerImpl gamePacketListener) { return isOnClient(gamePacketListener); } diff --git a/src/main/java/io/github/skippyall/minions/polymer/package-info.java b/src/main/java/io/github/skippyall/minions/polymer/package-info.java new file mode 100644 index 0000000..3be52cd --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/polymer/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.polymer; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumer.java b/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumer.java index 78228b0..a21a869 100644 --- a/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumer.java +++ b/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumer.java @@ -4,7 +4,7 @@ import com.mojang.serialization.Codec; import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.value.ValueType; import io.github.skippyall.minions.registration.MinionRegistries; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; /** * An ValueSupplier can be supplied to an instruction with a matching parameter. diff --git a/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumerList.java b/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumerList.java index 74981eb..4adf768 100644 --- a/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumerList.java +++ b/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumerList.java @@ -3,6 +3,7 @@ package io.github.skippyall.minions.program.consumer; import com.mojang.serialization.Codec; import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.supplier.Parameter; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.HashMap; @@ -22,7 +23,7 @@ public class ValueConsumerList> { this.valueConsumers = new HashMap<>(valueConsumers); } - public > A getValueConsumer(Parameter parameter) { + public > @Nullable A getValueConsumer(Parameter parameter) { ValueConsumer argument = valueConsumers.get(parameter.name()); return argument == null ? null : argument.cast(parameter.type()); } diff --git a/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumerType.java b/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumerType.java index aa33a8a..0a233f7 100644 --- a/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumerType.java +++ b/src/main/java/io/github/skippyall/minions/program/consumer/ValueConsumerType.java @@ -4,7 +4,7 @@ import com.mojang.serialization.Codec; import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.value.ValueType; import net.minecraft.server.level.ServerPlayer; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/io/github/skippyall/minions/program/consumer/package-info.java b/src/main/java/io/github/skippyall/minions/program/consumer/package-info.java new file mode 100644 index 0000000..c316073 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/consumer/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.program.consumer; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/program/conversion/CastConverter.java b/src/main/java/io/github/skippyall/minions/program/conversion/CastConverter.java index d14eaaa..a697089 100644 --- a/src/main/java/io/github/skippyall/minions/program/conversion/CastConverter.java +++ b/src/main/java/io/github/skippyall/minions/program/conversion/CastConverter.java @@ -10,7 +10,7 @@ import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.registration.ValueConverters; import io.github.skippyall.minions.util.TranslationUtil; import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/io/github/skippyall/minions/program/conversion/Casts.java b/src/main/java/io/github/skippyall/minions/program/conversion/Casts.java index 9ecb9df..81fcc40 100644 --- a/src/main/java/io/github/skippyall/minions/program/conversion/Casts.java +++ b/src/main/java/io/github/skippyall/minions/program/conversion/Casts.java @@ -7,7 +7,7 @@ import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.registration.ValueTypes; import io.github.skippyall.minions.util.TranslationUtil; import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; public class Casts { public static @Nullable Cast getCast(ValueType from, ValueType to) { @@ -28,11 +28,16 @@ public class Casts { return (Cast) new Cast.CastCrafter<>(from, ValueTypes.STRING, String::valueOf).craftCast(); } + if(from == ValueTypes.STRING && to == ValueTypes.DOUBLE) { + //noinspection unchecked + return (Cast) new Cast.CastCrafter<>(ValueTypes.STRING, ValueTypes.DOUBLE, Double::parseDouble).canFail().lossy().craftCast(); + } + return null; } public static @Nullable T cast(TypedValue from, ValueType to) { - @Nullable Cast cast = getCast(from.type(), to); + Cast cast = getCast(from.type(), to); if(cast != null) { return cast.cast(from.value()); } else { diff --git a/src/main/java/io/github/skippyall/minions/program/conversion/ConverterList.java b/src/main/java/io/github/skippyall/minions/program/conversion/ConverterList.java index 5029445..6222e48 100644 --- a/src/main/java/io/github/skippyall/minions/program/conversion/ConverterList.java +++ b/src/main/java/io/github/skippyall/minions/program/conversion/ConverterList.java @@ -4,8 +4,10 @@ import com.mojang.serialization.Codec; import io.github.skippyall.minions.gui.input.Result; import io.github.skippyall.minions.program.value.TypedValue; import io.github.skippyall.minions.program.value.ValueType; +import io.github.skippyall.minions.registration.MinionRegistries; +import io.github.skippyall.minions.util.TranslationUtil; import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -64,8 +66,19 @@ public class ConverterList { } } - public Result<@Nullable Void, Component> check() { - return new Result.Success<>(null); + public static @Nullable Component createConverterWarning(ValueConverter converter) { + return null; + } + + public static @Nullable Component createCastWarning(ValueType fromType, ValueType toType) { + Component warning = null; + + Cast cast = Casts.getCast(fromType, toType); + if(cast == null) { + warning = Component.translatable("minions.converter.cast.not_found", TranslationUtil.getTranslation(fromType, MinionRegistries.VALUE_TYPES), TranslationUtil.getTranslation(toType, MinionRegistries.VALUE_TYPES)); + } + + return warning; } @Override diff --git a/src/main/java/io/github/skippyall/minions/program/conversion/EqualityConverter.java b/src/main/java/io/github/skippyall/minions/program/conversion/EqualityConverter.java index 6f352e5..126af0d 100644 --- a/src/main/java/io/github/skippyall/minions/program/conversion/EqualityConverter.java +++ b/src/main/java/io/github/skippyall/minions/program/conversion/EqualityConverter.java @@ -8,7 +8,7 @@ import io.github.skippyall.minions.registration.MinionRegistries; import io.github.skippyall.minions.registration.ValueConverters; import io.github.skippyall.minions.registration.ValueTypes; import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/io/github/skippyall/minions/program/conversion/ValueConverter.java b/src/main/java/io/github/skippyall/minions/program/conversion/ValueConverter.java index 0f78511..2c26673 100644 --- a/src/main/java/io/github/skippyall/minions/program/conversion/ValueConverter.java +++ b/src/main/java/io/github/skippyall/minions/program/conversion/ValueConverter.java @@ -5,6 +5,7 @@ import io.github.skippyall.minions.gui.input.Result; import io.github.skippyall.minions.program.value.ValueType; import io.github.skippyall.minions.registration.MinionRegistries; import net.minecraft.network.chat.Component; +import org.jspecify.annotations.Nullable; public interface ValueConverter { Codec> CODEC = MinionRegistries.VALUE_CONVERTER_TYPES.byNameCodec().dispatch(ValueConverter::getType, ValueConverterType::getCodec); @@ -19,7 +20,7 @@ public interface ValueConverter { Component getDisplayText(); - default ValueConverter cast(ValueType from, ValueType to) { + default @Nullable ValueConverter cast(ValueType from, ValueType to) { if(from == getFrom() && to == getTo()) { //noinspection unchecked return (ValueConverter) this; diff --git a/src/main/java/io/github/skippyall/minions/program/conversion/ValueConverterType.java b/src/main/java/io/github/skippyall/minions/program/conversion/ValueConverterType.java index af541a3..1c56c88 100644 --- a/src/main/java/io/github/skippyall/minions/program/conversion/ValueConverterType.java +++ b/src/main/java/io/github/skippyall/minions/program/conversion/ValueConverterType.java @@ -3,7 +3,7 @@ package io.github.skippyall.minions.program.conversion; import com.mojang.serialization.MapCodec; import io.github.skippyall.minions.gui.MinionsGui; import io.github.skippyall.minions.program.value.ValueType; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/io/github/skippyall/minions/program/conversion/package-info.java b/src/main/java/io/github/skippyall/minions/program/conversion/package-info.java new file mode 100644 index 0000000..f288592 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/conversion/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.program.conversion; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/program/instruction/ConfiguredInstruction.java b/src/main/java/io/github/skippyall/minions/program/instruction/ConfiguredInstruction.java index 9232a37..b6ed7b1 100644 --- a/src/main/java/io/github/skippyall/minions/program/instruction/ConfiguredInstruction.java +++ b/src/main/java/io/github/skippyall/minions/program/instruction/ConfiguredInstruction.java @@ -8,9 +8,13 @@ import io.github.skippyall.minions.program.supplier.Parameter; import io.github.skippyall.minions.program.supplier.ParameterValueList; import io.github.skippyall.minions.program.supplier.ValueSupplierList; import io.github.skippyall.minions.registration.MinionRegistries; +import net.minecraft.network.chat.Component; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; /** * Holds an instruction, its configuration and is responsible for executing the instruction @@ -24,6 +28,7 @@ public class ConfiguredInstruction> { private boolean paused = false; private SerializableListenerManager listeners = new SerializableListenerManager<>(); + private List lastErrors = List.of(); private ConfiguredInstruction( InstructionType instruction, @@ -64,8 +69,18 @@ public class ConfiguredInstruction> { return arguments; } + public List preCheck() { + List errors = new ArrayList<>(); + arguments.checkRun(instruction, errors::add); + return errors; + } + public boolean canRun() { - return instruction != null && arguments != null && arguments.checkRun(instruction) == null; + return preCheck().isEmpty(); + } + + public List getLastErrors() { + return lastErrors; } public boolean isRunning() { @@ -78,15 +93,21 @@ public class ConfiguredInstruction> { public void run(R minion) { if(canRun() && !isRunning()) { + lastErrors = new ArrayList<>(); try { - ParameterValueList resolvedArguments = arguments.resolve(minion); - execution = instruction.createExecution(resolvedArguments, minion); - execution.start(minion); + ParameterValueList resolvedArguments = arguments.resolve(minion, lastErrors::add); + if(lastErrors.isEmpty()) { + execution = instruction.createExecution(resolvedArguments, minion); + execution.start(minion); + } } catch (Exception e) { Minions.LOGGER.error("An error occurred while executing configured Instruction", e); + lastErrors.add(Component.translatable("minions.gui.instruction.check.internal_error")); } - listeners.forEach(listener -> listener.onRun(this)); + for(ConfiguredInstructionListener listener : listeners) { + listener.onRun(this); + } } } diff --git a/src/main/java/io/github/skippyall/minions/program/instruction/execution/package-info.java b/src/main/java/io/github/skippyall/minions/program/instruction/execution/package-info.java new file mode 100644 index 0000000..5382cc5 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/instruction/execution/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.program.instruction.execution; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/program/instruction/package-info.java b/src/main/java/io/github/skippyall/minions/program/instruction/package-info.java new file mode 100644 index 0000000..b87df9f --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/instruction/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.program.instruction; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/program/package-info.java b/src/main/java/io/github/skippyall/minions/program/package-info.java new file mode 100644 index 0000000..943b914 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.program; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/program/supplier/FixedValueSupplierType.java b/src/main/java/io/github/skippyall/minions/program/supplier/FixedValueSupplierType.java index 343d433..3316efb 100644 --- a/src/main/java/io/github/skippyall/minions/program/supplier/FixedValueSupplierType.java +++ b/src/main/java/io/github/skippyall/minions/program/supplier/FixedValueSupplierType.java @@ -4,7 +4,7 @@ import com.mojang.serialization.Codec; import io.github.skippyall.minions.gui.MinionsGui; import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.value.ValueType; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/io/github/skippyall/minions/program/supplier/Parameter.java b/src/main/java/io/github/skippyall/minions/program/supplier/Parameter.java index 5ad7c64..5c9721b 100644 --- a/src/main/java/io/github/skippyall/minions/program/supplier/Parameter.java +++ b/src/main/java/io/github/skippyall/minions/program/supplier/Parameter.java @@ -5,7 +5,7 @@ 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 org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; public record Parameter(String name, ValueType type) { public static final MapCodec> MAP_CODEC = RecordCodecBuilder.mapCodec(instance -> diff --git a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplier.java b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplier.java index 12af1e8..d0af28c 100644 --- a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplier.java +++ b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplier.java @@ -6,7 +6,7 @@ import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.value.ValueType; import io.github.skippyall.minions.registration.MinionRegistries; import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; /** * An ValueSupplier can be supplied to an instruction with a matching parameter. @@ -53,8 +53,9 @@ public interface ValueSupplier> { "type", s -> DataResult.success(s.getValueType()), valueType -> { - if(type.getCodec(valueType) != null) { - return DataResult.success(type.getCodec(valueType).fieldOf("valueType")); + Codec> valueTypeCodec = type.getCodec(valueType); + if(valueTypeCodec != null) { + return DataResult.success(valueTypeCodec.fieldOf("valueType")); } else { return DataResult.error(() -> "Supplier type " + type + "not available for value type " + valueType); } diff --git a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplierList.java b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplierList.java index f6ae328..97834f9 100644 --- a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplierList.java +++ b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplierList.java @@ -10,7 +10,7 @@ import io.github.skippyall.minions.program.conversion.ConverterList; import io.github.skippyall.minions.program.instruction.InstructionType; import io.github.skippyall.minions.program.value.TypedValue; import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.Collection; @@ -37,7 +37,7 @@ public class ValueSupplierList> { return List.copyOf(arguments.values()); } - public ValueSupplier getArgument(Parameter parameter) { + public @Nullable ValueSupplier getArgument(Parameter parameter) { if(arguments.containsKey(parameter)) { return arguments.get(parameter).supplier; } else { @@ -60,10 +60,10 @@ public class ValueSupplierList> { arguments.remove(parameter); } - public ParameterValueList resolve(R runtime) { + public ParameterValueList resolve(R runtime, Consumer errorConsumer) { ParameterValueList list = new ParameterValueList(); for(ValueSupplierEntry argument : arguments.values()) { - argument.addToList(list, runtime); + argument.addToList(list, runtime, errorConsumer); } return list; } @@ -72,28 +72,20 @@ public class ValueSupplierList> { return arguments.containsKey(parameter); } - public @Nullable Component checkHasArguments(Collection> checkParameters) { + public void checkHasArguments(Collection> checkParameters, Consumer errorConsumer) { for(Parameter parameter : checkParameters) { if(!hasArgumentFor(parameter)) { - return Component.translatable("minions.gui.instruction.check.argument_not_set", parameter.name()); + errorConsumer.accept(Component.translatable("minions.gui.instruction.check.argument_not_set", parameter.name())); } } - return null; } - public @Nullable Component checkRun(InstructionType instructionType) { - @Nullable Component checkResult = checkHasArguments(instructionType.getParameters()); - if(checkResult != null) { - return checkResult; - } + public void checkRun(InstructionType instructionType, Consumer errorConsumer) { + checkHasArguments(instructionType.getParameters(), errorConsumer); for(ValueSupplierEntry entry : arguments.values()) { - checkResult = entry.check(); - if(checkResult != null) { - return checkResult; - } + entry.check(errorConsumer); } - return null; } private void onChange(Parameter parameter) { @@ -148,15 +140,13 @@ public class ValueSupplierList> { this.supplier = supplier; } - private @Nullable Component addToList(ParameterValueList list, R runtime) { + private void addToList(ParameterValueList list, R runtime, Consumer errorConsumer) { Result result = getValue(supplier, runtime); switch (result) { - case Result.Success success -> { - list.setValue(parameter, success.result()); - return null; - } + case Result.Success success -> list.setValue(parameter, success.result()); case Result.Error error -> { - return error.message(); + errorConsumer.accept(Component.translatable("minions.instruction.argument.error", parameter.name())); + errorConsumer.accept(error.message()); } } } @@ -168,7 +158,7 @@ public class ValueSupplierList> { return convertedResult.flatMap(convertedValue -> Casts.castOrError(convertedValue, parameter.type())); } - public @Nullable Component check() { + public @Nullable Component check(Consumer errorConsumer) { //TODO check it return null; } diff --git a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplierType.java b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplierType.java index 7ea95cc..1b433d7 100644 --- a/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplierType.java +++ b/src/main/java/io/github/skippyall/minions/program/supplier/ValueSupplierType.java @@ -4,12 +4,12 @@ import com.mojang.serialization.Codec; import io.github.skippyall.minions.gui.MinionsGui; import io.github.skippyall.minions.program.InstructionRuntime; import io.github.skippyall.minions.program.value.ValueType; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; public abstract class ValueSupplierType> { - public abstract Codec> getCodec(ValueType type); + public abstract @Nullable Codec> getCodec(ValueType type); public abstract CompletableFuture> openConfiguration(MinionsGui gui, ValueType valueType, @Nullable ValueSupplier previous); } diff --git a/src/main/java/io/github/skippyall/minions/program/supplier/package-info.java b/src/main/java/io/github/skippyall/minions/program/supplier/package-info.java new file mode 100644 index 0000000..29c560d --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/supplier/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.program.supplier; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/program/value/TypedValue.java b/src/main/java/io/github/skippyall/minions/program/value/TypedValue.java index b1608cd..6748bb0 100644 --- a/src/main/java/io/github/skippyall/minions/program/value/TypedValue.java +++ b/src/main/java/io/github/skippyall/minions/program/value/TypedValue.java @@ -1,7 +1,9 @@ package io.github.skippyall.minions.program.value; +import java.util.Objects; + public record TypedValue(T value, ValueType type) { public static TypedValue of(Object o, ValueType type) { - return new TypedValue<>(type.checkedCast(o), type); + return new TypedValue(Objects.requireNonNull(type.checkedCast(o)), type); } } diff --git a/src/main/java/io/github/skippyall/minions/program/value/ValueType.java b/src/main/java/io/github/skippyall/minions/program/value/ValueType.java index 8742bd0..2323e93 100644 --- a/src/main/java/io/github/skippyall/minions/program/value/ValueType.java +++ b/src/main/java/io/github/skippyall/minions/program/value/ValueType.java @@ -3,7 +3,7 @@ package io.github.skippyall.minions.program.value; import com.mojang.serialization.Codec; import io.github.skippyall.minions.gui.MinionsGui; import net.minecraft.network.chat.Component; -import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.Nullable; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/io/github/skippyall/minions/program/value/package-info.java b/src/main/java/io/github/skippyall/minions/program/value/package-info.java new file mode 100644 index 0000000..ad46bfa --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/program/value/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.program.value; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/registration/MinionBlocks.java b/src/main/java/io/github/skippyall/minions/registration/MinionBlocks.java index 17c32e8..d46e75c 100644 --- a/src/main/java/io/github/skippyall/minions/registration/MinionBlocks.java +++ b/src/main/java/io/github/skippyall/minions/registration/MinionBlocks.java @@ -36,6 +36,7 @@ public class MinionBlocks { FabricBlockEntityTypeBuilder.create(MinionTriggerBlockEntity::new, MINION_TRIGGER_BLOCK).build() ); + public static final Identifier ANALOG_INPUT_BLOCK_ID = Identifier.fromNamespaceAndPath(Minions.MOD_ID, "analog_input"); public static final AnalogInputBlock ANALOG_INPUT_BLOCK = Registry.register( BuiltInRegistries.BLOCK, diff --git a/src/main/java/io/github/skippyall/minions/registration/MinionCreativeTab.java b/src/main/java/io/github/skippyall/minions/registration/MinionCreativeTab.java index 089029d..97a10b1 100644 --- a/src/main/java/io/github/skippyall/minions/registration/MinionCreativeTab.java +++ b/src/main/java/io/github/skippyall/minions/registration/MinionCreativeTab.java @@ -7,11 +7,13 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; +import org.jspecify.annotations.Nullable; import java.util.ArrayList; import java.util.List; public class MinionCreativeTab { + @Nullable public static CreativeModeTab group; private static final List items = new ArrayList<>(); diff --git a/src/main/java/io/github/skippyall/minions/registration/MinionItems.java b/src/main/java/io/github/skippyall/minions/registration/MinionItems.java index f578f0f..697fd72 100644 --- a/src/main/java/io/github/skippyall/minions/registration/MinionItems.java +++ b/src/main/java/io/github/skippyall/minions/registration/MinionItems.java @@ -1,8 +1,7 @@ package io.github.skippyall.minions.registration; -import eu.pb4.polymer.core.api.item.PolymerBlockItem; import eu.pb4.polymer.core.api.item.SimplePolymerItem; -import io.github.skippyall.minions.block.miniontrigger.MinionTriggerBlockItem; +import io.github.skippyall.minions.block.MinionsBlockItem; import io.github.skippyall.minions.clipboard.ClipboardItem; import io.github.skippyall.minions.minion.MinionItem; import io.github.skippyall.minions.minion.MinionRuntime; @@ -69,12 +68,17 @@ public class MinionItems { List.of(SpecialAbilities.MOB_SPAWNING) ); - public static final PolymerBlockItem MINION_TRIGGER_ITEM = - registerItem( - MinionBlocks.MINION_TRIGGER_ID, - settings -> new MinionTriggerBlockItem(MinionBlocks.MINION_TRIGGER_BLOCK, settings, Items.COMPARATOR), - new Item.Properties().useBlockDescriptionPrefix() - ); + public static final MinionsBlockItem MINION_TRIGGER_ITEM = registerItem( + MinionBlocks.MINION_TRIGGER_ID, + settings -> new MinionsBlockItem(MinionBlocks.MINION_TRIGGER_BLOCK, settings, Items.COMPARATOR), + new Item.Properties().useBlockDescriptionPrefix() + ); + + public static final MinionsBlockItem ANALOG_INPUT_ITEM = registerItem( + MinionBlocks.ANALOG_INPUT_BLOCK_ID, + settings -> new MinionsBlockItem(MinionBlocks.ANALOG_INPUT_BLOCK, settings, Items.REPEATER), + new Item.Properties().useBlockDescriptionPrefix() + ); public static final ClipboardItem REFERENCE_ITEM = registerItem(Identifier.fromNamespaceAndPath(MOD_ID, "clipboard"), ClipboardItem::new); diff --git a/src/main/java/io/github/skippyall/minions/registration/package-info.java b/src/main/java/io/github/skippyall/minions/registration/package-info.java new file mode 100644 index 0000000..da8efc6 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/registration/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.registration; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/java/io/github/skippyall/minions/util/TranslationUtil.java b/src/main/java/io/github/skippyall/minions/util/TranslationUtil.java index 446183a..13a630a 100644 --- a/src/main/java/io/github/skippyall/minions/util/TranslationUtil.java +++ b/src/main/java/io/github/skippyall/minions/util/TranslationUtil.java @@ -1,14 +1,16 @@ package io.github.skippyall.minions.util; import net.minecraft.core.Registry; +import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; +import org.jspecify.annotations.Nullable; public class TranslationUtil { - public static String getTranslationKey(T object, Registry registry, String defaultKey) { + public static String getTranslationKey(@Nullable T object, Registry registry, String defaultKey) { return getTranslationKey(object, registry, registry.key().identifier().getPath(), defaultKey); } - public static String getTranslationKey(T object, Registry registry, String prefix, String defaultKey) { + public static String getTranslationKey(@Nullable T object, Registry registry, String prefix, String defaultKey) { if(object == null) { return defaultKey; } @@ -20,7 +22,11 @@ public class TranslationUtil { return id.toLanguageKey(prefix); } - public static String getTranslationKey(T object, Registry registry) { + public static String getTranslationKey(@Nullable T object, Registry registry) { return getTranslationKey(object, registry, "minions.generic.unknown"); } + + public static Component getTranslation(@Nullable T object, Registry registry) { + return Component.translatable(TranslationUtil.getTranslationKey(object, registry)); + } } diff --git a/src/main/java/io/github/skippyall/minions/util/package-info.java b/src/main/java/io/github/skippyall/minions/util/package-info.java new file mode 100644 index 0000000..43dc4e1 --- /dev/null +++ b/src/main/java/io/github/skippyall/minions/util/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.github.skippyall.minions.util; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/src/main/resources/assets/minions/lang/en_us.json b/src/main/resources/assets/minions/lang/en_us.json index 2f00732..70d534d 100644 --- a/src/main/resources/assets/minions/lang/en_us.json +++ b/src/main/resources/assets/minions/lang/en_us.json @@ -34,6 +34,7 @@ "minions.gui.instruction.configure.delete.confirm": "Delete %s?", "minions.gui.instruction.configure.copy": "Copy Reference", "minions.gui.instruction.configure.copy.description": "Click here and then use a Minion Trigger Block to bind it", + "minions.gui.instruction.last_errors": "Last Errors", "minions.gui.instruction.run": "Run", "minions.gui.instruction.stop": "Stop", "minions.gui.instruction.argument.title": "Argument for %s (%s)", @@ -44,30 +45,19 @@ "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.gui.instruction.converters": "Converters", "minions.gui.instruction.converters.cast": "Cast from %s to %s", "minions.gui.instruction.converter.title": "Configure Converter", "minions.gui.instruction.converter.type.title": "Select a Converter Type", "minions.gui.instruction.converter.data": "Converter Data", - "minions.converter.list.passing_error": "Error while passing previous value to converter #%s: %s", - - "minions.command.input.int.fail": "Not an integer", - "minions.command.input.float.fail": "Not a number", - "minions.command.action.details": "Set how to %s", - "minions.command.action.once": "%s once", - "minions.command.action.continuous": "%s continuously", - "minions.command.action.interval": "%s every x seconds", - "minions.command.action.stop": "Stop %s", - "minions.command.action.interval.enter": "Enter an interval in seconds", - "minions.command.interact.name": "Interact", - "minions.command.interact.description": "Use and place blocks", - "minions.command.attack.name": "Attack", - "minions.command.attack.description": "Attack and mine blocks", - - "minions.command.minion.not_present": "This minion does not exist", + "minions.gui.instruction.check.instruction_type_not_set": "Instruction Type is not set", + "minions.gui.instruction.check.arguments_not_set": "Arguments are not set", + "minions.gui.instruction.check.argument_not_set": "Argument %s is not set", + "minions.gui.instruction.check.internal_error": "Internal Error, check server console", + "minions.instruction.argument.error": "Error while getting argument for %s:", + "minions.converter.list.passing_error": "Error while passing previous value to converter #%s:", + "minions.converter.cast.not_found": "No cast from %s to %s", "minions.reference.instruction.tooltip": "Linked to instruction %s in %s", "minions.reference.block.tooltip": "Linked to block at %s", @@ -88,6 +78,7 @@ "instruction.minions.turn_vector.description": "Turn the head so that it faces a block with specific cardinal offsets", "value_type.minions.long": "Integer", + "value_type.minions.long.not_long": "Not an Integer", "value_type.minions.double": "Decimal", "value_type.minions.boolean": "Boolean", "value_type.minions.boolean.true": "True", @@ -125,5 +116,6 @@ "minions.generic.name.invalid": "Name is invalid", "minions.generic.name.taken": "This name is already used", "minions.generic.mod_name": "Minions", - "minions.generic.unknown": "Unknown" + "minions.generic.unknown": "Unknown", + "minions.generic.error": "Error" } \ No newline at end of file