How-To: Form Parties
Goal: let players invite each other into a party that stays together across level travel and a dropped connection, and have every party member count as Friendly the moment they join.
1. Give every PlayerState a party member component
UCrimsonPartyMemberComponent is the only per-actor piece. It is added on the server and replicates to clients on its own; the party subsystem is always present. Pick one path:
| Path | When to use |
|---|---|
| Add Component in your PlayerState Blueprint | Your own PlayerState class - always present, no setup |
| `UCrimsonGameFeatureAction_AddParty` ("Add Party System" Game Feature action) | Enable parties from a mode or feature without editing the PlayerState: list the PlayerState class in Player State List. A PlayerState that already has the component is left alone |
Open your PlayerState Blueprint -> Add Component -> Crimson Party Member. Nothing to configure on the component itself.
2. Set the rules
Open Project Settings -> Crimson -> Crimson Teams. Every value has a working default:
| Setting | Meaning | Default |
|---|---|---|
Default Max Party Size | Size a party gets when created without an override | 4 |
Absolute Max Party Size | Hard cap, including leader-requested size changes | 8 |
Invite Lifetime Seconds | How long an invite (or an invite suggestion) stays open | 60 |
Offline Member Grace Seconds | How long a disconnected member keeps their slot. Level travel counts as offline time, so keep this above your longest load. 0 keeps the slot until kicked | 300 |
Only Leader Can Invite | When on, other members can still suggest an invite to the leader | on |
Invite Attitude Gate | Which team attitudes (inviter toward target) may be invited: Friendly Only, Friendly & Neutral, or Any. Friendly is always allowed | Friendly & Neutral |
Member Location Update Interval | Seconds between last-known-location samples the server replicates to the party (drives minimap markers and teleport-to-member at any distance). 0 disables | 1 |
Member Location Min Delta | A member is re-sent only after moving this far (cm) | 100 |
Default Party Max Range | Party reach (cm) for players without ICrimsonPartyRangeProvider; members farther away are out of range and dimmed in the party UI. 0 = unlimited | 0 |
Party Info Class | The replicated party actor to spawn; subclass ACrimsonPartyInfo to add data | ACrimsonPartyInfo |
3. Send and answer invites
Every request lives on the member component and works from the owning client (it RPCs to the server) or on the server directly. The server validates and answers on On Operation Result with the operation and an ECrimsonPartyResult; anything but Success left the party untouched.
| Request | What it does |
|---|---|
Invite Player (Target) | Invites the target's PlayerState. If you have no party one is created with you as leader |
Accept Invite (Invite Id) / Decline Invite | From an entry in Get Pending Invites. Accepting leaves your current party first |
Cancel Invite (Invite Id) | Withdraws an invite you sent (Get Sent Invites) |
Suggest Invite (Target) | Non-leaders ask the leader to invite someone; it lands in the leader's Get Pending Invite Suggestions, who calls Accept Invite Suggestion or Dismiss Invite Suggestion |
Leave Party | The longest-standing online member becomes leader if you led; an emptied party dissolves |
Kick Member (Id) / Promote Leader (Id) / Set Max Party Size (N) | Leader only. Kick also frees an offline member's slot early |
Invite button -> Invite Player (Target = the other player's PlayerState, from Get Player State on their pawn or the Game State's Player Array). Event On Invite Received (on your own component) -> show a prompt -> Accept Invite (Invite Id from the event's Invite). Event On Operation Result -> if Result != Success, show the reason (Party Full, Attitude Blocked, Not Leader, ...).
To gray out an Invite button before the click, call Can Invite Player (Inviter, Target) on the Crimson Party Subsystem - it evaluates the same rules from replicated state on the client.
4. React to party changes
Three hooks, pick by where your logic runs:
| Hook | Fires | Runs on |
|---|---|---|
On Party State Changed on the member component | Joining or leaving, the party actor arriving, and every roster / leader / max-size change of your party | Server and every client that has the component |
| Observe Party Blueprint async node | Same as above, as a latent node with Is In Party, Party Id, and the Party Info actor | Wherever you place it |
On Party Message on UCrimsonPartySubsystem (OnPartyMessageNative in C++): a Crimson.Party.Message.* channel tag plus an FCrimsonPartyMessage payload | Created, Dissolved, MemberJoined, MemberLeft, MemberOnlineChanged, LeaderChanged, MaxSizeChanged, InviteReceived, InviteResolved, InviteSuggested | Server (exact LeaveReason / InviteResolution), and clients from replicated state |
Observe Party (Party Agent = your PlayerState) -> On Party Changed (Is In Party, Party Id, Party Info) -> Get Members on Party Info -> rebuild your party frames. Party Info can be none on a client for a frame or two after Is In Party turns true; the node fires again when it arrives.
Mechanics that run off the party (minimap markers, teleport to a member, shared loot) read UCrimsonPartyStatics: Get Party Members / Get Other Party Members for PlayerStates, Get Party Member Pawns for the pawns replicated to you, and Get Party Member Locations (or Get Party Member Location for one) for a member who is out of net-relevancy range - the server samples every online member's pawn at Member Location Update Interval and replicates it to the party, so the location is there whether or not the pawn is.
Get Party Member Locations (Agent = your pawn) -> For Each -> project Location onto the minimap. Teleport: Get Party Member Location (Member = the chosen PlayerState) -> Branch on the return value -> your teleport logic with the location. On Member Locations Changed on the party info actor (from Get Party Info) fires when a fresh sample lands.
5. Give players a party reach
Range-gated party mechanics (teleport to a member, shared loot, a marker that fades with distance) ask Is Party Member In Range / Get Party Members In Range, and the party UI dims a member who is out of reach. The reach belongs to the player, not the project - a mage might reach 30 m while an oracle reaches 100 m - so it comes from ICrimsonPartyRangeProvider on the pawn (checked first), the PlayerState, or the PlayerController. Players without an implementer use Default Party Max Range from the settings; leave that at 0 and nothing is ever out of range. Test it with the PartyRanges console cheat, which prints your reach and every member's distance.
Open your character Blueprint -> Class Settings -> Interfaces -> add Crimson Party Range Provider. Implement Get Party Max Range and return the reach in centimeters (3000 for 30 m). Then Is Party Member In Range (Agent = your pawn, Member = the PlayerState) gates the mechanic.
6. Show real names
Rosters and invites carry an FText display name resolved on the server. By default it is the PlayerState name. To show an account name, a character name, or anything else, implement ICrimsonPartyDisplayNameProvider on your PlayerState (checked first) or PlayerController and return the text from Get Party Display Name. Return empty text to fall back.
PlayerState Blueprint -> Class Settings -> Interfaces -> Add Crimson Party Display Name Provider -> implement Get Party Display Name -> return your character name.
PartyInvite <name>, PartyAccept, PartyLeave, ListParties (see How-To: Debug at Runtime (Dev Tools)).See also
- Concept: Parties - where party state lives, what replicates to whom, and what happens on travel and disconnect
- How-To: Query Attitude & Gate Damage - the attitude queries that already treat party members as Friendly
- API Reference -> Parties