Jump to content

3 input furnace?


Eastonium

Recommended Posts

  • Replies 59
  • Created
  • Last Reply

Top Posters In This Topic

No, they range from 1 to 3 input items.

Oh...that severely complicates things. It may also be why you had trouble with the HashMap.

Could you maybe create a video tutorial for this? I also wanted to know how to do this :)

Link to comment
Share on other sites

Oh...that severely complicates things. It may also be why you had trouble with the HashMap.

Ok, well then. I'm not sure If something like this would work, but would I be possible to have the code get the current number of input items, and find recipes accordingly?

Link to comment
Share on other sites

Oh...that severely complicates things. It may also be why you had trouble with the HashMap.

Ok, well then. I'm not sure If something like this would work, but would I be possible to have the code get the current number of input items, and find recipes accordingly?

That can certainly be done (I would use three HashMaps), but you said you are fairly new to this area of modding, and a lot of it may be putting you on the hook for a lot of suffering.

Link to comment
Share on other sites

Oh...that severely complicates things. It may also be why you had trouble with the HashMap.

Ok, well then. I'm not sure If something like this would work, but would I be possible to have the code get the current number of input items, and find recipes accordingly?

That can certainly be done (I would use three HashMaps), but you said you are fairly new to this area of modding, and a lot of it may be putting you on the hook for a lot of suffering.

Yes, it probably would. And I really don't like the hook of suffering... So is there ANY easy way to go about this? Or any way I could compute at all?

Link to comment
Share on other sites

I haven't figured out hashmaps yet (somehow I never learned them even though they were covered in a class I took) so I made arrays for my 2 input furnace. You would have yours behave similarly.

 

Note- this is not a good way to do things! Every 5 recipes I add, I have to go through and expand my array. This is just a temporary thing until I can figure out hash-maps independently.

 

Also, my furnace requires a certain order for the items in the slots. If there were no particular order you could just add the recipe with each order possibility.

 

 

    private int recipes[][] = new int[5][2];
    private ItemStack[] results = new ItemStack[5];
    private float[] exp = new float[5];
    private int count;
    private int max;

    public static final ObsidianFurnaceRecipes smelting()
    {
        return smeltingBase;
    }

    private ObsidianFurnaceRecipes()
    {
    	count = 0;
    	max = 5;
        this.addSmelting(Block.obsidian.blockID, Item.diamond.itemID, new ItemStack(Obsidian.obsidianDiamond), 1.0F);
    }

    public void addSmelting(int ID1, int ID2, ItemStack resultItemStack, float experience)
    {
        if (count == max)
        {
        	this.expandRecipes();
        }
        recipes[count][0] = ID1;
        recipes[count][1] = ID2;
        results[count] = resultItemStack;
        exp[count] = experience;
        count = count + 1;
    }
    
    //expands the recipe array - note I have not tested this yet since I only have 1 recipe so far but it *should* work
    private void expandRecipes()
    {
    	int newR[][] = new int[max + 5][4];
    	ItemStack[] newOut = new ItemStack[max + 5];
        float[] newE = new float[max + 5];
    	for (int i = 0; i < max; i++)
    	{
    		newR[i][0] = recipes[i][0];
    		newR[i][1] = recipes[i][1];
    		newOut[i] = results[i];
    		newE[i] = exp[i];
    	}
    	recipes = newR;
    	results = newOut;
    	exp = newE;
    	max = max + 5;
    }

    public void addSmelting(int ID1, int ID2, int meta1, int meta2, ItemStack resultItemStack, float experience)
    {
    	if (count == max)
        {
        	this.expandRecipes();
        }
        recipes[count][0] = ID1;
        recipes[count][1] = ID2;
        results[count] = resultItemStack;
        exp[count] = experience;
    	count = count + 1;
    }

    public ItemStack getSmeltingResult(ItemStack item1, ItemStack item2) 
    {
        if (item1 == null || item2 == null)
        {
            return null;
        }
        for (int i = 0; i < count; i++)
        {
        	if (recipes[i][0] == item1.itemID && recipes[i][1] == item2.itemID)
        	{
        		return results[i];
        	}
        }
        return null;
    }

    public float getExperience(ItemStack item)
    {
        if (item == null)
        {
            return 0;
        }
        for (int i = 0; i < count; i++)
        {
        	if (results[i] == item)
        	{
        		return exp[i];
        	}
        }
        return 0;
    }

        //Checks if an item is part of a recipe in the second slot
public boolean isSecond(ItemStack item) 
{
	if (item == null)
        {
            return false;
        }
        for (int i = 0; i < count; i++)
        {
        	if (recipes[i][1] == item.itemID)
        	{
        		return true;
        	}
        }
        return false;
}

        //Checks if an item is part of a recipe in the first slot
public boolean isFirst(ItemStack item) 
{
	if (item == null)
        {
            return false;
        }
        for (int i = 0; i < count; i++)
        {
        	if (recipes[i][0] == item.itemID)
        	{
        		return true;
        	}
        }
        return false;
}

 

For you, I would actually recommend making 3 recipe classes, one for one input, one for 2 inputs, and one for 3 inputs.

If you would like me to any part of this to you just ask.

Read my thoughts on my summer mod work and tell me what you think!

http://www.minecraftforge.net/forum/index.php/topic,8396.0.html

 

I absolutely love her when she smiles

Link to comment
Share on other sites

I haven't figured out hashmaps yet (somehow I never learned them even though they were covered in a class I took) so I made arrays for my 2 input furnace. You would have yours behave similarly.

 

Note- this is not a good way to do things! Every 5 recipes I add, I have to go through and expand my array. This is just a temporary thing until I can figure out hash-maps independently.

 

