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.

Prerequisites
CrimsonTeams enabled (Quick Start). Parties work with or without declared teams; the invite gate in step 2 only matters once players carry team tags.

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:

PathWhen to use
Add Component in your PlayerState BlueprintYour 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:

SettingMeaningDefault
Default Max Party SizeSize a party gets when created without an override4
Absolute Max Party SizeHard cap, including leader-requested size changes8
Invite Lifetime SecondsHow long an invite (or an invite suggestion) stays open60
Offline Member Grace SecondsHow 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 kicked300
Only Leader Can InviteWhen on, other members can still suggest an invite to the leaderon
Invite Attitude GateWhich team attitudes (inviter toward target) may be invited: Friendly Only, Friendly & Neutral, or Any. Friendly is always allowedFriendly & Neutral
Member Location Update IntervalSeconds between last-known-location samples the server replicates to the party (drives minimap markers and teleport-to-member at any distance). 0 disables1
Member Location Min DeltaA member is re-sent only after moving this far (cm)100
Default Party Max RangeParty reach (cm) for players without ICrimsonPartyRangeProvider; members farther away are out of range and dimmed in the party UI. 0 = unlimited0
Party Info ClassThe replicated party actor to spawn; subclass ACrimsonPartyInfo to add dataACrimsonPartyInfo
Project Settings -> Crimson -> Crimson Teams: the party rules.

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.

RequestWhat 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 InviteFrom 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 PartyThe 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:

HookFiresRuns on
On Party State Changed on the member componentJoining or leaving, the party actor arriving, and every roster / leader / max-size change of your partyServer and every client that has the component
Observe Party Blueprint async nodeSame as above, as a latent node with Is In Party, Party Id, and the Party Info actorWherever you place it
On Party Message on UCrimsonPartySubsystem (OnPartyMessageNative in C++): a Crimson.Party.Message.* channel tag plus an FCrimsonPartyMessage payloadCreated, Dissolved, MemberJoined, MemberLeft, MemberOnlineChanged, LeaderChanged, MaxSizeChanged, InviteReceived, InviteResolved, InviteSuggestedServer (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.

Debug it live
The Crimson Teams Dev Tools window has a Parties tab: pick an actor and a target, then Invite / Suggest / Accept / Leave / Kick / Promote from the server context and watch the roster and the per-player invite lists update on each client. Console: 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