๐Ÿงฉ RPG ATTRIBUTES SYSTEM


ATT


Introduction

This is implementation of a performant, generic, multiplayer-ready Attribute System for RPG / RTS projects.
The system works by network replicating Gameplay Tags instead of reproducing the raw state of Unreal Objects.
With this setup we can create complex attribute calculations without having to rework the network code everytime game decide to change some idea of implementation details of a project.
Since RPG games require a ridiculous large amount of attribute calculations, across multiple entangled systems, this is a core component for the development of any higher level system to be implemented.


Example Component

NOTE: Sample Blueprint can be found in folder: \ATT\Content\Example\

ATT_Sample


UCharacterAttributeSetComponent - Attributes Component


ATT_Sample

The Attribute Set Component is properly setup to create, manage the memory, and replicate the data of UCharacterFeature and UCharacterAttribute sub-objects that you create within the Details Panel.
Although it's possible to create Blueprints of this component, it's recommended that you add the base Component Class to character blueprints instead, to avoid conflicts with Unreal's serialization system where components of instantiated blueprints can ignore changes to the base component blueprint if the fields of that instance are marked as 'Dirty' (modified by the user). This is just a minor flaw of the Unreal Editor, but can confuse developers regularly.

The Attributes Component can host two sets of properties:

UCharacterFeature - Character Features are attributes that usually will serve as base attributes to more dynamic attributes. The main characteristics of these properties are that they can simply output a Base Value or have that same value computed by an input Data Table. In this case the GetFormulatedValue() method will automatically consider the existence of a table and return the computed value, whereas the Base Value access will return the base, simple, raw replicated value of the attribute...

UCharacterAttribute - Character Attributes are a little different from Features in the sense that Attributes can be mapped to a Curve Table from its Base Value, instead of Tables, and can also by default be linked to adjacent Attributes with their Attribute Tag address. When an Attribute instance has a Min/Max assigned tag, its own GetFormulatedValue() method will automatically take that external input into consideration when generating the final value.


ATT_GetFormulatedValue

GetFormulatedValue() - Custom Fomulas

Although Attribute Modifiers can be blueprinted, and spawned as blueprints objects, Attributes and Features cannot!
Still, there are many situations where designers are going to need or wish they just had a blueprint to develop custom attribute formulas. There's no deny the great usefulness of blueprints, but if go on converting everything to blueprints then they become a performance problem later on.
To address this problem, to create custom formulas, designers can generate functions within the parent character blueprint where the function name is mapped to the Gameplay Tag address of that Attribute or Feature.

For example:

The Attribute Experience is mapped to a | Level | EXP | Data Table and, to return the correct value, the GetFormulatedValue() method of the EXP Attribute would have to track first the actual value of another Attribute: Level. The current output of the Level Attribute can be many, will depend on how many items, weapons, accessories, the character has active that can influence the final value...
But the output value of Experience Attribute requires to know the real base value, so we can map the Attribute Tag to a custom Blueprint Function defined on the Character Blueprint itself and query the actual base value of the Level Attribute every time we have to update the display value of the Exerience Attribute from the Data Table automatically mapped to the base value of the Level Attribute:

ATT_CustomFormula

ATT_CustomFormulaGraph



ATT_Signature

ATT_FormulaUse ATT_FormulaSignature


Attribute Modifiers - Networked Effects


ATT_MakeModifier

Modifiers are regular Blueprinted Objects. They cannot Tick and have no World Transform, but contain several helper functions to author any level of attribute calculation you might want to achieve.

ATT_Modifier

You must register the Archetype Class of a Modifier to the ModArchetypes list within the "System" section of each Attribute considering to use that Modifier sub system;
Otherwise the Modifier will not work across the network:

ATT_ModArchetypes

ATT_ApplyModifier


Attributes Entanglement - Server Pre-Calculations


In RTS / RPG systems, very frequently, a designed rule requires an attribute to automatically update itself on the Server when another related attribute in the same component has changed.
We can't escape this in modern games, but these calculations on the background can cause a networking flood if not taken care closely, one replicated attribute will trigger another and so on...
To avoid networking issues, we then create several Helper Functions to conform each different design pattern for each type of attribute before packing a struct to send accross the network.
That as well can lead to several calls to different RPCs.

