Jump to content

How to make a Workbench with New Recipes?


KhrBasil

Recommended Posts

Hello I would like to ask if someone would know to  make a Workbench ( just like the Vanilla One (of course i will change the Pictures and such) that Only accepts Recipes I made ? so i have a Page full of Recipes and It can only Craft those Items and no Other.

It would be realy Nice if someone were to know because If i was able to make such a thing it would Help sooo much.

 

P.s

-Im sorry if my English isnt the best  I am from germany and i talk way better English then I  write sometimes.

Thanks in Advance !,

-KhrBasil

Link to comment
Share on other sites

Well classes besides Blocks and Items are and the Main Code are my Client and Common Proxys .

I am a bit new to modding as well coding so it would be cool if you could explain how some things there work if possible.

Thanks to everyone who wants to Help ! :D

Link to comment
Share on other sites

Okay...

 

Now, first of all in your class where you register an call the blocks and stuff (so probably your main mod class) do these, like you usually do:

 

 

 

//the block
blockName = new BLOCKNAME(blockID).setHardness(1.0F).setResistance(F).setStepSound(Block.soundWoodFootstep).setBlockName("blockYOURBLOCKNAME");

//game registry
GameRegistry.registerBlock(BLOCKNAME);
GameRegistry.registerTileEntity(TileEntityYOURBLOCK.class, "TileEntityYOURBLOCK");


private GuiHandler guiHandler = new GuiHandler();
NetworkRegistry.instance().registerGuiHandler(instance, guiHandler);


 

 

 

 

Just like the usual stuff. Create the TileEntity class, the block-class and the GuiHandler class. Also don't forget the LanguageRegistry for your block.

 

 

In your Block Class:

 

 

public class YOURBLOCK extends BlockContainer {

public YOURBLOCK(int blockID){
        super(blockID, Material.wood);
        this.setCreativeTab(CreativeTabs.tabBlock);
  
}


@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int i, float f, float g, float t){
        
                if(tile_entity == null || player.isSneaking()){
                return false;
                }

        player.openGui(YOURMODCLASS.instance, 1, world, x, y, z);
        return true;
        }

        @Override
public TileEntity createNewTileEntity(World world){
        return new TileEntityYOURBLOCK();
}

@Override
public String getTextureFile(){
	return YOUR_TEXTURE_PATH;
}	
}

 

 

 

This is just like a basic block, except for onBlockActivated, which makes it open the gui.

Watch out at this line:

player.openGui(YOURMODCLASS.instance, 1, world, x, y, z);

 

The "1" is the internal GuiID. If you plan to add more Guis, you should probably create an extra class, like GuiIDs ore something where you just store them as integers, like

public static final int YOURBLOCK = 1;
public static final int YOURBLOCK2 = 2;

and then just call them with GuiIDs.YOURMODBLOCK in the line instead of 1.

 

Now to the GuiHandler class, that you made when registering it in you main mod class:

 

 

 

public class GuiHandler implements IGuiHandler {

 @Override
     public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z){
    
	 if (!world.blockExists(x, y, z))
			return null;

		TileEntity tile = world.getBlockTileEntity(x, y, z);

		switch (ID) {

		case 1:
			if (!(tile instanceof TileEntityYOURBLOCK))
				return null;
			return new GuiYOURBLOCK(player.inventory, (TileEntityYOURBLOCK) tile);

		default:
			return null;
		}
     }


  @Override
      public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z){
     
	  if (!world.blockExists(x, y, z))
			return null;

		TileEntity tile = world.getBlockTileEntity(x, y, z);

		switch (ID) {

		case 1:
			if (!(tile instanceof TileYOURBLOCK))
				return null;
			return new ContainerYOURBLOCK(player.inventory, (TileYOURBLOCK) tile);


		default:
			return null;
		}
     
  }
}

 

 

 

Note that the getClientGuiElement returns the GUI of your block and the getServerGuiElement returns the Container of your block.

The gui is just the texture and text if you want it, where the container actually gives you the slots to put stuff in.

Also, If you are using the GuiIDs class, instead of writing "case 1:"  do  "case GuiIDs.YOURBLOCK", so everything is controlled by the GuiIDs class if you want to change the guiIDs around.

 

 

 

Now to the Container Class. Create it at first, just like eclipse should recommend you in your GuiHandler Class.

If you have a normal 3x3 crafting table you can pretty much just copy it from the ContainerWorkbench class. If you have something different, like a 2x2, 3x1 or basically anything, you'll have to change some things. I'll explain it if you want.

For now I recommend just copying the ContainerWorkbench.class

 

The only thing you have to change is onCraftMatrixChanged:

 

