Skip to content

Material Properties

hp-1e edited this page Oct 31, 2026 · 7 revisions

English | 中文

Material Properties and Stat Formulas

In development: this feature is not in a released version yet. It needs HPTlib 1.1.0 or newer.

Give a material three numbers: hardness, density and toughness. Then write a linear formula once per stat type, for example "each point of hardness gives +1 attack" on head. On /reload, every material that has properties gets its stats and traits for that stat type calculated for it.

The result is ordinary Tinkers' Construct data: part tooltips, the book, JEI, tool building and repair all work as usual, and nothing is calculated while playing.

The calculation is done by HPTlib, so a plain data pack can use the same system without KubeJS (see Data pack format). This mod only lets you write it in KubeJS.

Material properties

ArsenalMaterialEvents.data(event => {
  // New material: hardness, density, toughness
  event.create('kubejs:mythril')
    .properties(4, 5, 9)
    .color('#7FD4FF')

  // Existing material, written as an object; you can add your own keys and use them in formulas
  event.extend('tconstruct:iron')
    .properties({ hardness: 6, density: 7, toughness: 5 })
    .excludeFormula('limb')
})
Method Meaning
.properties(hardness, density, toughness) Set the three properties
.properties({ ... }) Set properties by name; extra keys are custom properties
.excludeFormula(...statTypes) Do not generate data for these stat types from formulas
.replaceStats() Replace mode: drop hand-written stats and use only formula results (see below)

Missing properties count as 0.

Stat formulas

ArsenalMaterialEvents.data(event => {
  event.statFormula('head')
    .field('melee_attack', { hardness: 1 })
    .field('durability', { base: 100, toughness: 50 }, 'nearest')
    .field('mining_speed', { base: 2, hardness: 0.5, density: -0.2, min: 1 })
    .tiers({ hardness: 1 }, [[0, 'minecraft:wood'], [3, 'minecraft:stone'], [6, 'minecraft:iron'], [9, 'minecraft:diamond']])
    .trait('tconstruct:reinforced', { toughness: 0.25 }, 5)
})

With properties 4 / 5 / 9 this gives melee_attack 4, durability 550, mining_speed 3, mining tier minecraft:stone and Reinforced II.

Method Meaning
event.statFormula(statType) Start a formula for a stat type. Without a namespace, tconstruct: is assumed. Works for built-in and script stat types
.field(field, coefficients) Numeric field = base + Σ(coefficient × property)
.field(field, coefficients, round) Same, then round: none, nearest, floor or ceil
.levels(field, coefficients, [[threshold, value], ...]) Non-numeric field: calculate a score, then use the value of the highest threshold not above it
.tiers(coefficients, levels) Shortcut for .levels('mining_tier', ...) with harvest tier IDs
.trait(modifier, coefficients) Trait level = score rounded down; not added below 1
.trait(modifier, coefficients, max) Same, with a maximum level

Coefficient object keys:

Key Meaning
hardness, density, toughness, custom keys Multiplier for that property
base Constant added to the result
min, max Clamp the result
round Rounding mode, same as the third argument of .field

Integer fields such as durability should use 'nearest'.

Field names of built-in stat types:

Stat type Fields
head durability, melee_attack, mining_speed, mining_tier
handle durability, melee_damage, melee_speed, mining_speed
limb durability, accuracy, draw_speed, velocity
grip durability, accuracy, melee_damage
plating_* durability, armor, toughness, knockback_resistance

Script stat types use the field names from .field(name, ...) in Stat Types.

Part formulas

Stat formulas are shared by every part of a stat type: a pickaxe head and a broad axe head both use head. A part formula adds a bonus for one specific part item on top of that, based on the properties of the material the part is made of. It works for any part, including Tinkers' Construct's own parts.

