Jump to content

[1.16.5] Help with Furnace Container/Recipe


Luis_ST

Recommended Posts

i just creat a block which is called smelting furnace it should be a faster furnace for the default smelting recipes (like stone, clay, etc.).

At the moment the block has the normal furnace container and the normal recipes and i try to creat custom (container and recipe), but now im stuck.

1. registration of container:

- i creat a container which extends the vanilla AbstractFurnaceContainer

	public static final DeferredRegister<ContainerType<?>> CONTAINERS = DeferredRegister.create(ForgeRegistries.CONTAINERS, Cave.Mod_Id);
	
	
	public static final RegistryObject<ContainerType<?>> SMELTING_CONTAINER = CONTAINERS.register("smelting_container", 
			() -> IForgeContainerType.create(SmeltingContainer::new));

but i cant register the container/ why doesn't work that way

 

2. registration of recipe serializer

- how to register a custom AbstractCookingRecipe and how to create form that a IRecipeType which i need for the container

	public static final DeferredRegister<IRecipeSerializer<?>> RECIPE_SERIALIZERS = DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, Cave.Mod_Id);
	
	
	public static final RegistryObject<IRecipeSerializer<?>> SMELTING_RECIPE = RECIPE_SERIALIZERS.register("smelting_recipe", null);

what i have to set at "null"

Link to comment
Share on other sites

17 minutes ago, diesieben07 said:

If you want it to use the normal furnace recipes, why are you making a custom serializer

i not want to use the normal recipes that already work but minecraft has the blast furnace which smelt ores and the smoker which "cook" food.

i want to creat a furnace which process / smelt the other recipes faster (like cobblestone to stone in 5 seconds instead of 10 seconds)

Edited by Luis_ST
Link to comment
Share on other sites

27 minutes ago, diesieben07 said:

So you want it to use the normal furnace recipes, not the smoker recipes for example - yes?

normal furnace - No.

I think you don't understand exactly what I want,

so simplified I want recipes for a custom furnace with the same gui like the vanilla furnace

 

Short: I want custom recipes that only work in my furnace

Edited by Luis_ST
Link to comment
Share on other sites

But back to my questions

3 hours ago, Luis_ST said:

1. registration of container:

- i creat a container which extends the vanilla AbstractFurnaceContainer

 

3 hours ago, Luis_ST said:

2. registration of recipe serializer

- how to register a custom AbstractCookingRecipe and how to create form that a IRecipeType which i need for the container

 

 

Edited by Luis_ST
Link to comment
Share on other sites

15 minutes ago, diesieben07 said:

You can register your own IRecipeType in the same way vanilla does (look at IRecipeType).

To use your custom recipe type, you need to also implement IRecipeSerializer and return recipes that use your custom IRecipeType.

Okay thanks, but the more important question is how to properly register the container and recipe because that's the reason why i ask?

	public static final DeferredRegister<ContainerType<?>> CONTAINERS = DeferredRegister.create(ForgeRegistries.CONTAINERS, Cave.Mod_Id);
	
	
	public static final RegistryObject<ContainerType<?>> SMELTING_CONTAINER = CONTAINERS.register("smelting_container", 
			() -> IForgeContainerType.create(null));

and

	public static final DeferredRegister<IRecipeSerializer<?>> RECIPE_SERIALIZERS = DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, Cave.Mod_Id);
	
	
	public static final RegistryObject<IRecipeSerializer<?>> SMELTING_RECIPE = RECIPE_SERIALIZERS.register("smelting_recipe", null);

 

Link to comment
Share on other sites

15 hours ago, diesieben07 said:

What is your question?

 

18 hours ago, Luis_ST said:

1. registration of container:

- i creat a container which extends the vanilla AbstractFurnaceContainer

but i cant register the container/ why doesn't work that way

and

18 hours ago, Luis_ST said:

how to register a custom AbstractCookingRecipe

for more information just read my post at the beginning

 

 

 

 

 

Link to comment
Share on other sites

32 minutes ago, diesieben07 said:

Why can't you? What is your issue?

my IDE show this error: "The type SmeltingContainer does not define SmeltingContainer(int, PlayerInventory, PacketBuffer) that is applicable here"

this is my container class:

https://github.com/Luis-st/Forge-1.16.5-36.0.1-mdk/blob/main/forge-1.16.5-36.0.1-mdk/src/main/java/net/luis/cave/blocks/container/SmeltingContainer.java

 

38 minutes ago, diesieben07 said:

Recipes do not need to be registered. You register a recipe type and a recipe serializer.

i mean the recipe serializer

this is my registration class:

https://github.com/Luis-st/Forge-1.16.5-36.0.1-mdk/blob/main/forge-1.16.5-36.0.1-mdk/src/main/java/net/luis/cave/init/CaveRecipe.java

and my recipe serializer class:

https://github.com/Luis-st/Forge-1.16.5-36.0.1-mdk/blob/b55bad37a4e156a1cbc7979697809e027e3a4589/forge-1.16.5-36.0.1-mdk/src/main/java/net/luis/cave/blocks/recipes/SmeltingRecipe.java#L12

 

41 minutes ago, diesieben07 said:

Your recipe serializer...

like this:

public static final RegistryObject<IRecipeSerializer<?>> SMELTING_RECIPE = RECIPE_SERIALIZERS.register("smelting_recipe", SmeltingRecipe::new);

but i get the same error: "The type SmeltingRecipe does not define SmeltingRecipe() that is applicable here"

 

So what am I doing wrong / where is the mistake

Link to comment
Share on other sites

1 hour ago, diesieben07 said:

You need to provide a method reference or lambda with the correct signature (look at IForgeContainerType.create to find out what is needed).

I found. I had to add a Packetbuffer i don't know what i need it for but the container works.

 

1 hour ago, diesieben07 said:

You need to specify your serializer. Your recipe class constructor is not useful here.

but how to get the serializer

Link to comment
Share on other sites

23 minutes ago, diesieben07 said:

You make a class for it...

So do I have to create another class for the serializer even if I already have a recipe class?

https://github.com/Luis-st/Forge-1.16.5-36.0.1-mdk/blob/main/forge-1.16.5-36.0.1-mdk/src/main/java/net/luis/cave/blocks/recipes/SmeltingRecipe.java
and from which class extends the Serializer?

Edited by Luis_ST
Link to comment
Share on other sites

50 minutes ago, diesieben07 said:

Yes you need an IRecipeSerializer. Look at the vanilla examples.

have I to implement / extend IRecipeSerializer?

now i creat this

package net.luis.cave.init;

import net.luis.cave.blocks.recipes.SmeltingRecipe;
import net.minecraft.item.crafting.CookingRecipeSerializer;
import net.minecraft.item.crafting.IRecipeSerializer;

public class CaveRecipeSerializer {

	CookingRecipeSerializer<SmeltingRecipe> CAVE_SMELTING = IRecipeSerializer.register("cave_smelting", new CookingRecipeSerializer<>(SmeltingRecipe::new, 100));

}

 

but i got an error: "The type CookingRecipeSerializer.IFactory<SmeltingRecipe> from the descriptor computed for the target context is not visible here."

Link to comment
Share on other sites

16 hours ago, diesieben07 said:

You cannot use CookingRecipeSerialier, because it requires use of a private inner class (IFactory).

I found out that I need to create a serializer class in my recipe,

but I don't understand what to do in the class, is there a forge documentation

or can i copy the read and write methods from the CookingRecipeSerializer

when i return my SmeltingRecipe

 

Edited by Luis_ST
Link to comment
Share on other sites

1 minute ago, diesieben07 said:

You can take a look at vanilla for examples. Basically your serializer needs to take the JSON and return the correct recipe instance for it. It also needs to handle serializing to and from PacketBuffer to manage syncing to the client.

i currently creat this:

1. is this correct?

2. i have to set the cookingTime but it's a private field so can i create a own one or should i use ObfuscationReflectionHelper to get the field

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

		@Override
		@SuppressWarnings("deprecation")
		public SmeltingRecipe read(ResourceLocation recipeId, JsonObject json) {

			String s = JSONUtils.getString(json, "group", "");
			JsonElement jsonelement = (JsonElement) (JSONUtils.isJsonArray(json, "ingredient")
					? JSONUtils.getJsonArray(json, "ingredient")
					: JSONUtils.getJsonObject(json, "ingredient"));
			Ingredient ingredient = Ingredient.deserialize(jsonelement);
			ItemStack itemstack;

			if (!json.has("result")) {

				throw new JsonSyntaxException("Missing result, expected to find a string or object");

			}

			if (json.get("result").isJsonObject()) {

				itemstack = ShapedRecipe.deserializeItem(JSONUtils.getJsonObject(json, "result"));

			} else {

				String s1 = JSONUtils.getString(json, "result");
				ResourceLocation resourcelocation = new ResourceLocation(s1);
				itemstack = new ItemStack(Registry.ITEM.getOptional(resourcelocation).orElseThrow(() -> {

					return new IllegalStateException("Item: " + s1 + " does not exist");

				}));

			}

			float f = JSONUtils.getFloat(json, "experience", 0.0F);
//			int i = JSONUtils.getInt(json, "cookingtime", cookingTime);
			return new SmeltingRecipe(recipeId, s, ingredient, itemstack, f, 0);

		}

		@Override
		public SmeltingRecipe read(ResourceLocation recipeId, PacketBuffer buffer) {

			String s = buffer.readString(32767);
			Ingredient ingredient = Ingredient.read(buffer);
			ItemStack itemstack = buffer.readItemStack();
			float f = buffer.readFloat();
			int i = buffer.readVarInt();
			return new SmeltingRecipe(recipeId, s, ingredient, itemstack, f, i);

		}

		@Override
		public void write(PacketBuffer buffer, SmeltingRecipe recipe) {

			buffer.writeString(recipe.group);
			recipe.ingredient.write(buffer);
			buffer.writeItemStack(recipe.result);
			buffer.writeFloat(recipe.experience);
			buffer.writeVarInt(recipe.cookTime);

		}

	}

 

