Skip to main content

Artisan Skills API Reference

Complete API reference for Hyperscape’s artisan skills systems.

Table of Contents

CraftingSystem

Tick-based crafting system for leather armor, dragonhide, jewelry, and gems. Location: packages/shared/src/systems/shared/interaction/CraftingSystem.ts

Public Methods

isPlayerCrafting(playerId: string): boolean

Check if a player is currently crafting. Parameters:
  • playerId: Player entity ID
Returns: true if player has an active crafting session Example:

Events

Subscribes To

  • CRAFTING_INTERACT: Trigger crafting interaction
  • PROCESSING_CRAFTING_REQUEST: Start crafting with quantity
  • SKILLS_UPDATED: Cache player skill levels
  • MOVEMENT_CLICK_TO_MOVE: Cancel crafting on movement
  • COMBAT_STARTED: Cancel crafting on combat
  • PLAYER_UNREGISTERED: Cleanup on disconnect

Emits

  • CRAFTING_INTERFACE_OPEN: Send available recipes to client
  • CRAFTING_START: Crafting session started
  • CRAFTING_COMPLETE: Crafting session completed
  • INVENTORY_ITEM_REMOVED: Consume materials
  • INVENTORY_ITEM_ADDED: Add crafted item
  • SKILLS_XP_GAINED: Grant crafting XP
  • ANIMATION_PLAY: Play crafting animation
  • UI_MESSAGE: User feedback messages

Internal Types

Mechanics

Thread Consumption:
  • Thread has 5 uses per item
  • Uses tracked in consumableUses Map
  • New thread consumed when uses depleted
  • Crafting stops if no thread available
Tick-Based Processing:
  • Processes once per game tick (600ms)
  • Uses completionTick for timing
  • Avoids duplicate processing with lastProcessedTick guard
Performance:
  • Single inventory scan per tick
  • Reusable arrays for completed sessions
  • Pre-allocated inventory state buffer

FletchingSystem

Tick-based fletching system for bows and arrows with multi-output support. Location: packages/shared/src/systems/shared/interaction/FletchingSystem.ts

Public Methods

isPlayerFletching(playerId: string): boolean

Check if a player is currently fletching. Parameters:
  • playerId: Player entity ID
Returns: true if player has an active fletching session Example:

Events

Subscribes To

  • FLETCHING_INTERACT: Trigger fletching interaction
  • PROCESSING_FLETCHING_REQUEST: Start fletching with quantity
  • SKILLS_UPDATED: Cache player skill levels
  • MOVEMENT_CLICK_TO_MOVE: Cancel fletching on movement
  • COMBAT_STARTED: Cancel fletching on combat
  • PLAYER_UNREGISTERED: Cleanup on disconnect

Emits

  • FLETCHING_INTERFACE_OPEN: Send available recipes to client
  • FLETCHING_START: Fletching session started
  • FLETCHING_COMPLETE: Fletching session completed
  • INVENTORY_ITEM_REMOVED: Consume materials
  • INVENTORY_ITEM_ADDED: Add fletched items
  • SKILLS_XP_GAINED: Grant fletching XP
  • ANIMATION_PLAY: Play fletching animation
  • UI_MESSAGE: User feedback messages

Internal Types

Mechanics

Multi-Output Recipes:
  • outputQuantity field in recipe (default: 1)
  • Arrow shafts: 15 per log
  • Headless arrows: 15 per action
  • Arrows: 15 per action
Item-on-Item Interactions:
  • Bowstring + unstrung bow → strung bow
  • Arrowtips + headless arrows → arrows
  • Arrow shafts + feathers → headless arrows
Recipe Filtering:
  • getFletchingRecipesForInput(itemId): Single input (knife + logs)
  • getFletchingRecipesForInputPair(itemA, itemB): Both inputs (item-on-item)

RunecraftingSystem

Instant essence-to-rune conversion system with multi-rune multipliers. Location: packages/shared/src/systems/shared/interaction/RunecraftingSystem.ts

Public Methods

None (instant conversion, no active sessions)

Events

Subscribes To

  • RUNECRAFTING_INTERACT: Trigger runecrafting interaction
  • SKILLS_UPDATED: Cache player skill levels
  • PLAYER_UNREGISTERED: Cleanup on disconnect

Emits

  • RUNECRAFTING_COMPLETE: Runecrafting completed
  • INVENTORY_ITEM_REMOVED: Consume essence
  • INVENTORY_ITEM_ADDED: Add runes
  • SKILLS_XP_GAINED: Grant runecrafting XP
  • UI_MESSAGE: User feedback messages

