V4 has to sound, spark, cut, and read like six games at once: the brassy
bombast of a CoD set-piece, the sparse noir pulse of a Splinter Cell
infiltration, the erhu-and-orchestra swell of a Wukong boss, the diegetic
strings of a Commandos op, the modular sci-fi of an RTS skirmish, and the
synth-rock of a Contra run — all emitted by one shared presentation stack. Four
Unreal C++ modules own that job: V4Audio (MetaSounds patches, dynamic
music stacks, voice barks, foley, spatialization, the karaoke rhythm mode),
V4VFX (Niagara muzzle flashes, blood decals, debris, weather, Wukong
combat auras), V4Cinematics (Sequencer-driven
openers/boss-intros/finishers, the slow-mo "showdown" governor, Movie Render
Queue profiles, director commentary), and V4UI (the CommonUI/MVVM
front-end shell, six per-cell HUDs, the stealth light-gauge widget, and the full
accessibility contract). Where the combat and netcode layers must be provably
correct (./networking-determinism.md), this
layer has the inverse remit: it is cosmetic, it may be as expensive as the
platform budget allows, and its only hard rule is that it must never feed back
into the integer state the lockstep and rollback paths hash.
What actually lives in the repo is the decision, policy, and validation
layer for that stack — built as four UGameInstanceSubsystems plus a handful
of components and view-models, every one of which compiles and is exercised by
automation — sitting above a set of engine plugins that are linked but, with
two honest exceptions, not yet called, and above authored content that ships
today as JSON descriptors rather than binary .uasset. This page is part of the
Presentation, Production & Launch group; the section hub is
../V4_ARCHITECTURE.md.
What ships, honestly#
The four modules are real, deterministic C++ that builds and is tested, but they are a specification-and-decision layer, not a wired audiovisual runtime. Six qualifications so the rest of the page reads at face value:
-
The modules link the real presentation plugins.
V4Audio.Build.cs:12-19addsMetasoundEngine,AudioModulation, andAudioGameplayVolume;V4VFX.Build.cs:12-16addsNiagara;V4Cinematics.Build.cs:12-23addsMovieScene,MovieRenderPipelineCore, andSequencer(editor-only); andV4UI.Build.cs:12-21addsUMG,CommonUI,ModelViewViewModel, andFieldNotification. Linking is not calling. -
Only two of the four modules touch an engine runtime at all — and modestly.
V4AudiocallsIPluginManager::Get().FindPlugin(...)to probe whether a spatialization plugin is installed (V4AudioBootstrapSubsystem.cpp:7), andV4UI's HUD view-model callsUMVVMViewModelBase::BroadcastFieldValueChanged(V4HUDViewModel.cpp:94). NeitherV4VFXnorV4Cinematicsinvokes its plugin at all: there is noUNiagaraFunctionLibrary::SpawnSystem*, noULevelSequencePlayer, and noSetGlobalTimeDilationanywhere in their source. They are bookkeepers and state machines, not spawners. -
There are zero binary
.uassetpresentation assets.V4/ue/Contentholds no.uassetat all; the presentation content directories ship 102*.uasset.v4asset.jsondescriptors instead — MetaSounds patches, Niagara systems, level sequences, loading-screen libraries, data assets — none of which a soft-object path resolves to yet. The cue, patch, and sequence soft paths the C++ builds (/Game/V4VFX/Niagara/...,/Game/V4Audio/MetaSounds/...,/Game/V4Cinematics/...) name content that is specified but not authored. -
The dispatchers do real policy, not real emission. The VFX spawner enforces per-LOD budgets and cooldowns and tracks active counts; it does not put a particle on screen. The cinematic subsystem advances a playhead and flips a state enum; it does not drive a Sequencer. The slow-mo subsystem computes an
EffectiveTimeDilationcurve; it does not slow the world. The gate is the product here — the engine hand-off is the pending integration. -
The decision math is genuine and value-tested. Footstep attenuation, spatial occlusion gain, decibel ducking, rhythm-timing judgement, slow-mo blends, and MVVM change-notification are real algorithms asserted against specific computed numbers across 16 automation specs under
V4Tests/Private/{V4AudioTests,V4VFXTests,V4CinematicsTests,V4UITests,V4AccessibilityTests}. They would fail against a hardcoded return. -
Authored data sidecars are real and locked.
V4/ui/launch-experience/launch-experience.jsonand the sixV4/cinematics/*.jsoncommentary manifests (2,148 lines) are schema-versioned feature contracts with owners and QA-coverage lists — design data, not code, and honestly labeled as such.
Everything below is real where it cites a function and a line; where it names an authored asset or an un-called plugin, that is the specified-but-pending part.
The shared shape: four subsystems, one discipline#
All four modules are built the same way and for the same reason. Each is a
UGameInstanceSubsystem (or, for V4UI, a small family of subsystems plus a
view-model and widget) that holds registered catalogs in TMaps and exposes
three kinds of entry point: Build…/Default… factories that emit launch
manifests, Validate… self-checks that fail loud with a TArray<FString> of
errors, and Resolve…/Dispatch…/Judge… decisions that are pure functions of
their inputs. That split lets every rule be unit-tested without a live world and
keeps the math side-effect-free, so the same call yields the same answer on
every machine — the same determinism hygiene the gameplay core demands, applied
to the cosmetic layer.
The dashed edges are the boundary: two are real engine-runtime touches, the rest are soft references awaiting authored content and a spawn/playback call site.
Audio — V4Audio#
Runtime mixers: music, barks, foley, spatial#
Four small subsystems and a component do the live audio decisions, each with its own automation spec.
Dynamic music stacks. UV4MusicStackSubsystem holds a per-cell stack of
FV4MusicLayers and resolves a blend target by summing the active layers'
volumes and clamping to unity: GetCellTargetVolume
(V4MusicStackSubsystem.cpp:43) returns
FMath::Clamp(Σ active TargetVolume, 0, 1). Toggling a layer (SetLayerActive)
is how a cell transitions combat-to-ambient without restarting the bed
(V4.Audio.MusicStack.Layering).
Voice barks with cooldown. UV4VoiceBarkSubsystem::DispatchBark
(V4VoiceBarkSubsystem.cpp:14) keys barks Operator.Bark, and refuses a
dispatch when CurrentTime − LastDispatch < CooldownSeconds — a genuine
per-line rate limiter, not a coin-flip (V4.Audio.VoiceBark.DispatchCooldown).
Stance-aware foley. UV4FoleyComponent::ResolveFootstepVolume
(V4FoleyComponent.cpp:21) multiplies a per-surface volume by a stance
multiplier — Prone 0.25, Crouch 0.55, Sprint 1.25, Stand 1.0
(:41-55) — and by a speed ratio clamped to [0.2, 1.5], then clamps the
product to [0, 2]. This is the audible side of the stealth sound-footprint
(./ai-perception-stealth.md): crouching is quiet,
sprinting is loud (V4.Audio.Foley.StanceAndSurface).
Spatial attenuation. UV4SpatialAudioBridge::ResolveAttenuatedGain
(V4SpatialAudioBridge.cpp:51) computes a linear-falloff distance gain
clamp(1 − dist/radius, 0, 1) times an occlusion gain 1 − occlusion. It is a
real, testable attenuation model that runs without any audio device
(V4.Audio.SpatialBridge.AttenuationAndOcclusion).
The bootstrap subsystem: manifests, ducking, providers, rhythm#
UV4AudioBootstrapSubsystem (788 lines) is the catalog and policy hub. It
builds the launch manifest the audio team commits to — 110 weapon-foley
patches, 40 operators × 120 bark lines = 4,800 bark patches, 4,942 MetaSound
patches total, 6 music-stack cells, 12 ambience maps, 12 vehicle profiles —
and ValidateLaunchAudioManifest fails if any floor is missed
(V4.Audio.Bootstrap.Patches pins every number).
Three pieces are worth reading as genuine domain logic:
-
Decibel ducking.
ResolveDuckedMix(:370) converts each rule'sDuckAmountDbto a linear multiplier withFMath::Pow(10, min(0, dB)/20)— the correct dB→amplitude law — and applies it to the named target bus, accumulating the applied-rule ids. The default rules duck music −7 dB under voice and SFX −5 dB under a critical callout (:364-367), exactly the "music ducks under VO; SFX ducks under callouts" promise (V4.Audio.Modulation.SnapshotsAndDucking). -
Honest provider probing.
BuildDefaultSpatialProviderProfiles(:426) ties each profile's backing-engine flag to whether the plugin is actually enabled:V4IsPluginEnabled("SteamAudio")andV4IsPluginEnabled("ResonanceAudio")call throughIPluginManager(:7-11). The inline comment is explicit — it sets the flag "instead of asserting it unconditionally." This is a fail-loud capability seam, the opposite of a fabricatedtrue. -
Karaoke rhythm judging.
JudgeRhythmInput(:616) computes the timing offset in milliseconds and returns Perfect (≤45 ms → 1000 pts, combo continues), Good (≤110 ms → 500 pts, combo continues), or Miss, reading the per-note windows. The spec drives an input0.52 sagainst a0.50 sbeat to Perfect,0.59 sto Good/500, and0.70 sto Miss — three outcomes a hardcoded return could not satisfy (V4.Audio.KaraokeRhythmMode).BuildKaraokeRhythmChartsships three original, streaming-cleared charts, andValidateKaraokeRhythmModerejects any chart with fewer than 8 notes, 4 lyric cues, or a missing clearance flag.
VFX — V4VFX#
UV4VFXSpawnerSubsystem is a budget-and-cooldown gate, and that is the
honest description of the whole module: it decides whether a Niagara cue may
play and records that it did, but never calls Niagara. DispatchCue
(V4VFXSpawnerSubsystem.cpp:72) walks four checks in order and returns an
EV4VFXDispatchResult:
- unknown cue →
UnknownCue; - inside the cue's cooldown →
CoolingDown; - at the cue's per-cue
MaxActiveOverride→BudgetExceeded; - at the LOD-bucket budget →
BudgetExceeded; - otherwise increment the active count, append a
FV4VFXDispatchRecord, and returnSpawned.
The LOD buckets carry real defaults — Hero 32, Medium 96, Background 160
active systems (V4VFXSpawnerSubsystem.h:67-74), with per-bucket emitter caps
and tick intervals in BuildDefaultLodBucketPolicies (:250 — Hero allows
dynamic lights and ticks every frame; Background caps at 3 emitters and ticks at
0.1 s). ReleaseCueInstance decrements the count so freeing a slot re-opens the
budget. The launch library is 22 cues across eight Niagara families (muzzle
flash, blood, debris, weather, environment, Wukong combat, RTS projectiles,
arcade sprites), each with a family-tuned cooldown (muzzle flash 0.04 s,
weather 1.0 s). The V4.VFX.Spawner.DispatchCooldownAndResolve spec asserts
the exact Spawned→CoolingDown→Spawned sequence across a cooldown boundary, and
V4.VFX.Spawner.LodBudgets asserts the 32/96/160 budgets, a BudgetExceeded
when a 1-slot hero bucket is full, and recovery after a release. The pending
work is the last inch: turn a Spawned result into a UNiagaraFunctionLibrary
call against an authored system.
Cinematics — V4Cinematics#
UV4CinematicSubsystem models Sequencer playback as a state machine over a
playhead float, not a live ULevelSequencePlayer. PlayCinematic (:159)
returns Started, UnknownCinematic, or AlreadyPlaying; Pause/Resume
gate on the current state; and AdvanceCurrentCinematic (:206) clamps the
playhead to the duration and flips to Finished when it lands — so
Advance(5 s) on a 5-second opener reports Finished with the playhead pinned
at 5.0 (V4.Cinematics.Playback.SequencerDrivenState). The module also emits
the authoring contracts: five Sequencer templates (CampaignOpener,
BossIntro, ARPGFinisher, Takedown, RivalryPostMatch), each with required story
beats; two Movie Render Queue profiles (CoD campaign at 3840×2160 EXR,
marketing trailer at 30 fps ProRes 4444); per-cell camera-language presets; and
nine director commentary tracks gated on campaign completion via
IsDirectorCommentaryUnlocked, which only unlocks when the completed-campaign
list actually contains the campaign id
(V4.Cinematics.Assets.TrackCameraAndTemplateValidation,
V4.Cinematics.DirectorCommentaryExtended).
UV4SlowMoSubsystem is the showdown / death-cam time-dilation governor.
ResolveBlendedDilation (V4SlowMoSubsystem.cpp:63) lerps from 1.0 down to
the clamped target dilation over BlendInSeconds, holds for DurationSeconds,
then lerps back to 1.0 over BlendOutSeconds; TickSlowMo advances the clock
and auto-clears when the total elapses. The dilation is clamped to [0.05, 1.0]
on activation. The honest seam: it produces GetEffectiveTimeDilation() for a
caller to apply, but never calls UGameplayStatics::SetGlobalTimeDilation
itself — the curve is real, the application is the integration point
(V4.Cinematics.SlowMo.BlendLifecycle).
UI / HUD — V4UI#
MVVM: the one real engine-runtime binding#
UV4HUDViewModel is the module's genuine engine touch: it subclasses
UMVVMViewModelBase and, in SetNumericBinding/SetTextBinding, dedupes
(a no-op write returns false and broadcasts nothing) and otherwise calls
BroadcastFieldValueChanged(FFieldId(BindingId, 0))
(V4HUDViewModel.cpp:92-95). That is the "all HUD bindings via MVVM; no direct
attribute access from UMG" rule made concrete — a real
ModelViewViewModel/FieldNotification change-notification, not a stub.
UV4MVVMRegistry complements it with per-screen binding tables and
BuildDefaultHUDBindings (V4MVVMRegistry.cpp:91), which encodes the six
per-cell HUDs verbatim: Tactical-FPS (Health/Ammo/MiniMap/Killfeed), Stealth
(LightGauge/SuspicionRadius/Disguise/Objective), Tactics
(PartyPortraits/CommandQueue/Showdown), ARPG
(HP/Stamina/Will/Posture/CharmSlots/LockOn), RTS
(ResourceTicker/BuildMenu/MiniMap/GroupHotkeys), and Arcade
(Score/Lives/WeaponIcon/BossHealth) (V4.UI.MVVMRegistry.Bindings).
Per-cell HUDs and the stealth bow-tie#
UV4StealthBowTieWidget is a real UUserWidget subclass whose static
BuildPresentation (V4StealthBowTieWidget.cpp:15) maps an
EV4LightExposureState (shared from V4Stealth) to a deterministic
presentation: Dark → dim blue-grey tint, 0.2 wing-fill; Dim → amber
tint, 0.55 wing-fill; Lit → bright tint, full wings, with bPulseAttention
set when lux ≥ 1.0. This is the Splinter Cell light-gauge "bow-tie" read
straight off the stealth gauge — logic and presentation data are real even
though the visual WBP widget is not yet authored. UV4UIBootstrapSubsystem
registers the front-end shell screens and drives focus navigation for
gamepad-vs-mouse routing (V4.UI.Bootstrap.NavigationAndFocus).
Accessibility#
UV4AccessibilitySubsystem builds and validates the full launch accessibility
contract into a UV4AccessibilitySettingsAsset. The substantive parts are real
behavior, not toggles: ShouldApplyAimAssist
(V4AccessibilitySubsystem.cpp:97) refuses aim assist in ranked PvP when
the opt-out flag is set, and ResolveWukongParryWindowFrames widens the parry
window by a configurable bonus — a base of 6 frames plus the default 4 yields
10 frames (:167, asserted exactly). ValidateAccessibilityLaunchCoverage
enforces the floors: subtitle size > 1.0 with a speaker indicator, four
colorblind profiles (Protanopia/Deuteranopia/Tritanopia/Monochrome) each
covering HUD, minimap, and vision-cone overlays, six high-contrast HUDs (one
per cell), audio-cue toggles, two one-handed schemes, and difficulty toggles
that never silently disable achievements (V4.UI.Accessibility.LaunchCoverage).
The V4/ui/launch-experience manifest layers the loading screens, What's-New
modal, toast queue, and companion push on top.
How it connects (and where it does not yet)#
Presentation sits downstream of gameplay and reads, never writes. GAS verbs
and combat events (./gas-layout.md) are what should call
DispatchCue, DispatchBark, PlayCinematic, and ActivateSlowMo; the HUD
view-models read attributes through MVVM and push nothing back. The poses
these effects dress come from the animation pipeline
— the MetaHuman facial-performance and lip-sync flags the animation module
declares are realized here on the audio/VFX side — and the weather, fog, and
debris cues are emitted into the streamed sandbox the
world-streaming & procgen layer manages. The
authored content these modules name — MetaSounds patches, Niagara systems, level
sequences, compiled WBP widgets — is tracked as the *.v4asset.json descriptor
set and belongs to the build-and-content path
(./build-data-content.md).
The honest remaining work is uniform across all four modules and identical in
shape to the animation layer's: the policy, math, and validation are real and
tested; the authored .uasset and the final engine-API call (Niagara spawn,
LevelSequence play, global time-dilation apply, MetaSound playback) are the
pending integration. These are shippable units awaiting a call site and
authored content, not stubs — every decision they make is computed,
deterministic, and pinned to a known-correct value.
Related#
- Animation Pipeline — the poses, MetaHuman faces, and lip-sync this layer dresses with audio and VFX
- World Streaming & Procgen — the streamed sandbox weather, fog, and debris cues are emitted into
- Build, Data & Content — the
*.v4asset.jsondescriptor set and cook path the authored presentation assets flow through - AI Perception & Stealth — the sound-footprint and light-exposure state the foley component and bow-tie widget present
- The section hub: ../V4_ARCHITECTURE.md