Skip to main content

ProcessingDataProvider

Runtime data provider for processing skills (cooking, firemaking, smelting, smithing). Builds lookup tables from recipe manifest files loaded by DataManager. Location: packages/shared/src/data/ProcessingDataProvider.ts

Overview

ProcessingDataProvider is a singleton that:
  1. Loads recipe manifests from recipes/ directory
  2. Builds efficient lookup tables for runtime queries
  3. Provides methods to check requirements and availability
  4. Falls back to embedded item data if manifests missing

Initialization

import { processingDataProvider } from '@hyperscape/shared';

// Initialize (called automatically by DataManager)
processingDataProvider.initialize();

// Check if initialized
const summary = processingDataProvider.getSummary();
console.log(summary.isInitialized); // true

Cooking Methods

isCookableItem

Check if an item can be cooked.
isCookableItem(itemId: string): boolean
Example:
const canCook = processingDataProvider.isCookableItem("raw_shrimp");
// Returns: true

getCookingData

Get cooking data for a raw food item.
getCookingData(rawItemId: string): CookingItemData | null
Returns:
interface CookingItemData {
  rawItemId: string;
  cookedItemId: string;
  burntItemId: string;
  levelRequired: number;
  xp: number;
  stopBurnLevel: {
    fire: number;
    range: number;
  };
}
Example:
const data = processingDataProvider.getCookingData("raw_shrimp");
// Returns: { rawItemId: "raw_shrimp", cookedItemId: "shrimp", burntItemId: "burnt_shrimp", ... }

getCookableItemIds

Get all cookable item IDs.
getCookableItemIds(): Set<string>

getCookingLevel

Get cooking level requirement for an item.
getCookingLevel(rawItemId: string): number

getCookingXP

Get cooking XP for an item.
getCookingXP(rawItemId: string): number

Firemaking Methods

isBurneableLog

Check if an item can be burned.
isBurneableLog(itemId: string): boolean

getFiremakingData

Get firemaking data for a log.
getFiremakingData(logId: string): FiremakingItemData | null
Returns:
interface FiremakingItemData {
  logId: string;
  levelRequired: number;
  xp: number;
}

getBurneableLogIds

Get all burneable log IDs.
getBurneableLogIds(): Set<string>

getFiremakingLevel

Get firemaking level requirement for a log.
getFiremakingLevel(logId: string): number

getFiremakingXP

Get firemaking XP for a log.
getFiremakingXP(logId: string): number

Smelting Methods

isSmeltableBar

Check if an item is a smeltable bar.
isSmeltableBar(itemId: string): boolean
Example:
const canSmelt = processingDataProvider.isSmeltableBar("bronze_bar");
// Returns: true

getSmeltingData

Get smelting data for a bar.
getSmeltingData(barItemId: string): SmeltingItemData | null
Returns:
interface SmeltingItemData {
  barItemId: string;
  primaryOre: string;
  secondaryOre: string | null;
  coalRequired: number;
  levelRequired: number;
  xp: number;
  successRate: number;
  ticks: number;
}
Example:
const data = processingDataProvider.getSmeltingData("bronze_bar");
// Returns: { 
//   barItemId: "bronze_bar",
//   primaryOre: "copper_ore",
//   secondaryOre: "tin_ore",
//   coalRequired: 0,
//   levelRequired: 1,
//   xp: 6.25,
//   successRate: 1.0,
//   ticks: 4
// }

getSmeltableBarsFromInventory

Get all bars that can be smelted from inventory.
getSmeltableBarsFromInventory(
  inventory: Array<{ itemId: string; quantity?: number }>,
  smithingLevel: number
): SmeltingItemData[]
Example:
const inventory = [
  { itemId: "copper_ore", quantity: 5 },
  { itemId: "tin_ore", quantity: 5 },
  { itemId: "iron_ore", quantity: 3 },
  { itemId: "coal", quantity: 10 }
];

const bars = processingDataProvider.getSmeltableBarsFromInventory(inventory, 30);
// Returns: [bronze_bar, iron_bar, steel_bar] (player has level 30)

isSmeltableOre

Check if an item is an ore that can be used for smelting.
isSmeltableOre(itemId: string): boolean

getSmeltableOreIds

Get all ore IDs that can be used for smelting.
getSmeltableOreIds(): Set<string>

getSmeltableBarIds

Get all smeltable bar IDs.
getSmeltableBarIds(): Set<string>

getSmeltingLevel

Get smelting level requirement for a bar.
getSmeltingLevel(barItemId: string): number

getSmeltingXP

Get smelting XP for a bar.
getSmeltingXP(barItemId: string): number

getSmeltingTicks

Get smelting ticks for a bar (time in game ticks).
getSmeltingTicks(barItemId: string): number

Smithing Methods

isSmithableItem

