Fighting Game · Features

Community, Store, Support & AI Services

A focused page within the Fighting Game Features documentation. The full map and every sibling page live in the Features hub.

7sections13 minread1diagram

On this page
mindmap root((Around the V2 match)) Community Editorial and moderated galleries Clubs events and sharing Reports blocks and appeals Commerce Region-aware pricing Entitlements refunds and receipts Store and progression boundaries Support Account recovery and tickets Ambassadors and Hall of Fame Audit-safe operator actions Broadcast AI Commentary and translation Captions and moderation Caster face and lip sync Never influences rollback

All four clusters are deliberately off the rollback simulation. They consume versioned match or account evidence and produce governed external effects, but cannot perturb deterministic combat truth.

Everything on this page happens around the match, never inside it. When a fight ends, V2 hands the moment off to a ring of out-of-match surfaces: the community team's editorial picks and moderated galleries, the per-platform storefront that prices a cosmetic differently in São Paulo than in San Jose, the support desk that triages a lost-account ticket, and — the most architecturally interesting cluster — the AI services that turn a recorded set into a produced broadcast with live commentary, translated chat, captions, and a lip-synced caster face. The throughline is a hard line: every one of these surfaces is off-rollback. None of them can perturb the deterministic combat simulation, and the code says so out loud, with mayInfluenceRollback: false and rollbackPolicy fields stamped on each service's output.

The shape of what ships matters here, because this group spans the full implemented-to-spec spectrum. The web surfaces are versioned JSON data contracts, not React apps. The store's region-aware pricing is genuinely implemented math in two separate engines. The AI services are real orchestration bridges whose generative core is an honest provider-gated seam. And the moderation underneath the galleries composes the shared Kuanyin/Themis trust-and-safety plane that governs every Oshun product. This is the feature-side companion to the "Online, Esports & Live Service" group; the section hub is ../V2_features.md.

What ships, honestly#

  • The web surfaces are real but data-shaped. apps/v2/web/community, apps/v2/web/hub, and apps/v2/web/support are not standalone apps — each is a single schema-versioned JSON document (community.jsonv2.web.community.v1, hub.jsonv2.webHub.v1, support.jsonv2.web.support.v1) that the shared Oshun shell renders. They are the shipped data contract: Player of the Week, the gallery roster, support SLA tiers, the ambassador languages, and the Hall of Fame inductees are all concrete fields, not lorem ipsum.
  • The store math is implemented twice, for two economies. Real-money region-aware pricing (PPP) is a real function, calculateV2MaatFinanceRegionalPriceMinor in @maat/finance, bridged into V2 by @v2/maat-finance-ledger. The in-game soft-currency economy is a separate, fully-implemented C++ engine, UV2PriceTableLibrary in V2/ue/Source/V2Gameplay/Private/V2PriceTable.cpp. Both carry validators and contract specs.
  • The AI services are real bridges with a provider-gated core. iris-commentary-orchestration, iris-realtime-translation, iris-accessibility, isis-commentary-lipsync-pipeline, psyche-commentary-face-animation, psyche-caption-streaming, euterpe-commentary-ducking, calliope-commentator-personas, and psyche-ai-director-hints all exist under apps/v2/ with real orchestration, latency budgeting, and fallback logic. What is provider-gated is the generation itself — the commentary text, the synthesized voice, the animated face — produced by the shared Iris/Isis/Psyche/Euterpe substrates those bridges call, exactly the fail-loud-when-unconfigured seam the platform uses everywhere.
  • What is plan, not artifact: the editorial spotlights, the specific brand partners, the newsletter copy. Those are authored/scheduled content the services carry, honestly a roadmap and not engine code.

The architecture-side treatment of these same surfaces lives in two companions: ../architecture/live-ops-store-progression-and-community.md (store, economy, community governance) and ../architecture/esports-companion-and-ai-services.md (the AI broadcast chain). This page stays on the feature surface and dips into code only where a claim needs backing.

Community surfaces#

The web data contracts#

apps/v2/web/community/community.json is the seed for the out-of-game community page, and its fields map one-to-one onto the source feature list. featured carries the three editorial picks — player (Player of the Week), crew (Crew of the Month), and replay (Replay of the Week) — each with a reward flair id like Flair.PlayerOfTheWeek.2026W22, so the "featured account gets a flair cosmetic" promise is a concrete grant token, not prose. apps/v2/web/hub/hub.json is the account-bound player hub: rank, Crown balance, Battle-Pass tier, faction, a friends panel, a wishlist, a leaderboard slice, public replays, a moderated gallery strip, two server-validated web micro-games (Web Frame Quiz, Web Replay Scout), and a news feed whose items are tagged confirmed | planned | exploratory — the same roadmap-honesty taxonomy the roadmap surface uses.