Mechanics

Instant Conversion:
  • No tick delay (unlike other skills)
  • All essence converted in one action
  • XP granted per essence consumed
Multi-Rune Multipliers:
  • Calculated from multiRuneLevels array
  • Each threshold grants +1 rune per essence
  • Example: Air runes at level 22 = 3 runes per essence
Essence Validation:
  • Basic runes: rune_essence OR pure_essence
  • Advanced runes: pure_essence only
  • Invalid essence types ignored

TanningSystem

Instant hide-to-leather conversion system at tanner NPCs. Location: packages/shared/src/systems/shared/interaction/TanningSystem.ts

Public Methods

None (instant conversion, no active sessions)

Events

Subscribes To

  • TANNING_INTERACT: Trigger tanning interaction
  • TANNING_REQUEST: Request tanning with quantity
  • PLAYER_UNREGISTERED: Cleanup on disconnect

Emits

  • TANNING_INTERFACE_OPEN: Send available recipes to client
  • TANNING_COMPLETE: Tanning completed
  • INVENTORY_ITEM_REMOVED: Consume hides
  • INVENTORY_REMOVE_COINS: Deduct tanning cost
  • INVENTORY_ITEM_ADDED: Add leather
  • UI_MESSAGE: User feedback messages

Mechanics

Instant Conversion:
  • No tick delay
  • Coins deducted first, then hides removed, then leather added
  • No XP granted (tanning is a service, not a skill)
Cost Calculation:
  • Total cost = quantity × cost per hide
  • If insufficient coins, tans only what player can afford
  • Minimum 1 hide if player has any coins

ProcessingDataProvider

Central data provider for all artisan skill recipes. Location: packages/shared/src/data/ProcessingDataProvider.ts

Singleton Access

Crafting Methods

getCraftingRecipe(outputItemId: string): CraftingRecipeData | null

Get crafting recipe by output item ID. Parameters:
  • outputItemId: Item ID of crafted item (e.g., “leather_gloves”)
Returns: Recipe data or null if not found Example:

getCraftingRecipesByStation(station: string): CraftingRecipeData[]

Get all crafting recipes for a specific station. Parameters:
  • station: Station type (“none” or “furnace”)
Returns: Array of recipes Example:

getCraftingRecipesByCategory(category: string): CraftingRecipeData[]

Get all crafting recipes in a category. Parameters:
  • category: Category name (leather, dragonhide, jewelry, gem_cutting)
Returns: Array of recipes

isCraftableItem(itemId: string): boolean

Check if an item can be crafted. Parameters:
  • itemId: Item ID to check
Returns: true if item has a crafting recipe

getCraftableItemIds(): Set<string>

Get all craftable item IDs. Returns: Set of item IDs

getCraftingInputsForTool(toolId: string): Set<string>

Get valid input items for a crafting tool. Parameters:
  • toolId: Tool item ID (e.g., “needle”, “chisel”)
Returns: Set of input item IDs Example:

isCraftingInput(itemId: string): boolean

Check if an item is used as input in any crafting recipe. Parameters:
  • itemId: Item ID to check
Returns: true if item is a crafting input

getCraftingToolForInput(inputItemId: string): string | null

Get the tool required for a crafting input item. Parameters:
  • inputItemId: Input item ID
Returns: Tool item ID or null

Fletching Methods

getFletchingRecipe(recipeId: string): FletchingRecipeData | null

Get fletching recipe by unique recipe ID. Parameters:
  • recipeId: Unique recipe ID (format: “output:primaryInput”)
Returns: Recipe data or null if not found Example:

getFletchingRecipesForInput(inputItemId: string): FletchingRecipeData[]

Get all fletching recipes using a specific input item. Parameters:
  • inputItemId: Input item ID (e.g., “logs”)
Returns: Array of recipes Example:

getFletchingRecipesForInputPair(itemA: string, itemB: string): FletchingRecipeData[]

Get fletching recipes matching both input items (item-on-item). Parameters:
  • itemA: First item ID
  • itemB: Second item ID
Returns: Array of recipes using both items Example:

getFletchingRecipesByCategory(category: string): FletchingRecipeData[]

Get all fletching recipes in a category. Parameters:
  • category: Category name (arrow_shafts, headless_arrows, arrows, shortbows, longbows, stringing)
Returns: Array of recipes

