diff --git a/.vitepress/sidebars/developers.ts b/.vitepress/sidebars/developers.ts index fc6868e..784eae8 100644 --- a/.vitepress/sidebars/developers.ts +++ b/.vitepress/sidebars/developers.ts @@ -38,11 +38,18 @@ export default { }, ], }, - // TODO - Finish - // { - // text: "API Documentation", - // link: "/developers/api-docs", - // }, + { + text: "API Documentation", + // TODO: Write the API Docs page + // link: "/developers/api-docs", + collapsed: true, + items: [ + { + text: "Custom Recipes", + link: "/developers/api-docs/recipes", + }, + ] + }, { text: "Useful Tags", collapsed: true, diff --git a/developers/api-docs/recipes.md b/developers/api-docs/recipes.md new file mode 100644 index 0000000..671ccd6 --- /dev/null +++ b/developers/api-docs/recipes.md @@ -0,0 +1,327 @@ +--- +title: Custom Recipes +description: How to write recipes for Create using datapacks and KubeJS. + +next: false +--- + +# Custom Recipes +***Creating Custom, Creative Recipes with Create*** + +Create, like Vanilla and plenty of other mods, uses the Datapack JSON format introduced in 1.13. +This lets you further customize Create for whatever modpack you're playing with it on. +This article will describe how to [set up your datapack](#getting-started), +[add recipes with JSON](#adding-a-recipe), +and [add recipes with other mods](#adding-recipes-with-other-mods). + +## What even *is* a Datapack? +Datapacks are a Vanilla-provided method to modify, add, and remove certain content from the game. +This includes World Generation, Advancements, Command Functions, Block/Mob/Loot drops, +and much more—more "data-driven" aspects of the game are added every Minecraft update. + +We will be modifying Recipes with datapacks here. + +If you want to learn more about Data Packs, we recommend reading up on the [Minecraft Wiki](https://minecraft.wiki/w/Data_pack). + +## What do I need? +You will need basic knowledge on how to write JSON and how to create a Datapack in order to create your recipe. +You can study the [Creating a Datapack](https://minecraft.wiki/w/Tutorial:Creating_a_data_pack) page on the Minecraft Wiki and get the following tools: + +### Applications +- Text Editor: Most operating systems nowdays usually provide this (Notepad on Windows, TextEdit on Mac, and it varies on Linux), but we recommend getting a fancier tool suited for code like this, like [VSCode](https://code.visualstudio.com/) and [Notepad++](https://notepad-plus-plus.org/). These will highlight your code and point out any *syntax* errors you have made in your JSON. + +### Mods (Optional) +- [JEI](https://modrinth.com/mod/jei) **(Recommended)**: lets you quickly preview your recipes in-game without having to attempt making them. +- [Paxi](https://modrinth.com/mod/paxi) (Fabric+NeoForge): If you're a modpack creator or wish to test in multiple worlds at once, Paxi can let you load datapacks globally. +- [KubeJS](https://modrinth.com/mod/kubejs) (Neoforge): KubeJS lets you write JavaScript to add recipes with a bit more automation and ease than manually writing them. It also lets you add items for your recipes and functions as another global datapack loader. + - [KubeJS Create](https://modrinth.com/mod/kubejs-create/) is an addon for Create and KubeJS that allows you to make recipes even quicker. Base KubeJS can still do this with custom recipes, however. + +## Getting Started +Once again, you should check out the [Creating a Datapack](https://minecraft.wiki/w/Tutorial:Creating_a_data_pack) page on the Minecraft Wiki. This provides good information on how to set up your datapack. However, **the wiki always reflects the latest version of Minecraft**, and you may encounter differences in the format between Minecraft versions. + +:::info +This article details creation of recipes for NeoForge 1.21.1. +::: + +![A screenshot of Finder, showing the basic structure of a datapack including the recipe and tags folder](/media/developers/api-docs/recipes/pack_blank.png?url) +This will be the basic structure of your datapack. Remember that the `recipe` folder is named `recipes` **before 1.21**. + +`my_datapack_id` is an Alphanumeric string, **including** `_`. Change it to fit the **datapack** you're making, not the **mod** your recipes are targeting. + +You also need a `pack.mcmeta` for your datapack to load. +```json [pack.mcmeta] +{ + "pack": { + "pack_format": 48, + "description": "An example Create datapack" + } +} +``` + +When you have created your datapack, run `/reload` in chat. +This command requires Operator—it's a quick way to reload your recipes and tags without rejoining/restarting your server. + +To confirm that your datapack has loaded, run `/datapack list`. If it doesn't show up on the list, check your setup; if it shows up red, run `/datapack enable "file/my_datapack_id"`. + +[An example datapack setup with these recipes can be found here.](https://github.com/vercte/example_create_datapack) + +## Adding a Recipe +This is where knowing JSON really comes in. For a guide on writing a Vanilla recipe, see the Minecraft Wiki for the [Vanilla Recipe Format](https://minecraft.wiki/w/Recipe). + +To start, add a recipe to the Recipes folder, optionally inside a folder for organization: +![Almost the same Finder screenshot, now including recipe/deploying/enchanted_golden_apple.json](/media/developers/api-docs/recipes/pack_with_recipe.png?url) + +This will be a **deploying** recipe. +```json [enchanted_golden_apple.json] +{ + "type": "create:deploying", + "ingredients": [ + { + "item": "minecraft:golden_apple" + }, + { + "item": "create:experience_block" + } + ], + "results": [ + { + "id": "minecraft:enchanted_golden_apple" + } + ] +} +``` +Upon `/reload`, JEI will show this recipe: +![A deploying recipe, showing a Block of Experience being deployed on a Golden Apple to make an Enchanted Golden Apple.](/media/developers/api-docs/recipes/deploying_enchanted_golden_apple.png?url) + +Congratulations! That's your first recipe! +Recipe types that use this format, with one input: +- Milling (millstone, crushing wheels) `create:milling` +- Crushing (crushing wheels) `create:crushing` +- Cutting (mechanical saw) `create:cutting` +- Deploying (deployer) `create:deploying` +- Haunting (soul fire, encased fan) `create:haunting` +- Splashing (water, encased fan) `create:splashing` +- Sandpaper Polishing (sandpaper) `create:sandpaper_polishing` +- Item Application (by hand; e.g. andesite casing) `create:item_application` + +## Fluid Ingredients +Recipes that use a basin (compacting, mixing) and recipes that use a spout or item drain can have fluids in the recipe. +Recipes that take in **one** item and **one** fluid always include both in `ingredients`, in that order. + +Another example recipe, for the Spout this time, in `recipe/filling/exposed_copper.json`: +```json [exposed_copper.json] +{ + "type": "create:filling", + "ingredients": [ + { + "item": "minecraft:copper_block" + }, + { + "type": "fluid_stack", + "amount": 1000, + "fluid": "minecraft:water" + } + ], + "results": [ + { + "id": "minecraft:exposed_copper" + } + ] +} +``` + +And the resulting recipe: +![A spouting recipe, showing a bucket of water being spouted on a Block of Copper to make Exposed Copper.](/media/developers/api-docs/recipes/filling_exposed_copper.png?url) + +The key part here is the fluid ingredient: +```json +{ + "type": "fluid_stack", + "amount": 1000, + "fluid": "minecraft:water" +} +``` +`amount` is in Millibuckets, which means 1,000 millibuckets is a full bucket. +:::warning +On Fabric, fluid measurement uses Droplets instead, with 81,000 droplets to a bucket. +::: + +## Extra Arguments +`heat_requirement`: Only Basin Recipes have this property. This can be `none`, `heated`, or `superheated`, and reflects blaze heating below it. This should be omitted on recipes that don't support it, and it can be omitted if `none`. + +`processing_time`: Only applies to `create:milling`, `create:crushing`, and `create:cutting`. How long this duration really is in-game varies between recipe types and how fast the machines are running. + +`chance` (inside a result): The chance, out of 100, that this result will be yielded. + +## Sequenced Assembly +Sequenced Assembly is a much more complicated Create Recipe, involving a parent recipe and multiple processing recipes nested inside it. + +They take in one ingredient (`ingredient`), turn it into a transitional item (`transitional_item`) during processing, and turn it into the results at the end. + +A basic rundown of the arguments: +- `loops`: Required. How many times the sequence has to be done. +- `sequence`: Required. A list of compatible processing recipes to include in the sequence. + - These recipes have to return the `transitional_item` as a result. + - Valid recipes: `create:pressing`, `create:cutting`, `create:deploying`, `create:filling` + - If you want to make your own custom recipe types compatible with this, implement `IAssemblyRecipe`. +- `transitional_item`: The item to use while the recipe is in-progress (like the Incomplete Precision Mechanism). + - This can be any item, but if you want the custom progress bar, your item has to be a `SequencedAssemblyItem`. + +Here's how Create uses it for the Sturdy Sheet: +```json [sturdy_sheet.json] +{ + "type": "create:sequenced_assembly", + "ingredient": { + "tag": "c:dusts/obsidian" + }, + "loops": 1, + "results": [ + { + "id": "create:sturdy_sheet" + } + ], + "sequence": [ + { + "type": "create:filling", + "ingredients": [ + { + "item": "create:unprocessed_obsidian_sheet" + }, + { + "type": "fluid_stack", + "amount": 500, + "fluid": "minecraft:lava" + } + ], + "results": [ + { + "id": "create:unprocessed_obsidian_sheet" + } + ] + }, + { + "type": "create:pressing", + "ingredients": [ + { + "item": "create:unprocessed_obsidian_sheet" + } + ], + "results": [ + { + "id": "create:unprocessed_obsidian_sheet" + } + ] + }, + { + "type": "create:pressing", + "ingredients": [ + { + "item": "create:unprocessed_obsidian_sheet" + } + ], + "results": [ + { + "id": "create:unprocessed_obsidian_sheet" + } + ] + } + ], + "transitional_item": { + "id": "create:unprocessed_obsidian_sheet" + } +} +``` +![A sequenced assembly recipe for the Sturdy sheet, showing Obsidian dust having lava being spouted on it and then pressed two times.](/media/developers/api-docs/recipes/sequenced_sturdy_sheet.png?url) + +Writing Sequenced Assembly recipes can get quite tedious and prone to mistake, so it's advised to [set up Data Generation] for them if you're developing an addon. + +## Modifying/Removing recipes with Datapacks +If you want to remove recipes with a datapack, you can use the `filter` section of your `pack.mcmeta`. +This section allows you to specify the IDs of recipes you would like to remove. + +```json +{ + "pack": { + "pack_format": 48, + "description": "An example Create datapack" + }, + "filter": { + "block": [ + { + "namespace": "create", + "path": "recipe/mixing/brass_ingot" + }, + { + "namespace": "create", + "path": "recipe/mixing/andesite_alloy.*" + } + ] + } +} +``` +This example removes the recipes for the Brass Ingot and Andesite Alloy (from both Iron and Zinc nuggets) via mixing. + +`filter.block` is an array which accepts an object with two optional keys: +- `namespace`: The namespace (`create`) in which the resource you want to remove is included. If unspecified, it applies to every namespace. +- `path`: The path (`recipe/mixing/brass_ingot`) where the resource you want to remove is located. If unspecified, it applies to every resource. + +*These can be [regular expressions](https://en.wikipedia.org/wiki/regular_expression), if you know how to use them.* + +If you wish to modify a recipe, remove it using this method and re-create the recipe in your datapack with +whatever modification you wish to apply. + +## Managing Recipes with Other Mods +You can avoid datapack setup using mods like KubeJS and CraftTweaker to modify parts of the game. + +### KubeJS +:::info +This section will assume you know JavaScript. +::: +[KubeJS](https://kubejs.com) is a mod that lets you write JavaScript to customize the behavior of your modpack. +Upon installing it and launching a world with it installed for the first time, a `kubejs` folder will be created +with a `server_scripts` directory inside it. This is where our recipe script will go. + +We can listen to the `ServerEvents.recipes` event, which lets us add recipes using JavaScript. +This also lets us script the creation of recipes, instead of manually fully creating them. +Without an addon like [KubeJS Create](https://modrinth.com/mod/kubejs-create/), this uses the +[JSON format](#adding-a-recipe) inside `event.custom`. + +Inside your script, placed inside the `.minecraft/kubejs/server_scripts` directory: +```js +ServerEvents.recipes(event => { + event.custom({ + type: "create:deploying", + ingredients: [ + { + item: "minecraft:paper" + }, + { + item: "minecraft:light_blue_dye" + } + ], + results: [ + { + id: "create:empty_schematic" + } + ] + }); +}); +``` +Using the Deploying JSON format, this adds a recipe for the Empty Schematic: +![A deploying recipe, showing Light Blue Dye being deployed on Paper to make an Empty Schematic.](/media/developers/api-docs/recipes/deploying_empty_schematic.png?url) + +To remove recipes, we can use `event.remove`, which you provide a filter to: +```js +ServerEvents.recipes(event => { + event.remove({ output: "create:andesite_alloy" }); // Removes all recipes with the output of Andesite Alloy + event.remove({ input: "minecraft:iron_nugget" }); // Removes all recipes that take in an Iron Nugget + event.remove({ type: "create:deploying", input: "#minecraft:planks" }) // Remove all Deploying recipes that take in wooden planks + event.remove({ not: { type: "create:mixing", input: "create:zinc_ingot" }}) // Remove all Mixing recipes that DO NOT take in Zinc Ingot +}); +``` +You can also pass in an array of objects to `event.remove` for multiple operations at once. +The object passed in checks for any property of a recipe that matches it, barring the `not` object. + +:::info +The [Official KubeJS Tutorial for Editing Recipes](https://kubejs.com/wiki/tutorials/recipes) is a great place to learn more about this. +::: \ No newline at end of file diff --git a/public/media/developers/api-docs/recipes/deploying_empty_schematic.png b/public/media/developers/api-docs/recipes/deploying_empty_schematic.png new file mode 100644 index 0000000..c1e80ff Binary files /dev/null and b/public/media/developers/api-docs/recipes/deploying_empty_schematic.png differ diff --git a/public/media/developers/api-docs/recipes/deploying_enchanted_golden_apple.png b/public/media/developers/api-docs/recipes/deploying_enchanted_golden_apple.png new file mode 100644 index 0000000..40c7bb7 Binary files /dev/null and b/public/media/developers/api-docs/recipes/deploying_enchanted_golden_apple.png differ diff --git a/public/media/developers/api-docs/recipes/filling_exposed_copper.png b/public/media/developers/api-docs/recipes/filling_exposed_copper.png new file mode 100644 index 0000000..efed024 Binary files /dev/null and b/public/media/developers/api-docs/recipes/filling_exposed_copper.png differ diff --git a/public/media/developers/api-docs/recipes/pack_blank.png b/public/media/developers/api-docs/recipes/pack_blank.png new file mode 100644 index 0000000..b1e65cd Binary files /dev/null and b/public/media/developers/api-docs/recipes/pack_blank.png differ diff --git a/public/media/developers/api-docs/recipes/pack_with_recipe.png b/public/media/developers/api-docs/recipes/pack_with_recipe.png new file mode 100644 index 0000000..3a1ba7f Binary files /dev/null and b/public/media/developers/api-docs/recipes/pack_with_recipe.png differ diff --git a/public/media/developers/api-docs/recipes/sequenced_sturdy_sheet.png b/public/media/developers/api-docs/recipes/sequenced_sturdy_sheet.png new file mode 100644 index 0000000..dc1fef6 Binary files /dev/null and b/public/media/developers/api-docs/recipes/sequenced_sturdy_sheet.png differ