Editorial spotlights, galleries & moderation#

Each gallery entry in community.json carries the fields that make a community gallery safe to ship: a creator, a creatorCode (the creator-attribution code that also applies at store checkout), moderation: "approved", consent: true, and a source (Community Art Gallery, PhotoModeCloud, TournamentArchive). Those two booleans are load-bearing — nothing surfaces in the gallery until it has passed moderation and carries explicit consent.

The moderation pipeline the relationships/creator page defers to lives here, and it is governed rather than ad-hoc. @v2/kuanyin-first-line-moderation is the primary moderation path — its README is explicit that it replaces Two Hat, Community Sift, Hive AI, and AWS Rekognition with @kuanyin/precognition and @kuanyin/foundation as the first-line filter. Public UGC accept-gating (custom championships, decals, logos, music swaps) runs through @v2/themis-originality-shields, which composes the full Themis originality family — @themis/music-shield, @themis/visual-shield, @themis/text-shield, @themis/video-shield, and @themis/design-shield — so an uploaded decal is checked for visual originality and an uploaded soundtrack swap for music-rights collision before it can appear. Crew/faction governance (rule votes, member reputation, constitution amendments) composes @themis/community through @v2/themis-community-governance, and community-health signals (temperature scoring, raid detection, new-user throttles) run through @v2/kuanyin-community-harmony. Because all of this resolves through the same audited Themis/Kuanyin path, a community ban and a match-conduct ban are the same appealable action.

Newsletter, meetups, Discord & journals#

The newsletter block lists eight serviced regions (NA, EU, JP, KR, LATAM, SEA, India, MENA) and a fixed recap shape (patch highlights, new content, tournament results, community moments, roadmap teaser). meetups are opt-in and privacy-first: each entry carries a locationLabel, a subscribable .ics feed, and noPii: true, so the discovery map never leaks an account's location. discord enumerates the eight per-region staffed servers, and journalPrompts seeds the per-account public journal (moderated on the same pipeline as gallery submissions). Photo-mode tournament submissions and community/jury voting are a separate bridge, @v2/photo-mode-tournament-voting-bridge (§133), which emits a v2.photo-mode-tournament-voting-manifest consumed by V2PhotoMode, V2ReplayTheater, V2CommunityHub, and V2CompanionApp.

Store & region-aware pricing (PPP)#

V2 runs two distinct price engines, and conflating them is the easy mistake. One prices real money (the cosmetic/DLC storefront); the other prices in-game soft currency (the Koin/Crown vendor economy). Both are implemented; they live in different languages and answer to different rules.

Real-money pricing: the PPP ledger#

Real-money region-aware pricing is calculateV2MaatFinanceRegionalPriceMinor in libs/maat/finance/src/v2-persistence-ledger.ts, bridged into V2 by buildV2MaatFinanceLedgerSurface in apps/v2/maat-finance-ledger/src/maat-finance-ledger.ts. The policy struct V2MaatFinanceRegionalPricingPolicy carries a baselinePriceMinor, a pppRatioBasisPoints, a priceFloorRatioBasisPoints, and a priceCeilingMinor, and the function is exactly the "ratio, floored, ceilinged" rule the source describes:

text
ratioPrice = round(baselinePriceMinor × pppRatioBasisPoints / 10_000)
floorPrice = round(baselinePriceMinor × priceFloorRatioBasisPoints / 10_000)
regionalPrice = min(priceCeilingMinor, max(floorPrice, ratioPrice))

The contract spec pins this with a worked policy — pppRatioBasisPoints: 6500 (a 0.65 purchasing-power ratio), priceFloorRatioBasisPoints: 4000 (the ratio × 0.4 floor that blocks inversion attacks, straight from the source), and a priceCeilingMinor that caps the regional price at baseline. The same function is reused inside buildV2MaatFinanceLedgerDecision, which is the spend gate: a spend transaction is rejected with reason region-price-mismatch if the client's unitPriceMinor does not equal the freshly-computed regional price (so a VPN-spoofed or stale price cannot transact), and with regulatory-cap-exceeded if it breaches regulatoryTransactionCapMinor or the running regulatoryDailySpendCapMinor — and minor accounts get a stricter minorDailySpendCapMinor. Refunds require a refundReferenceId and fall inside refundWindowDays, or they fail refund-reference-required / refund-window-expired. The whole decision is offline-tolerant: it can approve against an in-engine ledger cache (approved-offline-cache) and reconcile on the next online sync, which is why support.json's refund ticket shows a "Maat finance review queued" history line.

