feat: Add Enhanced Input Manager for context management and key rebinding

- Implemented USS_EnhancedInputManager to manage input contexts with priority.
- Added methods for pushing, popping, and querying input contexts.
- Integrated input mode switching and key rebinding functionality.

feat: Introduce Inventory System Component for item management

- Created UBPC_InventorySystem to handle inventory operations such as adding, removing, and sorting items.
- Implemented weight management and slot organization features.
- Added event dispatchers for inventory changes.

feat: Develop Item Data Asset for item definitions

- Established UDA_ItemData as a base class for all items, encapsulating properties like type, weight, and stack limits.
- Included conditional sub-data structures for equipment, consumables, and inspect data.

feat: Create State Manager Component for player state management

- Developed UBPC_StateManager to manage player action states and overlays.
- Implemented gating logic for action requests and vital sign tracking.

feat: Implement Save Manager for game state persistence

- Introduced USS_SaveManager for handling save/load operations and slot management.
- Utilized FArchive for efficient binary serialization.

feat: Implement Damage Reception System for combat mechanics

- Created UBPC_DamageReceptionSystem to process incoming damage and apply resistance calculations.
- Added event dispatchers for damage reception and hit reactions.
This commit is contained in:
Lefteris Notas
2026-05-20 15:04:17 +03:00
parent fee12b115f
commit f6c4f44827
24 changed files with 5160 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — DA_GameTagRegistry (01)
// Central gameplay tag registry Data Asset. Eliminates the 3 C++-only API workarounds
// (RequestAllGameplayTags, RequestGameplayTag, UGameplayTagsManager singleton access).
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "GameplayTagContainer.h"
#include "Engine/DataTable.h"
#include "DA_GameTagRegistry.generated.h"
/**
* DA_GameTagRegistry — Central GameplayTag namespace registry.
*
* In C++, this directly wraps UGameplayTagsManager APIs instead of using the
* Data Table proxy workaround required in Blueprint. Maintains the Data Table
* references for the Blueprint implementation guide, but the C++ functions
* bypass them entirely for performance and correctness.
*/
UCLASS(BlueprintType, Blueprintable, meta = (DisplayName = "DA_GameTagRegistry"))
class FRAMEWORK_API UDA_GameTagRegistry : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UDA_GameTagRegistry();
// ========================================================================
// Configuration
// ========================================================================
/** Human-readable description of the tag namespace (e.g. "Player.State"). */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Documentation")
FText TagNamespace;
/** True for framework-defined tags, false for project-specific overrides. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Documentation")
bool bIsFrameworkTag = true;
/**
* Array of 11 per-category Data Tables used by Blueprint implementations.
* C++ functions use UGameplayTagsManager directly and ignore this array.
* Maintained for the Blueprint Manual Implementation Guide.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Config")
TArray<TObjectPtr<UDataTable>> TagDataTables;
// ========================================================================
// Query Functions
// ========================================================================
/**
* Returns ALL registered gameplay tags from the engine's tag manager.
* C++ implementation: single call to UGameplayTagsManager.
* Blueprint equivalent: nested ForEachLoop over 11 Data Tables (workaround).
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Tags|Query")
TArray<FGameplayTag> GetAllRegisteredTags() const;
/**
* Returns the human-readable display name of a gameplay tag.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Tags|Query")
FText GetTagDisplayName(const FGameplayTag& Tag) const;
/**
* Validates whether a gameplay tag is registered in the engine's tag table.
* Returns false + logs warning for unregistered tags.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Tags|Validation")
bool ValidateTag(const FGameplayTag& Tag) const;
/**
* Validates that a tag exists AND returns it. Fails gracefully with warning.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Tags|Validation")
FGameplayTag RequestTag(FName TagName, bool bLogWarning = true) const;
// ========================================================================
// Debug / Tooling
// ========================================================================
/** Prints all registered tags to the output log. Editor-only. */
UFUNCTION(BlueprintCallable, Category = "Framework|Tags|Debug")
void LogAllTags() const;
/**
* Exports all tags matching a namespace prefix as a formatted string.
* Useful for auditing discrepancies between Data Tables and DefaultGameplayTags.ini.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Tags|Tooling")
FString ExportTagNamespace(const FString& NamespacePrefix) const;
// ========================================================================
// Overrides
// ========================================================================
virtual void PostLoad() override;
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
};

View File

@@ -0,0 +1,169 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — FL_GameUtilities (02)
// Shared Blueprint Function Library. In C++, all functions are static template/inline
// with proper null-safety — no BP workarounds needed.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "GameplayTagContainer.h"
#include "FL_GameUtilities.generated.h"
class UGI_GameFramework;
class APC_CoreController;
/**
* FL_GameUtilities — Static utility functions available from any Blueprint or C++.
*
* In C++, these are proper static functions with template type-safety.
* The Blueprint version requires macro wrappers for subsystem access —
* here we get clean UFUNCTION(BlueprintCallable) with fast native paths.
*/
UCLASS()
class FRAMEWORK_API UFL_GameUtilities : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
// ========================================================================
// Subsystem Access (Null-Safe)
// ========================================================================
/**
* Safe subsystem retrieval — returns nullptr instead of crashing.
* Use this instead of raw GetSubsystem() everywhere.
*/
template<typename T>
static T* GetSubsystemSafe(const UObject* WorldContextObject)
{
if (!WorldContextObject)
{
UE_LOG(LogTemp, Warning, TEXT("FL_GameUtilities::GetSubsystemSafe — Invalid WorldContextObject"));
return nullptr;
}
const UGameInstance* GameInstance = WorldContextObject->GetWorld()->GetGameInstance();
if (!GameInstance)
{
UE_LOG(LogTemp, Warning, TEXT("FL_GameUtilities::GetSubsystemSafe — No GameInstance found"));
return nullptr;
}
T* Subsystem = GameInstance->GetSubsystem<T>();
if (!Subsystem)
{
UE_LOG(LogTemp, Warning, TEXT("FL_GameUtilities::GetSubsystemSafe — Subsystem '%s' not found"),
*T::StaticClass()->GetName());
}
return Subsystem;
}
// Blueprint-accessible subsystem getters (UFUNCTION wrappers for the template)
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Utilities",
meta = (WorldContext = "WorldContextObject"))
static UGI_GameFramework* GetGameFramework(const UObject* WorldContextObject);
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Utilities",
meta = (WorldContext = "WorldContextObject", DeterminesOutputType = "SubsystemClass"))
static UGameInstanceSubsystem* GetSubsystemByClass(const UObject* WorldContextObject,
TSubclassOf<UGameInstanceSubsystem> SubsystemClass);
// ========================================================================
// Actor Utilities
// ========================================================================
/**
* Finds the first component on an actor that implements a given interface.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Utilities")
static UActorComponent* FindComponentByInterface(AActor* Actor,
TSubclassOf<UInterface> InterfaceClass);
/**
* Finds the nearest actor within a radius that has a specific gameplay tag.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Utilities",
meta = (WorldContext = "WorldContextObject"))
static AActor* FindNearestActorWithTag(const UObject* WorldContextObject,
FVector Origin, float Radius, FGameplayTag RequiredTag);
// ========================================================================
// Math Utilities
// ========================================================================
/** Remap a value from [InMin, InMax] to [OutMin, OutMax]. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Math")
static float RemapFloat(float Value, float InMin, float InMax, float OutMin, float OutMax);
/** Linear interpolation clamped to [0, 1]. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Math")
static float LerpClamped(float A, float B, float Alpha);
/** Convert a direction vector to a 2D angle in degrees. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Math")
static float VectorToAngle2D(FVector2D Direction);
/** Shortest signed angle difference between two angles in degrees. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Math")
static float AngleDifference(float A, float B);
// ========================================================================
// GameplayTag Utilities
// ========================================================================
/** Safe gameplay tag check — returns false if actor has no tag container. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Tags")
static bool HasGameplayTag(AActor* Actor, FGameplayTag Tag);
/**
* Creates a gameplay tag from a string with validation.
* Returns EmptyTag and logs warning if the tag isn't registered.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Tags")
static FGameplayTag MakeTagFromString(const FString& TagString, bool bLogWarning = true);
// ========================================================================
// Text Utilities
// ========================================================================
/** Format seconds into HH:MM:SS string. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Text")
static FText FormatTime(float TotalSeconds);
/** Returns singular or plural form based on count. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Text")
static FText Pluralise(const FText& Singular, const FText& Plural, int32 Count);
/** Truncates text to MaxLength with ellipsis. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Text")
static FText TruncateText(const FText& Text, int32 MaxLength);
// ========================================================================
// Screen / Projection Utilities
// ========================================================================
/**
* Projects a world position to screen space.
* bIsOnScreen is false if the point is behind the camera.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Screen",
meta = (WorldContext = "WorldContextObject"))
static bool WorldToScreenSafe(const UObject* WorldContextObject, FVector WorldPosition,
FVector2D& OutScreenPosition, bool& bIsOnScreen);
// ========================================================================
// Debug (Shipping-safe)
// ========================================================================
/** Debug log — stripped from shipping builds. */
UFUNCTION(BlueprintCallable, Category = "Framework|Debug")
static void DebugLog(const FString& Message, bool bPrintToScreen = false,
float ScreenDuration = 5.0f, FColor ScreenColor = FColor::Cyan);
/** Draw debug sphere in world — stripped from shipping builds. */
UFUNCTION(BlueprintCallable, Category = "Framework|Debug")
static void DebugSphere(const UObject* WorldContextObject, FVector Location,
float Radius = 50.0f, FColor Color = FColor::Green, float Duration = 5.0f);
};