@Override
    public void onCraftMatrixChanged(IInventory par1IInventory){
		craftResult.setInventorySlotContents(0, CraftingManagerYOURBLOCKNAME.getInstance().findMatchingRecipe(craftMatrix, worldObj));
	}

 

Create the CraftingManagerYOURBLOCKNAME class, but worry about it later.

First the GuiYOURBLOCK class:

 

 

 

public class GuiYOURBLOCK extends GuiContainer {

public GuiYOURBLOCK(InventoryPlayer player_inventory, TileEntityYOURBLOCK tile_entity){
         super(new ContainerYOURBLOCK(player_inventory, tile_entity));
}


@Override
protected void drawGuiContainerForegroundLayer(int i, int j){
         fontRenderer.drawString("THE TEXT AT THE TOP", 75, 6, 0x404040);
  
}


@Override
protected void drawGuiContainerBackgroundLayer(float f, int i, int j){

         int picture = mc.renderEngine.getTexture(YOURTEXTUREPATH);
        
         GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
        
         this.mc.renderEngine.bindTexture(picture);
        
         int x = (width - xSize) / 2;
        
         int y = (height - ySize) / 2;
        
         this.drawTexturedModalRect(x, y, 0, 0, xSize, ySize);
}
}

 

 

You don't have to draw a text at the top, but if you want, you probably have to play around with the x and y coordinates a bit.

 

Now to the CraftingManagerYOURBLOCKNAME class:

 

 

 

public class CraftingManagerYOURBLOCKNAME {

private static final CraftingManagerYOURBLOCKNAME instance = new CraftingManagerYOURBLOCKNAME();
private List recipes = new ArrayList();

public static final CraftingManagerYOURBLOCKNAME getInstance() {
return instance;
}
public CraftingManagerYOURBLOCKNAME() {

       addRecipe(new ItemStack(Block.wood), new Object[]
{
"###",
"###",
"###",
Character.valueOf('#'), Item.ingotIron
});

}

void addRecipe(ItemStack par1ItemStack, Object par2ArrayOfObj[])
{
	String s = "";
	int i = 0;
	int j = 0;
	int k = 0;

	if (par2ArrayOfObj[i] instanceof String[])
	{
		String as[] = (String[])par2ArrayOfObj[i++];

		for (int l = 0; l < as.length; l++)
		{
			String s2 = as[l];
			k++;
			j = s2.length();
			s = (new StringBuilder()).append(s).append(s2).toString();
		}
	}
	else
	{
		while (par2ArrayOfObj[i] instanceof String)
		{
			String s1 = (String)par2ArrayOfObj[i++];
			k++;
			j = s1.length();
			s = (new StringBuilder()).append(s).append(s1).toString();
		}
	}

	HashMap hashmap = new HashMap();

	for (; i < par2ArrayOfObj.length; i += 2)
	{
		Character character = (Character)par2ArrayOfObj[i];
		ItemStack itemstack = null;

		if (par2ArrayOfObj[i + 1] instanceof Item)
		{
			itemstack = new ItemStack((Item)par2ArrayOfObj[i + 1]);
		}
		else if (par2ArrayOfObj[i + 1] instanceof Block)
		{
			itemstack = new ItemStack((Block)par2ArrayOfObj[i + 1], 1, -1);
		}
		else if (par2ArrayOfObj[i + 1] instanceof ItemStack)
		{
			itemstack = (ItemStack)par2ArrayOfObj[i + 1];
		}

		hashmap.put(character, itemstack);
	}

	ItemStack aitemstack[] = new ItemStack[j * k];

	for (int i1 = 0; i1 < j * k; i1++)
	{
		char c = s.charAt(i1);

		if (hashmap.containsKey(Character.valueOf(c)))
		{
			aitemstack[i1] = ((ItemStack)hashmap.get(Character.valueOf(c))).copy();
		}
		else
		{
			aitemstack[i1] = null;
		}
	}

	recipes.add(new ShapedRecipes(j, k, aitemstack, par1ItemStack));
}

public void addShapelessRecipe(ItemStack par1ItemStack, Object par2ArrayOfObj[])
{
	ArrayList arraylist = new ArrayList();
	Object aobj[] = par2ArrayOfObj;
	int i = aobj.length;

	for (int j = 0; j < i; j++)
	{
		Object obj = aobj[j];

		if (obj instanceof ItemStack)
		{
			arraylist.add(((ItemStack)obj).copy());
			continue;
		}

		if (obj instanceof Item)
		{
			arraylist.add(new ItemStack((Item)obj));
			continue;
		}

		if (obj instanceof Block)
		{
			arraylist.add(new ItemStack((Block)obj));
		}
		else
		{
			throw new RuntimeException("Invalid shapeless recipe!");
		}
	}

	recipes.add(new ShapelessRecipes(par1ItemStack, arraylist));
}

public ItemStack findMatchingRecipe(InventoryCrafting par1InventoryCrafting, World par2World)
{
	int i = 0;
	ItemStack itemstack = null;
	ItemStack itemstack1 = null;

	for (int j = 0; j < par1InventoryCrafting.getSizeInventory(); j++)
	{
		ItemStack itemstack2 = par1InventoryCrafting.getStackInSlot(j);

		if (itemstack2 == null)
		{
			continue;
		}

		if (i == 0)
		{
			itemstack = itemstack2;
		}

		if (i == 1)
		{
			itemstack1 = itemstack2;
		}

		i++;
	}

	if (i == 2 && itemstack.itemID == itemstack1.itemID && itemstack.stackSize == 1 && itemstack1.stackSize == 1 && Item.itemsList[itemstack.itemID].isDamageable())
	{
		Item item = Item.itemsList[itemstack.itemID];
		int l = item.getMaxDamage() - itemstack.getItemDamageForDisplay();
		int i1 = item.getMaxDamage() - itemstack1.getItemDamageForDisplay();
		int j1 = l + i1 + (item.getMaxDamage() * 10) / 100;
		int k1 = item.getMaxDamage() - j1;

		if (k1 < 0)
		{
			k1 = 0;
		}

		return new ItemStack(itemstack.itemID, 1, k1);
	}

	for (int k = 0; k < recipes.size(); k++)
	{
		IRecipe irecipe = (IRecipe)recipes.get(k);

		if (irecipe.matches(par1InventoryCrafting, par2World))
		{
			return irecipe.getCraftingResult(par1InventoryCrafting);
		}
	}

	return null;
}

/**
 * returns the List<> of all recipes
 */
public List getRecipeList()
{
	return recipes;
}
}

 

 

 

