> For the complete documentation index, see [llms.txt](/ko/llms.txt)


# 플레이어 연결하기

두 계정으로 프로필, 랭킹, 친구, 길드를 확인합니다.



지금까지 사용한 플레이어를 A로 두고 B를 새로 만듭니다. 두 사람의 이름을 표시하고 점수를 겨루며 친구와 길드로 연결합니다.

## 1. 프로필·랭킹·길드 설정 추가하기


**Studio**

**Add features** 에서 **Friends & Profile**, **Rankings**, **Guilds** 를 추가합니다. 프로필과 친구는 표에 설정을 추가할 필요가 없습니다.

**Tables → Rankings → Ranking** 에 행을 추가하고 다음 값을 입력합니다.

| 항목 | 값 |
| --- | --- |
| ID | `adventure` |
| 순위 방향 | `desc`(높은 점수순) |
| 점수 합산 | 끔 |
| 최소 점수 | `0` |
| 최대 점수 | `1000000` |
| 개최 일정 | 비워 둠 |

랭킹 보상 행은 추가하지 않습니다. 이번에는 마지막으로 보낸 점수를 사용하는 랭킹을 만듭니다.

**Tables → Guilds → GuildRole** 에 다음 두 행을 추가합니다. 링크의 JSON 전체를 각 **Permission policy** 셀에 붙여 넣습니다.

| ID | 권한 정책 |
| --- | --- |
| `master` | <a href="/samples/adventure/ko/extensions/guild-master-policy.json" download>마스터 정책</a>. 길드 설정 변경과 신청 승인을 허용 |
| `member` | <a href="/samples/adventure/ko/extensions/guild-member-policy.json" download>일반 멤버 정책</a>. 길드 관리 권한은 부여하지 않음 |

**Guild** 에 행을 추가하고 다음 값을 입력합니다.

| 항목 | 값 |
| --- | --- |
| ID | `adventure` |
| 초기·최대 정원 | 모두 `10` |
| 재가입 대기 시간 | `0` |
| 동시 소속·마스터 수 상한 | 모두 `1` |
| 마스터 역할 | `master` |
| 일반 멤버 역할 | `member` |
| 마스터 부재 판정 기간 | 비워 둠 |

**Publish → Calculate server differences** 에서 배포한 뒤 **Update the Unity project** 를 누릅니다.


**SDK (Unity)**

<a href="/samples/adventure/ko/extensions/social.json" download>교류 기능 템플릿</a>을 다운로드합니다. 관리 콘솔의 Tokyo 리전에서 **Deploy → Stack list → Create stack** 을 엽니다. 이름을 `adventure-social`로 지정하고 **Template data** 에서 파일을 선택해 생성합니다.

| 기능 | 서비스 / 네임스페이스 | 설정 |
| --- | --- | --- |
| 프로필과 친구 | Friend / `adventure-friend` | 플레이어별 이름과 친구 저장 |
| 랭킹 | Ranking2 / `adventure-ranking` | `adventure`. 높은 점수순, 합산하지 않고 마지막 값으로 갱신 |
| 길드 | Guild / `adventure-guild` | 유형 `adventure`. 정원 10명, 동시 소속 1개, 재가입 대기 없음 |

이 스택을 추가한 뒤에도 기존 모험과 캐릭터 설정은 그대로 사용할 수 있습니다.




### Unity에 교류 화면 추가하기

재생을 멈추고 `Extensions`의 **Adventure Characters** 체크를 해제합니다. 왼쪽 모험 화면은 그대로 사용합니다.


**Studio**

<a href="/samples/adventure/ko/extensions/studio/AdventureSocial.cs" download>AdventureSocial.cs</a>를 `Assets/AdventureExtensions`에 넣고 `Extensions`에 **Adventure Social** 을 추가합니다. 로그인된 `Gs2ClientHolder`와 `Gs2GameSessionHolder`를 사용합니다.


**SDK (Unity)**

<a href="/samples/adventure/ko/extensions/sdk/AdventureSocial.cs" download>AdventureSocial.cs</a>를 `Assets/AdventureExtensions`에 넣고 `Extensions`에 **Adventure Social** 을 추가합니다. **Login** 에 씬의 `AdventureLogin`을 할당합니다.




재생하면 오른쪽에 교류 화면이 나타납니다. 아래쪽 버튼은 화면 안을 스크롤하면 볼 수 있습니다.

### A와 B 전환하기

오른쪽의 **내 ID 복사** 를 누르고 텍스트 편집기 등에 A의 플레이어 ID로 기록합니다. **표시 이름** 을 `모험가 A`로 지정하고 **내 이름 저장** 을 누릅니다.


**Studio**

재생을 멈춥니다. 로그인 오브젝트의 **PlayerPrefs Account Store → Key Prefix** 를 `adventure.main`에서 `adventure.social-b`로 바꾸고 재생합니다. 처음에는 B의 계정이 만들어집니다.

이후 A를 사용할 때는 재생을 멈추고 Key Prefix를 `adventure.main`, B를 사용할 때는 `adventure.social-b`로 바꾼 뒤 재생합니다. 저장된 계정으로 로그인하므로 같은 플레이어 ID로 돌아옵니다.


**SDK (Unity)**

재생을 멈추고 `AdventureLogin`의 **Account Slot** 을 `main`에서 `social-b`로 바꾼 뒤 재생하고 로그인합니다. 처음에는 B의 계정이 만들어집니다.

이후에도 재생을 멈추고 A는 Account Slot을 `main`, B는 `social-b`로 바꾼 뒤 재생하고 로그인합니다. 저장된 계정으로 로그인하므로 같은 플레이어 ID로 돌아옵니다.




