> ## Documentation Index
> Fetch the complete documentation index at: https://hyperscape-ai-mintlify-docs-update-1771471401694.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# TierDataProvider

> OSRS-accurate tier-based level requirements for equipment and tools

# TierDataProvider

Provides OSRS-accurate tier-based level requirements for equipment and tools. Single source of truth loaded from `tier-requirements.json` manifest.

**Location**: `packages/shared/src/data/TierDataProvider.ts`

***

## Overview

TierDataProvider eliminates redundant requirement definitions by mapping metal tiers (bronze, iron, steel, etc.) to skill requirements. Instead of manually specifying requirements for every item, you just set the `tier` property.

### Before (Manual Requirements)

```json theme={null}
{
  "id": "steel_sword",
  "name": "Steel Sword",
  "requirements": {
    "skills": {
      "attack": 5
    }
  }
}
```

### After (Tier-Based)

```json theme={null}
{
  "id": "steel_sword",
  "name": "Steel Sword",
  "tier": "steel",
  "equipSlot": "weapon",
  "attackType": "MELEE"
  // requirements auto-derived from tier
}
```

***

## Initialization

```typescript theme={null}
import { TierDataProvider, loadTierRequirements } from '@hyperscape/shared';

// Load tier requirements (called by DataManager)
const manifest = await fetch('/assets/manifests/tier-requirements.json');
loadTierRequirements(await manifest.json());

// Check if loaded
if (TierDataProvider.isLoaded()) {
  console.log("Tier data ready");
}
```

***

## Methods

### getRequirements

Get requirements for an item based on its tier.

```typescript theme={null}
getRequirements(item: TierableItem): TierRequirements | null
```

**Parameters:**

```typescript theme={null}
interface TierableItem {
  id: string;
  type: string;
  tier?: string;
  equipSlot?: string;
  attackType?: string;
  requirements?: {
    level?: number;
    skills?: Record<string, number>;
  };
  tool?: {
    skill: "woodcutting" | "mining" | "fishing";
    priority: number;
    rollTicks?: number;
  };
}
```

**Returns:**

```typescript theme={null}
interface TierRequirements {
  attack?: number;
  defence?: number;
  ranged?: number;
  magic?: number;
  woodcutting?: number;
  mining?: number;
  fishing?: number;
}
```

**Example:**

```typescript theme={null}
const item = {
  id: "steel_sword",
  type: "weapon",
  tier: "steel",
  equipSlot: "weapon",
  attackType: "MELEE"
};

const requirements = TierDataProvider.getRequirements(item);
// Returns: { attack: 5 }
```

### getTierData

Get raw tier data for a specific category and tier.

```typescript theme={null}
getTierData(
  category: "melee" | "tools" | "ranged" | "magic",
  tier: string
): MeleeTierData | ToolTierData | RangedTierData | MagicTierData | null
```

**Example:**

```typescript theme={null}
const steelMelee = TierDataProvider.getTierData("melee", "steel");
// Returns: { attack: 5, defence: 5 }

const steelTools = TierDataProvider.getTierData("tools", "steel");
// Returns: { attack: 5, woodcutting: 6, mining: 6 }
```

### getAvailableTiers

Get all available tiers for a category.

```typescript theme={null}
getAvailableTiers(category: "melee" | "tools" | "ranged" | "magic"): string[]
```

**Example:**

```typescript theme={null}
const meleeTiers = TierDataProvider.getAvailableTiers("melee");
// Returns: ["bronze", "iron", "steel", "black", "mithril", "adamant", "rune", "dragon"]
```

### isLoaded

Check if tier data is loaded.

```typescript theme={null}
isLoaded(): boolean
```

### reset

Reset tier data (for testing).

```typescript theme={null}
reset(): void
```

***

## Tier Categories

### Melee Equipment

Weapons and armor that use Attack/Defence requirements.

```typescript theme={null}
interface MeleeTierData {
  attack: number;
  defence: number;
}
```

**Tiers:**

| Tier    | Attack | Defence |
| ------- | ------ | ------- |
| Bronze  | 1      | 1       |
| Iron    | 1      | 1       |
| Steel   | 5      | 5       |
| Black   | 10     | 10      |
| Mithril | 20     | 20      |
| Adamant | 30     | 30      |
| Rune    | 40     | 40      |
| Dragon  | 60     | 60      |

### Tools

Hatchets and pickaxes that use Attack + skill requirements.

```typescript theme={null}
interface ToolTierData {
  attack: number;
  woodcutting: number;
  mining: number;
}
```

**Tiers:**

