Jump to content

[1.12.2] What's the best way to make a crafting recipe that just changes NBT?


Recommended Posts

Posted

What I'm trying to do is have a recipe with an item and materials based on the main item's NBT, that results in the original item with additional/changed NBT.

 

For example, if Weapon(NO NBT) is in a recipe with MaterialOne, I want to add element tag Fire resulting in Weapon(Fire), or if Weapon(Fire) is in a recipe with MaterialTwo I want to remove the tag Fire resulting in Weapon(NO NBT).

Or, if Weapon(Fire, Level1) is in a recipe with MaterialThree, I want to increase its Level tag so it becomes Weapon(Fire, Level2), etc.

 

I've only figured out a way to do this WITHOUT NBT, but unfortunately that involves creating a new item and recipe for every possible combination of element and levels, which results in around 2000 model/recipe json files to be generated for each weapon, which is obviously a bad idea.

 

What's the best way to actually DO this?

 

This is all I've got so far, but I'm not sure if it's even right, much less where to go from here.

  Reveal hidden contents

 

Posted

No you only have one item but depending on the parameters it can have different damage/effects/whateveryouwant

Sword(String name, int material, String infusion)

in your ModItem class:

 

FIRESWORD_LEVEL_TWO = new Sword(firesword_level_two,2, fire)

 

Posted
  On 5/8/2019 at 6:37 PM, SaltStation said:

No you only have one item but depending on the parameters it can have different damage/effects/whateveryouwant

Sword(String name, int material, String infusion)

in your ModItem class:

 

FIRESWORD_LEVEL_TWO = new Sword(firesword_level_two,2, fire)

 

Expand  

That's exactly my point....

 

Your way would require:

 

sword = new Sword(name, 0, none)

sword1 = new Sword(name, 1, none)

sword2 = new Sword(name, 2, none)

sword3 = new Sword(name, 3, none)

sword4 = new Sword(name, 4, none)

firesword = new Sword(name, 0, fire)

firesword1 = new Sword(name, 1, fire)

firesword2 = new Sword(name, 2, fire)

firesword3 = new Sword(name, 3, fire)

firesword4 = new Sword(name, 4, fire)

 

...and so on, for 10 levels each with 8 different elements for each level on over 200 weapons I'm adding.

That's 16,000 new items, which would then need about 100 recipes each to allow changing them to and from other variants.

 

I want to create ONE of each weapon, and just add the level and element using NBT to save literally thousands of file creations and dozens of megabytes in total file size...

Posted
  On 5/8/2019 at 6:58 PM, V0idWa1k3r said:

Loops exist.

But in your usecase sure, NBT may be preferrable.

You can make a custom IRecipe implementation that deals with the ingredients passed and determines the results.

Expand  

Loops are exactly how I already did it, resulting in thousands of items that I wanted to avoid, therefore my wanting to use NBT instead.

But I forgot IRecipe was a thing.

 

I assume I could just use something similar to how RecipeFireworks does it?

And the proper way to register it is this something like this?

@SubscribeEvent
public static void registerRecipes(Register<IRecipe> event)
{
	event.getRegistry().register(new RecipeWeapon());
}

 

Posted

The proper way is to make a _factories.json file where you would register a factory for your custom IRecipe implementation and register it though json. It may still be just one file, just registered via a json and not via a registry event.

The reason for that is once you are migrating to 1.13 and up all recipes must have a json file defining them(so they can be disabled by a datapack).

Posted (edited)
  On 5/8/2019 at 7:16 PM, V0idWa1k3r said:

The proper way is to make a _factories.json file where you would register a factory for your custom IRecipe implementation and register it though json. It may still be just one file, just registered via a json and not via a registry event.

The reason for that is once you are migrating to 1.13 and up all recipes must have a json file defining them(so they can be disabled by a datapack).

Expand  

So... something like this?

{
    "recipes": {
        "weaponvariant": "avrye.soulsstuff.util.RecipeWeapon.Factory"
    }
}

 

How am I supposed to return an IRecipe in parse()? I can't find any implementations of IRecipeFactory in the code.

All examples I can find use either outdated code or helper classes that just make things way more complicated than what I need...

package avrye.soulsstuff.util;

public class RecipeWeapon extends Impl<IRecipe> implements IRecipe
{
	// ...

	public static class Factory implements IRecipeFactory
	{
		@Override
		public IRecipe parse(JsonContext context, JsonObject json)
		{
			//TODO ?
			return null;
		}
	}
}

 

Edited by SapphireSky
Posted

If you are just using it to register your ONE particular recipe that handles all kind of cases then just return a new instance of your IRecipe implementation since you don't need to parse anything

