# Recipes

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).

```javascript
onEvent('recipes', event => {

  event.recipes.custommachinery.custom_machine("namespace:machine_id", duration)
  
  //Add requirements here

})
```

### Requirements

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

<details>

<summary>Items</summary>

**Use one of these methods to add an** [**Item Requirement**](https://frinn.gitbook.io/custom-machinery-1.16/recipes/requirements/item) **to the recipe.**

```javascript
.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](https://frinn.gitbook.io/custom-machinery-1.16/creating-custom-machines/machine-components/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"}`.

</details>

<details>

<summary>Durability</summary>

**Use one of these methods to add a** [**Durability Requirement**](https://frinn.gitbook.io/custom-machinery-1.16/recipes/requirements/durability) **to the recipe.**

```javascript
.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](https://frinn.gitbook.io/custom-machinery-1.16/creating-custom-machines/machine-components/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"}`.

</details>

<details>

<summary>Fluid</summary>

**Use one of these methods to add a** [**Fluid Requirement**](https://frinn.gitbook.io/custom-machinery-1.16/recipes/requirements/fluid) **to the recipe.**

```javascript
.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](https://frinn.gitbook.io/custom-machinery-1.16/creating-custom-machines/machine-components/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"}`.

</details>

<details>

<summary>Energy</summary>

**Use one of these methods to add an** [**Energy Requirement**](https://frinn.gitbook.io/custom-machinery-1.16/recipes/requirements/energy) **to the recipe.**

```javascript
.requireEnergy(amount)

.requireEnergyPerTick(amount)

.produceEnergy(amount)

.produceEnergyPerTick(amount)
```

* The `amount` param must be a positive integer.

</details>

<details>

<summary>Time</summary>

**Use one of these methods to add a** [**Time Requirement**](https://frinn.gitbook.io/custom-machinery-1.16/recipes/requirements/time) **to the recipe.**

```javascript
.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.

</details>

<details>

<summary>Position</summary>

**Use one of these methods to add a** [**Position Requirement**](https://frinn.gitbook.io/custom-machinery-1.16/recipes/requirements/position) **to the recipe.**

```javascript
.requirePosition(String position)

.requirePosition(String[] positions)
```

* The `position` param must be a string or an array of strings. \
  Look at the [Position Requirement](https://frinn.gitbook.io/custom-machinery-1.16/recipes/requirements/position) wiki page to know what to put here.

</details>

<details>

<summary>Biome</summary>

**Use one of these methods to add a** [**Biome Requirement**](https://frinn.gitbook.io/custom-machinery-1.16/recipes/requirements/biome) **to the recipe.**

```javascript
.biomeWhitelist(Biome biome)
.biomeWhitelist(Biome[] biomes)

.biomeBlacklist(Biome biome)
.biomeBlacklist(Biomes[] biomes)
```

* The `biome` param must be a biome id. \
  Example : `minecraft:ocean`

</details>

<details>

<summary>Dimension</summary>

#### **Use one of these methods to add a** [Dimension **Requirement**](https://frinn.gitbook.io/custom-machinery-1.16/recipes/requirements/dimension) **to the recipe.**

```javascript
.dimensionWhitelist(String dimension)
.dimensionWhitelist(String[] dimensions)

.dimensionBlacklist(String dimension)
.dimensionBlacklist(String[] dimensions)
```

* The `dimension` param must be a string defining a valid dimension id. \
  Example : `minecraft:overworld`

</details>

<details>

<summary>Fuel</summary>

**Use this method to add a** [**Fuel Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Fuel-Requirement) **to the recipe.**

```javascript
.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.

</details>

<details>

<summary>Command</summary>

**Use one of these methods to add a** [**Command Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Command-Requirement) **to the recipe.**

```javascript
.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`

</details>

<details>

<summary>Effect</summary>

**Use one of these methods to add an** [**Effect Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Effect-Requirement) **to the recipe.**

```javascript
.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 : `[]`

</details>

<details>

<summary>Weather</summary>

**Use one of these methods to add a** [**Weather Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Weather-Requirement) **to the recipe.**

```javascript
.requireWeather("weather")

.requireWeatherOnMachine("weather")
```

* The `weather` param must be a string defining the required weather. \
  Valid values : `clear`, `rain`, `snow`, `thunder`

</details>

<details>

<summary>Redstone</summary>

**Use one of these methods to add a** [**Redstone Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Redstone-Requirement) **to the recipe.**

```javascript
.requireRedstone(power)

.requireRedstone(power, "comparator")
```

* The `power` param must be a positive integer between 0 and 15.
* The `comparator` param must be a string defining a valid [Comparator Mode](https://frinn.gitbook.io/custom-machinery-1.16/misc/comparator). \
  Default : `>=`

</details>

<details>

<summary>Light</summary>

**Use one of these methods to add a** [**Light Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Light-Requirement) **to the recipe.**

```javascript
.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](https://frinn.gitbook.io/custom-machinery-1.16/misc/comparator). \
  Default : `>=`

</details>

<details>

<summary>Entity</summary>

**Use one of these methods to add an** [**Entity Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Entity-Requirement) **to the recipe.**

```javascript
.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"...]`
* The `whitelist` param must be a boolean, if true the filter will be a whitelist, if false it will be a blacklist.

</details>

<details>

<summary>Block</summary>

**Use one of these methods to add a** [**Block Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Block-Requirement) **to the recipe.**

```javascript
.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](https://frinn.gitbook.io/custom-machinery-1.16/misc/comparator). \
  Default : `==`

</details>

<details>

<summary>Structure</summary>

**Use this method to add a** [**Structure Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Structure-Requirement) **to the recipe.**

```javascript
.requireStructure(pattern, keys)
```

* The `pattern` param must be an array of array of strings. \
  See `pattern` property of structure requirement.\
  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 property of structure requirement.\
  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**

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

A 3x1x3 hollow ring of stone behind the machine.

</details>

<details>

<summary>Loot Table</summary>

**Use one of these methods to add a** [**Loot Table Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Loot-Table-Requirement) **to the recipe.**

```javascript
.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.

</details>

<details>

<summary>Drop</summary>

**Use one of these methods to add a** [**Drop Requirement**](https://github.com/Frinn38/Custom-Machinery/wiki/Drop-Requirement) **to the recipe.**

```javascript
//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.

</details>

<details>

<summary>Function</summary>

**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.

```javascript
//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](https://github.com/Frinn38/Custom-Machinery/wiki/JS-Context)
* The function can be delayed, put `.delay(delay)` directly after any `.requireFunctionXXX()` call to make the function be executed at the specified delay.

Example :

```javascript
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");
	})
})
```

</details>

### Requirements special properties

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

To set these properties you must call one or several of the methods below **immediately 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).

<details>

<summary>Chance</summary>

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

```javascript
.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

</details>

<details>

<summary>Delay</summary>

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

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

```javascript
.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

</details>

### 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.

```javascript
.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.

```javascript
.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](https://github.com/Frinn38/Custom-Machinery/wiki/Recipes#jei-optional).

### Examples :

<details>

<summary>Example 1</summary>

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

```javascript
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](https://github.com/Frinn38/Custom-Machinery/raw/1.16.5/wiki/example_recipe_1.png)

</details>

<details>

<summary>Example 2</summary>

**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.**

```javascript
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](https://github.com/Frinn38/Custom-Machinery/raw/1.16.5/wiki/example_recipe_2.png)

</details>
