Exchanges

An exchange is something that happens all or nothing across players and plugins: two players trade, a player crafts (costs in, items out), a trader sells, a quest takes items and gives a reward. Pulse Foundation checks every step first, runs them, and undoes what was done when one fails, so no item is duplicated or lost on the way.

Parts

Part What it is
Parties A context per player (FPulseCostContext: player, source, cost fraction and offset)
Steps Each for one party: Conditions (only checked), Costs (paid, given back on failure), Rewards (granted after every cost, taken back on failure), or your own step

Steps that take (costs, own Take steps) run first, in order; steps that give (rewards, own Give steps) run after them.

FPulseExchange trade;
trade.Name = TEXT("Trade");
const int32 buyer = trade.AddParty(BuyerContext);
const int32 seller = trade.AddParty(SellerContext);
trade.AddStep<FPulseExchangeStep_Costs>(buyer).Costs = Price;        // gold of the buyer
trade.AddStep<FPulseExchangeStep_Costs>(seller).Costs = Goods;       // the sword of the seller
trade.AddStep<FPulseExchangeStep_Rewards>(buyer).Rewards = GoodsAsReward;
trade.AddStep<FPulseExchangeStep_Rewards>(seller).Rewards = PriceAsReward;

const FPulseResult result = Pulse::Exchange::Run(trade);   // on the server

Running

Function What it does
Pulse::Exchange::Check Checks every step, changes nothing
Pulse::Exchange::Run Checks, then runs every step all or nothing (server). The result is a result: Pulse.Result.Failure.Costs (a cost), .NoSpace (a reward has no room), .Conditions (a condition or an own step), .Authority, .Invalid; details FPulseExchangeFailure (step, party, whether it failed while running, steps undone)
Pulse::Exchange::RunAsync The same with steps that finish later (a purchase in a store): one step at a time; when a step fails, the steps before are undone in reverse order (compensation)

Everything of Run happens in one call on the game thread of the server, so no other exchange or request runs in between. Costs are given back with reversed rounding, so a refund is exactly what was paid. Rewards are checked with Can Grant before anything is taken (an inventory without room stops the exchange), and Revoke takes a reward back when a later step fails. This is not a general transaction system: a step outside the game (an online store) cannot always be undone, and its own Undo decides what compensation means.

Own steps

Derive from FPulseExchangeStep for things that are neither a cost nor a reward: move an item between two inventories, set a flag, buy in a store.

Function What it does
GetPhase Take (default) or Give
Check Whether it can run; nothing changes
Execute Runs it; false undoes the steps before
Undo Takes it back after a later step failed
IsAsync, BeginExecute A step that finishes later (only RunAsync runs it)
GetFailureReason, GetDisplayText The reason of a failed check and the line in the log

Rewards of your own can implement CanGrant and Revoke (C++ FPulseReward, Blueprint UPulseRewardObject), so exchanges know whether they fit and how to take them back (rewards).

Log

Every exchange records an event in the debug timeline (“Trade: done” or “nothing changed” with the reason), and a report for the Reports page of the Pulse Debugger: always for a failed exchange, for successful ones while the timeline records. The report lists every step that ran or was undone. The spec group PulseFoundation.Exchange.Dupes checks the cases in which items could be duplicated or lost (a party cannot pay, a payment fails late, a reward has no room, a step fails after the rewards, the same request twice).


PulseFoundation plugin documentation.

This site uses Just the Docs, a documentation theme for Jekyll.