Modding:Quick Start Tutorial

From Vintage Story Wiki
This page contains changes which are not marked for translation.

Welcome To Vintage Story Modding!

Looking for a quick 'zero-to-hero' start to get into modding Vintage Story? You're in the right place!

This tutorial aims to cover some important topics to demonstrate how mods can quickly be made. All you need is the game, an internet connection, any text editor, and about an hour or two of time in total.

So, let's jump straight into it, shall we?

The installation folder for Windows should look similar to this

Finding the Vintage Story Assets

The installation folder for Linux should look similar to this
The application folder for MacOS should look similar to this

Whenever a world in loaded, a whole bunch of assets are loaded into the game, and these are used to create different types of block, entities, items, and many more. Many of these assets are stored as JSON files, which are essentially human-readable text files that store a load of data. For example, a block's JSON file will contain information on its material, appearance, functionality, and more. These will then be loaded by the game, and the block will be available in the game.

The Vintage Story assets are found alongside the main executable for the game, so you'll need to find your installation directory.

Windows

Your installation folder will contain a few folders, including "assets", "lib", and "mods", and executables like "modmaker.exe", "VintageStory.exe", and "VintagestoryServer.exe".

  • If you have a shortcut to Vintage Story on your desktop, you should be able to right click on the shortcut and select 'Open File Directory'.
  • If you have installed the game to the default install directory, this will be in the %appdata% folder.
    • To access this, you can:
      • In the Windows File Explorer, type %appdata% into the search bar and press enter.
      • Press the Windows Key + R simultaneously to open the 'Run' menu, type %appdata% into the input field, and press run.
    • You will then need to enter the 'Vintagestory' folder. Note this is different from the 'VintagestoryData' folder;
  • If you have installed the game to a different install directory, you will have to use your file explorer to find and access this manually.

Linux

The installation folder for Linux is dependent on your installation method. It is worth doing an internet search for where your installation method installs to.

For example, my installation through Flatpak has the installation directory at: /home/nat/.local/share/flatpak/app/at.vintagestory.VintageStory/current/active/files/extra/vintagestory/ When using Flatpak, you will need to ensure you are using a local install directory instead of a shared one, otherwise you may not be able to modify files. If the folder is inside your home folder, you should be fine.

MacOS

On MacOS, the game assets path is based on where you place the .app file that is downloaded from the Vintage Story client area. You may need to right-click on the Vintage Story application in Finder and select 'Show Package Contents'. This should lead you to the folder that contains the 'assets' folder.


Feel free to explore the assets folder at your will. Everything inside this folder can be edited and adapted to mod the game. You'll find that most of the game content is inside the survival sub-folder.

Adding a Block

Let's start simple, and add a new type of block to the game. You can create any block you want, but I am going to make a generic paneled wood block.

The survival/blocktypes folder contains all the types of blocks that are used in survival mode. This image is up-to-date as of 1.21.6, different versions may have different contents

From the game directory that we found earlier, navigate to assets/survival/blocktypes in your file browser. This folder contains all the blocks that are included in survival mode for the game. The naming of folders controls what type of asset is contained within it. The game knows to load all files inside the blocktypes folder as new blocks. Because of this, all we need to do to add a new block is to create a new file inside of this folder.

The easiest way of creating a new JSON file is to copy and paste an existing one. Copy any file, paste it directly to the blocktypes folder, and rename it to an appropriate name for the block. Your file name should be lowercase, and one word. You can use hyphens ( - ) if needed. In my case, I have named the file 'paneledwood', whereas 'PaneledWood' is not a recommended file name.

You'll need to open your new file using any available text editor. Some editors are more suitable than others, but any simple text editor will work. You may need to right click on the file, and 'Open with...' to select a text editor.

Part 1/2 – Step-By-Step