Now this is pretty much the same as the vanilla CraftingManager class, look at it to understand how it works. You just add the recipes at the top, with the same pattern. The recipe that's in there currently is just an example.

 

You also need a RecipeSorter, as far as I know:

 

 

 

public class RecipeSorterYOURBLOCKNAME implements Comparator
{
final CraftingManagerYOURBLOCKNAME CraftingManagerYOURBLOCKNAME;

RecipeSorterYOURBLOCKNAME(CraftingManagerYOURBLOCKNAME par1CraftingManagerYOURBLOCKNAME)
{
CraftingManagerYOURBLOCKNAME = par1CraftingManagerYOURBLOCKNAME;
}

public int compareRecipes(IRecipe par1IRecipe, IRecipe par2IRecipe)
{
if ((par1IRecipe instanceof ShapelessRecipes) && (par2IRecipe instanceof ShapedRecipes))
{
return 1;
}

if ((par2IRecipe instanceof ShapelessRecipes) && (par1IRecipe instanceof ShapedRecipes))
{
return -1;
}

if (par2IRecipe.getRecipeSize() < par1IRecipe.getRecipeSize())
{
return -1;
}

return par2IRecipe.getRecipeSize() <= par1IRecipe.getRecipeSize() ? 0 : 1;
}

public int compare(Object par1Obj, Object par2Obj)
{
return compareRecipes((IRecipe)par1Obj, (IRecipe)par2Obj);
}

}

 

 

 

 

NOW

Take a breath.

 

That should be it. I probably forgot something, so tell me if it works. I have not tested this code yet, but that should be it and it should work :)

Don't forget to import all the needed stuff if you copy some code from here.

 

I am in no way a pro at this, and there is probably some unnecessary stuff, but other people that view this will tell you, (and me) :)

Link to comment
Share on other sites

Hey,

No Problem  ;)

Just send me a private message with the errors (like the content of the class files, or just the stuff where the errors are in) and I will look into them :)

 

 

EDIT: Once everything is sorted out I will post another kind of walkthrough or tutorial here for other people who want to make the same thing.

Link to comment
Share on other sites

Okay, so here is the updated "Tutorial".

Sorry, it took quite long because I have lots of stuff to do IRL at the moment.

 

I've written a mod just for this tutorial, I will post all the classes in spoilers here and put a little explaining text beneath them if necessary.

 

The mod is just called Mod1. I've named the block "Crafter", so replace it in the corresponding places with your own block name. If you do everything like this, it should work fine.

 

I am posting every class with imports, because at some places there are several possible imports that eclipse suggests you, but if you import the wrong thing it won't work.

 

Main Mod Class:

 

package mod;