isFletchableItem(itemId: string): boolean

Check if an item can be fletched. Parameters:
  • itemId: Item ID to check
Returns: true if item has a fletching recipe

getFletchableItemIds(): Set<string>

Get all fletchable item IDs. Returns: Set of item IDs

getFletchingInputsForTool(toolId: string): Set<string>

Get valid input items for a fletching tool. Parameters:
  • toolId: Tool item ID (e.g., “knife”)
Returns: Set of input item IDs

isFletchingInput(itemId: string): boolean

Check if an item is used as input in any fletching recipe. Parameters:
  • itemId: Item ID to check
Returns: true if item is a fletching input

getFletchingToolForInput(inputItemId: string): string | null

Get the tool required for a fletching input item. Parameters:
  • inputItemId: Input item ID
Returns: Tool item ID or null (null for no-tool recipes like stringing)

Runecrafting Methods

getRunecraftingRecipe(runeType: string): RunecraftingRecipeData | null

Get runecrafting recipe by rune type. Parameters:
  • runeType: Rune type identifier (e.g., “air”, “mind”, “water”)
Returns: Recipe data or null if not found Example:

getRunecraftingMultiplier(runeType: string, level: number): number

Calculate multi-rune multiplier for a given rune type and level. Parameters:
  • runeType: Rune type identifier
  • level: Player’s runecrafting level
Returns: Number of runes produced per essence Example:
Formula:

getAllRunecraftingRecipes(): RunecraftingRecipeData[]

Get all runecrafting recipes. Returns: Array of all recipes

isRunecraftingEssence(itemId: string): boolean

Check if an item is a valid runecrafting essence. Parameters:
  • itemId: Item ID to check
Returns: true if item is rune_essence or pure_essence

Tanning Methods

getTanningRecipe(inputItemId: string): TanningRecipeData | null

Get tanning recipe by input hide item ID. Parameters:
  • inputItemId: Hide item ID (e.g., “cowhide”)
Returns: Recipe data or null if not found Example:

getAllTanningRecipes(): TanningRecipeData[]

Get all tanning recipes. Returns: Array of all recipes

isTannableItem(itemId: string): boolean

Check if an item can be tanned. Parameters:
  • itemId: Item ID to check
Returns: true if item has a tanning recipe

Utility Methods

initialize(): void

Initialize the data provider by building lookup tables from manifests. Must be called after DataManager loads manifests. Example:

rebuild(): void

Rebuild all lookup tables (for hot-reload scenarios). Example:

isReady(): boolean

Check if provider is initialized. Returns: true if initialized

getSummary(): object

Get summary of loaded recipes for debugging. Returns:

Event Types

Crafting Events

CRAFTING_INTERACT

Trigger crafting interaction (player used tool on item or clicked furnace). Payload:

PROCESSING_CRAFTING_REQUEST

Request to start crafting with quantity. Payload:

CRAFTING_INTERFACE_OPEN

Server sends available recipes to client. Payload:

CRAFTING_START

Crafting session started. Payload:

CRAFTING_COMPLETE

Crafting session completed. Payload:

Fletching Events

FLETCHING_INTERACT

Trigger fletching interaction (player used knife on logs or item-on-item). Payload:

PROCESSING_FLETCHING_REQUEST

Request to start fletching with quantity. Payload:

FLETCHING_INTERFACE_OPEN

Server sends available recipes to client. Payload:

FLETCHING_START

Fletching session started. Payload:

FLETCHING_COMPLETE

Fletching session completed. Payload:

Runecrafting Events

RUNECRAFTING_INTERACT

Trigger runecrafting interaction (player clicked altar). Payload:

RUNECRAFTING_COMPLETE

Runecrafting completed. Payload:

Tanning Events

TANNING_INTERACT

Trigger tanning interaction (player talked to tanner NPC). Payload:

TANNING_REQUEST

Request tanning with quantity. Payload:

TANNING_INTERFACE_OPEN

Server sends available recipes to client. Payload:

TANNING_COMPLETE

Tanning completed. Payload:

Recipe Manifest Schemas

Crafting Recipe Schema

File: packages/server/world/assets/manifests/recipes/crafting.json
Validation Rules:
  • output: Must exist in items manifest
  • category: Non-empty string
  • inputs: Non-empty array, each item must exist in manifest
  • tools: Array (can be empty), each item must exist in manifest
  • consumables: Array (can be empty), each item must exist in manifest
  • level: Integer 1-99
  • xp: Positive number
  • ticks: Positive integer
  • station: Must be “none” or “furnace”