One way to avoid those problems is simply mapping Entangled Attributes to this pre-determined list of Base Value transformations we call *Entanglement.
So instead of creating a custom Formula for every attribute, we tell the subsystem that every time the Base Value of the Level Atribute changes, we want the Base Value of Experience to be updated as well, at the same frame:

ATT_Entanglement

Then when we set a new value to Level, the Server will performs its authoritative powers to update the property value of Experience to everyone, so we can stop coding already at the Set Base Value for the Level Attribute:

ATT_FeatureEntanglement


Attributes Preview - Preview Panel


ATT_Preview

To quickly check if you have got your Data Tables or Data Curves setup correctly, you can check the Preview from your Attribute Set Component's Details Panel and see if the values aren't exactly what you're expecting coming out from the GetFormulatedValue() method:

ATT_Panels

! Note on some versions of the Unreal Engine 5, these panels may be disabled due to an ongoing visual rework of these panels!


Gameplay Tags - Unreal Gameplay Tags System


ATT_Settings

The Attribute System by default registers several default Gameplay Tags, but you can either change what is registered by editing the in the ATT_AttributeData.cpp source, or disable them from plugins settings:

ATT_DefaultTags


๐Ÿงฐ Attribute, Feature & Modifier Sets

๐Ÿ” What are "Sets"?

Sets in this attribute system are Blueprintable DataAsset templates used to define shared defaults for:

They simplify prototyping and ensure consistency across multiple instances by allowing reuse of predefined configurations such as base values, gameplay tags, curves, and even UI styles.


๐Ÿงฑ Types of Sets

Set Class Applies To Data Structure Used
CharacterFeatureSet Character Features FHKH_CharacterFeatureData
CharacterAttributeSet Character Attributes FHKH_CharacterAttributeData
CharacterAttributeModifierSet Attribute Modifiers FHKH_CharacterAttributeModifierData
CharacterTraitSet Traits FHKH_CharacterTraitData

Each set acts as a container for initialization data, styling, and specialization logic.


๐Ÿงท Attaching Sets to Attributes or Features

To attach a set to an attribute or feature:

  1. Open the attribute or feature instance in the Details Panel
  2. Locate the Constants slot
  3. Assign an appropriate Set (e.g., CharacterAttributeSet for attributes)

Once attached, the system reads from the setโ€™s DefaultData and uses its parameters as initialization or fallback values.


๐Ÿงช Example Use Cases

๐Ÿงฌ Shared Feature Base

You create a StrengthFeatureSet with:

Attach this to all classes needing a Strength feature with the same baseline.

โš”๏ธ Shared Modifier Logic

You define a PoisonModifierSet:

Now any attribute referencing this modifier gets the same behavior, ensuring balance across entities.


๐ŸŽจ UI Support

Each set can also define:

These assets support both editor tooling and runtime visualization.


โœ… Sets Summary


Native Module:

To have access to the classes from native code you should import the plugin's module to your own, as usual:

PrivateDependencyModuleNames.AddRange(new string[] { "HKH_AttributeSystem" });
#include "HKH_AttributeSystem.h"

๐Ÿ“˜ Extended Documentation - Unreal Attribute System

๐ŸŽฎ Overview

This system implements a performant, network-replicated, and Blueprint-integrated attribute framework designed specifically for RPG and RTS projects in Unreal Engine. It uses Gameplay Tags as the primary mechanism for networking and data abstraction, reducing serialization overhead and decoupling implementation details from network logic.

๐Ÿš€ Key Features

๐Ÿงฉ Core Classes & Concepts

๐Ÿงฑ CharacterAttributeSetComponent

Main actor component that manages both Features and Attributes. Should be attached directly to Character Blueprints instead of subclassing in Blueprints to avoid Unreal's serialization inconsistencies.

Replicated Properties

Query Functions

CharacterFeature* GetFeatureByTag(FGameplayTag Tag) const;
CharacterAttribute* GetAttributeByName(FName Name) const;

๐Ÿงฌ CharacterAttribute

