Skip to content

KubeJS Recipes

Frinn38 edited this page Apr 28, 2022 · 19 revisions

Custom Machine recipes can be made with KubeJS.

Create a .js file in the kubejs/server_scripts/ folder (ex: custom_machine_recipes.js).

Then inside the .js file you can use the recipes kubejs event to get the custom machine recipe builder, pass it the id of the machine you want to make the recipe for and the duration of the recipe (in ticks).

onEvent('recipes', event => {

  event.recipes.custommachinery.custom_machine("namespace:machine_id", duration)

})

Requirements

You can now add various requirements by calling the methods below directly on the custom machine recipe builder.

Items

Use one of these methods to add an Item Requirement to the recipe.

.requireItem(item)
.requireItem(item, "slot")

.requireItemTag("tag", amount)
.requireItemTag("tag", amount, nbt)
.requireItemTag("tag", amount, "slot")
.requireItemTag("tag", amount, nbt, "slot")

.produceItem(item)
.produceItem(item, "slot")
  • The item param must be created using Item.of() KubeJS method. Example : Item.of("minecraft:diamond", 42)
  • The slot param must be a string corresponding to a slot id defined in a custom machine json Item Component slot property.
  • The tag param must be a string starting with # defining a valid tag id. Example : "#forge:stone"
  • The amount param must be a positive integer.
  • The nbt param must be a map. Example: {nbt1: 1, nbt2: "something"}.
Durability

Use one of these methods to add a Durability Requirement to the recipe.

.damageItem(item, amount)
.damageItem(item, amount, "slot")

.damageItemTag("tag", amount)
.damageItemTag("tag", amount, nbt)
.damageItemTag("tag", amount, "slot")
.damageItemTag("tag", amount, nbt, "slot")

.repairItem(item, amount)
.repairItem(item, amount, "slot")

.repairItemTag("tag", amount)
.repairItemTag("tag", amount, nbt)
.repairItemTag("tag", amount, "slot")
.repairItemTag("tag", amount, nbt, "slot")
  • The item param must be created using Item.of() KubeJS method. Example : Item.of("minecraft:diamond", 42)
  • The slot param must be a string corresponding to a slot id defined in a custom machine json Item Component slot property.
  • The tag param must be a string starting with # defining a valid tag id. Example : "#forge:stone"
  • The amount param must be a positive integer.
  • The nbt param must be a map. Example: {nbt1: 1, nbt2: "something"}.
Fluid

Use one of these methods to add a Fluid Requirement to the recipe.

.requireFluid(fluid)
.requireFluid(fluid, "tank")

.requireFluidTag("tag", amount)
.requireFluidTag("tag", amount, nbt)
.requireFluidTag("tag", amount, "tank")
.requireFluidTag("tag", amount, nbt, "tank")

.produceFluid(fluid, amount)
.produceFluid(fluid, amount, "tank")

.requireFluidPerTick(fluid)
.requireFluidPerTick(fluid, "tank")

.requireFluidTagPerTick("tag", amount)
.requireFluidTagPerTick("tag", amount, nbt)
.requireFluidTagPerTick("tag", amount, "tank")
.requireFluidTagPerTick("tag", amount, nbt, "tank")

.produceFluidPerTick(fluid, amount)
.produceFluidPerTick(fluid, amount, "tank")
  • The fluid param must be created using Fluid.of() KubeJS method. Example : Fluid.of("minecraft:water", 1000)
  • The tank param must be a string corresponding to a tank id defined in a custom machine json Fluid Component tank property.
  • The tag param must be a string starting with # defining a valid tag id. Example : "#minecraft:water"
  • The amount param must be a positive integer.
  • The nbt param must be a map. Example: {nbt1: 1, nbt2: "something"}.
Energy

Use one of these methods to add an Energy Requirement to the recipe.

.requireEnergy(amount)

.requireEnergyPerTick(amount)

.produceEnergy(amount)

