Skip to content
On this page

Modify Existing Content

Modifying vanilla (or modded) game content is just as important as adding new content. Katton provides a suite of modify* functions that let you change item properties, block behavior, entity attributes, recipes, loot tables, and villager trades — all from Kotlin scripts, all hot-reloadable.

NOTE

All modify functions live in top.katton.api.mod and are annotated @ApiStatus.Experimental. They are available on the currently supported Minecraft versions: 26.1.2 and 26.2.

Import

kotlin
import top.katton.api.mod.*

Run modifications from a ServerPhase.READY entrypoint, as shown in every example below. This gives server-dependent APIs a valid server and lets world packs replay staged changes during reload. Avoid executable modification calls at Kotlin class-load time because they bypass Katton's phase and ownership context.

Reload Behavior

Modify APIs fall into two categories based on how they interact with Minecraft's internal state:

MechanismAPIsReload Cleanup
Live mutation — writes directly to Minecraft's internal fieldsmodifyItem, modifyBlock, modifyEntityTypeChanges persist until JVM restart. Removing a modify* call from a script and reloading does not revert the change.
Staged mutation — defers writes to the datapack apply phasemodifyRecipe, removeRecipe, modifyLootTable, addVillagerTradeChanges are cleared and re-applied on every reload. Removing a call from a script and reloading cleanly drops the mutation.

1. Modify Items

Change data components on any existing item: max stack size, durability, rarity, food properties, fire resistance, crafting remainder, and attack stats.

kotlin
import net.minecraft.network.chat.Component
import net.minecraft.world.food.FoodProperties
import net.minecraft.world.item.Rarity
import top.katton.api.ServerPhase
import top.katton.api.ServerScriptEntrypoint
import top.katton.api.mod.*

@ServerScriptEntrypoint(ServerPhase.READY)
fun modifyItems() {
    // Make ender pearls stack to 64, add fire resistance, and set epic rarity
    modifyItem("minecraft:ender_pearl") {
        maxStackSize = 64
        rarity = Rarity.EPIC
        fireResistant = true
    }

    // Turn diamond into an edible food item
    modifyItem("minecraft:diamond") {
        name = Component.literal("Candy Diamond")
        foodProperties = FoodProperties.Builder()
            .nutrition(8)
            .saturationModifier(1.2f)
            .alwaysEdible()
            .build()
    }

    // Boost netherite sword attack damage
    modifyItem("minecraft:netherite_sword") {
        attackDamage = 14.0
        attackSpeed = 2.0
    }
}

Available properties:

PropertyDescription
maxStackSizeSets max stack. Katton rejects invalid > 1 && maxDamage > 0 combinations.
maxDamageSets durability.
rarityItem rarity (COMMON / UNCOMMON / RARE / EPIC).
nameDisplay name component.
foodPropertiesMakes the item edible. Katton automatically adds CONSUMABLE alongside FOOD.
fireResistantAdds DAMAGE_RESISTANT for fire damage type. Only true is supported.
craftingRemainderContainer item (e.g., bucket → empty bucket).
attackDamageSets attack damage. Katton adds a default WEAPON component if missing.
attackSpeedSets attack speed.

2. Modify Blocks

Change block properties: hardness, resistance, friction, speed/jump factor, light emission, collision flags, and sound type.

kotlin
import net.minecraft.world.level.block.SoundType
import top.katton.api.ServerPhase
import top.katton.api.ServerScriptEntrypoint
import top.katton.api.mod.*

@ServerScriptEntrypoint(ServerPhase.READY)
fun modifyBlocks() {
    // Make stone soft and sound like wool
    modifyBlock("minecraft:stone") {
        strength(0.5f)
        soundType = SoundType.WOOL
    }

    // Make obsidian glow
    modifyBlock("minecraft:obsidian") {
        lightEmission = 8
    }

    // Ice with increased friction (less slippery)
    modifyBlock("minecraft:ice") {
        friction = 0.8f
    }
}

NOTE

Katton writes changes into three layers: BlockBehaviour.Properties, live BlockBehaviour final fields, and every pre-built BlockStateBase, then calls initCache() to refresh cached shapes. This covers local-player step sounds, mob collision, and lighting.


3. Modify Recipes

Change the result, count, experience, or cooking time of an existing recipe — or remove it entirely.

kotlin
import top.katton.api.ServerPhase
import top.katton.api.ServerScriptEntrypoint
import top.katton.api.mod.*

@ServerScriptEntrypoint(ServerPhase.READY)
fun modifyRecipes() {
    // Change iron smelting to produce 3 gold ingots with bonus experience
    modifyRecipe("minecraft:iron_ingot_from_smelting_iron_ore") {
        result("minecraft:gold_ingot")
        resultCount = 3
        experience = 5.0f
        cookingTime = 60
    }

    // Remove the stone pickaxe recipe entirely
    removeRecipe("minecraft:stone_pickaxe")
}

