Jump to content

How to Avoid Using Int Enchant IDs in JSON Recipes


codahq

Recommended Posts

I'm trying to update my mod to 1.12.2.  Some of my recipes return books with stored enchants.  I can't figure out how to do this without using NBT and the int IDs of the enchants.  

 

 

According to @diesieben07 they should never be used.  How do I avoid using them in this scenario?  For example, I am using this as a recipe.  

 

{
    "type": "minecraft:crafting_shaped",
    "pattern":
    [
        "pbp",
        " p "
    ],
    "key":
    {
        "p":
        {
            "item": "minecraft:ender_pearl"
        },
        "b":
        {
            "item": "minecraft:book"
        }
    },
    "result":
    {
        "item": "minecraft:enchanted_book",
        "nbt": 
        {
            "StoredEnchantments": 
            [
                {
                    "id": 32,
                    "lvl": 1
                }
            ]
        }
    }
}

 

How can this be done without the int ID.  This is especially important since I also have custom enchants.

Edited by codahq
Additional Information:
Link to comment
Share on other sites

It took me a little while to figure this out because there aren't really that many examples out there but thanks for getting me on correct path.  Here is what I ended up doing.

 

JSON recipe:

{
    "type": "pearlmod:shaped_enchanting_book_recipe",
    "pattern": 
    [
        "fbf",
        " p "
    ],

    "key": 
    {
        "p": 
        {
            "item": "minecraft:ender_pearl"
        },

        "b": 
        {
            "item": "minecraft:book"
        },

        "f": 
        {
            "item": "minecraft:feather"
        }
    },

    "result": 
    {
        "item": "minecraft:enchanted_book",
        "enchantments": 
        [
            {
                "enchant": "minecraft:infinity",
                "lvl": 1
            }
        ]
    }
}

 

Parse method on recipe factory:

@Override
	public IRecipe parse(JsonContext context, JsonObject json)
	{
		ShapedOreRecipe recipe = ShapedOreRecipe.factory(context, json);
		ItemStack output = recipe.getRecipeOutput();

		final JsonObject result = JsonUtils.getJsonObject(json, "result");
		final String item = JsonUtils.getString(result, "item");
		assert item == "minecraft:enchanted_book";
		final JsonArray enchantments = JsonUtils.getJsonArray(result, "enchantments");
		for (JsonElement e : enchantments)
		{
			final String enchant = JsonUtils.getString(e.getAsJsonObject(), "enchant");
			final int lvl = JsonUtils.getInt(e.getAsJsonObject(), "lvl");
			EnchantmentData storedEnchant = new EnchantmentData(Enchantment.getEnchantmentByLocation(enchant), lvl);
			ItemEnchantedBook.addEnchantment(output, storedEnchant);
		}

		ShapedPrimer primer = new ShapedPrimer();
		primer.width = recipe.getRecipeWidth();
		primer.height = recipe.getRecipeHeight();
		primer.mirrored = JsonUtils.getBoolean(json, "mirrored", true);
		primer.input = recipe.func_192400_c();

		return new ShapedEnchantingBookRecipe(new ResourceLocation(Constants.modid, "shaped_enchanting_book_recipe"), output, primer);
	}

 

I'm not sure if there was a more effective way of parsing the JSON or not.  I'm not familiar with teh goog's JSON library and I didn't find any quick examples so I just fudged this together quickly.

 

At any rate, this works.  If anybody has a suggestion to make it better please contribute to the example.

Link to comment
Share on other sites

So, embarrassingly enough this doesn't work but I didn't notice because I didn't test it very well. 

 

At any rate, it works with the OOB enchants but it doesn't work with the custom enchants.  In parse it stores an int for the custom enchant's without using resource location for compatibility so it's just an int ID in NBT.  But by the time you are in-game and the recipe class's getCraftingResult method is called those enchant IDs have been changed.  Since I can't control when EITHER of the registry events happen (recipe factory or enchant registering), what am I supposed to do now?'

 

I guess I could store NBT data in the stack so I can find it later and just build the output stack when getCraftingResult is called but won't that break NEI, JEI, etc?