Let's make our new block by using step by step instructions. Every part of this is important, so make sure to follow them carefully. These steps will ignore most formatting. If you are familiar with using JSON, you may wish to format the file yourself.

  1. Delete the contents of the new file.
  2. Add a set of curly braces ( { } ), and add an empty line between them. Everything inside the curly braces will become part of our object (in this case, our block).
  3. In the empty line, add our first property: code:"paneledwood". This is a unique identifier for the new block. It needs to be unique, and be made up of only lowercase letters. Hyphens should not be used here.
  4. Add a comma after the last quotation mark, and then a new line. This ends our property and tells the game that we are now expecting the next property.
  5. Add our next property in the new empty line: creativeinventory: { "general": ["*"] }. This property tells the game to include our block in the creative inventory. We don't need to know the specific formatting here, but "general" is the name of the creative tab that the block will be included in.
  6. Add another comma and a new line after the property we just added.
  7. We're going to add two new properties now, complete with commas and new lines: drawtype:"cube", shape: { base: "block/basic/cube" },. These both control the 3D appearance of our block. When used together, they tell the game that our block should use the default cube shape.
  8. Next property: texture: { base: "block/paneledwood" },. A texture, when referring to a 3D object, refers to the 2D image that is mapped onto the 3D model/shape. The section in quotations ("block/paneledwood") refers to a file path without extension, starting from the 'textures' folder that is alongside the 'blocktypes' folder. If you are adding a different block, you will want to change 'paneledwood' to be the name of your block.
  9. We need to add or create the actual texture now. You can create or find the texture any way you want, but it should be 32x32 pixels, and square, to fit with the game style. It also needs to be in a png format. Or, you can use the texture for paneledwood, [ https://wiki.vintagestory.at/images/1/11/PaneledWoodForModding.png provided here]. When the texture is created or downloaded, you will need to place the file inside "survival/textures/block", and rename the file to fit the name we gave in step 8. In my case, the file is renamed to be 'paneledwood.png'.

Let's take a pause. With these properties, we should now have enough that our block appears in game.

paneledwood.json (unformatted)
{
code:"paneledwood",
creativeinventory: { "general": ["*"] },
drawtype:"cube",
shape: { base: "block/basic/cube" },
texture: { base: "block/paneledwood" },
}

It's good practice to format your JSON for readability. The following is what the same file would look like when well-formatted. Functionally, both are identical.

paneledwood.json (formatted)
{
  "code": "paneledwood",
  "creativeinventory": {
    "general": [
      "*"
    ]
  },
  "drawtype": "cube",
  "shape": {
    "base": "block/basic/cube"
  },
  "texture": {
    "base": "block/paneledwood"
  }
}
(Recommended read) About unformatted JSON files...
JSON is an object notation language, basically meaning that it's sole purpose is to store data. Because of this, different implementations of JSON have different features, but each works similarly. Vintage Story currently loads JSON files using a library called JSON.NET, by Newtonsoft, which provides its own implementation of JSON. It is remarkably similar to a format called JSON5, and supports more human-editing features, such as omitting certain quotation marks and commas.

Many programs and JSON checkers will only support standard JSON, so you may find that your text editor or JSON checkers will show errors even on valid Newtonsoft JSON files.

Part 1/2 – Testing

If working correctly, you should be able to place your new block just like any other block in the game

If you are confident and don't feel the need to test yet, feel free to skip this and move on to part 2. It's often a good idea to test your mods in parts, however.

Ensure you have completed all the steps in part 1. You should have 5 unique properties in your JSON file, as well as having copied and renamed the texture. Save your JSON file, load the game, and then load or create a world.

In creative mode, you should be able to search for your block. Note that the block's name will be in the form game:block-code, based on the code we provided in the very first property. We will change how this name displays in part 2. Feel free to place your new block. It should work just like any other block.

(Debugging) Can't find your block in the creative inventory?
There's a few things that may be wrong. To help solve this, try running the command /giveblock code, where code is the code specified in the block's JSON file.

If the block is successfully given, then your 'creativeinventory' property is likely malformed (incorrect). Check you have copied it correctly. If the game informs you that there is no block with that code, then your JSON is likely malformed, or your file is in the wrong location. Check your file matches the example code above, and ensure you have included all brackets and necessary commas. Also double check that your block file is inside of assets/survival/blocktypes. If all of this is correct, you may be using a code that is already taken or not valid. Or, you may be modifying an installation folder that is different from the installation you are currently running.

(Debugging) Block is solid white with a red?
This indicates that your texture did not load correctly for the block. Firstly, check your 'texture' property is correct. There are many blocks that use 'textures' (plural) when using multiple textures, but you only need to use the single version. If you are sure the texture property is correct, then ensure your texture file is in the correct location. Remember, if your block exists in the 'assets/survival/blocktypes' folder, then the texture should exist in 'assets/survival/textures' folder, and then inside the path specified in the texture property (e.g. 'assets/survival/textures/block/paneledwood.png'). Next, check your file is in png format, and the name is correct.

Some file browsers may have hidden file extensions. Ensure that your file is called "paneledwood.png", and not "paneledwood.png.png".

Part 2/2 – Step-By-Step

There's just a few more things to do for our block to be working as expected. As before, make sure to follow these steps accurately.

  1. We want to add a proper name for our block. We can do this by editing the lang files provided by the game. All lang files are located at: 'assets/game/lang'. Note that this is inside the game folder and not the survival folder that we were working in before. Open this folder, and open the en.json file.
  2. Scroll all the way to the bottom of the file.
  3. There will be a number of entries, similar to this: "itembook-writable": "Writable with Ink&Quill",. The last entry likely doesn't have a comma. Add one, and then a new line.
  4. On your new line, add the following: "block-paneledwood": "Paneled Wood". Note that the key (the part before the : ) is identical to how the game displays the block name. Remember to replace paneledwood with your blocks code, and the value (the part after the : ) should be how you want the name to be displayed.
  5. Save the file. Your block will now have a proper name when viewed in game!
  6. Back into the block's JSON file that we created earlier, we're going to add a few more functional properties.
  7. Make sure you have a comma after the last property, and make a new line. Add the following: blockmaterial: "Wood",. This will change your blocks material from stone to wood, which has a few functional effects such as increased break speed with an axe.
  8. Add the following 'sounds' property. These, as expected, will control what sounds play when interacting with the block.
    sounds: {
    	"place": "block/planks",
    	"hit": "block/planks",
    	"break": "block/planks",
    	"walk": "walk/wood"
    },
  9. Add the following set of properties. These control the player's animation when holding the block: heldTpIdleAnimation: "holdbothhandslarge", heldRightReadyAnimation: "heldblockready", heldTpUseAnimation: "twohandplaceblock",
  10. Finally, add the following property block. This controls the final position, rotation, and scale of the block when it is held:
    tpHandTransform: {
    	translation: { x: -1.23, y: -0.91, z: -0.8 },
    	rotation: { x: -2, y: 25, z: -78 },
    	scale: 0.4
    },

That should finish off our block. Let's have a look at the code:

paneledwood.json (unformatted)
{
code:"paneledwood",
creativeinventory: { "general": ["*"] },
drawtype:"cube",
shape: { base: "block/basic/cube" },
texture: { base: "block/paneledwood" },
blockmaterial: "Wood",
sounds: {
	"place": "block/planks",
	"hit": "block/planks",
	"break": "block/planks",
	"walk": "walk/wood"
},
heldTpIdleAnimation: "holdbothhandslarge", heldRightReadyAnimation: "heldblockready", heldTpUseAnimation: "twohandplaceblock",
tpHandTransform: {
	translation: { x: -1.23, y: -0.91, z: -0.8 },
	rotation: { x: -2, y: 25, z: -78 },
	scale: 0.4
},
}
paneledwood.json (formatted)
{
  "code": "paneledwood",
  "creativeinventory": {
    "general": [
      "*"
    ]
  },
  "drawtype": "cube",
  "shape": {
    "base": "block/basic/cube"
  },
  "texture": {
    "base": "block/paneledwood"
  },
  "blockmaterial": "Wood",
  "sounds": {
    "place": "block/planks",
    "hit": "block/planks",
    "break": "block/planks",
    "walk": "walk/wood"
  },
  "heldTpIdleAnimation": "holdbothhandslarge",
  "heldRightReadyAnimation": "heldblockready",
  "heldTpUseAnimation": "twohandplaceblock",
  "tpHandTransform": {
    "translation": {
      "x": -1.23,
      "y": -0.91,
      "z": -0.8
    },
    "rotation": {
      "x": -2,
      "y": 25,
      "z": -78
    },
    "scale": 0.4
  }
}

Part 2/2 – Testing & Finalizing

The finished paneled wood block. Note that the player now holds the block correctly, and the name and material are now also correct

Let's load the game and a world on creative mode. Find the new block in the creative menu and place it in your hotbar.

You'll notice that when holding the block, the player now uses two hands and it is positioned appropriately. As well as that, the block's name has been resolved and its material has changed to be wood.

You can double check the material is correct by attempting to mine it using an axe, compared to your bare hands. Using an axe with a modified that affects wood will mine our block significantly faster.


So, that's a new block created! You should hopefully begin to see how easy adding new content is to Vintage Story. And it's not just blocks, either. Items, entities, world configurations, recipes, and loads more can be added using JSON files. We will explore some of these in the next sections of this tutorial, as well as how to package them into a mod that can be distributed!

Before you move on, there are many properties that can be used for blocks. For a full list, you can use the [ https://apidocs.vintagestory.at/json-docs/index.html JSON Documentation] pages. The page that lists all properties available for blocks can be found here.

Adding a Grid Recipe

Next up on the quick start tutorial: Adding a grid recipe!

This is the recipe for cob. We will use a similar layout to this, but edit it for our ingredients

Grid recipes are the recipes that are made using the crafting grid in the player's inventory. They have a set of ingredients in a specific order, and a (usually) single output.

In your assets folder, in the survival domain (more on domains later, right now let's just assume it means a folder in the root of the assets path!), go into the folder recipes/grid.

Rather than creating a recipe from scratch, we're going to modify an existing recipe. In inspiration of ye olde alchemy, I'm going to make a recipe to turn lead ingots into gold ingots, when combined with some quartz ore for a slight mystical element. To keep things simple for this one, I do recommend you do the same recipe for this part until you understand how it all works.

(Fun Story) Why not use nuggets or bits?
When creating this tutorial, I wrote this section and then discovered a bug in version 1.21.6 while testing it. For some reason, crafting nuggets is not something the game expects, and it causes a crash when viewing the ingredients' handbook pages. So, I decided to make a change to bits. However, the handbook pages for gold bits already have many different recipes to make them, mainly using the chisel. For succinctness, I decided to go with using ingots.

Now, the recipe we're going to copy is called 'cob.json'. It's a rather simple recipe that only has two unique ingredients - Dry grass, and any dirt, and it outputs 10 cob. So, copy and paste the file into the same folder. Any files inside of the 'grid' folder will be parsed and used as grid recipes. You may have noticed there were also other folders for the different types of recipe, which follow the same file-placement rules.

Rename the file to something relevant, and lowercase. I named my file 'leadtogold.json'.

This is what the original cob file should look like, just in case it's changed in an update:

cob.json (unmodified, v1.21.6)
{
	ingredientPattern: "GDG DGD GDG",
	enabled: true,
	ingredients: {
		"G": { type: "item", code: "drygrass", quantity: 1  },
		"D": { type: "block", code: "soil-*", quantity: 1  },
	},
	name: "cob",
	width: 3,
	height: 3,
	output: { type: "block", code: "cob-none", quantity: 10  }
}

Let's open up the file, and go through it line by line.

Line-By-Line Explanation

Our file starts and ends with curly braces ( { } ) again. This is fairly normal, but some JSON files may start and end with square brackets ( [ ] ) instead. The difference is that a single object is surrounded by curly braces, whereas a group of objects (an array) will be surrounded by square brackets.

  1. ingredientPattern: "GDG DGD GDG" This is the layout pattern of our recipe - Notice how it matches to the image shown of the cob recipe? We can control the width and height of grid recipes, to a maximum of 3x3. Each unique character in the pattern represents a unique ingredient that we define later in the file. A space in the file represents a new line. Although not included in this file, an underscore ( _ ) represents an empty slot in a recipe. It's worth noting that the file starts from the top left, and proceeds horizontally, and then moves onto the next row.
  2. enabled: true Rather simply, this controls whether the recipe should be loaded or not. It isn't necessary to keep this, but I've left it in for completeness. The recipe can be easily disabled by setting this to false.
  3. ingredients: { This starts the list of ingredients that are included in the ingredient pattern, on line 1. Technically, the ingredients are a dictionary, as they have a key and a value. Anything after this line, until the single closing curly brace on line 6 (in this list) will count as an ingredient definition.
  4. "G": { type: "item", code: "drygrass", quantity: 1  }, This is where things get a little more complex. Firstly, we have "G":. This represents a single character in the ingredient pattern. There must be an ingredient entry for every letter given alphabetical character. Anything inside the curly braces that immediately follow are a definition of G in the ingredient pattern. type: "item" is for whether the ingredient is a block or item. Blocks and items are implemented separately in the game's code, so this type needs to be accurate so the game knows where to look. code: "drygrass" is the code of the block or item. There's a quick way to find this which will be explained when we get onto editing the recipe. quantity: 1, rather simply, means we only need one of this block or item per stack to satisfy the recipe.
  5. "D": { type: "block", code: "soil-*", quantity: 1  }, This is another ingredient definition, this time for D in the ingredient pattern. It's very similar to line 4, however this type is a block. You will also notice: code: "soil-*". To really quickly explain, there are many versions of soil in the game, based on their fertility. The code for every soil block is something like "soil-low" or "soil-barren", or "soil-compost". Point is, they all start with the same "soil-" prefix. Recipes can use this to their advantage and use an asterisk ( * ), which represents a wildcard. Any text that can match the wildcard will be a valid entry for this ingredient. In other words, any soil block will work for this ingredient.
  6. } This is just ending the ingredient list from line 3.
  7. name: "cob", This is just a readable name for the recipe. The sole purpose of this is for debugging purposes, but it is a necessary property.
  8. width: 3, is the width of the recipe in the grid. This needs to match with the width of the pattern on line 1.
  9. height: 3, is the height of the recipe in the grid. This needs to match with the height of the pattern on line 1.
  10. output: { type: "block", code: "cob-none", quantity: 10  } is the last part of the recipe. You'll notice that its setup very similar to an ingredient, e.g. on line 4 or 5.
This is the recipe we want to achieve from our "lead to gold" file

Step-By-Step

So, after that quick rundown of what each line does, I think we're ready to edit our recipe. It's always a good idea to visualize a recipe before you make it, so I've included a screenshot of the finished recipe here. Let's get to it!

Intermission – Finding object codes

Before we actually get started, we need to know how to find the codes for an object. You could try and find them inside of the JSON files, but this is often difficult, especially when the codes begin getting more complex.

To find the codes, we'll need to load a world up in the game, preferably on creative mode.

  1. Whilst the game is running, go into settings.
  2. Go to the 'Interface' tab.
  3. Enable 'developer mode', at the bottom.
  4. Go to the new 'Dev' tab
  5. Enable 'Extended Debug Info'.

If done correctly, any item that is hovered over will now display its ID and code. Note that an ID is a unique value and will change between worlds. The code is what we want to use. Also note that all codes will begin with a prefix for its domain, in this case it'll be game:. When modding, it is recommended you always include the domain. Whilst it isn't always necessary, domain errors are an extremely common issue when making mods. We will talk more about this in a further tutorial.


Now, to actual edit our recipe. Make sure you're in your newly created file and not the old, unmodified file.

  1. Let's first modify our ingredient pattern. We want something that represents a + shape, with lead (L) on the outsides and quartz (Q) on the insides: ingredientPattern: "_L_,LQL,_L_",. You'll probably notice that we've switched from using spaces to commas. This is perfectly acceptable and in fact required for this specific recipe. Why is it required? Let's call it a quirk of the recipe parsing system (the recipe won't load correctly if it uses spaces and starts with an underscore).
  2. Let's take a look at the ingredients. We need the codes for both lead and quartz ingots for our ingredients. I've included the codes in a table below, but I recommend you get into the practice of finding them yourself.
  3. Our first ingredient, for a lead ingot, should look like this: "L": { type: "item", code: "game:codeforlead", quantity: 1  }, but make sure to replace 'codeforlead' with the code you found for a lead ingot.
  4. The second ingredient, for quartz ore, should look like this: "Q": { type: "item", code: "game:codeforquartz", quantity: 1  }, again making sure to replace 'codeforquartz' with the code you found for quartz ore.
  5. Change the name property from 'cob' to 'leadtogold'.
  6. Finally, change the output to the following: output: { type: "item", code: "game:codeforgold", quantity: 4  }, once again making sure to replace 'codeforgold'.
(Spoiler) Codes required for the recipe
Lead: game:ingot-lead

Quartz: game:ore-quartz

Gold: game:ingot-gold

When completed, the finished file should look like this:

leadtogold.json
{
	ingredientPattern: "_L_,LQL,_L_",
	enabled: true,
	ingredients: {
		"L": { type: "item", code: "game:ingot-lead", quantity: 1  },
		"Q": { type: "item", code: "game:ore-quartz", quantity: 1  },
	},
	name: "leadtogold",
	width: 3,
	height: 3,
	output: { type: "item", code: "game:ingot-gold", quantity: 4  }
}

Testing & Finalizing

Our recipe file is now complete, so feel free to load the game and start up a creative world.

If you enabled developer mode earlier, you'll notice that your loading screen is a bit different. It now gives information from the logs, so you can hopefully spot errors. We'll talk about how to view, read, and fix errors later on, in another tutorial.

It's a good idea to check your recipe inside the crafting grid, too

For now, when you load your world, you will want to go onto the handbook page for the gold ingot. If you didn't already know, you can hover over a gold ingot in the creative inventory, and press 'H' to open the handbook directly. On that menu, you should be able to see our new crafting recipe!

(Debugging) Recipe doesn't seem to have loaded?
There's usually only three things that can go wrong here.
  1. Your recipe file is malformed (incorrect). Double check you have all the appropriate brackets and commas, especially on the ingredients list. Remember to use commas in your ingredient pattern instead of spaces, too.
  2. The code for one or more of your ingredients or output is incorrect. Make sure you have checked these in-game using the developer mode.
  3. Your JSON file is in the wrong location. Ensure it is placed in assets/survival/recipes/grid, and the filename is all lowercase.

You can also left click on both the lead and quartz to open their handbook pages. You should see that it now tells you how a gold ingot can be crafted.

It's often a good idea to check that your recipe actually functions, too. In rare occurrences, especially if a recipe has multiple variations, it may be shown here but the recipe may not actually be craftable.


So, we've created a new block, and created a new recipe!

There is a lot we can do with recipes, and each type of recipe has its own format. Perhaps you can take some time looking through the different recipe folders and files to get a feeling of how things are created in the game. There are tutorials on all the types of recipe later on in the wiki, but I recommend completing some of the previous tutorials first.

Grid recipes have a few extra properties that can be used, however some of these are quite specific. You can use the [ https://apidocs.vintagestory.at/json-docs/index.html JSON Documentation] pages to see these. The specific page for grid recipes can be found [ https://apidocs.vintagestory.at/json-docs/jsondocs/Vintagestory.API.Common.GridRecipe.html here].

Editing Shape Files (3D Models)

Every block and entity have a shape (a shape is a 3D model file for Vintage Story) attached to them, of some description. A lot of blocks are simply a 3D cube, but there are a lot of blocks that have much more complicated shapes too.

Shape files are also stored in JSON, but there is a specific program that should be used to edit these. Introducing: The [ https://github.com/anegostudios/vsmodelcreator/releases Vintage Story Model Creator].

VSMC2 is coming!
A new version of VSMC is being created that will offer many more modern features for the Vintage Story development team and modders. It will offer out-of-the-box execution, and should hopefully work on all major operating systems.

Testing versions of VSMC2 can be found here.

Installing VS Model Creator (VSMC)

Windows

  1. It is important to update your Java runtime to the most recent version. Java can be found here. VSMC requires an up-to-date version of Java 8.
  2. Download the most recent version of VSMC for Windows. This will start with 'vsmodelcreator_installer'.
  3. Install the file that has been downloaded by running it.
  4. You should now be able to run VSMC from your desktop or Windows search menu.

Linux

  1. It is important to update your Java runtime to the most recent version. The easiest way to do this is using the command line. Run sudo apt install openjdk-25-jre and follow the instructions to install Java. When reading this tutorial, you may find that OpenJDK has updated to a newer version — Feel free to use this, but make sure you do not install the 'headless' version (e.g. install openjdk-25-jre and not openjdk-25-jre-headless).
  2. Download the most recent version of VSMC for Linux. This will start with 'vsmodelcreator_linux'.
  3. Unzip the downloaded zip file, usually by double clicking it. The folder should contain 'natives', 'vsmodelcreator_lib', and 'vsmodelcreator.jar'.
  4. Open a terminal in the now unzipped folder.
  5. In the opened terminal, run: java -jar vsmodelcreator.jar. This should open the model creator.
  6. Repeat steps 4 and 5 to run the model creator.

MacOS

Unfortunately, the VS Model Creator is not currently supported on MacOS. You may be interested in reading the 'Using Blockbench' section below.


(Troubleshooting) Having problems with installation?
In my experience, 99% of problems with VSMC are caused by an incorrect or outdated installation of Java. Follow this checklist to make sure you have a correct installation:
  1. Ensure you have updated Java 8 to the most recent version for your operating system.
  2. Ensure you are installing the JRE (Java Runtime Environment) and not the JDK (Java Development Kit).
  3. Ensure you are not running a headless version of Java. When using Linux, ensure you are installing (for example) openjdk-25-jre and not openjdk-25-jre-headless.
  4. Ensure you have updated your graphics drivers and can run OpenGL applications.

If this still is not working, consider inquiring on the [ https://www.vintagestory.at/forums/forum/36-mod-development-questionstroubleshooting/ Vintage Story Forum] or [ https://discord.gg/vintagestory Vintage Story Discord server].

Using Blockbench
Blockbench is a 3D modeler that is similar to VSMC. If you are having trouble using the VS Model Creator, or you want to try something different, there is a community-made Blockbench plugin for Vintage Story. Please note that this method of creating shape files is not actively supported in these tutorials, and you may be interested in using the Blockbench forums to find out how that program works.

You can download Blockbench [ https://www.blockbench.net/ here], and the Vintage Story plugin here.

Loading and Editing a Shape

Before loading a shape, there is a little bit of preparation that we should do. With VSMC open, select 'File' and then 'Select Texture base path...' from the top-left menu bar. In the new menu that appears, you will need to find your way back to your assets folder, and then select the folder assets/survival/textures.

If you have loaded your textures and shape correctly, then this is what the chair should look like in the editor

Now we can open a file. Select 'File' and then 'Open' from the top-left menu bar.

Right, once again, find our way back to our assets folder from before in the open file menu. All shape files are stored in the shapes folder inside a domain. In this case, our folder will be in assets/survival/shapes. Similarly to the textures folder, this is split into sub-folders for organization purposes.

So, what should we edit? To keep it simple, we don't really want to edit anything with an animation, so we probably want to edit a placeable block. One shape which isn't too complex is the chair, found at assets/survival/shapes/block/wood/chair-normal.json. Let's edit this file and add some more reinforcements to it.

You'll notice that when the file is opened, it'll be fully colored and display with its textures loaded. If the shape is an off-blue/white, then this means you have not loaded your texture base path correctly. Make sure you select the survival textures folder, and you may have to reload your shape file afterwards.

VSMC Quick Rundown

VSMC can be a complex program to learn, but here's a quick rundown of what does what. To see all the options, you may need to select an element in the element hierarchy.

  1. This is the element hierarchy. Shapes in Vintage Story are made using a number of cuboids, called elements. Elements each have a unique name, which works as its identifier. Elements can be children of other elements, and this list can be used to change the parent of an element. You can also enable or disable viewing an element using this menu by clicking the cube next to the name of the element.
  2. Creates a new element.
  3. Deletes a selected element.
  4. Duplicates a selected element.
  5. The name of the selected element. This can be changed.
  6. The size, in 3D, of the cuboid. Each value represents a single axis (XYZ, where Y is the up/down axis).
  7. The position of the cuboid.
  8. The origin of the cuboid. This is the point that the object scales and rotates around.
  9. The rotation of the cuboid. Rotations are stored using euler rotations.
  10. The menu bar. There are numerous options here.
  11. The main viewport. Use LMB to pan the camera, RMB to rotate, and MMB to scroll.
  12. The edit mode selection. Cube mode is to modify the properties of each cuboid. Face mode is used to modify textures and per-face UV coordinates. Keyframe mode is used to create and modify animations. 'P' mode is to create and position attachment points.


    Select an element in the element hierarchy, and then select 'Face' mode to continue. If your menu looks different from the next image, you should enter 'Project' in the menu bar and disable 'Entity Texture Mode'.

  13. The face of the current cuboid to edit the texture of.
  14. 'Image' controls the choice of texture for the current face by opening the texture manager. Clear removes the texture from the current face. Copy will copy the texture choice of the currently selected face. Paste will paste the most recently copied texture choice.
  15. The UV coordinates of the current face. Essentially this is a mapping of the texture coordinates to the current cuboid. Most models use a texture ratio of 1 UV unit to 2 pixels per texture (e.g. a face UV of 0, 0, 4, 4 will map the pixels from 0, 0 to 8, 8 onto the face).
  16. The rotation of the UV. This is only per 90 degrees.
  17. Enabled controls whether the face is enabled. A disabled face will not render and will appear fully see-through. Auto-Resolution will automatically calculate the appropriate size of the UV, to ensure a constant pixel size throughout a model. Snap UV will ensure the UV is snapped to 0.5 intervals.
  18. The UV editor. This can be used on the mouse to position UV coordinates onto a texture.

The texture manager is shown below. This can be accessed by clicking the 'Image' button. The texture manager displays all currently loaded textures for the shape. Each one can be selected. Whilst a texture is selected, click 'Apply' to apply it to the currently selected face. Click 'Import' to load a new texture. The entry field above the buttons controls the names of each texture.


Hopefully you understand a bit about the basics of how to use VSMC. It's worth experimenting with.

I'm going to change the shape of the chair to make it more square and have a slightly wider surface. Here is the process I used:

  1. Select the 'leg1' element by clicking it in the element hierarchy.
  2. Set its rotation to 0 for all 3 axes. The origin is already setup appropriately for this to work.
  3. Repeat steps 1 and 2 for all 4 legs.
  4. Select 'Surface' in the element hierarchy.
  5. Raise the Y position from 7.5 to 9 using the increment arrow. The Y position is the central entry in the position. To increase by intervals of 0.1, you can hold down shift and click the appropriate up arrow. You may notice that the origin is moving too — This is normal to ensure that rotations remain the same. If you wish to move without moving the origin, you can hold 'ctrl' whilst using the interval arrows.
  6. Lower each support's Y position from -3.5 to -7.5 by selecting them one by and one and using either the increment arrows or entering the value into the input field.
  7. Now to make the surface larger. Select the 'surface' element again, and increase the voxel size to 16 x 2.5 x 16. You will notice that part of the surface will now turn a purple color. This is due to the UV being out of range, which we will sort out soon.
  8. Our chair is now off-center. Move the 'surface' element so it's X and Z position (first and last positions) are 0.
    After step 9, your chair should look like the following
    After step 18, your chair should look like this
  9. You'll notice that the legs, supports, and cloth are now off-center from the chair. Since we decreased the X and Z position of surface by 1 each, we need to select each other element and individually move them by 1 in both the X and Z axes to make them central again. Use the increment buttons to help with this. See the image to the right to check if your chair looks the same after this step.
  10. Reselect the 'surface' element, and this time enter the 'Face' mode. We are now going to fix the UVs.
  11. Ensure that 'auto-resolution' is enabled.
  12. We will need to change the UV values for each of the 6 faces of the surface element. For the first three, we will use the numeric UV values. For the latter three, we will use the graphical UV editor.
  13. In the face (or 'side') selection, select 'North'.
  14. Look at the numeric UV values (section 15. on our reference diagram above). Our chair uses the standard 1 unit to 2 pixels, and we are using a 32x32 size texture. This means that the maximum UV values should be 16. If you have the correct face selected, the UV should currently read: 1, 1, 17, 3.5. Noteably, since our maximum is 16, then a 17 is what is causing our invalid purple pixels.
  15. With auto-resolution enabled, making any change to the first or second UV value (X1 and Y1) will automatically change the third and fourth UV values (X2 and Y2). Decrease our X1 value (the first value) by one, and you should see that the 17 automatically drops to 16. Your UV should now read: 0, 1, 16, 3.5.
  16. Repeat steps 13 to 15 for sides 'east' and 'south.
  17. Let's now use the graphical UV editor. The white box in each section represents the UV coordinates for that face, on top of the texture that has been selected for that face. Dragging the white box with the left mouse button will result in the UV being moved as a whole, without its size changing. Dragging the white box with the right mouse button will result in its size being changed. Because we're using the auto-resolution, we should not need to worry about editing the sizing of our UV.
  18. For the last three faces (west, up, and down), use the graphical UV to make sure the white box is fully fitting inside of the texture. If there is any purple left on the table, then the UVs for that face are invalid.
  19. That's the chair finished! On the menu bar, click file, and then save. It'll overwrite the current chair that is included in the game, meaning that the edits should be available for testing!
Our finished chair, complete in game!

Testing & Finalizing

Load up the game, and place some chairs. All chairs that use the model we edited will be updated to be more square and wider.

Other than the chair working, there's not much to test! If there are any issues, ensure that you have saved the file to overwrite the current chair-normal.json.

If you need it, the full JSON file for the new chair shape can be found below. You can open the shape file in a text editor and paste the contents in - It is just a JSON file after all, the same as our block and recipe files.

chair-normal.json
{
	"editor": {
		"allAngles": false,
		"entityTextureMode": false
	},
	"textureWidth": 16,
	"textureHeight": 16,
	"textureSizes": {
		"oak": [16,16]
	},
	"textures": {
		"cover": "block/cloth/linen/normal1",
		"1": "block/wood/chair/normal/top",
		"oak": "block/wood/debarked/oak"
	},
	"elements": [
		{
			"name": "Surface",
			"from": [ 0.0, 9.0, 0.0 ],
			"to": [ 16.0, 11.5, 16.0 ],
			"rotationOrigin": [ 0.0, 10.5, 0.0 ],
			"faces": {
				"north": { "texture": "#oak", "uv": [ 0.0, 1.0, 16.0, 3.5 ] },
				"east": { "texture": "#oak", "uv": [ 0.0, 5.0, 16.0, 7.5 ], "windMode": [-1,-1,-1,-1] },
				"south": { "texture": "#oak", "uv": [ 0.0, 8.5, 16.0, 11.0 ], "windMode": [-1,-1,-1,-1] },
				"west": { "texture": "#oak", "uv": [ 0.0, 12.5, 16.0, 15.0 ] },
				"up": { "texture": "#1", "uv": [ 0.0, 0.0, 16.0, 16.0 ] },
				"down": { "texture": "#oak", "uv": [ 0.0, 0.0, 16.0, 16.0 ] }
			},
			"children": [
				{
					"name": "leg1",
					"from": [ 2.0, -9.0, 2.0 ],
					"to": [ 5.0, 0.5, 5.0 ],
					"rotationOrigin": [ 5.0, 0.5, 5.0 ],
					"faces": {
						"north": { "texture": "#oak", "uv": [ 0.5, 2.5, 10.0, 5.5 ], "rotation": 90 },
						"east": { "texture": "#oak", "uv": [ 2.0, 10.0, 11.5, 13.0 ], "rotation": 90 },
						"south": { "texture": "#oak", "uv": [ 5.0, 6.0, 14.5, 9.0 ], "rotation": 90 },
						"west": { "texture": "#oak", "uv": [ 4.0, 6.0, 13.5, 9.0 ], "rotation": 90 },
						"up": { "texture": "#null", "uv": [ 0.0, 0.0, 3.0, 3.0 ], "enabled": false },
						"down": { "texture": "#oak", "uv": [ 2.0, 9.0, 5.0, 12.0 ] }
					}
				},
				{
					"name": "leg3",
					"from": [ 11.0, -9.0, 2.0 ],
					"to": [ 14.0, 0.5, 5.0 ],
					"rotationOrigin": [ 11.0, 0.5, 5.0 ],
					"faces": {
						"north": { "texture": "#oak", "uv": [ 1.0, 12.5, 10.5, 15.5 ], "rotation": 90 },
						"east": { "texture": "#oak", "uv": [ 0.5, 3.5, 10.0, 6.5 ], "rotation": 90 },
						"south": { "texture": "#oak", "uv": [ 5.5, 10.0, 15.0, 13.0 ], "rotation": 90 },
						"west": { "texture": "#oak", "uv": [ 5.5, 2.0, 15.0, 5.0 ], "rotation": 90 },
						"up": { "texture": "#null", "uv": [ 0.0, 0.0, 3.0, 3.0 ], "enabled": false },
						"down": { "texture": "#oak", "uv": [ 2.5, 0.0, 5.5, 3.0 ] }
					}
				},
				{
					"name": "leg4",
					"from": [ 11.0, -9.0, 11.0 ],
					"to": [ 14.0, 0.5, 14.0 ],
					"rotationOrigin": [ 11.0, 0.5, 11.0 ],
					"faces": {
						"north": { "texture": "#oak", "uv": [ 2.0, 1.5, 11.5, 4.5 ], "rotation": 90 },
						"east": { "texture": "#oak", "uv": [ 5.0, 0.0, 14.5, 3.0 ], "rotation": 90 },
						"south": { "texture": "#oak", "uv": [ 1.0, 2.5, 10.5, 5.5 ], "rotation": 90 },
						"west": { "texture": "#oak", "uv": [ 3.0, 5.5, 12.5, 8.5 ], "rotation": 90 },
						"up": { "texture": "#null", "uv": [ 0.0, 0.0, 3.0, 3.0 ], "enabled": false },
						"down": { "texture": "#oak", "uv": [ 9.0, 6.5, 12.0, 9.5 ] }
					}
				},
				{
					"name": "leg5",
					"from": [ 2.0, -9.0, 11.0 ],
					"to": [ 5.0, 0.5, 14.0 ],
					"rotationOrigin": [ 5.0, 0.5, 11.0 ],
					"faces": {
						"north": { "texture": "#oak", "uv": [ 5.0, 9.5, 14.5, 12.5 ], "rotation": 90 },
						"east": { "texture": "#oak", "uv": [ 3.0, 0.5, 12.5, 3.5 ], "rotation": 90 },
						"south": { "texture": "#oak", "uv": [ 0.0, 11.5, 9.5, 14.5 ], "rotation": 90 },
						"west": { "texture": "#oak", "uv": [ 2.0, 1.5, 11.5, 4.5 ], "rotation": 90 },
						"up": { "texture": "#null", "uv": [ 0.0, 0.0, 3.0, 3.0 ], "enabled": false },
						"down": { "texture": "#oak", "uv": [ 3.5, 12.5, 6.5, 15.5 ] }
					}
				},
				{
					"name": "cloth",
					"from": [ 2.0, 2.2, 2.0 ],
					"to": [ 14.0, 2.7, 14.0 ],
					"rotationOrigin": [ 2.0, 2.2, 2.0 ],
					"faces": {
						"north": { "texture": "#cover", "uv": [ 2.5, 6.0, 14.5, 6.5 ] },
						"east": { "texture": "#cover", "uv": [ 2.5, 3.5, 14.5, 4.0 ] },
						"south": { "texture": "#cover", "uv": [ 2.5, 13.0, 14.5, 13.5 ] },
						"west": { "texture": "#cover", "uv": [ 2.5, 2.5, 14.5, 3.0 ] },
						"up": { "texture": "#cover", "uv": [ 2.5, 2.5, 14.5, 14.5 ] },
						"down": { "texture": "#null", "uv": [ 0.0, 0.0, 12.0, 12.0 ], "enabled": false }
					}
				},
				{
					"name": "Cube2",
					"from": [ 2.5, -7.5, 4.0 ],
					"to": [ 3.5, -6.5, 12.0 ],
					"rotationOrigin": [ 3.5, -6.5, 4.0 ],
					"rotationZ": -10.0,
					"faces": {
						"north": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
						"east": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"south": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
						"west": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"up": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 8.0 ] },
						"down": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 8.0 ] }
					}
				},
				{
					"name": "Cube3",
					"from": [ 11.5, -7.5, 4.0 ],
					"to": [ 12.5, -6.5, 12.0 ],
					"rotationOrigin": [ 11.5, -6.5, 4.0 ],
					"rotationZ": 10.0,
					"faces": {
						"north": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
						"east": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"south": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
						"west": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"up": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 8.0 ] },
						"down": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 8.0 ] }
					}
				},
				{
					"name": "Cube4",
					"from": [ 4.0, -7.5, 2.5 ],
					"to": [ 12.0, -6.5, 3.5 ],
					"rotationOrigin": [ 5.0, -6.5, 3.5 ],
					"rotationX": 10.0,
					"faces": {
						"north": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"east": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
						"south": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"west": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
						"up": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"down": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] }
					}
				},
				{
					"name": "Cube5",
					"from": [ 4.0, -7.5, 12.5 ],
					"to": [ 12.0, -6.5, 13.5 ],
					"rotationOrigin": [ 5.0, -6.5, 12.5 ],
					"rotationX": -10.0,
					"rotationZ": 1.0,
					"faces": {
						"north": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"east": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
						"south": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"west": { "texture": "#oak", "uv": [ 0.0, 0.0, 1.0, 1.0 ] },
						"up": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] },
						"down": { "texture": "#oak", "uv": [ 0.0, 0.0, 8.0, 1.0 ] }
					}
				}
			]
		}
	]
}

