# 01 — Core Foundation Systems (Systems 01-07) **Category Purpose:** The foundation layer provides the application kernel, service resolution, shared utilities, interfaces, game rules, session state, and the base data asset from which all items inherit. Everything else in the framework depends on this layer. --- ## System Index | # | System | Asset Type | Role | |---|--------|-----------|------| | 01 | `GI_GameTagRegistry` | Data Asset | Central GameplayTag namespace registry & validation | | 02 | `FL_GameUtilities` | Function Library | Static utility functions (safe casts, math, tags, debug) | | 03 | `I_InterfaceLibrary` | Interface Collection | All 9 framework interfaces for decoupled communication | | 04 | `GI_GameFramework` | Game Instance | Application kernel; owns subsystems, manages game phases | | 05 | `GM_CoreGameMode` | Game Mode | Session rules, player spawn, chapter transitions, death routing | | 06 | `GS_CoreGameState` | Game State | Shared session state: chapter, objectives, play time | | 07 | `DA_ItemData` | Data Asset | Base item data asset — all items derive from this template | --- ## Category Data Flow ``` ┌──────────────────────────────────────────────────────────────────┐ │ APPLICATION BOOT SEQUENCE │ │ │ │ GI_GameFramework.Init() │ │ ├─► InitPlatformServices() │ │ ├─► SS_ Subsystems auto-initialize (UE GameInstanceSubsystem) │ │ ├─► SS_SettingsSystem.PopulateDefaults() │ │ ├─► SS_SaveSystem.GetSlotManifest() │ │ └─► SetGamePhase(MainMenu) → Broadcast OnGamePhaseChanged │ │ │ │ GM_CoreGameMode (spawned by engine) │ │ ├─► Reads default class references │ │ ├─► Spawns PC_CoreController, PS_CorePlayerState │ │ ├─► Creates GS_CoreGameState │ │ └─► If save data: LoadFromSlot → SetGamePhase(InGame) │ │ └─► If new game: TransitionToChapter(first chapter) │ │ │ │ GS_CoreGameState.BeginPlay() │ │ ├─► Bind to GI_GameFramework.OnGamePhaseChanged │ │ └─► Tick: accumulate ElapsedPlayTime when InGame │ │ │ │ ALL SYSTEMS query GameplayTags via GI_GameTagRegistry │ │ ALL SYSTEMS use FL_GameUtilities for safe casts & logging │ │ ALL SYSTEMS communicate via I_InterfaceLibrary interfaces │ │ ALL ITEMS are defined as DA_ItemData Data Assets │ └──────────────────────────────────────────────────────────────────┘ ``` --- ## 01 — GI_GameTagRegistry: Central GameplayTag Registry **What It Does:** This is a **documentation anchor** Data Asset, not a runtime tag database. The actual GameplayTag definitions live in `DefaultGameplayTags.ini`, but this asset serves as the single place where all framework tag namespaces are documented and validated. Every system that uses GameplayTags references them from this registry's documented namespaces. **How It Works Internally:** - At `OnAssetLoaded`, it calls `GetAllRegisteredTags()` to verify the project has tags registered - If zero tags exist, it logs a warning — this catches misconfigured projects early - `ValidateTag(Tag)` checks if a given tag exists in the engine's tag table using `RequestGameplayTag()` - `ExportTagNamespace(Prefix)` iterates registered tags matching a namespace prefix for tooling/docs - The documented namespaces cover: `Player.State.*`, `Interaction.*`, `Item.*`, `Narrative.*`, `Objective.*`, `AI.*`, `Save.*`, `Achievement.*`, `Environment.*`, `DeathSpace.*` **Implementation Patterns:** - Create as `UPrimaryDataAsset` → Blueprint Data Asset - Functions are BlueprintCallable / Pure — no tick, no events, no state - `LogAllTags()` and `ExportTagNamespace()` are Editor-only via `#if WITH_EDITOR` - Framework tags use `Framework.` prefix; project tags use `Game.` prefix to avoid collisions **Integration Points:** - **Read by:** Every system that does `HasTag()` / `MatchesTag()` comparisons - **No outgoing calls** — this is purely passive **Edge Cases:** - If the tag table is empty at load, a warning fires but the game still runs (tags can be added later) - Duplicate tags across namespaces cause `RequestGameplayTag()` to return the first match — validate in editor - Raw string comparisons are forbidden — always use `HasTag()` or `MatchesTag()` --- ## 02 — FL_GameUtilities: Shared Function Library **What It Does:** A static Blueprint Function Library providing safe, reusable utility functions available from any Blueprint without needing an object reference. Handles subsystem lookups, math, tag operations, text formatting, screen projection, and debug logging. **How It Works Internally:** - **Pure static class** — no variables, no tick, no event dispatchers, no state - **Null-safe subsystem retrieval:** `GetSubsystemSafe()` wraps `GetSubsystem()` in a validity check and returns `None` instead of crashing - **Typed casts:** `GetGameFramework()` and `GetPlayerController()` cast to framework-specific types and log errors on failure - **Actor utilities:** `FindComponentByInterface()` iterates components checking `DoesImplementInterface()`; `FindNearestActorWithTag()` sphere-overlaps actors and filters by GameplayTag - **Math:** `RemapFloat()`, `LerpClamped()`, `VectorToAngle2D()`, `AngleDifference()` — standard blueprint-safe math - **Tag utilities:** `HasGameplayTag()` checks actor's tag container safely (returns false if no container); `MakeTagFromString()` converts strings with validation - **Text:** `FormatTime()` converts seconds to `HH:MM:SS`; `Pluralise()` handles singular/plural; `TruncateText()` clips with ellipsis - **Screen:** `WorldToScreenSafe()` projects world position to screen and returns `bIsOnScreen` (false if behind camera) - **Debug:** All debug functions are wrapped in `#if !UE_BUILD_SHIPPING` — automatically stripped from shipping builds **Implementation Patterns:** - All functions are `BlueprintCallable` or `BlueprintPure` - Functions requiring world context take `WorldContextObject` as first parameter (UE convention for static libraries) - Debug functions use `DO_CHECK` preprocessor — no manual removal needed **Integration Points:** - **Called by:** Every Blueprint in the project (context menu → category name) - **No outgoing calls** except to `GI_GameFramework` and `PC_CoreController` via typed cast functions **Edge Cases:** - `GetSubsystemSafe()` returning null must be handled by callers — no default fallback - `MakeTagFromString()` returns invalid tag if string isn't registered — caller must validate - Math functions assume float inputs — NaN protection uses `FMath::IsNaN()` internally --- ## 03 — I_InterfaceLibrary: All Framework Interfaces **What It Does:** Defines all 9 Blueprint Interfaces that form the backbone of cross-system communication. Rather than dozens of scattered interface files, all interfaces are documented in one collection. Interfaces are the **preferred communication method** — they decouple caller from callee's concrete class. **How It Works Internally — The 9 Interfaces:** | Interface | Functions | Implemented By | |-----------|-----------|---------------| | `I_Interactable` | `OnInteract`, `OnFocusBegin/End`, `GetInteractionPrompt`, `CanInteract`, `GetInteractionType` | Doors, pickups, devices, NPCs | | `I_Inspectable` | `StartInspect/EndInspect`, `RotateInspect`, `GetInspectData`, `HasInspectInfo` | Items with 3D examine mode | | `I_Damageable` | `TakeDamage`, `Heal`, `IsAlive`, `GetMaxHealth/GetCurrentHealth`, `OnDeath`, `GetDamageModifier` | Player, enemies, destructibles | | `I_Holdable` | `OnPickup/OnDrop`, `GetHoldTransform`, `IsHeld`, `OnReleasedFromHold` | Physics objects, puzzle items | | `I_Lockable` | `TryLock/TryUnlock`, `IsLocked`, `GetRequiredKeyTag`, `OnLockStateChanged` | Doors, containers, safes | | `I_UsableItem` | `UseItem`, `CanUseItem`, `GetUseDuration`, `OnItemUsed` | Consumables, tools, key items | | `I_Persistable` | `OnSave/OnLoad`, `GetSaveTag`, `NeedsSave` | Any actor that saves state | | `I_Toggleable` | `Toggle`, `SetState`, `GetCurrentState`, `GetStateLabel`, `OnStateChanged` | Lights, switches, machines | | `I_Adjustable` | `Adjust`, `SetValue`, `GetCurrentValue`, `GetMinValue/GetMaxValue`, `OnValueChanged` | Dials, valves, sliders | **Communication Pattern:** 1. Caller uses `DoesImplementInterface` or `Cast to Interface` to check 2. If interface exists, calls the interface function 3. Implementor handles the logic internally — caller never knows the concrete class 4. Interface default return values (typically `false` or `0.0f`) handle missing implementations gracefully **Implementation Patterns:** - Each interface function has a single clear responsibility - Implementors should NEVER call interface functions on themselves (use internal functions instead) - New interfaces extend the collection; child interfaces keep base interfaces stable - Multiple interfaces can be implemented by one actor (e.g., a door implements `I_Interactable`, `I_Toggleable`, `I_Lockable`, `I_Persistable`) **Edge Cases:** - Calling an interface function on an actor that doesn't implement it returns the default value (no crash) - `OnInteract` returning false triggers a "blocked" feedback sound — caller handles this - `CanInteract` provides `BlockReason` text for UI — always provide a reason, not just `false` --- ## 04 — GI_GameFramework: Application Kernel **What It Does:** The single persistent object that lives for the entire application session. It owns all `SS_` GameInstanceSubsystems, manages save slot ownership, provides the canonical service resolver (`GetSubsystem()`), and tracks the top-level game phase (MainMenu → Loading → InGame → Paused → Cutscene → DeathLoop → AltDeathSpace → Credits → PostGame). **How It Works Internally:** **State Machine — Game Phases:** ``` MainMenu → Loading → InGame ⇄ Paused ↓ Cutscene ↓ DeathLoop → AltDeathSpace ↓ Credits → PostGame ``` - `SetGamePhase(Phase)` updates `CurrentGamePhase` and broadcasts `OnGamePhaseChanged` - Phase transitions are the single point of authority — all systems react to dispatcher, not direct checks - `SessionFlags` (Map of GameplayTag → Boolean) stores transient flags that don't persist to disk **Boot Sequence (Init):** 1. Call parent `Init()` 2. `InitPlatformServices()` — routes to platform-specific stubs based on `PlatformType` (Steam/PS/Xbox/Switch/Generic) 3. All `SS_` Subsystems are auto-initialized by UE's `GameInstanceSubsystem` system 4. `SS_SettingsSystem.PopulateDefaults()` loads persistent settings 5. `SS_SaveSystem.GetSlotManifest()` checks existing saves 6. `SetGamePhase(MainMenu)` — game starts at main menu 7. Broadcast `OnPlatformReady` **Service Resolution:** - `GetSubsystem(Tag)` maps a GameplayTag to a subsystem class, then calls `GetSubsystem()` - This is the canonical entry point for any system needing a global service - Returns null and logs warning if tag isn't mapped — caller must handle null **Implementation Patterns:** - `SetActiveSlot(SlotIndex)` designates save slot without triggering load — slot is just an integer - `bFirstLaunch` stays true until onboarding flow clears it — controls intro sequence - `PlatformType` can be overridden via command-line: `-Platform=Steam` - Add new subsystems to the init list — they auto-initialize via UE's native system **Integration Points:** - **Owns:** All `SS_` Subsystems - **Broadcasts:** `OnGamePhaseChanged` → `GM_CoreGameMode`, `WBP_HUDController`, `WBP_MenuFlowController` - **Broadcasts:** `OnPlatformReady` → all platform-dependent systems - **Called by:** Any Blueprint via `GetSubsystem()` **Edge Cases:** - Calling `SetGamePhase()` with the same value should not fire dispatcher (prevents infinite loops) - `GetSubsystem()` during `PreInit()` returns null — systems must handle early-access gracefully - For multi-world / split-screen: this is a single-instance singleton per application session --- ## 05 — GM_CoreGameMode: Session Rules & Player Spawning **What It Does:** Sets the rules of the game session: which pawn, controller, player state, HUD, and game state classes to use. Manages chapter transitions, win/loss/death routing, and coordinates with the narrative system for story progression. **How It Works Internally:** **Default Class Setup:** - `DefaultPawnClass` — the GASP-based player pawn - `DefaultControllerClass` — `PC_CoreController` - `DefaultPlayerStateClass` — `PS_CorePlayerState` - `DefaultGameStateClass` — `GS_CoreGameState` - `DefaultHUDClass` — `WBP_HUDController` **Chapter Transition Flow:** 1. `TransitionToChapter(ChapterTag)` is called (by narrative trigger or menu) 2. Sets `CurrentChapterTag` on GM 3. Calls `GI_GameFramework.SetGamePhase(Loading)` 4. Opens/streams the level associated with `ChapterTag` 5. On level loaded: syncs chapter to `GS_CoreGameState`, fires `BPC_NarrativeSystem.OnChapterStart` 6. Calls `SetGamePhase(InGame)` **Death Handling Flow:** 1. `BPC_DeathHandlingSystem` dispatches player death 2. `HandlePlayerDead()` is called 3. Disables pause (`bPauseAllowed = false`) 4. Sets phase to `DeathLoop` 5. Decision: if Alt Death Space is configured → `TriggerEnding(AltDeathSpace)`, else → load checkpoint via `SS_SaveSystem`, respawn player **Implementation Patterns:** - All default class references are exposed as instance-editable variables — no hardcoded classes - `bPauseAllowed` is a runtime flag that menu widgets check before pausing (false during cutscenes/death) - `CurrentChapterTag` is a GameplayTag — chapters are data-driven, not hardcoded strings - `TriggerEnding(EndingTag)` passes the ending condition to `BPC_EndingAccumulator` **Integration Points:** - **Owns/Spawns:** Player Controller, Player State, Game State, HUD - **Listens to:** `BPC_DeathHandlingSystem` (death events), `BPC_NarrativeSystem` (chapter triggers) - **Calls:** `GI_GameFramework.SetGamePhase()`, `SS_SaveSystem.LoadCheckpoint()` - **Broadcasts:** `OnChapterTransition`, `OnGameOverTriggered` **Edge Cases:** - `TransitionToChapter` during loading should be ignored (check phase before transitioning) - `HandlePlayerDead` must be idempotent — calling it twice shouldn't double-stack death states - For multiplayer: extend to derive from replicated GameMode base class --- ## 06 — GS_CoreGameState: Shared Session State **What It Does:** A replicated game state singleton visible to all players. Tracks session-level data: elapsed play time, active chapter, narrative phase, encounter status, and active objectives. UI widgets and narrative systems read from here rather than querying individual systems. **How It Works Internally:** **Tracked State:** - `ElapsedPlayTime` — accumulates in Tick only when GamePhase is `InGame` - `ActiveChapterTag` — current story chapter (set by GM_CoreGameMode) - `ActiveNarrativePhase` — sub-chapter phase (set by NarrativeStateSystem) - `bEncounterActive` — whether an AI encounter is running (set by EncounterDirector) - `ActiveObjectiveTags` — array of active objective tags (set by ObjectiveSystem) **State Change Pattern (all variables follow this):** 1. Setter function updates internal variable 2. Broadcasts corresponding event dispatcher 3. UI/replication `OnRep` functions mirror the broadcast for network clients **Dispatcher Protocol:** - `OnElapsedPlayTimeUpdated` — fires every ~1 second tick (throttled for performance) - `OnChapterChanged` — UI updates chapter display, narrative systems react - `OnNarrativePhaseChanged` — sub-chapter transitions - `OnEncounterActiveStateChanged` — HUD shows encounter status, atmosphere shifts - `OnObjectiveTagsChanged` — `WBP_ObjectiveDisplay` refreshes **Implementation Patterns:** - Intentional lightweight — a singleton data holder, not a logic processor - All modification happens through dedicated setter functions (never direct variable write) - Objective tags array: add/remove check for duplicates before modifying - Time accumulation is gated by GamePhase check — stops during pause/loading/cutscenes - For multiplayer: all variables are `Replicated Using` with `OnRep` notification **Integration Points:** - **Written by:** `GM_CoreGameMode`, `BPC_ObjectiveSystem`, `BPC_EncounterDirector` - **Read by:** `WBP_HUDController`, `WBP_ObjectiveDisplay`, `BPC_RunHistoryTracker` - **Listens to:** `GI_GameFramework.OnGamePhaseChanged` (to gate time accumulation) **Edge Cases:** - Rapid chapter changes in same tick must fire dispatcher for each — use queue if necessary - Empty objective list removal from empty list should not crash - Time accumulation stops correctly on phase change to Paused/Loading/Cutscene --- ## 07 — DA_ItemData: Base Item Data Asset **What It Does:** The single source of truth for every item in the game. Each item is one `DA_ItemData` Primary Data Asset — no item data lives in Blueprint logic. This is the base class; all items inherit this template and fill in their specific values. **How It Works Internally:** **Core Properties (every item has these):** - `ItemTag` (GameplayTag) — unique identifier, must be registered in `GI_GameTagRegistry` - `DisplayName`, `Description` (FText) — player-facing text - `Icon` (Texture2D soft reference) — UI icon - `WorldMesh` (StaticMesh soft reference) — 3D mesh when dropped in world - `Weight` (Float) — carry weight units - `StackLimit` (Integer) — max per-slot stack count - `ItemType` (E_ItemType) — classification: Weapon, Ammo, Consumable, KeyItem, Document, Collectible, Tool, Resource, Misc **Conditional Sub-Data (shown based on ItemType via EditCondition):** - `EquipmentData` — shown when ItemType is Weapon or Tool (slot type, stats) - `ConsumableData` — shown when ItemType is Consumable (health restore, stress reduce) - `InspectData` — shown when `bHasInspectMode` is true (3D rotation anchors) - `AmmoData` — shown when ItemType is Ammo (ammo type tag, per-pickup count) **Combination Logic:** - `CombinesWith` — array of ItemTags this can combine with - `CombineResult` — the ItemTag produced on successful combination - Both fields are read by `BPC_ItemCombineSystem` to validate and execute combinations **Data-Driven Design:** - This is a pure data container — no runtime functions, no tick, no events - `ValidateItemData()` exists as an Editor-only function for content team validation - `CustomProperties` map (Name → String) provides per-project extensibility without modifying the base class **Implementation Patterns:** - Create one asset per item: name convention `DA_Item_[ShortName]` - All `ItemTag` values must be registered in tag table before use - `bIsKeyItem` forces `bCanBeDropped = false` — key items can't be discarded - `StackLimit = 1` for weapons, tools, key items; larger for ammo, consumables, resources - Assets registered with Primary Asset Manager (label: `Item`) for async loading **Integration Points:** - **Read by:** `BPC_InventorySystem` (every property), `BPC_ConsumableSystem` (ConsumableData), `BPC_EquipmentSlotSystem` (EquipmentData), `BPC_AmmoResourceSystem` (AmmoData), `BPC_ItemCombineSystem` (CombinesWith/CombineResult), `BPC_InspectItemSystem` (InspectData) - **Displayed by:** `WBP_InventoryMenu` (via InventorySystem), `WBP_InteractionPromptDisplay` (DisplayName for pickup prompt) **Edge Cases:** - Two items with same ItemTag causes confusion — editor validation must enforce uniqueness - Key items with `bCanBeDropped = true` is prevented by `ValidateItemData()` forcing it false - Empty DisplayName/Description should be caught by validation — not crash, just warn - Consumable items with all effect values = 0 are technically valid but useless — validation should warn --- ## Initialization Order (BeginPlay Sequence) ``` 1. GI_GameFramework.Init() ← Engine creates GameInstance 2. ├─ InitPlatformServices() 3. ├─ SS_ Subsystems init ← UE auto-initializes GameInstanceSubsystems 4. ├─ SS_SettingsSystem loads 5. └─ SetGamePhase(MainMenu) 6. GM_CoreGameMode.InitGame() ← Engine creates GameMode when level loads 7. ├─ Sets default classes 8. ├─ Spawns GS_CoreGameState 9. └─ Spawns Player Controller + Pawn 10. GS_CoreGameState.BeginPlay() 11. ├─ Binds to OnGamePhaseChanged 12. └─ Starts time tick 13. DA_ItemData assets are loaded on demand ← Asset Manager async loads 14. FL_GameUtilities calls available immediately ← Static library 15. GI_GameTagRegistry.OnAssetLoaded() ← Fires when data asset loads ``` --- ## Common Implementation Patterns in This Category 1. **Tag-Driven Everything:** No booleans for state, no string comparisons. Everything is a GameplayTag compared via `HasTag()` / `MatchesTag()`. 2. **Dispatcher-Based Phase Changes:** Systems don't poll `CurrentGamePhase` — they bind to `OnGamePhaseChanged` and react. 3. **Data Assets for Content:** All item definitions, platform configs, and settings live in Data Assets, never hardcoded in Blueprints. 4. **Interface-First Communication:** Systems query for interface implementation before calling — no direct class casting. 5. **Null-Safe Subsystem Lookup:** Always use `FL_GameUtilities.GetSubsystemSafe()` — never call engine `GetSubsystem()` directly. 6. **Session Flags vs Saved Data:** `GI_GameFramework.SessionFlags` for transient state; `I_Persistable` for data that survives sessions. --- *Developer Reference v1.0 — 01 Core Foundation Systems. Companion to docs/blueprints/01-core/ specs.*