.produceEnergyPerTick(amount)
  • The amount param must be a positive integer.
Time

Use one of these methods to add a Time Requirement to the recipe.

.requireTime("time")

.requireTime(["time1", "time2", "etc..."])
  • The time param must be a string or an array of strings. Look at the time requirement wiki page to know what to put here.
Position

Use one of these methods to add a Position Requirement to the recipe.

.requirePosition("position")
.requirePosition(["position1", "position2", "etc..."])

.biomeWhitelist("biome")
.biomeWhitelist(["biome1", "biome2", "etc..."])

.biomeBlacklist("biome")
.biomeBlacklist(["biome1", "biome2", "etc..."])

.dimensionWhitelist("dimension")
.dimensionWhitelist(["dimension1", "dimension2", "etc..."])

.dimensionBlacklist("dimension")
.dimensionBlacklist(["dimension1", "dimension2", "etc..."])
  • The position param must be a string or an array of strings. Look at the position requirement wiki page to know what to put here.
  • The biome param must be a string defining a valid biome id. Example : minecraft:ocean
  • The dimension param must be a string defining a valid dimension id. Example : minecraft:overworld
Fuel

Use this method to add a Fuel Requirement to the recipe.

.requireFuel()
.requireFuel(amount)
  • The amount param must be a positive integer that define the amount of fuel burned each tick of the recipe processing.
    Default to 1 when not specified.
Command

Use one of these methods to add a Command Requirement to the recipe.

.runCommandOnStart("command")
.runCommandOnStart("command", permissionLevel)
.runCommandOnStart("command", log)
.runCommandOnStart("command", permissionLevel, log)

.runCommandEachTick("command")
.runCommandEachTick("command", permissionLevel)
.runCommandEachTick("command", log)
.runCommandEachTick("command", permissionLevel, log)

.runCommandOnEnd("command")
.runCommandOnEnd("command", permissionLevel)
.runCommandOnEnd("command", log)
.runCommandOnEnd("command", permissionLevel, log)
  • The command param must be a string starting by / which will be run as a command.
  • The permissionLevel param must be a positive integer. Default : 2
  • The log param must be a boolean, if true the command will be logged in admin chat as a system command. Default : false
Effect

Use one of these methods to add an Effect Requirement to the recipe.

.giveEffectOnEnd("effect", time, radius)
.giveEffectOnEnd("effect", time, radius, level)
.giveEffectOnEnd("effect", time, radius, filter)
.giveEffectOnEnd("effect", time, radius, level, filter)

.giveEffectEachTick("effect", time, radius)
.giveEffectEachTick("effect", time, radius, level)
.giveEffectEachTick("effect", time, radius, filter)
.giveEffectEachTick("effect", time, radius, level, filter)
  • The effect param must be a string defining a valid effect id. Example : minecraft:regeneration
  • The time and radius params must be a positive integer.
  • The level param must be a positive integer. Default : 1
  • The filter param must be an array of string defining a valid entity id. Example : ["minecraft:cow", "minecraft:pig"...] Default : []
Weather

Use one of these methods to add a Weather Requirement to the recipe.

.requireWeather("weather")

.requireWeatherOnMachine("weather")
  • The weather param must be a string defining the required weather. Valid values : clear, rain, snow, thunder
Redstone

Use one of these methods to add a Redstone Requirement to the recipe.

.requireRedstone(power)

.requireRedstone(power, "comparator")
  • The power param must be a positive integer.
  • The comparator param must be a string defining a valid Comparator Mode. Default : >=
Light

Use one of these methods to add a Light Requirement to the recipe.

.requireSkyLight(amount)
.requireSkyLight(amount, "comparator")

.requireBlockLight(amount)
.requireBlockLight(amount, "comparator")
  • The amount param must be a positive integer between 0 and 15.
  • The comparator param must be a string defining a valid Comparator Mode. Default : >=
Entity

Use one of these methods to add an Entity Requirement to the recipe.

