- Updated Master Blueprint Index to include Multiplayer Networking support. - Added detailed Multiplayer Networking sections across all developer documentation (01-11). - Introduced authority maps, key patterns, and RPC guidelines for each system. - Established a comprehensive multiplayer networking architecture document outlining core principles, replication strategies, and anti-cheat considerations. - Enhanced UI documentation to clarify local-only behavior and binding to replicated dispatchers. - Implemented client prediction strategies and RPC naming conventions for consistency across the framework.
24 KiB
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 callsGetAllRegisteredTags()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 usingRequestGameplayTag()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()andExportTagNamespace()are Editor-only via#if WITH_EDITOR- Framework tags use
Framework.prefix; project tags useGame.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()orMatchesTag()
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()wrapsGetSubsystem()in a validity check and returnsNoneinstead of crashing - Typed casts:
GetGameFramework()andGetPlayerController()cast to framework-specific types and log errors on failure - Actor utilities:
FindComponentByInterface()iterates components checkingDoesImplementInterface();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 toHH:MM:SS;Pluralise()handles singular/plural;TruncateText()clips with ellipsis - Screen:
WorldToScreenSafe()projects world position to screen and returnsbIsOnScreen(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
BlueprintCallableorBlueprintPure - Functions requiring world context take
WorldContextObjectas first parameter (UE convention for static libraries) - Debug functions use
DO_CHECKpreprocessor — no manual removal needed
Integration Points:
- Called by: Every Blueprint in the project (context menu → category name)
- No outgoing calls except to
GI_GameFrameworkandPC_CoreControllervia typed cast functions
Edge Cases:
GetSubsystemSafe()returning null must be handled by callers — no default fallbackMakeTagFromString()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:
- Caller uses
DoesImplementInterfaceorCast to Interfaceto check - If interface exists, calls the interface function
- Implementor handles the logic internally — caller never knows the concrete class
- Interface default return values (typically
falseor0.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)
OnInteractreturning false triggers a "blocked" feedback sound — caller handles thisCanInteractprovidesBlockReasontext for UI — always provide a reason, not justfalse
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)updatesCurrentGamePhaseand broadcastsOnGamePhaseChanged- 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):
- Call parent
Init() InitPlatformServices()— routes to platform-specific stubs based onPlatformType(Steam/PS/Xbox/Switch/Generic)- All
SS_Subsystems are auto-initialized by UE'sGameInstanceSubsystemsystem SS_SettingsSystem.PopulateDefaults()loads persistent settingsSS_SaveSystem.GetSlotManifest()checks existing savesSetGamePhase(MainMenu)— game starts at main menu- Broadcast
OnPlatformReady
Service Resolution:
GetSubsystem(Tag)maps a GameplayTag to a subsystem class, then callsGetSubsystem()- 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 integerbFirstLaunchstays true until onboarding flow clears it — controls intro sequencePlatformTypecan 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()duringPreInit()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 pawnDefaultControllerClass—PC_CoreControllerDefaultPlayerStateClass—PS_CorePlayerStateDefaultGameStateClass—GS_CoreGameStateDefaultHUDClass—WBP_HUDController
Chapter Transition Flow:
TransitionToChapter(ChapterTag)is called (by narrative trigger or menu)- Sets
CurrentChapterTagon GM - Calls
GI_GameFramework.SetGamePhase(Loading) - Opens/streams the level associated with
ChapterTag - On level loaded: syncs chapter to
GS_CoreGameState, firesBPC_NarrativeSystem.OnChapterStart - Calls
SetGamePhase(InGame)
Death Handling Flow:
BPC_DeathHandlingSystemdispatches player deathHandlePlayerDead()is called- Disables pause (
bPauseAllowed = false) - Sets phase to
DeathLoop - Decision: if Alt Death Space is configured →
TriggerEnding(AltDeathSpace), else → load checkpoint viaSS_SaveSystem, respawn player
Implementation Patterns:
- All default class references are exposed as instance-editable variables — no hardcoded classes
bPauseAllowedis a runtime flag that menu widgets check before pausing (false during cutscenes/death)CurrentChapterTagis a GameplayTag — chapters are data-driven, not hardcoded stringsTriggerEnding(EndingTag)passes the ending condition toBPC_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:
TransitionToChapterduring loading should be ignored (check phase before transitioning)HandlePlayerDeadmust 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 isInGameActiveChapterTag— 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):
- Setter function updates internal variable
- Broadcasts corresponding event dispatcher
- UI/replication
OnRepfunctions mirror the broadcast for network clients
Dispatcher Protocol:
OnElapsedPlayTimeUpdated— fires every ~1 second tick (throttled for performance)OnChapterChanged— UI updates chapter display, narrative systems reactOnNarrativePhaseChanged— sub-chapter transitionsOnEncounterActiveStateChanged— HUD shows encounter status, atmosphere shiftsOnObjectiveTagsChanged—WBP_ObjectiveDisplayrefreshes
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 UsingwithOnRepnotification
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 inGI_GameTagRegistryDisplayName,Description(FText) — player-facing textIcon(Texture2D soft reference) — UI iconWorldMesh(StaticMesh soft reference) — 3D mesh when dropped in worldWeight(Float) — carry weight unitsStackLimit(Integer) — max per-slot stack countItemType(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 whenbHasInspectModeis 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 withCombineResult— the ItemTag produced on successful combination- Both fields are read by
BPC_ItemCombineSystemto 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 validationCustomPropertiesmap (Name → String) provides per-project extensibility without modifying the base class
Implementation Patterns:
- Create one asset per item: name convention
DA_Item_[ShortName] - All
ItemTagvalues must be registered in tag table before use bIsKeyItemforcesbCanBeDropped = false— key items can't be discardedStackLimit = 1for 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 = trueis prevented byValidateItemData()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
- Tag-Driven Everything: No booleans for state, no string comparisons. Everything is a GameplayTag compared via
HasTag()/MatchesTag(). - Dispatcher-Based Phase Changes: Systems don't poll
CurrentGamePhase— they bind toOnGamePhaseChangedand react. - Data Assets for Content: All item definitions, platform configs, and settings live in Data Assets, never hardcoded in Blueprints.
- Interface-First Communication: Systems query for interface implementation before calling — no direct class casting.
- Null-Safe Subsystem Lookup: Always use
FL_GameUtilities.GetSubsystemSafe()— never call engineGetSubsystem()directly. - Session Flags vs Saved Data:
GI_GameFramework.SessionFlagsfor transient state;I_Persistablefor data that survives sessions.
Multiplayer Networking
Category Authority Map
| System | Role | Authority |
|---|---|---|
GI_GameFramework |
GamePhase, session flags | Server sets; clients read via replicated dispatcher |
GM_CoreGameMode |
Player spawning, chapter transitions, death routing | Server-only (extends replicated GameMode) |
GS_CoreGameState |
Shared session state bus | Fully replicated — 5 vars with OnRep handlers |
GI_GameTagRegistry |
Tag documentation | Read-only config — identical on all clients |
FL_GameUtilities |
Static utilities | No state — callable from any side |
I_InterfaceLibrary |
Communication contracts | Interface calls work on any side; mutators must check authority |
DA_ItemData |
Item definitions | Read-only Data Asset — identical on all clients |
Key Patterns
- GS_CoreGameState as Replication Hub: All shared session state (chapter, phase, objectives, encounter status) writes through GS_CoreGameState which auto-replicates to all clients via OnRep → dispatcher.
- GamePhase transitions are server-authoritative:
SetGamePhase()checksHasAuthority(). Clients receive phase changes viaOnRep_GamePhase→OnGamePhaseChangeddispatcher. - Interface calls route through server:
I_Interactable.Execute_OnInteractmust be called server-side. Clients callServer_InteractRPC → server validates → calls interface. - Data Assets are client-ready: All
DA_*assets load identically on all instances from disk. No replication needed.
Full Spec
See docs/architecture/multiplayer-networking.md Section 3.1.
Developer Reference v1.0 — 01 Core Foundation Systems. Companion to docs/blueprints/01-core/ specs.