Pragma Engine 0.0.88

November 8th, 2022

Features #

You can now force your inventory cache to update in the SDKs. #

Description: If your inventory is stale, you can force the cache to update with ForceGetInventory.

PragmaSession->InventoryService->ForceGetInventory(FOnCompleteInventoryCacheCallDelegate::CreateLambda([this](FInventoryFull Full) {
// use the Full.LastRefreshSuccess to assess that the cache sas successfully refreshed.
// The inventory is within Full.Stackable and Full.Instanced
});
PragmaSession.InventoryService.ForceGetInventory(r =>{
// use the r.Payload.lastRefreshSuccess to assess that the cache was successfully refreshed.
// The inventory is within r.Payload.instancedItems and r.Payload.stackableItems
});

Players that create a party while in an active party will automatically leave and move to the new party. #

Description: If a player tries to create a new party while in an active party, they will automatically leave the party they already were in and join the newly created one. This means a player can create a new party at any time. To check if a player is in a party, you can use the HasParty() helper method in the Party service.

New version properties have been added to /v1/info for different artifacts. #

Description: We’ve added version properties to /v1/info for each artifact type (platformVersion, portalVersion, contentVersion, and configVersion).

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

Purchasing and entitlement catalogs are now retrieved by GetLoginData. #

Description: GetLoginData now includes the catalogs for ItemBundles and ProviderEntitlementMappings. Hidden item filtering is also supported for ItemBundles.

You can now call GetLoginData through the SDK Rich GameDataService. #

Description: GameDataService in the SDKs now propagates the GetLoginDataV2Response. The client-side inventory cache of the Rich InventoryService will be updated through a new event called OnGetLoginData. We strongly recommend you use this new feature.

To use this new endpoint, replace any uses of GameDataServiceRaw’s GetLoginData with the new call:

UPragmaGameDataService::GetLoginData()
GameDataService.GetLoginData()
GameDataService’s GetLoginData

SDK Raw Partner RPCs have been added to the Inventory service. #

Description: The following Raw Partner RPCs have been added to the Inventory service.

Note: Make sure the game server config overwrites the PragmaProtocolType to Http with PragmaProtocolType={Http,WebSocket}.

  • PragmaInventoryServiceRaw.GetInventoryPartnerV1()
  • PragmaInventoryServiceRaw.GrantItemsPartnerV1()
  • PragmaInventoryServiceRaw.DestroyItemsPartnerV1()
  • PragmaInventoryServiceRaw.UpdateItemsPartnerV2()
  • Inventory.Raw.GetInventoryPartnerV1()
  • Inventory.Raw.GrantItemsPartnerV1()
  • Inventory.Raw.DestroyItemsPartnerV1()
  • Inventory.Raw.UpdateItemsPartnerV2()
  • GetInventoryPartnerV1()
  • GrantItemsPartnerV1()
  • DestroyItemsPartnerV1()
  • UpdateItemsPartnerV2()

Added an SDK event that notifies players to update their game client if it doesn’t match the configured GameServerVersions. #

Description: The new SDK event OnGameClientVersionUpdateRequired notifies players if their client version does not match the currently configured GameServerVersions.

Related note: See integration note about game client update notifications.

Unreal SDK: Messages can now be excluded from SDK code generation. #

Description: A new option has been added to support hiding certain messages from the Unreal code generation phase of the processing of proto files. This means you can hide messages that aren’t relevant to players or game servers–for example, in a situation where your custom services uses a custom Partner request internally.

Add the following line within the body of any message to prevent the message from being provided to the protoc compiler used in the code generation phase:

option (external_visibility) = HIDE;

Example: In paymentRpc.proto, there are some internal Partner requests and responses that the engine uses. By using this new feature, we prevent exporting this information because game servers can’t use it:

message InitializeOrderPartnerV1Response {
  option (pragma_session_type) = PARTNER;
  option (pragma_message_type) = RESPONSE;
  option (external_visibility) = HIDE;
}

Unreal SDK: You can now use the PreDisconnect event to make sure cleanup happens inline with disconnection. #

Description: We’ve added a PreDisconnect event to the Unreal SDK to make sure handlers are fired before UPragmaConnection::OnDisconnectedV2. You can use this to make sure cleanup happens inline with disconnection.

Portal: You can now edit content catalogs in Portal. #

Description: A new portlet called Content Catalogs Editor has been added to allow Operators to create, update, and delete content entries. Changes can be previewed on the Content Changes page before they’re applied. You can also import and export source files for tasks like moving content between game servers or making a backup before altering data.

This portlet is disabled by default to prevent use in production. Changes can be applied directly in the environment where the Portal is running, or exported in a zip file.

Deprecations #

If you’re using the version properties endpoint in /v1/info, you’ll need to update it to platformVersion. #

Description: We’re adding version properties to /v1/info for each artifact type (platformVersion, portalVersion, contentVersion, and configVersion). You’ll need to use platformVersion instead of version.

originalreplacementremoval release
versionplatformVersion0.0.89

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

Unreal SDK: Some Inventory service calls have been renamed for clarity. See included table for details. #

Description: We’ve renamed/removed several Inventory service calls for clarity.

  • UPragmaInventoryService::GetInstancedItemsV1 and UPragmaInventoryService::GetStackableItemsV1 will be removed. Use UPragmaInventoryService::GetInventory and you can see the instanced and stackable items within the response of this call.
  • UPragmaInventoryService::GetInventoryV1 will be replaced with UPragmaInventoryService::GetInventory.
  • UPragmaInventoryService::DeletePlayerInventoryV2 will be replaced with UPragmaInventoryService::DeletePlayerInventory.
originalreplacementremoval release
UPragmaInventoryService::GetInstancedItemsV1, UPragmaInventoryService::GetStackableItemsV1UPragmaInventoryService::GetInventory

You can see the instanced and stackable items within the response of this call.
0.0.89
UPragmaInventoryService::GetInventoryV1UPragmaInventoryService::GetInventory0.0.89
UPragmaInventoryService::DeletePlayerInventoryV2UPragmaInventoryService::DeletePlayerInventory0.0.89

Integrations #

To update Pragma Engine’s build tools, install or update your Corretto JDK to JDK 17. #

Description: The tools used to build Pragma Engine have been updated and require the newer Corretto JDK 17 version.

Integration steps: Follow steps in the provided doc on Dev Environment Changes to get your JDK running with Pragma Engine. If you’re having trouble with a new make build, try clearing your .m2 Maven cache to start with a clean build.

Consolidate development defaults in a single location (./platform/config/dev-defaults.yml) by following the listed integration steps. #

Description: Pragma Engine no longer supports embedding development defaults within the engine codebase. Dev defaults should be specified within config files as appropriate:

  • ./platform/config/dev-defaults.yml: Pragma Engine-supplied defaults for development and useful for getting started. This is an engine file and therefore should not be modified by studios.
  • ./platform/5-ext/config/dev.yml: studio-supplied dev config values. These config values will override the Pragma Engine-provided defaults, and is a checked-in file to share across a dev team.
  • ./platform/5-ext/config/common.yml: studio-supplied configuration used for config values appropriate in all contexts, including production and development.
  • ./platform/5-ext/config/local-dev.yml: local machine overrides (i.e. debug logging for local box). This file is not checked in and can be used to configure settings unique to a local dev machine (such as a local Unreal engine install directory).

Integration step:

  1. Complete the following renames in pragma-engine/platform/5-ext/config/. Note that if you’ve already tried a build, you may need to replace or remove the common.yml and local-dev files that were copied from our templates.

    originalreplacement
    CommonConfig.ymlcommon.yml
    LocalConfig.ymllocal-dev.yml
  2. Update anything that extends a ConfigObject, such as ServiceConfig or PluginConfig objects.

  • Remove the mode parameter from both constructors and the call to the superclass constructor.
  • Remove the mode parameter from the ConfigBackendModeFactory.getFor method.
  • Move any default config values specified within the DEVELOPMENT mode into the new ./platform/5-ext/config/dev.yml file, which will simplify default configuration by keeping it in one place near the rest of your config.
  • Dao configurations: The shared username and password config must be placed within the file for all Daos even when not specific within the code individually.
  1. If you have unit tests that connect to the database (not ITs), replace any config creation to match the following example:
OriginalReplacement
val config = InventoryDaoConfig.getFor(BackendMode.DEVELOPMENT, BackendType.GAME).apply {
this.databaseConfig.hostPortSchemas = configMapOfPrimitiveOf(
"1" to "localhost:3306/test_local_game_inventory1",
"2" to "localhost:3306/test_local_game_inventory2",)}
val config = InventoryDaoConfig.getFor(BackendType.GAME).apply {
this.databaseConfig.addCredentials("localhost:3306/test_local_game_inventory1", "localhost:3306/test_local_game_inventory2")
  1. Update shard .env files to export the correct ENV_CONFIG paths to match the following example:
OriginalReplacement

In ./platform/5-ext/config/test.env:

export ENV_CONFIG="config/CommonConfig.yml,config/shard/test.yml"

In: ./platform/5-ext/config/test.env

export ENV_CONFIG="config/common.yml,config/shard/test.yml"

  1. Update run configs in IntelliJ by doing the following commands:
rm 5-ext/.run/LocalConfigured.run.xml
make ext

Once this is complete, in IntelliJ navigate to File -> Reload all From Disk. Note that you may still need to adjust the working directory in the Edit Configurations dialog box, depending on how you’ve loaded the 5-ext project.

  1. Update any customized run configs. For any custom run configurations used in IntelliJ, you’ll need to update the --configuration-filepaths to include the additional and renamed configs. For example:
--configuration-filepaths "config/dev-defaults.yml,5-ext/config/dev.yml,5-ext/config/common.yml,5-ext/config/local-dev.yml"

Example:

  • Original

class ArbiterLeaderboardDaoConfig private constructor(
    mode: BackendMode, type: BackendType
) : ServiceConfig<ArbiterLeaderboardDaoConfig>(mode, type) {
    override val description =
        "Configuration for the LeaderboardDaoConfig"

    var databaseConfig by types.embeddedObject(
        UnpartitionedDatabaseConfig::class,
        "database config for the leaderboard dao"
    )

    companion object :
        ConfigBackendModeFactory<ArbiterLeaderboardDaoConfig> {
        override fun getFor(
            mode: BackendMode, type: BackendType
        ) = when (mode) {
            BackendMode.DEVELOPMENT -> ArbiterLeaderboardDaoConfig(
                mode, type
            ).apply {
                databaseConfig =
                    UnpartitionedDatabaseConfig.getFor(
                        mode, type
                    ).apply {
                        hostPortSchema =
                            "localhost:3306/local_game_leaderboard"
                    }
            }

            BackendMode.PRODUCTION -> ArbiterLeaderboardDaoConfig(
                mode, type
            ).apply {
                databaseConfig =
                    UnpartitionedDatabaseConfig.getFor(
                        mode, type
                    )
            }
        }
    }
}
  • Replacement
class ArbiterLeaderboardDaoConfig private constructor(
    type: BackendType
) : ServiceConfig<ArbiterLeaderboardDaoConfig>(type) {
    override val description =
        "Configuration for the LeaderboardDaoConfig"

    var databaseConfig by types.embeddedObject(
        UnpartitionedDatabaseConfig::class,
        "database config for the leaderboard dao"
    )

    companion object :
        ConfigBackendModeFactory<ArbiterLeaderboardDaoConfig> {
        override fun getFor(type: BackendType) =
            ArbiterLeaderboardDaoConfig(type).apply {
                databaseConfig =
                    UnpartitionedDatabaseConfig.getFor(type)
            }
    }
}
  • dev.yml entry
game:
 core:
 serviceConfigs:
    ArbiterLeaderboardDaoConfig:
      databaseConfig:
        username: "superuser"
        password: "password"
        hostPortSchema: "localhost:3306/local_game_leaderboard"
 pluginConfigs:
social:
  core:
  serviceConfigs:
  pluginConfigs:

Related note: See Docs note on the config renames.

Generate new Partner tokens (both Social and Game) to include gameShardIds. #

Description: We’ve made this organizational change so that Partner Game tokens can only be used to communicate with their assigned game shard. You can check for token validation errors using the following config:

game:
  core:
    logging:
      loggers:
        pragma.auth.PragmaTokenValidator: "DEBUG"

Integration step: Generate new Partner tokens (both Social and Game) to include gameShardIds for each platform instance you have. Visit the Authentication docs page to learn how to generate Partner tokens.

In DefaultGame.ini

[/Script/PragmaSDK.PragmaSdkConfig]
...
PartnerSessionSocialAuthToken="<your-social-token-here>"
PartnerSessionGameAuthToken="<your-game-token-here>"
...

In Pragma.json:

{
...
"partnerSessionGameAuthToken": "<your-game-token-here>",
"partnerSessionSocialAuthToken":"<your-social-token-here>"
  ...
}

Delete remaining Lobby service files. #

Description: As a cleanup step for the removal of the Lobby service, you’ll need to delete some remaining files. The Lobby service and associated protobuf files have been deleted, so the ext file corresponding to those protos should be deleted.

Integration step: If they exist, delete the files lobbyExt.proto and lobbyRpcExt.proto in platform\5-ext\ext-protos\src\main\proto\shared\.

Update your configs for identity providers to reflect the new structural changes. #

Description: We’ve moved the plugins for identity providers to a new plugin collection named AccountService.identityProviderPlugins.

Integration step: Update your config for identity providers to reflect the new structural changes.

Example: For a Discord identity provider, update your YAML files to make sure you’re using the new structure.

OriginalReplacement
social:
pluginConfigs:
  AccountService.discordIdentityProvider:
    class: "pragma.account.DiscordIdentityProviderPlugin"
    config:
      clientId: "$discordClientId"
      clientSecret: "$discordClientSecret"
      redirectUri: "http://localhost:11000/v1/account/discord-redirect"
social:
pluginConfigs:
  AccountService.identityProviderPlugins:
    plugins:
      Discord:  <--- a unique key per Plugin
        class: "pragma.account.DiscordIdentityProviderPlugin"
        config:
          clientId: "$discordClientId"
          clientSecret: "$discordClientSecret"
          redirectUri: "http://localhost:11000/v1/account/discord-redirect"

Replace usages of the LinkIdentityProviderAccountV1 endpoint with the renamed versions. #

Description: We’ve renamed this endpoint to be consistent with Service endpoint naming conventions.

Integration step: Replace usages of the LinkIdentityProviderAccountV1 endpoint with the renamed versions.

originalreplacement
LinkIdentityProviderAccountV1RequestLinkIdentityProviderAccountServiceV1Request
LinkIdentityProviderAccountV1ResponseLinkIdentityProviderAccountServiceV1Response

Update any config files that use the Epic or Steam identity providers to reference their new class names. #

Description: We’ve renamed these class names to be consistent with plugin naming conventions.

Integration step: Update any config files that use the Epic or Steam ID Providers to reference their new class names.

originalreplacement
class: "pragma.account.EpicIdentityProvider"class: "pragma.account.EpicIdentityProviderPlugin"
class: "pragma.account.SteamIdentityProvider"class: "pragma.account.SteamIdentityProviderPlugin"

Replace usages of InventoryRpc.DeletePlayerInventoryV2() with InventoryRpc.DeletePlayerInventoryV3(). #

Description: To complete the deprecation listed in release 0.0.87, we’ve removed this endpoint.

Integration step: Replace usages of InventoryRpc.DeletePlayerInventoryV2() with InventoryRpc.DeletePlayerInventoryV3(). We recommend using the rich layer in the SDK so inventory caches are updated accordingly.

Raw: PragmaInventoryServiceRaw.DeletePlayerInventoryV3() Rich: PragmaInventoryService.DeletePlayerInventory() *rich wrapper
Raw: InventoryServiceRaw.DeletePlayerInventoryV3() Rich: InventoryService.DeletePlayerInventory()

Postman: To update your localhost environment, use the renamed file Localhost.pragma_environment.json. #

Description: To be consistent with the Postman UI, we’ve renamed the LocalNode1.pragma_environment.json file to Localhost.pragma_environment.json.

Integration step: To update your localhost environment, use the renamed file Localhost.pragma_environment.json.

originalreplacement
LocalNode1.pragma_environment.jsonLocalhost.pragma_environment.json

If you’re using the test helper method matchCapacity_partyStartMatchV1Request, replace it with matchCapacity_startMatchV1Request. #

Description: With the removal of the Lobby service, we’re simplifying and deduplicating names.

Integration step: Rename the listed test helper method. Note that the arguments and return value are the same.

originalreplacement
matchCapacity_partyStartMatchV1RequestmatchCapacity_startMatchV1Request

If you have custom implementations of the MatchmakingStrategy interface, remove the functions validateParty and addPartyToMatchAndBuildMatchmakingDetails. #

Description: As part of the Lobby service cleanup, we’ve removed two methods.

Integration step: If you have custom implementations of the MatchmakingStrategy interface, remove the functions validateParty and addPartyToMatchAndBuildMatchmakingDetails.

If you’re referencing SDK error enums by int (instead of by name) update the int values. #

Description: We’ve simplified SDK error enums as part of the Lobby service removal effort. The following errors have been removed from the Unreal (EPragma_SdkError) and Unity (public enum SdkError) SDKs, which means that error ints have changed and references to them will need to be updated to the correct ints.

  • LobbyService_NotEnabled
  • LobbyService_MatchAlreadyFound
  • LobbyService_NoPlayAgainId

Integration step: If you’re referencing SDK error enums by int (instead of by name) update the int values.

For any custom services using InstancedConcurrentMap, update your code to handle the new internal exception correctly when getting keys from the map. #

Description: Referencing routing keys from the wrong instance will now throw an internal exception. This affects custom services using InstancedConcurrentMap.

Integration step: For any custom services using InstancedConcurrentMap, you’ll need to update your code. Note that requesting items from an InstancedConcurrentMap with keys not appropriate to the current Pragma node instance will result in an exception.

To use the new game client update notification feature, implement the game client update check on any GameServerCompatibilityPlugin. #

Description: When a party is shut down due to invalid GameServerVersions, party members who need to update their game clients should be notified.

Integration step: To use the new game client update notification feature, implement the update check on any GameServerCompatibilityPlugin:

FUpdateClientVersionEvent OnGameClientVersionUpdateRequired;
public event Action OnGameClientVersionUpdateRequired;
fun getValidGameClientVersions(): List<String>

Related note: See Features note about OnGameClientVersionUpdateRequired.

Bugs and Fixes #

  • Fixed an error where players that were kicked via the KickV1 RPC were unable to join another party due to their session containing their original PARTY_ID. Players can now join another party after being kicked, while still being unable to join their original party.

  • Fixed a server bug that prevented players from receiving a SessionChangedV1Notification when rejoining a match. After rejoining their original match, players will now correctly receive a SessionChangedV1Notification containing their match’s MATCH_ID.

  • Fixed several bugs caused by declining party invites. These bugs included Pragma SDK clearing party states, not providing valid party data, and not allowing valid Pragma SDK actions from being performed. These bugs are fixed for both Unity and Unreal Pragma SDKS.

  • Unreal SDK: Fixed an assertion error with the Unreal SDK when multiple login and disconnects occurred in a row.

  • Portal: Fixed the item details tab opening by itself in a player’s inventory when switching between the Stackable and Instanced tabs.

  • Portal: Fixed an error that prevented removing items from a player’s inventory.

  • Portal: Fixed a bug that required users to press Enter or Return when creating a new tag to an account. You can now click the Apply button directly to create new tags for an account.

  • Portal: Fixed a bug that caused a 404 page to show for 1 second after signing in to Portal with Google.

Docs #

  • [Docs Rename] Services has been renamed to Concepts, and User Guides has been renamed to Tutorials. Old links to Services and User Guides have been redirected, so bookmarks to existing pages will not need to be updated.

  • [Docs Rename] All uses of config files have been updated to reflect the config changes made this release. See related integration note on the config file changes.

OriginalReplacement
LocalConfig.ymllocal-dev.yml
CommonConfig.ymlcommon.yml
  • [Updated Concepts Guide] The Analytics Concepts section has been renamed to Telemetry. The Metrics page in the original Analytics section has been removed.

  • [New Concepts Section] Added a new Concepts section called Operability with three new pages: an Overview page, the Metrics page that was previously in the Analytics section, and the Logging page from the README.

  • [Updated Concepts Guide] Added a warning about account linking on the Cross-Platform Accounts page in the Accounts section.

  • [Updated SDK Guide] Fixed the Unreal SDK Setup Guide Logging Into the Platform page by including a required step on calling InitSession() before using the session, and adding additional clarifying edits.

  • [Updated Concepts Guide] Fixed the Identity Providers page in Accounts with updated code blocks on identity provider configuration.