B에서도 **내 ID 복사** 로 ID를 기록하고 표시 이름을 `모험가 B`로 저장합니다. **상대 플레이어 ID** 에 A의 ID를 입력하고 **상대 이름 읽기** 를 누르면 `모험가 A`가 표시됩니다.

A로 전환하고 상대 ID에 B의 ID를 넣어 이름을 읽습니다. B의 이름이 표시되면 ID로 다른 플레이어를 참조할 수 있는 것입니다.

이름은 Friend의 공개 프로필에 저장합니다.

```csharp
await Client.Friend.Namespace(FriendNamespace).Me(Session).Profile()
    .UpdateProfileAsync(publicProfile: displayName);

await Client.Friend.Namespace(FriendNamespace).User(targetUserId)
    .PublicProfile().ModelAsync();
```

## 2. 점수를 보내고 순위 비교하기

이 랭킹은 최고 기록이 아니라 **마지막으로 보낸 점수** 로 순위를 매깁니다.

목록에는 순위, 전송 당시 표시 이름, 점수, 플레이어 ID가 나옵니다. 목록에 반영되기까지 최대 5분이 걸릴 수 있습니다. 보낸 점수가 아직 표시되지 않으면 잠시 기다린 뒤 **랭킹 읽기** 를 누릅니다. 순위를 확인하고 표의 다음 조작으로 진행합니다.

| 조작 | 랭킹을 읽었을 때의 결과 |
| --- | --- |
| A에서 표시 이름 `모험가 A`, 점수 `100`으로 **점수 보내기** | A가 100점 |
| B로 전환해 표시 이름 `모험가 B`, 점수 `200`을 전송 | B가 200점으로 A보다 높은 순위 |
| A로 전환해 표시 이름 `모험가 A`, 점수 `300`을 전송 | A가 300점으로 B보다 높은 순위 |
| A에서 `50`을 전송 | A가 50점으로 갱신되어 B보다 낮은 순위 |

```csharp
var ranking = Client.Ranking2.Namespace(RankingNamespace)
    .GlobalRankingModel("adventure").GlobalRankingSeason(Session);
await ranking.PutGlobalRankingAsync(value, displayName);
await foreach (var item in ranking.GlobalRankingsAsync())
{
    if (item != null) message += item.Rank + ": " + item.Metadata + " / " + item.Score + "\n";
}
```

표시 이름은 점수와 함께 보냅니다. 프로필 이름만 바꿔서는 랭킹의 이름이 바뀌지 않습니다. 새 표시 이름을 입력하고 점수를 보내면 갱신됩니다.

## 3. 친구 신청하고 승인하기

1. A에서 상대 플레이어 ID에 B의 ID를 넣고 **친구 신청 보내기** 를 누릅니다.
2. **친구 목록 읽기** 를 누릅니다. 승인 전이므로 B는 아직 목록에 없습니다.
3. B로 전환하고 상대 ID에 A의 ID를 넣어 **상대 신청 승인** 을 누릅니다. 친구 목록에 A가 표시됩니다.
4. A로 전환해 목록을 읽으면 B가 표시됩니다.
5. A에서 상대 ID에 B의 ID를 넣고 **친구 해제** 를 누릅니다. A의 목록에서 B가 사라집니다. B로 전환해 다시 읽으면 B의 목록에서도 A가 사라집니다.

신청 대상과 승인할 신청의 발신자를 각각 플레이어 ID로 지정합니다.

```csharp
var me = Client.Friend.Namespace(FriendNamespace).Me(Session);
await me.SendRequestAsync(targetUserId);
await me.ReceiveFriendRequest(targetUserId).AcceptAsync();
await foreach (var item in me.FriendsAsync(withProfile: true))
{
    if (item != null) message += item.UserId + " / " + item.PublicProfile + "\n";
}
```

## 4. 길드 가입하기

A로 전환하고 **모험가 길드 만들기** 를 누릅니다. 생성된 길드 ID가 입력란에 표시되므로 기록합니다. 멤버 목록에는 A와 `master` 역할이 표시됩니다.

1. B로 전환하고 기록한 ID를 **길드 ID** 에 입력합니다.
2. **이 길드에 가입·신청** 을 누릅니다. 처음에는 자유 가입(`anybody`)이므로 바로 가입됩니다.
3. **멤버 목록 읽기** 를 누르면 A와 B가 표시됩니다. B의 역할은 `member`입니다.
4. B에서 **이 길드 탈퇴** 를 누릅니다.
5. A로 전환하고 같은 길드 ID를 입력해 **마스터: 승인제로 변경** 을 누릅니다. 가입 방식이 `approval`로 바뀝니다.
6. B로 전환하고 같은 길드에 다시 **이 길드에 가입·신청** 을 누릅니다. 이번에는 신청만 전송되고 B는 아직 멤버 목록에 없습니다.
7. A로 전환하고 길드 ID와 상대 플레이어 ID(B)를 입력해 **마스터: 상대 신청 승인** 을 누릅니다. 멤버 목록에 B가 추가됩니다.

길드 생성과 가입에는 로그인 중인 플레이어의 세션을 사용합니다.

```csharp
var me = Client.Guild.Namespace(GuildNamespace).Me(Session);
await me.CreateGuildAsync("adventure", "모험가 길드", "anybody");
await me.SendRequestAsync("adventure", guildName);
```

신청 승인이나 가입 방식 변경은 A의 권한으로 길드 세션을 얻은 뒤 실행합니다. 이 처리는 `AdventureSocial.cs`의 `ManageGuild()`에 있습니다.

마지막에는 A로 둡니다. 다음 장에서는 이 플레이어에게 이벤트 보상을 보냅니다.

[다음: 이벤트 열기]()



