Before we can start coding we need to create the required file structure for the mod. A mod requires a few things more than just the code let's take a look at a basic mod and cover the what we have.
The mod resides in a directory that usually has the same name as the mod, there are time when this might not be the case, but you should always name the folder the same as your mod name. There can be a slew of different subfolders, and we'll cover those more in the future when we get to actually needing them. In this lesson we'll just need the textures folder, as you'd probably already figured out this is where we place the textures that our mod will be using.
Looking at the files we have the depends.txt file. This file lists the mods that our mod requires to run. If the mod name had a question mark behind it it's optional, meaning that the mod will run without it, but will have more, or different features if that mod is enabled. The description.txt file just has a short description of what the mod is or does. This is visible in game on the mods tab. init.lua contains the code for the mod. The code can be broken down into multiple files, and we'll cover that in detail when we get further along with modding. License.txt contains the license for your code and media. If you aren't planning on releasing the mod publicly, you could skip this. If you ever plan on releasing the mod you'll need to select a license. I cover license some in the appendix, and list resources for further information. mod.conf currently has only one line, name = modname. In the future this will likely be expanded to take over some of the previous files we looked at. readme.md This file is similar to the description, but can contain more information and instructions on how to enable or disable specific parts of the mod if applicable, or how to use the API, if the mod creates one. Lastly we have screenshot.png If the mod adds blocks or items you can take a picture of them ingame. This picture should be in a 3:2 aspect ratio, recommended 300x200px. This is also visible in the mod tab.
Let's get to making a mod. Find your mod directory and create a new folder, we'll be calling our fist mod mod_1.
::Warning::
It should be noted that only characters a-z, 0-9, and _ are allowed in the mod name, if you try using anything else, such as a dash or capital letters you'll get an error when you try to load the mod.
::Warning::
We could create an init.lua file directly by right clicking and creating a new file, but that might not be an option on all operating systems, so what we'll do instead is open our code editor, and add a project folder, we'll select our mod folder and click okay. Then right click in the side panel and new file, which we will call init.lua. Now if you not using Atom just open your code editor and save a file init.lua in the mod directory. Doing this ensures that we get a file ends up with the .lua extension, rather then ending up with something like init.lua.txt.
Alright, so we have things ready, lets start with some code. To create a node we start with minetest.register_node. Everything that follows this is information about the node. Add an opening parenthesis and then double quotes, then type the mod name followed by a colon and the node name. Move over one space, hit a comma, add in an opening squiggly brace, and hit enter to start the second line.
We're going add a description to the node and to do that we'll just type description equals "our very first node ever!", and hit enter to go to the next line. We need to define a texture, and we do that with, tiles = {"mod_1_first.png"}, We'll add a group right away so we can dig the node. We do that with groups = {oddly_breakable_by_hand=2}, To close out the node registration we'll type })
The final code should look like this.
minetest.register_node("mod_1:first", {
description = "our very first node ever!",
tiles = {"mod_1_first.png"},
groups = {oddly_breakable_by_hand=2},
})
Notice how every line with the exception of the first and last ends with a comma. This is very important, forget one of those commas and your mod won't load. It should be noted that you could technically put all of these lines together as one long line, and the code would still run, but be much less readable, so I don't suggest doing that. We will be covering everything here in more detail in future lessons, as there is much more that we can add to a node registration.
Before we launch Minetest and load up the mod we need that texture. You can use the supplied texture from the resource pack, or create your own, just be sure to call it mod_1_first.png. Create a new folder in the mod directory and call it textures, and then paste the texture file there. The filenames for textures can have underscores and dashes, but not spaces. File type is usually png, but other formats will work too, but most everything I've ever seen has been png. PNG is a lossless image format, so you can edit it as many times as you like, while keeping edges sharp. If you use a lossy format you'll loose detail on every edit, and get muddy textures. While not required it is a good idea to prefix all your resource files with your mods name, this insures that you never get two mods using different textures that have the same name, which will lead to unwanted results.
Launch Minetest, create a new world, enable our new mod, and be sure to check creative mode and then launch the world. Search creative inventory for the node. You can use any word from the description, the nodename, or even the mod name to find the node. Right now the only way to get this node is to use the creative inventory, or the giveme command. Because we are in creative mode we can break any node by hand, so our added group doesn't do anything here, but if you were to start the world with Creative Mode turned off you'd find you could break the node by hand, and if you remove the group you'd have an invincible node. We want to be able to craft the node, so lets find some materials that could be used for the recipe. Let's just grab a dirt node and place it in the world. We can find the node name of any node by looking at the debug info in the upper left of the window. If you don't see it, use the F5 key to toggle it on. When we point at any node the nodename and texture will be listed at the end of the second line. We can see that the nodename for the dirt cube is default:dirt. This lets us know that dirt comes from the mod default. Exit Minetest.
To craft an item we need to create a recipe, and because this recipe is going to use an item from the default mod we need to add that to our depends.txt file. We haven't actually created that file yet, so lets do so now. Create a file called depends.txt and add the word default, and save the file. That's all there is. This lets the engine know that to use our mod the mod default must be loaded. If somehow you were to try to use this mod, and had the mod default turned off this mod wouldn't load. While we're at it, let's create the mod.conf file. In here we'll just put this line, "name = mod_1" This will let us use the mod even if the directory name isn't mod_1.
To create a craft recipe we'll go back to the init.lua file and add some code after the node registration. We'll start by typing minetest.register_craft({. This lets the engine know that the following code is a craft recipe.
hit enter and type output = "mod_1:first" This is what the result, or output of the craft is.
Then we have the recipe which is a table. For our first recipe we'll do something simple, so we'll just type recipe = {{"default:dirt", "default:dirt"}} hit enter and close with }) This recipe will let us put two dirt nodes side by side at any location in the grid to get our node. The final code should look like this.
minetest.register_craft({
output = "mod_1:first",
recipe = {{"default:dirt", "default:dirt"}}
})
Just like node registrations there is a lot things that we can change with recipes and we'll look into them more in a future lesson.
Let's launch Minetest and our world again to make sure the recipe is working. You should be able to put two dirt blocks side by side at any point in the grid and get the output of our node.
Lets create a second node, it will be similar to the first in it's features.
minetest.register_node("mod_1:fake_diamond", {
description = "I can't believe this isn't diamond block",
tiles = {"default_diamond_block.png"},
groups = {oddly_breakable_by_hand=2},
})
Because we've added Default to our dependencies we can use any of the textures from that mod. Finding the names of the textures can be done in game with the debug info, or you can browse to the game's install location and locate the files that way.
Let's create a craft recipe right away.
minetest.register_craft({
output = "mod_1:fake_diamond 99",
recipe = {
{"mod_1:first"},
{"mod_1:first"}
}
})
The number after the node name is the number of items the recipe will yield. This recipe requires for the nodes to be placed one above the other, rather than side by side like our last one.
If we launch our world again we'll see we can craft 99 diamond blocks out of two first node blocks, but these are not true diamond blocks. Any recipe that needs diamond blocks will not accept these, because we've only used that texture. For example a true diamond block can be turned into nine diamonds, whereas our fake block won't make any diamonds.
To wrap things up we just need a few more files. A readme, screenshot, license information, and a description. For the screenshot I took a screenshot in game using F12 then edited it with GIMP and cropped and resized to 200x300.
This is what our mod looks like on the mod page in the menu, you can see the screenshot, description, and what mods our mod needs to run.
You should now know how to make a basic node and recipe, so lets put what you've learned to the test. The challenge for this lesson is to create two more nodes with recipes. Feel free to use textures from default or create your own. This is really open ended, make the recipes with whatever you want. As long as your new nodes can be created with your recipes you've passed.
See the handout for some helpful tips and a challenge reminder.