Pragma Engine 0.0.91

March 2, 2023

Features #

[Game Flow] New Matchmaking Plugin method endLoop allows for custom code to be injected after each matchmaking loop. #

Description: The new Matchmaking Plugin method endLoop is now invoked after each matchmaking loop. This makes it possible to add custom logic, such as the functionality to start a Potential Match early even if it fails to make an ideal match.

Related note: See docs note on endLoop.

[Game Flow] Leaving a party or kicking a player from a party removes the entire party from matchmaking. #

Description: This change was made to keep matchmaking and party player membership in sync.

[Game Flow] Match reconnect can now be set as optional for players. #

Description: Operators can now configure game flows to allow for optional match reconnect. If configured, game clients can invoke DeclineReconnect to leave the existing match when they disconnect.

Details:

  • New Player endpoint: DeclineReconnectV1

    bool UPragmaPartyService::CanDeclineReconnectV1() const
    
    bool UPragmaPartyService::CanDeclineReconnectV1(FPragmaError& OutError) const
    
    TFuture<TPragmaResult<>> UPragmaPartyService::DeclineReconnectV1()
    
    void UPragmaPartyService::DeclineReconnectV1(const FOnCompleteDelegate& OnComplete)
    
    public bool CanDeclineReconnectV1()
    
    public bool CanDeclineReconnectV1(out Error? error)
    
    public Future DeclineReconnectV1()
    
    public void DeclineReconnectV1(CompleteDelegate onComplete)
    

  • New Partner notification that can be subscripted via engine-specific events: PlayerDeclinedReconnectV1Notification

    FPlayerDeclinedReconnectEvent UPragmaMatchLifecycleService.OnPlayerDeclinedReconnectEvent;
    
    public event Action<PragmaId, PragmaId> MatchLifecycleService.OnPlayerDeclinedReconnect;
    

  • New Match Lifecycle service configuration option: matchReconnect can have the values OFF, OPTIONAL, or REQUIRED.

[Player Data] UpdateEntryId is now an optional field when making instanced item update calls. #

Description: You can now call instanced item update without needing a placeholder for the update entry. ServerInstancedItemUpdate and InstancedItemUpdate no longer require you to assign an UpdateEntryId.

Examples: The following are examples of instanced item update calls without UpdateEntryId:

FPragma_Inventory_InstancedItemUpdate{*InstanceId}
var instancedItemUpdate = new InstancedItemUpdate {InstanceId = instancedId}};
"payload": {
        "itemUpdate": {
            "instanced":
            {
                "instanceId": "<items-instance-id>"
            }
        }
    }

[Player Data] Items that do not correspond to a valid catalogId will no longer show up in a player’s inventory. #

Description: The Inventory service now filters out items that do not have a corresponding catalogId defined by instanced and stackable content specs. This filtering prevents runtime errors that occurred on retrieval when a catalogId check was happening.

If you want to load items in the database with invalid catalogId, assign and set legacyItemLoadBehavior: true in the Inventory service config, though this may result in runtime errors.

[Player Data] The Instanced Item Plugin’s newInstanced() and update() functions can now access a player’s inventory before and during an RPC call. #

Description: The Instanced Item Plugin’s functions have been updated with one new and one renamed parameter. This enables player inventory access for instanced item modifications before the call runs, as well as a view into the item logic that would be committed to the database once the engine processes the call’s request.

Related note: See integration note to update the Instanced Item Plugin.

[Infra & Tooling] New configuration validation process checks configs and outputs errors. #

Description: Pragma Engine now validates configuration files and provides detailed explanations of any issues. This new config validation process means the engine will catch issues, prevent bad configs from being used, and provide meaningful guidance for resolving errors. This validation runs both when you build, and when you dynamically change a config for an actively running backend.

Related note: See integration note for config validation.

[Infra & Tooling] Version information on all gateways can now be viewed using the new /v1/healthcheck. #

