CrimsonTeams · Lesson 1 of 6
How Crimson Teams Works
Before you start
- None — start here
Chapters
Teams are tags
CrimsonTeams models teams as gameplay tags, not numeric ids. An actor can be on several teams at once and factions nest naturally (Team.Red, Faction.Bandit). Any actor becomes team-aware by holding a UCrimsonTeamAgentComponent.
Friend or foe
Attitude between two actors is computed live by GetTeamAttitudeBetween(Source, Target) — never stored — using a short priority order:
| Priority | Rule | Result |
| 1 | Either side's hostile tags overlap the other's team tags | Hostile |
| 2 | The two share any team tag | Friendly |
| 3 | Neither resolves a team component, or no rule matched | Neutral |
The headline feature: dynamic attitude
Because attitude is computed on demand, changing a tag at runtime instantly changes friend/foe everywhere — and the system even refreshes AI perception, which Unreal otherwise evaluates once per stimulus and never re-checks. We build up to that over this course.
What's included
| Area | Purpose |
| Membership | Per-actor team/hostile tags via UCrimsonTeamAgentComponent |
| Attitude & queries | Attitude, damage gating, GAS target filtering, agent resolution |
| Declared teams | Named teams on the Game State, player auto-assignment, replicated info actors |
| Cosmetics | Per-team material/Niagara colors via a display asset |
| Observers | Blueprint async nodes that fire on team / color change |
| GameFeature | Add the agent component + tags to actor classes from a Game Feature |
| Tooling | A multiplayer dev-tools window + CycleTeam / SetTeam / ListTeams cheats |
Decoupled by design
The team contract
ICrimsonTeamAgentInterface lives in CrimsonCommon, not here — so any plugin can read a team or attitude without depending on CrimsonTeams.