Add core gameplay systems and data assets for player mechanics

- 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.
This commit is contained in:
Lefteris Notas
2026-05-21 14:38:30 +03:00
parent a145ae9373
commit f986343325
50 changed files with 86 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — BPC_InventorySystem (31)
// Core inventory grid. Add/remove/sort/stack/weight management.
// In C++, TArray operations with lambdas are natively fast — no BP array node overhead.
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "GameplayTagContainer.h"
#include "BPC_InventorySystem.generated.h"
class UDA_ItemData;
/**
* Single inventory slot entry.
*/
USTRUCT(BlueprintType)
struct FRAMEWORK_API FInventorySlot
{
GENERATED_BODY()
/** The item in this slot. nullptr = empty slot. */
UPROPERTY(BlueprintReadOnly)
TObjectPtr<UDA_ItemData> Item = nullptr;
/** How many of this item are stacked here. */
UPROPERTY(BlueprintReadOnly)
int32 Quantity = 0;
/** Grid position for UI layout. */
UPROPERTY(BlueprintReadOnly)
int32 GridX = 0;
/** Grid position for UI layout. */
UPROPERTY(BlueprintReadOnly)
int32 GridY = 0;
bool IsEmpty() const { return Item == nullptr || Quantity <= 0; }
void Clear()
{
Item = nullptr;
Quantity = 0;
}
bool operator==(const FInventorySlot& Other) const
{
return Item == Other.Item && Quantity == Other.Quantity && GridX == Other.GridX && GridY == Other.GridY;
}
};
// Delegates
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInventoryChanged);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnItemAdded, UDA_ItemData*, Item, int32, Quantity);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnItemRemoved, UDA_ItemData*, Item, int32, Quantity);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnWeightChanged, float, CurrentWeight, float, MaxWeight);
/**
* BPC_InventorySystem — Core Inventory Grid.
*
* Manages the player's carried items: add, remove, sort, stack, weight tracking.
* C++ TArray operations (FindByPredicate, Sort, Filter) are natively compiled —
* no BP interpretive array node overhead.
*/
UCLASS(Blueprintable, ClassGroup = (Framework), meta = (BlueprintSpawnableComponent))
class FRAMEWORK_API UBPC_InventorySystem : public UActorComponent
{
GENERATED_BODY()
public:
UBPC_InventorySystem();
// ========================================================================
// Configuration
// ========================================================================
/** Grid width (columns). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Inventory|Config")
int32 GridWidth = 8;
/** Grid height (rows). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Inventory|Config")
int32 GridHeight = 5;
/** Maximum carry weight. Items exceeding this cannot be picked up. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Framework|Inventory|Config")
float MaxWeight = 50.0f;
// ========================================================================
// Inventory State
// ========================================================================
/** All inventory slots (GridWidth × GridHeight). */
UPROPERTY(BlueprintReadOnly, Category = "Framework|Inventory")
TArray<FInventorySlot> Slots;
/** Current total weight carried. */
UPROPERTY(BlueprintReadOnly, Category = "Framework|Inventory")
float CurrentWeight = 0.0f;
/** Whether the inventory has been modified since last save. */
UPROPERTY(BlueprintReadOnly, Category = "Framework|Inventory")
bool bDirty = false;
// ========================================================================
// Core Operations
// ========================================================================
/**
* Add an item to the inventory. Stacks if possible, finds empty slot otherwise.
* Returns the quantity actually added (may be less than requested if full).
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Inventory")
int32 AddItem(UDA_ItemData* Item, int32 Quantity = 1);
/**
* Remove an item from the inventory.
* Returns the quantity actually removed.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Inventory")
int32 RemoveItem(UDA_ItemData* Item, int32 Quantity = 1);
/**
* Remove an item from a specific slot.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Inventory")
int32 RemoveItemFromSlot(int32 SlotIndex, int32 Quantity = 1);
/**
* Check if an item can be added (enough space and weight capacity).
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Inventory")
bool CanAddItem(UDA_ItemData* Item, int32 Quantity = 1) const;
// ========================================================================
// Query
// ========================================================================
/** Returns the total quantity of an item across all stacks. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Inventory")
int32 GetItemCount(UDA_ItemData* Item) const;
/** Returns whether the inventory contains at least this many of an item. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Inventory")
bool HasItem(UDA_ItemData* Item, int32 Quantity = 1) const;
/** Finds the first slot containing the given item. Returns -1 if not found. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Inventory")
int32 FindItemSlot(UDA_ItemData* Item) const;
/** Returns all unique items currently in the inventory. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Inventory")
TArray<UDA_ItemData*> GetAllItems() const;
/** Returns the number of empty slots available. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Inventory")
int32 GetEmptySlotCount() const;
/** Returns the number of free weight units remaining. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Inventory")
float GetRemainingWeight() const;
// ========================================================================
// Organization
// ========================================================================
/** Sort inventory by ItemType, then by DisplayName. */
UFUNCTION(BlueprintCallable, Category = "Framework|Inventory")
void SortInventory();
/** Auto-merge all partial stacks of the same item. */
UFUNCTION(BlueprintCallable, Category = "Framework|Inventory")
void ConsolidateStacks();
// ========================================================================
// Event Dispatchers
// ========================================================================
UPROPERTY(BlueprintAssignable, Category = "Framework|Inventory|Events")
FOnInventoryChanged OnInventoryChanged;
UPROPERTY(BlueprintAssignable, Category = "Framework|Inventory|Events")
FOnItemAdded OnItemAdded;
UPROPERTY(BlueprintAssignable, Category = "Framework|Inventory|Events")
FOnItemRemoved OnItemRemoved;
UPROPERTY(BlueprintAssignable, Category = "Framework|Inventory|Events")
FOnWeightChanged OnWeightChanged;
// ========================================================================
// Overrides
// ========================================================================
virtual void BeginPlay() override;
protected:
/** Recalculates total weight from all slots. */
void RecalculateWeight();
/** Finds an existing stack for an item (not at max stack limit). Returns -1 if none found. */
int32 FindExistingStack(UDA_ItemData* Item) const;
/** Finds the first empty slot. Returns -1 if inventory is full. */
int32 FindEmptySlot() const;
/** Marks inventory as modified and broadcasts change dispatchers. */
void MarkDirty();
};