View File

@@ -0,0 +1,226 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — GI_GameFramework (04)
// Application kernel GameInstance. Owns all SS_ subsystems, manages game phases,
// platform initialization, save slot ownership, and service resolution.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "GameplayTagContainer.h"
#include "GI_GameFramework.generated.h"
// Forward declarations
class UDA_GameTagRegistry;
class USS_SaveManager;
class USS_UIManager;
class USS_SettingsSystem;
class USS_EnhancedInputManager;
class USS_AchievementSystem;
class USS_AudioManager;
/**
* Game Phase — top-level application state.
* Transitions are server-authoritative; clients receive via OnRep_GamePhase.
*/
UENUM(BlueprintType)
enum class EGamePhase : uint8
{
MainMenu UMETA(DisplayName = "Main Menu"),
Loading UMETA(DisplayName = "Loading"),
InGame UMETA(DisplayName = "In Game"),
Paused UMETA(DisplayName = "Paused"),
Cutscene UMETA(DisplayName = "Cutscene"),
DeathLoop UMETA(DisplayName = "Death Loop"),
AltDeathSpace UMETA(DisplayName = "Alt Death Space"),
Credits UMETA(DisplayName = "Credits"),
PostGame UMETA(DisplayName = "Post Game"),
};
/** Platform type for platform-specific initialization routing. */
UENUM(BlueprintType)
enum class EPlatformType : uint8
{
Generic UMETA(DisplayName = "Generic (PC)"),
Steam UMETA(DisplayName = "Steam"),
PS5 UMETA(DisplayName = "PlayStation 5"),
Xbox UMETA(DisplayName = "Xbox Series X|S"),
Switch UMETA(DisplayName = "Nintendo Switch"),
};
// ============================================================================
// Delegates (Event Dispatchers)
// ============================================================================
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGamePhaseChanged, EGamePhase, NewPhase);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnPlatformReady);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnFrameworkReady);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnFrameworkInitFailed, const FString&, ErrorReason);
/**
* GI_GameFramework — Application Kernel.
*
* The single persistent object that lives for the entire application session.
* Owns all SS_ GameInstanceSubsystems, manages save slot ownership, provides
* the canonical service resolver (GetService()), and tracks the top-level
* game phase state machine.
*
* In C++, this replaces the Blueprint "Get Game Instance → Cast → Get Subsystem"
* pattern with clean template access via GetService<T>().
*/
UCLASS()
class FRAMEWORK_API UGI_GameFramework : public UGameInstance
{
GENERATED_BODY()
public:
UGI_GameFramework();
// ========================================================================
// Lifecycle
// ========================================================================
virtual void Init() override;
virtual void Shutdown() override;
// ========================================================================
// Configuration
// ========================================================================
/** Hard reference to the tag registry Data Asset. Loaded during Init. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Config")
TObjectPtr<UDA_GameTagRegistry> TagRegistry;
/** If true, validates all tags during Init. Recommended: true for development. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Config")
bool bValidateTagsOnInit = true;
/** If true, logs all registered tags to the output log during Init. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Debug")
bool bLogTagsOnInit = false;
/** Platform override. Determined automatically; can be overridden via command-line: -Platform=Steam */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Platform")
EPlatformType PlatformType = EPlatformType::Generic;
// ========================================================================
// Game Phase State Machine
// ========================================================================
/** Current top-level game phase. Server-authoritative; replicated to clients. */
UPROPERTY(BlueprintReadOnly, Category = "Framework|State")
EGamePhase CurrentGamePhase = EGamePhase::MainMenu;
/**
* Sets the game phase and broadcasts OnGamePhaseChanged.
* Server-authoritative. No-ops if phase is unchanged.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|State")
void SetGamePhase(EGamePhase NewPhase);
/** Returns whether the framework has completed initialization. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|State")
bool IsFrameworkReady() const { return bFrameworkInitialized; }
// ========================================================================
// Session Flags (Transient, Non-Persisted)
// ========================================================================
/** Gets a session flag value. Returns false if the flag doesn't exist. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Session")
bool GetSessionFlag(FGameplayTag FlagTag) const;
/** Sets a session flag. Creates it if it doesn't exist. */
UFUNCTION(BlueprintCallable, Category = "Framework|Session")
void SetSessionFlag(FGameplayTag FlagTag, bool bValue);
/** Clears all session flags. Called on new game start. */
UFUNCTION(BlueprintCallable, Category = "Framework|Session")
void ClearAllSessionFlags();
// ========================================================================
// Save Slot Management
// ========================================================================
/** Currently active save slot index (-1 = none). */
UPROPERTY(BlueprintReadOnly, Category = "Framework|Save")
int32 ActiveSlotIndex = -1;
/** Designates the active save slot. Does NOT trigger a load. */
UFUNCTION(BlueprintCallable, Category = "Framework|Save")
void SetActiveSlot(int32 SlotIndex);
// ========================================================================
// Service Resolution
// ========================================================================
/**
* Canonical subsystem accessor. Maps a GameplayTag to a subsystem class.
* Returns nullptr and logs warning if tag isn't mapped or subsystem unavailable.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Services")
UGameInstanceSubsystem* GetService(FGameplayTag ServiceTag) const;
/** Template accessor for type-safe subsystem retrieval. */
template<typename T>
T* GetService() const
{
return GetSubsystem<T>();
}
// ========================================================================
// First-Launch State
// ========================================================================
/** True until onboarding/intro sequence clears it. */
UPROPERTY(BlueprintReadOnly, Category = "Framework|State")
bool bFirstLaunch = true;
// ========================================================================
// Event Dispatchers
// ========================================================================
/** Broadcast when game phase changes. All systems react to this — never poll CurrentGamePhase. */
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnGamePhaseChanged OnGamePhaseChanged;
/** Broadcast when platform-specific initialization is complete. */
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnPlatformReady OnPlatformReady;
/** Broadcast when framework initialization is complete and tag registry is validated. */
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnFrameworkReady OnFrameworkReady;
/** Broadcast if framework initialization fails (missing tag registry, zero tags, etc.). */
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnFrameworkInitFailed OnFrameworkInitFailed;
protected:
// ========================================================================
// Internal State
// ========================================================================
bool bFrameworkInitialized = false;
/** Map of GameplayTag → bool for session-scoped flags. */
UPROPERTY()
TMap<FGameplayTag, bool> SessionFlags;
/** Maps service GameplayTags to subsystem classes. Populated during Init. */
UPROPERTY()
TMap<FGameplayTag, TSubclassOf<UGameInstanceSubsystem>> ServiceRegistry;
// ========================================================================
// Internal Methods
// ========================================================================
/** Platform-specific initialization routing. */
void InitPlatformServices();
/** Validates the tag registry and logs results. */
void ValidateFrameworkTags();
/** Builds the ServiceRegistry map of GameplayTag → SubsystemClass. */
void RegisterServices();
};