Check if an item can be smithed.
isSmithableItem(itemId: string): boolean
Example:
const canSmith = processingDataProvider.isSmithableItem("bronze_sword");
// Returns: true

getSmithingRecipe

Get smithing recipe data for an output item.
getSmithingRecipe(itemId: string): SmithingRecipeData | null
Returns:
interface SmithingRecipeData {
  itemId: string;
  name: string;
  barType: string;
  barsRequired: number;
  levelRequired: number;
  xp: number;
  category: SmithingCategory;
  ticks: number;
}

type SmithingCategory = "weapons" | "armor" | "tools" | "misc";
Example:
const recipe = processingDataProvider.getSmithingRecipe("bronze_sword");
// Returns: {
//   itemId: "bronze_sword",
//   name: "Bronze Sword",
//   barType: "bronze_bar",
//   barsRequired: 1,
//   levelRequired: 4,
//   xp: 12.5,
//   category: "weapons",
//   ticks: 4
// }

getSmithableItemsFromInventory

Get all items that can be smithed from inventory (deprecated - use getSmithableItemsWithAvailability instead).
getSmithableItemsFromInventory(
  inventory: Array<{ itemId: string; quantity?: number }>,
  smithingLevel: number
): SmithingRecipeData[]

getSmithableItemsWithAvailability

Get all smithable items with availability info for UI display.
getSmithableItemsWithAvailability(
  inventory: Array<{ itemId: string; quantity?: number }>,
  smithingLevel: number
): SmithingRecipeWithAvailability[]
Returns:
interface SmithingRecipeWithAvailability extends SmithingRecipeData {
  meetsLevel: boolean;  // Player has sufficient level
  hasBars: boolean;     // Player has enough bars
}
Example:
const inventory = [
  { itemId: "bronze_bar", quantity: 10 }
];

const recipes = processingDataProvider.getSmithableItemsWithAvailability(inventory, 1);
// Returns all bronze recipes with meetsLevel/hasBars flags
// Items with meetsLevel=false should be greyed out in UI
This method returns ALL recipes for bar types the player has, including items they can’t make yet. Use the meetsLevel and hasBars flags to grey out unavailable items in the UI.

getSmithingRecipesForBar

Get all recipes for a specific bar type.
getSmithingRecipesForBar(barType: string): SmithingRecipeData[]
Example:
const bronzeRecipes = processingDataProvider.getSmithingRecipesForBar("bronze_bar");
// Returns: [bronze_dagger, bronze_sword, bronze_scimitar, bronze_platebody, ...]

getSmithingRecipesByCategory

Get recipes grouped by category for a specific bar type.
getSmithingRecipesByCategory(barType: string): Map<SmithingCategory, SmithingRecipeData[]>
Example:
const grouped = processingDataProvider.getSmithingRecipesByCategory("bronze_bar");
// Returns: Map {
//   "weapons" => [bronze_dagger, bronze_sword, bronze_scimitar, ...],
//   "armor" => [bronze_full_helm, bronze_platebody, bronze_platelegs, ...],
//   "tools" => [bronze_pickaxe, bronze_hatchet]
// }

getAllSmithingRecipes

Get all smithing recipes.
getAllSmithingRecipes(): SmithingRecipeData[]

getAvailableSmithingRecipes

Get all recipes the player can make with their smithing level.
getAvailableSmithingRecipes(smithingLevel: number): SmithingRecipeData[]

getSmithableItemIds

Get all smithable item IDs.
getSmithableItemIds(): Set<string>

getSmithingLevel

Get smithing level requirement for an item.
getSmithingLevel(itemId: string): number

getSmithingXP

Get smithing XP for an item.
getSmithingXP(itemId: string): number

getSmithingTicks

Get smithing ticks for an item (time in game ticks).
getSmithingTicks(itemId: string): number

Utility Methods

getSummary

Get summary of loaded data.
getSummary(): {
  cookableItems: number;
  burnableLogs: number;
  smeltableBars: number;
  smithingRecipes: number;
  isInitialized: boolean;
}
Example:
const summary = processingDataProvider.getSummary();
console.log(`Loaded ${summary.smithingRecipes} smithing recipes`);

rebuild

Rebuild all lookup tables (for testing or after manifest reload).
rebuild(): void

Performance Optimizations

Pre-Allocated Buffers

ProcessingDataProvider uses pre-allocated buffers to reduce GC pressure:
// Pre-allocated Map for inventory counting
private readonly inventoryCountBuffer = new Map<string, number>();

// Reused across getSmeltableBarsFromInventory and getSmithableItemsFromInventory
private buildInventoryCounts(inventory): Map<string, number> {
  this.inventoryCountBuffer.clear();
  // ... populate buffer
  return this.inventoryCountBuffer;
}
This avoids creating new Map instances on every inventory query.

