> ## 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.

# エンティティ グループ

> PlayFab エンティティ グループがギルド、クラン、パーティ、チャット チャンネルをどのようにモデル化するか、メンバーの役割、招待、共有オブジェクトおよびファイル データについて学びます。

ギルド、クラン、コーポレーション、カンパニー、トライブなど、ゲームで何と呼んでいてもかまいませんが、そうしたプレイヤーの永続的なグループ化が必要な場合、PlayFab は[エンティティ プログラミング モデル](/services/playfab/live-service-management/game-configuration/entities)を使用してそのニーズをサポートできます。

グループ エンティティは、プレイヤーやキャラクターを含む他のエンティティのコレクションを格納するために使用でき、ゲーム内でさまざまな目的に役立てることができます。

## 例

* **クラン/ギルド** - エンティティ グループは、長期的にプレイヤー同士を結び付けるどのような社会的な絆であっても、定期的に一緒にプレイするプレイヤーのセットを表すのに使用できます。

* **パーティ** - エンティティ グループは、個々のプレイヤーが直近の目標を達成できるようにするために作成され、その後簡単に解散される短期的なグループとして使用できます。

* **チャット チャンネル** - 短期または長期のチャット チャンネルをエンティティ グループとして定義できます。

* **ゲーム内の情報購読** - ゲーム内に単一インスタンスの伝説のアイテムがありますか? プレイヤーがそのアイテムの状況について常に更新情報を受け取りたい場合はどうしますか? そのアイテムに焦点を当てたエンティティ グループを作成し、そのアイテムに関心のあるすべてのプレイヤー エンティティをメンバーとして加えましょう。

つまり、エンティティ グループは、そのグループにひも付けられた永続的な状態が必要な、エンティティの*任意の*コレクション (NPC でもプレイヤー制御でも、現実でも抽象的でも) とすることができます。

さらに、エンティティ グループはそれ自体もエンティティであるため、エンティティが持つすべての初期機能を備えています。

* **オブジェクト データ**
* **ファイル データ**
* **プロファイル**

<Note>
  グループには既定でグループごとに 1000 メンバーの制限があり、メンバーとしてはプレイヤーとキャラクターのみをサポートします。
</Note>

## エンティティ グループの使用

グループを作成する際、グループに追加される最初のエンティティは Admin (管理者) ロールに配置されます (このガイドでは簡略化のため、そのエンティティをオーナーと呼びます)。オーナーは、新しいメンバーの招待、さまざまなカスタマイズ可能な権限を持つ新しいロールの作成、メンバーのロールの変更、メンバーのキックなどを行うことができます。

さらに、エンティティに存在する同じエンティティ関数が*グループにも機能する*ため、JSON オブジェクトやファイルを直接グループに保存して、ゲーム固有の任意のデータを保存できます。

以下に示すコード例は、基本的なギルド操作を始めるのに役立ちます。

このコードでは、グループの作成、メンバーの追加および削除、グループの削除が可能です。あくまで出発点として意図されており、ロールや権限については示していません。