We've created a block, added a recipe, and now edited a shape. With these skills, you're well on your way to becoming a successful modder for Vintage Story. There's just one more thing to do... How do we package our mod and send it off to other people? Find out in the next section!

VSMC can be a tough beast to tame, but is very rewarding when you find out how to use it efficiently. We only scratched the surface with this tutorial. The wiki is a bit limited on VSMC tutorials at the moment, but I recommend watching the tutorials provided by Tenth Architect, which can be found here:

  1. Part 1: Modelling
  2. Part 2: Design
  3. Part 3: UV Mapping
  4. Part 4: Texturing
  5. Part 5: Animating

Using the ModMaker.exe (Packaging a Mod)

Please note that the mod maker program is due to receive some updates to make it more functional. This section of the tutorial may change at any time.

So, we now have a block, a recipe, and a custom shape! The problem at the moment is that all of our files are scattered in with the game assets. As we get more files that we have modified, this is going to become more and more unmanageable to distribute to other people. That is one of the problems that the mod maker tries to solve. The mod maker will automatically find our changed files, and export them into a zip file that can be loaded by the game.

Let's jump into it.

For Linux Flatpak Users...
The mod maker requires a bit of extra setup for Flatpak users. You will need to install the appropriate version of dotnet for your version of Linux (see 'Installing .NET' here) and you will also need to create folders to the path: /home/user/.config/VintagestoryData/Mods. After the mod is fully complete, you will need to move the zip file from this folder into the Vintage Story Data mods folder, which can be easily accessed from the in-game mod manager.