Link to comment
Share on other sites

5 hours ago, codahq said:

what am I supposed to do now?

Write your own IRecipe implementation. Potentially just override getResult() from one of the ShapedRecipes. (I think that is the methods name). And have it return a new ItemStack with the EnchantmentData that is stored in your IRecipe implementation.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

Here's an example:

https://github.com/Draco18s/ReasonableRealism/blob/1.14.4/src/main/java/com/draco18s/hardlib/api/recipe/RecipeTagOutput.java

My recipe returns an output based on tags (as all things tagged as iron (copper, steel, tin...) ingots (dust, nuggets...) are all functionally iron ingots, and all I want is to have an iron ingot output, find all items tagged as iron ingot and get the first one), but the general process would be the same for grabbing enchantments by registry name.

Edited by Draco18s

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Yes, thank you to both of you.  I understand that I need to implement logic on the result.  I'm not able to just implement logic in parse as I was doing previously.  The dilemma now is that the result itemstack that I give during parse (and pre-init) is different than the result itemstack that I would give during recipe use and when getCraftingResult is called in-game.

 

For example...  the id in the NBT for stored enchant in pre-init is assigned to, let's say 85, and written to the item stack.  But if I call Enchantment.getEnchantmentbyId(85) in-game that enchant ID has been moved since pre-init and it fails to find an enchant with 85.  If I get the id again with the resource location it returns 95 let's say.

 