Description: /v1/healthcheck can be used to monitor nodes that don’t necessarily run frontend gateways. The following are /v1/healthcheck responses and their associated JSON payloads:

  • 200: Health of node is ideal.
{"isHealthy":true,"version":"DEFAULT-0.0.91-WIP-a5bb265-dirty","platformVersion":"local-dev","portalVersion":"local-dev","contentVersion":"local-dev","configVersion":"local-dev"}
  • 503: Health of node is not ideal. Note that "isHealthy": false is currently used during startup to indicate that not all services are running yet.
{"isHealthy":false,"version":"DEFAULT-0.0.91-WIP-a5bb265-dirty","platformVersion":"local-dev","portalVersion":"local-dev","contentVersion":"local-dev","configVersion":"local-dev"}

Related note: See integration note about /v1/info.

[SDKs] Added rich bindings for PlayerLeave. #

Description: The rich Match Lifecycle service on the PragmaSession now has PlayerLeave functions for both Unity and Unreal.

[SDKs] SDK code generation now supports the proto3 optional field attribute. #

Description: The proto3 optional field is now supported. This allows the SDK to support messages that recursively reference themselves. You can also now check for the existence of optional fields.

Example:

// Given a MyData field called "Data"
bool b = Data.SomeInt.HasValue(); // Check that the field has a value set.
Int x = Data.SomeInt.Value(); // Get the value.
Data.SomeInt.SetValue(42); // Set the value.
// Given a MyData field called "Data"
bool b = Data.SomeInt.HasSomeInt; // Check that the field has a value set.
int x = Data.SomeInt; // Get the value. Note this will return default if not set.
Data.SomeInt = 42; // Set the value.
message MyData {
  optional int32 some_int = 1;
}

[SDKs] SDK code generation now supports messages that recursively reference themselves. #

Description: Messages can reference themselves in their own fields or in sub-message fields. Fields involved in cyclic references must be marked optional or repeated.

Example: The following code block shows message A referencing itself both in its own field and in message B, which is a sub-message of A.

message A {
  optional A = 1;
  optional B = 2;
}

message B {
  repeated A = 1;
}

[SDKs] BackendAddress and ProtocolType can now be specified separately for client and server. #

Description: Pragma SDK running on a game server now uses the new config fields PartnerBackendAddress and PartnerProtocolType. These fields can be overridden via command line parameters: -PragmaPartnerBackendAddress="http://127.0.0.1:10100" -PragmaPartnerProtocolType="Http". If the PartnerBackendAddress field is empty, BackendAddress will be used instead.

[SDKs] The Inventory service now supports item lookups by catalogId and instanceId. #

Description: You can now look up items by catalogId and instanceId instead of iterating through the list on InventoryResults.InventoryFull using the two new functions GetInstancedItemsByCatalogId and GetStackableItemsByCatalsogId.

Example: The following are the two new item lookup functions in PragmaInventory.Service:

var itemsWithCatalogIdLookup = PragmaInventory.Service.GetInstancedItemsByCatalogId("<<catalog-id>>");

var itemWithInstanceIdLookup = PragmaInventory.Service.GetInstancedItemByInstanceId("<<instance-id>>");

[SDKs] Game servers now connect to Pragma Engine over WebSocket by default. #

Description: The default PartnerProtocolType for Pragma SDKs is now WebSocket instead of HTTP. If you prefer HTTP, you can override this behavior with the command line parameter -PragmaPartnerProtocolType="Http" or via the config field PartnerProtocolType according to your engine.

[Portal] The new Portal is now available! #

Description: The new Portal has better extensibility, clearer separation of customer data, and a simplified configuration. New capabilities include:

  • Update and extend existing pages and portlets with components, pages, and actions.
  • Use flags to toggle features with the featureToggles option.
  • Define custom rendering components for ext data in content and inventory.
  • Use the <Icon /> component to access 400+ new icons and add custom icons.
  • Leverage the new Less support across the entire Portal; all .less files are loaded and compiled automatically.

Related note: See integration note about custom content in Portal.

[Portal] Portal shows how much time remains before an event begins or ends. #

Description: You can now see the amount of time remaining before events start or end when viewing scheduled events in the Portal. This information is shown in a new Status column.

The Events table can be seen in the Social PortalServices menu → Game Title ManagementShardsSelect a shard, then scroll down to the Events table.

Deprecations #