```csharp theme={null}
using PlayFab;
using PlayFab.GroupsModels;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace TestGuildController
{
    /// <summary>
    /// Assumptions for this controller:
    /// + Entities can be in multiple groups
    ///   - This is game specific, many games would only allow 1 group, meaning you'd have to perform some additional checks to validate this.
    /// </summary>
    [Serializable]
    public class GuildTestController
    {
        // A local cache of some bits of PlayFab data
        // This cache pretty much only serves this example , and assumes that entities are uniquely identifiable by EntityId alone, which isn't technically true. Your data cache will have to be better.
        public readonly HashSet<KeyValuePair<string, string>> EntityGroupPairs = new HashSet<KeyValuePair<string, string>>();
        public readonly Dictionary<string, string> GroupNameById = new Dictionary<string, string>();

        public static EntityKey EntityKeyMaker(string entityId)
        {
            return new EntityKey { Id = entityId };
        }

        private void OnSharedError(PlayFab.PlayFabError error)
        {
            Debug.LogError(error.GenerateErrorReport());
        }

        public void ListGroups(EntityKey entityKey)
        {
            var request = new ListMembershipRequest { Entity = entityKey };
            PlayFabGroupsAPI.ListMembership(request, OnListGroups, OnSharedError);
        }
        private void OnListGroups(ListMembershipResponse response)
        {
            var prevRequest = (ListMembershipRequest)response.Request;
            foreach (var pair in response.Groups)
            {
                GroupNameById[pair.Group.Id] = pair.GroupName;
                EntityGroupPairs.Add(new KeyValuePair<string, string>(prevRequest.Entity.Id, pair.Group.Id));
            }
        }

        public void CreateGroup(string groupName, EntityKey entityKey)
        {
            // A player-controlled entity creates a new group
            var request = new CreateGroupRequest { GroupName = groupName, Entity = entityKey };
            PlayFabGroupsAPI.CreateGroup(request, OnCreateGroup, OnSharedError);
        }
        private void OnCreateGroup(CreateGroupResponse response)
        {
            Debug.Log("Group Created: " + response.GroupName + " - " + response.Group.Id);

            var prevRequest = (CreateGroupRequest)response.Request;
            EntityGroupPairs.Add(new KeyValuePair<string, string>(prevRequest.Entity.Id, response.Group.Id));
            GroupNameById[response.Group.Id] = response.GroupName;
        }
        public void DeleteGroup(string groupId)
        {
            // A title, or player-controlled entity with authority to do so, decides to destroy an existing group
            var request = new DeleteGroupRequest { Group = EntityKeyMaker(groupId) };
            PlayFabGroupsAPI.DeleteGroup(request, OnDeleteGroup, OnSharedError);
        }
        private void OnDeleteGroup(EmptyResponse response)
        {
            var prevRequest = (DeleteGroupRequest)response.Request;
            Debug.Log("Group Deleted: " + prevRequest.Group.Id);

            var temp = new HashSet<KeyValuePair<string, string>>();
            foreach (var each in EntityGroupPairs)
                if (each.Value != prevRequest.Group.Id)
                    temp.Add(each);
            EntityGroupPairs.IntersectWith(temp);
            GroupNameById.Remove(prevRequest.Group.Id);
        }

        public void InviteToGroup(string groupId, EntityKey entityKey)
        {
            // A player-controlled entity invites another player-controlled entity to an existing group
            var request = new InviteToGroupRequest { Group = EntityKeyMaker(groupId), Entity = entityKey };
            PlayFabGroupsAPI.InviteToGroup(request, OnInvite, OnSharedError);
        }
        public void OnInvite(InviteToGroupResponse response)
        {
            var prevRequest = (InviteToGroupRequest)response.Request;

            // Presumably, this would be part of a separate process where the recipient reviews and accepts the request
            var request = new AcceptGroupInvitationRequest { Group = EntityKeyMaker(prevRequest.Group.Id), Entity = prevRequest.Entity };
            PlayFabGroupsAPI.AcceptGroupInvitation(request, OnAcceptInvite, OnSharedError);
        }
        public void OnAcceptInvite(EmptyResponse response)
        {
            var prevRequest = (AcceptGroupInvitationRequest)response.Request;
            Debug.Log("Entity Added to Group: " + prevRequest.Entity.Id + " to " + prevRequest.Group.Id);
            EntityGroupPairs.Add(new KeyValuePair<string, string>(prevRequest.Entity.Id, prevRequest.Group.Id));
        }

        public void ApplyToGroup(string groupId, EntityKey entityKey)
        {
            // A player-controlled entity applies to join an existing group (of which they are not already a member)
            var request = new ApplyToGroupRequest { Group = EntityKeyMaker(groupId), Entity = entityKey };
            PlayFabGroupsAPI.ApplyToGroup(request, OnApply, OnSharedError);
        }
        public void OnApply(ApplyToGroupResponse response)
        {
            var prevRequest = (ApplyToGroupRequest)response.Request;

            // Presumably, this would be part of a separate process where the recipient reviews and accepts the request
            var request = new AcceptGroupApplicationRequest { Group = prevRequest.Group, Entity = prevRequest.Entity };
            PlayFabGroupsAPI.AcceptGroupApplication(request, OnAcceptApplication, OnSharedError);
        }
        public void OnAcceptApplication(EmptyResponse response)
        {
            var prevRequest = (AcceptGroupApplicationRequest)response.Request;
            Debug.Log("Entity Added to Group: " + prevRequest.Entity.Id + " to " + prevRequest.Group.Id);
        }
        public void KickMember(string groupId, EntityKey entityKey)
        {
            var request = new RemoveMembersRequest { Group = EntityKeyMaker(groupId), Members = new List<EntityKey> { entityKey } };
            PlayFabGroupsAPI.RemoveMembers(request, OnKickMembers, OnSharedError);
        }
        private void OnKickMembers(EmptyResponse response)
        {
            var prevRequest= (RemoveMembersRequest)response.Request;
            
            Debug.Log("Entity kicked from Group: " + prevRequest.Members[0].Id + " to " + prevRequest.Group.Id);
            EntityGroupPairs.Remove(new KeyValuePair<string, string>(prevRequest.Members[0].Id, prevRequest.Group.Id));
        }
    }
}
```