Packaging our Mod

Before continuing, it is highly recommended to make a backup of your assets folder. You will also need an internet connection for this to work.

When launched, the mod maker will look similar to this

The first step for all of this is finding the mod maker. The modmaker.exe is found directly in the installation folder, the same place where the 'assets' folder is located. If in doubt, just go into your assets folder and then go the folder above that.

On Windows, you can double click the mod maker to run it. A command-prompt style window will open.

On other platforms, you may have to use the terminal or command prompt. Open a terminal in the folder that contains the modmaker, and simply run ./ModMaker or ./ModMaker.exe. The modmaker will launch inside of the terminal that was used to open it.

Step-By-Step

  1. You'll see a list of 5 options. For now, we only need to worry about options 1 and 3. Enter '1' into the terminal, and then press enter/return to submit. The program will inform you about what it does, and also inform you that textures will not be copied. We will copy these over afterwards.
  2. The program should automatically detect your game version, based on the assets that are included. Press enter if it is correct to move on.
  3. If this is the first time running the mod maker for this game version, it will automatically download a set of unmodified assets. The modmaker will automatically compare against these files. Wait for the download to finish.
  4. You will be asked whether you want to skip the shape files. Since we want to include checking the shape files, type 'N' and press enter.
  5. The mod maker will now scan for file changes, and will let you know of its progress. You should notice a few of the changed files as it progresses.
  6. You will be asked for a name for your mod. I have called mine 'Tutorial Mod Set'.
  7. You will now be asked for a unique ID for your mod. As stated in the mod maker, this must be all lowercase letters and numbers, and should start with a letter. I have called mine 'tutorialmodset'.
  8. You will be asked for an author name. Enter your name.
  9. Your mod will now be packaged, and you will be told what folder the zip file is created to. This is usually the folder that mods get loaded from for Vintage Story.

