Modding:Content Tutorial Block Variants: Difference between revisions

From Vintage Story Wiki
(Created page. In progress.)
 
(Marked this version for translation)
 
(3 intermediate revisions by the same user not shown)
Line 3: Line 3:
{{GameVersion|1.19.7}}
{{GameVersion|1.19.7}}
__FORCETOC__
__FORCETOC__
In progress.
== Introduction == <!--T:1-->


== Introduction ==
=== Objective === <!--T:2-->
The variant system has an extensive amount of uses. In this tutorial, we will create a set of blocks with independent textures, using two separate variant groups. These blocks will show you how you can mix variant groups together to create a huge number of new assets.


=== Objective ===
=== Assets === <!--T:3-->
So far, the tutorials have only scratched the surface of creating new assets. To make your modding more efficient, you can utilize the variant system to create numerous similar objects from a single json file, and allow each object to have minor (or major) differences.
Before starting, it is recommended you [https://github.com/Nateonus/vsmodexamples/releases/tag/BlockVariantsTutorial download the workspace and assets] for this tutorial. The completed files can also be found here.  
 
In this tutorial you will create a set of items using variants, each with independent textures. The items will not have any functionality, however this tutorial should give you a good understanding of what variants are and how to use them.
 
=== Assets ===
Before starting, it is recommended you [https://github.com/Nateonus/vsmodexamples/releases/tag/ItemVariantsTutorial download the workspace and assets] for this tutorial. The completed files can also be found here.  


<!--T:4-->
This tutorial starts with the following assets:
This tutorial starts with the following assets:


<!--T:5-->
* Mod Setup & Folder Structure
* Mod Setup & Folder Structure
* Template advanced wand file
* Template advanced shiny block file
* Completed lang file
* Completed lang file
* Item shape file
* Block texture files
* Item texture files


=== Prerequisites ===
=== Prerequisites === <!--T:6-->
This tutorial will assume you understand the following topics:
This tutorial will assume you understand the following topics:


<!--T:7-->
* [[Modding:Developing a Content Mod|Setting up a content mod and using an IDE.]]
* [[Modding:Developing a Content Mod|Setting up a content mod and using an IDE.]]
* [[Modding:Content Tutorial Basics|The functions of shape, texture and lang files.]]
* [[Modding:Content Tutorial Basics|The functions of shape, texture and lang files.]]


It is recommended to have completed the following tutorial:
<!--T:8-->
It is recommended to have completed the following tutorials:


* [[Modding:Content Tutorial Simple Item|2. Simple Item]] - The simple item made in this tutorial is the basis for this tutorial.
<!--T:9-->
* [[Modding:Content Tutorial Simple Block|3. Simple Block]] - The simple block made in this tutorial is the basis for this tutorial.
* [[Modding:Content Tutorial Item Variants|5. Item Variants]] - This tutorial gives a good beginning stage for creating variants. These tutorials will also be formatted very similarly.


<!--T:10-->
It is recommended, but not necessary, to understand the following concept:
It is recommended, but not necessary, to understand the following concept:


<!--T:11-->
* [[Modding:Variants|Variants]]
* [[Modding:Variants|Variants]]


== Navigating Assets ==
== Navigating Assets == <!--T:12-->
Using the downloaded workspace, have a look at the mod assets that currently exist.
Using the downloaded workspace, have a look at the mod assets that currently exist.


* ''itemtypes/advancedwand.json'' - This itemtype file is from the finished [[Modding:Content Tutorial Simple Item|Simple Item]] tutorial.
<!--T:13-->
* ''blocktypes/advancedshinyblock.json'' - This blocktype file is from the finished [[Modding:Content Tutorial Simple Block|Simple Block]] tutorial.
* ''lang/en.json'' - This already contains the entries needed for the tutorial.
* ''lang/en.json'' - This already contains the entries needed for the tutorial.
* ''shapes/item/advancedwand.json'' - The shape file for the new wand. If you open this file in your IDE, you should notice that this new model takes in two textures - ''head'' and ''handle''.
<syntaxhighlight lang="json">
"textures": {
"head": "item/wand-blue",
"handle": "item/wand-handle"
},
</syntaxhighlight>


* ''textures/item/wand-...'' - The four texture files for our wand. Notice that there exists 3 variants of colored texture, and 1 handle texture.
<!--T:14-->
* ''textures/block/shiny...'' - The four texture files for our blocks. Notice that we are using gold and iron textures, and both have 'damaged' states.
 
== Defining Variants == <!--T:15-->
All work in this tutorial will be done in the ''blocktypes''/''advancedshinyblock.json'' file. Open it in your IDE and you can get started.


== Defining Variants ==
<!--T:16-->
All work in this tutorial will be done in the itemtypes/''advancedwand.json'' file. Open it in your IDE and you can get started.
Firstly, the item's code is still set to "''simplegoldblock"''. Change this to "''advancedshinyblock"''.  


Firstly, the item's code is still set to "''simplewand"''. Change this to "''advancedwand"''.  
<!--T:17-->
Before you can utilize any variant systems, you will need to define the variants for your block. To do this, use the ''"variantGroups"'' property. This is ''usually'' placed directly below the ''code'' property, but it would work anywhere in the object.


Before you can utilize any variant systems, you will need to define the variants for your item. To do this, use the ''"variantGroups"'' property. This is ''usually'' placed directly below the ''code'' property, but it would work anywhere in the object.<syntaxhighlight lang="json">
<!--T:18-->
For this block, we are going to create two variant groups.<syntaxhighlight lang="json">
"variantgroups": [
"variantgroups": [
    {
{
      "code": "wandtype",
"code": "type",
      "states": [ "blue", "red", "green" ]
"states": [ "gold", "iron" ]
    }
},
{
"code": "condition",
"states": [ "good", "used" ]
}
],
],
</syntaxhighlight>This example will create a single variant group called ''"wandtype''". The variant code is used for a number of purposes, so make sure it is named sensibly and clearly. After the code property, we can define a list of states in an array. As you have only defined a single variant group, each entry in state will create a single object.
</syntaxhighlight>This example creates two variant groups - Named "''type''" and "''condition''". When you use more than one variant group, the game will create block codes using every permutation of those two groups.  


If you were to test the mod now, you will see that there exists three wand objects with the codes:
<!--T:19-->
If you were to test the mod now, you will see that there exists four block objects with the codes:


* ''advancedwand-blue''
<!--T:20-->
* ''advancedwand-red''
* ''advancedshinyblock-gold-good''
* ''advancedwand-green''
* ''advancedshinyblock-gold-used''
* ''advancedshinyblock-iron-good''
* ''advancedshinyblock-iron-used''
Notice that the order your variant groups are defined affects the order they appear in the ID. When using variants, especially when using wildcards, this is important to remember.


However, the items do not have valid textures or shapes attached to them.  
<!--T:21-->
As you probably expected by now, these blocks do not have the appropriate textures.  


[[File:ContentTutorialItemVariantsWandsAddedNoShapeOrTexture.png|frameless]]
<!--T:22-->
[[File:BlockVariantsContentTutorial Block all with same textures..png|frameless]]


== Adding Multiple Textures ==
== Variant-Based Textures == <!--T:23-->
Before adding any textures to the object, you should update the object to the new shape. Find the "''shape"'' property and make it use "''item/advancedwand"'' instead of the current value.
As explained in the [[Modding:Content Tutorial Item Variants|Item Variants]] tutorial, there are two ways of using variants - ''ByType'' and ''Substitution''. In this tutorial, you're going to use both methods. Before continuing, it may be a good idea to refresh yourself about how both methods work in the item variants tutorial.


Currently, your item is using a single texture. Remember that the new shape contains two textures, so you will now need to define both textures within the item. Replace the entire "''texture"'' property (including the values and { }'s) with the following property:<syntaxhighlight lang="json">
<!--T:24-->
This is the current texture property:<syntaxhighlight lang="json">
"textures": {
"textures": {
    "handle": { "base": "item/wand-handle" },
"all": { "base": "block/shinygoldtexture" }
    "head": { "base": "item/wand-blue" }
},
},
</syntaxhighlight>This code allows the use of two textures. It is important to note that the keys for this property, namely "''handle"'' and "''head"'', match to the textures defined in the shape file.
</syntaxhighlight>This blocktype has a total of four variants - That's not many. Although you could create a ''byType'' entry for each variant code, it is a good idea to understand how you can use a mixture of the two methods. Keep in mind, similar to the item variants, there are a number of ways to achieve the final result. Feel free to experiment with other methods, variants are a complex but beautiful subject when used effectively.


You may have noticed that the property is going to turn all the wand heads blue.
<!--T:25-->
Using the ''ByType'' suffix, you can split the texture by the condition variant:<syntaxhighlight lang="json">
"texturesbytype": {
"*-good": {
"all": { "base": "block/shinygoldtexture" }
},
"*-used": {
"all": { "base": "block/shinygoldtexture" }
}
},
</syntaxhighlight>A quick reminder of wildcards may be in order. When using the ''ByType'' suffix, each object's resolved code will start at the first key (''"*-good")'' listed and go down the list. If the resolved code matches with the given string, if will then use that key's property. Using an asterisk ( '''*''' ) in a key tells the game that ''any'' string can go here. So, in this example, here is the list of matching objects:
{| class="wikitable"
!"*-good"
|"advancedshinyblock-gold-good", "advancedshinyblock-iron-good"
|-
!"*-used"
|"advancedshinyblock-gold-used", "advancedshinyblock-iron-used"
|}
Although not used in this example, you can simply use an asterisk as a byType key to match everything. This is useful when you wish to specify a value for a single object, but have every other object use a different value.
{| class="wikitable mw-collapsible mw-collapsed"
|Why can't you use "'''*-gold'''" as a key?
|-
|Remember that the order of the variant groups is important when using wildcards. In every example where wildcards have been used, it has always been to specify the final variant. The ID of, for example, "advancedshinyblock-gold-good" does ''not'' fit within the wildcard "*-gold", as "gold" is not the final part of the code.
As such, you would have to use "'''*-gold-*'''". This will accept any string before "'''-gold-'''" as well as any string after it.
|}
''Anyway, back to the code.''


[[File:ContentTutorialItemVariantsInGameButAllSameTexture.png|frameless]]
<!--T:26-->
 
The given code sample doesn't actually specify a different texture for each type. Replace each texture property with a specific variant substitution.<syntaxhighlight lang="json">
You would be correct.
"texturesbytype": {
 
"*-good": {
== Variant-Based Textures ==
"all": { "base": "block/shiny{type}texture" }
When using variants, there are two ways of adding differences between your objects. Read both methods first, and then decide which is more suitable in this case.
},
 
"*-used": {
=== ByType ===
"all": { "base": "block/shiny{type}texture-damaged" }
By using the ByType suffix on a property, you can specify completely different values for each variant.<syntaxhighlight lang="json">
}
"texturesByType": {
  "advancedwand-blue": {
"handle": { "base": "item/wand-handle" },
"head": { "base": "item/wand-blue" }
  },
  "advancedwand-red": {
"handle": { "base": "item/wand-handle" },
"head": { "base": "item/wand-red" }
  },
  "advancedwand-green": {
"handle": { "base": "item/wand-handle" },
"head": { "base": "item/wand-green" }
  }
},
},
</syntaxhighlight>However, a lot of content here is duplicated as all the wands use the same handle, and have head textures that are in the same folders.
</syntaxhighlight>As you can see, this uses the '''{type}''' to substitute "gold" or "iron" into the texture path. If you follow the code, you end up with these resolved texture paths:
{| class="wikitable"
!Block ID
!Resolved Texture Path
|-
|advancedshinyblock-gold-good
|block/shinygoldtexture
|-
|advancedshinyblock-gold-used
|block/shinygoldtexture-damaged
|-
|advancedshinyblock-iron-good
|block/shinyirontexture
|-
|advancedshinyblock-iron-used
|block/shinyirontexture-damaged
|}
If you are having issues getting any textures to work, it is often a good idea to create a table like this. For every ID, work out the resolved texture path, and ensure it exists.


The advantage of using ByType is that it is considerably versatile - If you wanted to add a completely different texture to a specific wand, you could easily achieve this by using ByType. It is also worth noting that ByType can be used on ''any'' property within an item, block, or entity, except from the main code and variant properties.
<!--T:27-->
If you now test your mod, you'll see your blocks working as expected!


=== Variant Substitution ===
<!--T:28-->
The other option is to substitute part of the texture path with each wands variant state.<syntaxhighlight lang="json">
[[File:ContentTutorialBlockVariants All Block Variants Working With Textures.png|frameless]]
"textures": {
    "handle": { "base": "item/wand-handle" },
    "head": { "base": "item/wand-{wandtype}" }
}
</syntaxhighlight>By adding our variant code inside curly brackets ('''{ }''') in the string, the head texture automatically turns into "''item/wand-blue", "item/wand-red",'' and ''"item/wand-green"'' for each respective variant object.


Evidently, this method uses considerably less code, however it does have some drawbacks. Variant substitution can only be used in properties that accept strings, usually limiting it's functionality to textures, shapes, and sounds. As well as this, it offers less customizability of what textures you can use, as they would all have to be located in specific file paths.
== Conclusion == <!--T:29-->
Congratulations, you now have four variants of a single block, all within one file! After this tutorial, you should have more of an understanding of how variants can be grouped together, and how to get the most out of them.  


=== Which to use? ===
=== Next Steps... === <!--T:30-->
Honestly, it doesn't matter which method you choose, as both achieve the same result. In a lot of cases, a mixture of using both ByTypes and substitution is the best option: you could specify a unique texture for a more unique variant, but then use substitution on all of the other variants. By using the ByType method, you could choose to have completely different handle textures, however the substitution method offers considerably neater and shorter code.
 
If you load the game, you should be able to see your three different wands, each using a different primary color.
 
[[File:ContentTutorialItemVariantsWorking.png|frameless]]
 
== Conclusion ==
Congratulations, you now have three variants of a single item, all within one file! This tutorial should have given you a good understanding of what variants are and how they work, as well as the potential they can have when making content mods.
 
=== Next Steps... ===
If you want to test your knowledge, consider doing the tasks under the ''Going Further'' section below.
If you want to test your knowledge, consider doing the tasks under the ''Going Further'' section below.


Now that you've had a proper introduction to variants, go take a look at the [[Modding:Content Tutorial Block Variants|Block Variants]] tutorial. This will give you even more experience in creating and using variants.
<!--T:31-->
Variants are pretty nifty, but they can get even better. Take a look at the next tutorial, [[Modding:Content Tutorial Complex Grid Recipes|Complex Grid Recipes]] for a demonstration on how to use variants inside recipes.


== Going Further ==
== Going Further == <!--T:32-->
Want to make some additional changes to this mod? Try and achieve the following things!
Want to make some additional changes to this mod? Try and achieve the following things!


Create a new colored wand.
<!--T:33-->
Make the '<nowiki/>''used''<nowiki/>' blocks destroy faster than the '<nowiki/>''good''' blocks.
{| class="wikitable mw-collapsible mw-collapsed"
{| class="wikitable mw-collapsible mw-collapsed"
|To achieve this...
|To achieve this...
|-
|-
|Add a new state to the ''wandtype'' variant, and create a new colored texture that matches to your new state. Don't forget, if you are using the 'byType', you will need to add a new entry for your new wand. You will also need to add a new entry in your lang file.
|Replace the ''resistance'' property with ''resistanceByType.'' Specify two wildcard keys, namely "'''*-good'''" and "'''*-used'''" to specify values of 3.5 and 2 respectively.
{| class="wikitable mw-collapsible mw-collapsed"
|Example...
|-
|<syntaxhighlight lang="json">
"resistanceByType": {
"*-good": 3.5,
"*-used": 2
},
</syntaxhighlight>
|}
|}
Make some new grid recipes, one for each wand color ([[Modding:Content Tutorial Simple Recipe|Simple Recipe Tutorial]]). For an extra challenge, see if you can work out how to create all three recipes from one file (Tip: arrays of recipes must be contained within square brackets ('''[ ]''')).
|}
Remove texturesByType, and achieve the same result using just variant substitution. (Hint: You will have to rename texture files)
{| class="wikitable mw-collapsible mw-collapsed"
{| class="wikitable mw-collapsible mw-collapsed"
|To achieve this...
|To achieve this...
|-
|-
|Create three new recipes based on the simple wand, making sure each one is unique. The output code for each is the resolved item code, for example "''advancedwand-blue''". Make sure your domains are correct, and [[Modding:Debugging Content|check the logs for errors]] if you struggle with this.
|There are a number of similar methods to achieve this. Here is my method:
To create more than one recipe in a file, place a comma after the final curly bracket ( '''}''' ), and then place your next recipe inside another set of curly brackets. When all recipes have been added, place an opening square bracket ( '''[''' ) at the very beginning of the file, and a closing square bracket ( ''']''' ) at the very end of the file.
Firstly, revert the "texturesByType" to a "textures" property. Change the base property to be "''block/shiny{type}texture-{condition}".'' This will result in the following ID to Texture table:
{| class="wikitable"
!Block ID
!Resolved Texture Path
|-
|advancedshinyblock-gold-good
|block/shinygoldtexture-good
|-
|advancedshinyblock-gold-used
|block/shinygoldtexture-used
|-
|advancedshinyblock-iron-good
|block/shinyirontexture-good
|-
|advancedshinyblock-iron-used
|block/shinyirontexture-used
|}
You will now have to rename the texture files to match those in the resolved texture path column.
{| class="wikitable mw-collapsible mw-collapsed"
|Example...
|-
|<syntaxhighlight lang="json">
"textures": {
"all": { "base": "block/shiny{type}texture-{condition}" }
},
</syntaxhighlight>
|}
|}
|}


<!--T:34-->
{{Navbox/contentmodding}}
{{Navbox/contentmodding}}
</translate>
</translate>

Latest revision as of 20:53, 8 April 2024

Other languages:
  • English

This page was last verified for Vintage Story version 1.19.7.


Introduction

Objective

The variant system has an extensive amount of uses. In this tutorial, we will create a set of blocks with independent textures, using two separate variant groups. These blocks will show you how you can mix variant groups together to create a huge number of new assets.

Assets

Before starting, it is recommended you download the workspace and assets for this tutorial. The completed files can also be found here.

This tutorial starts with the following assets:

  • Mod Setup & Folder Structure
  • Template advanced shiny block file
  • Completed lang file
  • Block texture files

Prerequisites

This tutorial will assume you understand the following topics:

It is recommended to have completed the following tutorials:

  • 3. Simple Block - The simple block made in this tutorial is the basis for this tutorial.
  • 5. Item Variants - This tutorial gives a good beginning stage for creating variants. These tutorials will also be formatted very similarly.

It is recommended, but not necessary, to understand the following concept:

Navigating Assets

Using the downloaded workspace, have a look at the mod assets that currently exist.

  • blocktypes/advancedshinyblock.json - This blocktype file is from the finished Simple Block tutorial.
  • lang/en.json - This already contains the entries needed for the tutorial.
  • textures/block/shiny... - The four texture files for our blocks. Notice that we are using gold and iron textures, and both have 'damaged' states.

Defining Variants

All work in this tutorial will be done in the blocktypes/advancedshinyblock.json file. Open it in your IDE and you can get started.

Firstly, the item's code is still set to "simplegoldblock". Change this to "advancedshinyblock".

Before you can utilize any variant systems, you will need to define the variants for your block. To do this, use the "variantGroups" property. This is usually placed directly below the code property, but it would work anywhere in the object.

For this block, we are going to create two variant groups.

"variantgroups": [
	{
		"code": "type",
		"states": [ "gold", "iron" ]
	},
	{
		"code": "condition",
		"states": [ "good", "used" ]
	}
],

This example creates two variant groups - Named "type" and "condition". When you use more than one variant group, the game will create block codes using every permutation of those two groups.

If you were to test the mod now, you will see that there exists four block objects with the codes:

  • advancedshinyblock-gold-good
  • advancedshinyblock-gold-used
  • advancedshinyblock-iron-good
  • advancedshinyblock-iron-used

Notice that the order your variant groups are defined affects the order they appear in the ID. When using variants, especially when using wildcards, this is important to remember.

As you probably expected by now, these blocks do not have the appropriate textures.

BlockVariantsContentTutorial Block all with same textures..png

Variant-Based Textures

As explained in the Item Variants tutorial, there are two ways of using variants - ByType and Substitution. In this tutorial, you're going to use both methods. Before continuing, it may be a good idea to refresh yourself about how both methods work in the item variants tutorial.

This is the current texture property:

"textures": {
	"all": { "base": "block/shinygoldtexture" }
},

This blocktype has a total of four variants - That's not many. Although you could create a byType entry for each variant code, it is a good idea to understand how you can use a mixture of the two methods. Keep in mind, similar to the item variants, there are a number of ways to achieve the final result. Feel free to experiment with other methods, variants are a complex but beautiful subject when used effectively. Using the ByType suffix, you can split the texture by the condition variant:

"texturesbytype": {
	"*-good": {
		"all": { "base": "block/shinygoldtexture" }
	},
	"*-used": {
		"all": { "base": "block/shinygoldtexture" }
	}
},

A quick reminder of wildcards may be in order. When using the ByType suffix, each object's resolved code will start at the first key ("*-good") listed and go down the list. If the resolved code matches with the given string, if will then use that key's property. Using an asterisk ( * ) in a key tells the game that any string can go here. So, in this example, here is the list of matching objects:

"*-good" "advancedshinyblock-gold-good", "advancedshinyblock-iron-good"
"*-used" "advancedshinyblock-gold-used", "advancedshinyblock-iron-used"

Although not used in this example, you can simply use an asterisk as a byType key to match everything. This is useful when you wish to specify a value for a single object, but have every other object use a different value.

Why can't you use "*-gold" as a key?
Remember that the order of the variant groups is important when using wildcards. In every example where wildcards have been used, it has always been to specify the final variant. The ID of, for example, "advancedshinyblock-gold-good" does not fit within the wildcard "*-gold", as "gold" is not the final part of the code.

As such, you would have to use "*-gold-*". This will accept any string before "-gold-" as well as any string after it.

Anyway, back to the code.

The given code sample doesn't actually specify a different texture for each type. Replace each texture property with a specific variant substitution.

"texturesbytype": {
	"*-good": {
		"all": { "base": "block/shiny{type}texture" }
	},
	"*-used": {
		"all": { "base": "block/shiny{type}texture-damaged" }
	}
},

As you can see, this uses the {type} to substitute "gold" or "iron" into the texture path. If you follow the code, you end up with these resolved texture paths:

Block ID Resolved Texture Path
advancedshinyblock-gold-good block/shinygoldtexture
advancedshinyblock-gold-used block/shinygoldtexture-damaged
advancedshinyblock-iron-good block/shinyirontexture
advancedshinyblock-iron-used block/shinyirontexture-damaged

If you are having issues getting any textures to work, it is often a good idea to create a table like this. For every ID, work out the resolved texture path, and ensure it exists.

If you now test your mod, you'll see your blocks working as expected!

ContentTutorialBlockVariants All Block Variants Working With Textures.png

Conclusion

Congratulations, you now have four variants of a single block, all within one file! After this tutorial, you should have more of an understanding of how variants can be grouped together, and how to get the most out of them.

Next Steps...

If you want to test your knowledge, consider doing the tasks under the Going Further section below.

Variants are pretty nifty, but they can get even better. Take a look at the next tutorial, Complex Grid Recipes for a demonstration on how to use variants inside recipes.

Going Further

Want to make some additional changes to this mod? Try and achieve the following things!

Make the 'used' blocks destroy faster than the 'good' blocks.

To achieve this...
Replace the resistance property with resistanceByType. Specify two wildcard keys, namely "*-good" and "*-used" to specify values of 3.5 and 2 respectively.
Example...
"resistanceByType": {
	"*-good": 3.5,
	"*-used": 2
},

Remove texturesByType, and achieve the same result using just variant substitution. (Hint: You will have to rename texture files)

To achieve this...
There are a number of similar methods to achieve this. Here is my method:

Firstly, revert the "texturesByType" to a "textures" property. Change the base property to be "block/shiny{type}texture-{condition}". This will result in the following ID to Texture table:

Block ID Resolved Texture Path
advancedshinyblock-gold-good block/shinygoldtexture-good
advancedshinyblock-gold-used block/shinygoldtexture-used
advancedshinyblock-iron-good block/shinyirontexture-good
advancedshinyblock-iron-used block/shinyirontexture-used

You will now have to rename the texture files to match those in the resolved texture path column.

Example...
"textures": {
	"all": { "base": "block/shiny{type}texture-{condition}" }
},


Content Modding
Basics Content Mods Developing a Content Mod
Tutorials
Concepts Modding Concepts Variants Domains Patching Remapping World Properties
Uncategorized
Icon Sign.png

Wondering where some links have gone?
The modding navbox is going through some changes! Check out Navigation Box Updates for more info and help finding specific pages.

Modding
Modding Introduction Getting Started Theme Pack
Content Modding Content Mods Developing a Content Mod Basic Tutorials Intermediate Tutorials Advanced Tutorials Content Mod Concepts
Code Modding Code Mods Setting up your Development Environment
Property Overview ItemEntityBlockBlock BehaviorsBlock ClassesBlock EntitiesBlock Entity BehaviorsWorld properties
Workflows & Infrastructure Modding Efficiency TipsMod-engine compatibilityMod ExtensibilityVS Engine
Additional Resources Community Resources Modding API Updates Programming Languages List of server commandsList of client commandsClient startup parametersServer startup parameters
Example ModsAPI DocsGitHub Repository