Data Driven Donuts

I wrote an article recently about my initial attempts to data drive Minecraft. Since then I’ve made a lot of progress with the system. I can create block items, spawn eggs, armor, tools, and food. I’ve added a spell system and can now attach spells to items. I can make items compostable. I can add data-driven effects that can be applied when an item is eaten, or if an item takes damage. I can change color tints on textures.

I also have data driven blocks of various types, including crops, hay, nests, and traps.

I can do all this without writing a single line of Java. It’s all done via JSON. And to prove it I’m going to talk about the new item (or rather, items) I added this morning: a Jam Donut.

As always you can find the source code in my github repository.

Textures

To start with I created a few new textures for the items I wanted to add. Jam donuts need to be cooked, so I had to have a raw donut. You also need jam to fill the donut so I had to add a texture for that as well:

I’m not the best artist, but I’m okay with how these came out.

The Data

When it comes to data driving Minecraft is almost but not quite there. A lot of the work for adding an item can already be done through JSON. First we have localisation, which we can just add a few lines to the en_us.json:

  "item.docwheat.bottle_jam": "Bottle of Jam",
  "item.docwheat.uncooked_jam_donut": "Uncooked Jam Donut",
  "item.docwheat.jam_donut": "Jam Donut"

Next is the model which tells the item what texture to used. Note that the name of the JSON file is the same as the item’s registry name.

bottle_jam.json:

{
  "parent": "item/generated",
  "textures": {
    "layer0": "docwheat:item/bottle_jam"
  }
}

The other model files look exactly the same except the name of the texture refers to the texture we created.

Finally we have the recipes. Minecraft allows us to edit this through JSON as well. For this item I only needed a couple of simple recipes.

bottle_jam.json:

@@ -0,0 +1,17 @@
{
  "type": "minecraft:crafting_shapeless",
  "ingredients": [
    {
      "item": "minecraft:sweet_berries"
    },
    {
      "item": "minecraft:glass_bottle"
    },
    {
      "item": "minecraft:sugar"
    }
  ],
  "result": {
    "item": "docwheat:bottle_jam"
  }
}

Jam is made using a shapeless recipe. In this mod you basically stuff berries and sugar into a bottle and it makes jam. Not 100% realistic, but I’m okay with that.

uncooked_jam_donut:

{
  "type": "minecraft:crafting_shaped",
  "pattern": [
    " A ",
    "ABA",
    " A "
  ],
  "key": {
    "A": {
      "item": "docwheat:dough"
    },
    "B": {
      "item": "docwheat:bottle_jam"
    }
  },
  "result": {
    "item": "docwheat:uncooked_jam_donut"
  }
}

A shaped recipe where we stuff the jam into some dough. I’m aware that jam is usually added after the dough is cooked, but I needed a way to differentiate the recipe from a normal ring donut.

jam_donut.json:

{
  "type": "minecraft:smoking",
  "ingredient": {
    "item": "docwheat:uncooked_jam_donut"
  },
  "result": "docwheat:jam_donut",
  "experience": 0.35,
  "cookingtime": 100
}

Stick it in a smoker and cook it and you now have a tasty jam donut. Yum!

That’s the end of what we can do in vanilla minecraft. Normally a modder would have to start writing some JSON code to create and add a new item to the registry. Luckily we have the…

Item Data Manager

The data driving system I have is based on a group of Data Managers that get created when Forge loads. The base data manager class provides the ability to parse a folder of JSON files and load each file one by one. It also provides a group of helper functions for parsing the JSON data within the files.

The actual parsing of the JSON data is done in various subclasses, and in this case it’s the Item Data Manager that does most of the work. I won’t go over the entire code in this article, but if you look at the deserialize function you can see the JSON attributes that can be read, and the types of items that can be created. This file can’t handle all types of items – but I expand upon it whenever I need to data drive something new. For example, I only recently added the ability to create armor, and I added a new item attribute to support the Healing Amulet I added recently.

The Item Data Manager also makes use of two other data managers: the Armor Material Data Manager so we can define materials on Armor, and the Effects Data Manager so we can add custom effects.

Using all of this, defining our items are really simple. The registry name of an item comes from the name of the JSON file in our data/items folder.

bottle_jam.json:

{
    "type": "item",
    "group": "food",
    "food": {
        "hunger": 2,
        "saturation": 1.0
    },
    "container": "minecraft:glass_bottle"
}

The type is a normal item. This works because food data can be attached to any item in vanilla Minecraft. The group defines where in the creative menu the item appears. Obviously we want it with the rest of the food.

Next we define the food properties. Eating jam will restore 2 points of hunger and add 1 saturation.

Finally we set the container to a glass bottle. This means that if we eat the jam we will keep the glass bottle. It also means that if we use jam in a recipe, the glass bottle will remain behind.

uncooked_jam_donut.json:

{
    "type": "item",
    "group": "food",
    "food": {
        "hunger": 9,
        "saturation": 6.0,
        "effects": [
            {
                "effect_type": "docwheat:food_poisoning",
                "probability": 0.3
            }
        ]
    }
}

Like the bottle of jam, this is a food item. It restores more hunger and saturation if eaten, but it also has a 30% chance of causing the food poisoning effect. Effects are also data driven with the Effects Data Manager. I did this because I wanted to be able to reuse the effects for different food items – I have a lot of raw/uncooked food in the mod that uses the same effect.

jam_donut.json:

{
    "type": "item",
    "group": "food",
    "food": {
        "hunger": 9,
        "saturation": 6.0
    }
}

This is basically the same as an uncooked jam donut, except there is no chance of causing food poisoning.

Done

And that’s it. A couple of images, a few JSON files and we now have a new feature in our mod. And if there are any bugs, or I want to alter things slightly in the future, all I need to do is tweak a few values in the JSON files.

Om nom nom!

If you want to check it out the full commit is here, and if you look through it you will see that there are zero changes to the Java code. It’s all data, as it should be.