Astral Realms Documentation Help

AstralRecipes Overview

AstralRecipes registers custom crafting, cooking, and stonecutting recipes from plain YAML files. It is a standalone Paper plugin split out of AstralEssentials' older RecipeService — the same shaped/shapeless/stonecutting authoring model, plus new furnace/campfire/smoking cooking recipe types that AstralEssentials never had. It depends only on AstralCore (depend: [AstralCore] in plugin.yml, load: STARTUP, api-version: 26.2) and has no commands, placeholders, or events of its own.

Loading lifecycle

AstralRecipes#onEnable registers the six blueprint types (see Recipe types) with BLUEPRINT_REGISTRY, a NamedRegistry<Class<? extends RecipeBlueprint>>, and the RecipeBlueprintTypeSerializer that resolves a file's type key against it. It then schedules loadConfiguration() 10 ticks later (Bukkit.getScheduler().runTaskLater(this, this::loadConfiguration, 10L)) rather than loading recipes synchronously during onEnable.

loadConfiguration() calls RecipeService#unload() then RecipeService#load():

  1. Unload — every NamespacedKey this service currently tracks is removed with Server#removeRecipe(NamespacedKey), and the in-memory blueprint map is cleared. A no-op on first startup (the map starts empty).

  2. Readplugins/AstralRecipes/recipes/ is walked recursively; every regular file ending in .yml is parsed into a RecipeBlueprint via plugin.configurationManager().load(file, RecipeBlueprint.class). A file that fails to parse is logged (Failed to load recipe from <file>: <error>) and skipped — the rest continue loading.

  3. Register — each parsed blueprint is keyed by new NamespacedKey(plugin, <filename without .yml>) (namespace astralrecipes, so the registered key is astralrecipes:<filename>) and added with Server#addRecipe(Recipe). The filename is the recipe id — two files with the same base name (including across sub-folders, since the walk is recursive) compute the same key; the second one logs Duplicate recipe key <key> found in <file>. Skipping. and is dropped.

  4. RecipeBlueprint#build(NamespacedKey) on each blueprint class builds the concrete Bukkit Recipe.

There is no first-run seeding — unlike the old AstralEssentials service, AstralRecipes does not ship or copy any example .yml files into recipes/ on first startup. The folder is created empty and recipes are entirely author-provided.

Reload

AstralRecipes has no /recipes reload command of its own. Reloading goes through AstralCore's generic /core reload <plugin> command (core.commands permission), which calls target.loadConfiguration() on any AstralPaperPlugin/core reload AstralRecipes re-runs the unload/read/register sequence above.

Recipe types

type value

Blueprint class

Produces

shaped

ShapedRecipeBlueprint

ShapedRecipe

shapeless

ShapelessRecipeBlueprint

ShapelessRecipe

stonecutter

StoneCutterRecipeBlueprint

StonecuttingRecipe

furnace

FurnaceRecipeBlueprint

FurnaceRecipe

campfire

CampfireRecipeBlueprint

CampfireRecipe

smoking

BlastingRecipeBlueprint

BlastingRecipe

The type key is matched case-sensitively against this table (NamedRegistry#findByName is a plain Map lookup — unlike the old AstralEssentials discriminator, which matched case-insensitively). A type value that isn't one of the six above, or a missing type key, throws Missing or unknown recipe blueprint type: <value>; RecipeService catches it per-file, logs it, and skips just that file.

See Recipe blueprints for the field reference and YAML shape of every type.

Developer access

RecipeService is reachable off the plugin instance via the Lombok fluent accessor plugin.recipes() (this package's lombok.config sets lombok.accessors.fluent = true, so there is no getRecipes()). It is not registered with AstralPaperAPI's service registry, so other plugins must resolve the AstralRecipes plugin instance directly ((AstralRecipes) Bukkit.getPluginManager().getPlugin("AstralRecipes")) to reach it.

The service's only public surface is load() and unload() — there is no lookup method (no findByKey or recipes() snapshot accessor like the old AstralEssentials RecipeService had), so a consumer can trigger a reload but cannot query which blueprints are currently loaded.

Where to go next

Last modified: 25 July 2026