Convert Recipes from 1.12 to 1.11.2 in Minecraft using Linux Bash

I found a way to extract values without strange syntax using jq and with the help of the article at https://programminghistorian.org/lessons/json-and-jq

Let’s take a look at my gravel_button.json recipe:

gravel_button.json
 
  1. {
  2. "type": "forge:ore_shapeless",
  3. "ingredients": [
  4. {
  5. "item": "minecraft:gravel"
  6. },
  7. {
  8. "item": "morebeautifulbuttons:button_press"
  9. }
  10. ],
  11. "result": {
  12. "item": "morebeautifulbuttons:gravel_button"
  13. }
  14. }

 

All of my buttons are formatted in the exact same way as recipes, with the Minecraft material as the first item.

Therefore extrapolating from the article I’ve developed the command line snippet that produces:

cat gravel_button.json | jq -r '.ingredients[0].item'

This line says to send all of the JSON data from the recipe file and use it as the input for the jq (json query) program, to output the value as a raw string that is unquoted and that I want the ingredients value which is an array, that element 0 of this array is the target and in that target we’re interesting in the field named item.

This outputs the value:

minecraft:gravel

Therefore I can save this output in Bash as a variable using:

theBlock=$(cat gravel_button.json | jq -r '.ingredients[0].item')

Granted I’m still doing this at the command line and this will shine when I put it in a script using a for iteration as you will soon see.

Changing gears for a bit, let’s look at what I need from 1.11.2 to make a shapless recipe.

GameRegistry.addShapelessRecipe(new ItemStack(resultItem), minecraftItem, modItem);

In this case resultItem will be extracted from field above using jq, just the same I can extract it from the file name as I made sure the file names matched the result when I generated these in the first place. However, to be clear and accurate I’ll add a portion of script the reads it from the result block.

cat gravel_button.json | jq -r '.result.item'

which will produce the expected value of 

morebeautifulbuttons:gravel_button

the modItem for my mod is called “morebeautifulbuttons:button_press” and this will be a constant in my script. The button_press is an object that ensures that my recipes don’t collide with other mods’ recipes.

I am sure at this point some of you will inform me how to do the following on oneline or in some other better way. Please by all means share it. For now, based on my research this is how I am going about doing it.

Yeah, so based on that you know I’m gonna cat the file twice to get two different values for my script. I’ve saved the script as convertThem.sh and did chmod a+x on it to make it executable and therefore allow type ./convertThem.sh to activate it.

#!/bin/bash
# you must have jq installed for this to work

for f in *.json;
do
  theBlock=$(cat $f | jq -r '.ingredients[0].item')
  theResult=$(cat $f | jq -r '.result.item')
  echo "GameRegistry.addShapelessRecipe(new ItemStack(${theResult}), ${theBlock}, morebeautifulbuttons:button_press);" >> copyMe;
done

That’s it! Now all I have to do is open the file copyMe and copy the data to my recipes.java and I’m done with it. I have back-ported my 1.12 mod to 1.11.2. And thanks to this and the fact that I can’t tell people to bugger off, the rest of you 1.12 authors have an avenue that you can modify to your needs to back-port to 1.11.2 or other versions.

Now that you have read through that novel. There are some other things you need to consider.

  1. modid:item is not how it is represented in 1.11.2 so you will need to cut the value at the colon. Therefore use: cut -f2 -d:
    That will get you the part after the :.
  2. Most items in typical JAVA code that you will be using will be the variable references and those are uppercase, usually. Use ^^ in the variable reference for this. Example: ${theBlock^^} will uppercase the variable.
  3. On top of that you are referencing those variables against the class file they come from, in my case it is InitBlocks.
  4. The Button Press comes from the InitItems class, this also is taken into account.

My updated conversion script is as follows:

convertThem.sh
 
  1. #!/bin/bash
  2. # you must have jq installed for this to work
  3. for f in *.json;
  4. do
  5. echo "found $f"
  6. echo "extracting ingredient"
  7. tempVar=$(cat $f | jq -r '.ingredients[0].item')
  8. theBlock=$(echo "$tempVar" | cut -f2 -d:)
  9. echo "extracting result"
  10. tempVar=$(cat $f | jq -r '.result.item')
  11. theResult=$(echo "$tempVar" | cut -f2 -d:)
  12. echo "creating code fragment"
  13. echo "GameRegistry.addShapelessRecipe(new ItemStack(InitBlocks.${theResult^^}), Blocks.${theBlock^^}, InitItems.BUTTON_PRESS);" >> copyMe;
  14. done

 

The script above does not take into account the data field from the 1.12 recipes. I discovered this after testing my mod in 1.11.2 last night. While I can make this adjustment manually in the code, I’d rather not as it still way too many recipes to edit.

 

convertThem.sh
 
#!/bin/bash
# you must have jq installed for this to work
for f in *.json;
do
  echo "loading $f into memory"
  theFile=$(<"${f}")
  echo "extracting ingredient"
  theBlock=$(echo $theFile | jq -r '.ingredients[0].item' | cut -f2 -d:)
  echo "extracting meta value if it exists"
  theMeta=$(echo $theFile | jq -r '.ingredients[0].data')
  echo "extracting result"
  theResult=$(echo $theFile | jq -r '.result.item' | cut -f2 -d:)
  echo "creating code fragment"
  if [ "$theMeta" == "null" ]; then
    echo "GameRegistry.addShapelessRecipe(new ItemStack(InitBlocks.${theResult^^}), Blocks.${theBlock^^}, InitItems.BUTTON_PRESS);" >> copyMe;
  else
    echo "GameRegistry.addShapelessRecipe(new ItemStack(InitBlocks.${theResult^^}), new ItemStack(Blocks.${theBlock^^},1,${theMeta}), InitItems.BUTTON_PRESS);" >> copyMe;
  fi
done

I’ve also loaded the file into a variable so as to reduce the cat operation which is rather intensive on the system. This will provide a decent speed increase.

jq returns the value “null” for objects that do not existing in the JSON being parsed. So I test for that. When data does exist it will possess the integer value assigned to it in the JSON recipe.

FINAL