import mod.Block.Crafter;
import mod.Tile.TileCrafter;
import mod.client.handler.ClientPacketHandler;
import mod.client.handler.GuiHandler;
import mod.client.proxy.ClientProxy;
import mod.handler.ServerPacketHandler;
import mod.proxy.CommonProxy;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraftforge.common.Configuration;
import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.Init;
import cpw.mods.fml.common.Mod.Instance;
import cpw.mods.fml.common.Mod.PostInit;
import cpw.mods.fml.common.Mod.PreInit;
import cpw.mods.fml.common.SidedProxy;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
import cpw.mods.fml.common.network.NetworkMod;
import cpw.mods.fml.common.network.NetworkMod.SidedPacketHandler;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.LanguageRegistry;


@Mod(modid = "Mod", name = "Mod", version = "1.0")
@NetworkMod(clientSideRequired = true, serverSideRequired = false, 
	clientPacketHandlerSpec = @SidedPacketHandler(channels = {"Mod"}, 
			packetHandler = ClientPacketHandler.class),
	serverPacketHandlerSpec =@SidedPacketHandler(channels = {"Mod"}, 
			packetHandler = ServerPacketHandler.class))

public class Mod1 {

@Instance("Mod")
public static Mod1 instance;

@SidedProxy
(clientSide = "mod.client.proxy.ClientProxy", 
	serverSide = "mod.proxy.CommonProxy")
public static CommonProxy proxy;
public static ClientProxy clientproxy;

    private GuiHandler guiHandler = new GuiHandler();




@PreInit
public void PreInit(FMLPreInitializationEvent event)
{
        Configuration config = new Configuration(event.getSuggestedConfigurationFile());
        
        config.load();
        
        crafterID = config.getBlock("Crafter", 4000).getInt();
        
        config.save();
        

}



@Init
public void load(FMLInitializationEvent event)
{
	crafter = new Crafter(crafterID, 1, Material.wood);

	GameRegistry.registerBlock(crafter, "Crafter");
	GameRegistry.registerTileEntity(TileCrafter.class, "TileCrafter");

	LanguageRegistry.addName(crafter, "Crafter");

	NetworkRegistry.instance().registerGuiHandler(instance, guiHandler);

}



@PostInit
public void PostInit(FMLPostInitializationEvent event)
{


}



public static int crafterID;
public static Block crafter;


}

 

Just your old simple Main Class. Registering a Block and a TileEntity. The only 'new' thing is the GuiHandler.

 

Block - Crafter

 

package mod.Block;

import mod.Mod1;
import mod.Tile.TileCrafter;
import mod.lib.GuiIDs;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.material.Material;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;

public class Crafter extends BlockContainer {

public Crafter(int id, int texture, Material material)
{
	super(id, texture, material);
	setHardness(1.2F);
	setResistance(10.0F);
	setBlockName("crafter");
	setCreativeTab(CreativeTabs.tabBlock);

}


@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int i, float f, float g, float t)
{
        TileEntity tile_entity = world.getBlockTileEntity(x, y, z);
        
                if(tile_entity == null || player.isSneaking()){
                return false;
                }

        player.openGui(Mod1.instance, GuiIDs.CRAFTER, world, x, y, z);
        return true;
        }


@Override
public void breakBlock(World world, int x, int y, int z, int i, int j)
{
        super.breakBlock(world, x, y, z, i, j);
        }


@Override
public TileEntity createNewTileEntity(World world)
{
	return new TileCrafter();
}


}

 

This is just like a normal block, except it extends BlockContainer. It creates a TileEntity called TileCrafter, and the onBlockActivated opens the GUI, managed by the GuiHandler (we will get to it in a moment). If the player is sneaking, it won't open it.

 

 

TileEntity - TileCrafter

 

package mod.Tile;

import mod.Gui.ContainerCrafter;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;

public class TileCrafter extends TileEntity implements IInventory {

private ItemStack[] inventory;


    public TileCrafter(){
            this.inventory = new ItemStack[ContainerCrafter.InputSlotNumber];//number of slots - without product slot
            this.canUpdate();
           
    }
   
    @Override
    public int getSizeInventory(){
            return this.inventory.length;
    }
   
    
    @Override
    public ItemStack getStackInSlot(int slotIndex){
            return this.inventory[slotIndex];
    }
   
    
    @Override
    public void setInventorySlotContents(int slot, ItemStack stack){
            this.inventory[slot] = stack;
           
            if(stack != null && stack.stackSize > getInventoryStackLimit()){
                    stack.stackSize = getInventoryStackLimit();
            }
    }
   
   
    @Override
    public ItemStack decrStackSize(int slotIndex, int amount){
   
            ItemStack stack = getStackInSlot(slotIndex);
           
           
            if(stack != null){
           
                    if(stack.stackSize <= amount){
                            setInventorySlotContents(slotIndex, null);
                    }
                    else{
                            stack = stack.splitStack(amount);
                            if(stack.stackSize == 0){
                                    setInventorySlotContents(slotIndex, null);
                            }
                    }
            }
   
   
            return stack;
    }
   
   
    @Override
    public ItemStack getStackInSlotOnClosing(int slotIndex){
   
            ItemStack stack = getStackInSlot(slotIndex);
           
           
            if(stack != null){
                    setInventorySlotContents(slotIndex, null);
            }
           
           
            return stack;
    }
   
   
    @Override
    public int getInventoryStackLimit(){
            return 64;
    }
   
   
    @Override
    public boolean isUseableByPlayer(EntityPlayer player){
            return worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) == this && player.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64;
    }
  
   
    @Override
    public void openChest() {}
   
    
    @Override
    public void closeChest() {}
   
   
    @Override
    public String getInvName(){
    return "TileCrafter";
    }
}

 

