Party #

The Party service allows players to create a party with their friends, and configure their game and other selections before entering matchmaking. Extension data and the Party plugin can be used to create custom party configuration and workflows.

Architecture #

The Party service coordinates invites and shared player state in real time. This requires sending out player broadcasts to each individual player when states change and managing a careful multithreaded implementation.

The Pragma Engine architecture uses its deterministic routing capability to send broadcasts directly to each player without extra network hops that can create load bottlenecks. Each party is synchronized to maintain integrity of the party state, while the service itself is massively parallel to support thousands of parties per box and scale horizontally to any number of Party service instances.

Party Plugin #

Pragma Engine handles running all basic party operations and provides access to a plugin to add custom behavior. The Party plugin supports defining and updating extension data at points of change for the party lifecycle–creating a party, joining a party, updating ready state, leaving a party, updating any selections on the party, starting matchmaking, and recreating the party after players leave matchmaking or finish their match.

Custom Party behavior #

Custom ext logic can be defined for endpoints within the Party plugin.

To customize plugin behavior with ext fields, use the appropriate function to take client-supplied data in RequestExt objects and translate it to the relevant ext selections object within a party.

Pragma Engine provides several of these RequestExt objects that are sent on the payloads of RPC calls, such as Create, Join, UpdatePlayerSelections, and UpdatePartySelections.

Send custom data to the game server #

To allow the game server to take advantage of any Party plugin ext fields, implement a custom MatchFoundPlugin with a prepareMatchInfo function.

prepareMatchInfo has two important capabilities:

  • provides the plugin access to MatchLifecycleRpc.CreateMatchV2Request
  • includes a builder called MatchCapacityRpc.StartMatchV1Request.Builder

The CreateMatchV2Request is called after matchmaking to create a match, and includes complete party payloads for all individual parties. Use this to retrieve any ext data from the original party payloads, and then embed them into the StartMatchV1Request request.

The builder can be used to customize payloads sent to the game server:

  • to modify global game settings, update the ExtCreateMatchV1Request on the builder
  • to modify individual player settings, locate the correct player within the prepopulated list of pragma.matchlifecycle.PlayerInfoV2, then update the ExtPlayerInfo field

Extension Data #

There are three kinds of party data: public player selections, private player selections, and public party selections.

TypeVisibilityExamples
public party selectionspartycurrent mode or map, active mutations
public player selectionspartyselected hero or skin, preferred map or mode to play
private player selectionsplayerselected deck in a CCG not visible to opponent until match start
sequenceDiagram participant Player1 participant Player2 Player1->>Party:create() Player1->>Party:sendInvite(Player2) Party->>Player2:inviteReceivedFrom(Player1) Player2->>Party:respondToInvite(acceptInvite = true) Player1->>Party:updatePlayerSelections(hero = rogue) par Party->>Player2:partyDetails(p1.hero = rogue) Party->>Player1:partyDetails(p1.hero = rogue) end Player1->>Party:startMatchmaking()

Quick Guides #

Creating a party #

Send CreateV1 to create a party based on the active player:

{
  "requestId": 1,
  "type": "PartyRpc.CreateV1Request",
  "payload": {
    "createRequestExt":{},
    "playerJoinRequestExt":{},
    "gameClientVersion":"gameClientVersion1"
  }
}

The party’s creator is added to the party as the leader. The PartyPlugin plugin functions initializeParty and onAddPlayer are invoked during creation.

When using the Pragma SDK, gameClientVersion is automatically managed and sent via configuration.

Sample response contains data about the generated party, including the display name, party state, and an invite code:

{
  "sequenceNumber": 0,
  "response": {
  "requestId": 1,
    "type": "PartyRpc.CreateV1Response",
    "payload": {
      "party": {
        "extPartySelections": {},
        "extPrivatePlayerSelections": {},
        "partyId": "41b6a903-bd3a-4317-b7cb-db996021087d",
        "partyMembers": [
          {
            "ext": {},
            "playerId": "d560eb9b-4f34-4350-b733-5f6df678dab0",
            "displayName": {
              "displayName": "test01",
              "discriminator": "0001"
            },
            "isReady": false,
            "isLeader": true
          }
        ],
        "inviteCode": "CDCLGP"
      }
    }
  }
}

Sending a party invite #

Use SendPartyInviteV1 with the invited player’s ID:

{
  "requestId": 1,
  "type": "PartyRpc.SendInviteV1Request",
  "payload": {
    "inviteePlayerId": "f9525239-cd99-425d-9f14-1ff948c02553"
  }
}

Receiving and responding to a party invite #