WARNING

modifyRecipe and removeRecipe require a running server. The recipe being modified must already be registered in the live RecipeManager.


4. Modify Entity Attributes

Override default attribute values for vanilla or modded entity types — max health, attack damage, movement speed, armor, and more.

kotlin
import top.katton.api.ServerPhase
import top.katton.api.ServerScriptEntrypoint
import top.katton.api.mod.*

@ServerScriptEntrypoint(ServerPhase.READY)
fun modifyEntities() {
    // Make zombies stronger
    modifyEntityType("minecraft:zombie") {
        maxHealth(40.0)
        attackDamage(8.0)
        movementSpeed(0.32)
        followRange(40.0)
    }

    // Skeleton: faster and tougher
    modifyEntityType("minecraft:skeleton") {
        maxHealth(30.0)
        movementSpeed(0.30)
    }

    // Creeper with armor
    modifyEntityType("minecraft:creeper") {
        maxHealth(30.0)
        armor(4.0)
    }
}

Available attributes:

MethodAttribute
maxHealth(value)generic.max_health
movementSpeed(value)generic.movement_speed
knockbackResistance(value)generic.knockback_resistance
attackDamage(value)generic.attack_damage
attackSpeed(value)generic.attack_speed
armor(value)generic.armor
armorToughness(value)generic.armor_toughness
followRange(value)generic.follow_range
luck(value)generic.luck
attribute(holder, value)Any custom attribute

WARNING

Katton copies all existing attributes from the original supplier before applying overrides. Mob-specific attributes (FOLLOW_RANGE, zombie reinforcement, etc.) are preserved. Starting from LivingEntity.createLivingAttributes() alone would crash mobs.


5. Modify Loot Tables

Read an existing loot table, add or remove pools and entries, and re-register it — all from a Kotlin DSL.

kotlin
import top.katton.api.ServerPhase
import top.katton.api.ServerScriptEntrypoint
import top.katton.api.mod.*

@ServerScriptEntrypoint(ServerPhase.READY)
fun modifyLootTables() {
    // Add a diamond drop to stone blocks
    modifyLootTable("minecraft:blocks/stone") {
        pool {
            rolls = 1
            addItem("minecraft:diamond", weight = 1)
        }
    }

    // Add coal to grass block drops
    modifyLootTable("minecraft:blocks/grass_block") {
        pool {
            addItem("minecraft:coal", weight = 3)
        }
    }
}

Operations:

MethodEffect
pool { … }Append a new pool
rawPool(json)Append a raw JSON pool
removePool(index)Drop a pool at the given index
removeItem(itemId)Drop every item entry matching itemId from every pool

Within a pool { ... } block:

MemberDescription
rolls = NPool roll count (default 1)
addItem(id, weight, quality)Add an item entry
addTag(id, weight, expand)Add a tag entry
addEmpty(weight)Add an empty entry

6. Modify Villager & Wandering Trader Trades

Append new trades to profession trade sets or wandering trader pools.

kotlin
import top.katton.api.ServerPhase
import top.katton.api.ServerScriptEntrypoint
import top.katton.api.mod.*

@ServerScriptEntrypoint(ServerPhase.READY)
fun addTrades() {
    // Farmer level 1: 1 emerald → 5 apples
    addVillagerTrade("minecraft:farmer/level_1") {
        cost("minecraft:emerald", count = 1)
        result("minecraft:apple", count = 5)
        maxUses = 12
        xp = 2
        priceMultiplier = 0.05f
    }

    // Weaponsmith level 3: 8 emeralds → 1 diamond sword
    addVillagerTrade("minecraft:weaponsmith/level_3") {
        cost("minecraft:emerald", count = 8)
        result("minecraft:diamond_sword")
        maxUses = 3
        xp = 15
        priceMultiplier = 0.2f
    }

    // Wandering trader: 5 emeralds → 1 diamond
    addVillagerTrade("minecraft:wandering_trader/uncommon") {
        cost("minecraft:emerald", count = 5)
        result("minecraft:diamond")
        maxUses = 3
        xp = 0
    }
}

Configuration:

PropertyDefaultDescription
cost(itemId, count)requiredItem the merchant wants
additionalCost(itemId, count)unsetOptional secondary cost
result(itemId, count)requiredItem the merchant gives back
maxUses12Trade lock-out threshold
xp2Villager XP per trade
priceMultiplier0.05fVanilla 0.05 for farmers

NOTE

Trades appear after /katton reload. The manager snapshots every modified TradeSet on first apply and automatically cleans up previous injections on subsequent reloads.


Requirements

APINeeds server?Needs reload?
modifyItem / modifyBlock / modifyEntityTypeNoNo
modifyRecipe / removeRecipeYesApplied at reload
modifyLootTable / getLootTableYesApplied at reload
addVillagerTradeYesApplied at reload

For complete API signatures, see the Common API docs.