๐งฉ RPG ATTRIBUTES SYSTEM
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\

UCharacterAttributeSetComponent - Attributes Component

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.

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:


Pay extra attention to the
signatureof Formula Functions!They must always follow the format of an input
Feature Dataand an output ofInt64forFEATURES!They must always follow the format of an input
Attribute Dataand an output ofInt64forATTRIBUTES!


Attribute Modifiers - Networked Effects
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.

-
Note that you cannot apply Modifiers to an Attribute that did not register that Modifier as an Archetype!
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:


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:
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:

Attributes Preview - Preview Panel
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:

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
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:
๐งฐ Attribute, Feature & Modifier Sets
๐ What are "Sets"?
Sets in this attribute system are Blueprintable DataAsset templates used to define shared defaults for:
- Attributes
- Features
- Modifiers
- Traits
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:
- Open the attribute or feature instance in the Details Panel
- Locate the
Constantsslot - Assign an appropriate Set (e.g.,
CharacterAttributeSetfor attributes)
Once attached, the system reads from the setโs
DefaultDataand uses its parameters as initialization or fallback values.
๐งช Example Use Cases
๐งฌ Shared Feature Base
You create a StrengthFeatureSet with:
FeatureTag = ftr.strengthBaseValue = 100BaseTable = CharacterStatsTable
Attach this to all classes needing a Strength feature with the same baseline.
โ๏ธ Shared Modifier Logic
You define a PoisonModifierSet:
- Modifier Tag:
mod.poison - Lifetime:
10 seconds - Stackable:
True, Stack Interval:1 sec
Now any attribute referencing this modifier gets the same behavior, ensuring balance across entities.
๐จ UI Support
Each set can also define:
- Custom icon (SlateBrush)
- Description text
- Color coding
- Button style for UI styling
These assets support both editor tooling and runtime visualization.
โ Sets Summary
- Sets offer a clean and centralized way to manage attribute, feature, and modifier definitions
- They are ideal for prototyping, consistency, and reusability
- Use the
Constantsfield to assign them in the editor
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
- ๐ Multiplayer-Ready Replication via
GameplayTagsand subobject replication - โ๏ธ Component-Based Attribute & Feature Management
- ๐งฎ Customizable Attribute Formulas
- ๐ Attribute Entanglement for Dependency Chains
- ๐ก Blueprint-Friendly Modifier System
- ๐ Preview Tools for Debugging & Balancing
๐งฉ 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
TArray<CharacterFeature*> FeaturesTArray<CharacterAttribute*> Attributes
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

โ Best Practices
- Avoid Blueprint subclassing of
AttributeSetComponent - Use consistent
GameplayTags - Register modifiers with
ModArchetypes - Prevent circular entanglements
- Prefer Blueprint formula functions for design flexibility
๐ (BONUS) EXP / Level โ Attack Power Relationship
๐งฑ System Setup Overview
In this system:
Experienceis typically aCharacter Featurethat tracks progress.Levelis anotherCharacter Featurethat is derived fromExperience.Attack Poweris often aCharacter Attribute, but it depends onLevelto scale.
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
Experienceis updated, recalculateLevel'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:
Experienceis updated (e.g., viaAddModifierorSetBaseValue)Experiencetriggers recalculation ofLevelvia entanglementLevelrecalculatesAttack Powerthrough its own formula- UI updates based on
GetFormulatedValue()ofAttack 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 |
Note on some versions of the Unreal Engine 5, these panels may be disabled due to an ongoing visual rework of these panels!