Fletching Recipe Schema

File: packages/server/world/assets/manifests/recipes/fletching.json
Validation Rules:
  • output: Must exist in items manifest
  • outputQuantity: Positive integer (default: 1)
  • category: Non-empty string
  • inputs: Non-empty array, each item must exist in manifest
  • tools: Array (can be empty for stringing), each item must exist in manifest
  • level: Integer 1-99
  • xp: Positive number
  • ticks: Positive integer
  • skill: Must be “fletching”

Runecrafting Recipe Schema

File: packages/server/world/assets/manifests/recipes/runecrafting.json
Validation Rules:
  • runeType: Non-empty string, unique
  • runeItemId: Must exist in items manifest
  • levelRequired: Integer 1-99
  • xpPerEssence: Positive number
  • essenceTypes: Non-empty array of item IDs
  • multiRuneLevels: Array of integers (can be empty), sorted ascending

Tanning Recipe Schema

File: packages/server/world/assets/manifests/recipes/tanning.json
Validation Rules:
  • input: Must exist in items manifest
  • output: Must exist in items manifest
  • cost: Non-negative integer
  • name: Non-empty string

Recipe Data Types

CraftingRecipeData

FletchingRecipeData

RunecraftingRecipeData

TanningRecipeData

Usage Examples

Starting a Crafting Session

Starting a Fletching Session

Runecrafting at Altar

Tanning Hides

Error Handling

Common Errors

Invalid Recipe:
Insufficient Level:
Missing Materials:
Missing Tools:
Out of Thread:

Performance Considerations

Memory Usage

Per Active Session:
  • CraftingSession: ~200 bytes (includes consumableUses Map)
  • FletchingSession: ~150 bytes
  • RunecraftingSystem: No active sessions (instant)
Recipe Data:
  • Crafting: ~30 recipes × ~500 bytes = ~15KB
  • Fletching: ~37 recipes × ~400 bytes = ~15KB
  • Runecrafting: ~11 recipes × ~300 bytes = ~3KB
  • Total: ~33KB for all recipe data

CPU Usage

Tick Processing:
  • CraftingSystem: O(n) where n = active sessions
  • FletchingSystem: O(n) where n = active sessions
  • RunecraftingSystem: No tick processing
Inventory Scans:
  • Single scan per tick per active session
  • Pre-allocated buffers to avoid allocations
  • Reusable arrays for completed sessions

Optimizations

Inventory State Caching:
Once-Per-Tick Processing:
Pre-Allocated Buffers:

Security

Rate Limiting

All artisan skill interactions are rate-limited:

Audit Logging

All completions are logged for economic tracking:

Input Validation

Recipe ID Validation:
  • Must exist in recipe map
  • Must match expected format
Quantity Validation:
  • Must be positive integer
  • Clamped to available materials
Level Validation:
  • Checked before starting session
  • Re-checked on each craft action
Material Validation:
  • Checked before starting session
  • Re-checked on each craft action
  • Prevents crafting with insufficient materials

Testing

Unit Tests

CraftingSystem:
  • CraftingSystem.test.ts: 19 tests covering lifecycle, cancellation, edge cases
FletchingSystem:
  • FletchingSystem.test.ts: 15 tests covering multi-output, item-on-item, cancellation
RunecraftingSystem:
  • RunecraftingSystem.test.ts: 12 tests covering multipliers, essence validation, levels
ProcessingDataProvider:
  • ProcessingDataProvider.test.ts: 25 tests covering recipe loading, filtering, validation

Integration Tests

Crafting Flow:
  1. Player uses needle on leather
  2. Server sends available recipes
  3. Player selects recipe and quantity
  4. Server starts crafting session
  5. Tick-by-tick processing
  6. Materials consumed, items added, XP granted
  7. Session completes
Fletching Flow:
  1. Player uses knife on logs
  2. Server sends available recipes (arrow shafts, bows)
  3. Player selects arrow shafts and quantity 5
  4. Server starts fletching session
  5. Each action produces 15 arrow shafts
  6. Total: 75 arrow shafts after 5 actions
Runecrafting Flow:
  1. Player clicks air altar with 100 rune essence
  2. Server calculates multiplier (e.g., 3x at level 22)
  3. Server converts all essence instantly
  4. Player receives 300 air runes
  5. Player gains 500 XP (100 essence × 5 XP)

License

GPL-3.0-only - See LICENSE file