Party Implementation #

Party flows are built and customized using a combination of calls and plugin methods, which have been grouped on this page by category. Each section includes descriptions of SDK actions and related Party Plugin methods.

The categories are:

For a full list of all available calls and Party Plugin methods, see All Calls and Methods.

Create a party #

A party is initialized and the first player is added as the leader.

Actions: CreateParty Functions: initializeParty, onAddPlayer

Actions #

Create a party

The CreateParty RPC call requires the following data:

  • ExtCreateRequest: custom-defined content related to party creation
  • ExtPlayerJoinRequest: custom-defined content related to players joining
  • (optional) Game server zones: preferred game server zones, which can be changed later (see SetPreferredGameServerZones)
  • (optional) Game server zone to ping map: a ping map that can be changed later (see SetGameServerZoneToPing)
    TArray<FString> preferredGameServerZones;
    preferredGameServerZones.Add("gameServerZone1");
    preferredGameServerZones.Add("gameServerZone2");
    TMap<FString, int32> gameServerZoneToPing;
    gameServerZoneToPing.Add("gameServerZone1", 10);
    gameServerZoneToPing.Add("gameServerZone2", 20);
    UPragmaPartyService::FOnCompleteDelegate OnPartyCreatedDelegate;
    OnPartyCreatedDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
    {
    });
    Session->GameLoopApi().CreateParty(
      FPragma_Party_ExtCreateRequest{},
      FPragma_Party_ExtPlayerJoinRequest{},
      preferredGameServerZones,
      gameServerZoneToPing,
      OnPartyCreatedDelegate
    );
    
    session.GameLoopApi.CreateParty(new ExtCreateRequest(), new ExtPlayerJoinRequest());
    
      {
        "requestId": 1,
        "type": "PartyRpc.CreateV1Request",
        "payload": {
          "createRequestExt":{},
          "playerJoinRequestExt":{},
          "gameClientVersion":"gameClientVersion1",
          "preferredGameServerZones": [ "gameServerZone1", "gameServerZone2" ],
          "gameServerZoneToPing": { "gameServerZone1": 10, "gameServerZone2": 20 }
        }
      }
    

Functions #

The following function initializes the party, leveraging the data from the ExtCreateRequest.

suspend fun initializeParty(
  party: Party,
  requestExt: ExtCreateRequest,
  partyConfig: PartyConfig
)

Once the blank party is created, the first player is added as the party’s leader using the onAddPlayer function. Note that this is the same function that is used to add other players in the next section.

suspend fun onAddPlayer(
  requestExt: ExtPlayerJoinRequest,
  playerToAdd: PartyPlayer,
  party: Party,
  partyConfig: PartyConfig
)
If a player is already in a party when attempting to make a new party, they’re automatically removed from the existing party.

Join or leave a party #

Players join and leave parties.

Actions: JoinWithInviteCode, JoinWithPartyId, Leave Functions: onAddPlayer, onRemovePlayer

Actions #

Join by invite code

To join by invite code, use the JoinWithInviteCode request. This includes the following information:

  • ExtPlayerJoinRequest
  • invite code
  • game client version
  • map of pings to game server zones
    UPragmaPartyService::FOnCompleteDelegate JoinWithInviteCodeDelegate;
    JoinWithInviteCodeDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
    {
    });
    Session->GameLoopApi().JoinWithInviteCode(
      FPragma_Party_ExtPlayerJoinRequest {},
      "CDCLGP",
      JoinWithInviteCodeDelegate
    );
    
    session.Party.JoinWithInviteCode(
      new ExtPlayerJoinRequest(),
      "CDCLGP"
    );
    
    {
      "requestId": 3,
      "type": "PartyRpc.JoinWithInviteCodeV1Request",
      "payload": {
        "requestExt":{},
        "inviteCode":"CDCLGP",
        "gameClientVersion":"gameClientVersion1"
      }
    }
    

Join by party ID