The TileEntity. You will get an Error at "ContainerCrafter.InputSlotNumber", but it will be fixed once the ContainerCrafter class is created and ready.

 

GuiHandler

 

package mod.client.handler;

import mod.Gui.ContainerCrafter;
import mod.Gui.GuiCrafter;
import mod.Tile.TileCrafter;
import mod.lib.GuiIDs;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import cpw.mods.fml.common.network.IGuiHandler;

public class GuiHandler implements IGuiHandler {

 @Override
     public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z){
    
	 if (!world.blockExists(x, y, z))
			return null;

		TileEntity tile = world.getBlockTileEntity(x, y, z);

		switch (ID) {

		case GuiIDs.CRAFTER:
			if (!(tile instanceof TileCrafter))
				return null;
			return new GuiCrafter(player.inventory, (TileCrafter) tile);

		default:
			return null;
		}
     }


  @Override
      public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z){
     
	  if (!world.blockExists(x, y, z))
			return null;

		TileEntity tile = world.getBlockTileEntity(x, y, z);

		switch (ID) {

		case GuiIDs.CRAFTER:
			if (!(tile instanceof TileCrafter))
				return null;
			return new ContainerCrafter(player.inventory, (TileCrafter) tile);


		default:
			return null;
		}
     
  }

}

 

This handles which Gui should be opened for which TileEntity. "getServerGuiElement" returns the Container class, "getClientGuiElement" the Gui class.

 

GuiIDs

 

package mod.lib;

public class GuiIDs {

public static final int CRAFTER = 1;

}

 

This is just a class with a bunch of integers in it. You don't need it, but if you want to have more Guis and Inventories, it's beneficial, because you can just manage your Guis much easier.

The numbers are mod-intern, so you can pretty much choose any.

 

 

The Container - ContainerCrafter

 

package mod.Gui;

import mod.Mod1;
import mod.Tile.TileCrafter;
import mod.handler.CraftingManagerCrafter;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCraftResult;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.inventory.Slot;
import net.minecraft.inventory.SlotCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;

public class ContainerCrafter extends Container {

protected TileCrafter tile_entity;
public InventoryCrafting craftMatrix = new InventoryCrafting(this, 3, 3);
    public IInventory craftResult = new InventoryCraftResult();
    private World worldObj;
    private int posX;
    private int posY;
    private int posZ;
   
    public static int InputSlotNumber = 9; //Number of Slots in the Crafting Grid
    public static int InOutputSlotNumber = InputSlotNumber + 1; //Same plus Output Slot
    public static int InventorySlotNumber = 36; //Inventory Slots (Inventory and Hotbar)
    public static int InventoryOutSlotNumber = InventorySlotNumber + 1; //Inventory Slot Number + Output
    public static int FullSlotNumber = InventorySlotNumber + InOutputSlotNumber; //All slots
    
    
    
    public ContainerCrafter(InventoryPlayer inventory, TileCrafter tile){

   
    		this.tile_entity = tile;
            int o=0;
            
            int var6;
            int var7;
            worldObj = tile.worldObj;
            posX = tile.xCoord;
            posY = tile.yCoord;
            posZ = tile.zCoord;
  

            addSlotToContainer(new SlotCrafting(inventory.player, this.craftMatrix, craftResult, 0, 124, 35));
            
            for (var6 = 0; var6 < 3; ++var6)
            {
                for (var7 = 0; var7 < 3; ++var7)
                {
                    this.addSlotToContainer(new Slot(this.craftMatrix, var7 + var6 * 3, 30 + var7 * 18, 17 + var6 * 18));
                }
            }
            

            

            for (var6 = 0; var6 < 3; ++var6)
            {
                for (var7 = 0; var7 < 9; ++var7)
                {
                    this.addSlotToContainer(new Slot(inventory, var7 + var6 * 9 + 9, 8 + var7 * 18, 84 + var6 * 18));
                }
            }

            for (var6 = 0; var6 < 9; ++var6)
            {
                this.addSlotToContainer(new Slot(inventory, var6, 8 + var6 * 18, 142));
            }

            this.onCraftMatrixChanged(this.craftMatrix);
           
           
            
           }

   
    @Override
    public void onCraftMatrixChanged(IInventory par1IInventory){
		craftResult.setInventorySlotContents(0, CraftingManagerCrafter.getInstance().findMatchingRecipe(craftMatrix, worldObj));
	}


