セッションストレージを統合する
注釈:本資料はAI技術を用いて翻訳されています。
はじめに
AccelByte Gaming Services (AGS) Session には、幅広いゲームクライアントに対応する多用途なソリューションを提供するストレージ機能があります。セッション内でシームレスな読み込みを可能にし、リーダーデータとパブリックデータに対して異なる権限を提供します。パブリックデータは読み取り可能ですが、所有者のみが変更できます。この機能により、ゲーム開発者向けにセッションデータのストレージが効率化され、全体的な効率が向上します。
セッションストレージは、ゲームセッションとパーティーセッションの両方で利用できます。
ゲームセッションストレージ
- スコープ: 特定のゲームセッション/マッチに紐づくデータ。
- アクセス: リーダーストレージとメンバーストレージをサポート。リーダーストレージはリーダーのみが書き込み可能、メンバーストレージはそのメンバーのみが書き込み可能。
- 使用方法: 共有セッションメタデータとメンバーごとのデータで、リーダー/メンバーが(権限に応じて)読み取り可能でゲームプレイを調整できます。
- ライフサイクル: ゲームセッションの存続期間中のみ存在します。
パーティーセッションストレージ
- スコープ: パーティーセッション(プレイヤーグループ)に紐づくデータ。
- アクセス: 各プレイヤーは自分自身のストレージのみを変更可能。他のプレイヤーやゲームクライアントには公開されません。
- 使用方法: 他のプレイヤーが変更できない個人的なパーティースコープのデータ(例: ロードアウトやメンバーごとの設定)。
- ライフサイクル: パーティーセッションがアクティブな間のみ存在します。
この記事には、以下の機能のコードスニペットが含まれています。
- ゲームセッションストレージの更新
- ゲームセッションストレージの読み取り
- ゲームセッションストレージ更新イベントのリスニング
- パーティーセッションストレージの更新
- パーティーセッションストレージの読み取り
- パーティーセッションストレージ更新イベントのリスニング
仕組み
以下の図は、AGS を使用したセッションストレージの動作を示しています。
プレイヤーは、ゲームセッションに登録され、かつアクティブである場合にのみ、セッションストレージにデータを更新または挿入する権限が付与されます。アクセスは、該当するゲームセッションに参加し接続しているプレイヤーに制限されます。すでに退出したプレイヤー、またはセッションから切断されたプレイヤーは、セッションストレージを更新することはできません。
セッションストレージの更新
セッションストレージにデータがない場合は作成します。既にデータがある場合は、ゲームセッション内で更新します。
セッションリーダーストレージの更新
セッションリーダーストレージのデータを変更します。この関数は、リーダー用のセッションストレージのデータのみを変更できます。
- 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
});
セッションメンバーストレージの更新
セッションメンバーストレージのデータを変更します。この関数は、メンバー(非リーダー)用のセッションストレージのデータのみを変更できます。
- 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
});
セッションストレージの読み取り
ゲームセッション内で、JSON オブジェクト型のセッションストレージデータを取得します。
- Unreal
- Unity
セッションリーダーストレージの読み取り
リーダーからセッションストレージのデータを取得します。
// 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
}
セッションメンバーストレージの読み取り
メンバーからセッションストレージのデータを取得します。
// 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
}
リーダーとメンバーからセッションストレージのデータを取得します。
// 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
});
セッションストレージ更新イベントのリスニング
セッションストレージの更新があった場合、同じゲームセッション内のすべてのユーザーに送信されるイベントです。このイベントは、リアルタイムで受信されることを保証するため、WebSocket 接続を通じて送信されます。
- Unreal
- Unity
セッションリーダーストレージ更新イベント
リーダーからのセッションストレージの更新があった場合に受信されます。
// 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);
セッションメンバーストレージ更新イベント
メンバーからのセッションストレージの更新があった場合に受信されます。
// 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);
リーダーまたはメンバーからのセッションストレージの更新があった場合に受信されます。
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
};
パーティーセッションストレージの更新
現在のユーザーのパーティーセッションストレージを更新します。各パーティーメンバーは、自分自身のストレージデータのみを更新できます。成功した場合、現在のパーティーセッションストレージは上書きされます。
- 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);
パーティーセッションストレージの読み取り
ローカルキャッシュからパーティーセッションストレージデータを取得するか、バックエンドにクエリします。
- Unreal
ローカルキャッシュからパーティーストレージを読み取る
// 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 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;
}
}));
パーティーセッションストレージ更新イベントのリスニング
パーティーストレージの更新があった場合、すべてのパーティーメンバーに送信されるイベントです。このイベントは、リアルタイムで受信されることを保証するため、WebSocket 接続を通じて送信されます。
- 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);