So, if I use the old result with the old ID it has bad enchantment data in it.  I can recreate the output (which I'm doing in the current implementation in getCraftingResult) by getting the new id from the resource location but that breaks mods like JEI, NEI which must be caching or grabbing data created during pre-init.  

 

Doesn't that bother anybody?  That I have to return two different stacks?  Or is that the way it should be?  Shouldn't those stacks be the same?  Wouldn't you think the factory event should fire AFTER the enchant IDs are moved so that the result that is saved during the factory's parse stores a recipe result with the current enchant IDs?

Link to comment
Share on other sites

34 minutes ago, codahq said:

For example...  the id in the NBT for stored enchant in pre-init is assigned to, let's say 85, and written to the item stack.  But if I call Enchantment.getEnchantmentbyId(85) in-game that enchant ID has been moved since pre-init and it fails to find an enchant with 85.  If I get the id again with the resource location it returns 95 let's say.

And this is why you don't used numerical IDs anywhere ever.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

3 hours ago, Draco18s said:

And this is why you don't used numerical IDs anywhere ever.

I'm not.  You're not getting it yet.  I'm using the resource location as is best practice.  Minecraft/forge is assigning the int ID.  Then it runs the recipe factories and builds the result with the first IDs.  Then at some point it changes the IDs.  Eventually in game when I use the same resource location I get a different ID back.  The recipe output built during pre-init has the wrong IDs.  Do you understand?

Edited by codahq
*spelling
Link to comment
Share on other sites

Let me tee it up for you.  See the attached code examples:

 

The output:

[22:24:34] [main/INFO] [STDOUT]: [me.bendy.pearlmod.recipe.ShapedEnchantingBookRecipeFactory:parse:48]: pre-init :: location: pearlmod:ender_stability id: 11 lvl: 1

 

And when I use the recipe in a table in-game later on:

[22:25:31] [Server thread/INFO] [STDOUT]: [me.bendy.pearlmod.recipe.ShapedEnchantingBookRecipeFactory$ShapedEnchantingBookRecipe:getCraftingResult:91]: in-game :: location: pearlmod:ender_stability id: 90 lvl: 1

 

PearlmodEnchants.java ShapedEnchantingBookRecipeFactory.java _factories.json book_ender_stability.json

Link to comment
Share on other sites

11 hours ago, codahq said:

Doesn't that bother anybody?  That I have to return two different stacks?

Why would you have to return two different stacks?

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

5 hours ago, Animefan8888 said:

Why would you have to return two different stacks?

Because forge has changed the int IDs of the enchants since the factories were called.  If I don't return a different stack, when the recipe is used the first stack is returned with IDs that no longer match any enchants.  Since the IDs are not the same anymore it the ItemStack shows as an enchanted book with stored enchants but the stored enchants are missing.

Link to comment
Share on other sites

2 minutes ago, codahq said:

Because forge has changed the int IDs of the enchants since the factories were called.  If I don't return a different stack, when the recipe is used the first stack is returned with IDs that no longer match any enchants.  Since the IDs are not the same anymore it the ItemStack shows as an enchanted book with stored enchants but the stored enchants are missing.

Why not just return one stack...Pass in the raw enchantment data. IE the registry names and levels. Then compute the enchantments after the registry has been loaded. In both the output methods in your IRecipe implementation because it appears you are only doing it in one.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

That exactly what I did in my workaround.  I decided to put the resource location and level in the factory ItemStack so it would be there for easy access in getCraftingResult.  This is still a problem though because apparently mods like NEI/JEI look and cache recipes during pre-init or shortly afterwards.  If I don't put the wrong, soon-to-be-replaced enchants on the books during factory pre-init they won't show up in those mods.  

 

I don't need a workaround.  I don't need a solution.  I have that already.  I'm continuing to post now because I want somebody to realize and validate what I'm saying about the order of these events.  Why are the IDs changed AFTER recipe registration instead of before?  Or why aren't they adjusted?  I have to return ItemStacks with two different IDs for the same enchant for this to work.  The order should be changed so that I don't have to do that OR when the IDs are changed by forge forge SHOULD go to all of the places they are used and update them.

Link to comment
Share on other sites

6 hours ago, codahq said:

I'm continuing to post now because I want somebody to realize and validate what I'm saying about the order of these events.

It didn't replicate the issue when I downloaded your file you sent.
 

Quote

[04:02:58] [main/INFO] [STDOUT]: [me.bendy.pearlmod.recipe.ShapedEnchantingBookRecipeFactory:parse:47]: pre-init :: location: blah:stability id: 11 lvl: 1
...
[04:03:46] [Server thread/INFO] [STDOUT]: [me.bendy.pearlmod.recipe.ShapedEnchantingBookRecipeFactory$ShapedEnchantingBookRecipe:getCraftingResult:90]: in-game :: location: blah:stability id: 11 lvl: 1

Try creating a new world.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

9 hours ago, codahq said:

This is still a problem though because apparently mods like NEI/JEI look and cache recipes during pre-init or shortly afterwards. 

That's their problem and they should fix it.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • C:\Minecraft Server>java -Xmx4096M -Xms1024M -jar server.jar nogui Starting net.minecraft.server.Main ERROR StatusConsoleListener Unable to delete file C:\Minecraft Server\logs\latest.log: java.nio.file.FileSystemException C:\Minecraft Server\logs\latest.log: The process cannot access the file because it is being used by another process ^CTerminate batch job (Y/N)?
    • Oke i tried to download a different mod and try that out on my server and i get the same error. Now i know for a fact that my port forwarding and server is working properly, because i can join them without adding any mods into the server file, but then i dont know what i am doing wrong 
    • Salutation to you ladies and gentlemen, i must confidently say a very big thanks to Fastfundrecovery8 AT GMAIL COM for their tremendous action taken over my case immediately brought to their table, i saw how the whole process was going, and i wisperred to myself and said indeed i am previlledge to know such a legitimate recovery company who is very understable and do not stress their client over recovery software tools, Fastfunds Recovery are good in keeping to time, punctuality, I was scammed last year December 18, i realized that my long investment which i inteded to withdraw has long been a scam, got so frustrated, hired 4 recovery hackers which ended up taking money from me and i couldn't contact them anymore, i went through emotional pains and betrayer, wasn't easy for me at that moment, am very greatful for FastFunds Recovery, who was referred to me by a civil engineer who i was opportuned to share part of my story with and he was like i have a cyber friend do reach and say i'm from Pato's, that's how i got in touch with fastfundsrecovery8(@)gmail(.)com, do inform FastFunds recovery for any cyber issues. Fastfundsrecovery8 AT GMAIL WILL ALWAYS HELP GET BACK YOUR FUNDS.
    • Hello everyone i have made a server with forge and have added pixelmon into the server. But for some reason i keep getting "Internal Exception: io.netty.handles.codec.DecoderException: Not enough bytes in buffer, expected 105, byt got 48". I tried upping the ram of the server to 2GB but it didnt solve anything. I have 16 GB of ram on my pc (where i host the server), but i cant seem to get it to work. Pixelmon does work when i try to go into singleplayer, but for some reason just doesnt work online   Edit: server logs sais nothing aswell [18:55:49] [ServerMain/INFO]: Environment: Environment[accountsHost=https://api.mojang.com, sessionHost=https://sessionserver.mojang.com, servicesHost=https://api.minecraftservices.com, name=PROD] [18:55:50] [ServerMain/INFO]: Loaded 7 recipes [18:55:51] [ServerMain/INFO]: Loaded 1271 advancements [18:55:51] [Server thread/INFO]: Starting minecraft server version 1.20.2 [18:55:51] [Server thread/INFO]: Loading properties [18:55:51] [Server thread/INFO]: Default game type: SURVIVAL [18:55:51] [Server thread/INFO]: Generating keypair [18:55:51] [Server thread/INFO]: Starting Minecraft server on *:xxxx [18:55:51] [Server thread/INFO]: Using default channel type [18:55:51] [Server thread/INFO]: Preparing level "world" [18:55:52] [Server thread/INFO]: Preparing start region for dimension minecraft:overworld [18:55:53] [Worker-Main-8/INFO]: Preparing spawn area: 0% [18:55:53] [Worker-Main-8/INFO]: Preparing spawn area: 0% [18:55:53] [Worker-Main-8/INFO]: Preparing spawn area: 0% [18:55:53] [Worker-Main-12/INFO]: Preparing spawn area: 0% [18:55:54] [Worker-Main-11/INFO]: Preparing spawn area: 31% [18:55:54] [Server thread/INFO]: Time elapsed: 2344 ms [18:55:54] [Server thread/INFO]: Done (2.865s)! For help, type "help" [18:55:56] [User Authenticator #1/INFO]: UUID of player kemal007023 is 9a2a1dff-fa06-4e29-b57d-b1e6afb2db87 [18:55:56] [Server thread/INFO]: kemal007023[/xxxx] logged in with entity id 271 at (9.497695306619189, 68.0, 10.973182362716573) [18:55:56] [Server thread/INFO]: kemal007023 joined the game [18:55:56] [Server thread/INFO]: kemal007023 lost connection: Disconnected [18:55:56] [Server thread/INFO]: kemal007023 left the game [18:56:00] [User Authenticator #2/INFO]: UUID of player kemal007023 is 9a2a1dff-fa06-4e29-b57d-b1e6afb2db87 [18:56:00] [Server thread/INFO]: kemal007023[xxxx] logged in with entity id 272 at (9.497695306619189, 68.0, 10.973182362716573) [18:56:00] [Server thread/INFO]: kemal007023 joined the game [18:56:00] [Server thread/INFO]: kemal007023 lost connection: Disconnected [18:56:00] [Server thread/INFO]: kemal007023 left the game  
    • Hi, im making a BlockEntity that can contain fluids, and render them in the GUI, only one fluid works perfectly, I can fill or drain it, sync it to the client, and render it. The problem comes when i try to have two fluids in the same GUI, depending on what I delete or leave, the fluids act differently; for example, deleting both of them from "saveAdditional" and "load" methods makes that the fluids cannot render. Also, it can only render one fluid alone, or again, render one fluid, but twice (copies one fluid to the other one). FYI the left one is water, the right one is a red custom fluid. How can I fix this? BoilerBlockEntity: https://pastebin.com/e6b2U3sD BoilerMenu: https://pastebin.com/D375yCNr BoilerScreen: https://pastebin.com/WMrK83Du 
  • Topics

×
×
  • Create New...

Important Information

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