- Implemented DA_EquipmentConfig for managing equipment resistances, durability, and weight. - Created DA_ItemData to serve as a base item data asset with various item types and properties. - Introduced BPC_HealthSystem for managing player health and death events. - Added BPC_MovementStateSystem to handle player movement modes with event delegation. - Developed BPC_StaminaSystem to track player stamina and exhaustion states. - Established BPC_StateManager as a central authority for managing player action states and gating. - Created BPC_StressSystem to monitor and respond to player stress levels. - Implemented PC_CoreController and PS_CorePlayerState for player controller and state management. - Developed SS_SaveManager for save/load functionality with slot management and serialization. - Introduced DA_StateGatingTable for defining action gating rules based on gameplay tags. - Added BPC_DamageReceptionSystem to process incoming damage and apply resistance calculations. - Implemented BPC_HitReactionSystem for managing hit reactions based on damage received. - Created BPC_ShieldDefenseSystem to manage shield health and blocking mechanics. - Added PG_FrameworkEditor.Target.cs for editor build configuration.
247 lines
9.2 KiB
C++
247 lines
9.2 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
// UE5 Modular Game Framework — BPC_StateManager (130)
|
|
// Central State Authority. Single source of truth for "what can the player do right now?"
|
|
// Manages exclusive action states, upper-body overlay states, action gating,
|
|
// vital signs (heart rate), and the force-stack pattern for nested overrides.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Components/ActorComponent.h"
|
|
#include "GameplayTagContainer.h"
|
|
#include "BPC_StateManager.generated.h"
|
|
|
|
// Forward declarations
|
|
class UDA_StateGatingTable;
|
|
class UBPC_HealthSystem;
|
|
class UBPC_StressSystem;
|
|
class UBPC_StaminaSystem;
|
|
class UBPC_MovementStateSystem;
|
|
|
|
// ============================================================================
|
|
// Delegates
|
|
// ============================================================================
|
|
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnActionStateChanged, FGameplayTag, NewState, FGameplayTag, OldState);
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnOverlayStateChanged, FGameplayTag, NewOverlay, FGameplayTag, OldOverlay);
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnVitalSignChanged, FGameplayTag, VitalTag, float, NewValue);
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnForceStackPushed, FGameplayTag, ForceState);
|
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnForceStackPopped, FGameplayTag, RestoredState);
|
|
|
|
/**
|
|
* Result codes for state change requests.
|
|
* Mirrors the Blueprint E_ActionRequestResult enum.
|
|
*/
|
|
UENUM(BlueprintType)
|
|
enum class EActionRequestResult : uint8
|
|
{
|
|
Granted UMETA(DisplayName = "Granted"),
|
|
Denied UMETA(DisplayName = "Denied — Gated"),
|
|
BlockedByForce UMETA(DisplayName = "Blocked — Force Stack Override"),
|
|
AlreadyActive UMETA(DisplayName = "Already Active"),
|
|
InvalidState UMETA(DisplayName = "Invalid State Tag"),
|
|
RequesterNotFound UMETA(DisplayName = "Requester Not Found"),
|
|
CooldownActive UMETA(DisplayName = "Cooldown Active"),
|
|
VitalThreshold UMETA(DisplayName = "Vital Threshold Not Met"),
|
|
};
|
|
|
|
/**
|
|
* Heart rate tier for vital sign tracking.
|
|
*/
|
|
UENUM(BlueprintType)
|
|
enum class EHeartRateTier : uint8
|
|
{
|
|
Resting UMETA(DisplayName = "Resting (60-80 BPM)"),
|
|
Elevated UMETA(DisplayName = "Elevated (80-100 BPM)"),
|
|
Stressed UMETA(DisplayName = "Stressed (100-130 BPM)"),
|
|
Panic UMETA(DisplayName = "Panic (130-160 BPM)"),
|
|
Critical UMETA(DisplayName = "Critical (160+ BPM)"),
|
|
};
|
|
|
|
/**
|
|
* BPC_StateManager — Central State Authority.
|
|
*
|
|
* Every system queries IsActionPermitted(Tag) instead of checking other systems
|
|
* directly. Gating rules are defined in DA_StateGatingTable (37 rules).
|
|
* In C++, the Chooser Table iteration is native-speed — no BP interpretive overhead.
|
|
*/
|
|
UCLASS(Blueprintable, ClassGroup = (Framework), meta = (BlueprintSpawnableComponent))
|
|
class FRAMEWORK_API UBPC_StateManager : public UActorComponent
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
UBPC_StateManager();
|
|
|
|
// ========================================================================
|
|
// Configuration
|
|
// ========================================================================
|
|
|
|
/** The gating rules Data Asset. Contains all 37 action rules. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Config")
|
|
TObjectPtr<UDA_StateGatingTable> GatingTable;
|
|
|
|
/** Default action state on BeginPlay. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Config")
|
|
FGameplayTag DefaultActionState;
|
|
|
|
/** Default overlay state on BeginPlay. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Config")
|
|
FGameplayTag DefaultOverlayState;
|
|
|
|
// ========================================================================
|
|
// Core Query — Hot Path
|
|
// ========================================================================
|
|
|
|
/**
|
|
* Central query: "Can the player perform this action right now?"
|
|
* Called by EVERY gameplay system per-frame. C++ makes this fast.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|State")
|
|
bool IsActionPermitted(FGameplayTag ActionTag) const;
|
|
|
|
/**
|
|
* Request a state change. Returns the result code.
|
|
* Server-authoritative.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "Framework|State")
|
|
EActionRequestResult RequestStateChange(FGameplayTag NewState, AActor* Requester);
|
|
|
|
// ========================================================================
|
|
// Current State (Read-Only)
|
|
// ========================================================================
|
|
|
|
/** Currently active exclusive action state (only one at a time). */
|
|
UPROPERTY(BlueprintReadOnly, Category = "Framework|State")
|
|
FGameplayTag CurrentActionState;
|
|
|
|
/** Currently active upper-body overlay state. */
|
|
UPROPERTY(BlueprintReadOnly, Category = "Framework|State")
|
|
FGameplayTag CurrentOverlayState;
|
|
|
|
// ========================================================================
|
|
// Force Stack Pattern (Death, Cutscenes, Void Space)
|
|
// ========================================================================
|
|
|
|
/**
|
|
* Pushes a forced state onto the stack. Overrides all gating.
|
|
* Example: death overrides everything.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "Framework|State")
|
|
void ForceStateChange(FGameplayTag ForceState, FString Reason);
|
|
|
|
/**
|
|
* Pops the top forced state and restores the previous state.
|
|
* Example: respawn restores the pre-death state.
|
|
*/
|
|
UFUNCTION(BlueprintCallable, Category = "Framework|State")
|
|
void RestorePreviousState();
|
|
|
|
/** Returns the number of states currently on the force stack. */
|
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|State")
|
|
int32 GetForceStackDepth() const { return ForceStack.Num(); }
|
|
|
|
// ========================================================================
|
|
// Vital Signs — Heart Rate
|
|
// ========================================================================
|
|
|
|
/** Current heart rate in BPM (smoothed). */
|
|
UPROPERTY(BlueprintReadOnly, Category = "Framework|Vitals")
|
|
float HeartRateBPM = 70.0f;
|
|
|
|
/** Current heart rate tier. */
|
|
UPROPERTY(BlueprintReadOnly, Category = "Framework|Vitals")
|
|
EHeartRateTier HeartRateTier = EHeartRateTier::Resting;
|
|
|
|
/** Target heart rate (set by stress, stamina, combat). Interpolated toward each tick. */
|
|
UPROPERTY(BlueprintReadOnly, Category = "Framework|Vitals")
|
|
float TargetHeartRate = 70.0f;
|
|
|
|
/** Smoothing speed for heart rate interpolation. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Vitals")
|
|
float HeartRateSmoothSpeed = 2.0f;
|
|
|
|
// ========================================================================
|
|
// Event Dispatchers
|
|
// ========================================================================
|
|
|
|
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
|
|
FOnActionStateChanged OnActionStateChanged;
|
|
|
|
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
|
|
FOnOverlayStateChanged OnOverlayStateChanged;
|
|
|
|
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
|
|
FOnVitalSignChanged OnVitalSignChanged;
|
|
|
|
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
|
|
FOnForceStackPushed OnForceStackPushed;
|
|
|
|
UPROPERTY(BlueprintAssignable, Category = "Framework|Events")
|
|
FOnForceStackPopped OnForceStackPopped;
|
|
|
|
// ========================================================================
|
|
// Overrides
|
|
// ========================================================================
|
|
|
|
virtual void BeginPlay() override;
|
|
virtual void TickComponent(float DeltaTime, ELevelTick TickType,
|
|
FActorComponentTickFunction* ThisTickFunction) override;
|
|
|
|
protected:
|
|
// ========================================================================
|
|
// Internal State
|
|
// ========================================================================
|
|
|
|
/** Force stack — array of (State, Reason) pairs. Most recent is active. */
|
|
struct FForceStackEntry
|
|
{
|
|
FGameplayTag State;
|
|
FString Reason;
|
|
};
|
|
|
|
TArray<FForceStackEntry> ForceStack;
|
|
|
|
/** Previous action state before force override (for restore). */
|
|
FGameplayTag PreForceActionState;
|
|
|
|
/** Previous overlay state before force override (for restore). */
|
|
FGameplayTag PreForceOverlayState;
|
|
|
|
// ========================================================================
|
|
// Gating Logic
|
|
// ========================================================================
|
|
|
|
/** Check gating rules for a tag against current state. */
|
|
bool EvaluateGatingRules(FGameplayTag ActionTag) const;
|
|
|
|
/** Check if any force stack entry blocks this action. */
|
|
bool IsBlockedByForceStack(FGameplayTag ActionTag) const;
|
|
|
|
// ========================================================================
|
|
// Vital Sign Calculation
|
|
// ========================================================================
|
|
|
|
/** Recalculates target heart rate based on stress tier + stamina exhaustion + combat. */
|
|
void RecalculateTargetHeartRate();
|
|
|
|
/** Determines heart rate tier from current BPM. */
|
|
static EHeartRateTier GetHeartRateTier(float BPM);
|
|
|
|
// ========================================================================
|
|
// Binding References (cached in BeginPlay)
|
|
// ========================================================================
|
|
|
|
UPROPERTY()
|
|
TObjectPtr<UBPC_HealthSystem> CachedHealthSystem;
|
|
|
|
UPROPERTY()
|
|
TObjectPtr<UBPC_StressSystem> CachedStressSystem;
|
|
|
|
UPROPERTY()
|
|
TObjectPtr<UBPC_StaminaSystem> CachedStaminaSystem;
|
|
|
|
UPROPERTY()
|
|
TObjectPtr<UBPC_MovementStateSystem> CachedMovementSystem;
|
|
};
|