From 94b0862222e5ed8180552e9d0b17b229776efdcd Mon Sep 17 00:00:00 2001 From: Su5eD Date: Wed, 16 Aug 2023 21:58:45 +0200 Subject: [PATCH] Forgify ingredient serialization --- .../client/CustomIngredientSyncClient.java | 36 ------ .../CustomIngredientSerializer.java | 6 +- .../ingredient/CustomIngredientImpl.java | 59 +++------- .../ingredient/CustomIngredientSync.java | 103 ------------------ .../ForgeCustomIngredientSerializer.java | 53 +++++++++ .../impl/recipe/ingredient/RecipesImpl.java | 18 +-- .../ingredient/CraftingHelperAccessor.java} | 22 ++-- .../ingredient/CraftingHelperMixin.java | 61 +++++++++++ .../recipe/ingredient/IngredientMixin.java | 91 +--------------- .../recipe/ingredient/PacketEncoderMixin.java | 77 ------------- .../fabric-recipe-api-v1.mixins.json | 3 +- gradle.properties | 2 +- 12 files changed, 165 insertions(+), 366 deletions(-) delete mode 100644 fabric-recipe-api-v1/src/client/java/net/fabricmc/fabric/impl/recipe/ingredient/client/CustomIngredientSyncClient.java delete mode 100644 fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientSync.java create mode 100644 fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/ForgeCustomIngredientSerializer.java rename fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/{impl/recipe/ingredient/SupportedIngredientsPacketEncoder.java => mixin/recipe/ingredient/CraftingHelperAccessor.java} (55%) create mode 100644 fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/CraftingHelperMixin.java delete mode 100644 fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/PacketEncoderMixin.java diff --git a/fabric-recipe-api-v1/src/client/java/net/fabricmc/fabric/impl/recipe/ingredient/client/CustomIngredientSyncClient.java b/fabric-recipe-api-v1/src/client/java/net/fabricmc/fabric/impl/recipe/ingredient/client/CustomIngredientSyncClient.java deleted file mode 100644 index ad022277a..000000000 --- a/fabric-recipe-api-v1/src/client/java/net/fabricmc/fabric/impl/recipe/ingredient/client/CustomIngredientSyncClient.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.fabric.impl.recipe.ingredient.client; - -import java.util.concurrent.CompletableFuture; - -import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking; -import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientSync; - -/** - * @see CustomIngredientSync - */ -public class CustomIngredientSyncClient { - - public static void onInitializeClient() { - ClientLoginNetworking.registerGlobalReceiver(CustomIngredientSync.PACKET_ID, (client, handler, buf, listenerAdder) -> { - int protocolVersion = buf.readVarInt(); - - return CompletableFuture.completedFuture(CustomIngredientSync.createResponsePacket(protocolVersion)); - }); - } -} diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/api/recipe/v1/ingredient/CustomIngredientSerializer.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/api/recipe/v1/ingredient/CustomIngredientSerializer.java index 7f419bb7d..b0ad2d5c8 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/api/recipe/v1/ingredient/CustomIngredientSerializer.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/api/recipe/v1/ingredient/CustomIngredientSerializer.java @@ -18,6 +18,10 @@ import com.google.gson.JsonObject; import com.google.gson.JsonSyntaxException; + +import net.fabricmc.fabric.impl.recipe.ingredient.ForgeCustomIngredientSerializer; + +import net.minecraftforge.common.crafting.CraftingHelper; import org.jetbrains.annotations.Nullable; import net.minecraft.network.PacketByteBuf; @@ -39,7 +43,7 @@ public interface CustomIngredientSerializer { * @throws IllegalArgumentException if the serializer is already registered */ static void register(CustomIngredientSerializer serializer) { - CustomIngredientImpl.registerSerializer(serializer); + CraftingHelper.register(serializer.getIdentifier(), new ForgeCustomIngredientSerializer(serializer)); } /** diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientImpl.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientImpl.java index 3f18e6c88..35ec6d587 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientImpl.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientImpl.java @@ -16,23 +16,19 @@ package net.fabricmc.fabric.impl.recipe.ingredient; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Stream; - import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import org.jetbrains.annotations.Nullable; - +import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredient; +import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer; +import net.fabricmc.fabric.mixin.recipe.ingredient.CraftingHelperAccessor; import net.minecraft.item.ItemStack; -import net.minecraft.network.PacketByteBuf; import net.minecraft.recipe.Ingredient; import net.minecraft.util.Identifier; +import net.minecraftforge.common.crafting.IIngredientSerializer; +import org.jetbrains.annotations.Nullable; -import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredient; -import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer; +import java.util.Objects; +import java.util.stream.Stream; /** * To test this API beyond the unit tests, please refer to the recipe provider in the datagen API testmod. @@ -42,24 +38,18 @@ public class CustomIngredientImpl extends Ingredient { // Static helpers used by the API public static final String TYPE_KEY = "fabric:type"; - // Use a random constant number instead of -1 to avoid conflicts with Forge's own custom ingredient deserializer - public static final int PACKET_MARKER = -22; - static final Map> REGISTERED_SERIALIZERS = new ConcurrentHashMap<>(); - - public static void registerSerializer(CustomIngredientSerializer serializer) { - Objects.requireNonNull(serializer.getIdentifier(), "CustomIngredientSerializer identifier may not be null."); - - if (REGISTERED_SERIALIZERS.putIfAbsent(serializer.getIdentifier(), serializer) != null) { - throw new IllegalArgumentException("CustomIngredientSerializer with identifier " + serializer.getIdentifier() + " already registered."); - } + @Nullable + public static CustomIngredientSerializer getSerializer(Identifier identifier) { + IIngredientSerializer serializer = getWrappedSerializer(identifier); + return serializer instanceof ForgeCustomIngredientSerializer customSerializer ? customSerializer.unwrap() : null; } @Nullable - public static CustomIngredientSerializer getSerializer(Identifier identifier) { + public static IIngredientSerializer getWrappedSerializer(Identifier identifier) { Objects.requireNonNull(identifier, "Identifier may not be null."); - return REGISTERED_SERIALIZERS.get(identifier); + return CraftingHelperAccessor.getIngredients().get(identifier); } // Actual custom ingredient logic @@ -96,24 +86,6 @@ public boolean test(@Nullable ItemStack stack) { return stack != null && customIngredient.test(stack); } - // FFAPI: Injected via mixin into Ingredient.toNetwork - public void fabric_toNetwork(PacketByteBuf buf) { - // Can be null if we're not writing a packet from the PacketEncoder; in that case, always write the full ingredient. - // Chances are this is a mod's doing and the client has the Ingredient API with the relevant ingredients. - Set supportedIngredients = CustomIngredientSync.CURRENT_SUPPORTED_INGREDIENTS.get(); - - if (supportedIngredients != null && !supportedIngredients.contains(customIngredient.getSerializer().getIdentifier())) { - // The client doesn't support this custom ingredient, so we send the matching stacks as a regular ingredient. - // Conveniently, this is exactly what the super call does. - super.write(buf); - } else { - // The client supports this custom ingredient, so we send it as a custom ingredient. - buf.writeVarInt(PACKET_MARKER); - buf.writeIdentifier(customIngredient.getSerializer().getIdentifier()); - customIngredient.getSerializer().write(buf, coerceIngredient()); - } - } - @Override public JsonElement toJson() { JsonObject json = new JsonObject(); @@ -130,6 +102,11 @@ public boolean isEmpty() { return matchingStacks != null && matchingStacks.length == 0; } + @Override + public IIngredientSerializer getSerializer() { + return getWrappedSerializer(this.customIngredient.getSerializer().getIdentifier()); + } + private T coerceIngredient() { return (T) customIngredient; } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientSync.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientSync.java deleted file mode 100644 index d92ad1c7a..000000000 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/CustomIngredientSync.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.fabric.impl.recipe.ingredient; - -import java.util.HashSet; -import java.util.Set; - -import io.netty.channel.ChannelHandler; -import org.jetbrains.annotations.Nullable; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketEncoder; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; -import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents; -import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking; -import net.fabricmc.fabric.mixin.recipe.ingredient.PacketEncoderMixin; - -/** - * To reasonably support server-side only custom ingredients, we only send custom ingredients to clients that support them. - * If a specific client doesn't support a custom ingredient, we send the matching stacks as a regular ingredient. - * This is fine since all recipe computation happens server-side anyway. - * - *

    - *
  • Each client sends a packet with the set of custom ingredients it supports.
  • - *
  • We store that set inside the {@link PacketEncoder} using {@link PacketEncoderMixin}.
  • - *
  • When serializing a custom ingredient, we get access to the current {@link PacketEncoder}, - * and based on that we decide whether to send the custom ingredient, or a vanilla ingredient with the matching stacks.
  • - *
- */ -public class CustomIngredientSync { - public static final Identifier PACKET_ID = new Identifier("fabric", "custom_ingredient_sync"); - public static final int PROTOCOL_VERSION_1 = 1; - public static final ThreadLocal> CURRENT_SUPPORTED_INGREDIENTS = new ThreadLocal<>(); - - @Nullable - public static PacketByteBuf createResponsePacket(int serverProtocolVersion) { - if (serverProtocolVersion < PROTOCOL_VERSION_1) { - // Not supposed to happen - notify the server that we didn't understand the query. - return null; - } - - // Always send protocol 1 - the server should support it even if it supports more recent protocols. - PacketByteBuf buf = PacketByteBufs.create(); - buf.writeVarInt(PROTOCOL_VERSION_1); - buf.writeCollection(CustomIngredientImpl.REGISTERED_SERIALIZERS.keySet(), PacketByteBuf::writeIdentifier); - return buf; - } - - public static Set decodeResponsePacket(PacketByteBuf buf) { - int protocolVersion = buf.readVarInt(); - - switch (protocolVersion) { - case PROTOCOL_VERSION_1 -> { - Set identifiers = buf.readCollection(HashSet::new, PacketByteBuf::readIdentifier); - // Remove unknown keys to save memory - identifiers.removeIf(id -> !CustomIngredientImpl.REGISTERED_SERIALIZERS.containsKey(id)); - return identifiers; - } - default -> { - throw new IllegalArgumentException("Unknown ingredient sync protocol version: " + protocolVersion); - } - } - } - - public static void onInitialize() { - ServerLoginConnectionEvents.QUERY_START.register((handler, server, sender, synchronizer) -> { - // Send packet with 1 so the client can send us back the list of supported tags. - // 1 is sent in case we need a different protocol later for some reason. - PacketByteBuf buf = PacketByteBufs.create(); - buf.writeVarInt(PROTOCOL_VERSION_1); // max supported server protocol version - sender.sendPacket(PACKET_ID, buf); - }); - ServerLoginNetworking.registerGlobalReceiver(PACKET_ID, (server, handler, understood, buf, synchronizer, responseSender) -> { - if (!understood) { - // Skip if the client didn't understand the query. - return; - } - - Set supportedCustomIngredients = decodeResponsePacket(buf); - ChannelHandler packetEncoder = handler.connection.channel.pipeline().get("encoder"); - - if (packetEncoder != null) { // Null in singleplayer - ((SupportedIngredientsPacketEncoder) packetEncoder).fabric_setSupportedCustomIngredients(supportedCustomIngredients); - } - }); - } -} diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/ForgeCustomIngredientSerializer.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/ForgeCustomIngredientSerializer.java new file mode 100644 index 000000000..9c0f78d22 --- /dev/null +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/ForgeCustomIngredientSerializer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.recipe.ingredient; + +import com.google.gson.JsonObject; +import net.minecraftforge.common.crafting.IIngredientSerializer; + +import net.minecraft.network.PacketByteBuf; + +import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredient; +import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer; + +@SuppressWarnings({"rawtypes", "unchecked"}) +public class ForgeCustomIngredientSerializer implements IIngredientSerializer { + private final CustomIngredientSerializer serializer; + + public ForgeCustomIngredientSerializer(CustomIngredientSerializer serializer) { + this.serializer = serializer; + } + + public CustomIngredientSerializer unwrap() { + return (CustomIngredientSerializer) this.serializer; + } + + @Override + public CustomIngredientImpl parse(PacketByteBuf buf) { + return (CustomIngredientImpl) this.serializer.read(buf).toVanilla(); + } + + @Override + public CustomIngredientImpl parse(JsonObject json) { + return (CustomIngredientImpl) this.serializer.read(json).toVanilla(); + } + + @Override + public void write(PacketByteBuf buf, CustomIngredientImpl ingredient) { + this.serializer.write(buf, ingredient.getCustomIngredient()); + } +} diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/RecipesImpl.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/RecipesImpl.java index c63cdfa4e..b4c1a8ab2 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/RecipesImpl.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/RecipesImpl.java @@ -16,20 +16,20 @@ package net.fabricmc.fabric.impl.recipe.ingredient; -import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.loading.FMLLoader; - -import net.fabricmc.fabric.impl.recipe.ingredient.client.CustomIngredientSyncClient; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @Mod("fabric_recipe_api_v1") public class RecipesImpl { public RecipesImpl() { - if (FMLLoader.getDist() == Dist.CLIENT) { - CustomIngredientSyncClient.onInitializeClient(); - } - CustomIngredientInit.onInitialize(); - CustomIngredientSync.onInitialize(); + IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); + bus.addListener(RecipesImpl::registerRecipeSerializers); + } + + private static void registerRecipeSerializers(FMLCommonSetupEvent event) { + event.enqueueWork(CustomIngredientInit::onInitialize); } } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/SupportedIngredientsPacketEncoder.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/CraftingHelperAccessor.java similarity index 55% rename from fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/SupportedIngredientsPacketEncoder.java rename to fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/CraftingHelperAccessor.java index c5de3e860..b9efcf3b1 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/impl/recipe/ingredient/SupportedIngredientsPacketEncoder.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/CraftingHelperAccessor.java @@ -14,16 +14,20 @@ * limitations under the License. */ -package net.fabricmc.fabric.impl.recipe.ingredient; +package net.fabricmc.fabric.mixin.recipe.ingredient; -import java.util.Set; - -import net.minecraft.network.PacketEncoder; +import com.google.common.collect.BiMap; import net.minecraft.util.Identifier; +import net.minecraftforge.common.crafting.CraftingHelper; +import net.minecraftforge.common.crafting.IIngredientSerializer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; -/** - * Implemented on {@link PacketEncoder} to store which custom ingredients the client supports. - */ -public interface SupportedIngredientsPacketEncoder { - void fabric_setSupportedCustomIngredients(Set supportedCustomIngredients); +@Mixin(CraftingHelper.class) +public interface CraftingHelperAccessor { + + @Accessor + static BiMap> getIngredients() { + throw new UnsupportedOperationException(); + } } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/CraftingHelperMixin.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/CraftingHelperMixin.java new file mode 100644 index 000000000..0112ce884 --- /dev/null +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/CraftingHelperMixin.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.recipe.ingredient; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientImpl; +import net.minecraft.recipe.Ingredient; +import net.minecraft.util.JsonHelper; +import net.minecraftforge.common.crafting.CraftingHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +@Mixin(CraftingHelper.class) +public class CraftingHelperMixin { + @Unique + private static final ThreadLocal FABRIC_JSON_ARRAY_DESERIALIZATION = ThreadLocal.withInitial(() -> false); + + @Inject(method = "lambda$getIngredient$0", at = @At("HEAD")) + private static void beforeJsonArrayDeserialize(boolean allowEmpty, List vanilla, List ingredients, JsonElement ele, CallbackInfo ci) { + FABRIC_JSON_ARRAY_DESERIALIZATION.set(true); + } + + @Inject(method = "lambda$getIngredient$0", at = @At("TAIL")) + private static void afterJsonArrayDeserialize(boolean allowEmpty, List vanilla, List ingredients, JsonElement ele, CallbackInfo ci) { + FABRIC_JSON_ARRAY_DESERIALIZATION.set(false); + } + + @Redirect(method = "getIngredient(Lcom/google/gson/JsonElement;Z)Lnet/minecraft/recipe/Ingredient;", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/JsonHelper;getString(Lcom/google/gson/JsonObject;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"), remap = false) + private static String modifyIngredientTypeValue(JsonObject object, String element, String defaultStr) { + if (object.has(CustomIngredientImpl.TYPE_KEY)) { + // Throw exception when someone attempts to use our custom key inside an array ingredient. + // The {@link AnyIngredient} should be used instead. + if (FABRIC_JSON_ARRAY_DESERIALIZATION.get()) { + throw new IllegalArgumentException("Custom ingredient cannot be used inside an array ingredient. You can replace the array by a fabric:any ingredient."); + } + element = CustomIngredientImpl.TYPE_KEY; + } + return JsonHelper.getString(object, element, defaultStr); + } +} diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/IngredientMixin.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/IngredientMixin.java index d2c60712e..a9a48cac9 100644 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/IngredientMixin.java +++ b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/IngredientMixin.java @@ -16,96 +16,11 @@ package net.fabricmc.fabric.mixin.recipe.ingredient; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -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.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.recipe.Ingredient; -import net.minecraft.util.Identifier; -import net.minecraft.util.JsonHelper; - -import net.fabricmc.fabric.api.recipe.v1.ingredient.CustomIngredientSerializer; import net.fabricmc.fabric.api.recipe.v1.ingredient.FabricIngredient; -import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientImpl; -import net.fabricmc.fabric.impl.recipe.ingredient.builtin.AnyIngredient; +import net.minecraft.recipe.Ingredient; +import org.spongepowered.asm.mixin.Mixin; @Mixin(Ingredient.class) public class IngredientMixin implements FabricIngredient { - /** - * Inject right when vanilla detected a json object and check for our custom key. - * - * @implNote FFAPI: Inject before forge checks for its ingredient serializers. - */ - @Inject( - at = @At( - value = "INVOKE", - target = "Lnet/minecraftforge/common/crafting/CraftingHelper;getIngredient(Lcom/google/gson/JsonElement;Z)Lnet/minecraft/recipe/Ingredient;", - ordinal = 0 - ), - method = "fromJson(Lcom/google/gson/JsonElement;Z)Lnet/minecraft/recipe/Ingredient;", - cancellable = true - ) - private static void injectFromJson(JsonElement json, boolean requireNotEmpty, CallbackInfoReturnable cir) { - if (!json.isJsonObject()) return; - - JsonObject obj = json.getAsJsonObject(); - - if (obj.has(CustomIngredientImpl.TYPE_KEY)) { - Identifier id = new Identifier(JsonHelper.getString(obj, CustomIngredientImpl.TYPE_KEY)); - CustomIngredientSerializer serializer = CustomIngredientSerializer.get(id); - - if (serializer != null) { - cir.setReturnValue(serializer.read(obj).toVanilla()); - } else { - throw new IllegalArgumentException("Unknown custom ingredient type: " + id); - } - } - } - - /** - * Throw exception when someone attempts to use our custom key inside an array ingredient. - * The {@link AnyIngredient} should be used instead. - */ - @Inject(at = @At("HEAD"), method = "entryFromJson") - private static void injectEntryFromJson(JsonObject obj, CallbackInfoReturnable cir) { - if (obj.has(CustomIngredientImpl.TYPE_KEY)) { - throw new IllegalArgumentException("Custom ingredient cannot be used inside an array ingredient. You can replace the array by a fabric:any ingredient."); - } - } - - @Inject( - at = @At("HEAD"), - method = "fromPacket", - cancellable = true - ) - private static void injectFromPacket(PacketByteBuf buf, CallbackInfoReturnable cir) { - int index = buf.readerIndex(); - - if (buf.readVarInt() == CustomIngredientImpl.PACKET_MARKER) { - Identifier type = buf.readIdentifier(); - CustomIngredientSerializer serializer = CustomIngredientSerializer.get(type); - - if (serializer == null) { - throw new IllegalArgumentException("Cannot deserialize custom ingredient of unknown type " + type); - } - - cir.setReturnValue(serializer.read(buf).toVanilla()); - } else { - // Reset index for vanilla's normal deserialization logic. - buf.readerIndex(index); - } - } - - @Inject(method = "write", at = @At("HEAD"), cancellable = true) - private void injectToNetwork(PacketByteBuf buf, CallbackInfo ci) { - if ((Ingredient) (Object) this instanceof CustomIngredientImpl customIngredient) { - customIngredient.fabric_toNetwork(buf); - ci.cancel(); - } - } + } diff --git a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/PacketEncoderMixin.java b/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/PacketEncoderMixin.java deleted file mode 100644 index 50d277607..000000000 --- a/fabric-recipe-api-v1/src/main/java/net/fabricmc/fabric/mixin/recipe/ingredient/PacketEncoderMixin.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018, 2019 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.fabric.mixin.recipe.ingredient; - -import java.util.Set; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.minecraft.network.packet.Packet; -import net.minecraft.network.PacketEncoder; -import net.minecraft.util.Identifier; - -import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientSync; -import net.fabricmc.fabric.impl.recipe.ingredient.SupportedIngredientsPacketEncoder; - -@Mixin(PacketEncoder.class) -public class PacketEncoderMixin implements SupportedIngredientsPacketEncoder { - @Unique - private Set fabric_supportedCustomIngredients = Set.of(); - - @Override - public void fabric_setSupportedCustomIngredients(Set supportedCustomIngredients) { - fabric_supportedCustomIngredients = supportedCustomIngredients; - } - - @Inject( - at = @At( - value = "INVOKE", - target = "net/minecraft/network/packet/Packet.write(Lnet/minecraft/network/PacketByteBuf;)V" - ), - method = "encode(Lio/netty/channel/ChannelHandlerContext;Lnet/minecraft/network/packet/Packet;Lio/netty/buffer/ByteBuf;)V" - ) - private void capturePacketEncoder(ChannelHandlerContext channelHandlerContext, Packet packet, ByteBuf byteBuf, CallbackInfo ci) { - CustomIngredientSync.CURRENT_SUPPORTED_INGREDIENTS.set(fabric_supportedCustomIngredients); - } - - @Inject( - at = { - // Normal target after writing - @At( - value = "INVOKE", - target = "net/minecraft/network/packet/Packet.write(Lnet/minecraft/network/PacketByteBuf;)V", - shift = At.Shift.AFTER, - by = 1 - ), - // In the catch handler in case some exception was thrown - @At( - value = "INVOKE", - target = "net/minecraft/network/packet/Packet.isWritingErrorSkippable()Z" - ) - }, - method = "encode(Lio/netty/channel/ChannelHandlerContext;Lnet/minecraft/network/packet/Packet;Lio/netty/buffer/ByteBuf;)V" - ) - private void releasePacketEncoder(ChannelHandlerContext channelHandlerContext, Packet packet, ByteBuf byteBuf, CallbackInfo ci) { - CustomIngredientSync.CURRENT_SUPPORTED_INGREDIENTS.set(null); - } -} diff --git a/fabric-recipe-api-v1/src/main/resources/fabric-recipe-api-v1.mixins.json b/fabric-recipe-api-v1/src/main/resources/fabric-recipe-api-v1.mixins.json index 1c405ec82..a8ba37a97 100644 --- a/fabric-recipe-api-v1/src/main/resources/fabric-recipe-api-v1.mixins.json +++ b/fabric-recipe-api-v1/src/main/resources/fabric-recipe-api-v1.mixins.json @@ -3,8 +3,9 @@ "package": "net.fabricmc.fabric.mixin.recipe", "compatibilityLevel": "JAVA_17", "mixins": [ + "ingredient.CraftingHelperAccessor", + "ingredient.CraftingHelperMixin", "ingredient.IngredientMixin", - "ingredient.PacketEncoderMixin", "ingredient.ShapelessRecipeMixin" ], "injectors": { diff --git a/gradle.properties b/gradle.properties index b0e4df860..5b67fd83a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -67,5 +67,5 @@ fabric-client-tags-api-v1-version=1.1.1 loom.platform=forge forge_version=1.20.1-47.1.3 pack_format=15 -forgified_version=1.8.6 +forgified_version=1.9.0 forge_fabric_loader_version=2.2.1+0.14.21+1.20.1