RevFramework – Sample Scene: 08_Currency_Awaiters¶
Goal¶
Teach event-driven waiting for currency changes:
Owner + Currency + ICurrencyService.OnWalletChanged → await condition → complete, timeout, or cancel.
What This Scene Demonstrates¶
This scene shows how to wait for wallet changes without writing your own polling loop.
The flow is:
Owner → ICurrencyService → selected CurrencyId → awaiter observes the wallet → condition check → completion
- Awaiters do not mutate balances
- Awaiters complete only when the selected condition is met
- Awaiters can timeout or be cancelled
- Existing waits are cancelled if the service instance changes
- Awaiters own the waiting, the timeout and the cancellation, so your gameplay code does not scatter per-frame balance checks around
Awaiters replace hand-written polling loops. That is not the same as "nothing ever polls":
| Variant | How it observes |
|---|---|
| Task / async awaiters | Subscribe to OnWalletChanged — genuinely event-driven |
Coroutine WaitForBalanceAtLeast | Re-reads the balance once per frame |
Why the coroutine polls on purpose
It used to subscribe and unsubscribe after the wait loop, and that leaked. Unity stops a coroutine when the behaviour that started it is destroyed, and runs neither the code after the last yield nor a finally block — the enumerator is never disposed. The handler stayed attached to a long-lived service forever, holding the owner and service alive.
Holding no registration at all is the only shape that cannot leak, and polling costs nothing extra because the coroutine already yields every frame. The one behavioural difference: a balance that rises past the target and falls back within a single frame is not observed. The async variants still use the event and do observe it.
The service event is the trigger.
What To Look For¶
Use the CurrencyAwaitersPanel to compare Task-based and Coroutine-based wait flows.
-
Setup tab
-
Owner is the wallet being observed
- Service shows the resolved
ICurrencyServicestack - Currency selection provides the
CurrencyIdbeing matched -
Live balance shows the current state before starting waits
-
Tasks tab
-
WaitForBalanceAtLeastAsynccompletes when balance is at least the target WaitForAnyChangeAsynccompletes on the first matching owner/currency changeWaitForDeltaAsynccaptures the starting balance and waits for an absolute delta thresholdWaitForPredicateAsynccompletes when the supplied predicate returns true-
Each task has timeout and cancellation controls
-
Coroutine tab
-
Coroutine
WaitForBalanceAtLeastteaches the same pattern without async/await -
The coroutine completes, times out, cancels, or exits if owner/service context becomes invalid
-
External mutation source
-
Use another panel or gameplay to change the observed balance
- The awaiter panel waits; it does not create the wallet change itself
Sample Scope¶
This scene covers:
- Event-driven currency waiting through
OnWalletChanged - Task-based awaiters
- Coroutine-based awaiters
- Balance-at-least waits
- Any-change waits
- Delta-threshold waits
- Predicate waits
- Timeout and cancellation behaviour
- Service swap cancellation
This scene does NOT cover:
- Mutating balances directly from the awaiter panel
- Hand-written polling loops in gameplay code
- Internal service inspection
- Custom production quest systems
- Full reactive UI architecture
- Multiplayer replication or networking
Those are project-level integration concerns.
Authority Note¶
This scene may include a permissive sample authority setup so it runs without additional configuration.
Networking Reminder¶
RevFramework does not include networking.
For multiplayer projects, wallet changes should come from server/host-approved mutations. Awaiters can react to local service events, but they are not a networking or authority layer.
How To Use¶
- Enter Play Mode.
- Toggle the
CurrencyAwaitersPanelwithF8. -
In Setup:
-
Confirm Owner is assigned
- Confirm
ICurrencyServiceis resolved - Select a valid currency
- Check the live balance
-
In Tasks:
-
Configure the target, delta, predicate value, or timeout
- Start one of the task awaiters
- Use another panel or gameplay to mutate the selected owner/currency
- Watch the status update when the condition completes, times out, or is cancelled
-
In Coroutine:
-
Enter a target and timeout
- Start the coroutine awaiter
- Mutate the selected owner/currency externally
- Watch the coroutine status complete or cancel
- Cancel running waits when you no longer need them.
Failure Behaviour¶
Failures or exits are shown through dependency messages, awaiter statuses, or result messages.
Common causes:
-
Play Mode required
-
Awaiters listen to live runtime service events
-
Fix: enter Play Mode
-
Service missing
-
No
ICurrencyServicewas resolved -
Fix: add a scene currency service, add
CurrencyServiceBootstrap, or publish a composed service -
Owner missing
-
No wallet owner is selected
-
Fix: assign an owner or tag the player GameObject as
Player -
No currencies bound
-
No
CurrencyDefinitionassets are available -
Fix: assign currencies in the Inspector or provide a
CurrencySet -
Invalid CurrencyId
-
The selected
CurrencyDefinitionhas an invalid Id -
Fix: correct the CurrencyDefinition asset
-
Bad input
-
Target, delta, predicate, or timeout values are invalid
-
Fix: enter values within the panel’s accepted ranges
-
Timeout
-
No matching event satisfied the condition before timeout
-
Fix: increase the timeout or trigger a matching owner/currency mutation
-
Cancelled
-
The user cancelled the awaiter, the panel disabled, or context changed
-
Fix: start the awaiter again when ready
-
Service changed
-
Existing waits are tied to the previous service instance
-
Fix: restart awaiters against the new service
-
No completion despite balance changes
-
The awaited owner/currency did not match the emitted change
- Fix: check owner binding, selected currency, service reference, and whether
OnWalletChangedfires for that mutation
Behind The Scenes¶
The panel uses real Currency awaiter APIs:
-
CurrencyResolve.ServiceFrom -
resolves the active
ICurrencyService -
ICurrencyService -
GetBalance -
OnWalletChanged -
CurrencyAwaiters -
WaitForBalanceAtLeastAsync WaitForAnyChangeAsyncWaitForDeltaAsyncWaitForPredicateAsync-
WaitForBalanceAtLeastcoroutine variant -
CancellationTokenSource -
cancels Task-based waits
-
Unity coroutine host
-
runs the coroutine awaiter
The panel observes service events only.
It does not inspect internals.
It does not mutate balances directly.
Key Takeaway¶
Awaiters wait on the real wallet.
They complete when the selected condition becomes true.
Use them when you want reactive currency logic without hand-writing the wait, the timeout and the cancellation yourself.