> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# エンティティ クイックスタート

> Unity C# で PlayFab エンティティを使い始めます。認証して EntityKey を取得し、SDK のサンプルでエンティティ オブジェクトとエンティティ ファイルを読み書きします。

このエンティティ クイックスタートでは、エンティティ オブジェクトとエンティティ ファイルの操作方法を示します。

レガシー アカウントおよびデータ システムから PlayFab エンティティへの移行についての情報は、[エンティティ移行情報](/services/playfab/live-service-management/game-configuration/entities/migration-information) を参照してください。

## 要件

* [PlayFab 開発者アカウント](https://developer.playfab.com)。
* インストール済みの Unity Editor。Unity Editor のインストールについては、Unity ドキュメントの [Installing Unity](https://docs.unity3d.com/Manual/GettingStartedInstallingUnity.html) を参照してください。Visual Studio の機能インストーラーを使用して Unity のバージョンをインストールすることもできます。

<Note>
  PlayFab Unity3D SDK は、Unity Editor バージョン 5.3 以上をサポートします。
</Note>

* Unity プロジェクト。Unity プロジェクトの作成については、[クイックスタート ガイド](https://docs.unity3d.com/Manual/Quickstart3D.html) を参照してください。

<Note>
  Unity に不慣れな場合は、最近のインストール パッケージにはゲーム作成のウォークスルーをインストールするオプションが含まれています。ウォークスルーの 1 つを使って、次のクイックスタートで使用するサンプル ゲームを作成できます。
</Note>

* PlayFab Unity3D SDK。

この記事の C# サンプルは Unity SDK 用に書かれています。Unity SDK は、非同期タスクを処理するためにイベント駆動モデルを使用します。C# SDK を使用してサンプル コードを実行するには、コードを async Task モデルを使用するように変更する必要があります。変更が必要なメソッドは、シグネチャのメソッド名に Async が付加されます。たとえば、Unity SDK の SetObject は、C# SDK では SetObjectAsync になります。詳細については、[async と await による非同期プログラミング](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/) を参照してください。

## 用語

エンティティとは、データを保持できる任意の PlayFab 概念です。組み込みのエンティティ タイプは次のとおりです。

* **title** - タイトルには、すべてのプレイヤーが利用可能なグローバル情報が含まれます。これは [TitleData](xref:titleid.playfabapi.com.client.title-widedatamanagement.gettitledata) に似ています。ゲーム/アプリケーションのタイトル ID (`TitleId`) で識別されます。
* **master\_player\_account** - このエンティティ タイプを使用すると、名前空間内の複数のゲーム間でプレイヤーに関する情報を共有できます。プレイヤーのプレイヤー ID (`PlayFabId`) で識別されます。これは、ログインの一部として、またはプレイヤー アカウントのアカウント情報を取得する呼び出し (たとえば、PlayFab Client API の [GetAccountInfo](xref:titleid.playfabapi.com.client.accountmanagement.getaccountinfo)) から返されます。
* **title\_player\_account** - 現在のタイトルの情報を保持するプレイヤー アカウントを識別します。これは、任意のログインで [EntityKey](xref:titleid.playfabapi.com.authentication.authentication.getentitytoken#entitykey) オブジェクトから返されるエンティティ ID (`EntityKey.Id`) で識別されます。
* **character** - プレイヤーが所有するキャラクターを識別し、取得可能な情報を保持します。キャラクターのキャラクター ID (`CharacterId`) で識別されます。

組み込みのエンティティ タイプの詳細については、[利用可能な組み込みエンティティ タイプ](/services/playfab/live-service-management/game-configuration/entities/available-built-in-entity-types) を参照してください。

## エンティティの初期化

いずれかの Entity API を呼び出すには、エンティティの `ID` と `Type` を取得する必要があります。この `ID` と `Type` を使用して他の Entity API メソッドを呼び出します。これらは [EntityKey](xref:titleid.playfabapi.com.authentication.authentication.getentitytoken#entitykey) オブジェクトのメンバーです。

これは、`LoginWithCustomID` などのログイン メソッドを呼び出すことで行います。

```csharp theme={null}
    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](xref:titleid.playfabapi.com.authentication.authentication.getentitytoken) メソッドを呼び出して、エンティティの `ID` と `Type` を取得することもできます。

```csharp theme={null}
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` メソッドをサポートします。

次のコード スニペットは、`title_player_account` エンティティに `Object` を設定して読み取る方法を示しています。

プレイヤーまたはタイトルにエンティティ オブジェクトを設定するには、[SetObjects](xref:titleid.playfabapi.com.data.object.setobjects) メソッドを使用します。

```csharp theme={null}
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](xref:titleid.playfabapi.com.data.object.getobjects) メソッドを使用します。

```csharp theme={null}
var getRequest = new GetObjectsRequest {Entity = new EntityKey {Id = entityId, Type = entityType}};
PlayFabDataAPI.GetObjects(getRequest,
    result => { var objs = result.Objects; },
    OnPlayFabError
);
```

## エンティティ ファイル

エンティティ ファイルを使用すると、任意の形式でエンティティに関連付けられたファイルを読み書きできます。

エンティティ ファイルを取得するには、[GetFiles](xref:titleid.playfabapi.com.data.file.getfiles) メソッドを使用します。

```csharp theme={null}
    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](xref:titleid.playfabapi.com.data.file.initiatefileuploads) メソッドを使用します。

```csharp theme={null}
    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](xref:titleid.playfabapi.com.data.file.abortfileuploads) メソッドを使用します。

```csharp theme={null}
    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](xref:titleid.playfabapi.com.data.file.finalizefileuploads) メソッドを使用します。エンティティ システムは、アトミック アップロード操作が正常に確定されるまで、ファイル アップロードを完了とはみなさず、他の呼び出し元にも変更を反映しません。

```csharp theme={null}
    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 度に 1 ファイルを保存しますが、複数ファイルをアトミックにセットとしてアップロードすることもできます。

この例では、Unity 3D エンジンの使用方法に慣れていることを前提としています。

```csharp theme={null}
#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
```

<Note>
  各ファイル操作には多数のステップと複数の API 呼び出しが必要になるため、同じファイルに対して複数の方法で同時にアクセスしないでください。十分に注意すれば、ロック メカニズムは不要になるかもしれません。複雑な処理を行いたい場合は、ロック メカニズムがはるかに複雑になる可能性があります。
</Note>

## Game Manager とエンティティ

Game Manager を使用すると、プレイヤーのオブジェクトとファイルを操作できます。プレイヤーの概要には、title player アカウントと master player アカウントの両方の情報が表示されます。

<img src="https://mintcdn.com/microsoft-4404708b/3hg2JQs0m7qmDqay/images/playfab/live-service-management/game-configuration/entities/tutorials/game-manager-entities-player-overview.png?fit=max&auto=format&n=3hg2JQs0m7qmDqay&q=85&s=ceac36d3b1e7fd248caeedbf4bea8055" alt="Game Manager - Entities - Player overview" width="1800" height="1406" data-path="images/playfab/live-service-management/game-configuration/entities/tutorials/game-manager-entities-player-overview.png" />

さらに、ファイルとオブジェクトは **Players** タブに専用のセクションを持つようになりました。

<img src="https://mintcdn.com/microsoft-4404708b/3hg2JQs0m7qmDqay/images/playfab/live-service-management/game-configuration/entities/tutorials/game-manager-entities-player-files.png?fit=max&auto=format&n=3hg2JQs0m7qmDqay&q=85&s=70b96669460d8bb673ec25fdbcd1bd41" alt="Game Manager - Entities - Player Files and Objects" width="1800" height="969" data-path="images/playfab/live-service-management/game-configuration/entities/tutorials/game-manager-entities-player-files.png" />

## 関連項目

PlayFab ブログの [Introducing Entities, Objects and Files](https://blog.playfab.com/blog/introducing-entities-objects-and-files)。


## Related topics

- [エンティティ移行情報](/ja-jp/services/playfab/live-service-management/game-configuration/entities/migration-information.md)
- [Lobby SDK クイックスタート](/ja-jp/services/playfab/multiplayer/lobby/lobby-getting-started.md)
- [クイックスタート](/ja-jp/services/playfab/economy-monetization/economy-v2/quickstart.md)
- [統計情報のクイックスタート](/ja-jp/services/playfab/player-progression/statistics/quickstart-statistics.md)
- [リーダーボードのクイックスタート](/ja-jp/services/playfab/community/leaderboards/quickstart-leaderboards.md)
