Integrations and Deprecations 0.6.x #
This topic includes integrations and deprecations for Pragma Version 0.6.0.
Application Error Reclassification #
We audited each Pragma service to make sure all expected failures are classified as Application Errors and all critical errors are classified as Service Errors. This change requires you to update any handling you have implemented for the reclassified errors. Contact your CSM for a list of all error classification changes.
Unreal:
// Result is a TPragmaResult<>
if (Result.IsFailure())
{
// Convert failure into a string regardless if it's a service error or application error
const auto ErrorString = Result.GetErrorAsString();
if (Result.IsTypedFailure())
{
// Add application error handling logic here
if (Result.GetErrorType() == FPragma_Account_AccountNotVerifiedApplicationError::StaticStruct())
{
const auto AppError = Result.ReadError<FPragma_Account_AccountNotVerifiedApplicationError>()
...
}
}
else
{
// Add service error handling logic here
const auto ServiceError = Result.Error();
...
}
}
Unity:
// result is a Pragma.Result<TPayloadType>
if (result.IsFailure)
{
// Convert failure into a string regardless if it's a service error or application error
var errorString = result.ErrorAsString;
if (result.IsTypedFailure)
{
// Add application error handling logic here
if (result.ErrorType == typeof(AccountNotVerifiedApplicationError))
{
var appError = result.ReadError<AccountNotVerifiedApplicationError>();
...
}
}
else
{
// Add service error handling logic here
var serviceError = result.Error;
...
}
}
Kotlin:
// result is a PragmaResult<out TSuccess, out TFailure>
result.onFailure {
// Convert failure into a string regardless if it's a service error or application error
val errorString = it.toString()
if (it.isApplicationError) {
// Add application error handling logic here
val appError: Message = it.applicationError!!.parse()
if (appError is AccountNotVerifiedApplicationError) {
...
}
}
else {
// Add service error handling logic here
val serviceError: ServiceError = it.serviceError
...
}
}
Behavioral integrations #
This section describes changes in behavior due to new/updated functionality. Extra care should be taken when implementing changes to avoid unexpected behaviors or regressions.
[Multiplayer ] Update player event listeners for matchmaking
#
We updated the GameInstanceApi.OnLeftMatchmaking
SDK event to only fire if a player leaves a party while in matchmaking, or if the party leader leaves matchmaking on behalf of the party. When a match is found, only the GameInstanceApi.OnAddedToGameInstance
SDK event fires.
Additionally, the GameInstanceApi.OnFailedToAllocateGameInstance
SDK event was removed in favor of the PartyApi.OnMatchmakingFailed
SDK event with the ERROR_SENDING_PLAYERS_TO_GAME_INSTANCE
reason.
Integration steps:
If you were listening to the
OnLeftMatchmaking
event to detect when a party left matchmaking due to a match being found, you should now listen to theOnAddedToGameInstance
event.For remaining
OnLeftMatchmaking
instances, update the event listeners to expect a player ID and matchmaking left reason.Old GameInstanceApi.OnLeftMatchmaking:
DECLARE_EVENT(UPragmaPartyApi, FLeftMatchmakingEvent); FLeftMatchmakingEvent OnLeftMatchmaking;
public event Action OnLeftMatchmaking;
New GameInstanceApi.OnLeftMatchmaking:
DECLARE_EVENT_TwoParams(UPragmaPartyApi, FLeftMatchmakingEvent, const EPragma_Matchmaking_LeftMatchmakingReason& /* LeftReason */, const FString& /* PlayerId */); FLeftMatchmakingEvent OnLeftMatchmaking;
public event Action<LeftMatchmakingReason, PragmaId> OnLeftMatchmaking;
If you were listening to the
GameInstanceApi.OnFailedToAllocateGameInstance
event to determine that players were not successfully matched and added to a game, instead listen forPartyApi.OnMatchmakingFailed
with the newERROR_SENDING_PLAYERS_TO_GAME_INSTANCE
failure reason.
[Portal ] Update Portal imports and configurations.
#
We made significant changes to Portal to support new features and bring it in line with common web standards, including making it easier to add your own package dependencies.
Integration steps:
- Create a packages.json file in
[project]/portal
. You can now include any dependencies you need in your project in this file. After creating this file you will need to run the portal setup command again: ./pragma portal setup
{
"name": "[project]",
"type": "module",
"version": "1.0.0",
"license": "UNLICENSED",
"private": true,
"dependencies": {
"pragma-portal": "*"
},
"scripts": {
"package": "node ../../web/portal/buildlib/bin/package.js",
"start": "node ../../web/portal/buildlib/bin/start.js",
"test": "npm run test:unit && npm run test:it && npm run test:rpcs",
"test:unit": "node ../../web/portal/buildlib/bin/test.js",
"test:rpcs": "node ../../web/portal/buildlib/bin/check-rpcs.js",
"test:it": "node ../../web/portal/buildlib/bin/test.js --integration"
}
}
#
- Update your Portal configuration file from a commonjs file into an ES6 module. For more information on ES6 modules see Mozilla’s documentation.
- Before:
const somePackage = require('some-package')
module.exports = {
common: { 'assets.js': ['js/global.js'], 'assets.styles': ['css/common.less'] }
}
- After:
import somePackage from 'some-package'
export default { common: { 'assets.js': ['js/global.js'], 'assets.styles': ['css/common.less'] } }
- Add imports for packages anywhere global variables are used.
- Before:
const exampleRef = Vue.ref(true)
const router = VueRouter.useRouter()
const route = VueRouter.useRoute()
const { validate, validateInfos } = antd.Form.useForm(formState, rulesRef)
- After:
import * as Vue from 'vue';
import * as VueRouter from 'vue-router';
import { Form } from 'ant-design-vue';
const exampleRef = Vue.ref(true)
const router = VueRouter.useRouter()
const route = VueRouter.useRoute()
const { validate, validateInfos } = Form.useForm(formState, rulesRef)
[Portal ] Removal of Legacy Inventory Views and Content Tabs
#
We removed the legacy Inventory and Content views in the Game Operator Portal.
If you are using Inventory Service, you can reenable these features. You can do this by updating your project’s portal config.
Update portal config at: [project]/portal/src/config/default.js
export default {
common: {
'app.featureToggles': {
"LEGACY\_INVENTORY": true
}
}
You can also enable the views through the Portal’s Development Tools, select the Feature Toggles tab and toggle on LEGACY_INVENTORY
.
Syntax integrations #
This section describes changes in naming, file locations, and other syntactical updates.
[Multiplayer ] Remove the PartyConfig.repeatInviteDelaySeconds configuration value from your YAML files
#
We have discontinued and removed support for the party repeatInviteDelaySeconds
configuration, which set the time a player had to wait before sending another party invite to the same player.
Integration steps:
- If you overrode the
repeatInviteDelaySeconds
configuration, remove it from your YAML files. - If you want to enforce a repeat invite delay value, you can customize the Party Plugin
handleSendInviteRequest()
and party exts to track when each invite was sent.
[Multiplayer ] Update Game Instance Plugin server connection/disconnection and expiration method signatures
#
Previously, the Game Instance Plugin onGameServerDisconnected()
, onGameServerFailedToConnectInitialPlayers()
, and onGameInstanceExpired()
methods accepted a read-only copy of the game instance. Now, you can directly modify the game instance.
Integration steps: If you override any of the above Game Instance Plugin methods, make the following changes:
- In all of the above methods, change the first parameter from
readOnlyGameInstance: ReadOnlyGameInstance
togameInstanceSnapshot: GameInstance.GameInstance
- In
onGameServerFailedToConnectInitialPlayers()
change the second parameter frominitialPlayers: List<ReadOnlyGamePlayer>
toinitialPlayers: List<GameInstance.GamePlayer>
[Multiplayer ] Rename Game Instance Plugin onEndGame() to handleBackendEndRequest()
#
To better standardize naming patterns, we renamed GameInstancePlugin.onEndGame()
to GameInstancePlugin.handleBackendEndRequest()
. Functionality remains the same.
Integration steps: Find all occurrences of GameInstancePlugin.onEndGame()
and replace them with GameInstancePlugin.handleBackendEndRequest()
.
[Multiplayer ] Add new ExtGameServerUnlinkRequest proto
#
We create a new ExtGameServerUnlinkRequest
proto for use in game server unlinking flows. This proto must be defined in your project protos to compile.
Integration steps:
- Option 1 (preferred): Run the 0-6-0 upgrade script using the Pragma CLI:
- ./pragma update 0-6-0
- Option 2: Manually add the proto definition to your
PROJECT_PROTOS/src/main/proto/shared/gameInstanceExt.proto
file:- message ExtGameServerUnlinkRequest {}
[Accounts ] Rename Unlink endpoints
#
We renamed the unlink endpoints to more accurately reflect the actual action of the RPC.
Integration steps:
- Update any references of the
UnlinkIdentityProviderAccount<*>V1
toDeleteIdentityProviderAccount<*>V1
RPC in the platform, Portal, or SDK. - Specify the
providerAccountId
when deleting an identity provider account.
[Accounts ] Update custom identity provider plugins
#
We added new configuration values to the shared Identity Provider Plugin configuration. These configurations will need to be added to the getPublicInfo
method.
Integration steps:
- Add the following configuration values to your
getPublicInfo
method in your custom identity provider plugins:accountLinkingCooldownInDays
accountLinkingOneAssociationOnly
accountUnlinkingEnabled
Before:
override fun getPublicInfo(): Map<String, String> {
return mapOf(
"showPortalLoginButton" to config.showPortalLoginButton.toString(),
"clientId" to config.clientId,
"playerLoginEnabled" to config.playerLoginEnabled.toString(),
"operatorLoginEnabled" to config.operatorLoginEnabled.toString(),
"accountLinkingEnabled" to config.accountLinkingEnabled.toString()
)
}
After:
override fun getPublicInfo(): Map<String, String> {
return mapOf(
"showPortalLoginButton" to config.showPortalLoginButton.toString(),
"clientId" to config.clientId,
"playerLoginEnabled" to config.playerLoginEnabled.toString(),
"operatorLoginEnabled" to config.operatorLoginEnabled.toString(),
"accountLinkingEnabled" to config.accountLinkingEnabled.toString(),
"accountUnlinkingEnabled" to config.accountUnlinkingEnabled.toString(),
"accountLinkingOneAssociationOnly" to config.accountLinkingOneAssociationOnly.toString(),
"accountLinkingCooldownInDays" to config.accountLinkingCooldownInDays.toString()
)
}
[PlayerData ] Update to PlayerDataSnapshot
#
The `PlayerDataSnapshot.getUniqueEntity` function no longer throws an exception if the Entity is not found and instead returns null. Update any calls to this function and add in your own handling if the Entity is not found.
before | after |
---|---|
fun getUniqueEntity(name: String): Entity | fun getUniqueEntity(name: String): Entity? |
#
Deprecation removals #
We removed the following previously deprecated items. If you haven’t integrated the changes, follow the instructions in the linked deprecation and/or integration notes.
- Party Plugin
returnFromGameInstance()
method. Deprecation note. handleBackendCreateByMatchmaking()
,handleBackendAddPlayersByMatchmakingRequest()
, and related ext build methods. Deprecation note.NewGameInstance.setExtGamePlayer()
method and theExtGameInstance
value in theNewGameInstance
constructor. Deprecation note and integration note.ExtAddedToGame
payload and thebuildExtAddedToGame()
method in favor of using the Game Instance data stores. Integration note.
New deprecations #
[Multiplayer ] MatchApi.RequestStartGame() deprecated in favor of MatchApi.Link()
#
To match the naming of the new MatchApi.Unlink()
method, we added a MatchApi.Link()
method to replace MatchApi.RequestStartGame()
.
Integration steps:
Replace instances of
MatchApi.RequestStartGame()
withMatchApi.Link()
. Note thatLink()
includes aGameStartDataDelegate
with game start data.Old:
void RequestStartGame(FString GameInstanceId);
//Unity: public void RequestStartGame(PragmaId gameInstanceId)
New:
void Link( const FString& GameInstanceId, const FGameStartDataDelegate& OnComplete);
public void Link( PragmaId gameInstanceId, GameStartDataDelegate onComplete)
Instead of listening to the
MatchApi.OnGameStart
andMatchApi.OnGameStartFailed
SDK events, use theResult<GameStart>
returned in theGameStartDataDelegate
to handle success and failure cases.
Note: The OnGameStart/Failed
events will still trigger for the Match API StartReportCapacityPolling()
and RequestStartGame()
SDK methods.
MatchApi.RequestStartGame()
will be removed in version 0.7.0.
[Accounts ] Updated Account Plugin signatures
#
We updated the onAccountCreated
and onAccountLogin
methods in the Account Plugin to include the IdProviderAccount
object used to login. The old methods have been annotated as deprecated and will be removed in release 0.7.0.
Integration steps: Update any custom Account Plugins to now accept the new idProviderAccount
parameter in the onAccountCreated
and onAccountLogin
methods.
[Engine ] Database host credentials deprecated in favor of identifier schemas
#
Identifier schemas deduplicate common database config and are being rolled out as the standard.
Integrations steps:
Replace the deprecated service configurations with the new configurations for Pragma-managed or self-manage shards:
Deprecated configuration (unpartitioned):
[Service]DaoConfig:
databaseConfig:
driver: "MYSQLDB"
username: "superuser"
password: "[encrypted-password]"
hostPortSchemas: "database.[shard].[studio].pragmaengine.com:3306/[table schema]"
Deprecated configuration (partitioned):
[Service]DaoConfig:
databaseConfig:
driver: "MYSQLDB"
username: "superuser"
password: "[encrypted-password]"
hostPortSchemas:
1: "database.[shard].[studio].pragmaengine.com:3306/[table schema]"
For managed shards - Auto-generated identifier schemas: Contact your customer service representative to enable this feature, and then update your database configuration to reference the auto-generated defaultIdentifier
field.
For unpartitioned database:
serviceConfigs:
[Service]DaoConfig:
databaseConfig:
identifierSchema:
identifier: "defaultIdentifier"
schema: "[table schema]" # ex: for the shard name test: test_social_account
For partitioned database:
serviceConfigs:
[Service]DaoConfig:
databaseConfig:
identifierSchemas:
1:
identifier: "defaultIdentifier"
schema: "[table schema]" # ex: for the shard name test: test_social_account
Self-managed shards / local development: Move the database host credentials to the SharedDatabaseConfigServiceConfig
, and then reference the credentials by its identifier field.
serviceConfigs:
SharedDatabaseConfigServiceConfig:
databaseConfigsByIdentifier:
defaultDb:
username: "superuser"
password: "password"
host: "localhost"
# do this for all unpartitioned database tables
[Service]DaoConfig:
databaseConfig:
identifierSchema:
identifier: "defaultDb"
schema: "[table schema]"
# do this for all partitioned database tables
[Service]DaoConfig:
databaseConfig:
identifierSchemas:
1:
identifier: "defaultDb"
schema: "[table schema]"