-
Notifications
You must be signed in to change notification settings - Fork 0
KubeJS
Dynamic Brewing adds event.brewing to KubeJS's ServerEvents.recipes event.
ServerEvents.recipes(event => {
event.brewing.add(output, input, ingredient)
event.brewing.remove(filter)
})The argument order is deliberately output-first, matching normal KubeJS recipe functions:
-
output: anItemStack, including count and components -
input: anIngredientfor the bottle/container slot -
ingredient: anIngredientfor the brewing catalyst slot
Call .id(...) on a newly added recipe to give it a stable ID.
ServerEvents.recipes(event => {
event.brewing
.add('minecraft:diamond', 'minecraft:apple', 'minecraft:stick')
.id('kubejs:brewing/apple_to_diamond')
})Item component filters use the same bracket syntax as Minecraft's /give command. The input below matches a Water Potion, not every item whose ID is minecraft:potion.
ServerEvents.recipes(event => {
event.brewing.add(
'minecraft:potion[potion_contents={potion:"minecraft:awkward"}]',
'minecraft:potion[potion_contents={potion:"minecraft:water"}]',
'minecraft:nether_wart'
).id('kubejs:brewing/water_to_awkward')
})The output is parsed as an exact stack. The input and ingredient are parsed as ingredient filters.
KubeJS Item helpers are often easier to read than a long component string:
ServerEvents.recipes(event => {
const result = Item.of('minecraft:diamond')
.withCustomName(Text.aqua('Arcane Diamond'))
.enchant('minecraft:fortune', 3)
event.brewing
.add(result, 'minecraft:apple', '#c:rods/wooden')
.steps(1) // optional JEI display override
.id('kubejs:brewing/arcane_diamond')
})When .steps(...) is omitted, Dynamic Brewing infers the shortest chain. Any input not produced by another brewing recipe is treated as step 0, so a standalone Apple → Diamond recipe displays as step 1 automatically.
An explicit step is a JEI display override. It does not change brewing time, and it becomes the starting distance used to infer recipes later in that displayed chain.
Tags, lists, intersections, and subtractions work because both input positions are real KubeJS ingredients:
ServerEvents.recipes(event => {
const catalyst = Ingredient.of('#c:dusts')
.except('minecraft:redstone')
event.brewing.add(
Item.of('minecraft:emerald').withCustomName('Distilled Emerald'),
['minecraft:apple', 'minecraft:golden_apple'],
catalyst
).id('kubejs:brewing/distilled_emerald')
})Use /kubejs hand while holding an item to get a copyable representation. This is especially useful for custom components from other mods.
ServerEvents.recipes(event => {
const chargedInput = Ingredient.of(
'example:crystal[example:charge=100]'
)
event.brewing.add(
'example:refined_crystal[example:charge=0]',
chargedInput,
'minecraft:glowstone_dust'
).id('kubejs:brewing/refine_charged_crystal')
})Whether partial component matching is available depends on the ingredient syntax or custom ingredient type being used. A plain item ID ignores components; a component-bearing ingredient filters them.
KubeJS can register a custom effect and the potion that contains it from a startup script:
StartupEvents.registry('mob_effect', event => {
event.create('kubejs:effervescence')
.displayName('Effervescence')
.beneficial()
.color(0x45D6FF)
})
StartupEvents.registry('potion', event => {
event.create('kubejs:effervescence')
.effect('kubejs:effervescence', 20 * 60, 0)
})Only the normal-potion recipe needs to be added in server_scripts:
ServerEvents.recipes(event => {
event.brewing.add(
'minecraft:potion[potion_contents={potion:"kubejs:effervescence"}]',
'minecraft:potion[potion_contents={potion:"minecraft:awkward"}]',
'minecraft:amethyst_shard'
).id('kubejs:brewing/effervescence')
})The built-in generic conversions then preserve kubejs:effervescence automatically:
- Awkward Potion + Amethyst Shard → Potion of Effervescence
- Potion of Effervescence + Gunpowder → Splash Potion of Effervescence
- Splash Potion of Effervescence + Dragon's Breath → Lingering Potion of Effervescence
This requires the generic minecraft:brewing/splash/all and minecraft:brewing/lingering/all recipes to remain loaded. A pack that removes every Minecraft-owned brewing recipe must retain or recreate those two conversions.
Removal is always scoped to the dynamic_brewing:brewing recipe type, even if the filter would match recipes of another type.
ServerEvents.recipes(event => {
// One exact recipe ID
event.brewing.remove({ id: 'minecraft:brewing/base/awkward' })
// Every brewing recipe owned by Minecraft
event.brewing.remove({ mod: 'minecraft' })
// Recipes producing diamonds
event.brewing.remove({ output: 'minecraft:diamond' })
// Recipes using redstone in either input role
event.brewing.remove({ input: 'minecraft:redstone' })
})String shorthand is treated as a recipe ID:
event.brewing.remove('minecraft:brewing/base/awkward')- Put scripts in
kubejs/server_scripts/. - Run
/reloadafter editing them. - Check
logs/kubejs/server.logfor added, removed, or failed recipe counts. - Use
/kubejs handto inspect the held stack and its components. - Avoid defining multiple recipes with the same effective input and ingredient; matching order is not a priority system.