There are a few additional changes that need to be made to our mod before it works correctly.

Re-Adding Textures

The mod maker does not currently automatically add textures to a mod file. Let's re-add them.

  1. Using the file path that was given in step 9 before, locate the mod file .zip that was created.
  2. Unzip the file. This can usually be done by right clicking on the file and select 'Extract archive'.
  3. You should now have a folder that contains an assets folder. Enter it, and then go to the game folder. You will notice another folder called survival. Due to how domains work, we need to move all the contents of the survival folder into the mod's 'game' folder. After that, delete the now-empty survival folder.
  4. In the game folder, create a new folder called 'textures', and then a folder inside of that called 'block'.
  5. You will now need to find your original texture file from when we made our block. Mine was called 'paneledwood.png', so I copied that file and pasted it into the new 'textures/block' folder inside our mod's assets folder.

Your texture will now be included in your mod.

Re-Adding Lang Entries

The mod maker tries patching lang files, but unfortunately does so incorrectly, which causes our block name to be displayed incorrectly. We will need to create a lang folder and file inside of our mod, and re-add the new lang entries into this file.

  1. In our unzipped mod file from before, go to assets/game/survival, and create a folder called 'lang'.
  2. Locate the previously-edited lang file. This will be located in the game assets, under assets/game/lang/en.json. Copy this file, and paste it into our newly-created lang folder.
  3. Open the file. Remove all entries, except the final entry that we setup for our block. The final file should look like the one given below.
  4. In our mod folder, go to 'assets/tutorialmodset/patches', and delete the file called 'game-lang-en.json'. This is the modmakers incorrectly generated format for the lang file, which we do not need.
