🔌 Crafting System — Integration Surfaces¶
This page explains where new gameplay logic should integrate with the RevFramework Crafting system.
If you're adding a new mechanic, start here.
The Crafting architecture is intentionally modular. Each behaviour belongs to a specific extension surface. Choosing the correct surface keeps crafting predictable, testable, and compatible with the rest of the framework.
🧠 Extension Surfaces Overview¶
| Goal | Extension Point | Example |
|---|---|---|
| Allow or block crafting | ICraftingValidator |
cooldown, level gate, progression lock |
| Change craft behaviour | ICraftingModifier |
speed bonus, bonus outputs, currency scaling |
| Connect inventory | ICraftingInventoryAdapter |
backpack, chest, custom inventory backend |
| Connect currency | ICraftingCurrencyAdapter |
gold, credits, custom wallet service |
| Add strong reservation semantics | ICraftingInventoryReservationAdapter / ICraftingCurrencyHoldAdapter |
escrow / atomic immediate crafting |
| Route outputs to containers | ICraftingOutputRouter |
ore box, herb pouch, overflow container |
| Control mutation authority | ICraftingAuthority |
server authority, host-only crafting |
| Provide optional level data | ICraftingLevelSource |
progression gate, account level |
| Drive gameplay / UI flow | Your own code calling CraftingService |
buttons, workbenches, recipe menus |
⚙ Example Decision Flow¶
Cooldown Between Crafts¶
Use:
ICraftingValidator
Cooldowns decide whether crafting is allowed right now, so they belong in validation.
Faster Crafting Bench¶
Use:
ICraftingModifier
A bench that changes craft duration is modifying how the craft behaves, not whether it is permitted.
Bonus Rare Drop¶
Use:
ICraftingModifier
Rare or conditional extra outputs belong in modifier logic through
CraftAdjustments.extraOutputs or CraftAdjustments.chanceOutputs.
Route Ores to a Separate Container¶
Use:
ICraftingOutputRouter
Routing decides where outputs go, not whether the craft is allowed.
Server-Authoritative Crafting¶
Use:
ICraftingAuthority
Authority determines who may mutate crafting state. It does not perform replication.
Connect to Your Inventory System¶
Use:
ICraftingInventoryAdapter
Crafting should not know your inventory internals directly.
Atomic Immediate Crafting¶
Use:
ICraftingInventoryReservationAdapter
ICraftingCurrencyHoldAdapter
Escrow crafting requires reservation/hold-capable adapters. Without them, the strong path refuses to run.
🛡 Validators vs Modifiers¶
Validators control permission. Modifiers control behaviour.
| Behaviour | Correct Surface |
|---|---|
| Cooldown | Validator |
| Level requirement | Validator |
| Station tag requirement | Validator |
| Craft time scaling | Modifier |
| Currency scaling | Modifier |
| Bonus output | Modifier |
| Chance output | Modifier |
Rule of thumb:
- If it changes whether the craft can proceed → Validator
- If it changes what the craft does → Modifier
📦 Routing vs Inventory¶
Routing decides which container should receive outputs. Inventory adapters decide how containers are resolved and mutated.
| Behaviour | Correct Surface |
|---|---|
| Send herbs to HerbPouch | Output Router |
| Count items in Backpack | Inventory Adapter |
| Add crafted item to container | Inventory Adapter |
| Choose destination container for output | Output Router |
If you find yourself writing container-selection logic inside an inventory adapter, the responsibility is probably in the wrong place.
⚖ Best-Effort vs Escrow¶
Crafting supports two execution styles.
Best-Effort (Default)¶
Use the normal CraftingService.Enqueue(...) pipeline when:
- immediate consumption is acceptable
- delivery failure can be compensated
- you do not require strict atomicity
Escrow (Opt-In)¶
Use TryCraftImmediateEscrow(...) when:
- the craft is immediate (
duration == 0) - your adapters can reserve inputs and hold currency
- atomic immediate execution matters
Escrow is an adapter capability question, not a validator or modifier concern.
💾 Persistence (Save / Load)¶
Crafting supports snapshot-based persistence via:
SaveActiveJobs(...)
RestoreJobs(...)
These APIs define:
- what data to persist (active jobs)
- how jobs resume (including offline progress)
They do not provide a persistence system.
🧠 Responsibility Model¶
-
CraftingService
-
Owns job state
- Owns timing and offline progression
-
Owns how jobs resume and complete
-
Your Game
-
Decides when to save
- Decides where to store data (file, cloud, database)
- Provides ID resolution (owner / recipe)
- Calls restore at the correct time in your lifecycle
🧩 Example Integration Flow¶
Game Save:
→ SaveActiveJobs(...)
→ Store snapshot in your save system
Game Load:
→ Load snapshot
→ RestoreJobs(...)
⚠ Important Notes¶
-
Snapshots are data only — they do not resolve objects automatically
-
You must provide:
-
ownerResolver -
recipeResolver -
Offline progress depends on:
-
acceptedAtUtc - your configured
IWallClockProvider
⚠ Design Rule¶
Crafting is responsible for what the data means. Your game is responsible for when and where it is saved.
⚠ Common Mistakes¶
Avoid the following:
- Mutating inventory or currency directly from validators
- Performing authority logic inside modifiers
- Treating routing as an inventory concern
- Consuming inputs outside
CraftingService - Using UI or workbenches to fake job state
- Assuming escrow applies to timed crafts
- Assuming validators can override failed space preflight
🧩 Architecture Summary¶
Preflight
├─ Inventory Adapter
├─ Currency Adapter
├─ Output Router (space checks)
├─ Modifiers (adjustments)
└─ Validators
↓
Accept / Commit Boundary
├─ Authority
├─ Inputs / Currency consumed or reserved
└─ Job created (standard path only)
↓
Job / Schedule / Time
↓
Delivery
├─ Modifiers (delivery pass)
├─ Output Router
└─ Inventory Adapter
Every extension surface plugs into one of these stages.