はじめに
「UE5でEpic Online Services(EOS)を使ってみる」の続きです。
ログインの実装が必要なので、未実装の方は準備編・ログイン編をご確認ください。
プレーヤーデータはユーザー毎にストレージが用意されており、uint8の形式でファイルをアップロードできます。
セーブデータの保存などが主な用途になるかと思います。
今回はSaveGameの変換とアップロード・ダウンロードを実装します。
なお、今回はDeveloper Portalでの事前設定はありません。
目次
この章では、プレイヤーデータ機能に必要な実装を行っていきます。
必要なクラスを作成してC++を実装し、Blueprintで実行出来る状態にしてテストを行います。
1.クラス作成
1-1.C++クラス
SaveGameの変換用のクラスを作成します。
BlueprintFunctionLibraryを親クラスにして、EOS_BlueprintFunctionをC++クラスで作成します。
アップロード・ダウンロード用のクラスを作成します。
OnlineBlueprintCallProxyBaseを親クラスに指定して、EOS_SetPlayerDataとEOS_GetPlayerDataをC++クラスで作成します。
1-2.Blueprintクラス
SaveGameのクラスを作成します。
SaveGameを親クラスに指定して、BP_SaveGameをBlueprintクラスで作成します。
2.C++
C++を以下で実装します。
EOS_BlueprintFunction.h(cppの編集はありません)
#pragma once #include "CoreMinimal.h" #include "Kismet/GameplayStatics.h" #include "EOS_BlueprintFunction.generated.h" UCLASS() class EOS_API UEOS_BlueprintFunction : public UBlueprintFunctionLibrary { GENERATED_BODY() public: UFUNCTION(BlueprintPure, Category = "EOS") static USaveGame* int8ToSaveGame(const TArray<uint8>& DataToConvert) { return UGameplayStatics::LoadGameFromMemory(DataToConvert); } UFUNCTION(BlueprintPure, Category = "EOS") static TArray<uint8> SaveGameTouint8(USaveGame* DataToConvert) { TArray<uint8> Result; UGameplayStatics::SaveGameToMemory(DataToConvert, Result); return Result; } };
EOS_SetPlayerData.h
#pragma once #include "CoreMinimal.h" #include "Net/OnlineBlueprintCallProxyBase.h" #include "EOS_SetPlayerData.generated.h" UCLASS() class EOS_API UEOS_SetPlayerData : public UOnlineBlueprintCallProxyBase { GENERATED_BODY() UPROPERTY(BlueprintAssignable) FEmptyOnlineDelegate OnSuccess; UPROPERTY(BlueprintAssignable) FEmptyOnlineDelegate OnFailure; UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject"), Category = "EOS") static UEOS_SetPlayerData* SetPlayerData(UObject* WorldContextObject, FString FileName, TArray<uint8> UploadData); virtual void Activate() override; private: void OnSetPlayerDataComplete(bool bWasSuccessful, const FUniqueNetId& UserID, const FString& var_FileName); private: UWorld* World; TWeakObjectPtr<UObject> WorldContextObject; FString FileName; TArray<uint8> UploadData; };
EOS_SetPlayerData.cpp
#include "OnlineSubsystemUtils.h" #include "EOS_SetPlayerData.h" UEOS_SetPlayerData* UEOS_SetPlayerData::SetPlayerData(UObject* WorldContextObject, FString FileName, TArray<uint8> UploadData) { UEOS_SetPlayerData* PlayerData = NewObject<UEOS_SetPlayerData>(); PlayerData->WorldContextObject = WorldContextObject; PlayerData->FileName = FileName; PlayerData->UploadData = UploadData; return PlayerData; } void UEOS_SetPlayerData::Activate() { World = GEngine->GetWorldFromContextObject(WorldContextObject.Get(), EGetWorldErrorMode::LogAndReturnNull); if (!World) { UE_LOG(LogTemp, Error, TEXT("SetPlayerData:Worldの取得に失敗")); OnFailure.Broadcast(); return; } IOnlineSubsystem* SubsystemRef = Online::GetSubsystem(World); IOnlineIdentityPtr IdentityPointerRef = SubsystemRef->GetIdentityInterface(); IOnlineUserCloudPtr UserCloudPointerRef = SubsystemRef->GetUserCloudInterface(); if (UserCloudPointerRef) { const TSharedPtr<const FUniqueNetId> UserIDRef = IdentityPointerRef->GetUniquePlayerId(0).ToSharedRef(); UserCloudPointerRef->OnWriteUserFileCompleteDelegates.AddUObject(this, &UEOS_SetPlayerData::OnSetPlayerDataComplete); UserCloudPointerRef->WriteUserFile(*UserIDRef, FileName, UploadData); return; } OnFailure.Broadcast(); } void UEOS_SetPlayerData::OnSetPlayerDataComplete(bool bWasSuccessful, const FUniqueNetId& UserID, const FString& var_FileName) { if (bWasSuccessful) { UE_LOG(LogTemp, Warning, TEXT("Upload成功")); OnSuccess.Broadcast(); } else { UE_LOG(LogTemp, Error, TEXT("Upload失敗")); OnFailure.Broadcast(); } }
EOS_GetPlayerData.h
#pragma once #include "CoreMinimal.h" #include "Net/OnlineBlueprintCallProxyBase.h" #include "EOS_GetPlayerData.generated.h" DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnGetPlayerDataRetrieved, const TArray<uint8>&, DownloadData); UCLASS() class EOS_API UEOS_GetPlayerData : public UOnlineBlueprintCallProxyBase { GENERATED_BODY() UPROPERTY(BlueprintAssignable) FOnGetPlayerDataRetrieved OnSuccess; UPROPERTY(BlueprintAssignable) FOnGetPlayerDataRetrieved OnFailure; UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject"), Category = "EOS") static UEOS_GetPlayerData* GetPlayerData(UObject* WorldContextObject, FString FileName); virtual void Activate() override; private: void OnGetPlayerDataComplete(bool bSuccess, const FUniqueNetId& UserID, const FString& var_FileName); private: UWorld* World; TWeakObjectPtr<UObject> WorldContextObject; FString FileName; TArray<uint8> DownloadData; };
EOS_GetPlayerData.cpp
#include "OnlineSubsystemUtils.h" #include "EOS_GetPlayerData.h" UEOS_GetPlayerData* UEOS_GetPlayerData::GetPlayerData(UObject* WorldContextObject, FString FileName) { UEOS_GetPlayerData* PlayerData = NewObject<UEOS_GetPlayerData>(); PlayerData->WorldContextObject = WorldContextObject; PlayerData->FileName = FileName; return PlayerData; } void UEOS_GetPlayerData::Activate() { DownloadData.Empty(); World = GEngine->GetWorldFromContextObject(WorldContextObject.Get(), EGetWorldErrorMode::LogAndReturnNull); if (!World) { UE_LOG(LogTemp, Error, TEXT("GetPlayerData:Worldの取得に失敗")); OnFailure.Broadcast(DownloadData); return; } IOnlineSubsystem* SubsystemRef = Online::GetSubsystem(World); IOnlineIdentityPtr IdentityPointerRef = SubsystemRef->GetIdentityInterface(); IOnlineUserCloudPtr UserCloudPointerRef = SubsystemRef->GetUserCloudInterface(); if (UserCloudPointerRef) { const TSharedPtr<const FUniqueNetId> UserIDRef = IdentityPointerRef->GetUniquePlayerId(0).ToSharedRef(); UserCloudPointerRef->OnReadUserFileCompleteDelegates.AddUObject(this, &UEOS_GetPlayerData::OnGetPlayerDataComplete); UserCloudPointerRef->ReadUserFile(*UserIDRef, FileName); return; } OnFailure.Broadcast(DownloadData); } void UEOS_GetPlayerData::OnGetPlayerDataComplete(bool bWasSuccessful, const FUniqueNetId& UserID, const FString& var_FileName) { // ポインターの取得 IOnlineSubsystem* SubsystemRef = Online::GetSubsystem(World); IOnlineIdentityPtr IdentityPointerRef = SubsystemRef->GetIdentityInterface(); IOnlineUserCloudPtr UserCloudPointerRef = SubsystemRef->GetUserCloudInterface(); if (bWasSuccessful) { UE_LOG(LogTemp, Warning, TEXT("Download成功")); DownloadData.Empty(); const TSharedPtr<const FUniqueNetId> UserIDRef = IdentityPointerRef->GetUniquePlayerId(0).ToSharedRef(); UserCloudPointerRef->GetFileContents(*UserIDRef, FileName, DownloadData); OnSuccess.Broadcast(DownloadData); } else { UE_LOG(LogTemp, Error, TEXT("Download失敗")); OnFailure.Broadcast(DownloadData); } }
3.Blueprint
Blueprintを以下で実装します。
3-1.BP_SaveGame
変数RandomIntをInteger型で作成します。
3-2.EOS_Gameinstance
変数SaveGameをSaveGame型で作成します。
各カスタムイベントを用意し、以下で実装します。
Save:ランダムな値を生成し、SaveGameに保存します。
SetPlayerData:SaveGameをuin8に変換し、EOSへアップロードします。
・FileName:アップロードするファイル名を指定します。
GetPlayerData:EOSからファイルをダウンロードし、SaveGameに変換します。
・FileName:ダウンロードするファイル名を指定します。
4.テスト
4-1.SaveGame保存
ログイン後にSaveを実行し、保存した値を確認します。
4-2.アップロード
Save保存後にSetPlayerDataを実行し、ファイルをアップロードします。
4-2.ダウンロード
アップロード後にGetPlayerDataを実行し、ファイルをダウンロードします。
取得した値がアップロード時の値と一致していれば、SaveGameが無事にアップロード・ダウンロードされていることが確認できます。
5.Developer Portal
アップロードしたファイルはDeveloper Portal上で操作できます。
ゲームサービス>プレイヤーデータのストレージを開き、プレイヤーID(DevAuthToolから取得)を検索することで、そのユーザーのストレージを確認できます。
おわり
いかがでしたか。
以上で、EOSのお試し実装は終わりです。
とりあえず動く状態にするということで、メモリ管理やログインチェックの実装が出来ていてません。
アプリに組み込む際には実装を詰めていく必要がありそうです。