Integrate session storage
Introduction
AccelByte Gaming Services (AGS) Session has storage capability that offers a versatile solution that caters to a wide range of gaming clients. It facilitates seamless loading within sessions, while providing distinct permissions for leader and public data. Public data will be accessible for reading but can only be modified by its owner. This functionality streamlines the storage of session data for game developers, enhancing overall efficiency.
Session storage is available for both game sessions and party sessions:
Game Session Storage
- Scope: Data tied to a specific game session / match.
- Access: Supports leader and member storage; leader storage is only writable by the leader, member storage only by that member.
- Usage: Shared session metadata and per-member data, readable (with permissions) by leaders/members to coordinate gameplay.
- Lifecycle: Exists only for the lifetime of the game session.
Party Session Storage
- Scope: Data tied to a party session (group of players).
- Access: Each player can only modify their own storage; not exposed to other players or broadly to the game client.
- Usage: Personal, party-scoped data (e.g., loadouts or per-member prefs) that others can't change.
- Lifecycle: Exists only while the party session is active.
This article contains code snippets for the following functions:
- Update game session storage
- Read game session storage
- Listen to game session storage updated event
- Update party session storage
- Read party session storage
- Listen to party session storage updated event
How it works
The diagram below shows how session storage works using AGS.
A player is granted permission to update or insert data into session storage if they are both registered and active in the game session. Access is restricted to players who have joined and connected to the respective game session. Players who already left or disconnected from a session will not be allowed to update the session storage.
Update session storage
If there's no data in the session storage, create it. If there's already data, update it in the game session.
Update session leader storage
Modify the data for session leader storage. This function can only modify the data of session storage for leader.
- Unreal
- Unity
// Prepare the storage data
FJsonObjectWrapper LeaderStorageData;
LeaderStorageData.JsonObject = MakeShared<FJsonObject>();
LeaderStorageData.JsonObject->SetStringField(TEXT("map_name"), TEXT("Desert Arena"));
LeaderStorageData.JsonObject->SetBoolField(TEXT("is_ranked"), true);
LeaderStorageData.JsonObject->SetNumberField(TEXT("max_score"), 1000);
// Set a listener when the update session leader storage to backend completes
FOnUpdateSessionLeaderStorageCompleteDelegate OnUpdateLeaderStorageComplete = FOnUpdateSessionLeaderStorageCompleteDelegate::CreateLambda(
[](FName SessionName, const FOnlineError& ErrorInfo)
{
if (ErrorInfo.bSucceeded)
{
// Do something after updating leader storage completes
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Error on updating session leader storage. Code: %s, Reason: %s"), *ErrorInfo.ErrorCode, *ErrorInfo.ErrorMessage.ToString());
return;
}
});
SessionInterface_User1->AddOnUpdateSessionLeaderStorageCompleteDelegate_Handle(OnUpdateLeaderStorageComplete);
// Execute updating session leader storage to the backend
SessionInterface_User1->UpdateSessionLeaderStorage(LocalUserId1.ToSharedRef().Get(), NAME_GameSession, LeaderStorageData);
// Obtained from the result callback of creating a game session, joining a game session, etc.
string sessionId = "<game-session-id>";
var data = new SessionStorageTestData
{
StringField = "This is a string value",
IntegerField = 99,
BooleanField = true,
FloatField = 3.14f,
DoubleField = 2.718,
ArrayOfIntegerField = new int[] { 1, 1, 2, 3, 5, 8 }
};
var jData = JObject.FromObject(data);
AccelByteSDK.GetClientRegistry().GetApi().GetSession().UpdateLeaderStorage(sessionId, jData, result =>
{
if (result.IsError)
{
// Handle the error
Debug.Log(result.Error.Message);
return;
}
// Do something
});
Update session member storage
Modify the data for session member storage. This function can only modify the data of session storage for members (non-leaders).
- Unreal
- Unity
// Prepare the member storage data
FJsonObjectWrapper MemberStorageData;
MemberStorageData.JsonObject = MakeShared<FJsonObject>();
MemberStorageData.JsonObject->SetStringField(TEXT("weapon"), TEXT("AK-47"));
MemberStorageData.JsonObject->SetNumberField(TEXT("kills"), 10);
MemberStorageData.JsonObject->SetNumberField(TEXT("deaths"), 5);
// Set the listener when update session storage to the backend completes
FOnUpdateSessionMemberStorageCompleteDelegate OnUpdateSessionMemberStorageComplete = FOnUpdateSessionMemberStorageCompleteDelegate::CreateLambda(
[](FName SessionName, const FUniqueNetId& UpdatedMemberId, const FOnlineError& ErrorInfo)
{
if (ErrorInfo.bSucceeded)
{
// Do something after the update to the backend completes
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Error on updating session member storage. Code: %s, Reason: %s"), *ErrorInfo.ErrorCode, *ErrorInfo.ErrorMessage.ToString());
return;
}
});
SessionInterface_User1->AddOnUpdateSessionMemberStorageCompleteDelegate_Handle(OnUpdateSessionMemberStorageComplete);
// Execute updating session member storage to the backend
SessionInterface_User1->UpdateSessionMemberStorage(LocalUserId1.ToSharedRef().Get(), NAME_GameSession, MemberStorageData);
// Obtained from the result callback of creating a game session, joining a game session, etc
string sessionId = "<game-session-id>";
var data = new SessionStorageTestData
{
StringField = "This is a string value",
IntegerField = 99,
BooleanField = true,
FloatField = 3.14f,
DoubleField = 2.718,
ArrayOfIntegerField = new int[] { 1, 1, 2, 3, 5, 8 }
};
var jData = JObject.FromObject(data);
AccelByteSDK.GetClientRegistry().GetApi().GetSession().UpdateMemberStorage(sessionId,
jData,
result =>
{
if (result.IsError)
{
// Handle the error
Debug.Log(result.Error.Message);
return;
}
// Do something
});
Read session storage
Get the data of session storage with a JSON object type in the game session.
- Unreal
- Unity
Read session leader storage
Get the data of session storage from the leader.
// Get the named session object
const FNamedOnlineSession* GameSession = SessionInterface_User1->GetNamedSession(NAME_GameSession);
if (GameSession == nullptr)
{
return;
}
// Get the named game session's info object and cast it to FOnlineSessionInfoAccelByteV2
TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(GameSession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}
// Get session leader storage data
FJsonObjectWrapper LeaderStorage;
bool bSuccess = SessionInfo->GetSessionLeaderStorage(LeaderStorage);
if (bSuccess && LeaderStorage.JsonObject.IsValid())
{
// Access the storage data
FString MapName = LeaderStorage.JsonObject->GetStringField(TEXT("map_name"));
bool bIsRanked = LeaderStorage.JsonObject->GetBoolField(TEXT("is_ranked"));
int32 MaxScore = LeaderStorage.JsonObject->GetNumberField(TEXT("max_score"));
// Do something with the data
}
Read session member storage
Get the data of session storage from the members.
// Get the named session object
const FNamedOnlineSession* GameSession = SessionInterface_User1->GetNamedSession(NAME_GameSession);
if (GameSession == nullptr)
{
return;
}
// Get the named game session's info object and cast it to FOnlineSessionInfoAccelByteV2
TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(GameSession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}
// Read all session member storage
TUniqueNetIdMap<FJsonObjectWrapper> AllMemberStorages;
bool bSuccess = SessionInfo->GetAllSessionMemberStorage(AllMemberStorages);
if (bSuccess)
{
// Loop through all member storage
for (const TPair<FUniqueNetIdRef, FJsonObjectWrapper>& MemberStorage : AllMemberStorages)
{
const FUniqueNetIdRef& MemberId = MemberStorage.Key;
const FJsonObjectWrapper& Storage = MemberStorage.Value;
if (Storage.JsonObject.IsValid())
{
// Access the member's storage data
FString Weapon = Storage.JsonObject->GetStringField(TEXT("weapon"));
int32 Kills = Storage.JsonObject->GetNumberField(TEXT("kills"));
int32 Deaths = Storage.JsonObject->GetNumberField(TEXT("deaths"));
// Do something with the data
}
}
}
// Read specific member storage
FJsonObjectWrapper SpecificMemberStorage;
bSuccess = SessionInfo->GetSessionMemberStorage(LocalUserId1.ToSharedRef(), SpecificMemberStorage);
if (bSuccess && SpecificMemberStorage.JsonObject.IsValid())
{
// Access specific member's storage data
FString Weapon = SpecificMemberStorage.JsonObject->GetStringField(TEXT("weapon"));
// Do something with the data
}
Get the data of session storage from the leader and members.
// Obtained from the result callback of creating a game session, joining a game session, etc
string sessionId = "<game-session-id>";
AccelByteSDK.GetClientRegistry().GetApi().GetSession().GetGameSessionDetailsBySessionId(sessionId, result =>
{
if (result.IsError)
{
// Handle the error
Debug.Log(result.Error.Message);
return;
}
var sessionStorage = result.Value.Storage;
// Do something
});
Listen to session storage updated event
An event that will be sent to all users in the same game session when there is a session storage update. This event is sent through a WebSocket connection to ensure that they've been received in real time.
- Unreal
- Unity
Session leader storage updated event
Received when there is a session storage update from leader.
// Get notified when there is an update to session leader storage from backend
FOnSessionLeaderStorageUpdateReceivedDelegate OnSessionLeaderStorageUpdated = FOnSessionLeaderStorageUpdateReceivedDelegate::CreateLambda(
[](FName SessionName)
{
if (SessionName == NAME_GameSession)
{
// Session leader storage has been updated
// You can retrieve the updated storage data here
}
});
auto DelegateHandle = SessionInterface_User1->AddOnSessionLeaderStorageUpdateReceivedDelegate_Handle(OnSessionLeaderStorageUpdated);
// When done listening, clear the delegate
// SessionInterface_User1->ClearOnSessionLeaderStorageUpdateReceivedDelegate_Handle(DelegateHandle);
Session member storage updated event
Received when there is a session storage update from a member.
// Get notified when a session member updates their storage
FOnSessionMemberStorageUpdateReceivedDelegate OnSessionMemberStorageUpdated = FOnSessionMemberStorageUpdateReceivedDelegate::CreateLambda(
[](FName SessionName, const FUniqueNetId& UpdatedMemberId)
{
if (SessionName == NAME_GameSession)
{
// Get the session info to access the updated member storage
const FNamedOnlineSession* GameSession = SessionInterface_User1->GetNamedSession(SessionName);
if (GameSession == nullptr)
{
return;
}
TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(GameSession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}
// Get the updated member's storage
FJsonObjectWrapper UpdatedMemberStorage;
bool bSuccess = SessionInfo->GetSessionMemberStorage(UpdatedMemberId.AsShared(), UpdatedMemberStorage);
if (bSuccess && UpdatedMemberStorage.JsonObject.IsValid())
{
// Access the updated storage data
FString Weapon = UpdatedMemberStorage.JsonObject->GetStringField(TEXT("weapon"));
int32 Kills = UpdatedMemberStorage.JsonObject->GetNumberField(TEXT("kills"));
// Do something with the updated storage
}
}
});
auto DelegateHandle = SessionInterface_User1->AddOnSessionMemberStorageUpdateReceivedDelegate_Handle(OnSessionMemberStorageUpdated);
// When done listening, clear the delegate
// SessionInterface_User1->ClearOnSessionMemberStorageUpdateReceivedDelegate_Handle(DelegateHandle);
Received when there is a session storage update from the leader or a member.
AccelByteSDK.GetClientRegistry().GetApi().GetLobby().SessionV2StorageChanged += result =>
{
if (result.IsError)
{
// Handle the error
Debug.Log(result.Error.Message);
return;
}
// Do something when receiving an update to session leader or member storage
};
Update party session storage
Update the party session storage for the current user. Each party member can only update their own storage data. This will overwrite the current party session storage if successful.
- Unreal
// Prepare the party storage data
FJsonObjectWrapper PartyStorageData;
PartyStorageData.JsonObject = MakeShared<FJsonObject>();
PartyStorageData.JsonObject->SetStringField(TEXT("playerRole"), TEXT("tank"));
PartyStorageData.JsonObject->SetNumberField(TEXT("playerLevel"), 42);
PartyStorageData.JsonObject->SetBoolField(TEXT("isReady"), true);
// Set the listener when update party session storage to the backend completes
FOnUpdatePartySessionStorageCompleteDelegate OnUpdatePartyStorageComplete = FOnUpdatePartySessionStorageCompleteDelegate::CreateLambda(
[](FName SessionName, const FOnlineError& ErrorInfo)
{
if (ErrorInfo.bSucceeded)
{
// Do something after updating party storage completes
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Error on updating party session storage. Code: %s, Reason: %s"), *ErrorInfo.ErrorCode, *ErrorInfo.ErrorMessage.ToString());
return;
}
});
auto DelegateHandle = SessionInterface_User1->AddOnUpdatePartySessionStorageCompleteDelegate_Handle(OnUpdatePartyStorageComplete);
// Execute updating party session storage to the backend
SessionInterface_User1->UpdatePartySessionStorage(*LocalUserId1.Get(), PartyStorageData);
// When done listening, clear the delegate
// SessionInterface_User1->ClearOnUpdatePartySessionStorageCompleteDelegate_Handle(DelegateHandle);
Read party session storage
Get the party session storage data from the local cache or query from the backend.
- Unreal
Read party storage from local cache
// Get the party session
const FNamedOnlineSession* PartySession = SessionInterface_User1->GetPartySession();
if (PartySession == nullptr)
{
return;
}
// Get the party session's info object and cast it to FOnlineSessionInfoAccelByteV2
TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(PartySession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}
// Read all party members' storage
TUniqueNetIdMap<FJsonObjectWrapper> AllPartyStorages;
bool bSuccess = SessionInfo->GetAllPartyStorage(AllPartyStorages);
if (bSuccess)
{
// Loop through all party members' storage
for (const TPair<FUniqueNetIdRef, FJsonObjectWrapper>& PartyStorage : AllPartyStorages)
{
const FUniqueNetIdRef& MemberId = PartyStorage.Key;
const FJsonObjectWrapper& Storage = PartyStorage.Value;
if (Storage.JsonObject.IsValid())
{
// Access the party member's storage data
FString PlayerRole = Storage.JsonObject->GetStringField(TEXT("playerRole"));
int32 PlayerLevel = Storage.JsonObject->GetNumberField(TEXT("playerLevel"));
bool bIsReady = Storage.JsonObject->GetBoolField(TEXT("isReady"));
// Do something with the data
}
}
}
// Read specific party member's storage
FJsonObjectWrapper SpecificMemberStorage;
bSuccess = SessionInfo->GetPartyStorage(LocalUserId1.ToSharedRef(), SpecificMemberStorage);
if (bSuccess && SpecificMemberStorage.JsonObject.IsValid())
{
// Access specific member's storage data
FString PlayerRole = SpecificMemberStorage.JsonObject->GetStringField(TEXT("playerRole"));
// Do something with the data
}
Query party storage from backend
// Query party session storage from backend
FUniqueNetIdAccelByteUserPtr AccelByteUserId = FUniqueNetIdAccelByteUser::Cast(LocalUserId1.ToSharedRef().Get());
SessionInterface_User1->GetPartySessionStorage(AccelByteUserId,
FOnGetPartySessionStorageComplete::CreateLambda([](const FAccelByteModelsV2PartySessionStorage& Result, bool bWasSuccessful)
{
if (bWasSuccessful)
{
// Access the party storage data from backend
// Result.Leader contains party leader's storage data
// Result.Members contains all party members' storage data
}
else
{
UE_LOG(LogTemp, Warning, TEXT("Error on getting party session storage"));
return;
}
}));
Listen to party session storage updated event
An event that will be sent to all party members when there is a party storage update. This event is sent through a WebSocket connection to ensure that they've been received in real time.
- Unreal
// Get notified when a party member updates their storage
FOnPartyStorageUpdateReceivedDelegate OnPartyStorageUpdated = FOnPartyStorageUpdateReceivedDelegate::CreateLambda(
[](FName SessionName, const FUniqueNetId& UpdatedMemberId)
{
if (SessionName == NAME_PartySession)
{
// Get the party session info to access the updated member storage
const FNamedOnlineSession* PartySession = SessionInterface_User1->GetPartySession();
if (PartySession == nullptr)
{
return;
}
TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(PartySession->SessionInfo);
if (!SessionInfo.IsValid())
{
return;
}
// Get the updated member's storage
FJsonObjectWrapper UpdatedMemberStorage;
bool bSuccess = SessionInfo->GetPartyStorage(UpdatedMemberId.AsShared(), UpdatedMemberStorage);
if (bSuccess && UpdatedMemberStorage.JsonObject.IsValid())
{
// Access the updated storage data
FString PlayerRole = UpdatedMemberStorage.JsonObject->GetStringField(TEXT("playerRole"));
int32 PlayerLevel = UpdatedMemberStorage.JsonObject->GetNumberField(TEXT("playerLevel"));
bool bIsReady = UpdatedMemberStorage.JsonObject->GetBoolField(TEXT("isReady"));
// Do something with the updated storage
}
}
});
auto DelegateHandle = SessionInterface_User1->AddOnPartyStorageUpdateReceivedDelegate_Handle(OnPartyStorageUpdated);
// When done listening, clear the delegate
// SessionInterface_User1->ClearOnPartyStorageUpdateReceivedDelegate_Handle(DelegateHandle);