Skip to content

Economy – Model

This folder contains the value types, enums, and shared helpers that form the foundation of the Economy subsystem.
These types are public and stable — safe to depend on in gameplay code, UI, analytics, tests, and integrations.

They contain minimal shared logic (e.g., result helpers and canonical sourceId building), plus data contracts shared across all economy flows.


Value types


ChargeLine

Represents a single money line.

  • Fields: (currencyId, amount)
  • id is trimmed and normalised to lowercase.
  • Validity is expressed via IsValid (id non-empty and amount > 0).
  • Used in PriceBundle.money.

ChargeLine normalizes id casing on construction to keep identifiers consistent.


ItemLine

Represents a single item line.

  • Fields: (guid, quantity)
  • guid is typically an ItemDefinition GUID or item key.
  • Validity is expressed via IsValid (guid non-empty and quantity > 0).
  • Used in PriceBundle.items.

PriceBundle

Bundle of optional money and/or item lines.

  • Structure:
  • IReadOnlyList<ChargeLine> money
  • IReadOnlyList<ItemLine> items
  • Helper factory methods:
  • MoneyOnly(moneyLines)
  • ItemsOnly(itemLines)
  • Used for all economy flows (shop, reward, crafting, sell, etc.).
  • PriceBundle does not clone or freeze the provided lists; callers must treat list contents as read-only by contract.

A PriceBundle may contain:

  • Money only
  • Items only
  • Both money and items

Results


EcoOpResult

Represents the outcome of an economy operation.

Fields

  • Successbool
  • CodeEcoOpCode
  • Message — optional string

Features

  • Factory helpers:
  • Ok()
  • Fail()
  • InvalidArgs()
  • ServiceMissing()
  • NoSpace()
  • …and others
  • Deconstruction support:
    var (ok, code, message) = result;
    
  • No implicit bool conversion:
    if (result.Success) { /* success */ }
    // or:
    if (result.IsOk) { /* success */ }
    
  • Equality and hashing support

Use EcoOpResult for all branching logic — Economy never throws for normal failure paths.


EcoOpCode

Standardised result codes shared across all Economy services.

  • Ok
  • InvalidArgs
  • ServiceMissing
  • ContainerMissing
  • ResolverMissing
  • InsufficientFunds
  • NoSpace
  • NotOwned
  • PolicyBlocked
  • Overflow
  • EscrowUnavailable
  • UnknownError

These codes unify behaviour across:

  • Currency-backed ledgers
  • Inventory-backed item stores
  • Shop, Crafting, and Reward services

EcoOpResultComparers

Reusable comparers for EcoOpResult.

  • ByCode — compares only Success and Code, ignoring Message.

Useful for:

  • Unit tests
  • Dictionaries / sets
  • Deduplicating results where text is not relevant

Reasons & sources


EcoReasons

Canonical reason strings used for telemetry and auditing.

Reason groups include:

  • Economy / Money
  • EconomyPay
  • EconomyGrant
  • EconomyPayRollback
  • EconomyGrantRollback

  • Shop

  • ShopBuy
  • ShopSell
  • ShopRefund
  • Rollback variants

  • Crafting

  • Craft
  • CraftRefund
  • CraftRollbackItems

  • Rewards

  • Reward

Using canonical reasons prevents analytics fragmentation.


EcoSource

Builder for canonical sourceId strings.

  • Combines vendor and request identifiers:
  • (vendor: "VendorA", request: "abc") → "VendorA|rid:abc"
  • Sanitises delimiters and trims whitespace.
  • Applies length caps to keep analytics keys bounded.
  • Used by currency operations that support correlation.

Validation & policies


DebitValidationMode

Controls validation behaviour when computing effective debits under a policy.

  • Strict — invalid lines cause immediate failure.
  • SkipInvalid — invalid lines are ignored (appropriate for previews / UI).

Note: DebitValidationMode is an internal implementation detail used by built-in policy computation.


LedgerPreflightMode

Controls UX preflight behaviour for IValueLedger.CanPay().

  • Strict — UI disables when policy would adjust the nominal debit.
  • PolicyApproved — UI enables when policy approves and the wallet covers the effective debit.

This affects UX only.
Authoritative mutations always go through Pay() / Grant().


Usage guidelines

  • Use PriceBundle to represent all costs, payouts, and recipes.
  • Inspect EcoOpResult for branching in gameplay logic.
  • Pass canonical reason and sourceId values for consistent telemetry.
  • Use EcoOpResultComparers.ByCode when messages are not relevant.

Stability

  • All public types in this folder are stable and safe to depend on.
  • Behaviour is consistent across minor versions.
  • New result codes or helpers may be added, but existing semantics are preserved.

See Also