Jump to content

[1.16.5] Invalid or unsupported recipe type


Recommended Posts

Trying to add custom crafting type. I'm most likely not registering it right. I get this exeption "Invalid or unsupported recipe type" twice when loading world.

Recipe JOSN:

Spoiler

{
  "type": "futurearmour:fabricating",
  "group": "futurearmour",
  "pattern": [
     "xx",
     " x ",
    "x  x",
     "x x"
  ],
  "key": {
    "x": {
      "item": "minecraft:coal"
    }
  },
  "result": {
    "item": "futurearmour:carbon_fiber"
  }
}

 

Recipe and Serializer:

Spoiler

package com.spu.futurearmour.content.recipes.fabricator;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import com.spu.futurearmour.content.tileentities.FabricatorControllerTileEntity;
import com.spu.futurearmour.setup.RecipeTypesRegistry;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.*;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.registries.ForgeRegistryEntry;

import javax.annotation.Nullable;
import java.util.Map;
import java.util.Set;

import static com.spu.futurearmour.setup.RecipeTypesRegistry.Types.FABRICATING;

public class FabricatorRecipe implements IRecipe<FabricatorControllerTileEntity> {
    private final IRecipeType<?> type;
    private final ItemStack result;
    private final NonNullList<Ingredient> ingredients;
    private final ResourceLocation id;
    private final String group;


    public FabricatorRecipe(ItemStack result, NonNullList<Ingredient> ingredients, ResourceLocation id, String group) {
        this.ingredients = ingredients;
        this.id = id;
        this.group = group;
        this.type = FABRICATING;
        this.result = result;
    }

    @Override
    public boolean matches(FabricatorControllerTileEntity controllerEntity, World world) {
        return false;
    }

    @Override
    public ItemStack assemble(FabricatorControllerTileEntity controllerEntity) {
        return null;
    }

    @Override
    public boolean canCraftInDimensions(int width, int height) {
        return true;
    }

    @Override
    public ItemStack getResultItem() {
        return result;
    }

    @Override
    public ResourceLocation getId() {
        return id;
    }

    @Override
    public IRecipeType<?> getType() {
        return type;
    }

    public static int getRowWidth(int row) {
        switch (row) {
            case 0:
                return 2;
            case 1:
                return 3;
            case 2:
                return 4;
            case 3:
                return 3;
            default:
                return 0;
        }
    }

    //region Serializer
    @Override
    public IRecipeSerializer<?> getSerializer() {
        return RecipeTypesRegistry.Serializers.FABRICATING.get();
    }

