KitchenChaos/Assets/Scripts/KitchenGameLobby.cs

214 lines
6.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Unity.Netcode;
using Unity.Netcode.Transports.UTP;
using Unity.Services.Authentication;
using Unity.Services.Core;
using Unity.Services.Lobbies;
using Unity.Services.Lobbies.Models;
using Unity.Services.Relay;
using Unity.Services.Relay.Models;
using UnityEngine;
using UnityEngine.SceneManagement;
using Random = UnityEngine.Random;
public class KitchenGameLobby : MonoBehaviour {
public Lobby JoinedLobby { get; private set; }
public static KitchenGameLobby Instance { get; private set; }
private float heartbeatTimer;
private const float heartbeatTimerMax = 15f;
public event EventHandler OnCreateLobbyStarted;
public event EventHandler OnCreateLobbyFailed;
public event EventHandler OnJoinStarted;
public event EventHandler OnQuickJoinFailed;
public event EventHandler OnJoinFailed;
public event EventHandler<LobbyListChangedEventArgs> OnLobbyListChanged;
public class LobbyListChangedEventArgs : EventArgs {
public List<Lobby> LobbyList;
}
private void Awake() {
Instance = this;
DontDestroyOnLoad(gameObject);
InitializeUnityAuthentitcation();
}
private void Update() {
HandleHeartbeat();
HandlePeriodicListLobbies();
}
private float listLobbiesTimer;
private const float listLobbiesTimerMax = 3f;
private void HandlePeriodicListLobbies() {
if (JoinedLobby == null && AuthenticationService.Instance.IsSignedIn && SceneManager.GetActiveScene().name == Loader.Scene.LobbyScene.ToString()) {
listLobbiesTimer -= Time.deltaTime;
if (listLobbiesTimer <= 0f) {
listLobbiesTimer = listLobbiesTimerMax;
ListLobbies();
}
}
}
private void HandleHeartbeat() {
if (IsLobbyHost()) {
heartbeatTimer -= Time.deltaTime;
if (heartbeatTimer <= 0f) {
heartbeatTimer = heartbeatTimerMax;
LobbyService.Instance.SendHeartbeatPingAsync(JoinedLobby.Id);
}
}
}
private bool IsLobbyHost() => JoinedLobby != null && JoinedLobby.HostId == AuthenticationService.Instance.PlayerId;
private async void ListLobbies() {
try {
QueryLobbiesOptions queryLobbiesOptions = new() { Filters = new() { new(QueryFilter.FieldOptions.AvailableSlots, "0", QueryFilter.OpOptions.GT) } };
QueryResponse queryResponse = await LobbyService.Instance.QueryLobbiesAsync(queryLobbiesOptions);
OnLobbyListChanged?.Invoke(this, new() { LobbyList = queryResponse.Results });
}
catch (LobbyServiceException e) {
Debug.Log(e);
}
}
private async void InitializeUnityAuthentitcation() {
if (UnityServices.State != ServicesInitializationState.Initialized) await UnityServices.InitializeAsync();
InitializationOptions initializationOptions = new();
// initializationOptions.SetProfile(Random.Range(0, 10000).ToString());
await AuthenticationService.Instance.SignInAnonymouslyAsync();
}
private const string keyRelayJoinCode = "RelayJoinCode";
public async void CreateLobby(string lobbyName, bool isPrivate) {
OnCreateLobbyStarted?.Invoke(this, EventArgs.Empty);
try {
JoinedLobby = await LobbyService.Instance.CreateLobbyAsync(lobbyName, KitchenGameMultiplayer.MaxPlayerAmount, new() { IsPrivate = isPrivate });
Allocation allocation = await AllocateRelay();
NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new(allocation, "dtls"));
string relayJoinCode = await GetRelayJoinCode(allocation);
await LobbyService.Instance.UpdateLobbyAsync(JoinedLobby.Id, new() { Data = new() { { keyRelayJoinCode, new(DataObject.VisibilityOptions.Member, relayJoinCode) } } });
KitchenGameMultiplayer.Instance.StartHost();
Loader.LoadNetwork(Loader.Scene.CharacterSelectScene);
}
catch (LobbyServiceException e) {
Debug.Log(e);
OnCreateLobbyFailed?.Invoke(this, EventArgs.Empty);
}
}
private async Task<Allocation> AllocateRelay() {
try {
return await RelayService.Instance.CreateAllocationAsync(KitchenGameMultiplayer.MaxPlayerAmount - 1);
}
catch (RelayServiceException e) {
Debug.Log(e);
return default;
}
}
private async Task<string> GetRelayJoinCode(Allocation allocation) {
try {
return await RelayService.Instance.GetJoinCodeAsync(allocation.AllocationId);
}
catch (RelayServiceException e) {
Debug.Log(e);
return default;
}
}
private async Task<JoinAllocation> JoinRelay(string joinCode) {
try {
return await RelayService.Instance.JoinAllocationAsync(joinCode);
}
catch (RelayServiceException e) {
Debug.Log(e);
return default;
}
}
public async void QuickJoin() {
OnJoinStarted?.Invoke(this, EventArgs.Empty);
try {
JoinedLobby = await LobbyService.Instance.QuickJoinLobbyAsync();
JoinAllocation joinAllocation = await JoinRelay(JoinedLobby.Data[keyRelayJoinCode].Value);
NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new(joinAllocation, "dtls"));
KitchenGameMultiplayer.Instance.StartClient();
}
catch (LobbyServiceException e) {
Debug.Log(e);
OnQuickJoinFailed?.Invoke(this, EventArgs.Empty);
}
}
public async void DeleteLobby() {
if (JoinedLobby != null) {
try {
await LobbyService.Instance.DeleteLobbyAsync(JoinedLobby.Id);
JoinedLobby = null;
}
catch (LobbyServiceException e) {
Debug.Log(e);
}
}
}
public async void LeaveLobby() {
if (JoinedLobby != null) {
try {
await LobbyService.Instance.RemovePlayerAsync(JoinedLobby.Id, AuthenticationService.Instance.PlayerId);
JoinedLobby = null;
}
catch (LobbyServiceException e) {
Debug.Log(e);
}
}
}
public async void KickPlayer(string playerId) {
if (IsLobbyHost()) {
try {
await LobbyService.Instance.RemovePlayerAsync(JoinedLobby.Id, playerId);
}
catch (LobbyServiceException e) {
Debug.Log(e);
}
}
}
public async void JoinWithCode(string lobbyCode) {
OnJoinStarted?.Invoke(this, EventArgs.Empty);
try {
JoinedLobby = await LobbyService.Instance.JoinLobbyByCodeAsync(lobbyCode);
JoinAllocation joinAllocation = await JoinRelay(JoinedLobby.Data[keyRelayJoinCode].Value);
NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new(joinAllocation, "dtls"));
KitchenGameMultiplayer.Instance.StartClient();
}
catch (LobbyServiceException e) {
Debug.Log(e);
OnJoinFailed?.Invoke(this, EventArgs.Empty);
}
}
public async void JoinWithId(string lobbyId) {
OnJoinStarted?.Invoke(this, EventArgs.Empty);
try {
JoinedLobby = await LobbyService.Instance.JoinLobbyByIdAsync(lobbyId);
JoinAllocation joinAllocation = await JoinRelay(JoinedLobby.Data[keyRelayJoinCode].Value);
NetworkManager.Singleton.GetComponent<UnityTransport>().SetRelayServerData(new(joinAllocation, "dtls"));
KitchenGameMultiplayer.Instance.StartClient();
}
catch (LobbyServiceException e) {
Debug.Log(e);
OnJoinFailed?.Invoke(this, EventArgs.Empty);
}
}
}