| Tier    | Attack | Woodcutting | Mining |
| ------- | ------ | ----------- | ------ |
| Bronze  | 1      | 1           | 1      |
| Iron    | 1      | 1           | 1      |
| Steel   | 5      | 6           | 6      |
| Black   | 10     | 11          | 11     |
| Mithril | 20     | 21          | 21     |
| Adamant | 30     | 31          | 31     |
| Rune    | 40     | 41          | 41     |
| Dragon  | 60     | 61          | 61     |

<Info>
  **Fishing tools** don't use the tier system - they have explicit requirements in the item definition.
</Info>

### Ranged Equipment

Bows and ranged armor that use Ranged/Defence requirements.

```typescript theme={null}
interface RangedTierData {
  ranged: number;
  defence: number;
}
```

**Tiers:**

| Tier         | Ranged | Defence |
| ------------ | ------ | ------- |
| Leather      | 1      | 1       |
| Hardleather  | 10     | 10      |
| Studded      | 20     | 20      |
| Green D'hide | 40     | 40      |
| Blue D'hide  | 50     | 50      |
| Red D'hide   | 60     | 60      |
| Black D'hide | 70     | 70      |

### Magic Equipment

Staffs and robes that use Magic/Defence requirements.

```typescript theme={null}
interface MagicTierData {
  magic: number;
  defence?: number;
}
```

**Tiers:**

| Tier      | Magic | Defence |
| --------- | ----- | ------- |
| Basic     | 1     | -       |
| Wizard    | 10    | 10      |
| Mystic    | 40    | 20      |
| Infinity  | 50    | 25      |
| Ancestral | 75    | 65      |

***

## Requirement Precedence

TierDataProvider follows this order when determining requirements:

1. **Explicit requirements** (item.requirements.skills) - Highest priority
2. **Tier-derived requirements** (from tier-requirements.json)
3. **null** (no requirements)

This allows special items (Barrows, quest rewards) to override tier-based requirements.

***

## Manifest Structure

**File**: `packages/server/world/assets/manifests/tier-requirements.json`

```json theme={null}
{
  "melee": {
    "bronze": { "attack": 1, "defence": 1 },
    "iron": { "attack": 1, "defence": 1 },
    "steel": { "attack": 5, "defence": 5 },
    "mithril": { "attack": 20, "defence": 20 },
    "adamant": { "attack": 30, "defence": 30 },
    "rune": { "attack": 40, "defence": 40 },
    "dragon": { "attack": 60, "defence": 60 }
  },
  "tools": {
    "bronze": { "attack": 1, "woodcutting": 1, "mining": 1 },
    "iron": { "attack": 1, "woodcutting": 1, "mining": 1 },
    "steel": { "attack": 5, "woodcutting": 6, "mining": 6 },
    "mithril": { "attack": 20, "woodcutting": 21, "mining": 21 },
    "adamant": { "attack": 30, "woodcutting": 31, "mining": 31 },
    "rune": { "attack": 40, "woodcutting": 41, "mining": 41 },
    "dragon": { "attack": 60, "woodcutting": 61, "mining": 61 }
  },
  "ranged": {
    "leather": { "ranged": 1, "defence": 1 },
    "hardleather": { "ranged": 10, "defence": 10 },
    "studded": { "ranged": 20, "defence": 20 },
    "green_dhide": { "ranged": 40, "defence": 40 },
    "red_dhide": { "ranged": 60, "defence": 60 },
    "black_dhide": { "ranged": 70, "defence": 70 }
  },
  "magic": {
    "basic": { "magic": 1 },
    "wizard": { "magic": 10, "defence": 10 },
    "mystic": { "magic": 40, "defence": 20 },
    "infinity": { "magic": 50, "defence": 25 }
  }
}
```

***

## Integration with DataManager

DataManager uses TierDataProvider during item normalization:

```typescript theme={null}
// From DataManager.normalizeItem()
if (!requirements && item.tier && TierDataProvider.isLoaded()) {
  const tierableItem: TierableItem = {
    id: item.id,
    type: item.type,
    tier: item.tier,
    equipSlot: equipSlot || undefined,
    attackType: attackType || undefined,
    tool: item.tool,
  };
  
  const derived = TierDataProvider.getRequirements(tierableItem);
  if (derived) {
    // Calculate level as max of all skill requirements
    const level = Math.max(1, ...Object.values(derived).filter(
      (v): v is number => typeof v === "number"
    ));
    
    requirements = {
      level,
      skills: derived,
    };
  }
}
```

This automatically populates `item.requirements` from the tier system.

***

## Related Documentation

* [Manifest-Driven Design](/concepts/manifests)
* [Item Data Structure](/wiki/data/items)
* [Skills & Progression](/wiki/game-systems/skills)
* [DataManager](/api-reference/data-manager)