    private static Map<String, Ingredient> keysFromJson(JsonObject jsonObject) {
        Map<String, Ingredient> map = Maps.newHashMap();
        for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
            if (entry.getKey().length() != 1) {
                throw new JsonSyntaxException("Invalid key entry: '" + (String) entry.getKey() + "' is an invalid symbol (must be 1 character only).");
            }
            if (" ".equals(entry.getKey())) {
                throw new JsonSyntaxException("Invalid key entry: ' ' is a reserved symbol.");
            }
            map.put(entry.getKey(), Ingredient.fromJson(entry.getValue()));
        }
        map.put(" ", Ingredient.EMPTY);
        return map;
    }

    private static String[] patternFromJson(JsonArray jsonArray) {
        String[] pattern = new String[jsonArray.size()];
        if (pattern.length != 4) {
            throw new JsonSyntaxException("Invalid pattern: " + pattern.length + " rows instead of 4");
        } else {
            for (int i = 0; i < pattern.length; ++i) {
                String patternRow = JSONUtils.convertToString(jsonArray.get(i), "pattern[" + i + "]");
                if (patternRow.length() > getRowWidth(i)) {
                    throw new JsonSyntaxException("Invalid pattern: too many columns, " + getRowWidth(i) + " is maximum");
                }
                if (getRowWidth(i) != patternRow.length()) {
                    throw new JsonSyntaxException("Invalid pattern: row " + i + " has width " + patternRow.length() + "instead of " + getRowWidth(i));
                }
                pattern[i] = patternRow;
            }
            return pattern;
        }
    }

    private static NonNullList<Ingredient> dissolvePattern(String[] pattern, Map<String, Ingredient> ingredientMap) {
        NonNullList<Ingredient> result = NonNullList.withSize(12, Ingredient.EMPTY);
        Set<String> keys = Sets.newHashSet(ingredientMap.keySet());
        keys.remove(" ");

        for (int row = 0; row < pattern.length; row++) {
            for (int ch = 0; ch < pattern[row].length(); ch++) {
                String key = pattern[row].substring(ch, ch + 1);
                Ingredient ingredient = ingredientMap.get(key);
                if (ingredient == null) {
                    throw new JsonSyntaxException("Pattern references symbol '" + key + "' but it's not defined in the key");
                }

                keys.remove(key);
                result.set(ch + getRowWidth(row) * row, ingredient);
            }
        }

        if (!keys.isEmpty()) {
            throw new JsonSyntaxException("Key defines symbols that aren't used in pattern: " + keys);
        } else {
            return result;
        }
    }

    public static class Serializer extends ForgeRegistryEntry<IRecipeSerializer<?>> implements IRecipeSerializer<FabricatorRecipe> {

        @Override
        public FabricatorRecipe fromJson(ResourceLocation id, JsonObject jsonObject) {
            String group = JSONUtils.getAsString(jsonObject, "group", "");
            Map<String, Ingredient> ingredientMap = keysFromJson(JSONUtils.getAsJsonObject(jsonObject, "key"));
            String[] pattern = patternFromJson(JSONUtils.getAsJsonArray(jsonObject, "pattern"));
            NonNullList<Ingredient> ingredients = dissolvePattern(pattern, ingredientMap);
            ItemStack result = ShapedRecipe.itemFromJson(JSONUtils.getAsJsonObject(jsonObject, "result"));
            return new FabricatorRecipe(result, ingredients, id, group);
        }

        @Nullable
        @Override
        public FabricatorRecipe fromNetwork(ResourceLocation id, PacketBuffer packetBuffer) {
            String group = packetBuffer.readUtf(32767);
            NonNullList<Ingredient> ingredients = NonNullList.withSize(12, Ingredient.EMPTY);

            for(int k = 0; k < ingredients.size(); ++k) {
                ingredients.set(k, Ingredient.fromNetwork(packetBuffer));
            }

            ItemStack result = packetBuffer.readItem();
            return new FabricatorRecipe(result, ingredients, id, group);
        }

        @Override
        public void toNetwork(PacketBuffer packetBuffer, FabricatorRecipe recipe) {
            packetBuffer.writeUtf(recipe.group);

            for(Ingredient ingredient : recipe.ingredients) {
                ingredient.toNetwork(packetBuffer);
            }

            packetBuffer.writeItem(recipe.result);
        }
    }
    //endregion
}

 

Mod main class:

Spoiler

package com.spu.futurearmour;

import com.spu.futurearmour.setup.*;
import com.spu.futurearmour.content.world.OreGeneration;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

@Mod(FutureArmour.MOD_ID)
public class FutureArmour
{
    public static final String MOD_ID = "futurearmour";

    private static final Logger LOGGER = LogManager.getLogger();

    public static final CreativeItemTab ITEM_GROUP = new CreativeItemTab();

    public FutureArmour() {
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);

        Registration.register();

        MinecraftForge.EVENT_BUS.addListener(EventPriority.HIGH, OreGeneration::generateOres);

        MinecraftForge.EVENT_BUS.register(this);

        final IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
        final ClientSideOnlyModEventRegistry clientSideOnlyModEventRegistry = new ClientSideOnlyModEventRegistry(modEventBus);
        final ServerSideOnlyModEventRegistry serverSideOnlyModEventRegistry = new ServerSideOnlyModEventRegistry(modEventBus);

        registerCommonEvents(modEventBus);
        DistExecutor.safeRunWhenOn(Dist.CLIENT, () -> clientSideOnlyModEventRegistry::registerClientOnlyEvents);
        DistExecutor.safeRunWhenOn(Dist.DEDICATED_SERVER, () -> serverSideOnlyModEventRegistry::registerServerOnlyEvents);
    }

    private void registerCommonEvents(IEventBus eventBus){

    }

    private void setup(final FMLCommonSetupEvent event){

    }

    @OnlyIn(Dist.CLIENT)
    private void doClientStuff(final FMLClientSetupEvent event) {
        Registration.registerClientOnly(event);
        RenderTypeLookup.setRenderLayer(BlockRegistry.FABRICATOR_CONTROLLER_BLOCK.get(), RenderType.translucent());
    }
}

 

Registration:

Spoiler

package com.spu.futurearmour.setup;

