Skip to content

Instantly share code, notes, and snippets.

Last active January 15, 2021 11:20
Show Gist options
  • Save Choonster/1ee75eecb82c001ec10eca75be924bce to your computer and use it in GitHub Desktop.
Save Choonster/1ee75eecb82c001ec10eca75be924bce to your computer and use it in GitHub Desktop.
A description of the model loading process in Minecraft Forge 1.9-1.12.1

In this document, I use strings in the format "foo:bar" to represent ResourceLocations with domain foo and path bar. I also use [square brackets] for placeholders.

The Model Loading Process


On startup and whenever the resources are reloaded (in ModelLoader#setupModelRegistry), Minecraft iterates through every registered Block (in ModelLoader#loadBlocks) and asks its custom IStateMapper (or DefaultStateMapper if none has been registered) to create a mapping between every valid IBlockState of the Block and the ModelResourceLocation for that state (with the domain and path pointing to a blockstates file and the variant to a variant within that file). It then attempts to load these models.

DefaultStateMapper looks for the blockstates file with the Block's registry name (i.e. assets/[modid]/blockstates/[name].json) and serialises each property and value of the IBlockState to create the variant name that the model is loaded from (e.g. "enabled=true,type=foobar", or "normal" if there aren't any properties).

In both the vanilla and Forge blockstates formats you specify a model for each variant in the format "[domain]:[path]", which is transformed into "[domain]:block/[path]" and then loaded by calling ModelLoaderRegistry.getModel.

ModelLoaderRegistry.getModel transforms its argument into "[domain]:models/[path]" (called the actual location) and passes it to each registered ICustomModelLoader until it's accepted by one of them. ModelLoader.VanillaLoader (the default ICustomModelLoader) will load a standard JSON model from assets/[domain]/[path].json (where [path] is the actual location's path).


After the block models have been loaded, Minecraft then loads the item models (in ModelLoader#loadItemModels). This first collects the variant names that were registered by ModelBakery.registerItemVariants, then iterates through each registered Item and its variant names (or its registry name if none were registered).

For each variant name in the format "[domain]:[path]" (i.e. a ResourceLocation variant) or "[domain]:[path]#[variant]" (i.e. a ModelResourceLocation variant), Minecraft will first attempt to load the item model by calling ModelLoaderRegistry.getModel with the ResourceLocation "[domain]:item/[path]". This follows the same loading behaviour as described above, falling back to ModelLoader.VanillaLoader.

If that fails, it will then attempt to load the model from a blockstates file by calling ModelLoaderRegistry.getModel with the ModelResourceLocation "[domain]:[path]#[variant]" ([variant] defaults to inventory). This falls back to ModelLoader.VariantLoader, which loads the blockstates file at assets/[domain]/blockstates/[path].json and the model specified by the [variant] variant.

If the model couldn't be loaded from either location, an error is logged and the missing model is used. In 1.8.9, this only includes the exception thrown when loading the model specified by the blockstates file; but in 1.9 it includes the exception thrown while loading the item model as well.


Block models (used to render blocks in the world) are specified by blockstates files in the format "[domain]:[path]", which corresponds to the block model assets/[domain]/models/block/[path].json (if it's not accepted by a custom loader first).

Item models (used to render items in inventories, entities, etc.) are loaded by calling ModelBakery.registerItemVariants (the Item's registry name is used as the default variant) and mapped to Items by calling ModelLoader.setCustomModelResourceLocation or ModelLoader.setCustomMeshDefinition.

These accept ModelResourceLocations in the format "[domain]:[path]#[variant]", which correspond to either the item model assets/[domain]/models/item/[path].json or the model specified by the [variant] variant of the assets/[domain]/blockstates/[path].json blockstates file (if they're not accepted by a custom loader first).

Forge's documentation has an introduction to blockstates files here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment