From 00774a5229e9e2413c2e3703fac832c24c61849e Mon Sep 17 00:00:00 2001 From: Misode Date: Thu, 21 Mar 2024 18:05:18 +0100 Subject: [PATCH] Add /assert items --- gradle.properties | 2 +- .../packtest/PackTestItemPredicate.java | 13 ++++ .../packtest/commands/AssertCommand.java | 74 +++++++++++++++++++ .../mixin/ItemPredicateArgumentMixin.java | 27 +++++++ src/main/resources/packtest.mixins.json | 3 +- 5 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/main/java/io/github/misode/packtest/PackTestItemPredicate.java create mode 100644 src/main/java/io/github/misode/packtest/mixin/ItemPredicateArgumentMixin.java diff --git a/gradle.properties b/gradle.properties index 81a2e3a..0df91e3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,7 +8,7 @@ minecraft_version=24w12a loader_version=0.15.7 # Mod Properties -mod_version=1.7.0-beta2 +mod_version=1.7.0-beta3 maven_group=io.github.misode archives_base_name=packtest diff --git a/src/main/java/io/github/misode/packtest/PackTestItemPredicate.java b/src/main/java/io/github/misode/packtest/PackTestItemPredicate.java new file mode 100644 index 0000000..afb4592 --- /dev/null +++ b/src/main/java/io/github/misode/packtest/PackTestItemPredicate.java @@ -0,0 +1,13 @@ +package io.github.misode.packtest; + +import net.minecraft.commands.arguments.item.ItemPredicateArgument; +import net.minecraft.world.item.ItemStack; + +import java.util.function.Predicate; + +public record PackTestItemPredicate(Predicate predicate, String source) implements ItemPredicateArgument.Result { + @Override + public boolean test(ItemStack itemStack) { + return predicate.test(itemStack); + } +} diff --git a/src/main/java/io/github/misode/packtest/commands/AssertCommand.java b/src/main/java/io/github/misode/packtest/commands/AssertCommand.java index 2fb0a2d..488bce9 100644 --- a/src/main/java/io/github/misode/packtest/commands/AssertCommand.java +++ b/src/main/java/io/github/misode/packtest/commands/AssertCommand.java @@ -7,9 +7,11 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.context.ContextChain; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.Dynamic3CommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.suggestion.SuggestionProvider; import io.github.misode.packtest.*; +import it.unimi.dsi.fastutil.ints.IntList; import net.minecraft.advancements.critereon.MinMaxBounds; import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.CommandSourceStack; @@ -17,6 +19,7 @@ import net.minecraft.commands.arguments.*; import net.minecraft.commands.arguments.blocks.BlockPredicateArgument; import net.minecraft.commands.arguments.coordinates.BlockPosArgument; +import net.minecraft.commands.arguments.item.ItemPredicateArgument; import net.minecraft.commands.arguments.selector.EntitySelector; import net.minecraft.commands.execution.ChainModifiers; import net.minecraft.commands.execution.CustomCommandExecutor; @@ -32,7 +35,11 @@ import net.minecraft.server.ReloadableServerRegistries; import net.minecraft.server.commands.data.DataCommands; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.Container; import net.minecraft.world.entity.Entity; +import net.minecraft.world.inventory.SlotRange; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.pattern.BlockInWorld; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.LootParams; @@ -61,6 +68,9 @@ public class AssertCommand { private static final SimpleCommandExceptionType ERROR_NO_HELPER = new SimpleCommandExceptionType( Component.literal("Not inside a test") ); + private static final Dynamic3CommandExceptionType ERROR_SOURCE_NOT_A_CONTAINER = new Dynamic3CommandExceptionType( + (x, y, z) -> Component.translatableEscape("commands.item.source.not_a_container", x, y, z) + ); private static final SuggestionProvider SUGGEST_PREDICATE = (ctx, suggestions) -> { ReloadableServerRegistries.Holder registries = ctx.getSource().getServer().reloadableRegistries(); return SharedSuggestionProvider.suggestResource(registries.getKeys(Registries.PREDICATE), suggestions); @@ -92,6 +102,17 @@ public static void addConditions(LiteralArgumentBuilder buil .then(argument("predicate", ResourceOrIdArgument.lootPredicate(buildContext)) .suggests(SUGGEST_PREDICATE) .executes(expect.apply(AssertCommand::assertPredicate)))) + .then(literal("items") + .then(literal("entity") + .then(argument("entities", EntityArgument.entities()) + .then(argument("slots", SlotsArgument.slots()) + .then(argument("item_predicate", ItemPredicateArgument.itemPredicate(buildContext)) + .executes(expect.apply(AssertCommand::assertItemsEntity)))))) + .then(literal("block") + .then(argument("pos", BlockPosArgument.blockPos()) + .then(argument("slots", SlotsArgument.slots()) + .then(argument("item_predicate", ItemPredicateArgument.itemPredicate(buildContext)) + .executes(expect.apply(AssertCommand::assertItemsBlock))))))) .then(literal("score") .then(argument("target", ScoreHolderArgument.scoreHolder()) .suggests(ScoreHolderArgument.SUGGEST_SCORE_HOLDERS) @@ -177,6 +198,59 @@ private static AssertResult assertPredicate(CommandContext c return err(expected); } + private static AssertResult assertItemsEntity(CommandContext ctx) throws CommandSyntaxException { + EntitySelector selector = ctx.getArgument("entities", EntitySelector.class); + String selectorSource = ((PackTestArgumentSource)selector).packtest$getSource(); + List entities = selector.findEntities(ctx.getSource()); + SlotRange slotRange = SlotsArgument.getSlots(ctx, "slots"); + ItemPredicateArgument.Result itemPredicate = ItemPredicateArgument.getItemPredicate(ctx, "item_predicate"); + String itemPredicateSource = ((PackTestItemPredicate)itemPredicate).source(); + int count = 0; + for(Entity entity : entities) { + IntList slots = slotRange.slots(); + for(int i = 0; i < slots.size(); ++i) { + ItemStack itemStack = entity.getSlot(slots.getInt(i)).get(); + if (itemPredicate.test(itemStack)) { + count += itemStack.getCount(); + } + } + } + String expected = selectorSource + " to have items " + itemPredicateSource; + if (count > 0) { + return ok(expected); + } + return err(expected); + } + + private static AssertResult assertItemsBlock(CommandContext ctx) throws CommandSyntaxException { + BlockPos pos = BlockPosArgument.getLoadedBlockPos(ctx, "pos"); + SlotRange slotRange = SlotsArgument.getSlots(ctx, "slots"); + ItemPredicateArgument.Result itemPredicate = ItemPredicateArgument.getItemPredicate(ctx, "item_predicate"); + String itemPredicateSource = ((PackTestItemPredicate)itemPredicate).source(); + BlockEntity blockEntity = ctx.getSource().getLevel().getBlockEntity(pos); + if (blockEntity instanceof Container container) { + int count = 0; + int lvt6 = container.getContainerSize(); + IntList slots = slotRange.slots(); + for(int i = 0; i < slots.size(); ++i) { + int slot = slots.getInt(i); + if (slot >= 0 && slot < lvt6) { + ItemStack itemStack = container.getItem(slot); + if (itemPredicate.test(itemStack)) { + count += itemStack.getCount(); + } + } + } + String expected = "block to have items " + itemPredicateSource; + if (count > 0) { + return ok(expected); + } + return err(expected); + } else { + throw ERROR_SOURCE_NOT_A_CONTAINER.create(pos.getX(), pos.getY(), pos.getZ()); + } + } + private static LiteralArgumentBuilder addScoreCheck(String op, BiPredicate predicate, Function> expect) { return literal(op) .then(argument("source", ScoreHolderArgument.scoreHolder()) diff --git a/src/main/java/io/github/misode/packtest/mixin/ItemPredicateArgumentMixin.java b/src/main/java/io/github/misode/packtest/mixin/ItemPredicateArgumentMixin.java new file mode 100644 index 0000000..44e13b5 --- /dev/null +++ b/src/main/java/io/github/misode/packtest/mixin/ItemPredicateArgumentMixin.java @@ -0,0 +1,27 @@ +package io.github.misode.packtest.mixin; + +import com.llamalad7.mixinextras.injector.ModifyReturnValue; +import com.llamalad7.mixinextras.sugar.Local; +import com.llamalad7.mixinextras.sugar.Share; +import com.llamalad7.mixinextras.sugar.ref.LocalIntRef; +import com.mojang.brigadier.StringReader; +import io.github.misode.packtest.PackTestItemPredicate; +import net.minecraft.commands.arguments.item.ItemPredicateArgument; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ItemPredicateArgument.class) +public class ItemPredicateArgumentMixin { + + @Inject(method = "parse(Lcom/mojang/brigadier/StringReader;)Lnet/minecraft/commands/arguments/item/ItemPredicateArgument$Result;", at = @At("HEAD")) + private void getCursor(StringReader stringReader, CallbackInfoReturnable cir, @Share("cursor") LocalIntRef cursorRef) { + cursorRef.set(stringReader.getCursor()); + } + + @ModifyReturnValue(method = "parse(Lcom/mojang/brigadier/StringReader;)Lnet/minecraft/commands/arguments/item/ItemPredicateArgument$Result;", at = @At("RETURN")) + private ItemPredicateArgument.Result returnPredicate(ItemPredicateArgument.Result predicate, @Local StringReader reader, @Share("cursor") LocalIntRef cursorRef) { + return new PackTestItemPredicate(predicate, reader.getRead().substring(cursorRef.get())); + } +} diff --git a/src/main/resources/packtest.mixins.json b/src/main/resources/packtest.mixins.json index e142dc8..ecb5ba2 100644 --- a/src/main/resources/packtest.mixins.json +++ b/src/main/resources/packtest.mixins.json @@ -13,12 +13,13 @@ "EntitySelectorMixin", "ForceLoadCommandMixin", "GameTestBatchMixin", - "GameTestRunner1Mixin", "GameTestHelperMixin", "GameTestInfoMixin", "GameTestRegistryMixin", + "GameTestRunner1Mixin", "GameTestSequenceMixin", "GameTestServerMixin", + "ItemPredicateArgumentMixin", "LogTestReporterMixin", "LootDataTypeMixin", "MinecraftServerMixin",