.requireEntities(amount, radius, filter, whitelist)

.requireEntityHealth(amount, radius, filter, whitelist)

.consumeEntityHeathOnStart(amount, radius, filter, whitelist)

.consumeEntityHealthOnEnd(amount, radius, filter, whitelist)

.killEntitiesOnStart(amount, radius, filter, whitelist)

.killEntitiesOnEnd(amount, radius, filter, whitelist)
  • The amount and radius params must be a positive integer.
  • The filter param must be an array of string defining a valid entity id. Example : ["minecraft:cow", "minecraft:pig"...] Default : []
  • The whitelist param must be a boolean, if true the filter will be a whitelist, if false it will be a blacklist.
Block

Use one of these methods to add a Block Requirement to the recipe.

.requireBlock(filter, whitelist, startX, startY, startZ, endX, endY, endZ)
.requireBlock(filter, whitelist, startX, startY, startZ, endX, endY, endZ, amount)
.requireBlock(filter, whitelist, startX, startY, startZ, endX, endY, endZ, amount, comparator)

.placeBlockOnStart("block", startX, startY, startZ, endX, endY, endZ)
.placeBlockOnStart("block", startX, startY, startZ, endX, endY, endZ, amount)

.placeBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ)
.placeBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ, amount)

.breakAndPlaceBlockOnStart("block", startX, startY, startZ, endX, endY, endZ)
.breakAndPlaceBlockOnStart("block", startX, startY, startZ, endX, endY, endZ, amount)
.breakAndPlaceBlockOnStart("block", startX, startY, startZ, endX, endY, endZ, amount, filter)
.breakAndPlaceBlockOnStart("block", startX, startY, startZ, endX, endY, endZ, amount, filter, whitelist)

.breakAndPlaceBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ)
.breakAndPlaceBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ, amount)
.breakAndPlaceBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ, amount, filter)
.breakAndPlaceBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ, amount, whitelist)

.destroyAndPlaceBlockOnStart("block", startX, startY, startZ, endX, endY, endZ)
.destroyAndPlaceBlockOnStart("block", startX, startY, startZ, endX, endY, endZ, amount)
.destroyAndPlaceBlockOnStart("block", startX, startY, startZ, endX, endY, endZ, amount, filter)
.destroyAndPlaceBlockOnStart("block", startX, startY, startZ, endX, endY, endZ, amount, filter, whitelist)

.destroyAndPlaceBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ)
.destroyAndPlaceBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ, amount)
.destroyAndPlaceBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ, amount, filter)
.destroyAndPlaceBlockOnEnd("block", startX, startY, startZ, endX, endY, endZ, amount, filter, whitelist)

.destroyBlockOnStart(filter, whitelist, startX, startY, startZ, endX, endY, endZ)
.destroyBlockOnStart(filter, whitelist, startX, startY, startZ, endX, endY, endZ, amount)

.destroyBlockOnEnd(filter, whitelist, startX, startY, startZ, endX, endY, endZ)
.destroyBlockOnEnd(filter, whitelist, startX, startY, startZ, endX, endY, endZ, amount)

.breakBlockOnStart(filter, whitelist, startX, startY, startZ, endX, endY, endZ)
.breakBlockOnStart(filter, whitelist, startX, startY, startZ, endX, endY, endZ, amount)

.breakBlockOnEnd(filter, whitelist, startX, startY, startZ, endX, endY, endZ)
.breakBlockOnEnd(filter, whitelist, startX, startY, startZ, endX, endY, endZ, amount)
  • The block param must be a string defining a valid blockstate.
    Using the format namespace:block_id[property1=value1,property2=value2...]{tag1: value1, tag2: value2...} (The [] and {} are optional)
    This is the block that will be placed.
  • The filter param must be an array of string defining a valid blockstate.
    This is the blocks that can/can't be break by the machine depending of the whitelist property.
  • The whitelist param is a boolean, if true the filter list will be a whitelist, if false a blacklist. Default to false when not specified.
  • The startX, startY, startZ, endX, endY, endZ must be integer values defining the box where the machine will search for blocks.
    You can use the in-game Box Creator to select a box and put the values here.
  • The amount param must be a positive integer.
    This is the minimal amount of blocks that must be destroyed/placed. Default to 1 when not specified.
  • The comparator param must be a string defining a valid Comparator Mode. Default : ==