To join by party ID, use the JoinWithPartyId request. This includes the following information:

  • ExtPlayerJoinRequest
  • party ID
  • game client version
  • map of pings to game server zones
    UPragmaPartyService::FOnCompleteDelegate JoinWithPartyIdDelegate;
    JoinWithPartyIdDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
    {
    });
    Session->GameLoopApi().JoinWithPartyId(
      FPragma_Party_ExtPlayerJoinRequest{},
      "5e359a34-8112-4a84-81d5-86f11f261f67",
      JoinWithPartyIdDelegate
    );
    
    session.GameLoopApi.JoinWithPartyId(
      new ExtPlayerJoinRequest(),
      "5e359a34-8112-4a84-81d5-86f11f261f67"
    );
    
    {
      "requestId": 4,
      "type": "PartyRpc.JoinWithPartyIdV1Request",
      "payload": {
        "requestExt":{},
        "partyId":"5e359a34-8112-4a84-81d5-86f11f261f67",
        "gameClientVersion":"gameClientVersion1"
      }
    }
    

Leave a party

The Leave call allows players to voluntarily leave a party.

If a leader leaves a party, a random player in the party is made leader.
UPragmaPartyService::FOnCompleteDelegate LeavePartyDelegate;
LeavePartyDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
{
});
session->GameLoopApi().LeaveParty(LeavePartyDelegate);
session.GameLoopApi.LeaveParty(LeavePartyDelegate);
{
  "requestId": 4,
  "type": "PartyRpc.LeaveV1Request",
  "payload": {
  }
}
If a player disconnects from the engine or if they log into a second client, that player will be removed from the party.

Functions #

The onAddPlayer function is used for the following calls which add players to a party: JoinWithInviteCode and JoinWithPartyId.

suspend fun onAddPlayer(
  requestExt: ExtPlayerJoinRequest,
  playerToAdd: PartyPlayer,
  party: Party,
  partyConfig: PartyConfig
)

The onRemovePlayer function is used for calls that remove players from the party.

  • This function is used when a player opts to leave a party and when a player is kicked; the RemovalReason includes which case. If a party is in matchmaking when either of these functions is called, the party is also removed from matchmaking.
suspend fun onRemovePlayer(
  party: Party,
  removedPlayer: PartyPlayer,
  removalReason: RemovalReason
)

Manage invites #

Players respond to invites and invite their friends.

Actions: SendInvite, RespondToInvite Functions: onAddPlayer

Actions #

Send an invite

The RPC call SendInvite sends an invitation to the listed player with a PartyRpc.InviteReceivedV1Notification. This request contains the player ID of the invited player.

UPragmaPartyService::FOnCompleteDelegate SendInviteDelegate;
SendInviteDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result) {});
Session->GameLoopApi().SendInvite("f9525239-cd99-425d-9f14-1ff948c02553",
  SendInviteDelegate
);
session.GameLoopApi.SendInvite(
    new PragmaId("f9525239-cd99-425d-9f14-1ff948c02553")
);
{
  "requestId": 1,
  "type": "PartyRpc.SendInviteV1Request",
  "payload": {
    "inviteePlayerId": "f9525239-cd99-425d-9f14-1ff948c02553"
  }
}

Respond to an invite

The RespondToInvite call determines whether the player will join the party they’ve been invited to.

This request contains the following information:

  • ExtPlayerJoinRequest: a developer-defined ext used to declare publicly visible player selections
  • invite ID including in the SendInvite call
  • boolean stating whether the player accepted or declined the invite
  • game client version, which is used to calculate compatible game servers
  • map of pings to game server zones
    UPragmaPartyService::FOnCompleteDelegate RespondToPartyInviteDelegate;
    RespondToPartyInviteDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
    {
    });
    Session->GameLoopApi().RespondToInvite(
      FPragma_Party_ExtPlayerJoinRequest{},
      "89962f84-7edd-45b9-97c0-b6fd49fc8497",
      true,
      RespondToPartyInviteDelegate
    );
    
    session.GameLoopApi.RespondToInvite(
      new ExtPlayerJoinRequest(),
      invite.InviteId,
      true
    );
    
    {
      "requestId": 2,
      "type": "PartyRpc.RespondToInviteV1Request",
      "payload": {
        "requestExt":{},
        "inviteId":"89962f84-7edd-45b9-97c0-b6fd49fc8497",
        "accepted":true,
        "gameClientVersion":"gameClientVersion1"
      }
    }
    