Defines an attribute (e.g., Health, Mana, XP). Fully network-replicated with support for custom logic, entanglement, traits, and modifiers.

Core Properties

FName AttributeName;
FGameplayTag AttributeTag;
int64 BaseValue;
FCurveTableRowHandle BaseCurve;
TMap<FGameplayTag, EntanglementType> Entanglement;

Formula Support

Custom Blueprint function:

int64 att.health(const CharacterAttributeData& Data)
{
    return Data.BaseValue + 100; // Example
}

๐Ÿ” Attribute Entanglement

Allows automatic updates of dependent attributes when a source attribute changes.

Entanglement.Add(Tag_Level, OnBaseValueChange);

๐Ÿงฑ CharacterFeature

Used for simpler or foundational attributes like Strength. Can drive complex attributes.

๐Ÿงฉ Modifiers System

Modifiers are Blueprint-spawned, non-Ticking UObject instances with formula logic to alter attributes dynamically (buffs, debuffs).

Lifecycle

bool AddModifier(FGameplayTag Tag);
bool RemoveModifier(FGameplayTag Tag);

Registration

TMap<FGameplayTag, TSubclassOf<CharacterAttributeModifier>> ModArchetypes;

๐Ÿง  Traits System

Traits represent status effects or toggles, implemented via GameplayTags.

Interface

bool AddTrait(FGameplayTag Tag);
bool IsTraitActive(FGameplayTag Tag) const;

๐Ÿงช Preview System

Use the editor details panel to preview formulas, modifiers, and values dynamically.

โš™๏ธ Integration Guide

Module Setup

PrivateDependencyModuleNames.AddRange(new string[] { "ATT" });
#include "ATT.h"

๐Ÿ”– Gameplay Tags System

Modify tags in AttributeData.cpp or disable default tags via Plugin Settings.

๐Ÿ“Š Class Diagram

ATT_Classes


โœ… Best Practices


๐Ÿ“ˆ (BONUS) EXP / Level โžœ Attack Power Relationship

๐Ÿงฑ System Setup Overview

In this system:

This means the flow of influence looks like:

flowchart LR
    A[Experience] --> B(Level)
    B --> C(Attack Power)

๐Ÿ”— Step 1: Entangling EXP with Level

To ensure Level updates when Experience changes, use entanglement:

// In Experience attribute
Entanglement.Add(FGameplayTag("Attribute.Status.LV"), EHKH_Entanglement::OnBaseValueChange);

This tells the system:

โ€œEvery time Experience is updated, recalculate Level's value.โ€


๐Ÿงฎ Step 2: Deriving Level from EXP (Custom Formula)

Create a custom Blueprint function in the Character Blueprint named:

Attribute::Status::LV

Function Signature (required by system):

int64 Attribute::Status::LV(const FCharacterAttributeData& Data)

Example Logic:

Use a DataTable mapping EXP thresholds to levels.

If EXP = 5500 โžœ LEVEL = 7
If EXP = 7800 โžœ LEVEL = 9

This Blueprint custom formula reads the EXP value and looks up the level using a table like: XPToLevelTable.


โš”๏ธ Step 3: Scaling Attack Power by Level

Now create another Blueprint function named:

Attribute::Status::ATK

This is your custom formula for Attack Power.

Function Signature:

int64 Attribute::Status::ATK(const FCharacterAttributeData& Data)

Logic Example:

int64 Level = GetAttributeByTag("Attribute.Status.LV")->GetFormulatedValue();
return Level * 10 + 25;

This means:

โ€œAttack Power increases linearly with Level. Each level gives +10 Attack Power, base value is 25.โ€


๐Ÿ”„ Real-Time Data Flow:

  1. Experience is updated (e.g., via AddModifier or SetBaseValue)
  2. Experience triggers recalculation of Level via entanglement
  3. Level recalculates Attack Power through its own formula
  4. UI updates based on GetFormulatedValue() of Attack Power

โœ… Summary

Attribute Role Formula Source Depends On
Experience Progress Tracker Raw value โ€”
Level Milestone Marker Blueprint formula using EXP Experience
Attack Power Combat Stat Blueprint formula using Level Level