en.json (in our mod folder)
{
	"block-paneledwood": "Paneled wood"
}

Our lang entries should now be restored for our mod.

Re-Zipping the Mod

Your mods folder should look like this when finished

We now need to create a zip file for our mod which includes the files we just edited.

In our mods folder, where the original zip file for our mod was created, you can now delete the originally created zip file. This should leave a single folder.

Open the single folder, and select both the modinfo file and the assets folder. With both selected, right click on them and select 'Add to archive', or 'Compress'. It is important to zip the contents of the folder and not the folder itself, otherwise the game will not recognize your mod. The name of the zip file is up to you, but the standard is modid-vVersion. In my case, the zip file would be named tutorialmodset-v1.0.0.

Now, move the newly created zip file directly into the mods folder that the original was created in, and delete the extracted folder. You should be left with a single zip file inside of your mods folder.

Removing Previous Content

Once again, ensure you have backed-up your assets folder. The following process is not easily reversible.

Following the steps from earlier, reopen the mod maker. This time, you will want to select option 3. This will delete any new or m odified files from the base game assets, and will also restore any original files, leaving you with a fresh assets workspace. Note that the textures are not deleted, but these will not be loaded by the game if they are not used.

Testing & Finalizing

The mod manager from the main menu should now have your mod included in the list