Also, my furnace requires a certain order for the items in the slots. If there were no particular order you could just add the recipe with each order possibility.

 

 

    private int recipes[][] = new int[5][2];
    private ItemStack[] results = new ItemStack[5];
    private float[] exp = new float[5];
    private int count;
    private int max;

    public static final ObsidianFurnaceRecipes smelting()
    {
        return smeltingBase;
    }

    private ObsidianFurnaceRecipes()
    {
    	count = 0;
    	max = 5;
        this.addSmelting(Block.obsidian.blockID, Item.diamond.itemID, new ItemStack(Obsidian.obsidianDiamond), 1.0F);
    }

    public void addSmelting(int ID1, int ID2, ItemStack resultItemStack, float experience)
    {
        if (count == max)
        {
        	this.expandRecipes();
        }
        recipes[count][0] = ID1;
        recipes[count][1] = ID2;
        results[count] = resultItemStack;
        exp[count] = experience;
        count = count + 1;
    }
    
    //expands the recipe array - note I have not tested this yet since I only have 1 recipe so far but it *should* work
    private void expandRecipes()
    {
    	int newR[][] = new int[max + 5][4];
    	ItemStack[] newOut = new ItemStack[max + 5];
        float[] newE = new float[max + 5];
    	for (int i = 0; i < max; i++)
    	{
    		newR[i][0] = recipes[i][0];
    		newR[i][1] = recipes[i][1];
    		newOut[i] = results[i];
    		newE[i] = exp[i];
    	}
    	recipes = newR;
    	results = newOut;
    	exp = newE;
    	max = max + 5;
    }

    public void addSmelting(int ID1, int ID2, int meta1, int meta2, ItemStack resultItemStack, float experience)
    {
    	if (count == max)
        {
        	this.expandRecipes();
        }
        recipes[count][0] = ID1;
        recipes[count][1] = ID2;
        results[count] = resultItemStack;
        exp[count] = experience;
    	count = count + 1;
    }

    public ItemStack getSmeltingResult(ItemStack item1, ItemStack item2) 
    {
        if (item1 == null || item2 == null)
        {
            return null;
        }
        for (int i = 0; i < count; i++)
        {
        	if (recipes[i][0] == item1.itemID && recipes[i][1] == item2.itemID)
        	{
        		return results[i];
        	}
        }
        return null;
    }

    public float getExperience(ItemStack item)
    {
        if (item == null)
        {
            return 0;
        }
        for (int i = 0; i < count; i++)
        {
        	if (results[i] == item)
        	{
        		return exp[i];
        	}
        }
        return 0;
    }

        //Checks if an item is part of a recipe in the second slot
public boolean isSecond(ItemStack item) 
{
	if (item == null)
        {
            return false;
        }
        for (int i = 0; i < count; i++)
        {
        	if (recipes[i][1] == item.itemID)
        	{
        		return true;
        	}
        }
        return false;
}

        //Checks if an item is part of a recipe in the first slot
public boolean isFirst(ItemStack item) 
{
	if (item == null)
        {
            return false;
        }
        for (int i = 0; i < count; i++)
        {
        	if (recipes[i][0] == item.itemID)
        	{
        		return true;
        	}
        }
        return false;
}

 

For you, I would actually recommend making 3 recipe classes, one for one input, one for 2 inputs, and one for 3 inputs.

If you would like me to any part of this to you just ask.

 

Yes, I'd like help, but I was hoping on having it work exactly like a workbech with 3 slots and have ONLY shapeless recipes. I'm hoping the only shapeless recipes part will make things simpler, but I don't know if it will. So where do I start?

Link to comment
Share on other sites

Sorry, I have been mostly unable to use this website recently for whatever reason, so no promises that I will have timely responses at all...

 

If you want it to behave similarly to the workbench, you might want to try looking at the workbench code. I'm sure it could probably be combined with the furnace code to get what you want.

However...

 

What I would do as a preliminary test to get things working, followed by fixing and streamlining etc later, would be to have 3 recipe classes. These classes represent having 1 ingredient, 2 ingredients, and 3 ingredients. Each would have a variable similar to mine:

private int recipes[][] = new int[M][N];

Where N is the number of ingredients that class covers, and M is maybe the number of recipes you plan on having.

Each class also has their own array of results. The index of the recipe is the index of the results array.

 

Lots of code can be copied over from mine. Doing it this way will almost guarantee you a few errors the first time you run it simply because you will have to look through my code, understand what it is doing, see where you are changing something, and make that change work. This process makes this all a lot of work for something that might work slowly or be buggy that you will have to fix, but it is really gratifying when it works the first time and all you have left is making everything beautiful.

 

In the (I think) container class, or wherever checks are made on what recipes do what etc, you will have to check each of your recipe classes. Check how many ingredients are currently in the furnace and use the corresponding recipe class. Since it is shapeless, you will need to either have every variation of the recipe in your recipe class, or when you query your recipe class, you need to run through every variation of the ingredients currently in the furnace. It will probably be easier to code in every recipe and just make one query.

 

Does this make sense? When you make your recipe class, go to your container class and remove the vanilla recipes import. This will highlight every reference to the vanilla recipes and point out what methods are important and need to be understood.

Read my thoughts on my summer mod work and tell me what you think!

http://www.minecraftforge.net/forum/index.php/topic,8396.0.html

 

I absolutely love her when she smiles

Link to comment
Share on other sites

