⚒️ Crafting
Define recipes that consume ingredients (items and currencies) and produce outputs with optional chance-based rolls.
Defining Recipes
Recipes are registered via the Convex defineRecipe mutation. Each recipe has ingredients (consumed) and outputs (granted). Recipes are idempotent by recipeId.
await ctx.runMutation(api.economyCrafting.defineRecipe, {
gameId,
recipeId: "iron_sword_recipe",
name: "Iron Sword",
description: "Forge an iron sword from ore and wood",
ingredients: [
{ type: "item", id: "iron_ore", amount: 3 },
{ type: "item", id: "wood", amount: 2 },
{ type: "currency", id: "gold", amount: 10 },
],
outputs: [
{ type: "item", id: "iron-sword", amount: 1, chance: 1.0 },
{ type: "item", id: "legendary-sword", amount: 1, chance: 0.05 },
],
cooldownSeconds: 60,
});Ingredient Fields
| Field | Type | Description |
|---|---|---|
type | 'item' | 'currency' | What to consume |
id | string | Item ID or currency ID |
amount | number | Quantity to consume |
Output Fields
| Field | Type | Description |
|---|---|---|
type | 'item' | 'currency' | What to produce |
id | string | Item ID or currency ID |
amount | number | Quantity to produce |
chance | number (0-1) | Probability of this output (default 1.0 = guaranteed) |
Executing a Craft
Use the POST /craft endpoint to execute a recipe. The system validates ingredients, consumes them, rolls outputs, and grants results — all atomically.
curl -X POST https://gameplaygen.com/api/economy/craft \
-H "Authorization: Bearer gg_live_sk_..." \
-H "Content-Type: application/json" \
-d '{
"gameId": "j97abc...",
"playerId": "j97def...",
"recipeId": "iron_sword_recipe"
}'{
"success": true,
"data": {
"granted": [
{ "type": "item", "id": "iron-sword", "amount": 1 }
]
}
}Note: the legendary sword (5% chance) didn't drop this time. The granted array only includes outputs that passed their chance roll.
Cooldowns
Set cooldownSeconds on a recipe to prevent spam-crafting. The cooldown is per-player per-recipe. If a player tries to craft while on cooldown, the request fails with RECIPE_ON_COOLDOWN and tells them how many seconds remain.
Deterministic RNG
Chance-based outputs use a deterministic RNG (Mulberry32) seeded from the player ID, recipe ID, and timestamp. This means crafting results are reproducible given the same inputs at the same time, which is important for server-side verification and debugging.
Error Handling
| Error Code | Meaning |
|---|---|
RECIPE_NOT_FOUND | The recipeId doesn't exist for this game |
RECIPE_DISABLED | The recipe exists but is disabled |
RECIPE_ON_COOLDOWN | Player must wait before crafting again |
INSUFFICIENT_ITEMS | Player doesn't have enough of a required item |
INSUFFICIENT_BALANCE | Player doesn't have enough of a required currency |