    @Override
	public void onCraftGuiClosed(EntityPlayer par1EntityPlayer)
	{

		super.onCraftGuiClosed(par1EntityPlayer);

		if (worldObj.isRemote)
		{
			return;
		}

		for (int i = 0; i < InputSlotNumber; i++)
		{
			ItemStack itemstack = craftMatrix.getStackInSlotOnClosing(i);

			if (itemstack != null)
			{
				par1EntityPlayer.dropPlayerItem(itemstack);
			}
		}

	}

    
    @Override
	public boolean canInteractWith(EntityPlayer par1EntityPlayer){
		if (worldObj.getBlockId(posX, posY, posZ) != Mod1.crafter.blockID){
			return false;
		}

		return par1EntityPlayer.getDistanceSq((double)posX + 0.5D, (double)posY + 0.5D, (double)posZ + 0.5D) <= 64D;
	}
     
    
   @Override
   public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int par2)
    {
        ItemStack var3 = null;
        Slot var4 = (Slot)this.inventorySlots.get(par2);

        if (var4 != null && var4.getHasStack())
        {
            ItemStack var5 = var4.getStack();
            var3 = var5.copy();

            if (par2 == 0)
            {
                if (!this.mergeItemStack(var5, InOutputSlotNumber, FullSlotNumber, true))
                {
                    return null;
                }

                var4.onSlotChange(var5, var3);
            }
            else if (par2 >= InOutputSlotNumber && par2 < InventoryOutSlotNumber)
            {
                if (!this.mergeItemStack(var5, InventoryOutSlotNumber, FullSlotNumber, false))
                {
                    return null;
                }
            }
            else if (par2 >= InventoryOutSlotNumber && par2 < FullSlotNumber)
            {
                if (!this.mergeItemStack(var5, InOutputSlotNumber, InventoryOutSlotNumber, false))
                {
                    return null;
                }
            }
            else if (!this.mergeItemStack(var5, InOutputSlotNumber, FullSlotNumber, false))
            {
                return null;
            }

            if (var5.stackSize == 0)
            {
                var4.putStack((ItemStack)null);
            }
            else
            {
                var4.onSlotChanged();
            }

            if (var5.stackSize == var3.stackSize)
            {
                return null;
            }

            var4.onPickupFromSlot(par1EntityPlayer, var5);
        }

        return var3;
    }
}

 

This is the Container class. It creates the slots for your items to go in. More Explanation here:

 

 

Because we want to make a Crafting Table, we need a crafting grid:

public InventoryCrafting craftMatrix = new InventoryCrafting(this, 3, 3);

This makes one. It's 3x3. You can change the numbers at the end to pretty much anything, so 3x1, 5x5, 2x2, 9x9, basically x*y.

You add a slot to it like this:

addSlotToContainer(new Slot(this.craftMatrix, 0, 124, 35))

124 and 35 are the coordinates, 0 is the ID. In this particular class, I just used a for loop to add the slots, it's the same mojang uses for the vanilla Workbench. To add another slot to it you just increase the ID by one and change the coordinates.

 

The functions

 

onCraftMatrixChanged

public void onCraftMatrixChanged(IInventory par1IInventory){
		craftResult.setInventorySlotContents(0, CraftingManagerCrafter.getInstance().findMatchingRecipe(craftMatrix, worldObj));
	}

This just makes sure that every time the crafting grid gets changed in any way, the game checks for any recipes that match the current pattern. The CraftingManagerCrafter class does that, we will get to it in a moment.

 

onCraftGuiClosed

This drops all the items that were in the crafting grid on the floor when you close the gui, just like the vanilla crafting table. If you don't have that function in there, the items will just disappear, because we don't save the slots in the TileEntity.

 

transferStackInSlot

This makes it so you can shift click the result out of the table, it's the same as the one for the vanilla crafting table, except I changed out the numbers with the variables we defined on top (InputSlotNumber etc.), so you can easily adjust it for other size crafting tables.

 

 

 

 

The Gui - GuiCrafter

 

package mod.Gui;

import mod.Tile.TileCrafter;
import mod.proxy.CommonProxy;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.entity.player.InventoryPlayer;

import org.lwjgl.opengl.GL11;