[Game Flow] The MatchLifecycleServiceConfig.enableMatchReconnect boolean config has been deprecated in favor of the MatchLifecycleServiceConfig.matchReconnect enum config. #

Description: The MatchLifecycleServiceConfig.matchReconnect config will support an upcoming feature. The existing enableMatchReconnect config is scheduled to be removed in Pragma Engine release 0.0.92. To migrate early, make the following replacement in your config file:

originalreplacementremoval release
enableMatchReconnect: truematchReconnect: "REQUIRED"0.0.92
enableMatchReconnect: falsematchReconnect: "OFF"0.0.92

[SDKs] Sessions are changing. #

Description: PragmaSession has been split into Player and Server objects that provide a more relevant subset of the API based on their respective use cases.

  • See the Unreal and Unity SDK API v2 migration guide in the shared Google Drive for more details.
  • The existing implementation of PragmaSession is now deprecated and will be removed in a future release.

Integrations #

[Game Flow] Move the Match Reconnect config to its new location in the MatchLifecycleServiceConfig. #

Description: Match Reconnect now handles connections that were forcibly disconnected on the client side. The configuration for turning on Match Reconnect has been moved to the MatchLifecycleServiceConfig.

Integration step: Move the Match Reconnect config to its new location. Be sure to remove it from the existing location.

  • Before:
game:
  core:
    session:
      enableMatchReconnect: true
  • After:
game:
  serviceConfigs:
    MatchLifecycleServiceConfig:
      enableMatchReconnect: true

Related note: See bugfix note on client reconnects.

[Game Flow] Replace usages of the partyStartMatch Test Factory method with startMatch. #

Description: This helper has been removed as part of the post-Lobby service cleanup.

Integration step: Replace usages of the following Test Factory method in Game Loop.

originalreplacement
matchCapacity_partyStartMatchV1RequestmatchCapacity_startMatchV1Request()

[Game Flow] If you’re using the listed MatchLifecycleServiceConfig properties, you’ll need to update references to reflect their renames. #

Description: We’ve renamed several config properties for the Match Lifecycle service to be more clear. Note that these are optional properties, so if you’re not using them, no action is required.

Integration step: Update references to the following renamed config properties.

originalreplacement
enableInProgressMatchTimeoutenableMatchAbsoluteTimeout
inProgressMatchTimeoutMillismatchAbsoluteTimeoutMillis
missedKeepAlivesBeforeCleanupkeepAliveMissesLimit

Example: Below is an example of the new Match Lifecycle service config using all the new property names.

game:
  serviceConfigs:
    MatchLifecycleServiceConfig:
      enableMatchAbsoluteTimeout: true
      matchAbsoluteTimeoutMillis: 10000000
      enableKeepAlive: true
      keepAliveIntervalMillis: 30000
      keepAliveMissesLimit: 3

[Game Flow] If you have custom code referencing SessionServicePB or Session, update them to their new names. #

Description: To improve the structure of Pragma Engine and to keep components understandable, we’ve renamed a few Session-related protos and services.

Integration step: After rebuilding protos and sdk-types, check custom code for references to the following Session calls and update them to their replacements:

originalreplacement
SessionServicePBPlayerSessionRpc
SessionSessionCommon

[Game Flow] If your game server implementation uses the MatchReady call, generate an ExtPlayerMatchDetails object for each player. #

Description: Game server implementations that use the MatchReady call must provide ExtPlayerMatchDetails for each player. This change was made to detect missing ExtPlayerMatchDetails. If the game server provides fewer ExtPlayerMatchDetails than the required number of players as defined by the ReportCapacity response, it will throw a MatchLifecycle_MissingPlayerExt error.

Integration step: In your game server’s response handling for MatchCapacity::StartReportCapacityPolling, while creating the MatchReady request, an ExtPlayerMatchDetails object must be generated with the playerId for each player. These objects must then be put on the MatchReady request before calling MatchLifecycle.MatchReadyV2.

[Game Flow] If you’re using the listed Party service helper functions, update them to their new names. #

Description: We’ve renamed the getParty and getBroadcastParty proto helpers on the Party service to be more accurate.

