CrimsonCommon · Lesson 4 of 7
Track Counts with Tag Stacks
Before you start
- Completed: Adopt the Modular Base Classes
- A replicated actor to own the stacks (a Player State is ideal)
Chapters
One container, many counters
A tag stack is a replicated map of GameplayTag → count. FCrimsonTagStackContainer holds integer counts (ammo, charges, currency) and FCrimsonFloatTagStackContainer holds floats (buildup, meters). Both ride on a FFastArraySerializer, so only the stacks that changed replicate — not the whole container.
Declare and replicate
Add the container as a replicated property on a replicated actor and register it for replication:
// MyPlayerState.hUPROPERTY(Replicated)FCrimsonTagStackContainer TagStacks;// MyPlayerState.cppvoid AMyPlayerState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const{Super::GetLifetimeReplicatedProps(OutLifetimeProps);DOREPLIFETIME(AMyPlayerState, TagStacks);}
DOREPLIFETIME line compiles fine and silently never replicates — the server sees correct counts while every client reads zero. If clients disagree with the server, check this first.Add, remove, read
Mutate on the server only: AddStack, RemoveStack, and ClearStacks (the float container adds SetStack). Read from anywhere — server or client — with GetStackCount and ContainsTag.
Blueprint uses the UCrimsonTagStackStatics function library — Add Tag Stack, Remove Tag Stack, Get Tag Stack Count, Contains Tag Stack — always behind a Has Authority branch when writing:
HasAuthority().