Jump to content

[1.15.2] Custom Furnace Container


vortigon7

Recommended Posts

I have a problem (or problems?) with creating the Container for my custom furnace. I'm new to Minecraft modding, relatively new to Java, but not new to writing stuff for my own enjoyment, whether it's Godot, some simple C# apps, or Unity.

Anyways, I'm working on a Roman styled mod, and those guys had stuff made out of bronze. I created ores and ingots for copper and tin, have them generate in the world, all is well, but I somehow need to combine them. Now, I could add a simple recipe to put two ingots next to each other and get a third, but that doesn't really make sense. I opted to create a new Alloy Furnace, which works just like the vanilla furnace, but has two slots for items instead of one.

 

This lead to my discovery of Tile Entities, Containers, etc. I made a new block for the furnace (and a new block item as well), then I proceeded to write the functionality for it. Oops. Wasn't nearly as easy as placing a new block in the world. I tried to follow a tutorial on YouTube for 1.15, but it was about creating a new chest, then I found another one about creating a new furnace (hurray!), but for 1.12 (not hurray). I also figured out how to open vanilla Minecraft files, so I looked at the original furnace to figure out the way to do it.

 

The end result is a Tile Entity, which is basically a vanilla furnace but with an added slot. (It has mostly the same code duplicated to a new AlloyFurnaceTileEntity file, changing some functions to be able to have two slots instead of one.) Then, I figured, I needed a Container as well.

Spoiler

        // Alloy Furnace
        this.addSlot(new Slot(furnaceInventoryIn, 0, 46, 17));
        this.addSlot(new Slot(furnaceInventoryIn, 1, 67, 17));
        this.addSlot(new AlloyFurnaceFuelSlot(furnaceInventoryIn, 2, 56, 53));
        this.addSlot(new FurnaceResultSlot(playerInventoryIn.player, furnaceInventoryIn, 3, 112, 31));

        // Player Inventory
        for (int y = 0; y < 3; y++) {
            for (int x = 0; x < 3; x++) {
                this.addSlot(new Slot(playerInventoryIn, x + y * 9 + 9, 8 + x * 18, 84 + y * 18));
            }
        }

        // Hotbar
        for (int x = 0; x < 9; x++) {
            this.addSlot(new Slot(playerInventoryIn, x, 8 + x * 18, 142));
        }

I made the code based on this image: alloy_furnace.png.5d5fbf6b383458cfd055bd1b2ce9bb6f.png

 

