Introduction
MCpypack is a Python library to make the creation of Minecraft datapack easier.
In this book you will learn how to install MCpypack and how to use it properly.
We make the assumption that you already know how Python works.
Although you probably do not need to know a lot.
Installation
Warning
This guide only covers Linux Systems.
Python Version
MCpypack requires Python 3.14 or higher.
Run:
python --version
It should at least show:
Python 3.14.0
Virtual Environment
The next step is to create a new virtual environment in the directory of your project.
python -m venv venv
Then activate it.
source venv/bin/activate
Install MCpypack
Now you can install MCpypack via pip with the following command:
pip install MCpypack
Creating a new Datapack
Importing Datapacks
In order to create a new datapack you first have to import the Datapack class from MCpypack.
from MCpypack import Datapack
Creating Datapacks
Then you create a new datapack object using the Datapack class.
The Datapack class takes 5 arguments.
Out of them 3 are required and 2 are optional.
- Required:
name: Name of the datapack.description: Description of the datapack.version: The Minecraft version the datapack should be created for.
my_pack: Datapack = Datapack(
name="My Datapack",
description="My first datapack",
version="26.1"
)
- Optional:
relative_icon_path: Relative path to an icon that should be used for your datapack.relative_export_dir: Directory to export the datapack to. Default isexport/.
Note
Using keyword arguments is suggested to avoid confusion.
In the end you have to export your datapack using the export method.
my_pack.export()
There are 2 optional parameters for this method.
- overwrite: Whether the old version should be overwritten
(True)or get a different name(False). Default isTrue. - zip: Whether a
.zipshould be created. Default isTrue.
After creating the datapack through running the code it appears in ‘./export/’ or in the custom directory you specified in relative_export_dir.
You now can use the datapack inside Minecraft, altough it does not add any new functionality to the game yet.
Whole code
from MCpypack import Datapack
my_pack: Datapack = Datapack(
name="My Datapack",
description="My first datapack",
version="26.1"
)
my_pack.export()
Adding Namespaces
You learned how to create your first datapack. Now we want to add namespaces to that datapack.
Importing Namespaces
To add new namespaces to your datapack you use the Namespace class and the add_namespaces method from the Datapack class.
To do this we have to also import the Namespace class from MCpypack.
from MCpypack import Datapack, Namespace
Creating Namespaces
After that we can create a new datapack with a custom name.
my_namespace: Namespace = Namespace(name="my_namespace")
my_pack.add_namespaces(my_namespace)
Note
The
nameis currently the only argument the class accepts, but it is still recommended to use keyword arguments here.
Of course you can create multiple namespaces.
my_first_namespace: Namespace = Namespace(name="my_first_namespace")
my_second_namespace: Namespace = Namespace(name="my_second_namespace")
my_pack.add_namespaces(
my_first_namespace,
my_second_namespace,
)
Note
As you may have noticed we didn’t include any whitespaces ot other special characters in the names of our namespaces. This is because Minecraft has a special set of rules what characters namespace names can include.
Overwriting Game Content
Later you may want to change certain predefined aspects of the game like recipes.
To do that you have to create a new namespace named minecraft.
Whole Code
from MCpypack import Datapack, Namespace
my_pack: Datapack = Datapack(
name="My Datapack",
description="My first datapack",
version="26.1"
)
my_namespace: Namespace = Namespace(name="my_namespace")
my_pack.add_namespaces(my_namespace)
my_pack.export()
Adding Recipes
In this chapter we will discover how to create custom recipes using MCpypack.
Warning
Although creating recipes is quite easy to understand we won’t go into detail about specific recipe types and what they do. To get a better understanding of this you can inform yourself using other sources.
Important
This chapter uses features which recipes depend on but which are not explained in this chapter. These featues include:
- Item and Tag
- ItemStack
Crafting Shapeless
The first recipe type we will have a look at is the Crafting Shapeless.
New Datapack and Namespace
Let’s first create a new datapack for our new recipes we will add.
my_recipes: Datapack = Datapack(
name="My Recipes",
description="Adding missing recipes to make the world a better place.",
version="26.1",
)
We will also add a new namespace for recipes related to grass.
grass: Namespace = Namespace(
name="grass"
)
Importing
Now we can add a CraftingShapeless recipe.
We import it from MCpypack.recipe.
from MCpypack.recipe import CraftingShapeless
Note
Using CratingShapeless also requires imports from other submodules which are:
from MCpypack.utils import ItemStack from MCpypack.item.final import Item
New Recipe
The CraftingShapeless class takes the following required arguments.
name->str: The name of the recipe.ingredients->ItemLike | list[ItemLike]: Ingredients of the recipe.result->ItemStack: Result of the recipe.
You can also parse two optional arguments.
group->Group | None: String identifier for grouping recipes. Default isNone.category->CategoryLike: Recipe book category. Default isCategory.MISC.
It will then look like this.
grass_block: CraftingShapeless = CraftingShapeless(
name="grass_block",
ingredients=[Item.DIRT, Item.SHORT_GRASS],
result=ItemStack(
item_id=Item.GRASS_BLOCK,
)
)
Add to Namespace
Then we just add the recipe into our namespace
grass.add_recipes(grass_block)
Note
You can also instantly add the recipe to the namespace.
grass.add_recipes( CraftingShapeless( name="grass_block", ingredients=[Item.DIRT, Item.SHORT_GRASS], result=ItemStack( item_id=Item.GRASS_BLOCK, ) ) )
Export Datapack
Now we can export our datapack.
my_recipes.add_namespaces(grass)
my_recipes.export()
If you now add it to your Minecraft world you should be able to craft a grass block using one dirt and one short grass item regardless of how you arrange them.
Whole Code
from MCpypack import Datapack, Namespace
from MCpypack.recipe import CraftingShapeless
from MCpypack.utils import ItemStack
from MCpypack.item.final import Item
my_recipes: Datapack = Datapack(
name="My Recipes",
description="Adding missing recipes to make the world a better place.",
version="26.1",
)
grass: Namespace = Namespace(
name="grass"
)
grass.add_recipes(
CraftingShapeless(
name="grass_block",
ingredients=[Item.DIRT, Item.SHORT_GRASS],
result=ItemStack(
item_id=Item.GRASS_BLOCK,
)
)
)
my_recipes.add_namespaces(grass)
my_recipes.export()
Crafting Shaped
Now we will have a look at the Crafting Shaped recipe type.
Importing
First let’s import the CraftingShaped class from MCpypack.recipe.
from MCpypack.recipe import CraftingShaped
Note
Using
CratingShapedrequires the same additional imports asCraftinShapeless.
New Recipe
The CraftingShaped class takes the following required arguments.
name->str: The name of the recipe.pattern->list[str]: Pattern representing the crafting grid.key->dict[str, ItemLike]: All keys used inpatternand the corresponding items.result->ItemStack: Result of the recipe.
You can also parse three optional arguments.
group->Group | None: String identifier for grouping recipes. Default isNone.category->CategoryLike: Recipe book category. Default isCategory.MISC.show_notification->bool | None: Determines if a notification is shown when unlocking the recipe. Default isNone.
It will then look like this.
grass.add_recipes(
CraftingShaped(
name="grow_grass",
pattern=[
"A",
"A",
],
key={"A": Item.SHORT_GRASS},
result=ItemStack(
item_id=Item.TALL_GRASS,
)
)
)
If you now place two short grass item above each other you get one tall grass.
This recipe works even for a 2 by 2 crafting grid.
Full Grid
You can also extend it to a 3 by 3 grid.
For that we add a new namespace for mining.
mining: Namespace = Namespace(
name="mining"
)
my_recipes.add_namespaces(mining)
Now we create a new recipe in that namespace.
mining.add_recipes(
CraftingShaped(
name="diamond_in_stone",
pattern=[
"AAA",
"ABA",
"AAA",
],
key={
"A": Item.STONE,
"B": Item.DIAMOND,
},
result=ItemStack(
item_id=Item.DIAMOND_ORE,
)
)
)
Empty Fields
If you want to leave certain fields empty you just use a space for that in the string.
mining.add_recipes(
CraftingShaped(
name="best_iron_pick",
pattern=[
"AAA",
" B ",
" B ",
],
key={
"A": Item.IRON_BLOCK,
"B": Item.BLAZE_ROD,
},
result=ItemStack(
item_id=Item.IRON_PICKAXE,
components=components.ItemComponents(
components.Unbreakable(),
components.Enchantments({
Enchantment.EFFICIENCY: 10,
})
)
)
)
)
Important
For this example you also need to import the following:
from MCpypack import components from MCpypack.item.final import Enchantment
Whole code
from MCpypack import Datapack, Namespace, components
from MCpypack.recipe import CraftingShaped
from MCpypack.utils import ItemStack
from MCpypack.item.final import Item, Enchantment
my_recipes: Datapack = Datapack(
name="My Recipes",
description="Adding missing recipes to make the world a better place.",
version="26.1",
)
grass: Namespace = Namespace(
name="grass"
)
grass.add_recipes(
CraftingShaped(
name="grow_grass",
pattern=[
"A",
"A",
],
key={"A": Item.SHORT_GRASS},
result=ItemStack(
item_id=Item.TALL_GRASS,
)
)
)
mining: Namespace = Namespace(
name="mining"
)
mining.add_recipes(
CraftingShaped(
name="diamond_in_stone",
pattern=[
"AAA",
"ABA",
"AAA",
],
key={
"A": Item.STONE,
"B": Item.DIAMOND,
},
result=ItemStack(
item_id=Item.DIAMOND_ORE,
)
),
CraftingShaped(
name="best_iron_pick",
pattern=[
"AAA",
" B ",
" B ",
],
key={
"A": Item.IRON_BLOCK,
"B": Item.BLAZE_ROD,
},
result=ItemStack(
item_id=Item.IRON_PICKAXE,
components=components.ItemComponents(
components.Unbreakable(),
components.Enchantments({
Enchantment.EFFICIENCY: 10,
})
)
)
)
)
my_recipes.add_namespaces(grass, mining)
my_recipes.export()
Crafting Transmute
If you want to preserve all components of an ingredient you have to use the Crafting Transmute recipe type.
Importing
You also import the CraftingTransmute class from MCpypack.recipe.
from MCpypack.recipe import CraftingTransmute
New Recipe
The CraftingTransmute class takes the following required arguments.
name->str: The name of the recipe.input->ItemLike: Item whose components will be copied.material->ItemLike: Additional item for the recipe.result->ItemStack: Result of the recipe.
You can also parse two optional arguments.
group->Group | None: String identifier for grouping recipes. Default isNone.category->CategoryLike: Recipe book category. Default isCategory.MISC.
It will then look like this.
mining.add_recipes(
CraftingTransmute(
name="shimmer",
input=Item.DIAMOND_BLOCK,
material=Item.AMETHYST_SHARD,
result=ItemStack(
item_id=Item.DIAMOND,
components=components.ItemComponents(
components.EnchantmentGlintOverride(True)
)
)
)
)
Important
You need to import the following for this example.
from MCpypack import components
You now are able to use a diamond block and an amethyst shard to craft a diamond that shimmers and also copy the data of the diamond block.
You can also use it to keep enchantments on tools.
mining.add_recipes(
CraftingTransmute(
name="always_copper",
input=Tag.ITEM.PICKAXES,
material=Item.COPPER_BLOCK,
result=ItemStack(
item_id=Item.COPPER_PICKAXE,
)
)
)
Important
You need to import the following for this example.
from MCpypack.item.final import Tag
You can now upgrade every pickaxe to a copper pickaxe.
Note
You cannot insert a copper pickaxe as Minecraft does not allow to result to be the same as the input in
CraftingTransmuterecipes.
Whole code
from MCpypack import Datapack, Namespace, components
from MCpypack.recipe import CraftingTransmute
from MCpypack.utils import ItemStack
from MCpypack.item.final import Item, Tag
my_recipes: Datapack = Datapack(
name="My Recipes",
description="Adding missing recipes to make the world a better place.",
version="26.1",
)
mining: Namespace = Namespace(
name="mining"
)
mining.add_recipes(
CraftingTransmute(
name="shimmer",
input=Item.DIAMOND_BLOCK,
material=Item.AMETHYST_SHARD,
result=ItemStack(
item_id=Item.DIAMOND,
components=components.ItemComponents(
components.EnchantmentGlintOverride(True)
)
)
),
CraftingTransmute(
name="always_copper",
input=Tag.ITEM.PICKAXES,
material=Item.COPPER_BLOCK,
result=ItemStack(
item_id=Item.COPPER_PICKAXE,
)
)
)
my_recipes.add_namespaces(mining)
my_recipes.export()
Crafting Decorated Pot
Next we will cover the Crafting Decorated Pot recipe type. It copies the four ingredients and saves them as the decorated pot component.
Importing
We import the CraftingDecoratedPot class from MCpypack.recipe.
from MCpypack.recipe import CraftingDecoratedPot
New Recipe
The CraftingDecoratedPot class takes the following required arguments.
name->str: The name of the recipe.left->ItemLike: Left ingredient of the recipe.richt->ItemLike: Right ingredient of the recipe.front->ItemLike: Front ingredient of the recipe.back->ItemLike: Back ingredient of the recipe.result->ItemStack: Result of the recipe.
left, right, front, and back are the positions of the items. In a 3 by 3 crafting grid it would look like this:
" B " -> B = back
"L R" -> L = left; R = right
" F " -> F = front
It will then look like this.
luxury.add_recipes(
CraftingDecoratedPot(
name="gold_inside_diamond",
left=Item.GOLD_INGOT,
right=Item.GOLD_INGOT,
back=Item.GOLD_INGOT,
front=Item.GOLD_INGOT,
result=ItemStack(
item_id=Item.DIAMOND
)
)
)
Important
Don’t forget to create the
luxurynamespace.
Whole Code
from MCpypack import Datapack, Namespace
from MCpypack.recipe import CraftingDecoratedPot
from MCpypack.utils import ItemStack
from MCpypack.item.final import Item
my_recipes: Datapack = Datapack(
name="My Recipes",
description="Adding missing recipes to make the world a better place.",
version="26.1",
)
luxury: Namespace = Namespace(
name="luxury"
)
luxury.add_recipes(
CraftingDecoratedPot(
name="gold_inside_diamond",
left=Item.GOLD_INGOT,
right=Item.GOLD_INGOT,
back=Item.GOLD_INGOT,
front=Item.GOLD_INGOT,
result=ItemStack(
item_id=Item.DIAMOND
)
)
)
my_recipes.add_namespaces(luxury)
my_recipes.export()
Campfire Cooking
Now we will have a look at the Campfire Cooking recipe type. It is the only recipe type for the campfire.
Importing
We import the CampfireCooking class from MCpypack.recipe.
from MCpypack.recipe import CampfireCooking
New Recipe
The CampfireCooking class takes the following required arguments.
name->str: The name of the recipe.ingredient->ItemLike: Ingredient of the recipe.result->ItemStack: Result of the recipe.
Warning
In versions before 26.1 the count field was not allowed for the result.
You can also parse two optional arguments.
cookingtime->Time: Cookingtime in real-life time values. Default isNone.experience->Experience: The output experience of the recipe. Default isNone.
It will then look like this.
CampfireCooking(
name="edible_gold",
ingredient=Item.GOLD_BLOCK,
result=ItemStack(
item_id=Item.GOLD_INGOT,
count=2,
components=components.ItemComponents(
components.Consumable(),
components.Food(
nutrition=20,
saturation=20.0,
can_always_eat=True,
)
)
),
cookingtime=Time(Seconds(90)),
experience=25,
)
Now we are able to put gold blocks onto a campfire and as a result we get two edible pieces of gold ingots, which are a very strong source of food.
Whole Code
from MCpypack import Datapack, Namespace, Seconds, components, Time
from MCpypack.item.final import Item
from MCpypack.recipe import CampfireCooking
from MCpypack.utils import ItemStack
my_recipes: Datapack = Datapack(
name="My Recipes",
description="Adding missing recipes to make the world a better place.",
version="26.1",
)
luxury: Namespace = Namespace(
name="luxury"
)
luxury.add_recipes(
CampfireCooking(
name="edible_gold",
ingredient=Item.GOLD_BLOCK,
result=ItemStack(
item_id=Item.GOLD_INGOT,
count=2,
components=components.ItemComponents(
components.Consumable(),
components.Food(
nutrition=20,
saturation=20.0,
can_always_eat=True,
)
)
),
cookingtime=Time(Seconds(90)),
experience=25,
)
)
my_recipes.add_namespaces(luxury)
my_recipes.export()
Stonecutting
Next we will cover the Stonecutting recipe type. It is the only recipe type for the stonecutter.
Importing
We import the Stonecutting class from MCpypack.recipe.
from MCpypack.recipe import Stonecutting
New Recipe
The Stonecutting class takes the following required arguments.
name->str: The name of the recipe.ingredient->ItemLike: Ingredient of the recipe.result->ItemStack: Result of the recipe.
The Stonecutting class does not take any optional arguments.
It will look like this.
Stonecutting(
name="oak_stairs",
ingredient=Item.OAK_PLANKS,
result=ItemStack(
item_id=Item.OAK_STAIRS,
)
)
Now we can use a stonecutter to turn one oak plank into one oak stair.
Whole Code
from MCpypack import Datapack, ItemStack, Namespace
from MCpypack.item.final import Item
from MCpypack.recipe import Stonecutting
my_recipes: Datapack = Datapack(
name="My Recipes",
description="Adding missing recipes to make the world a better place.",
version="26.1",
)
carpenter: Namespace = Namespace(
name="carpenter"
)
carpenter.add_recipes(
Stonecutting(
name="oak_stairs",
ingredient=Item.OAK_PLANKS,
result=ItemStack(
item_id=Item.OAK_STAIRS,
)
)
)
my_recipes.add_namespaces(carpenter)
my_recipes.export()