Posted May 8, 20196 yr comment_341626 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. Spoiler public class CraftingUpgrades { @SubscribeEvent public void onCraft(ItemCraftedEvent event) { if (event.crafting != null) { ItemStack stack = event.crafting; if (stack.getItem() instanceof Weapon || stack.getItem() instanceof Shield) { ItemStack material = getUpgradeMaterial(event.craftMatrix); if (material != null) { // TODO Increase level based on material } else { material = getInfusionMaterial(event.craftMatrix); if (material != null) { // TODO Set infusion based on material } } } } } private ItemStack getUpgradeMaterial(IInventory matrix) { ItemStack stack; for (int i = 0; i < matrix.getSizeInventory(); i++) { if (matrix.getStackInSlot(i) != null) { stack = matrix.getStackInSlot(i); if (stack.getItem() instanceof UpgradeMaterial) { return stack; } } } return null; } private ItemStack getInfusionMaterial(IInventory matrix) { ItemStack stack; for (int i = 0; i < matrix.getSizeInventory(); i++) { if (matrix.getStackInSlot(i) != null) { stack = matrix.getStackInSlot(i); if (stack.getItem() instanceof InfusionGem) { return stack; } } } return null; } }
May 8, 20196 yr comment_341632 You could add additional parameters to the constructor of your sword class.
May 8, 20196 yr Author comment_341633 2 minutes ago, SaltStation said: You could add additional parameters to the constructor of your sword class. And that would help me how? Like I already said, I do not want to have thousands of instances of every variation of an item.
May 8, 20196 yr comment_341634 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)
May 8, 20196 yr Author comment_341637 1 minute ago, 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) 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...
May 8, 20196 yr comment_341638 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.
May 8, 20196 yr Author comment_341644 10 minutes ago, 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. 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()); }
May 8, 20196 yr comment_341645 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).
May 8, 20196 yr Author comment_341650 34 minutes ago, 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). 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 May 8, 20196 yr by SapphireSky
May 8, 20196 yr comment_341651 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
May 8, 20196 yr Author comment_341652 19 minutes ago, 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 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.
May 8, 20196 yr comment_341656 1 hour ago, SapphireSky said: But now how exactly do I tell the IRecipe which items to be removed during crafting? 1 hour ago, SapphireSky said: getRemainingItems() returns a list of itemstacks that are "left" after the craft is done.
May 9, 20196 yr Author comment_341730 19 hours ago, V0idWa1k3r said: returns a list of itemstacks that are "left" after the craft is done. 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.
May 9, 20196 yr comment_341739 I repeat myself yet again 20 hours ago, V0idWa1k3r said: 21 hours ago, SapphireSky said: getRemainingItems() returns a list of itemstacks that are "left" after the craft is done. 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. 1 hour ago, SapphireSky said: I can't find anything that actually determines which items should be removed and removes them. By default all items are consumed if their container item is empty, otherwise their container item is returned.
May 9, 20196 yr Author comment_341743 4 minutes ago, 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. 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.
May 9, 20196 yr comment_341749 34 minutes ago, SapphireSky said: I'm still failing to see how getRemainingItems() either gets the ingredients or consumes them. 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 37 minutes ago, SapphireSky said: ItemStack itemstack = inv.getStackInSlot(i); 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.
May 9, 20196 yr Author comment_341759 48 minutes ago, 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. ..... 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.