View File

@@ -0,0 +1,37 @@
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "GameplayTagContainer.h"
#include "DA_EquipmentConfig.generated.h"
USTRUCT(BlueprintType)
struct FRAMEWORK_API FDamageTypeResistance
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FGameplayTag DamageType;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Resistance = 0.0f;
};
UCLASS(BlueprintType)
class FRAMEWORK_API UDA_EquipmentConfig : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Config")
TArray<FDamageTypeResistance> DamageTypeResistances;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Config")
float Durability = 100.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Config")
float Weight = 1.0f;
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Config")
float GetResistance(FGameplayTag DamageType) const;
};

View File

@@ -0,0 +1,232 @@
// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — DA_ItemData (07)
// Base item Data Asset. Single source of truth for every item.
// C++ gives us UPROPERTY metadata (EditCondition, EditConditionHides, ClampMin/Max)
// that make the Data Asset editor usable for designers — impossible in Blueprint.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "GameplayTagContainer.h"
#include "Engine/Texture2D.h"
#include "Engine/StaticMesh.h"
#include "DA_ItemData.generated.h"
/**
* Item type classification.
*/
UENUM(BlueprintType)
enum class EItemType : uint8
{
Weapon UMETA(DisplayName = "Weapon"),
Ammo UMETA(DisplayName = "Ammo"),
Consumable UMETA(DisplayName = "Consumable"),
KeyItem UMETA(DisplayName = "Key Item"),
Document UMETA(DisplayName = "Document"),
Collectible UMETA(DisplayName = "Collectible"),
Tool UMETA(DisplayName = "Tool"),
Resource UMETA(DisplayName = "Resource"),
Misc UMETA(DisplayName = "Misc"),
};
/**
* Equipment slot type.
*/
UENUM(BlueprintType)
enum class EEquipmentSlot : uint8
{
None UMETA(DisplayName = "None"),
PrimaryWeapon UMETA(DisplayName = "Primary Weapon"),
SecondaryWeapon UMETA(DisplayName = "Secondary Weapon"),
Melee UMETA(DisplayName = "Melee"),
Tool UMETA(DisplayName = "Tool"),
Armor UMETA(DisplayName = "Armor"),
Accessory UMETA(DisplayName = "Accessory"),
};
/**
* Equipment-specific data (shown when ItemType is Weapon or Tool).
*/
USTRUCT(BlueprintType)
struct FRAMEWORK_API FItemEquipmentData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
EEquipmentSlot Slot = EEquipmentSlot::None;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Damage = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float FireRate = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Range = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 MagazineSize = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float ReloadTime = 0.0f;
};
/**
* Consumable-specific data (shown when ItemType is Consumable).
*/
USTRUCT(BlueprintType)
struct FRAMEWORK_API FItemConsumableData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = "0", ClampMax = "100"))
float HealthRestore = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = "0", ClampMax = "100"))
float StressReduce = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float UseDuration = 1.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bConsumedOnUse = true;
};
/**
* Inspect-specific data (shown when bHasInspectMode is true).
*/
USTRUCT(BlueprintType)
struct FRAMEWORK_API FItemInspectData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FVector AnchorPoint = FVector::ZeroVector;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
FRotator DefaultRotation = FRotator::ZeroRotator;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float ZoomDistance = 50.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
bool bCanRotate = true;
};
/**
* DA_ItemData — Base Item Data Asset.
*
* Every item in the game is one DA_ItemData asset. No item data lives in
* Blueprint logic. C++ gives us EditCondition metadata so the editor only
* shows relevant sub-structs based on ItemType — a massive UX win for designers.
*/
UCLASS(BlueprintType, Blueprintable, meta = (DisplayName = "Item Data"))
class FRAMEWORK_API UDA_ItemData : public UPrimaryDataAsset
{
GENERATED_BODY()
public:
UDA_ItemData();
// ========================================================================
// Core Properties (Every Item Has These)
// ========================================================================
/** Unique GameplayTag identifier. Must be registered in DA_GameTagRegistry. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Core")
FGameplayTag ItemTag;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Core")
FText DisplayName;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Core", meta = (MultiLine = true))
FText Description;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Core")
TSoftObjectPtr<UTexture2D> Icon;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Core")
TSoftObjectPtr<UStaticMesh> WorldMesh;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Core", meta = (ClampMin = "0", ClampMax = "1000"))
float Weight = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Core", meta = (ClampMin = "1", ClampMax = "999"))
int32 StackLimit = 1;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Core")
EItemType ItemType = EItemType::Misc;
// ========================================================================
// Conditional Sub-Data (Shown Based on ItemType via EditCondition)
// ========================================================================
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Equipment",
meta = (EditCondition = "ItemType == EItemType::Weapon || ItemType == EItemType::Tool", EditConditionHides))
FItemEquipmentData EquipmentData;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Consumable",
meta = (EditCondition = "ItemType == EItemType::Consumable", EditConditionHides))
FItemConsumableData ConsumableData;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Inspect",
meta = (EditCondition = "bHasInspectMode", EditConditionHides))
FItemInspectData InspectData;
// ========================================================================
// Flags
// ========================================================================
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Flags")
bool bIsKeyItem = false;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Flags")
bool bCanBeDropped = true;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Flags")
bool bHasInspectMode = false;
// ========================================================================
// Combination / Crafting
// ========================================================================
/** Tags of items this can combine with. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Combination")
TArray<FGameplayTag> CombinesWith;
/** The resulting item tag when combined with CombinesWith item. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Combination")
FGameplayTag CombineResult;
// ========================================================================
// Extensibility
// ========================================================================
/** Custom per-project properties — no need to modify the base class. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Item|Custom")
TMap<FName, FString> CustomProperties;
// ========================================================================
// Validation (Editor-Only)
// ========================================================================
#if WITH_EDITOR
/**
* Validates the item data asset for common errors.
* Called by editor utilities or pre-save validation.
*/
UFUNCTION(BlueprintCallable, Category = "Item|Validation")
bool ValidateItemData(FString& OutErrors) const;
#endif
// ========================================================================
// Overrides
// ========================================================================
virtual void PostLoad() override;
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
};