import com.spu.futurearmour.content.ModItemModelsProperties;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;

public class Registration {
    public static void register(){
        ModBlockStateProperties.register();
        BlockRegistry.register();
        ContainerTypeRegistry.register();
        TileEntityTypeRegistry.register();
        ItemRegistry.register();
        RecipeTypesRegistry.register();
    }

    public static void registerClientOnly(FMLClientSetupEvent event){
        ModItemModelsProperties.register();
        ContainerTypeRegistry.registerScreens(event);
    }
}

 

Spoiler

package com.spu.futurearmour.setup;

import com.spu.futurearmour.FutureArmour;
import com.spu.futurearmour.content.recipes.fabricator.FabricatorRecipe;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.IRecipeSerializer;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.function.Supplier;

public final class RecipeTypesRegistry {
    public static void register() {
        Types.register();
        Serializers.register();
    }

    public static final DeferredRegister<IRecipeSerializer<?>> RECIPE_SERIALIZER_TYPES =
            DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, FutureArmour.MOD_ID);

    public static final class Types {
        public static final IRecipeType<FabricatorRecipe> FABRICATING =
                IRecipeType.register(FutureArmour.MOD_ID + ":fabricating");
        public static void register() {
        }
    }

    public static final class Serializers {
        public static final RegistryObject<IRecipeSerializer<FabricatorRecipe>> FABRICATING =
                register("fabricating", FabricatorRecipe.Serializer::new);

        private static <T extends IRecipe<?>> RegistryObject<IRecipeSerializer<T>> register(String name, Supplier<IRecipeSerializer<T>> serializer) {
            return RECIPE_SERIALIZER_TYPES.register(name, serializer);
        }

        public static void register() {
        }
    }

    private static Logger LOGGER = LogManager.getLogger();
}

 

I'd be grateful for any suggestions you might have. Thanks in advance

Link to comment
Share on other sites

4 minutes ago, diesieben07 said:

Do not put the RegistryObject in a separate class from their DeferredRegister. Mainly do not use all those nested classes.

changed the registration part to this, still get the same exception

package com.spu.futurearmour.setup;

import com.spu.futurearmour.FutureArmour;
import com.spu.futurearmour.content.recipes.fabricator.FabricatorRecipe;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.IRecipeSerializer;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.function.Supplier;

public final class RecipeTypesRegistry {
    public static void register() {
    }

    public static final DeferredRegister<IRecipeSerializer<?>> RECIPE_SERIALIZER_TYPES =
            DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, FutureArmour.MOD_ID);

        public static final IRecipeType<FabricatorRecipe> FABRICATING =
                IRecipeType.register(FutureArmour.MOD_ID + ":fabricating");

        public static final RegistryObject<IRecipeSerializer<FabricatorRecipe>> FABRICATING_SERIALIZER =
                register("fabricating", FabricatorRecipe.Serializer::new);

        private static <T extends IRecipe<?>> RegistryObject<IRecipeSerializer<T>> register(String name, Supplier<IRecipeSerializer<T>> serializer) {
            return RECIPE_SERIALIZER_TYPES.register(name, serializer);
        }

    private static Logger LOGGER = LogManager.getLogger();
}

 

Link to comment
Share on other sites

9 minutes ago, diesieben07 said:

Where do you register your DeferredRegisters? Why do you have all these empty registrer methods?

I use empty register methods to classload all my registry classes

The DefferedRegisters are registered in the constructor of mod's main class
Registration.register();

@Mod(FutureArmour.MOD_ID)
public class FutureArmour
{
    public static final String MOD_ID = "futurearmour";

    private static final Logger LOGGER = LogManager.getLogger();

    public static final CreativeItemTab ITEM_GROUP = new CreativeItemTab();

    public FutureArmour() {
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);

        Registration.register();

        MinecraftForge.EVENT_BUS.addListener(EventPriority.HIGH, OreGeneration::generateOres);

        MinecraftForge.EVENT_BUS.register(this);
    }

 

Edited by SomeDudeOnTheInternet
Link to comment
Share on other sites

3 minutes ago, diesieben07 said:

Registryation.register calls a bunch of other register methods. You have shown one of them and it is empty and as such accomplishes nothing. Why do you have these empty methods?

From what I understand, referencing the classes in this way should class load them. If it is not a valid way to do it, please tell me.

Edited by SomeDudeOnTheInternet
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.