유니티(Unity) 릴레이 서버에 대해 (#Relay 1편)

릴레이 서버란?

Unity에서 제공하는 멀티플레이어 게임용 Relay 서비스입니다.
Relay 서버는 게임 세션 생명주기와 독립적으로 동작하는 특징을 가지고 있습니다.
 
Relay 서버는 플레이어 연결 시간이 초과되면 플레이어 연결을 해제합니다.
 
Relay서버 서비스를 사용하면 비용이 많이 드는 전용 게임 서버(DGS)를 구축 하지 않고도 간편하고 안전한 P2P 통신을 통해 플레이어를 연결할 수 있습니다.
 
또한, Join Code 형식의 워크플로우를 사용하여 게임 서버를 유지하는 데 필요한 노력과 비용을 절약할 수 있습니다.


Join Code 형식이란?

 

유니티(Unity) Relay Join Code에 대해서 (#Relay 5편)

Join Code는 게임세션에 플레이어들이 참가할 수 있게 해주는 코드입니다 플레이어들은 로비, Chat, 그 외 서비스를 통해 코드를 공유할 수 있습니다 Join Code는 대소문자를 구분하지 않아 단순하고

wlsdn629.tistory.com


 


Relay Integrations

유니티의 통합시스템으로써 Lobby, Unity authentication, Unity Transport Package, Netcode for GameObjects 그리고 Mirror Networking API 와 같이 유니티 프로덕트들과 잘 통합됩니다.
 


Lobby

로비는 게임이 시작하기전에 유저들이 연결되게 해주는 서비스이며 public / private으로 설정이 가능합니다.
 


Unity Transport Package

Relay는 UTP(Unity Transport Package)를 활용하여 UDP 소켓을 통한 연결 기반 추상화 계층을 제공합니다.

 

유니티(Unity) Relay Server With UTP Set Up(Untiy Transport Package)

Relay SDK는 Unity Transport Package (UTP)에서 잘 작동됩니다 About Unity Transport | Unity Multiplayer Networking Unity Transport provides the com.unity.transport package, used to add multiplayer and network features to your project. docs-multiplay

wlsdn629.tistory.com

 


Relay Server 사용 순서

1. Set up the NetworkManager / 네트워크 매니저 설정하기

더보기
  1. Add a new GameObject to your scene.
  2. Add the NetworkManager MonoBehavior.
  3. In the MonoBehavior Properties, select the UnityTransport transport. After selecting UnityTransport, you’ll see a MonoBehavior called Unity Transport (script) at the bottom of the components list.
  4. Set the Protocol Type of the new component to Relay Unity Transport.

 


2. Set variables and utility functions / 변수들과 유틸리티 함수 설정하기

더보기

You’ll also need to initialize some variables, such as the maximum number of connections and the join code

 

const int m_MaxConnections = 4;
 
public string RelayJoinCode;

3. Authenticate a player / 플레이어 인증하기

더보기

You must authenticate both the host player and the connecting players. The simplest way to authenticate players is with the Authentication service's SignInAnonymouslyAsync() method. (호스트 플레이어와 연결중인 플레이어 둘다 인증해야 합니다 /  SignInAnonymouslyAsync() 함수를 통해 쉽게 해결할 수 있습니다.

 

async void Example_AuthenticatingAPlayer()
{
    try
    {
        await UnityServices.InitializeAsync();
        await AuthenticationService.Instance.SignInAnonymouslyAsync();
        var playerID = AuthenticationService.Instance.PlayerId;
    }
    catch (Exception e)
    {
        Debug.Log(e);
    }
}

 


4. Create an allocation and request a join code / 할당과 요청 - Join Code

더보기

When your game client functions as a host player

it must be able to create an allocation, request a join code, configure the connection type, and create a Singleton instance of the NetworkDriver   / 할당, Join Code를 요청하고, 연결 타입을 구성하고, 네트워크 드라이버의 싱글톤을 만들어야 합니다. 

 

to bind the Relay server and listen for connection requests from joining players. / 릴레이 서버를 합치고 새로 들어오는 플레이어로부터 연결 요청을 듣기 위함입니다. 

 

AllocateRelayServerAndGetJoinCode, that shows how to use the Relay SDK to create an allocation, request a join code, and configure the connection type / AllocateRelayServerAndGetJoinCode 함수를 이용해서 쉽게 만들 수 있습니다. 

public static async Task<RelayServerData> AllocateRelayServerAndGetJoinCode(int maxConnections, string region = null)
{
    Allocation allocation;
    string createJoinCode;
    try
    {
        allocation = await RelayService.Instance.CreateAllocationAsync(maxConnections, region);
    }
    catch (Exception e)
    {
        Debug.LogError($"Relay create allocation request failed {e.Message}");
        throw;
    }

    Debug.Log($"server: {allocation.ConnectionData[0]} {allocation.ConnectionData[1]}");
    Debug.Log($"server: {allocation.AllocationId}");

    try
    {
        createJoinCode = await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
    }
    catch
    {
        Debug.LogError("Relay create join code request failed");
        throw;
    }

    return new RelayServerData(allocation, "dtls");
}

5. Configure The transport and start NGO / Transport를 구성하고 NGO시작하기

더보기

ConfigureTransportAndStartNgoAsHost, that shows how to use the Relay SDK and NGO SDK to configure the transport and start NGO as a host player.

Note: When starting a Relay server as a host player, both instances of connection data are identical to one another.

/ 호스트 플레이어로써 Relay 서버를 시작할 때, 연결된 데이터의 인스턴스들은 다른 사람과 동일해야 합니다.

IEnumerator Example_ConfigureTransportAndStartNgoAsHost()
{
    var serverRelayUtilityTask = AllocateRelayServerAndGetJoinCode(m_MaxConnections);
    while (!serverRelayUtilityTask.IsCompleted)
    {
        yield return null;
    }
    if (serverRelayUtilityTask.IsFaulted)
    {
        Debug.LogError("Exception thrown when attempting to start Relay Server. Server not started. Exception: " + serverRelayUtilityTask.Exception.Message);
        yield break;
    }

    var relayServerData = serverRelayUtilityTask.Result;

    // Display the joinCode to the user.

    NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(relayServerData);
    NetworkManager.Singleton.StartHost();
    yield return null;
}

6. Joining player / 참여하는 플레이어

더보기

When your game client functions as a joining player, it must be able to join an allocation, configure the connection type, and create a singleton instance of the NetworkDriver to bind to the Relay server and send a connection request to the host player.

JoinRelayServerFromJoinCode, that shows how to use the Relay SDK to join an allocation with a join code and configure the connection type

public static async Task<RelayServerData> JoinRelayServerFromJoinCode(string joinCode)
{
    JoinAllocation allocation;
    try
    {
        allocation = await RelayService.Instance.JoinAllocationAsync(joinCode);
    }
    catch
    {
        Debug.LogError("Relay create join code request failed");
        throw;
    }

    Debug.Log($"client: {allocation.ConnectionData[0]} {allocation.ConnectionData[1]}");
    Debug.Log($"host: {allocation.HostConnectionData[0]} {allocation.HostConnectionData[1]}");
    Debug.Log($"client: {allocation.AllocationId}");

    return new RelayServerData(allocation, "dtls");
}

Configure the transport and start NGO as a joining player

The following sample code demonstrates how to configure the transport and start Netcode for GameObjects (NGO) as a joining player.

Note: When starting a Relay server as a joining player, the host and the joining player each have distinct connection data. / 릴레이 서버에 새로 합류하는 플레이어로써 시작하면, Host와 참여하는 플레이어는 각각 다른 별개의 연결 데이터를 가지게 됩니다. 

IEnumerator Example_ConfigureTransportAndStartNgoAsConnectingPlayer()
{
    // Populate RelayJoinCode beforehand through the UI
    var clientRelayUtilityTask = JoinRelayServerFromJoinCode(RelayJoinCode);

    while (!clientRelayUtilityTask.IsCompleted)
    {
        yield return null;
    }

    if (clientRelayUtilityTask.IsFaulted)
    {
        Debug.LogError("Exception thrown when attempting to connect to Relay Server. Exception: " + clientRelayUtilityTask.Exception.Message);
        yield break;
    }

    var relayServerData = clientRelayUtilityTask.Result;

    NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(relayServerData);

    NetworkManager.Singleton.StartClient();
    yield return null;
}