public class GuiCrafter extends GuiContainer {

public GuiCrafter(InventoryPlayer player_inventory, TileCrafter tile){
        super(new ContainerCrafter(player_inventory, tile));
}


@Override
protected void drawGuiContainerForegroundLayer(int i, int j){
        fontRenderer.drawString("Crafter", 75, 6, 0x404040);

}


@Override
protected void drawGuiContainerBackgroundLayer(float f, int i, int j){

        int picture = mc.renderEngine.getTexture(TEXTURE-PATH);
       
        GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
       
        this.mc.renderEngine.bindTexture(picture);
       
        int x = (width - xSize) / 2;
       
        int y = (height - ySize) / 2;
       
        this.drawTexturedModalRect(x, y, 0, 0, xSize, ySize);
}
}

 

This just draws the box. You have to replace "TEXTURE-PATH" with the Image for your Gui. Make sure the slots on the image match with the slot positions defined in the Container. If you copy the vanilla gui of the crafting table it should fit.

        fontRenderer.drawString("Crafter", 75, 6, 0x404040);

draws the text on top of the gui, 75 and 6 are the coordinates, the other number is the color in hexadecimal notation.

 

 

The Crafting Manager - CraftingManagerCrafter

 

package mod.handler;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import net.minecraft.block.Block;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.ShapedRecipes;
import net.minecraft.item.crafting.ShapelessRecipes;
import net.minecraft.world.World;

public class CraftingManagerCrafter {

private static final CraftingManagerCrafter instance = new CraftingManagerCrafter();
private List recipes = new ArrayList();

public static final CraftingManagerCrafter getInstance() {
return instance;
}
public CraftingManagerCrafter() {

//just a example recipe so you know how to add them
addRecipe(new ItemStack(Item.diamond), new Object[]
{
"###",
"###",
"###",
Character.valueOf('#'), Item.ingotIron
});

//another example Recipe, but shapeless
addShapelessRecipe(new ItemStack(Item.cake),new Object[]{Item.stick});


}

void addRecipe(ItemStack par1ItemStack, Object par2ArrayOfObj[])
{
	String s = "";
	int i = 0;
	int j = 0;
	int k = 0;

	if (par2ArrayOfObj[i] instanceof String[])
	{
		String as[] = (String[])par2ArrayOfObj[i++];

		for (int l = 0; l < as.length; l++)
		{
			String s2 = as[l];
			k++;
			j = s2.length();
			s = (new StringBuilder()).append(s).append(s2).toString();
		}
	}
	else
	{
		while (par2ArrayOfObj[i] instanceof String)
		{
			String s1 = (String)par2ArrayOfObj[i++];
			k++;
			j = s1.length();
			s = (new StringBuilder()).append(s).append(s1).toString();
		}
	}

	HashMap hashmap = new HashMap();

	for (; i < par2ArrayOfObj.length; i += 2)
	{
		Character character = (Character)par2ArrayOfObj[i];
		ItemStack itemstack = null;

		if (par2ArrayOfObj[i + 1] instanceof Item)
		{
			itemstack = new ItemStack((Item)par2ArrayOfObj[i + 1]);
		}
		else if (par2ArrayOfObj[i + 1] instanceof Block)
		{
			itemstack = new ItemStack((Block)par2ArrayOfObj[i + 1], 1, -1);
		}
		else if (par2ArrayOfObj[i + 1] instanceof ItemStack)
		{
			itemstack = (ItemStack)par2ArrayOfObj[i + 1];
		}

		hashmap.put(character, itemstack);
	}

	ItemStack aitemstack[] = new ItemStack[j * k];

	for (int i1 = 0; i1 < j * k; i1++)
	{
		char c = s.charAt(i1);

		if (hashmap.containsKey(Character.valueOf(c)))
		{
			aitemstack[i1] = ((ItemStack)hashmap.get(Character.valueOf(c))).copy();
		}
		else
		{
			aitemstack[i1] = null;
		}
	}

	recipes.add(new ShapedRecipes(j, k, aitemstack, par1ItemStack));
}

public void addShapelessRecipe(ItemStack par1ItemStack, Object par2ArrayOfObj[])
{
	ArrayList arraylist = new ArrayList();
	Object aobj[] = par2ArrayOfObj;
	int i = aobj.length;

	for (int j = 0; j < i; j++)
	{
		Object obj = aobj[j];

		if (obj instanceof ItemStack)
		{
			arraylist.add(((ItemStack)obj).copy());
			continue;
		}

		if (obj instanceof Item)
		{
			arraylist.add(new ItemStack((Item)obj));
			continue;
		}

		if (obj instanceof Block)
		{
			arraylist.add(new ItemStack((Block)obj));
		}
		else
		{
			throw new RuntimeException("Invalid shapeless recipe!");
		}
	}

	recipes.add(new ShapelessRecipes(par1ItemStack, arraylist));
}

public ItemStack findMatchingRecipe(InventoryCrafting par1InventoryCrafting, World par2World)
{
	int i = 0;
	ItemStack itemstack = null;
	ItemStack itemstack1 = null;

	for (int j = 0; j < par1InventoryCrafting.getSizeInventory(); j++)
	{
		ItemStack itemstack2 = par1InventoryCrafting.getStackInSlot(j);

		if (itemstack2 == null)
		{
			continue;
		}

		if (i == 0)
		{
			itemstack = itemstack2;
		}

		if (i == 1)
		{
			itemstack1 = itemstack2;
		}

		i++;
	}

	if (i == 2 && itemstack.itemID == itemstack1.itemID && itemstack.stackSize == 1 && itemstack1.stackSize == 1 && Item.itemsList[itemstack.itemID].isDamageable())
	{
		Item item = Item.itemsList[itemstack.itemID];
		int l = item.getMaxDamage() - itemstack.getItemDamageForDisplay();
		int i1 = item.getMaxDamage() - itemstack1.getItemDamageForDisplay();
		int j1 = l + i1 + (item.getMaxDamage() * 10) / 100;
		int k1 = item.getMaxDamage() - j1;

		if (k1 < 0)
		{
			k1 = 0;
		}

		return new ItemStack(itemstack.itemID, 1, k1);
	}

	for (int k = 0; k < recipes.size(); k++)
	{
		IRecipe irecipe = (IRecipe)recipes.get(k);

		if (irecipe.matches(par1InventoryCrafting, par2World))
		{
			return irecipe.getCraftingResult(par1InventoryCrafting);
		}
	}

	return null;
}


public List getRecipeList()
{
	return recipes;
}
}

 