Functions #

The onAddPlayer function adds players to a party when they respond to an invite with a true boolean.

suspend fun onAddPlayer(
  requestExt: ExtPlayerJoinRequest,
  playerToAdd: PartyPlayer,
  party: Party,
  partyConfig: PartyConfig
)

Make selections #

Players make selections, including setting both player and party options.

Actions: SetGameServerZoneToPing, UpdatePlayerSelections, UpdatePartySelections Functions: updatePlayer, updateParty

Actions #

Set map to ping Individual players can call SetGameServerZoneToPing to update the map of their ping to different game server zones.

UPragmaPartyService::FOnCompleteDelegate SetGameServerZoneToPingDelegate;
SetGameServerZoneToPingDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result){});
const TMap<FString, int32> ZoneToPing = {{"us-west", 100}};
Session()->GameLoopApi().SetGameServerZoneToPing(
  ZoneToPing,
  SetGameServerZoneToPingDelegate
);
var pingMap = new Dictionary<string, int> { { "us-west", 30 } };
var future = Runtime.Player().Party.SetGameServerZoneToPing(pingMap);
{
  "requestId": 9,
  "type": "PartyRpc.SetGameServerZoneToPing",
  "payload": {
    "gameServerZoneToPing": {"us-west": 100}
  }
}

Update player selections

Update player selections using UpdatePlayerSelections. This takes the ExtUpdatePlayerSelectionsRequest parameter.

UPragmaPartyService::FOnCompleteDelegate UpdatePlayerSelectionsDelegate;
UpdatePlayerSelectionsDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result){});
Session->GameLoopApi().UpdatePlayerSelections(
  FPragma_Party_ExtUpdatePlayerSelectionsRequest{},
  UpdatePlayerSelectionsDelegate
);
session.GameLoopApi.UpdatePlayerSelections(
  new ExtUpdatePlayerSelectionsRequest()
);
{
  "requestId": 6,
  "type": "PartyRpc.UpdatePlayerSelectionsV1Request",
  "payload": {
    "requestExt": {}
  }
}

Update party selections

Update party selections using UpdatePartySelections. This takes the ExtUpdatePartySelectionsRequest parameter.

UPragmaPartyService::FOnCompleteDelegate UpdatePartySelectionsDelegate;
UpdatePartySelectionsDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result){}
);
Session->GameLoopApi().UpdatePartyV1(
  FPragma_Party_ExtUpdatePartySelectionsRequest{},
  UpdatePartySelectionsDelegate
);
session.GameLoopApi.UpdatePartySelections(
  new ExtUpdatePartySelectionsRequest()
);
{
  "requestId": 7,
  "type": "PartyRpc.UpdatePartySelectionsV1Request",
  "payload": {
    "requestExt": {}
  }
}
Example The following code block provides sample ext data.

Example: ext data
// request ext field that contains data about a party
// that can only be used on the server in plugins
message ExtHiddenPartyData {
}
// ext field for party state
message ExtPartySelections {
  bool can_queue_ranked = 1;
  party.GameMode game_mode = 2;
  party.AdventureModeDifficulty adventure_mode_difficulty = 3;
}
// ext field for player selection state within a party
message ExtPlayerSelections {
  pragma.inventory.ext.Rank current_rank = 1;
  string visible_hero_id = 2; // if your hero selection is visible, show it here
  int64 team_number = 3;
  string visible_skin_catalog_id = 4; // if your skin selection is visible, show it here
}
// ext field for private player selection state within a party
message ExtPrivatePlayerSelections {
  string desired_hero_id = 1; // which hero you have picked
  string desired_skin_catalog_id = 2; // which skin you have picked
}
// request ext field for creating a party
message ExtCreateRequest {
}
// request ext field for adding a player to a party
message ExtPlayerJoinRequest {
}
// request ext field for updating a player selection
message ExtUpdatePlayerSelectionsRequest {
  oneof update {
    string new_hero_id = 1;
    party.ChosenTeam chosen_team = 2;
    string new_skin_catalog_id = 3;
  }
}
// request ext field for updating a party selection
message ExtUpdatePartySelectionsRequest {
  oneof update {
    party.GameMode new_game_mode = 1;
    party.AdventureModeDifficulty adventure_mode_difficulty = 2;
  }
}

