# BPC_PlaystyleClassifier — Playstyle Classifier ## Blueprint Spec — UE 5.5–5.7 --- ### Parent Class `ActorComponent` ### Dependencies - **Requires:** [`BPC_PlayerMetricsTracker`](../02-player/15_BPC_PlayerMetricsTracker.md) — Reads behaviour metrics (AggressionScore, CautionScore, ExplorationScore) - **Required By:** [`BPC_AdaptiveEnvironmentDirector`](BPC_AdaptiveEnvironmentDirector.md) — Subscribes to `OnPlaystyleChanged` - **Required By:** [`BPC_BehaviourVariantSelector`](../09-ai/BPC_BehaviourVariantSelector.md) — AI adapts to playstyle - **Required By:** [`BPC_PacingDirector`](BPC_PacingDirector.md) — Pacing adjusted by playstyle - **Engine/Plugin Requirements:** GameplayTags (for playstyle tag output), Timer system ### Purpose Analyses player behaviour metrics from BPC_PlayerMetricsTracker and classifies their playstyle in real time. Outputs a dominant playstyle tag (Aggressive, Cautious, Explorer, etc.) that feeds into the adaptive environment director and AI behaviour systems. --- ## 1. Enums ```text Enum Name: E_PlaystyleTag (DisplayName = "Playstyle Tag") Values: Aggressive = 0 // Player favours combat and direct confrontation Cautious = 1 // Player favours hiding, sneaking, and avoidance Explorer = 2 // Player favours off-path exploration and discovery Passive = 3 // Player avoids interaction, moves slowly Speedrunner = 4 // Player rushes through content, skips optional Completionist = 5 // Player exhaustively searches every area ``` *Values are used as Gameplay Tags for routing to adaptive systems.* --- ## 2. Structs *No new structs defined. Reads from [`S_BehaviourEvent`](../02-player/15_BPC_PlayerMetricsTracker.md).* --- ## 3. Variables ### Configuration (Instance Editable, Expose On Spawn) | Variable | Type | Default | Category | Description | |----------|------|---------|----------|-------------| | `ClassificationInterval` | Float | 15.0 | Classifier | Seconds between playstyle re-evaluations | | `AggressionWeight` | Float | 1.0 | Classifier | Multiplier for aggression score influence | | `CautionWeight` | Float | 1.0 | Classifier | Multiplier for caution score influence | | `ExplorationWeight` | Float | 1.0 | Classifier | Multiplier for exploration score influence | | `ClassificationThreshold` | Float | 10.0 | Classifier | Minimum score delta required to change classification | ### Internal (Private / Protected, No Expose) | Variable | Type | Default | Category | Description | |----------|------|---------|----------|-------------| | `CurrentPlaystyleTag` | GameplayTag | Explorer | Internal | Dominant playstyle classification | | `PreviousPlaystyleTag` | GameplayTag | None | Internal | Last classification for change detection | | `ClassificationTimer` | TimerHandle | — | Internal | Timer for periodic re-evaluation | --- ## 4. Functions ### Public Functions #### `ClassifyPlaystyle` → `GameplayTag` - **Description:** Reads metrics from BPC_PlayerMetricsTracker, calculates weighted scores, and determines the dominant playstyle tag. - **Parameters:** None - **Blueprint Authority:** Any - **Flow:** Get metrics → multiply by weights → find highest scoring playstyle → return tag #### `GetCurrentPlaystyle` → `GameplayTag` - **Description:** Returns the current dominant playstyle tag. - **Parameters:** None - **Blueprint Authority:** Any #### `GetPlaystyleScores` → `Map (GameplayTag → Float)` - **Description:** Returns the weighted score for each playstyle tag for external analysis. - **Parameters:** None - **Blueprint Authority:** Any #### `ForcePlaystyle` → `void` - **Description:** Overrides the playstyle classification for debugging or scripted sequences. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `PlaystyleTag` | GameplayTag | Forced classification | - **Blueprint Authority:** Any --- ## 5. Event Dispatchers | Dispatcher | Parameters | Bind Access | Description | |------------|-----------|-------------|-------------| | `OnPlaystyleChanged` | OldTag: GameplayTag, NewTag: GameplayTag | Public | Playstyle classification changed | | `OnPlaystyleReclassified` | NewTag: GameplayTag | Public | Periodic re-evaluation completed (fires even if unchanged) | --- ## 6. Overridden Events / Custom Events ### Event: `BeginPlay` - **Description:** Starts the classification timer. Subscribes to metrics changes if needed. - **Flow:** 1. Start ClassificationTimer with ClassificationInterval repeating 2. Perform initial classification immediately ### Event: `TickClassification` - **Description:** Timer callback. Runs ClassifyPlaystyle and broadcasts if changed. - **Flow:** 1. Read BPC_PlayerMetricsTracker.AggressionScore, CautionScore, ExplorationScore 2. Calculate weighted scores 3. Determine dominant playstyle tag (highest weighted score) 4. If new tag differs from CurrentPlaystyleTag AND score delta exceeds ClassificationThreshold: - Set PreviousPlaystyleTag = CurrentPlaystyleTag - Set CurrentPlaystyleTag = new tag - Broadcast OnPlaystyleChanged 5. Always broadcast OnPlaystyleReclassified --- ## 7. Blueprint Graph Logic Flow ```mermaid flowchart TD A[BeginPlay] --> B[Start ClassificationTimer] B --> C[Timer fires each ClassificationInterval seconds] C --> D[Read AggressionScore from BPC_PlayerMetricsTracker] D --> E[Read CautionScore from BPC_PlayerMetricsTracker] E --> F[Read ExplorationScore from BPC_PlayerMetricsTracker] F --> G[Calculate weighted scores:] G --> H[AggressionScore * AggressionWeight] H --> I[CautionScore * CautionWeight] I --> J[ExplorationScore * ExplorationWeight] J --> K[Also factor in: DeathCount, HideCount, ItemsCollected, DistanceTravelled] K --> L[Map derived values to playstyle tags] L --> M[Find highest weighted playstyle tag] M --> N{New tag != CurrentPlaystyleTag?} N -->|Yes| O{Score delta >= ClassificationThreshold?} O -->|Yes| P[Broadcast OnPlaystyleChanged] O -->|No| Q[Keep current classification] N -->|No| Q P --> R[Update CurrentPlaystyleTag] R --> S[Broadcast OnPlaystyleReclassified] Q --> S ``` --- ## 8. Communication Matrix | Who Talks | How | What Is Sent | |-----------|-----|-------------| | [`BPC_PlayerMetricsTracker`](../02-player/15_BPC_PlayerMetricsTracker.md) | Direct read | `AggressionScore`, `CautionScore`, `ExplorationScore`, `DeathCount`, `HideCount` | | [`BPC_AdaptiveEnvironmentDirector`](BPC_AdaptiveEnvironmentDirector.md) | Dispatcher (`OnPlaystyleChanged`) | `OldTag: GameplayTag`, `NewTag: GameplayTag` | | [`BPC_BehaviourVariantSelector`](../09-ai/BPC_BehaviourVariantSelector.md) | Dispatcher (`OnPlaystyleChanged`) | `NewTag: GameplayTag` | | [`BPC_PacingDirector`](BPC_PacingDirector.md) | Direct read | `CurrentPlaystyleTag` | | [`SS_AchievementSystem`](../11-meta/SS_AchievementSystem.md) | Dispatcher (`OnPlaystyleChanged`) | Playstyle tag for adaptive achievement checks | --- ## 9. Validation / Testing Checklist - [ ] E_PlaystyleTag enum has all 6 values defined - [ ] ClassificationInterval timer fires at correct interval - [ ] Weighted scores correctly calculated from metrics - [ ] OnPlaystyleChanged fires when classification changes significantly - [ ] ClassificationThreshold prevents minor fluctuations from causing changes - [ ] ForcePlaystyle overrides the automatic classification - [ ] Edge case: BPC_PlayerMetricsTracker not present → default to Explorer - [ ] Edge case: all scores zero → classify as Passive - [ ] Edge case: timer fires during cutscene → classification still runs, adapt on exit --- ## 10. Reuse Notes - AggressionWeight, CautionWeight, ExplorationWeight can be tuned per project to prioritise different behaviours - ClassificationThreshold prevents "flickering" between similar playstyles on minor metric changes - For non-adaptive games, set ClassificationInterval to 0 to disable or force a fixed playstyle - Extend with new E_PlaystyleTag values per project (e.g., "Pacifist", "Collector") - Classification is player-pawn-relative — in co-op, each player has their own classifier --- *Specification based on Master Section 9.1, line 2699.*