So, let's give our mod one last test. Run the game, and from the main menu, enter the mod manager.

Hopefully, your mod will be listed in the list of mods!

Thanks for reading! We hope you have a fun time modding Vintage Story!
(Debugging) Mod not listed?
If your mod is not listed at all, then it is likely placed in the wrong folder. From the mod manager, select 'Open Mods Folder' and check your zip file is located in this folder. If it is not, then make sure to move it in there. If it is inside this folder and is still not listed, then you may have a certain system configuration that is making it difficult for the game to read from the folder. Try asking on the [ https://www.vintagestory.at/forums/forum/36-mod-development-questionstroubleshooting/ Vintage Story Forums] or Vintage Story Discord Server for more support.
(Debugging) "Unable to load mod. Check log files."
The most common cause of this, when using the mod maker, is that your mod has been zipped incorrectly, or the unzipped folder has not been removed. Select 'Open Mods Folder', and check there is only a single file in the folder. If it is the only file, then you may have to unzip it and try again. Remember to only zip/compress the contents of the folder, not the folder itself, as this will cause an invalid file structure for your mod.

For other mods, this may also mean that your modinfo.json is invalid. This is automatically created by the mod maker, so for our purposes it should be okay. If you are still having a problem, try asking on the [ https://www.vintagestory.at/forums/forum/36-mod-development-questionstroubleshooting/ Vintage Story Forums] or [ https://discord.gg/vintagestory Vintage Story Discord Server] for more support.

Let's create a new world! It's a good idea to create a new test world instead of using one that you have used before, as it will ensure that there is no content left over from the previous tests that will interfere with our mod.

Test the following:

  1. The paneled wood block (or whatever block you created) exists. (Blocktype is loading correctly!)
  2. Your block has the correct name. (Lang file is loading correctly!)
  3. The chair has kept its edits. (Shape file patch is loading correctly!)
  4. The recipe for gold ingots still works. (Grid recipe file is loading correctly!)

If all of those work, then congratulations! You set up your mod correctly and now have a zip file that can be given to other people to play with your mod!

If there are any issues with your mod at this stage, then restore your backup and try to repeat each step inside the 'Using The Mod Maker' section. If each individual component worked during creation, then it's likely something has gone wrong when setting up your zip file.

Concluding the Tutorial

That finishes up this tutorial! You've learned how to edit assets, created a block, a grid recipe, edited a shape, and zipped our mod into a file that can be distributed to other people!

You may have realized by now that there is a lot you can do to mod Vintage Story, and editing asset files is just the beginning. The possibilities for modding are truly endless. It's a long journey to learn everything, but there are a lot of resources to help and a whole modding community that can be found on both the [ https://www.vintagestory.at/forums/forum/36-mod-development-questionstroubleshooting/ Vintage Story Forums] and [ https://discord.gg/vintagestory Vintage Story Discord Server] who are always willing to help.

We would like to wish you all the best in your mod-making journey, and hope you have a lot of fun with making your own content for our game! Or perhaps, after modding it, you can make it into your game...