メインコンテンツまでスキップ

クラウドセーブに OSS を使用する - クラウドセーブ - (Unreal Engine モジュール)

Last updated on February 4, 2026

注釈:本資料は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 からゲームオプションを取得します。

  1. 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);
  2. 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);
    }
  3. 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);
    }
  4. 以下のコードで 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);
    }
  5. 以下のコードで 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);
    }
  6. 以下のコードで 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);
    }
  7. 以下のコードで 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);
    }
  8. 最後に、サブシステムが初期化または非初期化されたときに、コールバック関数をバインドおよびアンバインドする必要があります。これを行うには、既存の 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);
    }
  9. Byte Wars プロジェクトをビルドし、コンパイルエラーがないことを確認します。

リソース