## サンプルの内容を分解する

このサンプルはコントローラーとして構築されており、最小限のデータをローカル キャッシュに保存し (PlayFab が信頼できるデータ層です)、グループに対する CRUD 操作を実行する方法を提供します。

提供されているサンプルの一部の関数を見てみましょう。

* `OnSharedError` - これは PlayFab のサンプルにおける典型的なパターンです。エラーを処理する最も簡単な方法はそれを報告することです。実際のゲーム クライアントでは、はるかに高度なエラー処理ロジックが実装されることになるでしょう。

* `ListMembership` - `ListMembership` を呼び出して、指定したエンティティが所属するすべてのグループを判定します。プレイヤーは、既に参加しているグループを知りたいものです。

* `CreateGroup`/`DeleteGroup` - ほぼ名前のとおりです。このサンプルでは、これらの呼び出しが成功したときにローカルのグループ情報キャッシュを更新する方法を示します。

* `InviteToGroup`/`ApplyToGroup` - グループへの参加は 2 段階のプロセスであり、両方向から開始できます。
  * プレイヤーがグループへの参加を申請できます。
  * グループがプレイヤーを招待できます。

* `AcceptGroupInvitation`/`AcceptGroupApplication` - 参加プロセスの 2 番目の段階です。応答するエンティティが招待を承諾することで、プレイヤーがグループの一員となる処理が完了します。

* `RemoveMembers` - (ロールの権限で定義された) 権限を持つメンバーは、グループからメンバーをキックできます。

## サーバーとクライアントの比較

すべての新しいエンティティ API メソッドと同様に、サーバー API とクライアント API の区別はありません。

アクションは、プロセスがどのように認証されたかに応じて呼び出し元によって実行されます。クライアントはそのように識別され、これらのメソッドをタイトル プレイヤー エンティティとして呼び出します。グループ内でのロールと権限は呼び出しのたびに評価され、そのアクションを実行する権限があることが保証されます。

サーバーは同じ `developerSecretKey` で認証され、これによってそのプロセスがタイトル エンティティとして識別されます。タイトルはロール チェックをバイパスし、タイトルによって実行される API 呼び出しは、たとえばエンティティがメンバーでない場合に削除できないなど、アクションを実行することが不可能な場合にのみ失敗します。

## 関連項目

グループ、ギルド、クランのデータを保存するには、次を参照してください。

* [オブジェクト](/services/playfab/live-service-management/game-configuration/entities/entity-objects)
* [ファイル](/services/playfab/live-service-management/game-configuration/entities/entity-files)


## Related topics

- [group_updated](/ja-jp/services/playfab/api-references/events/Groups/group-updated.md)
- [group_created](/ja-jp/services/playfab/api-references/events/Groups/group-created.md)
- [group_members_removed](/ja-jp/services/playfab/api-references/events/Groups/group-members-removed.md)
- [PlayFab の PlayStream イベント モデル リファレンス](/ja-jp/services/playfab/api-references/events/index.md)
- [group_members_added](/ja-jp/services/playfab/api-references/events/Groups/group-members-added.md)
