Difference between revisions of "BlockState JSONs"

From Forge Community Wiki
m (fixed link)
(Explanation Cleanup)
Line 7: Line 7:
 
{
 
{
 
   "variants": {
 
   "variants": {
     "axis=y": { "model": "block/oak_log" },
+
     "axis=x": {
     "axis=z": { "model": "block/oak_log", "x": 90 },
+
      "model": "minecraft:block/oak_log_horizontal",
     "axis=x": { "model": "block/oak_log", "x": 90, "y": 90 }
+
      "x": 90,
 +
      "y": 90
 +
    },
 +
     "axis=y": {
 +
      "model": "minecraft:block/oak_log"
 +
    },
 +
     "axis=z": {
 +
      "model": "minecraft:block/oak_log_horizontal",
 +
      "x": 90
 +
    }
 
   }
 
   }
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
Here we define three variant strings, and for each we use a certain model, either the upright log and the sideways log (rotated in the y direction or not). These variants will define the look of a log depending on the property `axis`.
+
Here we define three variant strings, and for each we use a certain model: the upright log and the sideways log (rotated about the y-axis or not). These variants will define the look of a log depending on the property axis.
  
A blockstate always has to be defined for all possible variant strings. When you have many properties, this results in lots of possible variants, as every combination of properties must be defined. There is also a "multipart" format that can be used to simplify defining a model separately for every single state like so:
+
A variant should be defined for every property that invokes a change in the model displayed. Any property not specified in the JSON will not have any bearing to determine the current model (e.g. '''waterlogged''' has no effect on how a model might look).
 +
 
 +
Each blockstate can be specified using one of two methods: '''variants''' and '''multiparts'''. A variant defines an associated array of states which point to the associated model to render. Note that every single property that changes the model must be defined (e.g. If 4 boolean properties defines how the model looks, then 2 ^ 4 = 16 variants must be defined). Multiparts, on the other hand, use conditions to display a certain model when true (e.g. If a model is only shown when north was true, then when that case occurs, the model will display along with any other models whose conditions are met).
 +
 
 +
For a better understanding of multiparts, let's look at a variant built fence connection:
 +
<syntaxhighlight lang="json">
 +
"east=true,north=false,south=false,west=false": { "model": "oak_fence_n", "y": 90, "uvlock": true }
 +
</syntaxhighlight>
 +
This represents one variant out of 16 possible states. Even worse, there must be models that can uniquely define unique states (a state that can be rotated to become another state is not unique for this purpose). For fences, there are 6 models: one for no connections, one connection, two connections in a straight line, two perpendicular connections, three connections, and one for all four connections.
 +
 
 +
Now let's view a modern day multipart built fence connection:
 
<syntaxhighlight lang="json">
 
<syntaxhighlight lang="json">
 
{  
 
{  
   "when": { "east": "true" },
+
   "when": { "east": "true" },
 
   "apply": { "model": "oak_fence_side", "y": 90, "uvlock": true }
 
   "apply": { "model": "oak_fence_side", "y": 90, "uvlock": true }
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
This is one case of five. You can read this as “''when east is true, use the model <code>oak_fence_side</code> rotated 90 degrees''”. This allows the final model to be built up from five smaller parts, four of which (the connections) are conditional and the fifth being the unconditional central post. This uses only two models, one for the post, and one for the side connection.
+
In this case, the JSON defines that if the east connector is true, then show the model <code>oak_fence_side</code> rotated 90 degrees. This allows the model to be broken up in only two files: the base post and the connection. It can also be represented as 5 statements, one that checks if each of the sides is connected and one that applies the base post unconditionally.

Revision as of 15:42, 11 February 2021

Blockstate JSONs are Minecraft’s way to map “variant strings” to models. A variant string can be absolutely anything, from “inventory” to “power=5” to “I am your father.” They represent an actual model, where the blockstate is just a container for them. In code, a variant string within a blockstate JSON is represented by a ModelResourceLocation.

When the game searches for a model corresponding to a block in the world, it takes the blockstate for that position, and then it uses a map within ModelManager to find the corresponding ModelResourceLocation for it, which then refers to the actual model. BlockModelShapes uses the block's registry name as the location of the blockstate JSON. (E.g. block examplemod:testblock goes to the ResourceLocation examplemod:testblock.) The variant string is pieced together from the BlockState's properties.

As an example, let’s take a look at the vanilla oak_log.json:

{
  "variants": {
    "axis=x": {
      "model": "minecraft:block/oak_log_horizontal",
      "x": 90,
      "y": 90
    },
    "axis=y": {
      "model": "minecraft:block/oak_log"
    },
    "axis=z": {
      "model": "minecraft:block/oak_log_horizontal",
      "x": 90
    }
  }
}

Here we define three variant strings, and for each we use a certain model: the upright log and the sideways log (rotated about the y-axis or not). These variants will define the look of a log depending on the property axis.

A variant should be defined for every property that invokes a change in the model displayed. Any property not specified in the JSON will not have any bearing to determine the current model (e.g. waterlogged has no effect on how a model might look).

Each blockstate can be specified using one of two methods: variants and multiparts. A variant defines an associated array of states which point to the associated model to render. Note that every single property that changes the model must be defined (e.g. If 4 boolean properties defines how the model looks, then 2 ^ 4 = 16 variants must be defined). Multiparts, on the other hand, use conditions to display a certain model when true (e.g. If a model is only shown when north was true, then when that case occurs, the model will display along with any other models whose conditions are met).

For a better understanding of multiparts, let's look at a variant built fence connection:

"east=true,north=false,south=false,west=false": { "model": "oak_fence_n", "y": 90, "uvlock": true }

This represents one variant out of 16 possible states. Even worse, there must be models that can uniquely define unique states (a state that can be rotated to become another state is not unique for this purpose). For fences, there are 6 models: one for no connections, one connection, two connections in a straight line, two perpendicular connections, three connections, and one for all four connections.

Now let's view a modern day multipart built fence connection:

{ 
  "when":  { "east": "true" },
  "apply": { "model": "oak_fence_side", "y": 90, "uvlock": true }
}

In this case, the JSON defines that if the east connector is true, then show the model oak_fence_side rotated 90 degrees. This allows the model to be broken up in only two files: the base post and the connection. It can also be represented as 5 statements, one that checks if each of the sides is connected and one that applies the base post unconditionally.