diff --git a/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryGameTest.java b/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryGameTest.java index 149b9e87d..588008e41 100644 --- a/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryGameTest.java +++ b/fabric-content-registries-v0/src/testmod/java/net/fabricmc/fabric/test/content/registry/ContentRegistryGameTest.java @@ -20,10 +20,7 @@ import java.util.function.Consumer; import net.minecraft.block.Blocks; import net.minecraft.block.ComposterBlock; -import net.minecraft.block.HopperBlock; -import net.minecraft.block.entity.AbstractFurnaceBlockEntity; import net.minecraft.block.entity.BrewingStandBlockEntity; -import net.minecraft.block.entity.HopperBlockEntity; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.PotionContentsComponent; import net.minecraft.entity.player.PlayerEntity; @@ -34,7 +31,6 @@ import net.minecraft.test.GameTest; import net.minecraft.test.TestContext; import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; import net.minecraft.world.GameMode; import net.fabricmc.fabric.api.gametest.v1.FabricGameTest; @@ -67,35 +63,6 @@ public class ContentRegistryGameTest { context.complete(); } - @GameTest(templateName = FabricGameTest.EMPTY_STRUCTURE, tickLimit = 110) - public void testFuelRegistry(TestContext context) { - BlockPos pos = new BlockPos(0, 1, 0); - // Use blast furnace to make it cook faster (100 ticks / 200 ticks) - context.setBlockState(pos, Blocks.BLAST_FURNACE); - - if (!(context.getBlockEntity(pos) instanceof AbstractFurnaceBlockEntity furnace)) { - throw new AssertionError("Furnace was not placed"); - } - - furnace.setStack(0, new ItemStack(Items.RAW_IRON, 1)); - // Ensure hopper inserts fuel to the furnace - context.setBlockState(pos.east(), Blocks.HOPPER.getDefaultState().with(HopperBlock.FACING, Direction.WEST)); - - if (!(context.getBlockEntity(pos.east()) instanceof HopperBlockEntity hopper)) { - throw new AssertionError("Hopper was not placed"); - } - - // 100 ticks/1 smelted item worth of fuel. - hopper.setStack(0, new ItemStack(Items.OBSIDIAN, 2)); - hopper.setStack(1, new ItemStack(Items.DIRT)); - - context.waitAndRun(105, () -> { - context.assertTrue(hopper.isEmpty(), "fuel hopper should have been emptied"); - context.assertTrue(ItemStack.areEqual(furnace.getStack(2), new ItemStack(Items.IRON_INGOT, 1)), "one iron ingot should have been smelted"); - context.complete(); - }); - } - @GameTest(templateName = FabricGameTest.EMPTY_STRUCTURE) public void testStrippableBlockRegistry(TestContext context) { BlockPos pos = new BlockPos(0, 1, 0); diff --git a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientTagLoaderMixin.java b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientConfigurationNetworkHandlerMixin.java similarity index 55% rename from fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientTagLoaderMixin.java rename to fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientConfigurationNetworkHandlerMixin.java index 9274f4a55..1928da426 100644 --- a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientTagLoaderMixin.java +++ b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientConfigurationNetworkHandlerMixin.java @@ -16,27 +16,21 @@ package net.fabricmc.fabric.mixin.event.lifecycle.client; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import net.minecraft.client.network.ClientPlayNetworkHandler; -import net.minecraft.network.packet.s2c.common.SynchronizeTagsS2CPacket; +import net.minecraft.client.network.ClientConfigurationNetworkHandler; import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.resource.ResourceFactory; import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents; -@Mixin(ClientPlayNetworkHandler.class) -public class ClientTagLoaderMixin { - @Shadow - @Final - private DynamicRegistryManager.Immutable combinedDynamicRegistries; - - @Inject(method = "onSynchronizeTags", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/FuelRegistry;createDefault(Lnet/minecraft/registry/RegistryWrapper$WrapperLookup;Lnet/minecraft/resource/featuretoggle/FeatureSet;)Lnet/minecraft/item/FuelRegistry;")) - private void invokeTagsLoaded(SynchronizeTagsS2CPacket packet, CallbackInfo ci) { - CommonLifecycleEvents.TAGS_LOADED.invoker().onTagsLoaded(combinedDynamicRegistries, true); +@Mixin(ClientConfigurationNetworkHandler.class) +public class ClientConfigurationNetworkHandlerMixin { + @Inject(method = "method_57043", at = @At(value = "RETURN")) + private void invokeTagsLoaded(ResourceFactory factory, CallbackInfoReturnable cir) { + CommonLifecycleEvents.TAGS_LOADED.invoker().onTagsLoaded(cir.getReturnValue(), true); } } diff --git a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientPlayNetworkHandlerMixin.java b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientPlayNetworkHandlerMixin.java index 367589bb4..fea4a904a 100644 --- a/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientPlayNetworkHandlerMixin.java +++ b/fabric-lifecycle-events-v1/src/client/java/net/fabricmc/fabric/mixin/event/lifecycle/client/ClientPlayNetworkHandlerMixin.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.mixin.event.lifecycle.client; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -26,12 +27,15 @@ import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; +import net.minecraft.network.packet.s2c.common.SynchronizeTagsS2CPacket; import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket; import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket; +import net.minecraft.registry.DynamicRegistryManager; import net.minecraft.world.chunk.WorldChunk; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientEntityEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.CommonLifecycleEvents; import net.fabricmc.fabric.impl.event.lifecycle.LoadedChunksCache; @Mixin(ClientPlayNetworkHandler.class) @@ -39,6 +43,10 @@ abstract class ClientPlayNetworkHandlerMixin { @Shadow private ClientWorld world; + @Shadow + @Final + private DynamicRegistryManager.Immutable combinedDynamicRegistries; + @Inject(method = "onPlayerRespawn", at = @At(value = "NEW", target = "net/minecraft/client/world/ClientWorld")) private void onPlayerRespawn(PlayerRespawnS2CPacket packet, CallbackInfo ci) { // If a world already exists, we need to unload all (block)entities in the world. @@ -93,4 +101,9 @@ abstract class ClientPlayNetworkHandlerMixin { } } } + + @Inject(method = "onSynchronizeTags", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/FuelRegistry;createDefault(Lnet/minecraft/registry/RegistryWrapper$WrapperLookup;Lnet/minecraft/resource/featuretoggle/FeatureSet;)Lnet/minecraft/item/FuelRegistry;")) + private void invokeTagsLoaded(SynchronizeTagsS2CPacket packet, CallbackInfo ci) { + CommonLifecycleEvents.TAGS_LOADED.invoker().onTagsLoaded(combinedDynamicRegistries, true); + } } diff --git a/fabric-lifecycle-events-v1/src/client/resources/fabric-lifecycle-events-v1.client.mixins.json b/fabric-lifecycle-events-v1/src/client/resources/fabric-lifecycle-events-v1.client.mixins.json index 294663faf..7365897ec 100644 --- a/fabric-lifecycle-events-v1/src/client/resources/fabric-lifecycle-events-v1.client.mixins.json +++ b/fabric-lifecycle-events-v1/src/client/resources/fabric-lifecycle-events-v1.client.mixins.json @@ -5,7 +5,7 @@ "client": [ "ClientChunkManagerMixin", "ClientPlayNetworkHandlerMixin", - "ClientTagLoaderMixin", + "ClientConfigurationNetworkHandlerMixin", "ClientWorldClientEntityHandlerMixin", "ClientWorldMixin", "MinecraftClientMixin", diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/AllIngredient.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/AllIngredient.java index 9ffaaa237..20c798fae 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/AllIngredient.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/AllIngredient.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.impl.recipe.ingredient.builtin; +import java.util.ArrayList; import java.util.List; import com.mojang.serialization.MapCodec; @@ -54,10 +55,15 @@ public class AllIngredient extends CombinedIngredient { @Override public List> getMatchingStacks() { - return ingredients.stream() - .flatMap(ingredient -> ingredient.getMatchingStacks().stream()) - .distinct() - .toList(); + // There's always at least one sub ingredient, so accessing ingredients[0] is safe. + List> previewStacks = new ArrayList<>(ingredients.getFirst().getMatchingStacks()); + + for (int i = 1; i < ingredients.size(); ++i) { + Ingredient ing = ingredients.get(i); + previewStacks.removeIf(entry -> !ing.test(entry.value().getDefaultStack())); + } + + return previewStacks; } @Override diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/AnyIngredient.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/AnyIngredient.java index b7f53adf8..e9a1c6081 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/AnyIngredient.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/builtin/AnyIngredient.java @@ -16,6 +16,7 @@ package net.fabricmc.fabric.impl.recipe.ingredient.builtin; +import java.util.ArrayList; import java.util.List; import com.mojang.serialization.MapCodec; @@ -54,10 +55,13 @@ public class AnyIngredient extends CombinedIngredient { @Override public List> getMatchingStacks() { - return ingredients.stream() - .flatMap(ingredient -> ingredient.getMatchingStacks().stream()) - .distinct() - .toList(); + List> previewStacks = new ArrayList<>(); + + for (Ingredient ingredient : ingredients) { + previewStacks.addAll(ingredient.getMatchingStacks()); + } + + return previewStacks; } @Override diff --git a/fabric-recipe-api-v1/src/testmod/java/net/fabricmc/fabric/test/recipe/ingredient/IngredientMatchTests.java b/fabric-recipe-api-v1/src/testmod/java/net/fabricmc/fabric/test/recipe/ingredient/IngredientMatchTests.java index 1ef54ae8b..b83166981 100644 --- a/fabric-recipe-api-v1/src/testmod/java/net/fabricmc/fabric/test/recipe/ingredient/IngredientMatchTests.java +++ b/fabric-recipe-api-v1/src/testmod/java/net/fabricmc/fabric/test/recipe/ingredient/IngredientMatchTests.java @@ -43,7 +43,7 @@ public class IngredientMatchTests { Ingredient allIngredient = DefaultCustomIngredients.all(Ingredient.ofItems(Items.APPLE, Items.CARROT), Ingredient.ofItems(Items.STICK, Items.CARROT)); assertEquals(1, allIngredient.getMatchingStacks().size()); - assertEquals(Items.CARROT, allIngredient.getMatchingStacks().getFirst()); + assertEquals(Items.CARROT, allIngredient.getMatchingStacks().getFirst().value()); assertEquals(false, allIngredient.getMatchingStacks().isEmpty()); assertEquals(false, allIngredient.test(new ItemStack(Items.APPLE))); @@ -66,10 +66,10 @@ public class IngredientMatchTests { Ingredient anyIngredient = DefaultCustomIngredients.any(Ingredient.ofItems(Items.APPLE, Items.CARROT), Ingredient.ofItems(Items.STICK, Items.CARROT)); assertEquals(4, anyIngredient.getMatchingStacks().size()); - assertEquals(Items.APPLE, anyIngredient.getMatchingStacks().getFirst()); - assertEquals(Items.CARROT, anyIngredient.getMatchingStacks().get(1)); - assertEquals(Items.STICK, anyIngredient.getMatchingStacks().get(2)); - assertEquals(Items.CARROT, anyIngredient.getMatchingStacks().get(3)); + assertEquals(Items.APPLE, anyIngredient.getMatchingStacks().getFirst().value()); + assertEquals(Items.CARROT, anyIngredient.getMatchingStacks().get(1).value()); + assertEquals(Items.STICK, anyIngredient.getMatchingStacks().get(2).value()); + assertEquals(Items.CARROT, anyIngredient.getMatchingStacks().get(3).value()); assertEquals(false, anyIngredient.getMatchingStacks().isEmpty()); assertEquals(true, anyIngredient.test(new ItemStack(Items.APPLE))); @@ -84,7 +84,7 @@ public class IngredientMatchTests { Ingredient differenceIngredient = DefaultCustomIngredients.difference(Ingredient.ofItems(Items.APPLE, Items.CARROT), Ingredient.ofItems(Items.STICK, Items.CARROT)); assertEquals(1, differenceIngredient.getMatchingStacks().size()); - assertEquals(Items.APPLE, differenceIngredient.getMatchingStacks().getFirst()); + assertEquals(Items.APPLE, differenceIngredient.getMatchingStacks().getFirst().value()); assertEquals(false, differenceIngredient.getMatchingStacks().isEmpty()); assertEquals(true, differenceIngredient.test(new ItemStack(Items.APPLE))); @@ -195,7 +195,8 @@ public class IngredientMatchTests { List> matchingStacks = customDataIngredient.getMatchingStacks(); assertEquals(1, matchingStacks.size()); assertEquals(Items.STICK, matchingStacks.getFirst().value()); - assertEquals(NbtComponent.of(requiredNbt), matchingStacks.getFirst().value().getDefaultStack().get(DataComponentTypes.CUSTOM_DATA)); + // Test disabled as the vanilla API no longer exposes the stack with data. + // assertEquals(NbtComponent.of(requiredNbt), matchingStacks.getFirst().value().getDefaultStack().get(DataComponentTypes.CUSTOM_DATA)); context.complete(); } diff --git a/fabric-recipe-api-v1/src/testmod/java/net/fabricmc/fabric/test/recipe/ingredient/SerializationTests.java b/fabric-recipe-api-v1/src/testmod/java/net/fabricmc/fabric/test/recipe/ingredient/SerializationTests.java index a7514cb6a..42b86d0d5 100644 --- a/fabric-recipe-api-v1/src/testmod/java/net/fabricmc/fabric/test/recipe/ingredient/SerializationTests.java +++ b/fabric-recipe-api-v1/src/testmod/java/net/fabricmc/fabric/test/recipe/ingredient/SerializationTests.java @@ -27,6 +27,7 @@ import com.mojang.serialization.JsonOps; import net.minecraft.item.Items; import net.minecraft.recipe.Ingredient; +import net.minecraft.registry.RegistryOps; import net.minecraft.test.GameTest; import net.minecraft.test.GameTestException; import net.minecraft.test.TestContext; @@ -71,17 +72,18 @@ public class SerializationTests { public void testCustomIngredientSerialization(TestContext context) { for (boolean allowEmpty : List.of(false, true)) { String ingredientJson = """ - {"ingredients":[{"item":"minecraft:stone"}],"fabric:type":"fabric:all"} + {"ingredients":["minecraft:stone"],"fabric:type":"fabric:all"} """.trim(); + RegistryOps registryOps = context.getWorld().getRegistryManager().getOps(JsonOps.INSTANCE); Ingredient ingredient = DefaultCustomIngredients.all( Ingredient.ofItems(Items.STONE) ); Codec ingredientCodec = Ingredient.CODEC; - JsonObject json = ingredientCodec.encodeStart(JsonOps.INSTANCE, ingredient).getOrThrow(IllegalStateException::new).getAsJsonObject(); + JsonObject json = ingredientCodec.encodeStart(registryOps, ingredient).getOrThrow(IllegalStateException::new).getAsJsonObject(); context.assertTrue(json.toString().equals(ingredientJson), "Unexpected json: " + json); // Make sure that we can deserialize it - Ingredient deserialized = ingredientCodec.parse(JsonOps.INSTANCE, json).getOrThrow(JsonParseException::new); + Ingredient deserialized = ingredientCodec.parse(registryOps, json).getOrThrow(JsonParseException::new); context.assertTrue(deserialized.getCustomIngredient() != null, "Custom ingredient was not deserialized"); context.assertTrue(deserialized.getCustomIngredient().getSerializer() == ingredient.getCustomIngredient().getSerializer(), "Serializer did not match"); }