Resource Respawn System
Updated: March 27, 2026 (PR #1099)Location:
packages/shared/src/systems/shared/entities/ResourceSystem.ts
Overview
The resource respawn system provides deterministic, tick-based respawn mechanics for gathering resources (trees, rocks, fishing spots). It eliminates non-deterministicsetTimeout-based respawn in favor of OSRS-accurate tick counting.
Key Changes (March 2026)
Before (Non-Deterministic)
Resources usedsetTimeout for respawn timing:
- Respawn timing varied based on server load and event loop congestion
- Not OSRS-accurate (OSRS uses deterministic tick-based respawn)
- Difficult to test and reproduce timing issues
After (Tick-Based)
Resources use tick counting for deterministic respawn:- ✅ Deterministic respawn timing (exact tick count)
- ✅ OSRS-accurate mechanics
- ✅ Testable and reproducible
- ✅ No event loop dependency
Architecture
ResourceSystem
File:packages/shared/src/systems/shared/entities/ResourceSystem.ts
processRespawns()
Processes pending resource respawns based on tick count.
Behavior:
- Called every tick by the tick system
- Iterates all depleted resources
- Checks if
currentTick - depletedAtTick >= respawnTicks - Calls
resource.respawn()when ready
ResourceEntity
deplete(): Promise<void>
Marks resource as depleted and records depletion tick.
Behavior:
- Sets
depleted = true - Records
depletedAtTick = world.tickNumber - Calls
visualStrategy.onDepleted()for visual feedback - Does NOT schedule respawn (handled by
ResourceSystem.processRespawns())
respawn(): void
Respawns the resource and resets depletion state.
Behavior:
- Sets
depleted = false - Resets
depletedAtTick = null - Calls
visualStrategy.onRespawn()for visual feedback - Emits
RESOURCE_RESPAWNEDevent
Depletion Chance System
Manifest Configuration
Resources can specify adepleteChance in their manifest to control depletion probability:
depleteChance Values:
1.0- Always depletes on successful gather (default for most resources)0.5- 50% chance to deplete on successful gather0.0- Never depletes (e.g., rune essence rocks in OSRS)
Mining Integration
File:packages/server/src/systems/ServerNetwork/handlers/resources.ts
Mining now reads depleteChance from manifest instead of using hardcoded constants:
MINING_DEPLETE_CHANCE- No longer usedMINING_REDWOOD_DEPLETE_CHANCE- No longer used
- ✅ Rune essence rocks work correctly (never deplete with
depleteChance: 0) - ✅ Consistent depletion behavior across all gathering skills
- ✅ Manifest-driven design (no code changes for new resources)
Tick Calculation
Respawn Timing
Respawn time is converted from milliseconds to ticks:respawnTime: 2400ms→4 ticksrespawnTime: 3000ms→5 ticksrespawnTime: 1800ms→3 ticks
Tick Counting
Depletion tick is recorded when resource is depleted:OSRS Accuracy
Tick-Based Mechanics
OSRS uses a 600ms game tick for all timing:- Combat attacks
- Resource respawns
- Skill actions
- Movement
TICK_DURATION_MS = 600.
Depletion Mechanics
OSRS Behavior:- Most resources deplete on every successful gather
- Some resources (rune essence) never deplete
- Some resources (redwood trees) have low depletion chance
- Copper rock:
depleteChance: 1.0(always depletes) - Rune essence:
depleteChance: 0(never depletes) - Redwood tree:
depleteChance: 0.1(10% chance to deplete)
API Reference
ResourceEntity
Properties
Methods
deplete(): Promise<void>
Depletes the resource and records depletion tick.
Behavior:
- Sets
depleted = true - Records
depletedAtTick = world.tickNumber - Calls
visualStrategy.onDepleted()for visual feedback - Falls back to
loadDepletedModel()if visual strategy doesn’t handle depletion
respawn(): void
Respawns the resource and resets depletion state.
Behavior:
- Sets
depleted = false - Resets
depletedAtTick = null - Calls
visualStrategy.onRespawn()for visual feedback - Emits
RESOURCE_RESPAWNEDevent
ResourceSystem
Methods
processRespawns(): void
Processes pending resource respawns based on tick count.
Behavior:
- Iterates all entities in world
- Filters for depleted
ResourceEntityinstances - Checks if respawn time has elapsed (tick-based)
- Calls
resource.respawn()when ready
Configuration
Manifest Schema
File:packages/server/world/assets/manifests/resources.json
respawnTime- Respawn time in milliseconds (converted to ticks)depleteChance- Probability of depletion on successful gather (0.0-1.0)1.0- Always depletes (default)0.0- Never depletes (rune essence rocks)0.1- 10% chance (redwood trees)
Constants
File:packages/shared/src/constants/GameConstants.ts
Testing
Unit Tests
File:packages/shared/src/systems/shared/entities/gathering/__tests__/ToolUtils.test.ts
Integration Tests
File:packages/shared/src/systems/shared/entities/__tests__/ResourceSystem.integration.test.ts
Migration Guide
Updating from setTimeout-Based Respawn
Before:Updating Depletion Chance Logic
Before (hardcoded constants):Manifest Examples
Standard Tree (Always Depletes)
Rune Essence Rock (Never Depletes)
respawnTime: 0 is ignored since depleteChance: 0 means the resource never depletes.
Redwood Tree (Low Depletion Chance)
Tick Priority
Resource respawn processing runs atTickPriority.RESOURCE_RESPAWN priority:
TickPriority enum):
MOVEMENT- Player/mob movementCOMBAT- Combat processingRESOURCE_RESPAWN- Resource respawnsCLEANUP- Entity cleanup
Performance Characteristics
CPU
- O(resources): Iterates all resources every tick
- Early-out: Skips non-depleted resources immediately
- Typical Cost: ~0.01-0.1ms for 100-1000 resources
Memory
- No Timers: No
setTimeouthandles to track - Minimal State: Only
depletedAtTicknumber per resource - No Leaks: Tick-based approach has no timer cleanup issues
Troubleshooting
Resources not respawning
Symptoms: Depleted resources never respawn. Causes:ResourceSystem.processRespawns()not being calleddepletedAtTicknot being set on depletionrespawnTimeset to 0 or invalid value
Resources respawning too fast/slow
Symptoms: Respawn timing doesn’t match manifestrespawnTime.
Cause: Tick duration mismatch or incorrect respawn time calculation.
Fix: Verify TICK_DURATION_MS = 600 and respawn time is in milliseconds:
Rune essence rocks depleting
Symptoms: Rune essence rocks deplete when they shouldn’t. Cause:depleteChance not set to 0 in manifest, or depletion logic not reading from manifest.
Fix: Verify manifest has depleteChance: 0 and gathering handler reads from manifest:
Code Examples
Basic Resource Depletion
Tick-Based Respawn Processing
Registering Respawn Tick Handler
Related Systems
- TickSystem (
packages/server/src/systems/TickSystem.ts) - Manages game tick loop - ResourceEntity (
packages/shared/src/entities/world/ResourceEntity.ts) - Resource entity implementation - GatheringSystem (
packages/server/src/systems/ServerNetwork/handlers/resources.ts) - Handles gathering actions - TreeGLBVisualStrategy (
packages/shared/src/entities/world/visuals/TreeGLBVisualStrategy.ts) - Tree visual feedback
Related Documentation
- Tree Dissolve Transparency - Visual feedback for depletion/respawn
- Tree Collision Proxy - LOD2 geometry for collision detection
- Performance March 2026 - Server performance overhaul
- Tick System - Game tick implementation