View File

@@ -0,0 +1,127 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — GM_CoreGameMode (05)
// Core Game Mode. Server-authoritative session rules, player spawning, chapter
// transitions, death routing. In C++, extends the replicated GameMode base for
// full networking support.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "GameplayTagContainer.h"
#include "GM_CoreGameMode.generated.h"
// Forward declarations
class UGI_GameFramework;
class AGS_CoreGameState;
class APC_CoreController;
class APS_CorePlayerState;
// Delegates
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnChapterTransition, FGameplayTag, NewChapter);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGameOverTriggered, FGameplayTag, EndingTag);
/**
* GM_CoreGameMode — Core Game Mode.
*
* 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.
*
* Server-authoritative. Extends AGameModeBase for replication support.
*/
UCLASS()
class FRAMEWORK_API AGM_CoreGameMode : public AGameModeBase
{
GENERATED_BODY()
public:
AGM_CoreGameMode();
// ========================================================================
// Default Classes (Set in Blueprint or Config)
// ========================================================================
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Framework|Classes")
TSubclassOf<APC_CoreController> PlayerControllerClass;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Framework|Classes")
TSubclassOf<APS_CorePlayerState> PlayerStateClass;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Framework|Classes")
TSubclassOf<AGS_CoreGameState> GameStateClass;
// ========================================================================
// Chapter Management
// ========================================================================
/** The currently active chapter GameplayTag. */
UPROPERTY(BlueprintReadOnly, Category = "Framework|Narrative")
FGameplayTag CurrentChapterTag;
/**
* Transitions the game to a new chapter.
* Server-authoritative. Sets phase to Loading, opens the chapter level,
* then restores InGame phase on load complete.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Narrative")
void TransitionToChapter(FGameplayTag ChapterTag);
// ========================================================================
// Death Handling
// ========================================================================
/**
* Handles player death. Called by BPC_DeathHandlingSystem.
* Idempotent — safe to call multiple times.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Death")
void HandlePlayerDead(AController* DeadController);
// ========================================================================
// Ending / Game Over
// ========================================================================
/**
* Triggers a specific ending condition.
* Passes the ending tag to BPC_EndingAccumulator for accumulation logic.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Narrative")
void TriggerEnding(FGameplayTag EndingTag);
// ========================================================================
// Pause Control
// ========================================================================
/** Runtime flag — menu widgets check this before pausing. False during cutscenes/death. */
UPROPERTY(BlueprintReadOnly, Category = "Framework|State")
bool bPauseAllowed = true;
// ========================================================================
// Event Dispatchers
// ========================================================================
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnChapterTransition OnChapterTransition;
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnGameOverTriggered OnGameOverTriggered;
// ========================================================================
// Overrides
// ========================================================================
virtual void InitGame(const FString& MapName, const FString& Options, FString& ErrorMessage) override;
virtual void BeginPlay() override;
protected:
/** Cached reference to the framework GameInstance. */
UPROPERTY()
TObjectPtr<UGI_GameFramework> CachedFramework;
/** Server-side: performs the actual level transition for a chapter. */
void ServerTransitionToChapter(FGameplayTag ChapterTag);
/** Called when the chapter level finishes loading. */
void OnChapterLevelLoaded(FGameplayTag ChapterTag);
};

