Table of Contents

Class TradeSession

Namespace
FishMMO.Server.Implementation.World.SceneServer
Assembly
FishMMO.Server.dll

The state of one open trade between two characters.

public sealed class TradeSession
Inheritance
TradeSession
Inherited Members

Remarks

Pure state with the rules that govern it, and nothing else: no network, no containers, no Unity. TradeSystem resolves characters and inventories, validates what a request refers to, and then asks this object whether the change is allowed and records it here. That split is what lets the acceptance rules be tested as a truth table.

TWO STAGES: CONFIRM, THEN ACCEPT. Confirming says "this is my final offer". While both sides have confirmed the table is LOCKED: no item and no currency on either side can be changed at all, and only then may either party accept. That is what removes the last-minute switch as a category rather than as a race — there is no instant at which one player is reading a table the other can still edit. Changing your mind means revoking your confirmation first, which unlocks the table and clears both acceptances, in full view of the other player.

THE INVARIANT: every change to either offer clears both confirmations and both acceptances, and bumps Version. There is no way to alter what is on the table that leaves consent of either kind standing. TryConfirm(long, bool, uint) and TryAccept(long, bool, uint) both refuse a request that quotes any version but the current one, so a click that was in flight while the table changed lands as a no-op rather than as consent to something the player never saw.

Constructors

TradeSession(long, long, long, int)

public TradeSession(long id, long firstCharacterID, long secondCharacterID, int maxOfferSlots)

Parameters

id long
firstCharacterID long
secondCharacterID long
maxOfferSlots int

Fields

Commit

The in-flight commit, or null.

public TradeSession.CommitState Commit

Field Value

TradeSession.CommitState

First

public readonly TradeSession.Party First

Field Value

TradeSession.Party

ID

Process-unique session number, for log lines.

public readonly long ID

Field Value

long

MaxOfferSlots

The most slots one side may offer, fixed at creation from the system asset.

public readonly int MaxOfferSlots

Field Value

int

NextRangeCheckTime

Server time of the next range check. Owned by the system's tick.

public double NextRangeCheckTime

Field Value

double

Second

public readonly TradeSession.Party Second

Field Value

TradeSession.Party

Properties

BothAccepted

True when both sides have accepted the frozen table.

public bool BothAccepted { get; }

Property Value

bool

IsLocked

True when both sides have confirmed their offers: the table is frozen and the only things either party may do are accept, revoke, or cancel.

public bool IsLocked { get; }

Property Value

bool

Phase

public TradePhase Phase { get; }

Property Value

TradePhase

Version

Increments on every change to either side. Quoted back by accepts.

public uint Version { get; }

Property Value

uint

Remarks

Starts at 1 so a zeroed TradeAcceptBroadcast — one a client never filled in — can never match.

Methods

BuildStateFor(long)

The state message for characterID's side of the table.

public TradeStateBroadcast BuildStateFor(long characterID)

Parameters

characterID long

Returns

TradeStateBroadcast

Close()

Ends the session. Idempotent.

public void Close()

Involves(long)

True when the character is one of the two parties.

public bool Involves(long characterID)

Parameters

characterID long

Returns

bool

PartnerOf(long)

The side that is NOT characterID, or null when they are not a party.

public TradeSession.Party PartnerOf(long characterID)

Parameters

characterID long

Returns

TradeSession.Party

PartyOf(long)

The side belonging to characterID, or null.

public TradeSession.Party PartyOf(long characterID)

Parameters

characterID long

Returns

TradeSession.Party

TryAccept(long, bool, uint)

Accepts, or withdraws acceptance of, the frozen table as it stands at version.

public TradeOfferRefusal TryAccept(long characterID, bool accept, uint version)

Parameters

characterID long
accept bool
version uint

Returns

TradeOfferRefusal

Remarks

Stage two of two, and only reachable while IsLocked: there is nothing to accept until both sides have declared their offers final. The version quote is kept even though the table cannot change while locked, because an accept sent before a revoke-change-relock cycle would otherwise arrive as consent to a table the player never saw.

Withdrawing never fails on version: a player taking consent back must always be able to, whatever they were looking at. Only granting it is gated.

TryAddOffer(long, TradeOffer)

Puts an item on the table for characterID.

public TradeOfferRefusal TryAddOffer(long characterID, TradeOffer offer)

Parameters

characterID long
offer TradeOffer

Returns

TradeOfferRefusal

TryBeginCommit()

Moves an open session into Committing.

public bool TryBeginCommit()

Returns

bool

False unless the session was open, locked, and both sides had accepted.

TryConfirm(long, bool, uint)

Confirms, or revokes the confirmation of, this side's offer as final at version.

public TradeOfferRefusal TryConfirm(long characterID, bool confirm, uint version)

Parameters

characterID long
confirm bool
version uint

Returns

TradeOfferRefusal

Remarks

Stage one of two. Once BOTH sides have confirmed the table is locked and nothing on it can change; that is what makes the accept that follows a decision about a settled table rather than a race against the other player's next click.

Revoking clears both acceptances. An acceptance is consent to a frozen table, and a revocation unfreezes it — so consent given on that basis cannot survive, on either side. The other party's CONFIRMATION is left standing: they have not changed their mind about their own offer, and making them re-click for someone else's revocation is noise. Any actual change to the table clears everything, as ever.

Revoking never fails on version, for the same reason withdrawing an acceptance does not: taking consent back must always be possible, whatever the player was looking at.

TryRemoveOffer(long, int, out TradeOffer)

Takes the offer made from slot back off the table.

public TradeOfferRefusal TryRemoveOffer(long characterID, int slot, out TradeOffer removed)

Parameters

characterID long
slot int
removed TradeOffer

Returns

TradeOfferRefusal

TrySetCurrency(long, long)

Sets the currency on the table for characterID.

public TradeOfferRefusal TrySetCurrency(long characterID, long amount)

Parameters

characterID long
amount long

Returns

TradeOfferRefusal

Remarks

Setting the same amount again is still a change: it bumps the version and clears acceptances. A client that re-sends its own value has told the server "I changed something", and the cost of honouring that literally is one extra round of accepts — far cheaper than a rule that lets some writes through without clearing consent.