Structure

Use this method to add a Structure Requirement to the recipe.

.requireStructure(pattern, keys)
  • The pattern param must be an array of array of strings. See pattern.
    Example: [["aaa", "aaa", "aaa"], ["aaa", "ama", "aaa"], ["aaa", "aaa", "aaa"]] Define a 3x3x3 box around the machine m

  • The keys param must be a map of string -> string. See keys.
    The keys of the map must be single characters (except m which is reserved for the machine) and the values must be a block ID with the format: namespace:block_id[state1=value,state2=value] (states are optional).
    Example: {"a": "minecraft:stone", "b": "minecraft:diamond_block"}

Example

.requireStructure([[
    "aaa",
    "a a",
    "aaa",
    " m "
    ]], {"a": "minecraft:stone"})

A 3x1x3 hollow ring of stone behind the machine.

Loot Table

Use one of these methods to add a Loot Table Requirement to the recipe.

.lootTableOutput("loot_table")

.lootTableOutput("loot_table", luck)
  • The loot_table param must be a string path that point to a loot table. The loot table file must be loaded with a datapack or a loader mod.
    Example: custommachinery:my_test_loottable point to a file in data/custommachinery/loot_tables/my_test_loottable.json

  • The luck param must be a float. Default is 0.0 and it can be used in the loot table to alter the quantity of generated items.

Drop

Use one of these methods to add a Drop Requirement to the recipe.

//Check for a specific item.
.checkDrop(item, amount, radius)
//Check for any item.
.checkAnyDrop(amount, radius)
//Check for a list of items.
.checkDrops(filter, amount, radius)
.checkDrops(filter, amount, radius, whitelist)

.consumeDropOnStart(item, amount, radius)
.consumeAnyDropOnStart(amount, radius)
.consumeDropsOnStart(filter, amount, radius)
.consumeDropsOnStart(filter, amount, radius, whitelist)

.consumeDropOnEnd(item, amount, radius)
.consumeAnyDropOnEnd(amount, radius)
.consumeDropsOnEnd(filter, amount, radius)
.consumeDropsOnEnd(filter, amount, radius, whitelist)