Manifest Loading

ProcessingDataProvider loads recipes from JSON manifests:

Loading Order

  1. DataManager loads recipe manifests from recipes/ directory
  2. DataManager calls processingDataProvider.loadCookingRecipes(manifest)
  3. DataManager calls processingDataProvider.loadSmeltingRecipes(manifest)
  4. DataManager calls processingDataProvider.loadSmithingRecipes(manifest)
  5. DataManager calls processingDataProvider.rebuild()

Fallback Behavior

If recipe manifests are missing, ProcessingDataProvider falls back to embedded item data:
// Try manifest first
if (this.cookingManifest) {
  this.buildCookingDataFromManifest();
} else {
  // Fallback: scan ITEMS for items with cooking property
  this.buildCookingDataFromItems();
}
This ensures backwards compatibility with older manifest formats.

Type Definitions

CookingItemData

interface CookingItemData {
  rawItemId: string;
  cookedItemId: string;
  burntItemId: string;
  levelRequired: number;
  xp: number;
  stopBurnLevel: {
    fire: number;
    range: number;
  };
}

FiremakingItemData

interface FiremakingItemData {
  logId: string;
  levelRequired: number;
  xp: number;
}

SmeltingItemData

interface SmeltingItemData {
  barItemId: string;
  primaryOre: string;
  secondaryOre: string | null;
  coalRequired: number;
  levelRequired: number;
  xp: number;
  successRate: number;
  ticks: number;
}

SmithingRecipeData

interface SmithingRecipeData {
  itemId: string;
  name: string;
  barType: string;
  barsRequired: number;
  levelRequired: number;
  xp: number;
  category: SmithingCategory;
  ticks: number;
}

type SmithingCategory = "weapons" | "armor" | "tools" | "misc";

SmithingRecipeWithAvailability

interface SmithingRecipeWithAvailability extends SmithingRecipeData {
  meetsLevel: boolean;  // Player has sufficient level
  hasBars: boolean;     // Player has enough bars
}

Manifest Structures

CookingManifest

interface CookingManifest {
  recipes: Array<{
    raw: string;
    cooked: string;
    burnt: string;
    level: number;
    xp: number;
    ticks: number;
    stopBurnLevel: { fire: number; range: number };
  }>;
}

FiremakingManifest

interface FiremakingManifest {
  recipes: Array<{
    log: string;
    level: number;
    xp: number;
    ticks: number;
  }>;
}

SmeltingManifest

interface SmeltingManifest {
  recipes: Array<{
    output: string;
    inputs: Array<{ item: string; amount: number }>;
    level: number;
    xp: number;
    ticks: number;
    successRate: number;
  }>;
}

SmithingManifest

interface SmithingManifest {
  recipes: Array<{
    output: string;
    bar: string;
    barsRequired: number;
    level: number;
    xp: number;
    ticks: number;
    category: string;
  }>;
}

Usage Examples

Check if Player Can Smelt

const inventory = world.getInventory(playerId);
const smithingLevel = player.skills.smithing.level;

const availableBars = processingDataProvider.getSmeltableBarsFromInventory(
  inventory,
  smithingLevel
);

if (availableBars.length > 0) {
  console.log(`Player can smelt ${availableBars.length} bar types`);
}

Get Smithing UI Data

const inventory = world.getInventory(playerId);
const smithingLevel = player.skills.smithing.level;

const recipes = processingDataProvider.getSmithableItemsWithAvailability(
  inventory,
  smithingLevel
);

// Group by category for UI
const byCategory = new Map();
for (const recipe of recipes) {
  if (!byCategory.has(recipe.category)) {
    byCategory.set(recipe.category, []);
  }
  byCategory.get(recipe.category).push(recipe);
}

// Render UI with greyed-out items
for (const [category, items] of byCategory) {
  console.log(`Category: ${category}`);
  for (const item of items) {
    const available = item.meetsLevel && item.hasBars;
    console.log(`  ${item.name} - ${available ? "Available" : "Locked"}`);
  }
}

Validate Smelting Request

const barItemId = "steel_bar";
const smeltingData = processingDataProvider.getSmeltingData(barItemId);

if (!smeltingData) {
  console.error("Invalid bar type");
  return;
}

if (player.skills.smithing.level < smeltingData.levelRequired) {
  console.error(`Need level ${smeltingData.levelRequired} Smithing`);
  return;
}

// Check materials
const hasIron = inventory.some(i => i.itemId === "iron_ore");
const hasCoal = inventory.filter(i => i.itemId === "coal").length >= 2;

if (!hasIron || !hasCoal) {
  console.error("Missing materials");
  return;
}

// Start smelting
world.emit(EventType.PROCESSING_SMELTING_REQUEST, {
  playerId,
  barItemId,
  furnaceId,
  quantity: 10
});