Batch operations calls #

You can batch up operations but authoring a operation that calls others.

Calling operations from another operation #

Below is an example of a processGameEnd operation that calls two other operations: one to grant lootboxes and another to update experience.

This example code is not complete. It highlights how you can organize your player data code and access other operations.

Experience SubService

package documentation

import pragma.playerdata.Context
import pragma.playerdata.PlayerDataContentLibrary
import pragma.playerdata.PlayerDataOperation
import pragma.playerdata.PlayerDataRequest
import pragma.playerdata.PlayerDataResponse
import pragma.playerdata.PlayerDataSubService
import pragma.rpcs.SessionType

class ExperienceSubService(
    contentLibrary: PlayerDataContentLibrary
) : PlayerDataSubService(contentLibrary) {

    @PlayerDataOperation(sessionTypes = [SessionType.SERVICE, SessionType.PARTNER])
    fun processGameEnd(
        request: ProcessGameEnd,
        context: Context
    ): ProcessGameEndResponse {

        // get the sub-service from context and call one of its operations
        context.getSubService(LootboxSubService::class)
            .grantLootboxes(
                GrantLootboxRequest(request.lootBoxesToGrant),
                context // send context
            )

        // any operations in the same sub-service class can be called directly
        updateExperience(UpdateExperienceRequest(request.xpGained), context)

        return ProcessGameEndResponse()
    }

    @PlayerDataOperation(sessionTypes = [SessionType.SERVICE, SessionType.PARTNER])
    fun updateExperience(
        request: UpdateExperienceRequest,
        context: Context
    ): UpdateExperienceResponse {
        /**
         * Get component that store experience and update
         */
        return UpdateExperienceResponse()
    }
}

data class ProcessGameEnd(
    val xpGained: Int,
    val lootBoxesToGrant: Int,
): PlayerDataRequest
class ProcessGameEndResponse: PlayerDataResponse

data class UpdateExperienceRequest(
    val xpGained: Int,
): PlayerDataRequest
class UpdateExperienceResponse: PlayerDataResponse

Lootbox SubService

package documentation

import pragma.playerdata.Context
import pragma.playerdata.PlayerDataContentLibrary
import pragma.playerdata.PlayerDataOperation
import pragma.playerdata.PlayerDataRequest
import pragma.playerdata.PlayerDataResponse
import pragma.playerdata.PlayerDataSubService
import pragma.rpcs.SessionType

class LootboxSubService(
    contentLibrary: PlayerDataContentLibrary
): PlayerDataSubService(contentLibrary) {
    @PlayerDataOperation(sessionTypes = [SessionType.SERVICE, SessionType.PARTNER])
    fun grantLootboxes(
        request: GrantLootboxRequest,
        context: Context
    ): GrantLootboxResponse {
        // grant a loot box ...
        return GrantLootboxResponse()
    }
}

data class GrantLootboxRequest(val amount: Int): PlayerDataRequest
class GrantLootboxResponse: PlayerDataResponse

Batch from another game service or plugin #

You can make a batch call of operations from any game service or plugin using a PlayerDataClient and the doBatchOperation function.

Example from a game instance plugin

package documentation

import pragma.content.ContentDataNodeService
import pragma.gameinstance.ExtBackendRemovePlayer
import pragma.gameinstance.ExtBackendRemovePlayersRequest
import pragma.gameinstance.GameInstance.GameInstance
import pragma.gameinstance.GameInstancePlugin
import pragma.playerdata.kotlinclient.PlayerDataClient
import pragma.services.Service
import pragma.utils.PlayerId

class ExampleGameInstancePlugin(
    service: Service,
    contentDataNodeService: ContentDataNodeService,
    // use a PlayerDataClient to make calls to Player Data using the kotlin types
    private val playerDataClient: PlayerDataClient = PlayerDataClient(service)
): GameInstancePlugin {
    override suspend fun handleBackendRemovePlayersRequest(
        gameInstanceSnapshot: GameInstance,
        requestExt: ExtBackendRemovePlayersRequest,
        playersToRemove: Map<PlayerId, ExtBackendRemovePlayer>
    ) {
        playersToRemove.forEach { (playerId, extBackendRemovePlayer) ->
            updatePlayerData(playerId, extBackendRemovePlayer)
        }
    }

    private suspend fun updatePlayerData(
        playerId: PlayerId, 
        extBackendRemovePlayer: ExtBackendRemovePlayer
    ) {

        /**
          Send in a list of operations 
          * All changes will be applied in one database transaction.
          * If any of the operations throw an exception, 
             then all calls will fail. Player data will be unchanged. 
             Check the result.onFailure for what error occurred. 
         */
        val pragmaResult = playerDataClient.doBatchOperation(
            listOf(
                GrantLootboxRequest(requestExt.lootBoxesEarned),
                UpdateExperienceRequest(requestExt.xpGained),
            ),
            playerId
        )
        pragmaResult.onFailure { pragmaFailure ->
            // check failure type and handle as wanted
        }
        pragmaResult.onSuccess { responses ->
            // list of responses
        }
    }
}