> For the complete documentation index, see [llms.txt](https://docs.edgegap.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.edgegap.com/docs.edgegap.com-ko/learn/distributed-relay/relay-transport-samples.md).

# 전송 샘플

플레이어를 매치메이커나 로비로 관리한 다음 Edgegap API를 사용해 리레이 세션을 생성한 후, 리레이가 준비되면 플레이어를 리레이에 연결해야 합니다. Edgegap은 이를 수행하기 위한 전용 전송(트랜스포트)을 제공하며 이 가이드에서는 프로젝트에 이를 구현하는 방법을 보여줍니다. 이 전송은 [여기 우리 GitHub에서](https://github.com/edgegap/distributed-relay-examples/tree/main).

Unity의 경우 현재 다음 넷코드용 전송 버전이 제공됩니다:

* Mirror;
* Fishnet;
* Unity Netcode for GameObjects (NGO).

### 트랜스포트 추가하기

사용 중인 넷코드에 맞는 트랜스포트를 다운로드한 후 프로젝트에 포함해야 합니다. 먼저 다음 위치에 프로젝트 파일로 추가하세요:

* **Mirror** : `Edgegap` 폴더를 아래에 추가하세요 `Assets/Mirror/Transports`;
* **Fishnet** : `Edgegap KcpTransport` 폴더를 아래에 추가하세요 `Assets/Fishnet/Plugins`;
* **NGO** : `EdgegapRelay` 및 `kcp2k` 폴더를 아래에 추가하세요 `Assets/Edgegap`.

그런 다음, `EdgegapKcpTransport` 스크립트를 귀하의 `을(를) 선택하고` 게임오브젝트에 추가하고, 새 컴포넌트를 `Transport` 게임오브젝트의 속성에도 드래그해서 넣었는지 확인하세요.

{% hint style="info" %}
옵션이 있는 경우, 반드시 `Relay GUI` 안의(in the) `EdgegapKcpTransport` 컴포넌트를 `을(를) 선택하고`비활성화하세요. 그렇지 않으면 리레이에 연결 시 간섭을 일으킬 수 있습니다.

이 옵션은 특히 Mirror 및 NGO 버전의 트랜스포트에 존재합니다.
{% endhint %}

### 리레이에 연결하기

매치메이킹과 리레이 세션 생성을 마친 후 Edgegap API를 사용해 리레이가 연결을 수락할 준비가 되었는지 확인하세요. 준비되면 API 응답에서 제공되는 데이터를 사용해 트랜스포트의 값을 설정합니다. 적절한 필드에 다음 값들이 필요합니다:

* 리레이의 `IP` 주소는 `트랜스포트의 리레이 주소로 사용됩니다`;
* 다음 `세션 권한 토큰` 은 `트랜스포트의 세션 ID로 사용됩니다`;
* 다음 `사용자의 권한 토큰` 은 `트랜스포트의 사용자 ID`.

#### 서버/호스트 연결

* 리레이의 `서버 포트` 값은 `트랜스포트의 리레이 포트로 사용됩니다` .

#### 클라이언트 연결

* 리레이의 `클라이언트 포트` 값은 `트랜스포트의 리레이 포트로 사용됩니다` .

{% hint style="info" %}
각 플레이어는 고유한 권한 토큰을 가지지만 세션 토큰은 세션의 모든 플레이어에게 동일하게 유지됩니다.
{% endhint %}

### Mirror 사용하기

```cs
// `data`는 JSON으로 변환된 역직렬화된 API 응답입니다
// `_EdgegapTransport`는 EdgegapKcpTransport입니다

// uint?를 uint로 변환
uint sessionAuthorizationToken = data.authorization_token ?? 0;

//TODO 어떤 세션 사용자가 플레이어에 해당하는지 찾기, `i`는 목록에서의 위치
uint userAuthorizationToken = data.session_users?[i].authorization_token ?? 0;

_EdgegapTransport.ChangeValue(
    data.relay.ip,
    data.relay.ports.client.port,
    data.relay.ports.server.port,
    data.session_id,
    sessionAuthorizationToken,
    userAuthorizationToken
);

// 그런 다음 호스트 플레이어인 경우 `NetworkManager.Singleton.StartHost();`
// 또는 클라이언트인 경우 `NetworkManager.Singleton.StartClient();` 
```

### Fishnet 사용하기

```cs
// `data`는 JSON으로 변환된 역직렬화된 API 응답입니다
// `_transport`는 EdgegapKcpTransport입니다

// uint?를 uint로 변환
uint sessionAuthorizationToken = data.authorization_token ?? 0;

//TODO 어떤 세션 사용자가 플레이어에 해당하는지 찾기, `i`는 목록에서의 위치
uint userAuthorizationToken = data.session_users?[i].authorization_token ?? 0;

Relay relay = data.relay;
string address = relay.ip;
ushort serverPort = relay.ports.server.port;
ushort clientPort = relay.ports.client.port;

var relayData = new EdgegapRelayData(
    address,
    serverPort,
    clientPort,
    userAuthorizationToken,
    sessionAuthorizationToken
);
_transport.SetEdgegapRelayData(relayData);

// 그런 다음 호스트인 경우 `_transport.StartConnection(true);`
// 또는 클라이언트인 경우 `_transport.StartConnection(false);`
```

### NGO 사용하기

```cs
// `data`는 JSON으로 변환된 역직렬화된 API 응답입니다
// `_EdgegapTransport`는 EdgegapKcpTransport입니다

// uint?를 uint로 변환
uint sessionAuthorizationToken = data.authorization_token ?? 0;

//TODO 어떤 세션 사용자가 플레이어에 해당하는지 찾기, `i`는 목록에서의 위치
uint userAuthorizationToken = data.session_users?[i].authorization_token ?? 0;

_EdgegapTransport.relayAddress = data.relay.ip;
_EdgegapTransport.relayGameClientPort = data.relay.ports.client.port;
_EdgegapTransport.relayGameServerPort = data.relay.ports.server.port;
_EdgegapTransport.sessionId = sessionAuthorizationToken;
_EdgegapTransport.userId = userAuthorizationToken;

// 그런 다음 호스트 플레이어인 경우 `NetworkManager.Singleton.StartHost();`
// 또는 클라이언트인 경우 `NetworkManager.Singleton.StartClient();` 
```

### ApiResponse 사용하기

```cs
public class ApiResponse
{
    public string session_id { get; set; }
    public uint? authorization_token { get; set; }
    public string status { get; set; }
    public bool ready { get; set; }
    public bool linked { get; set; }
    public object? error { get; set; }
    public List<SessionUser>? session_users { get; set; }
    public Relay relay { get; set; }
    public object? webhook_url { get; set; }
}
```

값들이 올바르게 설정되면 각 플레이어를 트랜스포트를 사용해 리레이에 연결하세요. 잠시 후 게임을 플레이할 수 있게 됩니다!

### 샘플 프로젝트

다음 프로젝트들은 Edgegap 리레이 트랜스포트를 사용하는 간단한 예제들입니다.

정상적으로 작동시키려면 명령 프롬프트 터미널을 열고 `git clone [URL]` 명령으로 프로젝트를 다운로드하세요. Unity Hub를 통해 프로젝트 폴더를 에디터에서 열고, 그 다음 `RelayProfileToken` 값을 `HelloWorldManager` 컴포넌트를 `을(를) 선택하고` 게임오브젝트에서 귀하의 리레이 프로필 토큰으로 변경하세요.

* [Mirror 샘플](https://github.com/edgegap/unity-mirror-relay-sample)
* [Fishnet 샘플](https://github.com/edgegap/unity-fishnet-relay-sample)
* [NGO 샘플](https://github.com/edgegap/unity-ngo-relay-sample)

{% hint style="info" %}
사용자 지정 [리레이 프로필 토큰](https://app.edgegap.com/relay-management/dashboard) 을 `HelloWorldManager.cs` 또는 `EdgegapRelayService.cs`.
{% endhint %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.edgegap.com/docs.edgegap.com-ko/learn/distributed-relay/relay-transport-samples.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