Functions #

The updatePlayer function allows players to make individual choices like characters, skins, or votes for maps using the ExtUpdatePlayerSelectionsRequest.

suspend fun updatePlayer(
 playerToUpdate: PartyPlayer,
 requestExt: ExtUpdatePlayerSelectionsRequest,
 party: Party,
 partyConfig: PartyConfig
)

The updateParty function allows players to set shared information like game mode, map, or difficulty using the ExtUpdatePartySelectionsRequest.

  • This call can be restricted to leader-only by writing the plugin implementation to reject changes based on roles.
suspend fun updateParty(
 requestingPlayer: PartyPlayer,
 requestExt: ExtUpdatePartySelectionsRequest,
 party: Party,
 partyConfig: PartyConfig
)

Set ready states #

Determine whether players are ready to enter matchmaking.

Actions: SetReadyState

Functions: canChangeReady

Actions #

Readying up If players can set their ready state, they should use SetReadyState which contains the ready boolean.

UPragmaPartyService::FOnCompleteDelegate SetPartyReadyDelegate;
SetPartyReadyDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
{
});
Session->GameLoopApi().SetReadyState(true, SetPartyReadyDelegate);
session.GameLoopApi.SetReadyState(true);
{
  "requestId": 5,
  "type": "PartyRpc.SetReadyStateV1Request",
  "payload": {
    "ready": "true"
  }
}

Functions #

The canChangeReady function determines whether players are able to set their own ready state.

suspend fun canChangeReady(
  player: PartyPlayer,
  newReadyState: Boolean,
  party: Party,
  partyConfig: PartyConfig
): Boolean

Assign the leader role #

Assign the leader role to another player.

This action is only available to party leaders.

To assign the leader role to another player, use the AssignPartyLeader call. This takes the player ID to assign leader status.

If PartyConfig.enableTransferPartyLeader is set to true, this call transfers the party leader role to the indicated player. If it’s set to false, a new leader is made, resulting in multiple leaders.

UPragmaPartyService::FOnCompleteDelegate AssignPartyLeaderDelegate;
AssignPartyLeaderDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
{
});
Session->GameLoopApi().AssignPartyLeader(
  "5e359a34-8112-4a84-81d5-87f11f261f77",
  AssignPartyLeaderDelegate
);
session.GameLoopApi.AssignPartyLeader("5e359a34-8112-4a84-81d5-86f11f261f67");
{
  "requestId": 3,
  "type": "PartyRpc.AssignPartyLeaderV1Request",
  "payload": {
    "playerId":"5e359a34-8112-4a84-81d5-87f11f261f77"
  }
}

Kick players #

Remove a player from a party.

This action is only available to party leaders.

To kick a player from the party, party leaders can use the KickPlayer call, which takes the player ID for the kicked player. In the case of multiple leaders, one leader can kick another leader.

Session->GameLoopApi().KickPlayer(
  PlayerId, 
  FOnCompleteDelegate& OnComplete
);
session.GameLoopApi.KickPlayer(
  playerToKickId, 
  CompleteDelegate onComplete
  )
{
  "requestId": 5,
  "type": "PartyRpc.KickV1Request",
  "payload": {
    "playerId":"5e359a34-8112-4a84-81d5-87f11f261f77"
  }
}

The target player is removed from the party and the Party Plugin’s onRemovePlayer method is invoked. The kicked player RemovedV1Notification with a removal reason of KICKED. The remaining party members receive a notification with updated party state. If the kicked player is in matchmaking with the party, the party will be removed from matchmaking.

