[출처] - Unity Documentation
#1. Initialize Unity Services
await UnityServices.InitializeAsync();
를 사용해 UnityServices 를 초기화 해야합니다
#2. Authenticate the player
public async void OnSignIn()
{
await AuthenticationService.Instance.SignInAnonymouslyAsync();
playerId = AuthenticationService.Instance.PlayerId;
Debug.Log($"Signed in. Player ID: {playerId}");
}
호스트 플레이어와 연결중인 플레이어 모두 인증해야합니다
가장 쉬운 방법은 SignInAnonymouslyAsync() 함수를 이용하는 것입니다
#3.Host player(Host Player 기준!!)
호스트 플레이어로써 게임을 시작할 때, allocation, request a join code, configure the connection type, and create an instance of the NetworkDriver를 해야합니다, 자세한 내용은 아래 포스팅을 참고하면 됩니다
#4. The host player update loop
allocation flow 스텝을 밟기 전에 호스트 플레이어의 Update loop문을 설정해야 합니다
쉽게 하기 위해서, Update문에서 매번 아래 접은 글에 달려 있는 코드를 집어 넣으면 됩니다
void UpdateHost()
{
// Skip update logic if the Host isn't yet bound.
if (!hostDriver.IsCreated || !hostDriver.Bound)
{
return;
}
// This keeps the binding to the Relay server alive,
// preventing it from timing out due to inactivity.
hostDriver.ScheduleUpdate().Complete();
// Clean up stale connections.
for (int i = 0; i < serverConnections.Length; i++)
{
if (!serverConnections[i].IsCreated)
{
Debug.Log("Stale connection removed");
serverConnections.RemoveAt(i);
--i;
}
}
// Accept incoming client connections.
NetworkConnection incomingConnection;
while ((incomingConnection = hostDriver.Accept()) != default(NetworkConnection))
{
// Adds the requesting Player to the serverConnections list.
// This also sends a Connect event back the requesting Player,
// as a means of acknowledging acceptance.
Debug.Log("Accepted an incoming connection.");
serverConnections.Add(incomingConnection);
}
// Process events from all connections.
for (int i = 0; i < serverConnections.Length; i++)
{
Assert.IsTrue(serverConnections[i].IsCreated);
// Resolve event queue.
NetworkEvent.Type eventType;
while ((eventType = hostDriver.PopEventForConnection(serverConnections[i], out var stream)) != NetworkEvent.Type.Empty)
{
switch (eventType)
{
// Handle Relay events.
case NetworkEvent.Type.Data:
FixedString32Bytes msg = stream.ReadFixedString32();
Debug.Log($"Server received msg: {msg}");
hostLatestMessageReceived = msg.ToString();
break;
// Handle Disconnect events.
case NetworkEvent.Type.Disconnect:
Debug.Log("Server received disconnect from client");
serverConnections[i] = default(NetworkConnection);
break;
}
}
}
}
#5.Create an allocation
설정을 다 했으면 allocation을 만들 차례입니다
allocation 또한 스닙셋 코드가 존재하며 다음과 같습니다
public async void OnAllocate()
{
Debug.Log("Host - Creating an allocation. Upon success, I have 10 seconds to BIND to the Relay server that I've allocated.");
// Determine region to use (user-selected or auto-select/QoS)
string region = GetRegionOrQosDefault();
Debug.Log($"The chosen region is: {region ?? autoSelectRegionName}");
// Set max connections. Can be up to 100, but note the more players connected, the higher the bandwidth/latency impact.
int maxConnections = 4;
// Important: After the allocation is created, you have ten seconds to BIND, else the allocation times out.
hostAllocation = await RelayService.Instance.CreateAllocationAsync(maxConnections, region);
Debug.Log($"Host Allocation ID: {hostAllocation.AllocationId}, region: {hostAllocation.Region}");
// Initialize NetworkConnection list for the server (Host).
// This list object manages the NetworkConnections which represent connected players.
serverConnections = new NativeList<NetworkConnection>(maxConnections, Allocator.Persistent);
}
hostAllocation = await RelayService.Instance.CreateAllocationAsync(maxConnections, region);
#6. Bind to the Relay server and listen for connections
릴레이 서버와 연결을 Bind하는 방법은 OnBindHost 스닙셋 코드를 이용하여 쉽게 할 수 있습니다
public void OnBindHost()
{
Debug.Log("Host - Binding to the Relay server using UTP.");
// Extract the Relay server data from the Allocation response.
var relayServerData = new RelayServerData(hostAllocation, "udp");
// Create NetworkSettings using the Relay server data.
var settings = new NetworkSettings();
settings.WithRelayParameters(ref relayServerData);
// Create the Host's NetworkDriver from the NetworkSettings.
hostDriver = NetworkDriver.Create(settings);
// Bind to the Relay server.
if (hostDriver.Bind(NetworkEndPoint.AnyIpv4) != 0)
{
Debug.LogError("Host client failed to bind");
}
else
{
if (hostDriver.Listen() != 0)
{
Debug.LogError("Host client failed to listen");
}
else
{
Debug.Log("Host client bound to Relay server");
}
}
}
#7. Request a join code
Allocation이 성공적으로 마무리 되면 그 다음으론
OnJoinCode스닙셋 코드를 이용해서 호스트 플레이어는 게임 세션안에 호스트 플레이어와 참여 플레이어들이 함께
Join할 수 있게 Join Code를 공유해줍니다
public async void OnJoinCode()
{
Debug.Log("Host - Getting a join code for my allocation. I would share that join code with the other players so they can join my session.");
try
{
joinCode = await RelayService.Instance.GetJoinCodeAsync(hostAllocation.AllocationId);
Debug.Log("Host - Got join code: " + joinCode);
}
catch (RelayServiceException ex)
{
Debug.LogError(ex.Message + "\n" + ex.StackTrace);
}
}
#8. Joining player(여기 부터는 Join Player 기준!!)
참여하는 플레이어 또한, Allocation, Connection Type 구성, NetworkDriver 인스턴화하기가 필요합니다
이 또한,
이전 포스팅을 참고하면 됩니다
호스트 플레이어의 게임 세션에 참여하기 전에 , 참여하는 플레이어의 Update문을 설정해주어야 합니다
void UpdatePlayer()
{
// Skip update logic if the Player isn't yet bound.
if (!playerDriver.IsCreated || !playerDriver.Bound)
{
return;
}
// This keeps the binding to the Relay server alive,
// preventing it from timing out due to inactivity.
playerDriver.ScheduleUpdate().Complete();
// Resolve event queue.
NetworkEvent.Type eventType;
while ((eventType = clientConnection.PopEvent(playerDriver, out var stream)) != NetworkEvent.Type.Empty)
{
switch (eventType)
{
// Handle Relay events.
case NetworkEvent.Type.Data:
FixedString32Bytes msg = stream.ReadFixedString32();
Debug.Log($"Player received msg: {msg}");
playerLatestMessageReceived = msg.ToString();
break;
// Handle Connect events.
case NetworkEvent.Type.Connect:
Debug.Log("Player connected to the Host");
break;
// Handle Disconnect events.
case NetworkEvent.Type.Disconnect:
Debug.Log("Player got disconnected from the Host");
clientConnection = default(NetworkConnection);
break;
}
}
}
#10.Join an allocation
설정이 끝나면 호스트 플레이어가 만들어둔 Allocation에 Join하면 됩니다
OnJoin 스닙셋 코드를 이용해 쉽게 Join할 수 있습니다
public async void OnJoin()
{
// Input join code in the respective input field first.
if (String.IsNullOrEmpty(JoinCodeInput.text))
{
Debug.LogError("Please input a join code.");
return;
}
Debug.Log("Player - Joining host allocation using join code. Upon success, I have 10 seconds to BIND to the Relay server that I've allocated.");
try
{
playerAllocation = await RelayService.Instance.JoinAllocationAsync(JoinCodeInput.text);
Debug.Log("Player Allocation ID: " + playerAllocation.AllocationId);
}
catch (RelayServiceException ex)
{
Debug.LogError(ex.Message + "\n" + ex.StackTrace);
}
}
PlayerAllocation = await RelayService.Instance.JoinAllocationAsync(JoinCodeInput.text);
#11. Bind to the Relay server and connect to the host player
호스트플레이어와 Relay server에 Bind하기 위해 OnBindPlayer스닙셋 코드를 이용해서 쉽게 할 수 있습니다
public void OnBindPlayer()
{
Debug.Log("Player - Binding to the Relay server using UTP.");
// Extract the Relay server data from the Join Allocation response.
var relayServerData = new RelayServerData(playerAllocation, "udp");
// Create NetworkSettings using the Relay server data.
var settings = new NetworkSettings();
settings.WithRelayParameters(ref relayServerData);
// Create the Player's NetworkDriver from the NetworkSettings object.
playerDriver = NetworkDriver.Create(settings);
// Bind to the Relay server.
if (playerDriver.Bind(NetworkEndPoint.AnyIpv4) != 0)
{
Debug.LogError("Player client failed to bind");
}
else
{
Debug.Log("Player client bound to Relay server");
}
}
public void OnConnectPlayer()
{
Debug.Log("Player - Connecting to Host's client.");
// Sends a connection request to the Host Player.
clientConnection = playerDriver.Connect();
}
12. Sending messages
1) as the host
public void OnHostSendMessage()
{
if (serverConnections.Length == 0)
{
Debug.LogError("No players connected to send messages to.");
return;
}
// Get message from the input field, or default to the placeholder text.
var msg = !String.IsNullOrEmpty(HostMessageInput.text) ? HostMessageInput.text : HostMessageInput.placeholder.GetComponent<Text>().text;
// In this sample, we will simply broadcast a message to all connected clients.
for (int i = 0; i < serverConnections.Length; i++)
{
if (hostDriver.BeginSend(serverConnections[i], out var writer) == 0)
{
// Send the message. Aside from FixedString32, many different types can be used.
writer.WriteFixedString32(msg);
hostDriver.EndSend(writer);
}
}
}
2) as a player
public void OnPlayerSendMessage()
{
if (!clientConnection.IsCreated)
{
Debug.LogError("Player isn't connected. No Host client to send message to.");
return;
}
// Get message from the input field, or default to the placeholder text.
var msg = !String.IsNullOrEmpty(PlayerMessageInput.text) ? PlayerMessageInput.text : PlayerMessageInput.placeholder.GetComponent<Text>().text;
if (playerDriver.BeginSend(clientConnection, out var writer) == 0)
{
// Send the message. Aside from FixedString32, many different types can be used.
writer.WriteFixedString32(msg);
playerDriver.EndSend(writer);
}
}
#13. Disconnecting
1) a player as the host
public void OnDisconnectPlayers()
{
if (serverConnections.Length == 0)
{
Debug.LogError("No players connected to disconnect.");
return;
}
// In this sample, we will simply disconnect all connected clients.
for (int i = 0; i < serverConnections.Length; i++)
{
// This sends a disconnect event to the destination client,
// letting them know they're disconnected from the Host.
hostDriver.Disconnect(serverConnections[i]);
// Here, we set the destination client's NetworkConnection to the default value.
// It will be recognized in the Host's Update loop as a stale connection, and be removed.
serverConnections[i] = default(NetworkConnection);
}
}
2) as a player
public void OnDisconnect()
{
// This sends a disconnect event to the Host client,
// letting them know they're disconnecting.
playerDriver.Disconnect(clientConnection);
// We remove the reference to the current connection by overriding it.
clientConnection = default(NetworkConnection);
}
#정리
1. 초기화
2. 로그인
3. 호스트플레이어 SetUp - (Allocation, configure Connection Type, NetworkDriver)
4. Bind - Relay Server and listen for Connections request form joining players
5. 조인 코드 요청
6. Join 플레이어 SetUp - (Allocation, configure Connection Type, NetworkDriver)
7. Bind to the Relay server and connect to the host player