In-game economy: the C++ price table#

The soft-currency vendor economy is UV2PriceTableLibrary::QuotePriceTable in V2/ue/Source/V2Gameplay/Private/V2PriceTable.cpp — a real BlueprintPure resolver, not a lookup. A quote resolves a base price for the Buy/Sell kind, then applies a regional override (FV2PriceTableRegionalOverride can override the buy price, the sell price, or apply a RegionalMultiplier), then optional dynamic pricing that multiplies the entry's Demand × Supply × Event factors against the request's, clamps the result to the entry's Min/Max bounds, and finally scales by quantity. Every stage records an itemized FV2PriceTableIssue (RegionalOverrideApplied, DynamicPriceApplied, PriceEntryResolved) so a quote is auditable. ValidatePriceTable is the gate that keeps the catalogue honest — it rejects duplicate price-entry ids, duplicate item|currency pairs, currencies absent from the catalogue, non-positive prices, a sell price exceeding the buy price, and multipliers outside (0, 10], each as a blocking issue with a FailureTag. This is the engine behind the persistent-world economy and the Krypt/vendor shops, and it is fully separate from the real-money ledger above — nothing it prices touches a payment rail.

The per-platform storefront#

Real-money purchases route through each platform's native store. hub.json's commerce block is the surfaced contract: allowed, a region (e.g. US), platformPaymentRulesPermit: true, and a refundPolicy pointer (V2.86.5). The platform store is the exclusive path for any item that grants gameplay state on that platform; the non-item flows (coaching marketplace, donations, esports prize pools) are the TRC-permitted exceptions that route through Stripe/Adyen, and they are kept ledger-separate from earned currency for store-compliance reasons. Premium currency (Crowns) buys transparent items — no real-money loot boxes — under the daily spend caps the ledger enforces.

Customer support, ambassadors & Hall of Fame#

apps/v2/web/support/support.json is the support contract, and its priorityTiers are the SLA spine: critical (lost account / refund dispute / harassment) at 1h first response / 24h resolution under 24/7 coverage, high (ban appeal / cheat report / payment failed) at 8h/72h, normal (cosmetic loss / UI bug) at 48h/14d, and low (feature request) at 7d. regions pins per-region hours and locale coverage (eight regions, from en-US/es-MX in NA to ar-SA/en-AE in MENA); knowledgeBase ships real KB articles (account recovery, platform refunds, harassment escalation, rollback-quality troubleshooting); ambassadors declares the vetted program (eight regions, ten languages, a quarterly-review term, an Community Ambassador flair); coaches carries the certified-coach roster with per-coach ratings; and hallOfFame enumerates the inducted champions, record-holders, and community legends. The live ticket list (tickets) demonstrates the routing — SUP-1025's history shows a refund dispute handed to "Maat finance review," closing the loop back to the PPP ledger.

Support does not stand alone: when an outage or mispriced item harms players, @v2/player-compensation-service issues incident-scoped, evidence-backed, approval-gated make-goods; @v2/patch-notes-service publishes the structured, required-category change record that pairs with each balance hotfix; and @v2/message-of-the-day-service pushes announcements (events, downtime, patch notes) to the shipped client without a patch, with per-account dismissal — the same dismissal keys community.json's announcements block carries.

AI services: a produced broadcast#

This is V2's integration showcase. A match can be cast by AI in real time, and the pipeline is a chain of thin apps/v2/ bridges over shared Oshun substrates — V2 supplies fighting-game context and consumes a produced broadcast. The unifying invariant is the rollback boundary.

The off-rollback boundary#

Every AI service stamps its output as gameplay-inert. The commentary plan's rollbackBoundary literally sets gameplayInertOutput: true, feedsSimulationState: false, allowedOutputChannels: ['audio', 'subtitle'], and rejectsRollbackFrameOrigin: true; requestV2AICommentaryCue in apps/v2/iris-commentary-orchestration/src/v2-ai-commentary.ts validates that a cue is never called from inside a rollback frame (fromRollbackFrame is a hard rejection). The translation, caption, lip-sync, face-animation, and ducking bridges each carry the matching mayInfluenceRollback: false / off-rollback-* policy. The one AI service that does touch the deterministic path, @v2/psyche-ai-director-hints, does it safely: in rollback-with-CPU modes it samples a tendency vector at match load, serializes tendency-vector + seed into the match-start input vector, and then runs rollback-deterministically with no further RPCs — mid-match Psyche updates are queued for the next match start.