.dropItemOnStart(item)
.dropItemOnEnd(item)
  • The item param must be an item created using Item.of(). Example : Item.of("minecraft:dirt")
  • The amount param must be a positive integer, it represents the amount of items checked/consumed.
  • The radius param must be a positive integer, it represents the maximum distance to the machine the items will be searched.
  • The filter param must be an array of items. Example : [Item.of("minecraft:diamond"), Item.of("minecraft:cobblestone"). It represents a whitelist of items to search.
  • The whitelist param must be a boolean, if set to false the filter will be a blacklist instead of a whitelist.
Function

Use one of these methods to add a function that must be processed by the machine to continue the recipe.

Note: This has nothing to do with MC functions (or commands), this requirement allow you to make your own code in JavaScript and pass it to be executed by the machine.

//Executed when the machine is idle and search a recipe to process.
//Returning success will allow the machine to process this recipe (if all other requirements allow it as well).
//Returning error will prevent the machine to process this recipe (the machine will keep searching for another valid recipe).
.requireFunctionToStart(ctx => {return Result.success()})

//Executed the first tick of the crafting process.
//Returning success will allow the machine to continue to process this recipe.
//Returning error will put the machine in error status and display the provided error message.
.requireFunctionOnStart(ctx => {return Result.success()})

//Executed each tick of the crafting process.
//Returning success will allow the machine to continue to process this recipe.
//Returning error will put the machine in error status and display the provided error message.
.requireFunctionEachTick(ctx => {return Result.success()})

//Executed the last tick of the crafting process.
//Returning success will allow the machine to continue to process this recipe.
//Returning error will put the machine in error status and display the provided error message.
.requireFunctionOnEnd(ctx => {return Result.success()})
  • The passed function MUST return a Result.
  • Valid results are : Result.success() and Result.error("Error message")
  • Context has various methods for interacting with the machine, see it's wiki page
  • The function can be delayed, put .delay(delay) directly after any .requireFunctionXXX() call to make the function be executed at the specified delay.

Example :

onEvent('recipes', event => {
	event.recipes.custommachinery.custom_machine("custommachinery:power_crusher", 200)
	.requireFunctionEachTick(ctx => {
		var remaining = ctx.machine.addItemToSlot("output1", Item.of("minecraft:diamond", 2), true);

		if(item.count == 0) {
                        ctx.machine.addItemToSlot("output1", Item.of("minecraft:diamond", 2), false);
			return Result.success();
                }
		return Result.error("Can't add 2 diamonds in output slot");
	})
})

Requirements special properties

Some requirements (almost all) have various properties that can change its behaviour.

To set these properties you must call one or several of the methods below immediatly after the desired requirement. The properties will only be applied on the latest added requirement when the method is called.

If the latest added requirement doesn't support the property an error will be logged and nothing will happen (the property will be ignored).

Chance

Use this method to add a chance property to the latest added requirement.

.chance(chance)
  • The chance param must be a double between 0.0 and 1.0 included.

Supported requirements :

  • Command
  • Drop
  • Durability
  • Energy
  • Energy Per Tick
  • Fluid
  • Fluid Per Tick
  • Item
Delay

Use this method to set a delay for the requirement action.

The requirement will only execute its action after the specified delay.

.delay(delay)
  • The delay param must be a double between 0.0 and 1.0 excluded. 0 represent the start of the recipe and 1 represent its end.

Supported requirements :

  • Block
  • Command
  • Drop
  • Function

Priority

Use the method below to set the priority of the recipe.

If this method is called several times only the latest will be used.

If this is called AFTER .jei() (no need to be immediatly after) this will act as the "jeiPriority" instead, defining the priority of the recipe to show in jei instead of the priority to be checked in the machine.

If no priority is set, the default value : 0 will be used.

.priority(priority)
  • The priority param must be an integer value.

Jei

If the method below is called, all requirements added after that will be added to the jei property requirement list.

.jei()

This action cannot be inverted, you must add all your recipe requirements before calling it.

Requirements added after this method will only be displayed in jei but executed by the machine. Learn more here.

Examples :

Example 1

A 100 tick recipe that use 5mB of water, 5mB of any fluid with tag lava and 20FE per tick to create a stone.

onEvent('recipes', event => {

  event.recipes.custommachinery.custom_machine("custommachinery:stone_generator", 100)
  .requireFluid(Fluid.of("minecraft:water", 5))
  .requireFluidTag("#minecraft:lava", 5)
  .requireEnergyPerTick(20)
  .produceItem(Item.of("minecraft:stone", 1))
})

example_recipe_1

Example 2

A 200 tick recipe that use 1 item with tag stone and 20FE per tick to create 1 cobblestone, 1 gravel with 50% chance and 1 sand with 10% chance.

onEvent('recipes', event => {

  event.recipes.custommachinery.custom_machine("custommachinery:power_crusher", 200)
  .requireItemTag("#forge:stone", 1)
  .requireEnergyPerTick(20)
  .produceItem(Item.of("minecraft:cobblestone", 1))
  .produceItem(Item.of("minecraft:gravel", 1)).chance(0.5)
  .produceItem(Item.of("minecraft:sand", 1)).chance(0.1)
})

example_recipe_2

Clone this wiki locally