Docs/Core concepts/Multi-device (Provider / Consumer)
Multi-device (Provider / Consumer)
Split your game across multiple devices. A Provider owns shared data; Consumers call its exposed methods. Wired together with @editable bindings in UEFN.
Last updated 2026-06-06
Why split?
One big device works fine for small games. Splitting becomes attractive when:
- You have natural domain boundaries — economy, UI, inventory, analytics.
- Multiple devices want to read or write the same data (currency, leaderboard) — putting it on one Provider avoids duplication.
- You ship a pack — a reusable bundle of 2-3 devices a creator drops onto a map.
Provider vs. Consumer
- Provider — owns the state (variables, inventories) and exposes methods like
try_buy(amount),get_balance(),award_xp(amount). There's exactly one Provider per pack. - Consumer — calls the Provider's methods. A Shop device might call
try_buy; a HUD device might callget_balance. You can have many Consumers.
💡 Tip
Exports & bindings
On the Provider, the Exports list declares which methods are public. Each export becomes a Verse method on the Provider class. Internal helpers stay private.
On every Consumer, the Bindings list declares which Provider it depends on. The Composer emits a typed @editable field for the Provider reference, plus method calls that go through that field.
Patterns
Economy pack
Classic shape:
Economy (Provider)— holdscoins, exposesaward_coins(n),try_buy(n).Shop (Consumer)— UI for purchases, callstry_buy.HUD (Consumer)— displays balance, callsget_coins.
Tycoon pack
Provider holds upgrade levels; multiple generator Consumers tick income on their own timer and call award_income(n) on the Provider.
Gotchas
⚠️ Watch out
⚠️ Watch out
📌 Note
What gets generated?
On the Provider, exports are normal methods (often <public> and <decides><transacts>). On the Consumer, the binding becomes an @editable field of the Provider's type, and rule actions emit method calls through it.
shop_device := class(creative_device):
@editable Economy:economy_device = economy_device{}
OnPurchaseButton(Agent:agent):void=
if (Success := Economy.TryBuy[Agent, 100]):
# purchase succeeded — give the reward
...
See also