I dunno how good this would work, I have not tested it though (don't have a 3 input furnace to test with)  but it should work, I think,

 

let you use one list for 1 to 3 items for input in any order

as it sorts them into an int[][]

and counts them then

searches the list, then if it didn't find something(gets null) it and there are more then one input

it flips item 0 and item 1 looks again

then if still null and there's 3 inputs it will go and check for the other 4 possible combinations  left each checking for null

 

then returns either null or the itemstack

 

 

of course doing it this way does mean you have to add to the list with the items in a certain order so they can be found for 1 or to inputs, but that should not be a problem

 

when it searches it looks for 3 sets of values each time even if it only got 1 set, so you need to fill in the blanks with 0 as that's what it searches for if it don't get told something else.

 

two methods

http://pastebin.com/51krzJTD

Link to comment
Share on other sites

I dunno how good this would work, I have not tested it though (don't have a 3 input furnace to test with)  but it should work, I think,

 

let you use one list for 1 to 3 items for input in any order

as it sorts them into an int[][]

and counts them then

searches the list, then if it didn't find something(gets null) it and there are more then one input

it flips item 0 and item 1 looks again

then if still null and there's 3 inputs it will go and check for the other 4 possible combinations  left each checking for null

 

then returns either null or the itemstack

 

 

of course doing it this way does mean you have to add to the list with the items in a certain order so they can be found for 1 or to inputs, but that should not be a problem

 

when it searches it looks for 3 sets of values each time even if it only got 1 set, so you need to fill in the blanks with 0 as that's what it searches for if it don't get told something else.

 

two methods

http://pastebin.com/51krzJTD

Sorry, I have been mostly unable to use this website recently for whatever reason, so no promises that I will have timely responses at all...

 

If you want it to behave similarly to the workbench, you might want to try looking at the workbench code. I'm sure it could probably be combined with the furnace code to get what you want.

However...

 

What I would do as a preliminary test to get things working, followed by fixing and streamlining etc later, would be to have 3 recipe classes. These classes represent having 1 ingredient, 2 ingredients, and 3 ingredients. Each would have a variable similar to mine:

private int recipes[][] = new int[M][N];

Where N is the number of ingredients that class covers, and M is maybe the number of recipes you plan on having.

Each class also has their own array of results. The index of the recipe is the index of the results array.

 

Lots of code can be copied over from mine. Doing it this way will almost guarantee you a few errors the first time you run it simply because you will have to look through my code, understand what it is doing, see where you are changing something, and make that change work. This process makes this all a lot of work for something that might work slowly or be buggy that you will have to fix, but it is really gratifying when it works the first time and all you have left is making everything beautiful.

 

In the (I think) container class, or wherever checks are made on what recipes do what etc, you will have to check each of your recipe classes. Check how many ingredients are currently in the furnace and use the corresponding recipe class. Since it is shapeless, you will need to either have every variation of the recipe in your recipe class, or when you query your recipe class, you need to run through every variation of the ingredients currently in the furnace. It will probably be easier to code in every recipe and just make one query.

 

Does this make sense? When you make your recipe class, go to your container class and remove the vanilla recipes import. This will highlight every reference to the vanilla recipes and point out what methods are important and need to be understood.

 

Thank you both for your help, from what I've read, I think you have similar ideas, but I'm not sure which one to use.

I'm thinking of learning specifically about Arrays and HashMaps before I go any further as well, as I know I have to do SOMETHING with those no matter what.

Link to comment
Share on other sites

Thank you for your help,  but for the moment, I'm not at the experience level to be able to code my own furnace. I was hoping to just modify a furnace instead of writing it all myself. :P

Basically I don't really have a clue how to use what you have suggested.

 

it is easier to write your own furnace. By the way i did not read the full thread thats why i could be wrong but i have an old source code of an special furnace:

 

Special things:

3 inputslots

fuelbarrel, and an extra slot (i think it was for modules)

 

its a dirty code but its easy to understand. it does not make much lag but it could be a smaler code.

 

here is my old 1.2.5 code:

 

TileEntity:

package spmod.dynamictools.common.tileentities;

import spmod.dynamictools.common.lib.DTNames;
import spmod.dynamictools.common.recipes.AdvancedToolMakerRecipe;
import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.asm.SideOnly;
import cpw.mods.fml.common.registry.GameRegistry;
import net.minecraft.src.Block;
import net.minecraft.src.BlockFurnace;
import net.minecraft.src.EntityPlayer;
import net.minecraft.src.FurnaceRecipes;
import net.minecraft.src.IInventory;
import net.minecraft.src.Item;
import net.minecraft.src.ItemBlock;
import net.minecraft.src.ItemHoe;
import net.minecraft.src.ItemStack;
import net.minecraft.src.ItemSword;
import net.minecraft.src.ItemTool;
import net.minecraft.src.Material;
import net.minecraft.src.NBTTagCompound;
import net.minecraft.src.NBTTagList;
import net.minecraft.src.TileEntity;

public class TileAdvWorkbench extends TileEntity implements IInventory
{

private ItemStack[] advSlots = new ItemStack[6];
public int fuel = 0;
public int heat = 0;
public int progress = 0;


public TileAdvWorkbench()
{

}


@Override
public int getSizeInventory() 
{
	return advSlots.length;
}

@Override
public ItemStack getStackInSlot(int par1)
{
	return advSlots[par1];
}

@SideOnly(Side.CLIENT)
public int getFuel(int par1)
{
	return fuel * par1 / 240000;
}

@SideOnly(Side.CLIENT)
public boolean isBurning()
{
	return heat > 0;
}

@SideOnly(Side.CLIENT)
public boolean hasFuel()
{
	return fuel > 0;
}

@SideOnly(Side.CLIENT)
public boolean isWorking()
{
	return isPowered();
}

@SideOnly(Side.CLIENT)
public boolean canWork()
{
	return heat > 2000;
}

@SideOnly(Side.CLIENT)
public int getHeat(int par1)
{
	return heat * par1 / 5300;
}

@SideOnly(Side.CLIENT)
public int getProgress(int par1)
{
	return progress * par1 / 100;
}

    public ItemStack decrStackSize(int par1, int par2)
    {

        if (this.advSlots[par1] != null)
        {
            ItemStack var3;

            if (this.advSlots[par1].stackSize <= par2)
            {
                var3 = this.advSlots[par1];
                this.advSlots[par1] = null;
                return var3;
            }
            else
            {
                var3 = this.advSlots[par1].splitStack(par2);

                if (this.advSlots[par1].stackSize == 0)
                {
                    this.advSlots[par1] = null;
                }

                return var3;
            }
        }
        else
        {
            return null;
        }
    }

    public ItemStack getStackInSlotOnClosing(int par1)
    {

        if (this.advSlots[par1] != null)
        {
        	ItemStack var2 = this.advSlots[par1];
            this.advSlots[par1] = null;
            return var2;
        }
        else
        {
            return null;
        }
    }

    public void setInventorySlotContents(int par1, ItemStack par2ItemStack)
    {

        this.advSlots[par1] = par2ItemStack;

        if (par2ItemStack != null && par2ItemStack.stackSize > this.getInventoryStackLimit())
        {
            par2ItemStack.stackSize = this.getInventoryStackLimit();
        }
    }

@Override
public String getInvName() {
	return DTNames.AdvToolbenchName;
}


@Override
public int getInventoryStackLimit()
{
	return 64;
}


@Override
public boolean isUseableByPlayer(EntityPlayer var1) 
{
	return true;
}

@Override
public void openChest(){
}

@Override
public void closeChest(){
}



    public void readFromNBT(NBTTagCompound par1NBTTagCompound)
    {
        super.readFromNBT(par1NBTTagCompound);
        NBTTagList var2 = par1NBTTagCompound.getTagList("Items");
        this.advSlots = new ItemStack[this.getSizeInventory()];

        for (int var3 = 0; var3 < var2.tagCount(); ++var3)
        {
            NBTTagCompound var4 = (NBTTagCompound)var2.tagAt(var3);
            byte var5 = var4.getByte("Slot");

            if (var5 >= 0 && var5 < this.advSlots.length)
            {
                this.advSlots[var5] = ItemStack.loadItemStackFromNBT(var4);
            }
        }
        
        this.fuel = par1NBTTagCompound.getInteger("Fuel");
        this.heat = par1NBTTagCompound.getInteger("Heat");
        this.progress = par1NBTTagCompound.getInteger("Progress");
    }

    /**
     * Writes a tile entity to NBT.
     */
    public void writeToNBT(NBTTagCompound par1NBTTagCompound)
    {
        super.writeToNBT(par1NBTTagCompound);
        par1NBTTagCompound.setInteger("Fuel", this.fuel);
        par1NBTTagCompound.setInteger("Heat", this.heat);
        par1NBTTagCompound.setInteger("Progress", this.progress);
        NBTTagList var2 = new NBTTagList();

        for (int var3 = 0; var3 < this.advSlots.length; ++var3)
        {
            if (this.advSlots[var3] != null)
            {
                NBTTagCompound var4 = new NBTTagCompound();
                var4.setByte("Slot", (byte)var3);
                this.advSlots[var3].writeToNBT(var4);
                var2.appendTag(var4);
            }
        }

        par1NBTTagCompound.setTag("Items", var2);
    }


   	public void updateEntity()
   	{
   		boolean update = false;
   		
	   	if(heat > 0 && fuel == 0)
	   	{
		   	--heat;
		   	update = true;
	   	}
	   	else if(heat <= 2000 && fuel > 0&& isPowered())
	   	{
	   		fuel -= 5;
	   		heat += 1;
	   		update = true;
	   	}
	   	else if(heat > 2000 && fuel > 0 && heat < 5000 && isPowered())
	   	{
	   		fuel--;
	   		heat++;
	   		update = true;
	   	}
	   	else if(!isPowered() && heat > 0)
	   	{
	   		heat--;
	   		update = true;
	   	}
	   	else
	   	{
	   		
	   	}
	   	
	   	
	   	if(fuel < 100000)
	   	{
	   		
	   		if(advSlots[0] != null && this.isFuel(advSlots[0]))
	   		{
	   			fuel = fuel + addFuel(advSlots[0]);
	   			--advSlots[0].stackSize;
	   			update = true;
                    if (this.advSlots[0].stackSize == 0)
                    {
                        this.advSlots[0] = this.advSlots[0].getItem().getContainerItemStack(advSlots[0]);
                    }
	   		}
	   		else if(advSlots[0] != null && isBoostFuel(advSlots[0]))
	   		{
	   			fuel = fuel - (addBoostFuel(advSlots[0]) * 2);
	   			if(fuel < 0)
	   			{
	   				fuel = 0;
	   			}
	   			heat = heat + addBoostFuel(advSlots[0]);
	   			--advSlots[0].stackSize;
	   			update = true;
	   			if(this.advSlots[0].stackSize == 0)
	   			{
	   				this.advSlots[0] = this.advSlots[0].getItem().getContainerItemStack(advSlots[0]);
	   			}
	   		}
	   		else if(advSlots[0] != null && isExtraFuel(advSlots[0]) && heat > 2000)
	   		{
	   			fuel = fuel + addExtraFuel(advSlots[0]);
	   			heat = heat - (addExtraFuel(advSlots[0]) * 3);
	   			--advSlots[0].stackSize;
	   			update = true;
	   			if(this.advSlots[0].stackSize == 0)
	   			{
	   				this.advSlots[0] = this.advSlots[0].getItem().getContainerItemStack(advSlots[0]);
	   			}
	   		}
	   	}
	   	
	   	if(canSmeltVanillaThings())
	   	{
	   		++progress;
	   		
	   		if(progress > 100)
	   		{
	   			progress = 0;
	   			smeltVanilla();
	   			update = true;
	   		}
	   		
	   	}
	   	
	   	if(update == true)
	   	{
	   		this.onInventoryChanged();
	   	}
	   
   	}
   	
   	public static boolean isExtraFuel(ItemStack par1)
   	{
   		return addExtraFuel(par1) > 0;
   	}
   	
   	public static boolean isFuel(ItemStack par1)
   	{
   		return addFuel(par1) > 0;
   	}
   	
   	public static boolean isBoostFuel(ItemStack par1)
   	{
   		return addBoostFuel(par1) > 0;
   	}
   	
   	
   	public static int addBoostFuel(ItemStack par1)
   	{
   		if(par1 == null)
   		{
   			return 0;
   		}
   		
   		int any = par1.getItem().shiftedIndex;
   		Item item = par1.getItem();
   		int metaItem = par1.getItemDamage();
   		
   		if(par1.getItem() instanceof ItemBlock && Block.blocksList[any] != null)
   		{
   			Block block = Block.blocksList[any]; 
   		}
   		
   		if(item == item.bucketLava)
   		{
   			return 2000;
   		}
   		
   		
   		return GameRegistry.getFuelValue(par1);
   		
   	}
   	
   	public static int addExtraFuel(ItemStack par1)
   	{
   		if(par1 == null)
   		{
   			return 0;
   		}
   		
   		int any = par1.getItem().shiftedIndex;
   		Item item = par1.getItem();
   		int metaItem = par1.getItemDamage();
   		
   		if(par1.getItem() instanceof ItemBlock && Block.blocksList[any] != null)
   		{
   			Block block = Block.blocksList[any]; 
   			if(block == block.cobblestone || block == block.cobblestoneMossy)
   			{
   				return 500;
   			}
   		}

   		
   		
   		return GameRegistry.getFuelValue(par1);
   	}
   	
   	
   	public static int addFuel(ItemStack par1)
   	{
   		if(par1 == null)
   		{
   			return 0;
   		}
   		
   		int any = par1.getItem().shiftedIndex;
   		Item item = par1.getItem();
   		int metaItem = par1.getItemDamage();
   		
   		if(par1.getItem() instanceof ItemBlock && Block.blocksList[any] != null)
   		{
   			Block block = Block.blocksList[any]; 
   			if(block == block.wood)
   			{
   				return 25;
   			}

   			if(block == block.sapling)
   			{
   				return 2;
   			}
   			
   			if(block == block.planks)
   			{
   				return 25;
   			}
   		}
   		
   		if(item == item.coal)
   		{
   			return 1000;
   		}
   		
   		
   		return GameRegistry.getFuelValue(par1);
   		
   	}
   	
   	public boolean canSmeltVanillaThings()
   	{
   		if(canProgress() == true || canProgress2() == true || canProgress3() == true)
   		{
   			return true;
   		}
   		else
   		{
   			return false;
   		}
   	}

   	public boolean canProgress2()
   	{
   		if(advSlots[3] == null)
   		{
   			return false;
   		}
   		else
   		{
   				ItemStack par1 = AdvancedToolMakerRecipe.smelting().getCookResult(advSlots[3]);
   				if (par1 == null) return false;
   				if (this.advSlots[5] == null) return true;
   				if (!this.advSlots[5].isItemEqual(par1)) return false;
   				int result = advSlots[5].stackSize + par1.stackSize;
   				return (result <= getInventoryStackLimit() && result <= par1.getMaxStackSize());
   			
   		
   		}
   	}
   	
   	public boolean canProgress3()
   	{
   		if(advSlots[4] == null)
   		{
   			return false;
   		}
   		else
   		{
   				ItemStack par1 = AdvancedToolMakerRecipe.smelting().getCookResult(advSlots[4]);
   				if (par1 == null) return false;
   				if (this.advSlots[5] == null) return true;
   				if (!this.advSlots[5].isItemEqual(par1)) return false;
   				int result = advSlots[5].stackSize + par1.stackSize;
   				return (result <= getInventoryStackLimit() && result <= par1.getMaxStackSize());
   			
   		
   		}
   	}
   	
	public boolean canProgress()
   	{
   		
   		if(advSlots[2] == null)
   		{
   			return false;
   		}
   		else
   		{
   				ItemStack par1 = AdvancedToolMakerRecipe.smelting().getCookResult(advSlots[2]);
   				if (par1 == null) return false;
   				if (this.advSlots[5] == null) return true;
   				if (!this.advSlots[5].isItemEqual(par1)) return false;
   				int result = advSlots[5].stackSize + par1.stackSize;
   				return (result <= getInventoryStackLimit() && result <= par1.getMaxStackSize());
   			
   		
   		}
   		
   	}

	public void smeltVanilla()
	{
		smeltVanilla1();
		smeltVanilla2();
		smeltVanilla3();
	}


	public void smeltVanilla3()
	{
		if(canProgress3())
		{
			ItemStack par1 = AdvancedToolMakerRecipe.smelting().getCookResult(advSlots[4]);
            if (this.advSlots[5] == null)
            {
                this.advSlots[5] = par1.copy();
            }
            else if (this.advSlots[5].isItemEqual(par1))
            {
            	advSlots[5].stackSize += par1.stackSize;
            }

            --advSlots[4].stackSize;

            if (advSlots[4].stackSize <= 0)
            {
                this.advSlots[4] = null;
            }
		}
	}

	public void smeltVanilla2()
	{
		if(canProgress2())
		{
			ItemStack par1 = AdvancedToolMakerRecipe.smelting().getCookResult(advSlots[3]);
            if (this.advSlots[5] == null)
            {
                this.advSlots[5] = par1.copy();
            }
            else if (this.advSlots[5].isItemEqual(par1))
            {
            	advSlots[5].stackSize += par1.stackSize;
            }

            --advSlots[3].stackSize;

            if (advSlots[3].stackSize <= 0)
            {
                this.advSlots[3] = null;
            }
		}
	}

	public void smeltVanilla1()
	{
		if(canProgress())
		{
			ItemStack par1 = AdvancedToolMakerRecipe.smelting().getCookResult(advSlots[2]);
            if (this.advSlots[5] == null)
            {
                this.advSlots[5] = par1.copy();
            }
            else if (this.advSlots[5].isItemEqual(par1))
            {
            	advSlots[5].stackSize += par1.stackSize;
            }

            --advSlots[2].stackSize;

            if (advSlots[2].stackSize <= 0)
            {
                this.advSlots[2] = null;
            }
		}
	}

	public boolean isPowered()
	{
		return this.worldObj.isBlockIndirectlyGettingPowered(this.xCoord, this.yCoord, this.zCoord);
	}

   	
}

 

Gui

package spmod.dynamictools.client.gui;

import java.awt.Button;

import org.lwjgl.opengl.GL11;

import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.asm.SideOnly;
import spmod.dynamictools.common.tileentities.TileAdvWorkbench;
import spmod.dynamictools.common.container.ContainerAdvToolbench;
import spmod.dynamictools.common.lib.DTNames;
import net.minecraft.src.EntityPlayer;
import net.minecraft.src.GuiButton;
import net.minecraft.src.GuiContainer;
import net.minecraft.src.InventoryPlayer;
import net.minecraft.src.StatCollector;
import net.minecraft.src.World;

@SideOnly(Side.CLIENT)
public class GuiAdvToolbench extends GuiContainer
{
private TileAdvWorkbench tile;
int par5 = 175;
int par6 = 165;

public GuiAdvToolbench(InventoryPlayer par1, TileAdvWorkbench par2)
{
	super(new ContainerAdvToolbench(par1, par2));
	tile = par2;
}    

protected void drawGuiContainerForegroundLayer()
    {
        this.fontRenderer.drawString(DTNames.AdvToolbenchName, 28, 6, 4210752);
        this.fontRenderer.drawString(StatCollector.translateToLocal("container.inventory"), 8, this.ySize - 96 + 2, 4210752);
    }


    protected void drawGuiContainerBackgroundLayer(float par1, int par2, int par3)
    {
        int var4 = this.mc.renderEngine.getTexture("/spmod/dynamictools/textures/gui/advancedworkbench.png");
        GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
        this.mc.renderEngine.bindTexture(var4);
        int var5 = (this.width - this.xSize) / 2;
        int var6 = (this.height - this.ySize) / 2;
        this.drawTexturedModalRect(var5, var6, 0, 0, this.xSize, this.ySize);
        int var7;
        
        if(tile.isWorking())
        {
        	this.drawTexturedModalRect(var5 + 49, var6 + 68, 176, 77, 11, 5);
        }
        
        if (this.tile.hasFuel())
        {
            var7 = this.tile.getFuel(100);
            this.drawTexturedModalRect(var5 + 11, var6 + 76 - var7, 176, 73 - var7, 4, var7 + 2);
        }
        
        if (this.tile.isBurning())
        {
            var7 = this.tile.getHeat(12);
            this.drawTexturedModalRect(var5 + 25, var6 + 42 + 12 - var7, 176, 12 - var7, 14, var7 + 2);
        }
        var7 = this.tile.getProgress(24);
        this.drawTexturedModalRect(var5 + 90, var6 + 32, 176, 14, var7 + 1, 16);  

    }
}

 

Container

package spmod.dynamictools.common.container;

import java.util.Iterator;

import cpw.mods.fml.common.Side;
import cpw.mods.fml.common.asm.SideOnly;

import net.minecraft.src.Container;
import net.minecraft.src.EntityPlayer;
import net.minecraft.src.FurnaceRecipes;
import net.minecraft.src.ICrafting;
import net.minecraft.src.InventoryPlayer;
import net.minecraft.src.ItemStack;
import net.minecraft.src.Slot;
import net.minecraft.src.SlotFurnace;
import net.minecraft.src.TileEntityFurnace;
import spmod.dynamictools.common.tileentities.TileAdvWorkbench;

public class ContainerAdvToolbench extends Container
{
private TileAdvWorkbench tile;
private int fuelnow = 0;
private int heatnow = 0;
private int progressnow = 0;

public ContainerAdvToolbench(InventoryPlayer par1, TileAdvWorkbench par2) 
{
	tile = par2;
	addSlotToContainer(new Slot(par2, 0, 24, 60)); //fuelslot
	addSlotToContainer(new Slot(par2, 1, 7, 10)); // recipe slot
	addSlotToContainer(new Slot(par2, 2, 55, 31)); // input 1
	addSlotToContainer(new Slot(par2, 3, 80, 10)); // input 2
	addSlotToContainer(new Slot(par2, 4, 81, 54)); // input 3
	addSlotToContainer(new SlotFurnace(par1.player, par2, 5, 128, 32)); //output
        int var3;

        for (var3 = 0; var3 < 3; ++var3)
        {
            for (int var4 = 0; var4 < 9; ++var4)
            {
                this.addSlotToContainer(new Slot(par1, var4 + var3 * 9 + 9, 8 + var4 * 18, 84 + var3 * 18));
            }
        }

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

    public void updateCraftingResults()
    {
        super.updateCraftingResults();
        Iterator var1 = this.crafters.iterator();

        while (var1.hasNext())
        {
            ICrafting var2 = (ICrafting)var1.next();

            if (this.fuelnow != this.tile.fuel)
            {
                var2.updateCraftingInventoryInfo(this, 0, this.tile.fuel);
            }

            if (this.heatnow != this.tile.heat)
            {
                var2.updateCraftingInventoryInfo(this, 1, this.tile.heat);
            }

            if (this.progressnow != this.tile.progress)
            {
                var2.updateCraftingInventoryInfo(this, 2, this.tile.progress);
            }
        }

        this.fuelnow = this.tile.fuel;
        this.heatnow = this.tile.heat;
        this.progressnow = this.tile.progress;
    }

    
    @SideOnly(Side.CLIENT)
    public void updateProgressBar(int par1, int par2)
    {
        if (par1 == 0)
        {
            this.tile.fuel = par2;
        }

        if (par1 == 1)
        {
            this.tile.heat = par2;
        }

        if (par1 == 2)
        {
            this.tile.progress = par2;
        }
    }

@Override
public boolean canInteractWith(EntityPlayer var1) 
{
	return true;
}

public ItemStack transferStackInSlot(int par1)
{
        ItemStack var2 = null;
        Slot var3 = (Slot)this.inventorySlots.get(par1);

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

            if (par1 == 2)
            {
                if (!this.mergeItemStack(var4, 3, 39, true))
                {
                    return null;
                }

                var3.onSlotChange(var4, var2);
            }
            else if (par1 != 1 && par1 != 0)
            {
                if (FurnaceRecipes.smelting().getSmeltingResult(var4) != null)
                {
                    if (!this.mergeItemStack(var4, 2, 1, false))
                    {
                        return null;
                    }
                }
                else if (TileEntityFurnace.isItemFuel(var4))
                {
                    if (!this.mergeItemStack(var4, 0, 2, false))
                    {
                        return null;
                    }
                }
                else if (par1 >= 3 && par1 < 30)
                {
                    if (!this.mergeItemStack(var4, 30, 39, false))
                    {
                        return null;
                    }
                }
                else if (par1 >= 30 && par1 < 39 && !this.mergeItemStack(var4, 3, 30, false))
                {
                    return null;
                }
            }
            else if (!this.mergeItemStack(var4, 3, 39, false))
            {
                return null;
            }

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

            if (var4.stackSize == var2.stackSize)
            {
                return null;
            }

            var3.onPickupFromSlot(var4);
        }

        return var2;
   }
}

 

Block

package spmod.dynamictools.common.blocks;

import java.util.List;

import net.minecraft.src.Block;
import net.minecraft.src.BlockContainer;
import net.minecraft.src.CreativeTabs;
import net.minecraft.src.EntityLiving;
import net.minecraft.src.EntityPlayer;
import net.minecraft.src.ItemStack;
import net.minecraft.src.Material;
import net.minecraft.src.MathHelper;
import net.minecraft.src.TileEntity;
import net.minecraft.src.World;
import net.minecraftforge.common.ForgeDirection;
import spmod.api.common.lib.DTTextures;
import spmod.dynamictools.DynamicTools;
import spmod.dynamictools.common.tileentities.TileAdvWorkbench;
import spmod.dynamictools.common.tileentities.TileCobbleStorage;
import spmod.dynamictools.common.config.DTBlocks;
import spmod.dynamictools.common.lib.DTGuis;

public class BlockAdvancedToolbench extends BlockContainer
{
boolean isPowered = false;
public static DTTextures id;
public BlockAdvancedToolbench(int id)
{
	super(id, Material.rock);
	setHardness(1.0F);
	setResistance(5.0F);
	this.setCreativeTab(CreativeTabs.tabFood);
	if(isPowered)
	{
		setLightValue(2.0F);
	}
}


    public void getSubBlocks(int par1, CreativeTabs par2CreativeTabs, List par3)
    {
        par3.add(new ItemStack(par1, 1, 0));
        par3.add(new ItemStack(par1, 1, 1));
    }
    
    

public boolean onBlockActivated(World par1, int par2, int par3, int par4, EntityPlayer par5, int par6, float par7, float par8, float par9)
{


	if(par5.isSneaking())
	{
		return false;
	}

	if(!par1.isRemote)
	{
		int meta = par1.getBlockMetadata(par2, par3, par4);



		if(meta == 0)	
		{
				par5.openGui(DynamicTools.instance, DTGuis.advancedtoolworkbench, par1, par2, par3, par4);
				return true;

		}
		else if(meta == 1)
		{
			par5.openGui(DynamicTools.instance, DTGuis.cobblestorage, par1, par2, par3, par4);
			return true;
		}
		else
		{
			return true;
		}

	}
	return true;
}

public void onNeighborBlockChange(World par1World, int par2, int par3, int par4, int par5)
{
	int meta = par1World.getBlockMetadata(par2, par3, par4);
	if(meta == 0)
	{
		if(isPowered && !par1World.isBlockIndirectlyGettingPowered(par2, par3, par4))
		{
			isPowered = false;
		}
		else if (!this.isPowered && par1World.isBlockIndirectlyGettingPowered(par2, par3, par4))
		{
			isPowered = true;
		}
	}
}


public int getBlockTextureFromSideAndMetadata(int side, int meta)
{
	if(meta == 0)
	{
		if(side == 0 || side == 1)
		{
			return id.ADT0;
		}
		else if(side == 2) // front
		{
			if(isPowered)
			{
				return id.ADT2;
			}
			else
			{
				return id.ADT1;
			}

		}
		else if(side == 3)
		{
			return id.ADT3;
		}
		else if(side == 4)
		{
			return id.ADT4;
		}
		else
		{
			return id.ADT5;
		}
	}
	else if(meta == 1)
	{
		return 100;
	}
	else
	{
		return 256;
	}
}

@Override
public TileEntity createNewTileEntity(World world, int meta) 
{
	if(meta == 0)
	{
		return new TileAdvWorkbench();

	}
	else if(meta == 1)
	{

		return new TileCobbleStorage();
	}
	else
	{
		return null;
	}
}

@Override
public TileEntity createNewTileEntity(World var1) 
{
	return null;
}





}

 

a view things to know i didnt know at that time how to make stack in slot. it works but i crashes the game.

and the tile Cobblestorage is nothing else as a cobblechest. But thats not the part of interest.

 

I hope i can help you with that.

Link to comment
Share on other sites

  • 2 weeks later...

I'm not sure exactly if what you said is what I want. So I'll clarify.

 

A furnace with 3 input slots, one fuel slot, and one output slot. like this:

 

[input 1]

 

[input 2]          [fuel]    =    [output]

 

[input 3]

 

I already have the slots, and the first input slot works just like a normal furnace, but not the other two.

The 3 input slots need to function like a shapeless recipe. They also need to know if there are 1, 2 or 3 items and act accordingly.

I only have very very basic java knowledge, but I know I need to start with some sort of array/hashmap.

 

Now could you help me?

Link to comment
Share on other sites

Which one of your machinces?!?! I'm looking at the mod files, and there are 3 different machines from what I can see.

TEProcessor is a superclass of TESC and TEC. Both of them only use 1 input, but it can be easily configured for three.

Alright, I've looked at the code, however I'm still in the process of learning java, so how would I configure your processor to my liking?

Link to comment
Share on other sites

Which one of your machinces?!?! I'm looking at the mod files, and there are 3 different machines from what I can see.

TEProcessor is a superclass of TESC and TEC. Both of them only use 1 input, but it can be easily configured for three.

Alright, I've looked at the code, however I'm still in the process of learning java, so how would I configure your processor to my liking?

It's really just a matter of passing multiple arguments into ProcessorRecipeManager.getRecipe(). Assuming you have only three slots, you want something like this:

 

@Override
protected boolean dryMergeOutputsAndFeed(){
	for(int i = 0; i<3; i++){
		if(this.inventory[i]==null){
	            this.activeRecipe = null;
	            this.waitingOutputs = null;
                            return false;
                        }
                }
			this.activeRecipe = mymod.prmCrusher.getRecipe(this.inventory);
			this.waitingOutputs = this.activeRecipe.getOutputs(this);
			boolean flag = true;
			if(this.activeRecipe!=null){
				flag = flag&&this.container.dryMerge(this.waitingOutputs[0],40,42,false)>=this.waitingOutputs[0].stackSize;
				if(this.waitingOutputs.length==2){
					flag = flag&&this.container.dryMerge(this.waitingOutputs[1],42,44,false)>=this.waitingOutputs[1].stackSize;
				}
				if(flag){
					this.decrStackSize(i,this.activeRecipe.getInputs()[0].stackSize);
					return true;
				}
			}
		}
	}
	this.activeRecipe = null;
	this.waitingOutputs = null;
	return false;
}

 

