⚒️ 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.

typescript
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

FieldTypeDescription
type'item' | 'currency'What to consume
idstringItem ID or currency ID
amountnumberQuantity to consume

Output Fields

FieldTypeDescription
type'item' | 'currency'What to produce
idstringItem ID or currency ID
amountnumberQuantity to produce
chancenumber (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.

bash
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"
  }'
json
{
  "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 CodeMeaning
RECIPE_NOT_FOUNDThe recipeId doesn't exist for this game
RECIPE_DISABLEDThe recipe exists but is disabled
RECIPE_ON_COOLDOWNPlayer must wait before crafting again
INSUFFICIENT_ITEMSPlayer doesn't have enough of a required item
INSUFFICIENT_BALANCEPlayer doesn't have enough of a required currency