I can’t seem to find a straight answer on google. I have six characters in my project, and I want them all to use the same attribute sets but with different attribute values. I thought one way to do this would be to make a data table for each character with all their attribute values, but I’m not sure how to initialize the attributes using this method.
One shared attribute set is the right setup. Different characters are just different base values, and the engine already has a path for that: a Data Table of row type AttributeMetaData, applied with InitStats.
-
Keep a single attribute set. Each FGameplayAttributeData (Health, MaxHealth, and so on) is one row in the table. Do not make a set per character.
-
Content Browser, Miscellaneous, Data Table. Row structure: AttributeMetaData (the engine struct). One table per character is fine. Row Name must be the attribute name exactly, for example Health or MaxHealth, not the character name. BaseValue is the column that matters. MinValue and MaxValue are optional.
-
The set has to be registered on the ASC before you init it. Create it as a default subobject in the pawn constructor, or AddAttributeSetSubobject / AddSpawnedAttribute in PossessedBy.
-
On the server only, after the set exists:
AbilitySystem->InitStats(UMyAttributeSet::StaticClass(), CharacterTable);
Call that from PossessedBy, not from a client BeginPlay. InitStats writes the base value, and current starts equal to base. Call it once. Calling it again will not refresh a value that a GameplayEffect has already modified.
- Point each character BP at its own table with an EditDefaultsOnly UDataTable* on the pawn, and pass that pointer in. Same set class for all six.
For respawn or a class change, do not call InitStats again. Use an instant GameplayEffect with Override modifiers (one GE per character, or SetByCaller magnitudes). That goes through the normal replication path. InitStats is only the initial base.
The ASC on a pawn should replicate (Mixed or Full). Read the values back with GetGameplayAttributeValue on the ASC, not from a separate float that never replicates.
A custom row struct is only worth it if you need extra columns. Then skip AttributeMetaData, loop the rows, resolve the FGameplayAttribute by name, and call SetNumericAttributeBase. Same rule: server, and only after the set is registered.