Tinkers 1.20 Addon Update Primer
This post is a guide for Tinkers’ Construct addon authors to update to the latest API in 1.20. As the version stabilizes, this page will get updated with any new API changes or notable deprecations. See #5281 for likely upcoming breaking changes.
Update Summary
As new alphas are released, we plan to update this primer to ensure all information is in one place. On the chance you updated your addon to an earlier addon, you may find the following useful to link to you just what changed in later alphas.
Forge
This only covers information specific to Tinkers’ Construct; for general information see the following mod migration primers from ChampionAsh5357:
3.9.1
Data packs
Java
Mantle
Data Packs
Modifier Serializer Removal
Modifier serializers have now been fully removed in favor of modifier modules. The modifier JSON syntax now requires the type to be “composable”, meaning it gets the full module loader. All functionality that was previously in a modifier serializer exists in a modifier module.
If you are a modder who previously wrote a modifier serializer, it is very simple to migrate to a module; you basically implement the same interfaces plus ModifierModule
, using any object (including a record) as the base class. If you were relying on a specific class with a DynamicModifier
with a type filter, that is no longer possible; instead make use of a custom ModuleHook
implemented by a custom module for the required behavior.
Damage Predicates
Damage predicates got significantly reworked due to Mojang migrating most fields to tags. As a result, many simple damage predicates have been moved to tag predicates. See the relevant doc for available predicates.
Damage Fluid Effect
Damage fluid effects now contain an object damage_type
containing fields melee
and ranged
to apply behavior to the damage dealt by the fluid. The fields refer to the IDs of two damage types used for melee and ranged fluid attacks respectively. Behaviors that were previously added in this JSON are now added via damage type tags.
This change is made as the recent changes to damage sources means damage type tags are the only way to apply these behaviors. They also provide much greater flexibility.
Removed explosion knockback armor stat
The armor stat tconstruct:explosion_knockback
was removed (usable notably in module types tconstruct:armor_stat
and tconstruct:max_armor_stat
) in favor of the vanila enchantment which was recently fixed. The handler was a pretty large hack so its more efficient to remove it (plus Mojang will add an attribute with the same behavior come 1.21).
This armor stat was added late in 1.19.2 so this change is unlikely to affect many mods.
Part Chest Items
The part chest no longer holds all items that extend IMaterialItem
. Instead, you must add items to the item tag tconstruct:chest_parts
. All items under tconstruct:parts
are automatically added to this tag (which you should be tagging your tool parts as anyways).
Side Inventory Whitelist
- The Crafting Station, Part Builder, and Modifier Worktable now use a whitelist for side inventories instead of a blacklist.
- Whitelist can be found at the block entity tag
tconstruct:side_inventories
.- To reiterate, the white list is block entity IDs, not block IDs. You can get block entity IDs using
/mantle tags_for targeted block_entity
.
- To reiterate, the white list is block entity IDs, not block IDs. You can get block entity IDs using
- Relevant vanilla block entities, plus several from Iron Chests, Iron Shulker Boxes, and Immersive Engineering prepopulate the whitelist.
- A new config option under debug was added which disables the whitelist. This can be used to quickly test new blocks without needing to modify the tag to decide which entries to add to the tag.
- Feel free to suggest further default whitelist entries on GitHub.
- Note my requirements for whitelisting it are the inventory fully works in the crafting station UI.
- This means you need to test it before suggesting it.
- A notable case that I’ve seen commonly that doesn’t work is inventories with max stack size larger than 64, we cannot support that without special casing currently.
Fluid Outputs
- Mantle now supports fluids using the tag preference system in fluid outputs.
- All recipes that output fluids now support fluid outputs instead, including melting byproducts.
- In datapacks, a tag output can be specified by swapping
fluid
fortag
.
Relevant new tags
Since 3.9.1
- Fluid tag
tconstruct:hide_in_creative_tanks
will stop the fluid from appearing in a prefilled tank/copper can in JEI/creative. Prepopulated withc:hidden_from_recipe_viewers
.
Resource Packs
Modifier Icon Stitching
Modifier icons no longer automatically stitch any texture path passed in. Minecraft will automatically stitch all sprites in textures/item
and textures/block
folders, and Tinkers’ Construct additionally adds textures/gui/modifiers
for use with modifier icons. If you wish to place icons in any other directory you must stitch it using the atlas JSON.
Faucet Fluid moving
The JSON files for faucet fluids were moved from assets/<domain>/models/faucet_fluid/
to assets/<domain>/mantle/model/faucet_fluid/
. See faucet fluids for more information.
Inventory and fluid model rework
Model JSON that defined fluids or items inside were removed in favor of new JSON directories. The following list describes their replacements:
mantle:inventory
: Use render item lists.mantle:fluids
: Use block fluids.tconstruct:table
: Use themantle:retextured
loader for the retexturing and render item lists for the items.tconstruct:melter
: Usetconstruct:tank
for static fluid models, block fluid for dynamic fluids, and render item lists for item placement.tconstruct:channel
: Use channel fluids.
In addition, if you were using the tconstruct:tank
model, you will likely need to add a block fluid to ensure the block entity continues to render; the tconstruct:tank
models purpose is now just rendering fluids in the model (which is more efficient for static fluids and less efficient for changing fluids).
The reason for this change was other modders deciding they need to recreate the Optifine CTM format on Fabric by wrapping every single baked model with their own class, then using Connector to work on Forge, we were forced to migrate away from loading data from JSON models. Plus, we have far better methods of data loading that have been added since those models were coded.
Modifier Slot Type Colors
Modifier slot type colors are now controlled using Mantle’s resource colors instead of a constructor paramter. They key for slot type <name>
will be stat.tconstruct.slot.<name>
.
Java
Loadable Context Propagation
The TypedMap
context parameter from RecordLoadable
is now passed through all layers of the Loadable
parsing and can be passed to any JSON deserialize or buffer decode method. As a result of this change, you can pass in more advanced contexts to your parsing, such as registry access or client data lookups.
If you made use of raw Loadable
or RecordLoadable
instantiations, you may need to adjust your code to properly obtain the context parameter and pass it to children. If you only used RecordLoadable.create()
or other builders, then you shouldn’t need any changes. Callers of the API only need to pass in context if they plan to use it; if not an empty context will be passed.
ArmorSlotType -> ArmorItem.Type
ArmorSlotType
was an enum listing all 4 armor types (helmet, chestplate, leggings, and boots). In 1.20, Mojang created a nearly identical enum called ArmorItem.Type
.
The main difference between these two enums is Mojang ordered the types top down (helmet to boots), while our original enum was bottom up (boots to helmet). Any loops using ArmorSlotType#TOP_DOWN
can simply use ArmorItem.Type#values()
, while if you need to loop in the other order that will require your own list.
The ordering notably affected SetStatsModule.ArmorBuilder#setEach
as the constructor now receives slots in the opposite order (meaning using the default constructors you now list values top down instead of bottom up). To nudge addon authors of the change, we renamed the method to SetStatsModule.ArmorBuilder#setInOrder
and updating the docs accordingly. Your JSON for your tool definition shouldn’t change when you run updated datagen.
Utilities under ArmorSlotType
were relocated:
ArmorSlotType.ArmorBuilder
->ArmorModuleBuilder
ArmorSlotType.ArmorShieldBuilder
->ArmorModuleBuilder.ArmorShieldModuleBuilder
ArmorSlotType#MAX_DAMAGE_ARRAY
->ArmorModuleBuilder#MAX_DAMAGE_ARRAY
, though indices are now top down instead of bottom up.ArmorSlotType#SHIELD_DAMAGE
->ArmorModuleBuilder#SHIELD_DAMAGE
.
Armor Texture Supplier
The armor texture supplier got reworked to better support armor trims. Instead of returning a ArmorTexture
which contains a path to your texture and a tint, ArmorTexture
is now an interface which contains a method to render your texture on the model.
The class TintedArmorTexture
gives equivalent behavior to the 1.19 armor texture supplier return. Alternatively, you can implement your own texture supplier if you need more advanced behavior.
Tinker Station Lazy Tool Stack
- The tinker station recipe now returns
RecipeResult<LazyToolStack>
instead ofRecipeResult<ItemStack>
. This makes it easier to process tool stacks inITinkerStationRecipe#updateInputs()
and makes it more efficient as the NBT need not be parsed multiple times in the table UI. - To aid in creation of successful results, see
LazyToolStack#success()
,ITinkerStationRecipe#success()
, orAbstractModifierRecipe#success()
(based on the type of recipe you are working with).
ModDataNBT Cleanup
ModDataNBT
no longer long allows setting modifier slots, just reading them.- For usages that need to change modifier slots,
ToolDataNBT
must be used. This is only available toToolStack
and the volatile modifier hooks, not standard modifier hooks in persistent data. NamespacedNBT
was removed, all usages (projectile hooks, persistent data capability) now useModDataNBT
directly. SimilarlyINamespacedNBTView
was removed in favor ofIModDataView
.
Class renames
TinkerTransformTypes
was renamed toTinkerItemDisplays
.TinkerHooks
was renamed earlier in 1.19 toModifierHooks
.ModelItem
was renamed toRenderItem
Class and method removals
RetexturedBlockItem
/TableBlockItem
were removed as they are no longer needed. Just use a standardBlockItem
/TooltipBlockItem
. All the block items did was creative tab filling which now exists outside the item instance.- Many classes had their friendly byte buffer read/write methods or their JSON serialize/deserialize methods removed. If that happened, they typically have a static field named
LOADER
orLOADABLE
which can be used for those operations. Similarly, many methods fromJsonUtils
are removed as they have an equivalent in theLoadable
API. IGenericLoader
was replaced byRecordLoadable
. Methods are similar if you wish to implement it directly, or alternatively you can make use ofLoadable
API to build aRecordLoadable
automatically.FaucetFluidLoader
is now located atFaucetFluid#REGISTRY
, with some of its helper methods moved toRenderingHelper
.InventoryModifier
andInventoryMenuModifier
were replaced withInventoryModule
andInventoryMenuModule
.- Book command suggestions were removed as the book command is now a client command so it can just directly use the registry.
Modifiers:
AbstractWalkerModifier
was replaced withArmorWalkRadiusModule
. You can implement that interface on a modifier or a module.- Many modifier fields were removed from
TinkerModifiers
, they are likely inModifierIds
Fluid Object Tags
- Fluid objects
#getForgeTag()
was renamed to#getCommonTag()
. This method is also notably now nullable. - In the builder for a fluid object, calling
commonTag()
will add the default tag underforge:
for the fluid. CallingcommonTag(name)
will set the common tag to a specific name (previous behavior). - Any objects with no call to either variant of
commonTag()
will have no common tag. This will cause relevant datagen helpers to use the local tag or the fluid directly. - To conveniently create an ingredient from the object, use
FluidObject#ingredient()
. This will automatically use the common tag if set, otherwise the local tag (for flowing objects) or the fluid itself (for non-flowing objects). - To conveniently create a reicpe result from the object, use
FluidObject#result()
. This will automatically use the common tag if set, otherwise the fluid itself.