BEWARE OF GOD

---

Co-author of Pentachoron Labs' SBFP Tech.

Link to comment
Share on other sites

Which one of your machinces?!?! I'm looking at the mod files, and there are 3 different machines from what I can see.

TEProcessor is a superclass of TESC and TEC. Both of them only use 1 input, but it can be easily configured for three.

Alright, I've looked at the code, however I'm still in the process of learning java, so how would I configure your processor to my liking?

It's really just a matter of passing multiple arguments into ProcessorRecipeManager.getRecipe(). Assuming you have only three slots, you want something like this:

 

@Override
protected boolean dryMergeOutputsAndFeed(){
	for(int i = 0; i<3; i++){
		if(this.inventory[i]==null){
	            this.activeRecipe = null;
	            this.waitingOutputs = null;
                            return false;
                        }
                }
			this.activeRecipe = mymod.prmCrusher.getRecipe(this.inventory);
			this.waitingOutputs = this.activeRecipe.getOutputs(this);
			boolean flag = true;
			if(this.activeRecipe!=null){
				flag = flag&&this.container.dryMerge(this.waitingOutputs[0],40,42,false)>=this.waitingOutputs[0].stackSize;
				if(this.waitingOutputs.length==2){
					flag = flag&&this.container.dryMerge(this.waitingOutputs[1],42,44,false)>=this.waitingOutputs[1].stackSize;
				}
				if(flag){
					this.decrStackSize(i,this.activeRecipe.getInputs()[0].stackSize);
					return true;
				}
			}
		}
	}
	this.activeRecipe = null;
	this.waitingOutputs = null;
	return false;
}

 

The furnace itslef will have 5 slots, but 3 of them will be the items to be smelted. one will be fuel, and the other the output. Is that what this code will help with?

Link to comment
Share on other sites

Which one of your machinces?!?! I'm looking at the mod files, and there are 3 different machines from what I can see.

TEProcessor is a superclass of TESC and TEC. Both of them only use 1 input, but it can be easily configured for three.

Alright, I've looked at the code, however I'm still in the process of learning java, so how would I configure your processor to my liking?

It's really just a matter of passing multiple arguments into ProcessorRecipeManager.getRecipe(). Assuming you have only three slots, you want something like this:

 

@Override
protected boolean dryMergeOutputsAndFeed(){
	for(int i = 0; i<3; i++){
		if(this.inventory[i]==null){
	            this.activeRecipe = null;
	            this.waitingOutputs = null;
                            return false;
                        }
                }
			this.activeRecipe = mymod.prmCrusher.getRecipe(this.inventory);
			this.waitingOutputs = this.activeRecipe.getOutputs(this);
			boolean flag = true;
			if(this.activeRecipe!=null){
				flag = flag&&this.container.dryMerge(this.waitingOutputs[0],40,42,false)>=this.waitingOutputs[0].stackSize;
				if(this.waitingOutputs.length==2){
					flag = flag&&this.container.dryMerge(this.waitingOutputs[1],42,44,false)>=this.waitingOutputs[1].stackSize;
				}
				if(flag){
					this.decrStackSize(i,this.activeRecipe.getInputs()[0].stackSize);
					return true;
				}
			}
		}
	}
	this.activeRecipe = null;
	this.waitingOutputs = null;
	return false;
}

 

