エンティティのクイックスタート
このエンティティ クイック スタートでは、エンティティ オブジェクトとエンティティ ファイルを操作する方法を示します。
レガシ アカウントとデータ システムから PlayFab エンティティへの移行の詳細については、「エンティティの移行情報」 を参照してください。
要件
- PlayFab 開発者アカウント。
- インストール済みの Unity エディターのコピー。 Unity エディターのインストールの詳細については、Unity ドキュメントの「Unity のインストール」 を参照してください。 Visual Studio 機能インストーラーを使用して Unity のバージョンをインストールすることもできます。
注意
PlayFab Unity3D SDK は、Unity エディター バージョン 5.3 以降に対応しています。
- Unity プロジェクト。 Unity プロジェクトの作成の詳細については、「クイック スタート ガイドを」を参照してください。
注意
Unity に慣れていない場合は、最新のインストール パッケージを使用すると、ゲーム作成のチュートリアルをインストールできるオプションが使用できます。 チュートリアルのいずれかを使用してサンプル ゲームを作成すると、次のクイックスタートで使用できます。
- PlayFab Unity3D SDK。
この記事でご紹介する C# サンプルは、Unity SDK 用に記述されています。 Unity SDK では、イベント駆動モデルを使用して非同期のタスクを処理します。 標準の C# または Xamarin C# SDK でサンプル コードを実行するには、非同期タスク モデルを使用するようにコードを変更する必要があります。 修正が必要なメソッドは、署名のメソッド名に非同期が付加されています。 たとえば、Unity SDK の SetObject は、標準 C# SDK では SetObjectAsync になります。 詳細については、「MSDN ガイド - async と await を使った非同期プログラミング」を参照してください。
用語
エンティティは、データを含め、PlayFab の概念です。 組み込みのエンティティン種類は次のようになります:
-
Title - タイトルには、すべてのプレイヤーが利用可能なグローバルの情報が含まれます。 これは、TitleData に似ています。 ゲーム/アプリケーションのタイトル ID (
TitleId
) によって識別されます。 -
master_player_account - このエンティティ タイプを使用すると、名前空間内で複数のゲームにわたって 1 人のプレイヤーに関する情報を共有できます。 プレイヤーのプレイヤー ID (
PlayFabId
) によって識別されます。これは、任意のログインの一部か、プレイヤー アカウントのアカウント情報を取得するための任意の呼び出しで返されます (たとえば、PlayFab Client API GetAccountInfo など)。 -
title_player_account - 現在のタイトルの情報の一部を含むプレイヤー アカウントを識別します。 これは、ログイン時に EntityKey オブジェクトに戻るエンティティ ID (
EntityKey.Id
) によって識別されます。 -
character - 取得できる情報を含むプレイヤーが所有するキャラクターを識別します。 キャラクターのキャラクター ID (
CharacterId
) によって識別されます。
組み込みエンティティの種類の詳細については、「利用可能な組み込みエンティティの種類」を参照してください。
エンティティの初期化
いずれかの Entity API を呼び出すには、エンティティ ID
とエンティティ Type
を取得する必要があります。
ID
と Type
を使用すると、他のエンティティ API メソッドに呼び出しをできます。 これらは、 EntityKey オブジェクトのメンバーです。
これを行うには、LoginWithCustomID
などのログイン メソッドのいずれかを呼び出します。
void Login()
{
var request = new PlayFab.ClientModels.LoginWithCustomIDRequest
{
CustomId = SystemInfo.deviceUniqueIdentifier,
CreateAccount = true,
};
PlayFabClientAPI.LoginWithCustomID(request, OnLogin, OnSharedFailure);
}
void OnLogin(PlayFab.ClientModels.LoginResult result)
{
entityId = result.EntityToken.Entity.Id;
// The expected entity type is title_player_account.
entityType = result.EntityToken.Entity.Type;
}
GetEntityToken メソッドを呼び出して、エンティティ ID
とエンティティ Type
を取得することもできます。
PlayFabAuthenticationAPI.GetEntityToken(new GetEntityTokenRequest(),
(entityResult) =>
{
var entityId = entityResult.Entity.Id;
var entityType = entityResult.Entity.Type;
}, OnPlayFabError); // Define your own OnPlayFabError function to report errors
クライアントから呼び出された場合、これは通常ログインしているプレイヤーになります。 ゲーム サーバーから呼び出される場合は、タイトルになります。
エンティティのオブジェクト
エンティティのオブジェクトを使用すると、読み取り書き込みの JSON で連続する小さなオブジェクトをエンティティに添付できます。 すべてのエンティティの種類では、GetObjects
メソッドと SetObjects
メソッドをサポートしています。
次のコード スニペットは、Object
を title_player_account
エンティティで設定して読み取る方法を示しています。
SetObjects メソッドを使用すると、プレイヤーまたはタイトルにエンティティ オブジェクトを設定できます。
var data = new Dictionary<string, object>()
{
{"Health", 100},
{"Mana", 10000}
};
var dataList = new List<SetObject>()
{
new SetObject()
{
ObjectName = "PlayerData",
DataObject = data
},
// A free-tier customer may store up to 3 objects on each entity
};
PlayFabDataAPI.SetObjects(new SetObjectsRequest()
{
Entity = new EntityKey {Id = entityId, Type = entityType}, // Saved from GetEntityToken, or a specified key created from a titlePlayerId, CharacterId, etc
Objects = dataList,
}, (setResult) => {
Debug.Log(setResult.ProfileVersion);
}, OnPlayFabError);
GetObjects メソッドを使用すると、プレイヤーまたはタイトルにエンティティ オブジェクトを取得できます。
var getRequest = new GetObjectsRequest {Entity = new EntityKey {Id = entityId, Type = entityType}};
PlayFabDataAPI.GetObjects(getRequest,
result => { var objs = result.Objects; },
OnPlayFabError
);
エンティティ ファイル
エンティティ ファイルを使用すると、読み取り書き込みのファイルを任意の形式で、エンティティに添付できます。
GetFiles メソッドを使用して、エンティティ ファイルを取得します。
void LoadAllFiles()
{
if (GlobalFileLock != 0)
throw new Exception("This example overly restricts file operations for safety. Careful consideration must be made when doing multiple file operations in parallel to avoid conflict.");
GlobalFileLock += 1; // Start GetFiles
var request = new PlayFab.DataModels.GetFilesRequest { Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType } };
PlayFabDataAPI.GetFiles(request, OnGetFileMeta, OnSharedFailure);
}
initiatefileuploads メソッドを使用して、エンティティ プロファイルへのファイルのアップロードを開始します。
void UploadFile(string fileName)
{
if (GlobalFileLock != 0)
throw new Exception("This example overly restricts file operations for safety. Careful consideration must be made when doing multiple file operations in parallel to avoid conflict.");
ActiveUploadFileName = fileName;
GlobalFileLock += 1; // Start InitiateFileUploads
var request = new PlayFab.DataModels.InitiateFileUploadsRequest
{
Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType },
FileNames = new List<string> { ActiveUploadFileName },
};
PlayFabDataAPI.InitiateFileUploads(request, OnInitFileUpload, OnInitFailed);
}
AbortFileUploads メソッドを使用して、エンティティ プロファイルへの保留中ファイルのアップロードを中止します。
void OnInitFailed(PlayFabError error)
{
if (error.Error == PlayFabErrorCode.EntityFileOperationPending)
{
// This is an error you should handle when calling InitiateFileUploads, but your resolution path may vary
GlobalFileLock += 1; // Start AbortFileUploads
var request = new PlayFab.DataModels.AbortFileUploadsRequest
{
Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType },
FileNames = new List<string> { ActiveUploadFileName },
};
PlayFabDataAPI.AbortFileUploads(request, (result) => { GlobalFileLock -= 1; UploadFile(ActiveUploadFileName); }, OnSharedFailure); GlobalFileLock -= 1; // Finish AbortFileUploads
GlobalFileLock -= 1; // Failed InitiateFileUploads
}
else
OnSharedFailure(error);
}
FinalizeFileUploads メソッドを使用して、エンティティ プロファイルへのファイルのアップロードを終了します。 エンティティ システムでは、アトミック アップロードの操作が正常に終了するまで、ファイルのアップロード完了や他の呼び出し元への変更反映が無視されます。
void FinalizeUpload(byte[] data)
{
GlobalFileLock += 1; // Start FinalizeFileUploads
var request = new PlayFab.DataModels.FinalizeFileUploadsRequest
{
Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType },
FileNames = new List<string> { ActiveUploadFileName },
};
PlayFabDataAPI.FinalizeFileUploads(request, OnUploadSuccess, OnSharedFailure);
GlobalFileLock -= 1; // Finish SimplePutCall
}
次に示す例では、完全なエンティティファイルのループ、ログインからファイルの読み込みと新しいファイルのアップロードを示します。
この手順は次のとおりです。
- ログインし、エンティティ
ID
とエンティティType
を取得します。 - アトミック アップロードの操作を初期化します。
- すべてのファイルをアップロードします。
- アトミック アップロードの操作を終了します。
わかりやすくするために、この例では一度に 1 つのファイルを保存しますが、ファイルをアトミックにアップロードするように設定することができます。
この例では、Unity 3D エンジンの使い方に慣れていることを前提とします。
#if !DISABLE_PLAYFABENTITY_API && !DISABLE_PLAYFABCLIENT_API
using PlayFab;
using PlayFab.Internal;
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
public class EntityFileExample : MonoBehaviour
{
public string entityId; // Id representing the logged in player
public string entityType; // entityType representing the logged in player
private readonly Dictionary<string, string> _entityFileJson = new Dictionary<string, string>();
private readonly Dictionary<string, string> _tempUpdates = new Dictionary<string, string>();
public string ActiveUploadFileName;
public string NewFileName;
// GlobalFileLock provides is a simplistic way to avoid file collisions, specifically designed for this example.
public int GlobalFileLock = 0;
void OnSharedFailure(PlayFabError error)
{
Debug.LogError(error.GenerateErrorReport());
GlobalFileLock -= 1;
}
// OnGUI provides a way to build a Unity GUI entirely within script.
- // Your GUI will be game-specific.
void OnGUI()
{
if (!PlayFabClientAPI.IsClientLoggedIn() && GUI.Button(new Rect(0, 0, 100, 30), "Login"))
Login();
if (PlayFabClientAPI.IsClientLoggedIn() && GUI.Button(new Rect(0, 0, 100, 30), "LogOut"))
PlayFabClientAPI.ForgetAllCredentials();
if (PlayFabClientAPI.IsClientLoggedIn() && GUI.Button(new Rect(100, 0, 100, 30), "(re)Load Files"))
LoadAllFiles();
if (PlayFabClientAPI.IsClientLoggedIn())
{
// Display existing files
_tempUpdates.Clear();
var index = 0;
foreach (var each in _entityFileJson)
{
GUI.Label(new Rect(100 * index, 60, 100, 30), each.Key);
var tempInput = _entityFileJson[each.Key];
var tempOutput = GUI.TextField(new Rect(100 * index, 90, 100, 30), tempInput);
if (tempInput != tempOutput)
_tempUpdates[each.Key] = tempOutput;
if (GUI.Button(new Rect(100 * index, 120, 100, 30), "Save " + each.Key))
UploadFile(each.Key);
index++;
}
// Apply any changes
foreach (var each in _tempUpdates)
_entityFileJson[each.Key] = each.Value;
// Add a new file
NewFileName = GUI.TextField(new Rect(100 * index, 60, 100, 30), NewFileName);
if (GUI.Button(new Rect(100 * index, 90, 100, 60), "Create " + NewFileName))
UploadFile(NewFileName);
}
}
void Login()
{
var request = new PlayFab.ClientModels.LoginWithCustomIDRequest
{
CustomId = SystemInfo.deviceUniqueIdentifier,
CreateAccount = true,
};
PlayFabClientAPI.LoginWithCustomID(request, OnLogin, OnSharedFailure);
}
void OnLogin(PlayFab.ClientModels.LoginResult result)
{
entityId = result.EntityToken.Entity.Id;
entityType = result.EntityToken.Entity.Type;
}
void LoadAllFiles()
{
if (GlobalFileLock != 0)
throw new Exception("This example overly restricts file operations for safety. Careful consideration must be made when doing multiple file operations in parallel to avoid conflict.");
GlobalFileLock += 1; // Start GetFiles
var request = new PlayFab.DataModels.GetFilesRequest { Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType } };
PlayFabDataAPI.GetFiles(request, OnGetFileMeta, OnSharedFailure);
}
void OnGetFileMeta(PlayFab.DataModels.GetFilesResponse result)
{
Debug.Log("Loading " + result.Metadata.Count + " files");
_entityFileJson.Clear();
foreach (var eachFilePair in result.Metadata)
{
_entityFileJson.Add(eachFilePair.Key, null);
GetActualFile(eachFilePair.Value);
}
GlobalFileLock -= 1; // Finish GetFiles
}
void GetActualFile(PlayFab.DataModels.GetFileMetadata fileData)
{
GlobalFileLock += 1; // Start Each SimpleGetCall
PlayFabHttp.SimpleGetCall(fileData.DownloadUrl,
result => { _entityFileJson[fileData.FileName] = Encoding.UTF8.GetString(result); GlobalFileLock -= 1; }, // Finish Each SimpleGetCall
error => { Debug.Log(error); }
);
}
void UploadFile(string fileName)
{
if (GlobalFileLock != 0)
throw new Exception("This example overly restricts file operations for safety. Careful consideration must be made when doing multiple file operations in parallel to avoid conflict.");
ActiveUploadFileName = fileName;
GlobalFileLock += 1; // Start InitiateFileUploads
var request = new PlayFab.DataModels.InitiateFileUploadsRequest
{
Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType },
FileNames = new List<string> { ActiveUploadFileName },
};
PlayFabDataAPI.InitiateFileUploads(request, OnInitFileUpload, OnInitFailed);
}
void OnInitFailed(PlayFabError error)
{
if (error.Error == PlayFabErrorCode.EntityFileOperationPending)
{
// This is an error you should handle when calling InitiateFileUploads, but your resolution path may vary
GlobalFileLock += 1; // Start AbortFileUploads
var request = new PlayFab.DataModels.AbortFileUploadsRequest
{
Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType },
FileNames = new List<string> { ActiveUploadFileName },
};
PlayFabDataAPI.AbortFileUploads(request, (result) => { GlobalFileLock -= 1; UploadFile(ActiveUploadFileName); }, OnSharedFailure); GlobalFileLock -= 1; // Finish AbortFileUploads
GlobalFileLock -= 1; // Failed InitiateFileUploads
}
else
OnSharedFailure(error);
}
void OnInitFileUpload(PlayFab.DataModels.InitiateFileUploadsResponse response)
{
string payloadStr;
if (!_entityFileJson.TryGetValue(ActiveUploadFileName, out payloadStr))
payloadStr = "{}";
var payload = Encoding.UTF8.GetBytes(payloadStr);
GlobalFileLock += 1; // Start SimplePutCall
PlayFabHttp.SimplePutCall(response.UploadDetails[0].UploadUrl,
payload,
FinalizeUpload,
error => { Debug.Log(error); }
);
GlobalFileLock -= 1; // Finish InitiateFileUploads
}
void FinalizeUpload(byte[] data)
{
GlobalFileLock += 1; // Start FinalizeFileUploads
var request = new PlayFab.DataModels.FinalizeFileUploadsRequest
{
Entity = new PlayFab.DataModels.EntityKey { Id = entityId, Type = entityType },
FileNames = new List<string> { ActiveUploadFileName },
};
PlayFabDataAPI.FinalizeFileUploads(request, OnUploadSuccess, OnSharedFailure);
GlobalFileLock -= 1; // Finish SimplePutCall
}
void OnUploadSuccess(PlayFab.DataModels.FinalizeFileUploadsResponse result)
{
Debug.Log("File upload success: " + ActiveUploadFileName);
GlobalFileLock -= 1; // Finish FinalizeFileUploads
}
}
#endif
注意
各ファイルの操作では、多くの手順と複数の API 呼出しが必要なため、同時に複数の方法で同じファイルにアクセスしないでください。 十分に注意すれば、ロック メカニズムは必要ありません。 複雑な処理を実行する場合、ロック メカニズムがより複雑になる可能性があります。
ゲーム マネージャーとエンティティ
ゲーム マネージャーを使用して、プレイヤーのオブジェクトとファイルを操作できます。 プレイヤーの概要では、タイトル プレイヤーのアカウント情報とマスタ プレイヤーのアカウント情報の両方が表示されます。
さらに、ファイルとオブジェクトは、[プレイヤー] タブに独自のセクションができました。
関連項目
PlayFab ブログの Introducing Entities, Objects and Files (エンティティ、オブジェクト、ファイルの概要)。