View File

@@ -0,0 +1,144 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — GS_CoreGameState (06)
// Shared session state. Fully replicated singleton visible to all players.
// Tracks chapter, narrative phase, encounter status, and active objectives.
// C++ gives us proper GetLifetimeReplicatedProps() and OnRep_ handlers.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameStateBase.h"
#include "GameplayTagContainer.h"
#include "Net/UnrealNetwork.h"
#include "GS_CoreGameState.generated.h"
// Delegates
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnChapterChanged, FGameplayTag, NewChapter);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnNarrativePhaseChanged, FGameplayTag, NewPhase);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnEncounterStateChanged, bool, bActive);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnObjectiveTagsChanged);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPlayTimeUpdated, float, ElapsedSeconds);
/**
* GS_CoreGameState — Shared Session State.
*
* A replicated singleton data holder. All modification happens through
* dedicated setter functions — never direct variable writes.
*
* In C++, replication is handled via GetLifetimeReplicatedProps() with
* OnRep_ handlers that mirror broadcast dispatchers for both network
* clients and local single-player.
*/
UCLASS()
class FRAMEWORK_API AGS_CoreGameState : public AGameStateBase
{
GENERATED_BODY()
public:
AGS_CoreGameState();
// ========================================================================
// Replicated State
// ========================================================================
/** Elapsed play time (accumulated only when GamePhase is InGame). */
UPROPERTY(ReplicatedUsing = OnRep_ElapsedPlayTime, BlueprintReadOnly, Category = "Framework|State")
float ElapsedPlayTime = 0.0f;
/** Current story chapter tag. */
UPROPERTY(ReplicatedUsing = OnRep_ActiveChapter, BlueprintReadOnly, Category = "Framework|Narrative")
FGameplayTag ActiveChapterTag;
/** Sub-chapter narrative phase. */
UPROPERTY(ReplicatedUsing = OnRep_NarrativePhase, BlueprintReadOnly, Category = "Framework|Narrative")
FGameplayTag ActiveNarrativePhase;
/** Whether an AI encounter is currently active. */
UPROPERTY(ReplicatedUsing = OnRep_EncounterActive, BlueprintReadOnly, Category = "Framework|Combat")
bool bEncounterActive = false;
/** Array of active objective tags. */
UPROPERTY(ReplicatedUsing = OnRep_ObjectiveTags, BlueprintReadOnly, Category = "Framework|Narrative")
TArray<FGameplayTag> ActiveObjectiveTags;
// ========================================================================
// Setters (Server-Authoritative)
// ========================================================================
UFUNCTION(BlueprintCallable, Category = "Framework|Narrative")
void SetChapter(FGameplayTag ChapterTag);
UFUNCTION(BlueprintCallable, Category = "Framework|Narrative")
void SetNarrativePhase(FGameplayTag PhaseTag);
UFUNCTION(BlueprintCallable, Category = "Framework|Combat")
void SetEncounterActive(bool bActive);
UFUNCTION(BlueprintCallable, Category = "Framework|Narrative")
void AddObjective(FGameplayTag ObjectiveTag);
UFUNCTION(BlueprintCallable, Category = "Framework|Narrative")
void RemoveObjective(FGameplayTag ObjectiveTag);
UFUNCTION(BlueprintCallable, Category = "Framework|Narrative")
void ClearAllObjectives();
// ========================================================================
// Event Dispatchers
// ========================================================================
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnPlayTimeUpdated OnElapsedPlayTimeUpdated;
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnChapterChanged OnChapterChanged;
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnNarrativePhaseChanged OnNarrativePhaseChanged;
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnEncounterStateChanged OnEncounterActiveStateChanged;
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
FOnObjectiveTagsChanged OnObjectiveTagsChanged;
// ========================================================================
// Overrides
// ========================================================================
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
protected:
// ========================================================================
// OnRep Handlers — Fire dispatchers for network clients AND local single-player
// ========================================================================
UFUNCTION()
void OnRep_ElapsedPlayTime();
UFUNCTION()
void OnRep_ActiveChapter();
UFUNCTION()
void OnRep_NarrativePhase();
UFUNCTION()
void OnRep_EncounterActive();
UFUNCTION()
void OnRep_ObjectiveTags();
// ========================================================================
// Internal
// ========================================================================
/** Cached GameInstance for phase checking during time accumulation. */
UPROPERTY()
TObjectPtr<class UGI_GameFramework> CachedFramework;
/** Throttle timer for play time updates (fires ~1/sec). */
float TimeUpdateAccumulator = 0.0f;
static constexpr float TimeUpdateInterval = 1.0f;
};

