Skip to content

Commit

Permalink
Forgify ingredient serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
Su5eD committed Aug 16, 2023
1 parent f8babf3 commit 94b0862
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 366 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -39,7 +43,7 @@ public interface CustomIngredientSerializer<T extends CustomIngredient> {
* @throws IllegalArgumentException if the serializer is already registered
*/
static void register(CustomIngredientSerializer<?> serializer) {
CustomIngredientImpl.registerSerializer(serializer);
CraftingHelper.register(serializer.getIdentifier(), new ForgeCustomIngredientSerializer(serializer));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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<Identifier, CustomIngredientSerializer<?>> 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
Expand Down Expand Up @@ -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<Identifier> 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();
Expand All @@ -130,6 +102,11 @@ public boolean isEmpty() {
return matchingStacks != null && matchingStacks.length == 0;
}

@Override
public IIngredientSerializer<? extends Ingredient> getSerializer() {
return getWrappedSerializer(this.customIngredient.getSerializer().getIdentifier());
}

private <T> T coerceIngredient() {
return (T) customIngredient;
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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<CustomIngredientImpl> {
private final CustomIngredientSerializer serializer;

public ForgeCustomIngredientSerializer(CustomIngredientSerializer serializer) {
this.serializer = serializer;
}

public <T extends CustomIngredient> CustomIngredientSerializer<T> unwrap() {
return (CustomIngredientSerializer<T>) 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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<Identifier> supportedCustomIngredients);
@Mixin(CraftingHelper.class)
public interface CraftingHelperAccessor {

@Accessor
static BiMap<Identifier, IIngredientSerializer<?>> getIngredients() {
throw new UnsupportedOperationException();
}
}
Loading

0 comments on commit 94b0862

Please sign in to comment.