15 — Player Metrics Tracker (BPC_PlayerMetricsTracker)
Purpose
Records and exposes player behaviour telemetry throughout a play session. Metrics feed into the adaptive difficulty system, achievement tracking, end-game stats screen, and narrative pacing adjustments. This is a pure data-gathering component — it never blocks or modifies gameplay directly.
Dependencies
- Requires:
GI_GameFramework (session start/end events), DA_GameDifficulty (adaptive thresholds)
- Required By:
BPC_AdaptiveDifficulty (consumes metrics), WBP_StatsScreen (end-game display), GM_CoreGameMode (death/checkpoint metrics)
- Engine/Plugin Requirements:
FTimerHandle for play time tracking
Class Info
| Property |
Value |
| Parent Class |
ActorComponent |
| Class Type |
Blueprint Component |
| Asset Path |
Content/Framework/Player/BPC_PlayerMetricsTracker |
| Implements Interfaces |
I_Persistable (save/load metrics) |
1. Enums
E_MetricEventType
| Value |
Description |
Death = 0 |
Player died |
HideStarted = 1 |
Player entered a hide spot |
HideEnded = 2 |
Player exited a hide spot |
ItemCollected = 3 |
Player picked up an item |
EnemyEncountered = 4 |
Player entered an enemy detection range |
EnemyEvaded = 5 |
Player escaped enemy detection |
StressPeakReached = 6 |
Stress tier exceeded Distressed |
AreaExplored = 7 |
Player entered a new area/chapter |
NarrativeEvent = 8 |
Story beat triggered |
CombatEvent = 9 |
Player used a weapon or was attacked |
2. Structs
S_BehaviourEvent
| Field |
Type |
Description |
Timestamp |
Float |
Game time in seconds when event occurred |
EventType |
E_MetricEventType |
What happened |
ContextTag |
GameplayTag |
Tagged context for filtering |
FloatValue |
Float |
Numeric payload (e.g. distance, intensity) |
StringValue |
String |
Text payload (e.g. location name, enemy ID) |
Location |
Vector |
World location where event occurred |
S_MetricsSnapshot
| Field |
Type |
Description |
TotalPlayTime |
Float |
Total seconds played |
TimesDied |
Integer |
Total deaths this session |
TimesHid |
Integer |
Total hide events |
TotalDistanceWalked |
Float |
Cumulative walking distance (cm) |
TotalDistanceSprinted |
Float |
Cumulative sprinting distance (cm) |
ItemsCollected |
Integer |
Total items picked up |
UniqueItemsCollected |
Set<FName> |
Names of unique items collected |
EnemiesEncountered |
Integer |
Total unique enemy encounters |
EnemiesEvaded |
Integer |
Total successful evasions |
PeakStressTier |
Float |
Highest stress tier reached (as float) |
StressPeakCount |
Integer |
Times stress exceeded Distressed threshold |
NarrativeBeatsCompleted |
Integer |
Story triggers activated |
AreasExplored |
Set<FName> |
Unique areas/chapters visited |
CombatEvents |
Integer |
Total combat interactions |
S_TimeSegment
| Field |
Type |
Description |
SegmentLabel |
String |
Label for this time segment |
StartTime |
Float |
Game time at segment start |
EndTime |
Float |
Game time at segment end |
StressAverage |
Float |
Average stress during segment |
MetricsDelta |
S_MetricsSnapshot |
Metrics accumulated in this segment |
3. Variables
Configuration (Instance Editable, Expose On Spawn)
| Variable |
Type |
Default |
Category |
Description |
bTrackDetailedEvents |
Boolean |
true |
Metrics Config |
If true, store full S_BehaviourEvent history |
MaxEventHistory |
Integer |
5000 |
Metrics Config |
Cap on stored events to prevent memory bloat |
bAutoSaveMetrics |
Boolean |
true |
Metrics Config |
Auto-save metrics via I_Persistable on quit |
SnapshotInterval |
Float |
60.0 |
Metrics Config |
Seconds between automatic snapshot writes |
Computed / Runtime (Public, Blueprint Read Only)
| Variable |
Type |
Default |
Category |
Description |
CurrentSnapshot |
S_MetricsSnapshot |
- |
Runtime Metrics |
Live accumulated metrics this session |
bIsTrackingSession |
Boolean |
false |
Runtime Metrics |
Whether currently in a tracked session |
TimeSegmentHistory |
Array<S_TimeSegment> |
[] |
Runtime Metrics |
Historical segments for analysis |
CurrentSegment |
S_TimeSegment |
- |
Runtime Metrics |
Active time segment |
Internal (Private / Protected, No Expose)
| Variable |
Type |
Default |
Category |
Description |
SessionStartTime |
Float |
0.0 |
Timing |
Game time when session started |
CachedEventHistory |
Array<S_BehaviourEvent> |
[] |
History |
Full event history (if tracking enabled) |
LastPosition |
Vector |
(0,0,0) |
Tracking |
Previous frame position for distance calc |
SnapshotTimerHandle |
FTimerHandle |
- |
Timing |
Timer for automatic snapshots |
Replicated (if multiplayer)
| Variable |
Type |
Condition |
Description |
CurrentSnapshot |
S_MetricsSnapshot |
Replicated |
Synced session metrics |
4. Functions
Public Functions
StartSession → void
- Description: Begins a new metrics tracking session. Resets snapshot.
- Parameters:
| Param |
Type |
Description |
SegmentLabel |
String |
Label for initial segment (e.g. "Chapter 1") |
- Blueprint Authority: Any
- Flow:
- Set SessionStartTime = Current Game Time
- Reset CurrentSnapshot to zero values
- Initialize CurrentSegment with label and start time
- Set bIsTrackingSession = true
- Start snapshot timer
- Fire OnSessionStarted
EndSession → S_MetricsSnapshot
- Description: Ends the tracking session and returns final snapshot.
- Parameters: None
- Flow:
- Finalize CurrentSegment end time
- Finalize CurrentSnapshot.PlayTime
- Add CurrentSegment to TimeSegmentHistory
- Set bIsTrackingSession = false
- Clear snapshot timer
- Fire OnSessionEnded
- Return CurrentSnapshot
RecordEvent → void
- Description: Records a single behaviour event into history and updates snapshot.
- Parameters:
| Param |
Type |
Description |
EventType |
E_MetricEventType |
Type of event |
ContextTag |
GameplayTag |
Filtering tag |
FloatValue |
Float |
Numeric payload |
StringValue |
String |
Text payload |
- Flow:
- If not bIsTrackingSession: return
- Create S_BehaviourEvent with current timestamp
- If bTrackDetailedEvents and event count < MaxEventHistory:
- Add event to CachedEventHistory
- Update CurrentSnapshot based on EventType:
- Death: TimesDied++
- HideStarted: TimesHid++
- ItemCollected: ItemsCollected++, add name to UniqueItemsCollected
- EnemyEncountered: EnemiesEncountered++
- EnemyEvaded: EnemiesEvaded++
- StressPeakReached: StressPeakCount++, update PeakStressTier if higher
- NarrativeEvent: NarrativeBeatsCompleted++
- AreaExplored: add to AreasExplored
- CombatEvent: CombatEvents++
- Fire OnEventRecorded
RecordDistanceTraveled → void
- Description: Called by movement system or tick to log distance.
- Parameters:
| Param |
Type |
Description |
DistanceDelta |
Float |
Distance moved this frame |
bWasSprinting |
Boolean |
Whether player was sprinting |
- Flow:
- If bWasSprinting: CurrentSnapshot.TotalDistanceSprinted += Delta
- Else: CurrentSnapshot.TotalDistanceWalked += Delta
GetMetricsSnapshot → S_MetricsSnapshot
- Description: Returns a copy of the current live snapshot.
- Parameters: None
- Flow: Return CurrentSnapshot
GetEventHistory → Array<S_BehaviourEvent>
- Description: Returns recorded event history.
- Parameters:
| Param |
Type |
Description |
bFiltered |
Boolean |
If true, apply filter |
FilterType |
E_MetricEventType |
Only return events of this type |
- Flow:
- If bFiltered: return filtered CachedEventHistory by FilterType
- Else: return CachedEventHistory
GetPlayTimeFormatted → String
- Description: Returns total play time as formatted string (HH:MM:SS).
- Parameters: None
- Flow: Format SecondsToTimeString(SessionDuration)
Protected / Private Functions
OnTickDistance (Tick) → void
- Description: Each tick, compute distance from LastPosition. Only active when tracking.
- Flow:
- If not bIsTrackingSession: return
- Get current actor location
- Delta = Distance(LastPosition, CurrentLocation)
- If Delta < 10.0: skip (noise threshold)
- Check movement mode from BPC_MovementStateSystem
- Call RecordDistanceTraveled(Delta, bWasSprinting)
- Update LastPosition = CurrentLocation
CreateSnapshot → void
- Description: Timer callback to create periodic snapshots.
- Flow:
- Copy CurrentSnapshot as snapshot
- Finalize CurrentSegment end time
- Store snapshot delta in CurrentSegment.MetricsDelta
- Add CurrentSegment to TimeSegmentHistory
- Start new CurrentSegment
5. Event Dispatchers
| Dispatcher |
Parameters |
Bind Access |
Description |
OnSessionStarted |
String SegmentLabel |
Public |
Fired when a tracking session begins |
OnSessionEnded |
S_MetricsSnapshot FinalSnapshot |
Public |
Fired when a tracking session ends |
OnEventRecorded |
S_BehaviourEvent Event |
Public |
Fired each time an event is recorded |
OnMetricsThresholdReached |
E_MetricEventType EventType, int CurrentValue, int Threshold |
Public |
Fired when a metric crosses a threshold |
OnSnapshotCreated |
S_TimeSegment Segment |
Public |
Fired when a periodic snapshot is written |
6. Overridden Events / Custom Events
Event: BeginPlay
- Description: Cache owner reference, start session if game has started.
- Flow:
- Get owning pawn
- Bind to GI_GameFramework.OnGamePhaseChanged
- If game phase is Playing: StartSession("Initial")
Custom Event: OnGamePhaseChangedHandler
- Description: Auto-start/stop session based on game phase.
- Flow:
- If NewPhase == Playing: StartSession("Resume")
- If NewPhase == Menu / Transition / Ended: EndSession()
7. Blueprint Graph Logic Flow
8. Communication Matrix
| Who Talks |
How |
What Is Sent |
BPC_PlayerMetricsTracker |
Direct call (other) |
GetMetricsSnapshot -> BPC_AdaptiveDifficulty |
BPC_PlayerMetricsTracker |
Dispatcher |
OnEventRecorded -> BPC_AdaptiveDifficulty (real-time feed) |
BPC_PlayerMetricsTracker |
Dispatcher |
OnSessionEnded -> WBP_StatsScreen (end-game display) |
BPC_PlayerMetricsTracker |
Dispatcher |
OnMetricsThresholdReached -> GM_CoreGameMode (achievements) |
BPC_HealthSystem |
Direct |
Calls RecordEvent(Death) on player death |
BPC_HidingSystem |
Direct |
Calls RecordEvent(HideStarted/HideEnded) |
BPC_StressSystem |
Direct |
Calls RecordEvent(StressPeakReached) |
GI_GameFramework |
Dispatcher |
OnGamePhaseChanged -> BPC_PlayerMetricsTracker (start/stop) |
BPC_NarrativeManager |
Direct |
Calls RecordEvent(NarrativeEvent) on story beat |
BPC_WeaponSystem |
Direct |
Calls RecordEvent(CombatEvent) on attack |
BPC_InventoryManager |
Direct |
Calls RecordEvent(ItemCollected) on pickup |
9. Validation / Testing Checklist
10. Reuse Notes
- The metrics snapshot is designed to be consumed by
BPC_AdaptiveDifficulty for dynamic difficulty adjustment.
- Event history can be serialised to disk via
I_Persistable for cross-session analytics.
- The same
BPC_PlayerMetricsTracker can be attached to any character blueprint — not just the player.
- Threshold values are not defined here; they live in
DA_GameDifficulty or DA_AdaptiveSettings.
- For debugging, call
GetEventHistory(false) to dump all events to log.
11. Multiplayer Networking
Replication
| Variable |
Condition |
Purpose |
CurrentSnapshot |
Replicated |
Synced for scoreboard, playstyle classification |
Authority
- Server accumulates all metrics (listens to gameplay dispatchers server-side).
- Server creates periodic snapshots and replicates.
- Clients only read metrics (for local HUD/scoreboard display).
Server RPCs
| RPC |
Direction |
Description |
Server_LogEvent |
Client→Server |
Client reports a metric event. Server validates before recording. |
Anti-Cheat
- Server validates
Server_LogEvent calls: damage dealt must match server calculations, distance traveled must be plausible, item pickups validated by inventory system.
Blueprint Spec: Player Metrics Tracker. Conforms to TEMPLATE.md v1.0 — part of the UE5 Modular Game Framework.