Integration step:

originalreplacement
Party.getPartyParty.getPartyProto
Party.getBroadcastPartyParty.getBroadcastPartyProto

[Game Flow] If you have a custom implementation of the Matchmaking Plugin, update references to PotentialMatch, ActiveMatch, and MatchableParties to be consistent with new locations and names. #

Description: Studios using custom implementations of the Matchmaking Plugin will need to update the class references, as the interface for the plugin has been changed with new types. These changes were made to be more readable and prevent the usage of restricted properties and functions. Changes have been made to the locations of ActiveMatch and PotentialMatch, and to the name of MatchableParties.

Integration steps: If you have a custom implementation of the Matchmaking Plugin, you will need to complete the following steps.

  • Change the MatchableParties type to Matchable, and update any related imports as necessary.
  • Update any references to PotentialMatch and ActiveMatch, as they’ve been moved into a new folder.
  • If you were using a function or property that is now unavailable, reach out to your Pragma support representative to find alternate strategies using approved functions.

[Player Data] If you’re using the Instanced Item Plugin, update newInstanced()’s and update()’s parameters. #

Description: We’ve added in a new parameter called pendingInventory and renamed an existing parameter initialInventory in the Instanced Item Plugin’s newInstanced() and update() functions.

Integration steps:

  • Add the parameter pendingInventory to both newInstanced() and update().
  • Rename the parameter initialInventory with startingInventory to both newInstanced() and update().

Example: Below is an example of the Instanced Item Plugin with the updated parameters:

interface InstancedItemPlugin {

fun newInstanced(
    instancedSpec: InventoryContent.InstancedSpec,
    inventoryContent: InventoryServiceContent,
    startingInventory: InventoryData, // RENAMED from initialInventory
    pendingInventory: InventoryData, // NEW parameter
    clientRequestExt: ExtPurchaseRequest?,
    serverRequestExt: ExtInstancedItemServerGrant?
): InstancedItemPluginResult

fun update(
    initialInstancedItem: InstancedItem,
    instancedSpec: InventoryContent.InstancedSpec,
    updateEntry: InventoryContent.UpdateEntry,
    inventoryContent: InventoryServiceContent,
    startingInventory: InventoryData, // RENAMED from initialInventory
    pendingInventory: InventoryData, // NEW parameter
    clientRequestExt: ExtInstancedItemUpdate?,
    serverRequestExt: ExtInstancedItemServerUpdate?
): InstancedItemPluginResult
}

Related note: See feature note on updates to the Instanced Item Plugin.

[Infra & Tooling] Replace usages of /v1/info version information with /v1/healthcheck. #

Description: Version information is no longer available on /v1/info, as it has been moved to the new /v1/healthcheck.

Integration step: Replace any dependency on /v1/info version data with /v1/healthcheck.

[Infra & Tooling] You may need to check your config files for stale or unused configs to successfully pass the new config validation step. #

Description: As part of the new config validation feature, stale or broken configs that were previously ignored will now cause the engine to prevent startup and generate an error.

Integration step: Check your config files for stale, unused configurations from before Pragma Engine began validating. These will need to be removed.

Related note: See feature note on config validation.

[Infra & Tooling] If you’re using the SystemProxy class, reimplement it as it’s been deleted. #

Description: The old SystemProxy class is no longer in use by Pragma Engine and has been deleted. If you’re using this class in custom code, you’ll need to reimplement it.

Integration step: Please contact us for support for reimplementing the SystemProxy class.

[SDKs] Unreal: If you had manual HTTP implementations for game servers in any custom services, replace these with the new macros. #

Description: The Unreal game server now supports WebSocket connections. Any custom service that previously utilized manually created functions for the Http() handler can now make use of the prebuilt macros.

Integration steps:

  • Locate custom service code that directly invokes HTTP connections to Pragma.
  • Replace code with usage of an appropriate binding of the correct IMPL_PRAGMA_[BACKEND]_METHOD macro, where [BACKEND] should be replaced with SOCIAL or GAME.

Example:

  • Before:
void UPragmaMatchLifecycleServiceRaw::MatchReadyV2(
 const FPragma_MatchLifecycle_MatchReadyV2Request& Request,
 TUniqueFunction<void(TPragmaResult<FPragma_MatchLifecycle_MatchReadyV2Response>, const FPragmaMessageMetadata&)>
 Callback) const
{
 Connection().Http(EPragmaBackendType::Game).SendMessage(Request, MoveTemp(Callback));
}
  • After:
IMPL_PRAGMA_GAME_METHOD(UPragmaMatchLifecycleServiceRaw, MatchReadyV2, FPragma_MatchLifecycle_MatchReadyV2Request,
FPragma_MatchLifecycle_MatchReadyV2Response, FMatchReadyDelegate);

[SDKs] Unreal: Rename the listed types. #

Description: As part of Core SDK cleanup, some type names have changed.

Integration step: Find and rename the following types:

originalreplacement
UPragmaConnection::FConnectionErrorFPragmaConnectionError
EProtocolErrorEPragmaProtocolError

[SDKs] Unreal: Update your Init method in custom services to take new parameters. #

Description: As part of Core SDK cleanup, the Init method of custom services now takes new parameters.

Integration step: Make the following replacement:

originalreplacement
Init(UPragmaSession* InSession)Init(IPragmaShimSession* InSession, IPragmaShimConnection* InConnection)

[SDKs] Unreal: Complete the listed integration steps to enable a workaround for packaging standalone Unreal game builds. #

Description: To enable packaging standalone Unreal game builds, you must complete the integration steps.

Integration steps:

  1. Open the pragma-engine/sdk folder.
  2. Find PragmaInventoryCache.cpp and remove #include "BehaviorTree/BTCompositeNode.h".
  3. Find PragmaCore.cpp and comment out PRAGMA_LOG(Error, "Failed to load Pragma Core shared library.");.
  4. Run the update-pragma-sdk.sh script.
  5. Rebuild your Unreal game project to enable packaging projects from Unreal Editor.

[SDKs] Unity: Update your Init method in custom services to take new parameters. #

Description: As part of Core SDK cleanup, the Init method of custom services now takes new parameters.

Integration step: Make the following replacement:

originalreplacement
Init(PragmaSession session)Init(ISession session, IConnection connection)

[Portal] All customers must complete the provided Portal integration guide to prevent CI from breaking. #

Description: To support the new Portal workflow, you’ll need to upgrade portlets and deployment systems so they work properly with the new Portal.

Integration step: Check out the Portal Integration Guide in the shared Google Drive for integration steps and a changelist.

Related note: See feature note about the new Portal.

Bugs and Fixes #

  • [Game Flow] Pragma Engine now properly clears party and matchmaking states when a client crashes and restarts.

    • Description: New client connections are treated as fresh sessions, unless enableMatchReconnect is configured, in which case the players are automatically reconnected to the match.

    • Related note: See integration note on Match Reconnect.

  • [Game Flow] We’ve fixed an issue where sessions would prematurely time out if connected with HTTP and WebSocket.

Docs #

  • [Updated Docs] Updated SDK docs across the site to reflect the API V2 changes.

  • [Updated Concepts] Added a new section on Keep Alive Heartbeats in the Match End page, which explains the behavior regarding the Match Lifecycle service.

  • [Updated Concepts] Added new information on disabling Unsafe Providers and the related config to the Identity Providers page.

  • [Updated Concepts] Updated the Provider Entitlement page with new information and clarification.

  • [Updated Concepts] Added new information on match reconnect on the Match Lifecycle page.

    • Related note: See feature note about match reconnect.
  • [Updated Concepts] Added a new section Add Custom Behavior After Complete Loop to the Matchmaking page.

    • Related note: See feature note on the new Matchmaking Plugin method endLoop.
  • [Updated Concepts] Added a new section on Configuring Protocols for HTTP and WebSocket connection on the Game Server Management page.

  • [Tech Blog] The Tech Blog has migrated from the docs site to Pragma’s main site, with a new landing page which includes new locations for articles.

  • [New Tech Blog Articles] Two new Content Data articles are live! Learn about the Content Data system with Part 1 and Part 2 of the Content Data article series.