クラウドセーブに OSS を使用する - クラウドセーブ - (Unreal Engine モジュール)
注釈:本資料はAI技術を用いて翻訳されています。
サブシステムの概要
このチュートリアルでは、AccelByte Gaming Services (AGS) クラウドセーブを実装して、音楽と効果音 (SFX) のボリュームのゲームオプションを保存および取得する方法を学びます。Byte Wars には、CloudSaveSubsystem クラスで定義された Game Instance Subsystem があります。このサブシステムは、AGS クラウドセーブから Player Record を設定および取得するためのラッパーとして機能します。Player Record は、AGS で利用可能なレコードタイプの 1 つです。
AGS でサポートされているレコードタイプの定義は次のとおりです。
- Player Record: ゲームオプションや設定など、プレイヤーデータを保存するためのレコードタイプ。
- Game Record: ゲームのお知らせ、イベント設定など、ゲームデータを保存するためのレコードタイプ。
CloudSaveSubsystem クラスのスターターバージョンである CloudSaveSubsystem_Starter というサブシステムをセットアップします。
スターターパックの内容
CloudSaveSubsystem_Starter は リソース セクションで入手でき、以下で構成されています。
- ヘッダーファイル:
/Source/AccelByteWars/TutorialModules/Storage/CloudSaveEssentials/CloudSaveSubsystem_Starter.h - CPP ファイル:
/Source/AccelByteWars/TutorialModules/Storage/CloudSaveEssentials/CloudSaveSubsystem_Starter.cpp
CloudSaveSubsystem_Starter クラスには、いくつかの機能が提供されています。CloudSaveSubsystem_Starter クラスの CPP ファイルを開くと、Initialize() という関数があります。この関数内には、CloudSaveInterface という変数が定義されています。
void UCloudSaveSubsystem_Starter::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
// Get Online Subsystem and make sure it's valid.
const FOnlineSubsystemAccelByte* Subsystem = static_cast<const FOnlineSubsystemAccelByte*>(Online::GetSubsystem(GetWorld()));
if (!ensure(Subsystem))
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Warning, TEXT("The online subsystem is invalid. Please make sure OnlineSubsystemAccelByte is enabled and the DefaultPlatformService under [OnlineSubsystem] in the Engine.ini file is set to AccelByte."));
return;
}
// Grab the reference of AccelByte Identity Interface and make sure it's valid.
CloudSaveInterface = StaticCastSharedPtr<FOnlineCloudSaveAccelByte>(Subsystem->GetCloudSaveInterface());
if (!ensure(CloudSaveInterface.IsValid()))
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Warning, TEXT("Cloud Save interface is not valid."));
return;
}
// ...
}
CloudSaveInterface は、FOnlineCloudSaveAccelBytePtr インターフェースタイプの変数です。FOnlineCloudSaveAccelBytePtr は AGS オンラインサブシステム (OSS) の一部であり、このインターフェースを使用して AGS クラウドセーブ機能にアクセスできます。
AGS OSS を使用したクラウドセーブの実装
このセクションでは、AGS OSS を使用してクラウドセーブを実装し、Player Record にゲームオプションを保存し、Player Record からゲームオプションを取得します。
-
CloudSaveSubsystem_Starterクラスのヘッダーファイルを開き、以下の関数を宣言します。これらの関数はそれぞれ、Player Record に対して実行されるアクションに対応しています。SetPlayerRecord()は、既存のレコードを作成または更新します。GetPlayerRecord()は、指定されたレコードキーに関連付けられたデータを取得します。DeletePlayerRecord()は、保存されたレコードを削除します。また、各アクションに対応するレスポンス関数も宣言します。public:
void SetPlayerRecord(
const APlayerController* PlayerController,
const FString& RecordKey,
const FJsonObject& RecordData,
const FOnSetCloudSaveRecordComplete& OnSetRecordComplete);
void GetPlayerRecord(
const APlayerController* PlayerController,
const FString& RecordKey,
const FOnGetCloudSaveRecordComplete& OnGetRecordComplete);
void DeletePlayerRecord(
const APlayerController* PlayerController,
const FString& RecordKey,
const FOnDeleteCloudSaveRecordComplete& OnDeleteRecordComplete);private:
// ...
void OnSetPlayerRecordComplete(
int32 LocalUserNum,
const FOnlineError& Result,
const FString& Key);
void OnGetPlayerRecordComplete(
int32 LocalUserNum,
const FOnlineError& Result,
const FString& Key,
const FAccelByteModelsUserRecord& UserRecord);
void OnDeletePlayerRecordComplete(
int32 LocalUserNum,
const FOnlineError& Result,
const FString& Key); -
SetPlayerRecord()から始まる関数定義を作成します。CloudSaveSubsystem_Starterクラスの CPP ファイルを開き、以下のコードを追加します。これにより、指定されたレコードキーの下に、指定された JSON データで Player Record データを設定するリクエストが送信されます。リクエストが完了すると、OnSetPlayerRecordComplete()メソッドが呼び出されます。void UCloudSaveSubsystem_Starter::SetPlayerRecord(
const APlayerController* PlayerController,
const FString& RecordKey,
const FJsonObject& RecordData,
const FOnSetCloudSaveRecordComplete& OnSetRecordComplete)
{
if (!ensure(CloudSaveInterface.IsValid()))
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Warning, TEXT("Cloud Save interface is not valid."));
return;
}
const int32 LocalUserNum = GetLocalUserIndex(PlayerController);
SetPlayerRecordParams.Add(RecordKey, OnSetRecordComplete);
CloudSaveInterface->ReplaceUserRecord(LocalUserNum, RecordKey, RecordData);
} -
OnSetPlayerRecordComplete()関数を定義します。CPP ファイルに以下のコードを追加します。これにより、OnSetRecordCompleteデリゲートが実行されます。このデリゲートは、レコードが正常に保存されたか、エラーが発生したかをプレイヤーに通知するために使用されます。このデリゲートは後で使用します。void UCloudSaveSubsystem_Starter::OnSetPlayerRecordComplete(
int32 LocalUserNum,
const FOnlineError& Result,
const FString& Key)
{
if (Result.bSucceeded)
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Log, TEXT("Success to set player record."));
}
else
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Log, TEXT("Failed to set player record. Message: %s"), *Result.ErrorMessage.ToString());
}
for (TTuple<FString, FOnSetCloudSaveRecordComplete>& Param : SetPlayerRecordParams)
{
if (Param.Key.Equals(Key))
{
Param.Value.ExecuteIfBound(Result.bSucceeded);
}
}
SetPlayerRecordParams.Remove(Key);
} -
以下のコードで
GetPlayerRecord()の関数定義を作成します。これにより、指定されたレコードキーの下にある Player Record の保存された JSON データを取得するリクエストが送信されます。リクエストが完了すると、OnGetPlayerRecordComplete()が呼び出されます。void UCloudSaveSubsystem_Starter::GetPlayerRecord(
const APlayerController* PlayerController,
const FString& RecordKey,
const FOnGetCloudSaveRecordComplete& OnGetRecordComplete)
{
if (!ensure(CloudSaveInterface.IsValid()))
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Warning, TEXT("Cloud Save interface is not valid."));
return;
}
const int32 LocalUserNum = GetLocalUserIndex(PlayerController);
GetPlayerRecordParams.Add(RecordKey, OnGetRecordComplete);
CloudSaveInterface->GetUserRecord(LocalUserNum, RecordKey);
} -
以下のコードで
OnGetPlayerRecordComplete()関数を定義します。OnSetPlayerRecordComplete()関数と同様に、これはレコードの取得が成功したかどうかをプレイヤーに通知します。さらに、ゲームコードが読み取って使用できるように、デリゲートを通じてレコードデータを送信します。このデリゲートは後で使用します。void UCloudSaveSubsystem_Starter::OnGetPlayerRecordComplete(
int32 LocalUserNum,
const FOnlineError& Result,
const FString& Key,
const FAccelByteModelsUserRecord& UserRecord)
{
FJsonObject RecordResult;
if (Result.bSucceeded)
{
RecordResult = UserRecord.Value.JsonObject.ToSharedRef().Get();
UE_LOG_CLOUDSAVE_ESSENTIALS(Log, TEXT("Success to get player record."));
}
else
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Log, TEXT("Failed to get player record. Message: %s"), *Result.ErrorMessage.ToString());
}
for (TTuple<FString, FOnGetCloudSaveRecordComplete>& Param : GetPlayerRecordParams)
{
if (Param.Key.Equals(Key))
{
Param.Value.ExecuteIfBound(Result.bSucceeded, RecordResult);
}
}
GetPlayerRecordParams.Remove(Key);
} -
以下のコードで
DeletePlayerRecord()関数を定義します。これにより、指定されたレコードキーに関連付けられた Player Record を削除するリクエストが送信されます。リクエストが完了すると、OnDeletePlayerRecordComplete()が呼び出されます。void UCloudSaveSubsystem_Starter::DeletePlayerRecord(
const APlayerController* PlayerController,
const FString& RecordKey,
const FOnDeleteCloudSaveRecordComplete& OnDeleteRecordComplete)
{
if (!ensure(CloudSaveInterface.IsValid()))
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Warning, TEXT("Cloud Save interface is not valid."));
return;
}
const int32 LocalUserNum = GetLocalUserIndex(PlayerController);
DeletePlayerRecordParams.Add(RecordKey, OnDeleteRecordComplete);
CloudSaveInterface->DeleteUserRecord(LocalUserNum, RecordKey);
} -
以下のコードで
OnDeletePlayerRecordComplete()関数を定義します。これにより、OnDeleteRecordCompleteデリゲートが実行され、削除が成功したことをプレイヤーに通知します。void UCloudSaveSubsystem_Starter::OnDeletePlayerRecordComplete(
int32 LocalUserNum,
const FOnlineError& Result,
const FString& Key)
{
if (Result.bSucceeded)
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Log, TEXT("Success to delete player record."));
}
else
{
UE_LOG_CLOUDSAVE_ESSENTIALS(Log, TEXT("Failed to delete player record. Message: %s"), *Result.ErrorMessage.ToString());
}
for (TTuple<FString, FOnDeleteCloudSaveRecordComplete>& Param : DeletePlayerRecordParams)
{
if (Param.Key.Equals(Key))
{
Param.Value.ExecuteIfBound(Result.bSucceeded);
}
}
DeletePlayerRecordParams.Remove(Key);
} -
最後に、サブシステムが初期化または非初期化されたときに、コールバック関数をバインドおよびアンバインドする必要があります。これを行うには、既存の
BindDelegatesおよびUnbindDelegates()関数に以下のコードを追加します。void UCloudSaveSubsystem_Starter::BindDelegates()
{
// ...
CloudSaveInterface->OnReplaceUserRecordCompletedDelegates->AddUObject(this, &ThisClass::OnSetPlayerRecordComplete);
CloudSaveInterface->OnGetUserRecordCompletedDelegates->AddUObject(this, &ThisClass::OnGetPlayerRecordComplete);
CloudSaveInterface->OnDeleteUserRecordCompletedDelegates->AddUObject(this, &ThisClass::OnDeletePlayerRecordComplete);
}void UCloudSaveSubsystem_Starter::UnbindDelegates()
{
// ...
CloudSaveInterface->OnReplaceUserRecordCompletedDelegates->RemoveAll(this);
CloudSaveInterface->OnGetUserRecordCompletedDelegates->RemoveAll(this);
CloudSaveInterface->OnDeleteUserRecordCompletedDelegates->RemoveAll(this);
} -
Byte Wars プロジェクトをビルドし、コンパイルエラーがないことを確認します。
リソース
- このチュートリアルセクションで使用されるファイルは、Byte Wars GitHub リポジトリで入手できます。