V5 is an open-world narrative universe split into cells — an Urban heist city, a
three-era Period crime saga, a Frontier outlaw trail, a Hunter's
monster-contract world, a Sci-Fi galactic theatre, and the cross-cutting Mind
Palace deduction layer — and a universe that big is a service, not a box. It
ships five launch cells and then keeps growing for years: a 90-day season every
quarter, a 100-tier battle pass, weekly cold-case packs, persistent world
events, a whole Steampunk-Detective DLC cell, and a Year-3 roadmap that adds
four sub-cells and a new console SKU. Two pieces of machinery make that
post-launch life real rather than promised. The first is the live-service
calendar service — a NestJS package under apps/v5 that publishes seasonal
rotations, world events, and hot-fix windows over JWT-gated, ETag-cacheable
feeds, mirrored by a family of UV5_Online_* Blueprint builders in the UE
client. The second is the DLC boundary: every cell and mode is a GameFeature
plugin discovered, classified, and build-target-gated by V5Modes, so a new
cell drops in as a content-bearing plugin without forking the engine. This page
explains how both are wired, what is real TypeScript and C++ on disk versus
authored-but-uncooked content, and where the shipped code is honestly thinner
than the architecture prose. The section hub is
../V5_ARCHITECTURE.md.
The design choice underneath everything is the same one the rest of V5 follows,
and it is the same competitive line V2 and V4 drew: nothing sold or seasonal
ever touches gameplay power. Every calendar payload asserts
exclusiveGameplayRewards: false, the battle pass marks gameplay-affecting
rewards never-paid-only, store bundles are cosmetic-only, and the workshop
marketplace sells data-only mods. Live service grows the world; it never sells
an advantage in it.
What ships, honestly#
The split is clean, and stating it up front keeps the rest of the page honest.
The calendar service is real. apps/v5/live-service-calendar/ is a NestJS +
Fastify package (src/main.ts, port 4223) whose controller
(src/controller.ts) exposes five GET routes — /feed, /year1,
/world-events/year1, /pro-stadium-tour, /year3-pipeline — each
requiresJwt: true and regional: true in contract.json, each delegating to
handleRealRequest in the shared @v5/service-shared runtime. A 172-line
contract.test.ts pins the endpoint set, the 21 declared capabilities, the
port, and the exact shape of every feed payload, plus a
success/outage/unauthorized contract-case sweep and a Docker/k8s/failover
artifact check.
The UE client tier is real C++. V5/ue/Source/V5OnlineServices (a 1950-line
V5OnlineServicesSystems.cpp over a 1215-line types header, with an 809-line
test) ships UV5_Online_LiveServiceCalendarClient,
UV5_Online_CrossCellPersistentWorld, UV5_Online_FactionRepClient, and the AI
highlight-reel builders as UBlueprintFunctionLibrary composers that build
season rotations, world-event scripts, the Year-3 pipeline, and the request
envelopes the HTTP client sends.
The DLC machinery is real C++. V5/ue/Source/V5Modes (V5ModeSystems.cpp,
639 lines) classifies, discovers, and build-target-gates GameFeature plugins;
29 V5Mode_*.uplugin descriptors sit under V5/ue/Plugins/, and all 29
declare an enabled GameFeatures dependency.
The economy domains are real. @v5/service-shared's WorkshopDomain
(domain/workshop.ts) is a Postgres-backed UGC marketplace with a moderation
state machine, an ML pre-screen, and an exact-to-the-cent 70/20/5/3/2 revenue
split; FactionRepDomain (domain/faction-rep.ts) is a real exponential-decay
retention model. The store is a transparent Next.js storefront under
apps/v5/web/src/app/store/.
Five honest caveats matter. First, the shipped feed payloads are object
literals. handleRealRequest resolves to evaluateServiceSpecificRule
(runtime.ts:1818), which returns hand-authored constants —
seasonalThemeRotations: 4, scriptCount: 12, stopCount: 6 — not rows read
from a database or parsed from the manifests. Second, a real Postgres calendar
domain exists but is not on that path. LiveServiceCalendarDomain
(domain/live-service-calendar.ts) implements ensureSchema/upsertEvent/
feedEvents/activeEvents and a SHA-256 content-derived etag, but it is
imported only by realtime.ts and a test — the deployed /year1 feed does not
call it. Third, there is no V5/store directory; the only store surface is
the web storefront, which is presentation, not a transactional IAP backend.
Fourth, the content is uncooked: a scan of all 29 plugins finds zero
binary .uasset and 62 JSON stand-ins — V5, like V4, represents assets and
levels as JSON descriptors. Fifth, V5's GameFeature activation is thinner than
V4's. V5Modes ships discovery, classification, a static roster, and
per-target gating; it does not ship V4's UGameFeatureAction subclass that
drives UAssetManager async streaming on activation. The DLC boundary is
real; the runtime asset-streaming seam is a recorded step, not a call.
Live-service architecture: the calendar spine#
Post-launch content reaches players through one service and three representations of the same numbers, kept consistent by tests rather than by a single source of truth. The service is the calendar; the representations are the authored JSON manifests, the NestJS literals, and the UE C++ builders.
V5LiveServiceCalendarController is a thin router: each method stamps a
requestType/feed pair onto the query and calls
V5LiveServiceCalendarService.handle, which builds a ServiceRequest and runs
handleRealRequest(slug, request, now). resolveEndpointPath
(runtime.ts:1233) maps year1-calendar → /v5/live-service-calendar/year1,
year1-world-events → /world-events/year1, and so on, so the response carries
the canonical path back. Every route is JWT-gated and regional, every payload
carries clientCacheEtagRequired: true and orderedWindows: true, and the
failover block declares regional-active-active across iad/fra/sin
primaries with pdx/dublin/syd fallbacks. This is a genuine deployable service
with a genuine contract; what it is not, yet, is a database query —
evaluateServiceSpecificRule returns the authored constants directly, and the
contract test asserts exactly those constants
(calendarId: 'calendar.year1.live-service', seasonalThemeRotations: 4). The
Postgres LiveServiceCalendarDomain is the shape that path is specified to grow
into; today it is real code one wiring step removed from the feed.
Seasons, battle pass & the persistent calendar#
Season One is authored in V5/live-service/season-1-live-service-manifest.json:
Fracture Signals, a 90-day window (2027-03-01 → 2027-05-30) opened by a 30-day
Continuum Signal day-one event. Its battle pass is 100 tiers at a 6–8
hours-per-week target, with an explicit tierSkipPolicy — skips are purchasable
(purchaseEnabled: true, maxSkipsPerSeason: 20) but
gameplayAffectingRewards: "never-paid-only", the monetization line drawn in
the data itself. Reward families are per-cell cosmetics, battle-pass XP, creator
spotlights, and Mind Palace case stamps — never frame data or stats. The
manifest also names its sourceServices (the calendar, faction-rep,
balance-ledger, and workshop contracts), so the design doc points back at the
code that serves it.
The UE side builds the same data in C++. UV5_Online_LiveServiceCalendarClient
(V5OnlineServicesSystems.h:260) exposes BuildYear1Calendar,
BuildYear1SeasonalRotations, BuildYear1SpecialEvents, and the predicate
EvaluateCalendarEventState over constants Year1SeasonDays = 90 and
Year1SeasonCount = 4 (V5OnlineServicesSystems.cpp:20). SeasonalRotation
(:106) computes each season's start as
Year1CalendarStartUtc() + (n-1)·90 days and attaches per-cell themes from
BuildCellThemesForSeason — real date arithmetic, not a flag. The /year1 feed
literal mirrors it: four seasonal-theme rotations plus the Bureau Founding Day
anniversary, the Shelter Signal charity event, and the Platform Circuit console
tie-in, all with gameplayProgressionGated: false.
Persistent world events are their own feed.
BuildYear1PersistentWorldEvents and BuildYear1WorldEventScripts
(V5OnlineServicesSystems.h:311) compose the twelve one-week scripts authored
in year-1-persistent-world-events.json — Gang War Week first — and the
/world-events/year1 literal pins scriptCount: 12,
gangWarWeek: 'world-event.year1.01.gang-war-week',
persistentWorldState: true, settlementSnapshots: 12, and crucially
exclusiveGameplayRewards: false: a player who misses Gang War Week loses no
power, only a moment. The Year-3 pipeline (BuildYear3LiveServicePipeline,
BuildYear3SubCellPlans with a DlcGate per sub-cell,
BuildYear3CrossCellCoopMissionPlans, BuildYear3ConsoleSkuPlan) plans four
sub-cells, eight cross-cell co-op missions
(Year3CrossCellCoopMissionCount = 8, …Minutes = 240), and one
sku.year3.console.switch2-native-complete SKU with a first-party cert track
and reduced-install budgets — a roadmap feed, honestly labelled
contentLock: year-3-planning. Each builder also returns a Get…ManifestPath()
string so the companion app and the /api/public/season-calendar web surface
can resolve the same authored JSON the C++ encodes.
Faction-rep decay, highlight reels & retention#
Retention has real domain logic behind it. FactionRepDomain
(domain/faction-rep.ts) relaxes reputation toward a neutral floor while a
player is inactive: decayedRep(rep0, daysInactive) returns
REP_FLOOR + (rep0 − REP_FLOOR)·exp(−ln2/halfLife · effectiveDays) with
REP_FLOOR = 0, REP_CEILING = 1000, DEFAULT_HALF_LIFE_DAYS = 30, and a
DEFAULT_GRACE_DAYS = 14 window below which nothing decays. The surplus over
the floor halves every 30 idle days; a weekly runDecay(nowUnix) journals every
decrement into an append-only ledger. The file's own header records that this
"replaces the prior simulatedDecay: true" handler — a real de-fabrication,
not a flag pretending to be a model. The
UV5_Online_FactionRepClient::BuildYear1DecayPolicy builder surfaces the same
policy to the client, and year-1-faction-reputation-decay.json authors the
five restoration mission arcs that let a lapsed player climb back. The AI
highlight reel (BuildYear1AIHighlightReel, BuildTop10HighlightClips,
HighlightSignal) ranks replay clips into an optional commentator track; its
manifest id v5.year1.ai-generated-highlight-reel and the
/v5/replays/commentary/tts/year1 route both require synthetic-content
indicators and source-replay verification.
DLC delivery: the GameFeature boundary#
A new cell, a new mode, a new DLC expansion — in V5 these are all the same
thing: a V5Mode_* GameFeature plugin. The boundary is enforced in V5Modes,
and it is real engine-integration C++. IsV5GameFeaturePlugin
(V5ModeSystems.cpp:86) accepts a plugin only if its name starts with V5Mode_
and its descriptor references the engine GameFeatures plugin with
bEnabled — a two-part predicate, not a name match.
DiscoverGameFeaturePlugins (:102) walks IPluginManager's discovered or
enabled plugin set, filters through that predicate, de-duplicates with
AddUnique, and sorts by FNameLexicalLess so discovery is deterministic
across machines. The static roster MakeMode (:41) binds each plugin name to
an EV5Cell, an EV5ModeNetworkModel, a HUD surface, a max-player count, and
dedicated/listen-server flags — the 29 modes spanning every launch cell plus the
Steampunk DLC cell, the editors, and the online/co-op variants.
The DLC cell itself is V5Mode_Steampunk_Detective.uplugin: its descriptor
reads "EnabledByDefault": false, "CanContainContent": true,
"BuiltInInitialFeatureState": "Installed", an enabled GameFeatures
dependency, and the description "Content-bearing GameFeature root for the Brave
New World Steampunk Detective DLC cell." EV5Cell::SteampunkDetective
(V5ModeTypes.h:41) is a first-class cell, and
MakeMode("V5Mode_Steampunk_Detective", …, EV5Cell::Steampunk, …) registers it
alongside the launch roster — so the DLC cell is structurally identical to a
shipped cell, gated off by default until entitled.
What turns the roster into a per-build catalogue is GateKnownMode (:129), a
real build-target predicate over EV5ModeBuildTarget. A DedicatedServer build
enables only bSupportsDedicatedServer rulesets; a LANOffline build refuses
any mode with bRequiresOnlineServices or a CompetitivePvP/SocialLobby net
model; ArcadeCabinet cooks only the curated local co-op roster
(IsArcadeCabinetMode); Editor previews everything non-exclusive. This is the
fail-closed seam between content and platform: a DLC cell that needs online
services will not enable itself in an offline cabinet build. The honest limit,
stated above, is that V5 stops at discovery + gating + a roster. It does not
ship V4's UV4GameFeatureAction_ActivateModeAssets that issues a real
RequestAsyncLoad on activation — and with zero cooked .uasset on disk, the
soft content paths resolve to nothing at runtime. The plugin scaffolding,
dependency wiring, classification, and build-target logic are real and
test-pinned; the streaming activation is a documented gap, not a claimed
feature.
The DLC catalogue the architecture enumerates rides this boundary: 20 weekly
Cold Cases Mind Palace packs (V5Mode_Detective_ColdCases), Frontier bounty and
naturalist drops (V5Mode_Frontier_OutlawTrail), and the full-vision expansion
cells — Polynesian and Pirate Frontier, Egyptian and Cyberpunk-2087 sub-cells,
the Cosmic-Horror Hunter, and the Steampunk Detective cell — each a
plugin-shaped, JSON-manifested content drop owned by its mode, never a binary
client patch.
The store & the workshop marketplace#
The retail store is a transparent web surface, not a dark-pattern funnel.
apps/v5/web/src/app/store/page.tsx and store/[slug]/page.tsx render
storeEntries from lib/publicContent.ts: exactly two entries — the
Continuum Edition base game ($69.99, "all five launch cells and
cross-progression", a nine-platform entitlement map) and the Founders Field
Kit ($19.99, "cosmetic-only … profile frames, camp props, and ship decals",
tagged "No power"). The store copy's stated job is to "separate gameplay access
from cosmetics … without pressure tactics" and keep "balance-affecting rewards
out of paid bundles" — the same player-protective constraint expressed as
content rather than as a checkout flow.
The transactional economy with real backend logic is the workshop
marketplace. WorkshopDomain (domain/workshop.ts) persists UGC items
through a moderation state machine: a publish runs
prescreenRisk(reportCount, flaggedTerms) and moderationFromRisk to set an
initial state, a human moderate call overrides it, and revenueShareSplit
computes an exact-to-the-cent payout from REVENUE_SHARE basis points — 7000
creator (70%), 2000 platform, 500 creator fund, 300 chargeback reserve, 200
tax — with a 48-hour REFUND_WINDOW_HOURS. The marketplace endpoints
(/v5/workshop/marketplace/{listings,purchase,revenue-share,payouts},
runtime.ts:1220) are the paid data-only mod marketplace the architecture flags
as [P3], and they are the closest thing in V5 to a real store ledger — a
creator economy, not a loot box.
The honest line: no pay-to-win, no binary hot-patch#
Two invariants run through every system on this page. No gameplay power is
sold or seasonal-gated. It is asserted in the calendar literals
(exclusiveGameplayRewards: false, gameplayProgressionGated: false), in the
battle-pass manifest (gameplayAffectingRewards: "never-paid-only"), in the
store copy ("No power"), and in the cosmetic-only reward families — the same
hard competitive-integrity line V2's player-protective store and V4's
sim-isolated cosmetics draw. And hot-fixes are data, not binaries. The
architecture's "balance + UI strings via CDN-served data files; no binary patch"
is expressed as the calendar's hotfix-window capability and hotfix-windows
feed, paired with the append-only balance-ledger service whose every entry is
telemetry-evidence-linked. A balance change ships as a calendar-scheduled data
window and a ledgered tuning record, never as a forced client rebuild — which is
also why a DLC cell can be EnabledByDefault: false and simply flip on when
entitled.
Where this connects#
- The backbone underneath:
Persistence, Online Services & Cross-Play
— the 16-service
V5OnlineServicesclient catalog, the@v5/service-sharedNestJS tier, and the Bureau account/XP/cosmetic ledgers that the seasonal calendar, world events, workshop payouts, and faction-rep decay all read from and write to. - The guardrails around it: Accessibility, Security & Compliance — the JWT auth, spend-limit and store-compliance posture, synthetic-content indicators on AI highlight reels, and the moderation/DSAR path behind the workshop marketplace.
- Platform foundations: Oshun Domain Libraries — the shared economy, governance, and content substrates the V5 store, workshop, and live-ops services are specified to compose rather than reinvent.
- The catalogue index for the whole V5 architecture set is ../V5_ARCHITECTURE.md.