VerseBuilderDocs

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 call get_balance. You can have many Consumers.

💡 Tip

Think Provider = backend, Consumer = frontend. The Provider hides the storage details; Consumers just use its API.

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) — holds coins, exposes award_coins(n), try_buy(n).
  • Shop (Consumer) — UI for purchases, calls try_buy.
  • HUD (Consumer) — displays balance, calls get_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

Bindings are wired by name in UEFN. A typo or missing wire = silent failure at runtime (or a crash on the first method call). Test in UEFN early.

⚠️ Watch out

One Provider per pack. Two Providers exposing the same export would let Consumers pick one at wiring time — that's rarely what you want. Keep ownership clear.

📌 Note

Provider exports run in the Provider's device context, not the Consumer's. Anything they touch (variables, configs) belongs to the Provider.

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
            ...
Consumer side — note the @editable provider reference and the call.

See also