Real-time commentary#

requestV2AICommentaryCue composes createMatchCommentaryStream from @iris/conversation-orchestration in off-rollback-only determinism mode. The headline number is a 800 ms KO-trigger latency budget (V2_AI_COMMENTARY_KO_TRIGGER_LATENCY_BUDGET_MS = 800), and buildV2AICommentaryLatencyBudget splits it across the Iris LLM round trip (420 ms), persona TTS render (240 ms), Psyche lip-sync render (100 ms), and a 40 ms safety margin — and the validator refuses a request whose sub-budgets don't fit inside the total. When the envelope is missed, the client falls back to a pre-recorded bank line keyed by the deterministic tuple (cueKind, ruleset, commentatorId, seed), so a slow generation never leaves dead air. Streams are scoped local-peer | host-peer-canonical | broadcast-canonical. The commentator roster itself is validated by @v2/calliope-commentator-personas, which loads commentator-personas.json and verifies every persona has cleared @iris/voice clone metadata, signed talent approval, brand metadata, and deterministic fallback-bank metadata before exposing the Iris commentator ids the orchestrator uses.

Post-match experience#

buildV2AIPostMatchExperiencePlan (section 135) assembles the after-match surface. The highlight reel is a real selection: candidates are sorted by score descending (ties broken by earliest frame) and the top five taken, the plan requiring all five moment kinds — longest-combo, counter-hit-punish, power-play, dramatic-comeback, ko — and emitting mp4, gif, and vertical-9:16 share formats with trim/filter/music/caption controls. The analysis screen pins six panels (damage-by-move, combo breakdown, meter usage, corner-pressure win rate, mistake-frame timeline, matchup-specific advice) plus a rolling 10-match strength/weakness summary, and the auto-clip library tags an AI-suggested caption and title. Every output carries the compliance block: machineGeneratedLabel: true, a per-output opt-out, an EU AI Act cross-reference (80.4), and manualTrainingDataReview: true — and post-launch procedural fighter dialogue is flagged manualReviewRequired / signedOffBeforeDeployment, so generation accelerates authoring but never ships an unreviewed line.

Translation, captions, face & mix#

The rest of the chain makes the broadcast multilingual and accessible. buildV2IrisRealtimeTranslationSession (@v2/iris-realtime-translation) composes @iris/voice to translate spectator chat and commentary across four surfaces (spectator-chat, commentary-localization, broadcast-overlay, companion second-screen), registering per-locale receiver participants and reporting per-delivery success/fail counts with honest reason codes when a provider returns failures. @v2/iris-accessibility owns the accessibility semantics and, until Iris owns live captions end to end, drives the real-time caption engine through @psyche/caption-streaming (bottom-center, low-latency, speaker-aware). @v2/isis-commentary-lipsync-pipeline (composing @isis/visual-dubbing) and @v2/psyche-commentary-face-animation (composing @psyche/avatar-lipsync + @psyche/avatar-expressions) turn commentary audio into a lip-synced, ARKit-curved caster face, and @v2/euterpe-commentary-ducking (composing @euterpe/accompany + @euterpe/master) sidechains the music bus so the VO sits properly in the mix. Each of these is independently droppable — if the face-animation provider is absent, the audio/subtitle cue still ships.

How it connects#

These surfaces are the connective tissue between the fight and the player's life around it. The galleries moderate and sell the cosmetics, CAWs, and arenas authored in ./relationships-progression-and-creator-suite.md; the storefront's PPP ledger and the battle-pass/DLC economy are two halves of one monetization story, the other half of which — seasons, the battle pass, Twitch drops, and the read-only companion app — lives in ./live-service-dlc-battle-pass-and-companion.md. The AI broadcast chain feeds the esports/spectator surfaces and the director-cam, and its full substrate topology (Iris/Isis/Psyche/Euterpe/Nous) is the subject of the architecture companion ../architecture/esports-companion-and-ai-services.md, while the store, economy, and community-governance plumbing is detailed in ../architecture/live-ops-store-progression-and-community.md. The one constant across all of it: off-rollback, gameplay-inert, audited. The section hub is ../V2_features.md.