Then I did all the overrides the same way AbstractFurnaceContainer.class does. The problem is, I don't know how to register it properly. I have one big RegistryHandler.java file, which handles everything that has to do with the registry. The following is a snippet from my RegistryHandler. The last line I have no idea about, it's from a video I saw. I honestly don't know how to register a ContainerType, but I can't test the furnace until I do.

	public static final DeferredRegister<ContainerType<?>> CONTAINER_TYPES = new DeferredRegister<>(ForgeRegistries.CONTAINERS, ImperiumRomanum.MOD_ID);

	public static void init() {
        CONTAINER_TYPES.register(FMLJavaModLoadingContext.get().getModEventBus());
    	}

	public static final RegistryObject<ContainerType<AlloyFurnaceContainer>> ALLOY_FURNACE_CONTAINER = CONTAINER_TYPES.register("alloy_furnace", () -> IForgeContainerType.create(AlloyFurnaceContainer::new);

I know that AlloyFurnaceContainer::new won't work but I don't know what to put here.

Here's the whole AlloyFurnaceContainer:

Spoiler

package com.andreasalcor.imperiumromanum.inventory.container;

import com.andreasalcor.imperiumromanum.tileentity.AlloyFurnaceTileEntity;
import com.andreasalcor.imperiumromanum.util.RegistryHandler;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.IRecipeHelperPopulator;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.container.*;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.*;
import net.minecraft.util.IIntArray;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

public class AlloyFurnaceContainer extends RecipeBookContainer<IInventory> {
    private final IInventory furnaceInventory;
    private final IIntArray field_217064_e;
    private int burnTime, recipeUsed, cookTime, cookTimeTotal;
    protected final World world;
    private final IRecipeType<? extends AbstractCookingRecipe> recipeType;

    public AlloyFurnaceContainer(ContainerType<?> containerTypeIn, IRecipeType<? extends AbstractCookingRecipe> recipeTypeIn,
                                 int id, PlayerInventory playerInventoryIn, IInventory furnaceInventoryIn,
                                 IIntArray p_i50104_6_) {
        super(RegistryHandler.ALLOY_FURNACE_CONTAINER.get(), id);

        this.recipeType = recipeTypeIn;
        assertInventorySize(furnaceInventoryIn, 4);
        assertIntArraySize(p_i50104_6_, 5);
        this.furnaceInventory = furnaceInventoryIn;
        this.field_217064_e = p_i50104_6_;
        this.world = playerInventoryIn.player.world;

        // Alloy Furnace
        this.addSlot(new Slot(furnaceInventoryIn, 0, 46, 17));
        this.addSlot(new Slot(furnaceInventoryIn, 1, 67, 17));
        this.addSlot(new AlloyFurnaceFuelSlot(furnaceInventoryIn, 2, 56, 53));
        this.addSlot(new FurnaceResultSlot(playerInventoryIn.player, furnaceInventoryIn, 3, 112, 31));

        // Player Inventory
        for (int y = 0; y < 3; y++) {
            for (int x = 0; x < 3; x++) {
                this.addSlot(new Slot(playerInventoryIn, x + y * 9 + 9, 8 + x * 18, 84 + y * 18));
            }
        }

        // Hotbar
        for (int x = 0; x < 9; x++) {
            this.addSlot(new Slot(playerInventoryIn, x, 8 + x * 18, 142));
        }

        this.trackIntArray(p_i50104_6_);

    }

    @Override
    public void func_201771_a(RecipeItemHelper helper) {
        if (this.furnaceInventory instanceof IRecipeHelperPopulator) {
            ((IRecipeHelperPopulator)this.furnaceInventory).fillStackedContents(helper);
        }
    }

    @Override
    public void clear() {
        this.furnaceInventory.clear();
    }

    @Override
    public void func_217056_a(boolean p_217056_1_, IRecipe<?> p_217056_2_, ServerPlayerEntity p_217056_3_) {
        (new ServerRecipePlacerFurnace(this)).place(p_217056_3_, p_217056_2_, p_217056_1_);
    }

    @Override
    public boolean matches(IRecipe<? super IInventory> recipeIn) {
        return recipeIn.matches(this.furnaceInventory, this.world);
    }

    @Override
    public int getOutputSlot() {
        return 2;
    }

    @Override
    public int getWidth() {
        return 1;
    }

    @Override
    public int getHeight() {
        return 1;
    }

    @OnlyIn(Dist.CLIENT)
    public int getSize() {
        return 3;
    }

    @Override
    public boolean canInteractWith(PlayerEntity playerIn) {
        return this.furnaceInventory.isUsableByPlayer(playerIn);
    }

    @Override
    public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) {
        ItemStack itemstack = ItemStack.EMPTY;
        Slot lvt_4_1_ = (Slot)this.inventorySlots.get(index);
        if (lvt_4_1_ != null && lvt_4_1_.getHasStack()) {
            ItemStack itemstack2 = lvt_4_1_.getStack();
            itemstack = itemstack2.copy();
            if (index == 2) {
                if (!this.mergeItemStack(itemstack2, 3, 39, true)) {
                    return ItemStack.EMPTY;
                }

                lvt_4_1_.onSlotChange(itemstack2, itemstack);
            } else if (index != 1 && index != 0) {
                if (this.func_217057_a(itemstack2)) {
                    if (!this.mergeItemStack(itemstack2, 0, 1, false)) {
                        return ItemStack.EMPTY;
                    }
                } else if (this.isFuel(itemstack2)) {
                    if (!this.mergeItemStack(itemstack2, 1, 2, false)) {
                        return ItemStack.EMPTY;
                    }
                } else if (index >= 3 && index < 30) {
                    if (!this.mergeItemStack(itemstack2, 30, 39, false)) {
                        return ItemStack.EMPTY;
                    }
                } else if (index >= 30 && index < 39 && !this.mergeItemStack(itemstack2, 3, 30, false)) {
                    return ItemStack.EMPTY;
                }
            } else if (!this.mergeItemStack(itemstack2, 3, 39, false)) {
                return ItemStack.EMPTY;
            }

            if (itemstack2.isEmpty()) {
                lvt_4_1_.putStack(ItemStack.EMPTY);
            } else {
                lvt_4_1_.onSlotChanged();
            }

            if (itemstack2.getCount() == itemstack.getCount()) {
                return ItemStack.EMPTY;
            }

            lvt_4_1_.onTake(playerIn, itemstack2);
        }

        return itemstack;
    }

    protected boolean func_217057_a(ItemStack p_217057_1_) {
        return this.world.getRecipeManager().getRecipe(this.recipeType, new Inventory(new ItemStack[]{p_217057_1_}), this.world).isPresent();
    }

    protected boolean isFuel(ItemStack p_217058_1_) {
        return AlloyFurnaceTileEntity.isFuel(p_217058_1_);
    }

    @OnlyIn(Dist.CLIENT)
    public int getBurnLeftScaled() {
        int lvt_1_1_ = this.field_217064_e.get(1);
        if (lvt_1_1_ == 0) {
            lvt_1_1_ = 200;
        }

        return this.field_217064_e.get(0) * 13 / lvt_1_1_;
    }

    @OnlyIn(Dist.CLIENT)
    public boolean func_217061_l() {
        return this.field_217064_e.get(0) > 0;
    }
}

 

If anyone at least can point me in the right direction, I'd be the happiest person on the planet. I've been going at this single furnace for about 18-20 hours now.

Link to comment
Share on other sites

Break it down. IForgeContainerType#create returns an instance of ContainerType based on its IContainerFactory. IContainerFactory has two create methods. One method contains three variables (the window id, the player inventory, and a packet buffer) while the other one returns the packet buffer as null. Because of this, one of your Container constructors must contain only the window id and player inventory or include the packet buffer as well. Similar to the tile entity, this is the default constructor being used to declare the type and will be updated when called correctly.

 

For myself, I just use a new constructor instance of a container type with diamond syntax to assume the generic and then using a method reference operator on the correct class. Otherwise, you could just simply use the standard interface for your class.

Edited by ChampionAsh5357
  • Like 1
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.



×
×
  • Create New...

Important Information

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