This tells the game what a Shapeless/Shaped recipe is in your crafting table. You add the recipes on top where the two example recipes are. Try if they work before you add any more.

 

 

Recipe Sorter - RecipeSorterCrafter

 

package mod.handler;

import java.util.Comparator;

import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.ShapedRecipes;
import net.minecraft.item.crafting.ShapelessRecipes;

public class RecipeSorterCrafter implements Comparator
{
final CraftingManagerCrafter CraftingManagerCrafter;

RecipeSorterCrafter(CraftingManagerCrafter par1CraftingManager)
{
	CraftingManagerCrafter = par1CraftingManager;
}

public int compareRecipes(IRecipe par1IRecipe, IRecipe par2IRecipe)
{
if ((par1IRecipe instanceof ShapelessRecipes) && (par2IRecipe instanceof ShapedRecipes))
{
return 1;
}

if ((par2IRecipe instanceof ShapelessRecipes) && (par1IRecipe instanceof ShapedRecipes))
{
return -1;
}

if (par2IRecipe.getRecipeSize() < par1IRecipe.getRecipeSize())
{
return -1;
}

return par2IRecipe.getRecipeSize() <= par1IRecipe.getRecipeSize() ? 0 : 1;
}

public int compare(Object par1Obj, Object par2Obj)
{
return compareRecipes((IRecipe)par1Obj, (IRecipe)par2Obj);
}

}

 

This makes sure everything is fine with your recipes.

 

DONE!

if i didn't forget anything :P

 

This should work on single- and multiplayer.

If I helped you with this, make sure to give me a "thank you" ;)

Link to comment
Share on other sites

  • 4 weeks later...

I may of forgoten something but i get an error in my Tilecrafter class

 

public Tilewandtable(){

            this.inventory = new ItemStack[ContainerCrafter.9];//number of slots - without product slot

            this.canUpdate();

         

    [ContainerCrafter.9] has an error "ContainerCrafter cannot be resolved to a variable"

 

EDIT I know this post is a month old :)

Link to comment
Share on other sites

I may of forgoten something but i get an error in my Tilecrafter class

 

public Tilewandtable(){

            this.inventory = new ItemStack[ContainerCrafter.9];//number of slots - without product slot

            this.canUpdate();

         

    [ContainerCrafter.9] has an error "ContainerCrafter cannot be resolved to a variable"

 

EDIT I know this post is a month old :)

 

 

 

 

 

 

Never mind changed it to [ContainerCrafter.InputSlotNumber]

Link to comment
Share on other sites

  • 3 months later...

Hello i am working on a new workbench as well. i made the bench everything works fine except only the first 3x3 grids work for crafting and my grid is 5x4... i can place items on the other grids but they don't work for the recipe.. can anyone help me please?

Link to comment
Share on other sites

  • 5 years later...

This thread is 6 years old. Create your own thread.

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

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.