suspend fun onRemovePlayer(
  party: Party,
  removedPlayer: PartyPlayer,
  removalReason: RemovalReason
)

Specify preferred game server zones #

Manually specify one or more preferred game server zones.

This action is only available to party leaders.

To manually specify preferred game server zones, party leaders can use the SetPreferredGameServerZones call. This sets a list of acceptable game server zones for the entire party. Matchmaking can then take into account both manual game server zone selections and all party members’ pings to each game server zone as part of its game server allocation logic.

UPragmaPartyService::FOnCompleteDelegate SetPreferredGameServerZonesDelagate;
SetPreferredGameServerZonesDelagate.BindWeakLambda(this,
[this](TPragmaResult<> Result)
    {
    });
const TArray<FString> GameServerZones = {"us-west"};
Session()->GameLoopApi().SetPreferredGameServerZones(
  GameServerZones,
  SetPreferredGameServerZonesDelagate
);
var serverZones = new List<string> { "local" }
var future = Runtime.Player().GameLoopApi.SetPreferredGameServerZones(serverZones);
{
  "requestId": 8,
  "type": "PartyRpc.SetPreferredGameServerZonesV1Request",
  "payload": {
    "preferredGameServerZones": ["us-west"]
  }
}

Enter matchmaking #

Enter matchmaking and send custom match data.

Actions: EnterMatchmaking

Functions: buildMatchmakingKey, buildExtEnterMatchmaking

When entering matchmaking, a snapshot of the party’s state is captured, and is not automatically updated with changes.

Actions #

Enter matchmaking

To enter matchmaking, the leader can send EnterMatchmaking.

  • If a player without the leader role attempts to make this call, they receive the PlayerNotLeader error.
  • If any player has not set themselves to ready, the leader who called EnterMatchmaking receives the PlayersNotReady error.
UPragmaPartyService::FOnCompleteDelegate EnterMatchmakingDelegate;
EnterMatchmakingDelegate.BindWeakLambda(this, [this](TPragmaResult<> Result)
{
});

Session->GameLoopApi().EnterMatchmaking(EnterMatchmakingDelegate);
session.GameLoopApi.EnterMatchmaking();
{
  "requestId": 8,
  "type": "PartyRpc.EnterMatchmakingV1Request",
  "payload": {
  }
}

Functions #

Once the EnterMatchmaking call is made by the party leader, the buildMatchmakingKey, buildExtMatchmakingParty, and buildExtMatchmakingPlayer functions are called by the plugin. These allow for customization of matchmaking keys and any other custom matchmaking content.

suspend fun buildMatchmakingKey(
  party: Party
): ExtMatchmakingKey
suspend fun buildExtMatchmakingParty(
  party: Party
): ExtMatchmakingParty
suspend fun buildExtMatchmakingPlayer(
  party: Party
  player: Player
): ExtMatchmakingPlayer

See Matchmaking Tasks to see what happens once a party enters matchmaking.

Return from matchmaking #

Process matchmaking instance exit scenarios.

Functions: returnFromMatchmaking

Functions #

Use the returnFromMatchmaking() function to handle behaviors when a player returns from matchmaking. By default, no selections or relevant party fields are changed when a party leaves matchmaking. For example, if the party leaves matchmaking due to a player disconnecting, you may want to retain character selections so players don’t need to reselect their character.

suspend fun returnFromMatchmaking(
  party: Party,
  returningPlayers: List<PartyPlayer>,
  config: PartyConfig
)

After the player and their party are removed from matchmaking, players receive a OnLeftMatchmaking event.

Return from a game instance #

Process game instance exit scenarios.

Functions: returnFromMatch

Functions #

The returnFromMatch method provides a way to handle players leaving a game instance. returnFromMatch is called when a game instance ends or a player is removed from the game instance.

suspend fun returnFromMatch(
  party: Party,
  returningPlayers: List<PartyPlayer>,
  config: PartyConfig
)

For example, you can use returnFromMatch to require players to reselect a character after completing a game instance to encourage diverse character pools.

Upon returning from a game instance, players are returned to their original party, allowing them to quickly prepare for the next game instance and queue again.