The furnace itslef will have 5 slots, but 3 of them will be the items to be smelted. one will be fuel, and the other the output. Is that what this code will help with?

Yep. Although you will have to put an extra check in there for the fuel. And decrease it as appropriate. Frankly, you might be better off writing your own class :P

BEWARE OF GOD

---

Co-author of Pentachoron Labs' SBFP Tech.

Link to comment
Share on other sites

  • 2 weeks later...
Guest
This topic is now closed to further replies.



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • The future of Bitcoin recovery is a topic of great interest and excitement, particularly with the emergence of innovative companies like Dexdert Net Pro Recovery leading the charge. As the cryptocurrency market continues to evolve and face new challenges, the need for effective solutions to help users recover lost or stolen Bitcoin has become increasingly critical. Dexdert Net Pro, a specialized firm dedicated to this very purpose, has positioned itself at the forefront of this emerging field. Through their proprietary techniques and deep expertise in blockchain technology, Dexdert Net Pro has developed a comprehensive approach to tracking down and retrieving misplaced or compromised Bitcoin, providing a lifeline to individuals and businesses who have fallen victim to the inherent risks of the digital currency landscape. Their team of seasoned investigators and cryptography experts employ a meticulous, multi-pronged strategy, leveraging advanced data analysis, forensic techniques, and collaborative partnerships with law enforcement to painstakingly trace the movement of lost or stolen coins, often recovering funds that would otherwise be considered irrecoverable. This pioneering work not only restores financial assets but also helps to bolster confidence and trust in the long-term viability of Bitcoin, cementing Dexdert Net Pro role as a crucial player in shaping the future of cryptocurrency recovery and security. As the digital finance ecosystem continues to evolve, the importance of innovative solutions like those offered by Dexdert Net Pro will only grow, ensuring that users can navigate the complexities of Bitcoin with greater peace of mind and protection. Call Dexdert Net Pro now     
    • I'm developing a dimension, but it's kinda resource intensive so some times during player teleporting it lags behind making the player phase down into the void, so im trying to implement some kind of pregeneration to force the game loading a small set of chunks in the are the player will teleport to. Some of the things i've tried like using ServerLevel and ServerChunkCache methods like getChunk() dont actually trigger chunk generation if the chunk isn't already on persistent storage (already generated) or placing tickets, but that doesn't work either. Ideally i should be able to check when the task has ended too. I've peeked around some pregen engines, but they're too complex for my current understanding of the system of which I have just a basic understanding (how ServerLevel ,ServerChunkCache  and ChunkMap work) of. Any tips or other classes I should be looking into to understand how to do this correctly?
    • https://mclo.gs/4UC49Ao
    • Way back in the Forge 1.17 days, work started for adding JPMS (Java Platform Module Support) to ModLauncher and ForgeModLoader. This has been used internally by Forge and some libraries for a while now, but mods (those with mods.toml specifically) have not been able to take advantage of it. As of Forge 1.21.1 and 1.21.3, this is now possible!   What is JPMS and what does it mean for modders? JPMS is the Java Platform Module System, introduced in Java 9. It allows you to define modules, which are collections of packages and resources that can be exported or hidden from other modules. This allows for much more fine-tuned control over visibility, cleaner syntax for service declarations and support for sealed types across packages. For example, you might have a mod with a module called `com.example.mod` that exports `com.example.mod.api` and `com.example.mod.impl` to other mods, but hides `com.example.mod.internal` from them. This would allow you to have a clean API for other mods to use, while keeping your internal implementation details hidden from IDE hints, helping prevent accidental usage of internals that might break without prior notice. This is particularly useful if you'd like to use public records with module-private constructors or partially module-private record components, as you can create a sealed interface that only your record implements, having the interface be exported and the record hidden. It's also nice for declaring and using services, as you'll get compile-time errors from the Java compiler for typos and the like, rather than deferring to runtime errors. In more advanced cases, you can also have public methods that are only accessible to specific other modules -- handy if you want internal interactions between multiple of your own mods.   How do I bypass it? We understand there may be drama in implementing a system that prevents mods from accessing each other's internals when necessary (like when a mod is abandoned or you need to fix a compat issue) -- after all, we are already modding a game that doesn't have explicit support for Java mods yet. We have already thought of this and are offering APIs from day one to selectively bypass module restrictions. Let me be clear: Forge mods are not required to use JPMS. If you don't want to use it, you don't have to. The default behaviour is to have fully open, fully exported automatic modules. In Java, you can use the `Add-Opens` and `Add-Exports` manifest attributes to selectively bypass module restrictions of other mods at launch time, and we've added explicit support for these when loading your Forge mods. At compile-time, you can use existing solutions such as the extra-java-module-info Gradle plugin to deal with non-modular dependencies and add extra opens and exports to other modules. Here's an example on how to make the internal package `com.example.examplemod.internal` open to your mod in your build.gradle: tasks.named('jar', Jar) { manifest { attributes([ 'Add-Opens' : 'com.example.examplemod/com.example.examplemod.internal' 'Specification-Title' : mod_id, 'Specification-Vendor' : mod_authors // (...) ]) } } With the above in your mod's jar manifest, you can now reflectively access the classes inside that internal package. Multiple entries are separated with a space, as per Java's official spec. You can also use Add-Exports to directly call without reflection, however you'd need to use the Gradle plugin mentioned earlier to be able to compile. The syntax for Add-Exports is the same as Add-Opens, and instructions for the compile-time step with the Gradle plugin are detailed later in this post. Remember to prefer the opens and exports keywords inside module-info.java for sources you control. The Add-Opens/Add-Exports attributes are only intended for forcing open other mods.   What else is new with module support? Previously, the runtime module name was always forced to the first mod ID in your `mods.toml` file and all packages were forced fully open and exported. Module names are now distinguished from mod IDs, meaning the module name in your module-info.java can be different from the mod ID in your `mods.toml`. This allows you to have a more descriptive module name that doesn't have to be the same as your mod ID, however we strongly recommend including your mod ID as part of your module name to aid troubleshooting. The `Automatic-Module-Name` manifest attribute is now also honoured, allowing you to specify a module name for your mod without needing to create a `module-info.java` file. This is particularly useful for mods that don't care about JPMS features but want to have a more descriptive module name and easier integration with other mods that do use JPMS.   How do I use it? The first step is to create a `module-info.java` file in your mod's source directory. This file should be in the same package as your main mod class, and should look something like this: open module com.example.examplemod { requires net.minecraftforge.eventbus; requires net.minecraftforge.fmlcore; requires net.minecraftforge.forge; requires net.minecraftforge.javafmlmod; requires net.minecraftforge.mergetool.api; requires org.slf4j; requires logging; } For now, we're leaving the whole module open to reflection, which is a good starting point. When we know we want to close something off, we can remove the open modifier from the module and open or export individual packages instead. Remember that you need to be open to Forge (module name net.minecraftforge.forge), otherwise it can't call your mod's constructor. Next is fixing modules in Gradle. While Forge and Java support modules properly, Gradle does not put automatic modules on the module path by default, meaning that the logging module (from com.mojang:logging) is not found. To fix this, add the Gradle plugin and add a compile-time module definition for that Mojang library: plugins { // (...) id 'org.gradlex.extra-java-module-info' version "1.9" } // (...) extraJavaModuleInfo { failOnMissingModuleInfo = false automaticModule("com.mojang:logging", "logging") } The automatic module override specified in your build.gradle should match the runtime one to avoid errors. You can do the same for any library or mod dependency that is missing either a module-info or explicit Automatic-Module-Name, however be aware that you may need to update your mod once said library adds one. That's all you need to get started with module support in your mods. You can learn more about modules and how to use them at dev.java.
    • Faire la mise à jour grâce à ce lien m'a aider personnellement, merci à @Paint_Ninja. https://www.amd.com/en/support 
  • Topics

×
×
  • Create New...

Important Information

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