Files

340 lines
11 KiB
C#
Raw Permalink Normal View History

2022-12-03 20:40:43 +02:00
using System;
using System.Collections.Generic;
using UnityEngine;
2022-12-07 12:13:57 +02:00
using Unity.Services.Core;
using Unity.Services.Authentication;
using System.Threading.Tasks;
using Unity.Netcode;
using Unity.Services.Lobbies;
using Unity.Services.Lobbies.Models;
using System.Net;
using System.Net.Sockets;
2022-12-08 14:35:27 +02:00
using UnityEngine.SceneManagement;
2022-12-08 17:39:21 +02:00
using Unity.Netcode.Transports.UTP;
2023-01-01 12:50:59 +02:00
using STUN.Attributes;
using STUN;
2022-12-03 20:40:43 +02:00
2022-12-04 21:35:31 +02:00
public class NetworkManagerLobby : MonoBehaviour
2022-12-03 20:40:43 +02:00
{
2023-02-02 02:10:38 +02:00
[SerializeField] private OnlineErrorMenu _onlineErrorMenu = default;
2022-12-07 12:13:57 +02:00
[SerializeField] private int _maxPlayers = 2;
private Lobby _hostLobby;
private Lobby _clientLobby;
private float _lobbyUpdateTimer;
2022-12-08 03:28:59 +02:00
public Action OnLobbyUpdate;
2023-01-15 01:54:52 +02:00
//Initialize the Unity services and authenticate the user anonymously
//Will change when accounts are introduced
2022-12-07 12:13:57 +02:00
public static async void Authenticate()
{
await UnityServices.InitializeAsync();
AuthenticationService.Instance.SignedIn += () =>
{
Debug.Log("Signed in:" + AuthenticationService.Instance.PlayerId);
};
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
2023-01-15 01:54:52 +02:00
//Host a lobby
2022-12-07 12:13:57 +02:00
public async Task<string> CreateLobby(DemonData demonData)
{
2023-02-02 02:10:38 +02:00
Lobby lobby;
2023-02-12 03:29:03 +02:00
Unity.Services.Lobbies.Models.Player player = null;
try
{
player = GetPlayer(demonData);
}
catch (System.Exception e)
{
2023-02-22 15:36:55 +02:00
_onlineErrorMenu.Show("Host:" + e.Message);
2023-02-12 03:29:03 +02:00
return null;
}
2022-12-07 12:13:57 +02:00
CreateLobbyOptions createLobbyOptions = new CreateLobbyOptions
{
IsPrivate = false,
Player = player,
Data = new Dictionary<string, DataObject>
{
{
"Code", new DataObject(
visibility: DataObject.VisibilityOptions.Public,
value: "111111",
index: DataObject.IndexOptions.S1)
}
}
2022-12-07 12:13:57 +02:00
};
2023-02-02 02:10:38 +02:00
try
{
lobby = await LobbyService.Instance.CreateLobbyAsync("darklings", _maxPlayers, createLobbyOptions);
_hostLobby = lobby;
}
catch (LobbyServiceException e)
{
2023-02-22 15:36:55 +02:00
_onlineErrorMenu.Show("Lobby:" + e.Reason.ToString());
2023-02-02 02:10:38 +02:00
return null;
}
2022-12-07 12:13:57 +02:00
return lobby.LobbyCode;
}
2022-12-08 03:28:59 +02:00
public Lobby GetHostLobby()
{
return _hostLobby;
}
2022-12-08 14:35:27 +02:00
public Lobby GetClientLobby()
{
return _clientLobby;
}
//Quick join the first found lobby
public async Task<Lobby> QuickJoinLobby(DemonData demonData)
{
Lobby lobby;
Unity.Services.Lobbies.Models.Player player = null;
try
{
player = GetPlayer(demonData);
}
catch (System.Exception e)
{
_onlineErrorMenu.Show(e.Message);
return null;
}
QuickJoinLobbyOptions quickJoinLobbyByCodeOptions = new QuickJoinLobbyOptions
{
Player = GetPlayer(demonData)
};
try
{
lobby = await Lobbies.Instance.QuickJoinLobbyAsync(quickJoinLobbyByCodeOptions);
_clientLobby = lobby;
}
catch (LobbyServiceException e)
{
_onlineErrorMenu.Show(e.Reason.ToString());
return null;
}
return lobby;
}
//Search for lobbies
public async Task<Lobby[]> SearchLobbies()
{
Lobby[] lobbies;
try
{
QueryLobbiesOptions queryLobbiesOptions = new QueryLobbiesOptions();
queryLobbiesOptions.Count = 20;
queryLobbiesOptions.Filters = new List<QueryFilter>();
{
new QueryFilter(
field: QueryFilter.FieldOptions.AvailableSlots,
op: QueryFilter.OpOptions.GT,
value: "0");
}
QueryResponse query = await Lobbies.Instance.QueryLobbiesAsync(queryLobbiesOptions);
lobbies = query.Results.ToArray();
}
catch (LobbyServiceException e)
{
_onlineErrorMenu.Show(e.Reason.ToString());
return null;
}
if (lobbies.Length == 0)
{
2023-09-26 01:27:40 +03:00
_onlineErrorMenu.Show("No rooms found");
return null;
}
return lobbies;
}
2023-01-15 01:54:52 +02:00
//Join the lobby given a lobby Id
2022-12-07 12:13:57 +02:00
public async Task<Lobby> JoinLobby(DemonData demonData, string lobbyId)
{
Lobby lobby;
Unity.Services.Lobbies.Models.Player player = null;
try
{
player = GetPlayer(demonData);
}
catch (System.Exception e)
{
_onlineErrorMenu.Show(e.Message);
return null;
}
JoinLobbyByIdOptions joinLobbyByIdOptions = new JoinLobbyByIdOptions
{
Player = GetPlayer(demonData)
};
try
{
lobby = await Lobbies.Instance.JoinLobbyByIdAsync(lobbyId, joinLobbyByIdOptions);
_clientLobby = lobby;
}
catch (LobbyServiceException e)
{
_onlineErrorMenu.Show(e.Reason.ToString());
return null;
}
return lobby;
}
//Join the lobby given a lobby code
public async Task<Lobby> JoinLobbyByCode(DemonData demonData, string lobbyCode)
2022-12-07 12:13:57 +02:00
{
2023-02-02 02:10:38 +02:00
Lobby lobby;
2023-02-12 03:29:03 +02:00
Unity.Services.Lobbies.Models.Player player = null;
try
{
player = GetPlayer(demonData);
}
catch (System.Exception e)
{
_onlineErrorMenu.Show(e.Message);
return null;
}
2022-12-07 12:13:57 +02:00
JoinLobbyByCodeOptions joinLobbyByCodeOptions = new JoinLobbyByCodeOptions
{
Player = GetPlayer(demonData)
};
2023-02-02 02:10:38 +02:00
try
{
lobby = await Lobbies.Instance.JoinLobbyByCodeAsync(lobbyCode, joinLobbyByCodeOptions);
2023-02-02 02:10:38 +02:00
_clientLobby = lobby;
}
catch (LobbyServiceException e)
{
_onlineErrorMenu.Show(e.Reason.ToString());
return null;
}
2022-12-08 03:28:59 +02:00
return lobby;
2022-12-07 12:13:57 +02:00
}
2023-01-15 01:54:52 +02:00
//Update when a player is ready
2022-12-08 14:35:27 +02:00
public async void UpdateLobbyReady(bool ready, bool isHost)
{
string lobbyId;
string playerId;
if (isHost)
{
lobbyId = _hostLobby.Id;
playerId = _hostLobby.Players[0].Id;
}
else
{
lobbyId = _clientLobby.Id;
playerId = _clientLobby.Players[1].Id;
}
UpdateLobbyOptions updateLobbyOptions = new UpdateLobbyOptions();
await LobbyService.Instance.UpdatePlayerAsync(lobbyId, AuthenticationService.Instance.PlayerId, new UpdatePlayerOptions
{
Data = new Dictionary<string, PlayerDataObject>{
{ "Ready", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, ready.ToString())}
}
});
}
2023-01-15 01:54:52 +02:00
//Delete lobby as a host
2022-12-09 17:21:06 +02:00
public async Task DeleteLobby()
2022-12-07 12:13:57 +02:00
{
2022-12-08 17:39:21 +02:00
string id = _hostLobby.Id;
_hostLobby = null;
2022-12-09 17:21:06 +02:00
await LobbyService.Instance.DeleteLobbyAsync(id);
2022-12-07 12:13:57 +02:00
}
2023-01-15 01:54:52 +02:00
//Leave lobby as a client
2022-12-09 17:44:02 +02:00
public async Task LeaveLobby()
2022-12-07 12:13:57 +02:00
{
await LobbyService.Instance.RemovePlayerAsync(_clientLobby.Id, AuthenticationService.Instance.PlayerId);
}
2023-01-15 01:54:52 +02:00
void Update()
{
HandleLobbyPollForUpdates();
}
//Poll for updates, because there is a certain limit given by Unity, we have to wait before we check for an update
2022-12-07 12:13:57 +02:00
private async void HandleLobbyPollForUpdates()
{
2022-12-08 17:39:21 +02:00
if (_hostLobby != null)
2022-12-07 12:13:57 +02:00
{
_lobbyUpdateTimer -= Time.unscaledDeltaTime;
if (_lobbyUpdateTimer < 0)
{
_lobbyUpdateTimer = 1.1f;
2023-02-13 21:47:46 +02:00
Lobby lobby = await LobbyService.Instance.GetLobbyAsync(_hostLobby.Id);
_hostLobby = lobby;
OnLobbyUpdate?.Invoke();
2022-12-08 14:35:27 +02:00
}
}
else if (_clientLobby != null)
{
_lobbyUpdateTimer -= Time.unscaledDeltaTime;
if (_lobbyUpdateTimer < 0)
{
_lobbyUpdateTimer = 1.1f;
Lobby lobby = await LobbyService.Instance.GetLobbyAsync(_clientLobby.Id);
_clientLobby = lobby;
OnLobbyUpdate?.Invoke();
2022-12-07 12:13:57 +02:00
}
}
}
2023-01-15 01:54:52 +02:00
//Get the Player data required for the lobby and P2P connection
2022-12-07 12:13:57 +02:00
private Unity.Services.Lobbies.Models.Player GetPlayer(DemonData demonData)
{
2023-02-22 15:36:55 +02:00
string address = "";
string port = "";
2023-02-12 03:29:03 +02:00
try
{
PublicIp(out address, out port);
}
catch (Exception)
{
throw;
}
2022-12-07 12:13:57 +02:00
return new Unity.Services.Lobbies.Models.Player
{
Data = new Dictionary<string, PlayerDataObject>{
{ "DemonName", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, demonData.demonName)},
{ "Character", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, demonData.character.ToString())},
{ "Assist", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, demonData.assist.ToString())},
{ "Color", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, demonData.color.ToString())},
2022-12-08 14:35:27 +02:00
{ "Ready", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, "False")},
2023-01-30 15:36:37 +02:00
{ "Ip", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, address)},
{ "Port", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public,port)},
{ "PrivateIp", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Public, PrivateIp())},
2022-12-07 12:13:57 +02:00
}
};
}
2023-01-15 01:54:52 +02:00
//Use DNS to get the private Ip, this is done for LAN P2P connections
2023-01-01 12:50:59 +02:00
private string PrivateIp()
2022-12-07 12:13:57 +02:00
{
var host = Dns.GetHostEntry(Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
2023-01-01 12:50:59 +02:00
return "127.0.0.1";
}
2023-01-15 01:54:52 +02:00
//Use a STUN server for port forwarding, this is done for WAN P2P connections
2023-01-01 12:50:59 +02:00
private void PublicIp(out string address, out string port)
{
2023-02-12 03:29:03 +02:00
if (!STUNUtils.TryParseHostAndPort("stun1.l.google.com:19302", out IPEndPoint stunEndPoint))
throw new Exception("Failed to establish connection");
2023-01-01 12:50:59 +02:00
STUNClient.ReceiveTimeout = 500;
var queryResult = STUNClient.Query(stunEndPoint, STUNQueryType.ExactNAT, true, NATTypeDetectionRFC.Rfc3489);
if (queryResult.QueryError != STUNQueryError.Success)
2023-02-12 03:29:03 +02:00
throw new Exception("Connection Failed");
2023-02-11 23:18:02 +02:00
2023-01-01 12:50:59 +02:00
address = queryResult.PublicEndPoint.Address.ToString();
port = queryResult.PublicEndPoint.Port.ToString();
2022-12-07 12:13:57 +02:00
}
2022-12-03 20:40:43 +02:00
}