View File

@@ -0,0 +1,317 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — Framework Interfaces (03)
// All 9 Blueprint Interfaces defined in C++ for clean default values and type safety.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "GameplayTagContainer.h"
#include "I_InterfaceLibrary.generated.h"
// ============================================================================
// Forward Declarations
// ============================================================================
class UDA_ItemData;
class UDA_InteractionData;
// ============================================================================
// I_Interactable — World objects the player can interact with
// ============================================================================
UINTERFACE(MinimalAPI, BlueprintType, meta = (CannotImplementInterfaceInBlueprint))
class UInteractable : public UInterface
{
GENERATED_BODY()
};
class FRAMEWORK_API IInteractable
{
GENERATED_BODY()
public:
/** Called when a player interacts with this object. Returns true if interaction succeeded. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
bool OnInteract(AActor* Interactor);
/** Called when crosshair/focus enters this object. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void OnFocusBegin(AActor* Interactor);
/** Called when crosshair/focus leaves this object. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void OnFocusEnd(AActor* Interactor);
/** Returns the interaction prompt text (e.g. "Open Door", "Pick Up"). */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
FText GetInteractionPrompt() const;
/** Returns whether interaction is currently possible. BlockReason explains why if false. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
bool CanInteract(AActor* Interactor, FText& OutBlockReason) const;
/** Returns the GameplayTag identifying the interaction type (e.g. Framework.Interaction.Type.Pickup). */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
FGameplayTag GetInteractionType() const;
};
// ============================================================================
// I_Inspectable — Objects that can be examined in 3D inspect mode
// ============================================================================
UINTERFACE(MinimalAPI, BlueprintType)
class UInspectable : public UInterface
{
GENERATED_BODY()
};
class FRAMEWORK_API IInspectable
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void StartInspect(AActor* Inspector);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void EndInspect(AActor* Inspector);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void RotateInspect(FRotator RotationDelta);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
bool GetInspectData(FVector& OutAnchorPoint, FRotator& OutDefaultRotation, float& OutZoomDistance) const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
bool HasInspectInfo() const;
};
// ============================================================================
// I_Damageable — Anything that takes damage or can be healed
// ============================================================================
UINTERFACE(MinimalAPI, BlueprintType)
class UDamageable : public UInterface
{
GENERATED_BODY()
};
class FRAMEWORK_API IDamageable
{
GENERATED_BODY()
public:
/** Apply damage. Returns actual damage dealt after modifiers. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
float TakeDamage(float DamageAmount, AActor* DamageCauser, FGameplayTag DamageType, FVector HitLocation, FVector HitDirection);
/** Heal by amount. Returns actual health restored. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
float Heal(float HealAmount, AActor* Healer);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
bool IsAlive() const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
float GetCurrentHealth() const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
float GetMaxHealth() const;
/** Called when health reaches zero. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
void OnDeath(AActor* Killer, FGameplayTag DeathCause);
/** Returns multiplier for incoming damage (e.g. 1.5 = takes 50% more damage). */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Combat")
float GetDamageModifier(FGameplayTag DamageType) const;
};
// ============================================================================
// I_Holdable — Physics objects the player can grab and manipulate
// ============================================================================
UINTERFACE(MinimalAPI, BlueprintType)
class UHoldable : public UInterface
{
GENERATED_BODY()
};
class FRAMEWORK_API IHoldable
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void OnPickup(AActor* Holder);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void OnDrop(AActor* Dropper);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
FTransform GetHoldTransform() const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
bool IsHeld() const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void OnReleasedFromHold();
};
// ============================================================================
// I_Lockable — Objects that can be locked/unlocked with key items
// ============================================================================
UINTERFACE(MinimalAPI, BlueprintType)
class ULockable : public UInterface
{
GENERATED_BODY()
};
class FRAMEWORK_API ILockable
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
bool TryLock(AActor* Locker);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
bool TryUnlock(AActor* Unlocker, FGameplayTag KeyTag);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
bool IsLocked() const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
FGameplayTag GetRequiredKeyTag() const;
/** Broadcast when lock state changes (implementor fires via delegate). */
virtual void OnLockStateChanged(bool bNewLocked) {}
};
// ============================================================================
// I_UsableItem — Items that can be used from inventory/quick-slots
// ============================================================================
UINTERFACE(MinimalAPI, BlueprintType)
class UUsableItem : public UInterface
{
GENERATED_BODY()
};
class FRAMEWORK_API IUsableItem
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Inventory")
bool UseItem(AActor* User, AActor* Target);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Inventory")
bool CanUseItem(AActor* User, AActor* Target) const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Inventory")
float GetUseDuration() const;
/** Called after UseItem completes (for animations, effects). */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Inventory")
void OnItemUsed(AActor* User);
};
// ============================================================================
// I_Persistable — Actors that save/load their state to disk
// ============================================================================
UINTERFACE(MinimalAPI, BlueprintType)
class UPersistable : public UInterface
{
GENERATED_BODY()
};
class FRAMEWORK_API IPersistable
{
GENERATED_BODY()
public:
/** Serialize state to a byte array for saving. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Save")
TArray<uint8> OnSave();
/** Restore state from a previously saved byte array. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Save")
void OnLoad(const TArray<uint8>& Data);
/** Returns the unique GameplayTag identifier for this persistable actor. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Save")
FGameplayTag GetSaveTag() const;
/** Returns true if this actor has changed since last save. */
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Save")
bool NeedsSave() const;
};
// ============================================================================
// I_Toggleable — Objects with binary on/off states
// ============================================================================
UINTERFACE(MinimalAPI, BlueprintType)
class UToggleable : public UInterface
{
GENERATED_BODY()
};
class FRAMEWORK_API IToggleable
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void Toggle(AActor* Toggler);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void SetState(bool bNewState, AActor* Setter);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
bool GetCurrentState() const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
FText GetStateLabel() const;
/** Broadcast when state changes. */
virtual void OnStateChanged(bool bNewState, AActor* Changer) {}
};
// ============================================================================
// I_Adjustable — Objects with continuous value range (dials, sliders)
// ============================================================================
UINTERFACE(MinimalAPI, BlueprintType)
class UAdjustable : public UInterface
{
GENERATED_BODY()
};
class FRAMEWORK_API IAdjustable
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void Adjust(float Delta, AActor* Adjuster);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
void SetValue(float NewValue, AActor* Setter);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
float GetCurrentValue() const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
float GetMinValue() const;
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Framework|Interaction")
float GetMaxValue() const;
/** Broadcast when value changes. */
virtual void OnValueChanged(float NewValue, AActor* Changer) {}
};