Dynamic Attitude & Multiplayer
Attitude is never stored - it is computed on demand from the current tags on both sides via GetTeamAttitudeBetween. That makes it always-correct for direct queries (damage, targeting, UI). The hard part is the systems that cache attitude. Unreal's AI perception is the worst offender: it evaluates affiliation once per stimulus and never re-checks, so a mid-game defection would otherwise leave AI treating a new enemy as a friend forever.
How a change propagates
| Step | What happens |
|---|---|
| 1. Mutate (server) | JoinTeam / AddHostileTags / ... change the replicated TeamTags / HostileToTags |
| 2. Broadcast | The component fires OnTeamTagsChanged / OnHostileTagsChanged with the owning actor (on the server now, and on clients via OnRep) |
| 3. Refresh perception | The subsystem (which registered every agent) re-evaluates each AI perceiver via RequestStimuliListenerUpdate - preserving last-known-location, no ForgetActor |
| 4. Notify | UCrimsonTeamSubsystem::OnTeamAttitudeChanged(ChangedActor) broadcasts for any custom AI/UI re-evaluation |
Because the refresh re-runs affiliation rather than forgetting the actor, an AI that should now see a new enemy starts perceiving it, and one whose enemy became friendly stops - both without losing what they already knew.
The interface-on-actor rule
Perception reads attitude with FGenericTeamId::GetAttitude(PerceiverActor, Target), which casts the perceiving actor to IGenericTeamAgentInterface. CrimsonTeams puts that interface on the component, so the actor must also expose it (forwarding to GetTeamAttitudeBetween) for perception to read Crimson teams. A component added by UGFA_AddTeams (CrimsonCore - requires all Crimson plugins) cannot supply an interface - interfaces are compile-time on the class - so this forward lives on your AI controller/pawn (CrimsonCore's classes already have it). See How-To: Make an Actor a Team Agent, step 3.
HasAuthority() is true; clients get the result by replication and re-fire the change delegate from OnRep so client-side UI updates. A client-side mutation silently no-ops.Replication summary
| State | Mechanism |
|---|---|
TeamTags / HostileToTags (per agent) | ReplicatedUsing -> OnRep re-broadcasts the change delegate on clients |
| Team info actor + its tag | Replicated ACrimsonTeamPublicInfo; ACrimsonTeamPrivateInfo is server/owner-scoped |
| Faction tag stacks | FCrimsonTagStackContainer on the team info actor (FastArray, delta-replicated) |