ArsenalMaterialEvents.data(event => {
  event.partFormula('tconstruct:pick_head')
    .stat('attack_damage', { hardness: 0.5 })
    .stat('mining_speed', 'percent', { density: -0.02, min: -0.5 })
    .trait('tconstruct:lustrous', { hardness: 0.2 }, 2)
})
Method Meaning
event.partFormula(partItem) Start a formula for a part item
.stat(toolStat, coefficients) Add the calculated value to a tool stat
.stat(toolStat, operation, coefficients) Operation is base, add, percent or multiply, the same as Stat Types fields
.trait(modifier, coefficients) / .trait(modifier, coefficients, max) Give the tool a trait; level is the score rounded down, not added below 1
  • Values are multiplied by the part's scale in the tool definition, the same way as material stats.
  • A part made from a material without properties gets no bonus.
  • Only tools defined with parts get part bonuses.
  • The bonus shows on the finished tool and in the Tinker Station preview. On the part item's tooltip (at scale 1), bonus traits are listed with the material traits, and the same trait is merged into one line with the levels added together. Stat bonuses show while holding Shift: a bonus on a stat that is already listed is merged into that line as the final value, and with advanced tooltips (F3+H) the line shows the original value with the bonus in brackets. The properties themselves are not shown in game.
  • Existing tools are recalculated when they are loaded again, for example after rejoining or reloading the chunk.

Rules

  • Data is generated for every material that has properties, for every stat type that has a formula, unless the material excludes that stat type. So a material with properties can be made into every part whose stat type has a formula.
  • Fields written by hand win: if the material's stats already contain melee_attack, the formula does not change it and only fills the missing fields.
  • Replace mode (.replaceStats()) does the opposite: for every stat type that has a formula and is not excluded, the material's hand-written stats (including those from other data packs) are dropped and only the formula result is used. Traits and part bonuses are not affected and are still added on top.
  • Traits from formulas are added on top of the material's existing traits for that stat type. The material's default traits are kept. If the same trait is already there, the levels are added together (part formula traits work the same way).
  • To write a stat type completely by hand for one material, write all of its fields and add .excludeFormula(...) for it.
  • Stat types themselves cannot be defined by a data pack. They must be registered at startup, because clients need them to read material stats. Use built-in stat types or Stat Types.

Data pack format

The KubeJS methods above only generate these files, so a data pack gives exactly the same result.

Material properties go in the Tinkers' material stats file, data/<namespace>/tinkering/materials/stats/<path>.json, as a properties field next to stats. A file may contain only properties. Files from several data packs are merged key by key in priority order, so adding properties to an existing material does not replace its stats.

{
  "properties": {
    "hardness": 4,
    "density": 5,
    "toughness": 9,
    "exclude": ["tconstruct:limb"]
  },
  "stats": {
    "tconstruct:head": { "melee_attack": 10 }
  }
}

"replace": true in properties turns on replace mode, the same as .replaceStats() in KubeJS.

Stat formula, named after the stat type ID: data/<namespace>/tinkering/stat_formulas/<path>.json, for example data/tconstruct/tinkering/stat_formulas/head.json

{
  "fields": {
    "melee_attack": { "hardness": 1 },
    "durability": { "base": 100, "toughness": 50, "round": "nearest" },
    "mining_tier": {
      "score": { "hardness": 1 },
      "levels": [[0, "minecraft:wood"], [6, "minecraft:iron"], [9, "minecraft:diamond"]]
    }
  },
  "traits": [
    { "modifier": "tconstruct:reinforced", "level": { "toughness": 0.25 }, "max": 5 }
  ]
}

Part formula, named after the part item ID: data/<namespace>/tinkering/part_formulas/<path>.json, for example data/tconstruct/tinkering/part_formulas/pick_head.json

{
  "stats": [
    { "stat": "tconstruct:attack_damage", "op": "add", "value": { "hardness": 0.5 } },
    { "stat": "tconstruct:mining_speed", "op": "percent", "value": { "density": -0.02, "min": -0.5 } }
  ],
  "traits": [
    { "modifier": "tconstruct:lustrous", "level": { "hardness": 0.2 }, "max": 2 }
  ]
}

A higher-priority data pack replaces a file with the same path as a whole.

Clone this wiki locally