Link to comment
Share on other sites

39 minutes ago, diesieben07 said:

AbstractCookingRecipe#cookTime is protected, however it's also final. But it's set via the constructor, just pass your desired cooking time into the constructor...

i just edit the recipe class / serializer class

now is this correct?

package net.luis.cave.blocks.recipes;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;

import net.luis.cave.init.CaveRecipe;
import net.luis.cave.init.blocks.CaveBlocks;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.AbstractCookingRecipe;
import net.minecraft.item.crafting.IRecipeSerializer;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.item.crafting.ShapedRecipe;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraftforge.registries.ForgeRegistryEntry;

public class SmeltingRecipe extends AbstractCookingRecipe {
	
	public static int time;

	@SuppressWarnings("static-access")
	public SmeltingRecipe(ResourceLocation idIn, String groupIn, Ingredient ingredientIn, ItemStack resultIn, float experienceIn, int cookTimeIn) {

		super(IRecipeType.register("cave_smelting"), idIn, groupIn, ingredientIn, resultIn, experienceIn, cookTimeIn);
		this.time = cookTimeIn;
	}

	@Override
	public ItemStack getIcon() {

		return new ItemStack(CaveBlocks.SMELTING_FURNACE.get());

	}

	@Override
	public IRecipeSerializer<?> getSerializer() {

		return CaveRecipe.SMELTING_RECIPE.get();

	}

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

		@Override
		@SuppressWarnings("deprecation")
		public SmeltingRecipe read(ResourceLocation recipeId, JsonObject json) {

			String s = JSONUtils.getString(json, "group", "");
			JsonElement jsonelement = (JsonElement) (JSONUtils.isJsonArray(json, "ingredient")
					? JSONUtils.getJsonArray(json, "ingredient")
					: JSONUtils.getJsonObject(json, "ingredient"));
			Ingredient ingredient = Ingredient.deserialize(jsonelement);
			ItemStack itemstack;

			if (!json.has("result")) {

				throw new JsonSyntaxException("Missing result, expected to find a string or object");

			}

			if (json.get("result").isJsonObject()) {

				itemstack = ShapedRecipe.deserializeItem(JSONUtils.getJsonObject(json, "result"));

			} else {

				String s1 = JSONUtils.getString(json, "result");
				ResourceLocation resourcelocation = new ResourceLocation(s1);
				itemstack = new ItemStack(Registry.ITEM.getOptional(resourcelocation).orElseThrow(() -> {

					return new IllegalStateException("Item: " + s1 + " does not exist");

				}));

			}

			float f = JSONUtils.getFloat(json, "experience", 0.0F);
			int i = JSONUtils.getInt(json, "cookingtime", SmeltingRecipe.time);
			return new SmeltingRecipe(recipeId, s, ingredient, itemstack, f, i);

		}

		@Override
		public SmeltingRecipe read(ResourceLocation recipeId, PacketBuffer buffer) {

			String s = buffer.readString(32767);
			Ingredient ingredient = Ingredient.read(buffer);
			ItemStack itemstack = buffer.readItemStack();
			float f = buffer.readFloat();
			int i = buffer.readVarInt();
			return new SmeltingRecipe(recipeId, s, ingredient, itemstack, f, i);

		}

		@Override
		public void write(PacketBuffer buffer, SmeltingRecipe recipe) {

			buffer.writeString(recipe.group);
			recipe.ingredient.write(buffer);
			buffer.writeItemStack(recipe.result);
			buffer.writeFloat(recipe.experience);
			buffer.writeVarInt(recipe.cookTime);

		}

	}

}

 

Link to comment
Share on other sites

1 hour ago, diesieben07 said:

When opening the GUI in your Block.

so like this:

	@Override
	protected void interactWith(World worldIn, BlockPos pos, PlayerEntity player) {
		
		TileEntity tileentity = worldIn.getTileEntity(pos);
		
		if (player instanceof ServerPlayerEntity && tileentity instanceof SmeltingFurnaceTileEntity) {
			
			NetworkHooks.openGui((ServerPlayerEntity) player, (INamedContainerProvider) tileentity, pos);
			
		}
		
	}

 

Link to comment
Share on other sites

1 hour ago, diesieben07 said:

You never register your ContainerType, you get a giant error in the console from it, did you not read it?

I already registered it but forgot to add the registration to my mod constructor

I tested it again and it still doesn't work

and the consol show this:

[10:19:50] [Render thread/WARN] [minecraft/ScreenManager]: Failed to create screen for menu type: cave:smelting_container

 

I know where the error is coming from I still have to create a screen but where do I have to register / pass the container

Edited by Luis_ST
Link to comment
Share on other sites

49 minutes ago, diesieben07 said:

You need to register a screen factory for your container type using ScreenManager.registerFactory in FMLClientSetupEvent with enqueueWork.

		event.enqueueWork(() -> ScreenManager.registerFactory(CaveContainer.SMELTING_CONTAINER.get(), SmeltingScreen::new));

why does it not work that way (at SmeltingSreen::new)

my screen extends the vanilla Furnace screen and the constructor looks like the vanilla one:

package net.luis.cave.blocks.container;

import net.minecraft.client.gui.screen.inventory.AbstractFurnaceScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

@OnlyIn(Dist.CLIENT)
public class SmeltingScreen extends AbstractFurnaceScreen<SmeltingContainer> {
	
	private static final ResourceLocation FURNACE_GUI_TEXTURES = new ResourceLocation("textures/gui/container/furnace.png");

	public SmeltingScreen(SmeltingContainer screenContainer, PlayerInventory inv, ITextComponent titleIn) {
		
		super(screenContainer, null, inv, titleIn, FURNACE_GUI_TEXTURES);
		
	}

}

 

this is the factory:

create(T p_create_1_, PlayerInventory p_create_2_, ITextComponent p_create_3_);

 

so i dont understand why my IDE show me an error

("The type SmeltingScreen does not define SmeltingScreen(M, PlayerInventory, ITextComponent) that is applicable here")

 

Edited by Luis_ST
Link to comment
Share on other sites

14 minutes ago, diesieben07 said:

The solution is to declare the type of CaveContainer.SMELTING_CONTAINER properly.

What do you mean by "declare correctly" should I replace my container (SmeltingContainer) with generally all Containers (Container class).

So what do i have to do. I understand the problem but don't know how to fix it

Link to comment
Share on other sites

2 hours ago, diesieben07 said:

Properly means don't use ?, use your container class.

okay thanks but now i got an error when i place the block.

beacuse i not init my Recipe Serializer so now my question is there a special way to register the serializer

or can I use DeferredRegister <IRecipeSerializer <?>>

 

 

Link to comment
Share on other sites

1 hour ago, diesieben07 said:

IRecipeSerializer extends IForgeRegistryEntry, that means you can use it with DeferredRegister. Everything that implements IForgeRegistryEntry is a normal registry entry and the registration process is the same.

i hope these are my last two questions on this topic.

So first of all a question about the custom IRecipeType do I have to register this?

And secondly how do I tell the recipe book to show my recipes?

Link to comment
Share on other sites

12 hours ago, diesieben07 said:

Same as vanilla does.

12 hours ago, diesieben07 said:

I don't know.

 

okay thanks unfortunately i still have two problems:
1. when I put items in the slots, close the gui and open it again, the items disappear
2. I added a custom recipe. I can transfer the item into the slot using shift, which means that the recipe works but the smelting process does not start

Link to comment
Share on other sites

1 hour ago, diesieben07 said:

Your SmeltingContainer always uses the AbstractFurnaceContainer that is designed for the client side and which will create a temporary inventory. You need to use the constructor that actually takes in the furnace inventory on the server.

is the correct one the other constructor from the AbstractFurnaceContainer class?

Edited by Luis_ST
Link to comment
Share on other sites

3 hours ago, diesieben07 said:

Yes, the one that takes an inventory.

okay i change the constructor but now i have a costructor with:

	public SmeltingContainer(int id, PlayerInventory playerInventory, IInventory inventory, IIntArray array) {
		
		super(ModContainer.SMELTING_CONTAINER.get(), ModRecipeType.SMELTING_RECIPE, RecipeBookCategory.FURNACE, id, playerInventory, inventory, array);
		
	}

 

but now i cant register my container type because my constructor contains worng things (IInventory and the IIntArray)

so what i have to set there/ did i get this things from the PacketBuffer which i need in the constructor

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.