Posted
  On 5/8/2019 at 7:52 PM, V0idWa1k3r said:

If you are just using it to register your ONE particular recipe that handles all kind of cases then just return a new instance of your IRecipe implementation since you don't need to parse anything

Expand  

That's easier than I expected then.

 

But now how exactly do I tell the IRecipe which items to be removed during crafting?

Looking at RecipeFireworks, matches() just checks to see if the needed items are available and creates the result item.

And getRemainingItems() seems relevant but doesn't check for any of the needed items, so I'm confused how that's done.

Posted
  On 5/8/2019 at 9:26 PM, V0idWa1k3r said:

 

returns a list of itemstacks that are "left" after the craft is done.

Expand  

I know but how do I tell it which items are actually used up during crafting?

I can't find anything that actually determines which items should be removed and removes them.

Posted

I repeat myself yet again

  On 5/8/2019 at 9:26 PM, V0idWa1k3r said:
  On 5/8/2019 at 8:19 PM, SapphireSky said:

getRemainingItems()

Expand  

returns a list of itemstacks that are "left" after the craft is done.

Expand  

 

If you have a recipe of AB = C and you want A to be consumed then the list would return just B. Assuming A's max stack is 1.

It is a NonNullList though, so all empty slots are ItemStack.EMPTY.

 

  On 5/9/2019 at 4:41 PM, SapphireSky said:

I can't find anything that actually determines which items should be removed and removes them.

Expand  

By default all items are consumed if their container item is empty, otherwise their container item is returned.

Posted
  On 5/9/2019 at 5:43 PM, V0idWa1k3r said:

I repeat myself yet again

 

If you have a recipe of AB = C and you want A to be consumed then the list would return just B. Assuming A's max stack is 1.

It is a NonNullList though, so all empty slots are ItemStack.EMPTY.

 

By default all items are consumed if their container item is empty, otherwise their container item is returned.

Expand  

 

That still doesn't answer my question...

HOW does the list know what to return if you're not telling it what to return?

 

matches() is basically just roughly this:

public boolean matches(InventoryCrafting inv, World world)
{
    if(inv contains materialitem && inv contains mainitem)
    {
        ItemStack result = new ItemStack(mainitem);
        result.setNBTBasedOn(materialitem);
        return true;
    }
    return false;
}

 

while getRemainingItems() contains:

public NonNullList<ItemStack> getRemainingItems(InventoryCrafting inv)
{
	NonNullList<ItemStack> nonnulllist = NonNullList.<ItemStack>withSize(inv.getSizeInventory(), ItemStack.EMPTY);
	for (int i = 0; i < nonnulllist.size(); ++i)
	{
		ItemStack itemstack = inv.getStackInSlot(i);
		nonnulllist.set(i, ForgeHooks.getContainerItem(itemstack));
	}
	return nonnulllist;
}

 

I'm still failing to see how getRemainingItems() either gets the ingredients or consumes them.

Unless I'm supposed to add to and manually pick out the items from in getRemainingItems() ?

In which case, that's not exactly obvious since that method for Fireworks or Dyed Armour doesn't do that either.

Posted
  On 5/9/2019 at 6:05 PM, SapphireSky said:

I'm still failing to see how getRemainingItems() either gets the ingredients or consumes them.

 

Expand  

I am sorry, I do not know how to be more obvious.

getRemainingItems is the list of INGREDIENTS that REMAIN in the slots AFTER the crafting is done.

It doesn't consume anything. It is what's LEFT in the slots.

The ingredients currently in the crafting table are passed to you in the parameter of the method.

The default implementation goes through all ingredients

  On 5/9/2019 at 6:05 PM, SapphireSky said:

ItemStack itemstack = inv.getStackInSlot(i);

Expand  

and does the following:

If the item has a container item(like a bucket of milk has an empty bucket as it's container item) then the container item is added, otherwise an ampty stack is.

 

You can see how the vanilla's crafting system handles it in SlotCrafting#onTake.

It iterates through all items in the crafting matrix, decreasing their stack size by 1.

Then if the stack in the slot is empty but the getRemainingItems has a non-empty stack at that position then that stack in the list is inserted into the slot.

If the stack in the slot isn't empty but is identical(NBT + meta) to the one returned by the getRemainingItems then the stack in the slot's count is incremented by the size of the stack in the list.

Otherwise the item in the list is either added to the player's inventory or dropped.

Posted
  On 5/9/2019 at 6:46 PM, V0idWa1k3r said:

You can see how the vanilla's crafting system handles it in SlotCrafting#onTake.

It iterates through all items in the crafting matrix, decreasing their stack size by 1.

.....

 

Expand  

THIS is what I was asking.....

I did not know the creation and use of the recipe were handled separately.

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.