Manage Game Data #
This topic provides instructions on building and updating custom game data using the data store.
Get game instances by player #
Fetch game instance IDs for a specific player
Get from player client #
You can use the game instance cache in the SDK for Unreal and Unity to fetch game instance information for the current player:
//Get a player's specific game instance
PragmaPlayer->GameInstanceApi().GetGameInstanceCache()->GetGameInstance(gameInstanceId);
//Use if not allowing players to be in more than one game instance at a time
PragmaPlayer->GameInstanceApi().GetGameInstanceCache()->GetFirstGameInstance();
//Get array of the player's game instances
PragmaPlayer->GameInstanceApi().GetGameInstanceCache()->GetGameInstances();
//Get a player's specific game instance
PragmaPlayer.GameInstanceApi().GetGameInstanceCache().GetGameInstance(gameInstanceId);
//Use if not allowing players to be in more than one game instance at a time
PragmaPlayer.GameInstanceApi().GetGameInstanceCache().GetFirstGameInstance();
//Get array of the player's game instances
PragmaPlayer.GameInstanceApi().GetGameInstanceCache().GetGameInstances();
Get from backend #
The backend GameInstanceApi.kt
class provides a few methods that allow you to fetch game instance information for players:
getIdsForPlayers(playerId: PlayerId)
: Returns a list of game instance IDs for the game instances the provided player is in.getForPlayer(playerId: PlayerId)
: Returns a list of game instance summaries for the game instances the provided player is in.
Build custom data #
Create game instance and game player data
Using the Game Instance DataStore
and PlayerSync
features, you can create and manage custom data about a game instance and its players. You can handle data requests coming from the player, game server, or backend separately.
Define ExtData message #
You define custom game instance and game player details in the ExtData
message in your gameInstanceExt.proto
file.
Example usage:
In the following example, ExtData
includes information on game phase and player points. Because ExtData
holds data for both game instances and players, we’re using the oneof
keyword to ensure only one value is set at a time. We expect the gameInstance.dataStore
to use the game_phase
field, and the gamePlayer.dataStore
to use the player_points
field.
message ExtData {
oneof my_data {
string game_phase = 1;
int32 player_points = 2;
}
}
Create ExtData #
Use the the DataStore create()
method to create ExtData
for a game instance or game player. Create()
accepts the following parameters:
key
- unique string used to reference the datadata
- data to be storedplayerSync
- how the data should be synced with players in the game instance, if at all:Hidden
: Data is not synced with any player/party/team and is accessible only from theGameInstancePlugin
Player
: Data is sent to a specific player client in the game instanceParty
: Data is sent to player clients for all players in a specific party in the game instanceTeam
: Data is sent to player clients for all players on a specific team in the game instancePublic
: Data is sent to all players clients in the game instance
interface DataStore {
fun create(
key: String,
data: ExtData,
playerSync: PlayerSync = PlayerSync.Hidden
): ExtData
}
The data store create()
method can be called by any game instance plugin method.
Example usage:
As an example, say we want to set a game phase and a player point value as soon as a game instance is created from a custom service. We can use the ExtData
message defined above in the Game Instance Plugin’s handleBackendCreateRequest()
method, which is invoked when a game instance is created from a backend service.
In our example, we set the game instance game phase to “loading” and each game player’s player points to 0. Notice that the game phase value is available to everyone (PlayerSync.Public
), while the player points value is only available to the specific game player (PlayerSync.Player
).
override suspend fun handleBackendCreateRequest(
gameInstanceSnapshot: GameInstance.GameInstance,
requestExt: ExtBackendCreateRequest,
playersToAdd: Map<PlayerId, ExtBackendAddPlayer>
) {
val startingGamePhaseExtData = ExtData.newBuilder().setGamePhase(
"loading"
).build()
val startingPlayerPointsExtData = ExtData.newBuilder().setPlayerPoints(
0
).build()
gameInstanceSnapshot.dataStore.create(
"gamePhase", startingGamePhaseExtData, PlayerSync.Public
)
playersToAdd.forEach {
it.dataStore.create(
"playerPoints",
startingPlayerPointsExtData,
PlayerSync.Player(it.playerId)
)
}
//...
}
Get custom data #
Fetch data store values
Use the DataStore get()
method to fetch data by key value:
interface DataStore{
fun get(key: String): ExtData?
}
Update custom data #
Update game instance and game player data
Use the DataStore updateData()
method to update ExtData
for a game instance or game player. UpdateData()
accepts a key identifying the value to update, as well as the ExtData
itself.
interface DataStore{
fun updateData(key: String, data: ExtData)
}
The data store updateData()
method can be called by any game instance plugin method. The following examples call updateData()
from the plugin’s handlePlayerUpdateRequest()
and handleBackendUpdateRequest()
methods, allowing player clients, game clients, and backend processes to request updates to ExtData
values.
From player client #
To request game instance data updates from the player client, use the Game Instance API’s Update()
method with the ExtPlayerUpdateRequest
payload, which describes how the game instance data should be updated. Players can only request updates for games instances they are in.
Player->GameInstanceApi()->Update(
const FString& GameInstanceId,
const FPragma_GameInstance_ExtPlayerUpdateRequest& RequestExt,
const FOnCompleteDelegate& OnComplete
)
Player.GameInstanceApi.Update(
PragmaId gameInstanceId,
ExtPlayerUpdateRequest requestExt,
CompleteDelegate onComplete
)
When called, GameInstanceApi.Update()
invokes the Game Instance Plugin’s handlePlayerUpdateRequest()
method.
Example usage:
We can customize handlePlayerUpdateRequest()
to update the ExtData
with the ExtPlayerUpdateRequest
:
suspend fun handlePlayerUpdateRequest(
gameInstanceSnapshot: GameInstance.GameInstance,
requestingPlayer: GameInstance.GamePlayer,
requestExt: ExtPlayerUpdateRequest
) {
val currentPlayerPointsExtData: ExtData = requestingPlayer.dataStore.get("playerPoints")
requestingPlayer.dataStore.updateData(
"playerPoints", currentPlayerPointsExtData.playerPoints + requestExt.pointsToAdd)
}
From game server or backend #
Requests from game servers or backed Pragma processes are handled with the Game Instance Plugin’s handleBackendUpdateRequest()
method. We can customize this method to update the ExtData
with the ExtBackendUpdateRequest
provided by MatchApi.UpdateGameInstance()
(game server method) or the GameInstanceApi.kt
Kotlin class’s update()
method (Pragma backend method):
From game server:
To request game instance updates from the game server, use the Match API’s UpdateGameInstance()
method with the ExtBackendUpdateRequest
payload, which describes how the game instance data should be updated.
Server->MatchApi()->UpdateGameInstance(
const FString& GameInstanceId,
const FPragma_GameInstance_ExtBackendUpdateRequest& RequestExt,
const FOnCompleteDelegate& OnComplete
);
Server.MatchApi.UpdateGameInstance(
PragmaId gameInstanceId
ExtBackendUpdateRequest requestExt,
CompleteDelegate onComplete
);
From backend:
Backed processes and services can request to update game data via the GameInstanceApi.kt
backend class’s update()
method.
- Create an instance of the
GameInstanceApi.kt
Kotlin class in a Pragma plugin or custom service:
private val gameInstanceApi: GameInstanceApi = GameInstanceApi(service)
- Call the class’s
update()
method with the game instance ID andExtBackendUpdateRequest
payload:
suspend fun update(
gameInstanceId: GameInstanceId,
backendUpdateRequest: ExtBackendUpdateRequest,
): PragmaResult<Unit, PragmaFailure>
Customize handleBackendUpdateRequest:
Both the MatchApi.UpdateGameInstance()
method and the GameInstanceApi class’s update()
method invoke the Game Instance Plugin’s handleBackendUpdateRequest()
method. We can customize this method to update the ExtData
with the ExtBackendUpdateRequest
.
Example usage:
For example, say you want the game server to be able to advance the game instance’s game phase. You can call the game instance’s DataStore updateData()
method from the Game Instance Plugin’s handleBackendUpdateRequest()
method. The game server will send the new game phase data on the requestExt
.
interface GameInstancePlugin {
suspend fun handleBackendUpdateRequest(
gameInstanceSnapshot: GameInstance.GameInstance,
requestExt: ExtBackendUpdateRequest
) {
gameInstanceSnapshot.dataStore.updateData(
"gamePhase", requestExt.newGamePhase)
}
}
If the data is synced to a player, creating or updating the data store will trigger the GameInstanceApi OnGameInstanceUpdated
event on the player’s game client once the plugin completes, along with the created data.
Update sync #
In addition to updating the ext data on the data store, you can update the PlayerSync
value to change data visibility. To do so, use the DataStore updateSync()
method with the ext key value and new sync option (Hidden
, Player
, Party
, Public
):
interface DataStore{
fun updateSync(
key: String,
playerSync: PlayerSync
)
}
Update game instances in matchmaking #
If the game instance being updated is currently in matchmaking, all of the matchmaking ext
payloads for the game instance will be recalculated and sent to matchmaking to ensure the matchmaking representation of the game instance is up to date. See Add more players for more information about which plugins are invoked during this operation.
Delete custom data #
Delete custom game instance and game player data
Use the DataStore delete()
method to delete data from the data store by key value:
interface DataStore{
fun delete(key: String)
}
Related events and errors #
Related events:
Related errors:
- GameInstanceService_UnknownGameInstanceId
- GameInstanceService_FailedToUpdateMatchmakingGameInstance