The invited player’s client is sent an PartyRpc.InviteReceivedV1Notification.

Within the Party service in each SDK, there are OnInviteReceived events that can be leveraged for wiring up any UI and responding to the invite.

To respond to an invite, use RespondToInviteV1 with the invite ID provided in the InviteReceivedV1Notification.

{
  "requestId": 2,
  "type": "PartyRpc.RespondToInviteV1Request",
  "payload": {
    "requestExt":{},
    "inviteId":"89962f84-7edd-45b9-97c0-b6fd49fc8497",
    "accepted":true,
    "gameClientVersion":"gameClientVersion1"
  }
}

The PartyPlugin plugin function onAddPlayer is invoked as a player joins.

When using the Pragma SDK, gameClientVersion is automatically managed and sent via configuration.

Joining a party with an invite code #

For playtesting purposes, we provide an invite code system of 6-character strings that can be used to quickly join games.

To join with an invite code, use JoinWithInviteCodeV1 with the invite code from the party you wish to join.

{
  "requestId": 3,
  "type": "PartyRpc.JoinWithInviteCodeV1Request",
  "payload": {
    "requestExt":{},
    "inviteCode":"CDCLGP",
    "gameClientVersion":"gameClientVersion1"
  }
}

The PartyPlugin plugin function onAddPlayer is invoked as the player joins.

When using the Pragma SDK, gameClientVersion is automatically managed and sent via configuration.

Joining a party with a party ID #

Players can join existing parties by using the party ID as a key.

To join with a party ID, use JoinWithPartyIdV1 with the party ID from the party you wish to join.

{
  "requestId": 4,
  "type": "PartyRpc.JoinWithPartyIdV1Request",
  "payload": {
    "requestExt":{},
    "partyId":"5e359a34-8112-4a84-81d5-86f11f261f67",
    "gameClientVersion":"gameClientVersion1"
  }
}

The PartyPlugin plugin function onAddPlayer is invoked as the player joins.

When using the Pragma SDK, gameClientVersion is automatically managed and sent via configuration.

Leaving a party #

To leave a party, use LeaveV1.

{
  "requestId": 4,
  "type": "PartyRpc.LeaveV1Request",
  "payload": {
  }
}

Pragma Engine invokes the PartyPlugin function onRemovePlayer after a player leaves a party.

Updating player and party selections #

When called, Pragma Engine invokes the PartyPlugin function updateParty with the request ext, allowing for custom-built updates to selections.

To update player selections, use UpdatePlayerSelectionsV1.

{
  "requestId": 6,
  "type": "PartyRpc.UpdatePlayerSelectionsV1Request",
  "payload": {
    "requestExt": {}
  }
}

To update party selections, use UpdatePartySelectionsV1.

{
  "requestId": 7,
  "type": "PartyRpc.UpdatePartySelectionsV1Request",
  "payload": {
    "requestExt": {}
  }
}

Receiving party updates #

When a party member calls the Party service to change the state of the party, they receive an up-to-date payload of the new party state. All party members are automatically notified of any changes to the party state (that they did not directly invoke) via an PartyDetailsV1Notification.

The Unity and Unreal SDKs have behavior built in to automatically listen to these updates and manage latest party state appropriately.

Setting ready state #

Party members may toggle their ready state using SetReadyStateV1.

{
  "requestId": 5,
  "type": "PartyRpc.SetReadyStateV1Request",
  "payload": {
    "ready": "true"
  }
}

Matchmaking is blocked from starting if not all players are ready. When called, Pragma Engine invokes the PartyPlugin function canChangeReady to determine whether to accept or reject the player’s new ready state.

Starting matchmaking #

To start matchmaking, use StartMatchmakingV1.

{
  "requestId": 8,
  "type": "PartyRpc.StartMatchmakingV1",
  "payload": {  
  }
}

When called, Pragma Engine invokes both PartyPlugin functions buildMatchmakingKey and buildExtEnterMatchmakingV2Request to allow for customization of matchmaking keys and any other custom matchmaking context.

You can only enter matchmaking when when all party members are marked ready and StartMatchmaking is called by a party leader.

Sending custom data to a match #

To allow the game server to take advantage of any Party plugin ext fields, you can implement a custom MatchFoundPlugin.

The prepareMatchInfo function provides the plugin access to the complete MatchLifecycleRpc.CreateMatchV2Request. The complete party payloads for all individual parties in the match are embedded within this request.

The plugin’s function signature also contains a builder for the MatchCapacityRpc.StartMatchV1Request that defines the payload that the game server receives. Use this to retrieve any ext data from the original party payloads, and then embed them into the StartMatchV1Request request.