You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
515 lines
18 KiB
C#
515 lines
18 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using Unity.Services.Authentication;
|
|
using Unity.Services.Lobbies;
|
|
using Unity.Services.Lobbies.Models;
|
|
using Unity.Services.Relay;
|
|
using UnityEngine;
|
|
|
|
namespace LobbyScripts
|
|
{
|
|
public class GameLobby : MonoBehaviour
|
|
{
|
|
[SerializeField] private float _lobbyRefreshTime;
|
|
|
|
private float _heartBeatTimer;
|
|
|
|
private float _lobbyPollTimer;
|
|
|
|
public static event Action<GameLobby, Lobby> OnLobbyCreated;
|
|
public static event Action<GameLobby, Lobby> OnLobbyChanged;
|
|
public static event Action<GameLobby, Lobby> OnBasicLobbyChanged;
|
|
public static event Action<GameLobby, Lobby> OnLobbyFailedToJoin;
|
|
public static event Action<GameLobby, Lobby> OnLobbyLeaved;
|
|
public static event Action<GameLobby, Lobby> OnHostLeftLobby;
|
|
public static event Action<GameLobby, Lobby> OnLobbyFailedToLeave;
|
|
|
|
public static event Action<Lobby> OnWaitingForPLayers;
|
|
|
|
public static event Action OnRelayStarted;
|
|
public static event Action OnWaitingToJoinRelay;
|
|
public static event Action OnRelayCompleted;
|
|
public static event Action OnRelayFailed;
|
|
|
|
public static event Action OnUpdateLobby;
|
|
public static event Action OnLobbyUpdated;
|
|
public static event Action OnUpdateLobbyFailed;
|
|
|
|
public static event Action OnGameStarted;
|
|
|
|
private string _playerId;
|
|
private bool _lobbyFound = true;
|
|
private bool _gameIsStarted;
|
|
private bool _gameJoined;
|
|
private bool _isLeavingLobby;
|
|
private bool _leavingLobbyFailed;
|
|
private bool _hostHasLeftLobby;
|
|
|
|
public string LobbyCode { private set; get;}
|
|
public Lobby LobbyInstance { set; get; }
|
|
public static GameLobby GameLobbyInstance { private set; get;}
|
|
public bool IsCreatedThroughRelay { set; get; }
|
|
|
|
[SerializeField] private LoginSessions _loginSessionManager;
|
|
|
|
private void Awake()
|
|
{
|
|
if (GameLobbyInstance != null && GameLobbyInstance != this)
|
|
{
|
|
Destroy(GameLobbyInstance);
|
|
return;
|
|
}
|
|
GameLobbyInstance = this;
|
|
}
|
|
private void OnEnable()
|
|
{
|
|
LobbyUI.DoHostLobby += CreateLobbyInstance;
|
|
LobbyUI.DoJoinPrivateLobbyByCode += JoinLobbyThroughCode;
|
|
LobbyUI.DoJoinPrivateLobbyByID += JoinLobbyThroughID;
|
|
LobbyUI.DoStartTheGame += StartGame;
|
|
LobbyUI.DoLeaveLobby += LeaveLobby;
|
|
}
|
|
private void OnDisable()
|
|
{
|
|
LobbyUI.DoHostLobby -= CreateLobbyInstance;
|
|
LobbyUI.DoJoinPrivateLobbyByCode -= JoinLobbyThroughCode;
|
|
LobbyUI.DoJoinPrivateLobbyByID -= JoinLobbyThroughID;
|
|
LobbyUI.DoStartTheGame -= StartGame;
|
|
LobbyUI.DoLeaveLobby -= LeaveLobby;
|
|
}
|
|
|
|
|
|
private void Update()
|
|
{
|
|
HandleLobbyHeartBeat();
|
|
HandleLobbyPolling();
|
|
}
|
|
private async void HandleLobbyHeartBeat()
|
|
{
|
|
if(LobbyInstance == null) return;
|
|
if(!IsLobbyHost()) return;
|
|
_heartBeatTimer -= Time.deltaTime;
|
|
if (!(_heartBeatTimer < 0)) return;
|
|
_heartBeatTimer = _lobbyRefreshTime;
|
|
await LobbyService.Instance.SendHeartbeatPingAsync(LobbyInstance.Id);
|
|
}
|
|
private async void HandleLobbyPolling()
|
|
{
|
|
if (LobbyInstance == null) return;
|
|
|
|
if(_hostHasLeftLobby) return;
|
|
|
|
if(_isLeavingLobby) return;
|
|
|
|
_lobbyPollTimer -= Time.deltaTime;
|
|
if (!(_lobbyPollTimer < 0f)) return;
|
|
var lobbyPollTimerMax = 1.1f;
|
|
_lobbyPollTimer = lobbyPollTimerMax;
|
|
|
|
try
|
|
{
|
|
var lobby = await LobbyService.Instance.GetLobbyAsync(LobbyInstance.Id);
|
|
LobbyInstance = lobby;
|
|
}
|
|
catch (LobbyServiceException e)
|
|
{
|
|
if(e.Reason == LobbyExceptionReason.Forbidden)
|
|
{
|
|
LobbyInstance = null;
|
|
if(!IsCreatedThroughRelay)
|
|
OnLobbyLeaved?.Invoke(this, null);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (await CheckIfHostHasLeft()) return;
|
|
|
|
if (CheckIfPlayerIsKicked()) return;
|
|
|
|
if (IsCreatedThroughRelay)
|
|
{
|
|
OnBasicLobbyChanged?.Invoke(this, LobbyInstance);
|
|
return;
|
|
}
|
|
|
|
await CheckWhetherGameHasStarted();
|
|
}
|
|
private async Task CheckWhetherGameHasStarted()
|
|
{
|
|
if (!_gameIsStarted)
|
|
OnLobbyChanged?.Invoke(this, LobbyInstance);
|
|
|
|
if (LobbyInstance.Data["START_GAME"].Value == "0") return;
|
|
|
|
if (!IsLobbyHost() && !_gameJoined)
|
|
{
|
|
Debug.Log("LC: "+ LobbyInstance.Data["START_GAME"].Value);
|
|
OnWaitingToJoinRelay?.Invoke();
|
|
await GameRelay.Instance.JoinRelay(LobbyInstance.Data["START_GAME"].Value);
|
|
OnRelayCompleted?.Invoke();
|
|
_gameJoined = true;
|
|
Debug.Log("End of if");
|
|
}
|
|
|
|
OnWaitingForPLayers?.Invoke(LobbyInstance);
|
|
Debug.Log("OnWaitingForPLayers");
|
|
|
|
// if (LobbyInstance.Data["PLAYER_COUNT"].Value != LobbyInstance.Players.Count.ToString()) return;
|
|
// Debug.Log("PLAYER_COUNT");
|
|
|
|
OnGameStarted?.Invoke();
|
|
Debug.Log("OnGameStarted");
|
|
// GameManager.Ins.isHost = IsLobbyHost();
|
|
LobbyInstance = null;
|
|
Debug.Log("LobbyInstance");
|
|
}
|
|
private async Task<bool> CheckIfHostHasLeft()
|
|
{
|
|
if (LobbyInstance.Data["HOST_LIFE"].Value == "Dead")
|
|
{
|
|
if (LobbyInstance.Players.Count == 0)
|
|
{
|
|
await Lobbies.Instance.DeleteLobbyAsync(LobbyInstance.Id);
|
|
}
|
|
|
|
LeaveLobby();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
private bool CheckIfPlayerIsKicked()
|
|
{
|
|
var currentPlayer = AuthenticationService.Instance.PlayerId;
|
|
if (LobbyInstance.Data["PLAYER_TO_KICK"].Value != currentPlayer) return false;
|
|
OnLobbyLeaved?.Invoke(this, LobbyInstance);
|
|
LobbyInstance = null;
|
|
return true;
|
|
|
|
}
|
|
public bool IsLobbyHost() =>
|
|
LobbyInstance != null && LobbyInstance.HostId == AuthenticationService.Instance.PlayerId;
|
|
|
|
private Player GetPlayer() => new() {
|
|
Data = new Dictionary<string, PlayerDataObject>
|
|
{
|
|
{ "PlayerName", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Member, "BRO") }
|
|
}
|
|
};
|
|
|
|
// private Player GetPlayer2() => new() {
|
|
// Data = new Dictionary<string, PlayerDataObject>
|
|
// {
|
|
// { "PlayerName", new PlayerDataObject(PlayerDataObject.VisibilityOptions.Member, $"SecondPlayer") }
|
|
// }
|
|
// };
|
|
|
|
public async void CreateLobbyInstance(LobbyData lobbyData, bool shouldUpdateUI) =>
|
|
await CreateLobby(lobbyData, shouldUpdateUI);
|
|
public async Task CreateLobby(LobbyData lobbyData, bool shouldUpdateUI)
|
|
{
|
|
await _loginSessionManager.LoginUnityServices();
|
|
try
|
|
{
|
|
var player = GetPlayer();
|
|
bool shouldUpdateLobbyName = String.IsNullOrWhiteSpace(lobbyData.LobbyName);
|
|
|
|
var options = new CreateLobbyOptions {
|
|
Player = player,
|
|
IsPrivate = lobbyData.IsPrivate,
|
|
Data = new Dictionary<string, DataObject> {
|
|
{"LOBBY_NAME", new DataObject(DataObject.VisibilityOptions.Member,shouldUpdateLobbyName?"GameLobby":lobbyData.LobbyName)},
|
|
{"START_GAME", new DataObject(DataObject.VisibilityOptions.Member, "0")},
|
|
{"PLAYER_COUNT", new DataObject(DataObject.VisibilityOptions.Member, "0")},
|
|
{"HOST_LIFE", new DataObject(DataObject.VisibilityOptions.Member, "Alive")},
|
|
{"PLAYER_TO_KICK", new DataObject(DataObject.VisibilityOptions.Member, "None")},
|
|
{"HOST_ROOM_DATA", new DataObject(DataObject.VisibilityOptions.Member,"ROOM1")}
|
|
}
|
|
};
|
|
var lobby = await LobbyService.Instance.CreateLobbyAsync(lobbyData.LobbyName, lobbyData.MaxPlayers, options);
|
|
//Updating lobby name to lobby code that was generated after the creation of the lobby
|
|
|
|
if (shouldUpdateLobbyName)
|
|
UpdateLobbyNameToLobbyCode();
|
|
LobbyCode = lobby.LobbyCode;
|
|
|
|
|
|
|
|
/*
|
|
if (GameVivoxManager.Instance.ChannelSession?.Parent.State != LoginState.LoggedIn)
|
|
{
|
|
GameVivoxManager.Instance.Login(player.Data["PlayerName"].Value);
|
|
GameVivoxManager.Instance.ChannelName = lobby.Data["LOBBY_NAME"].Value;
|
|
}*/
|
|
|
|
Debug.Log(LobbyCode);
|
|
|
|
IsCreatedThroughRelay = !shouldUpdateUI;
|
|
|
|
LobbyInstance = lobby;
|
|
|
|
if (shouldUpdateUI)
|
|
{
|
|
OnLobbyCreated?.Invoke(this, lobby);
|
|
OnLobbyChanged?.Invoke(this, lobby);
|
|
}
|
|
|
|
Debug.Log("Created Lobby " + lobby.Name);
|
|
|
|
async void UpdateLobbyNameToLobbyCode()
|
|
{
|
|
try {
|
|
var updatedLobby = await Lobbies.Instance.UpdateLobbyAsync(lobby.Id, new UpdateLobbyOptions
|
|
{
|
|
Name = lobby.LobbyCode
|
|
});
|
|
lobby = updatedLobby;
|
|
}
|
|
catch (Exception e) {
|
|
Debug.Log($"Failed updating lobby: {e}");
|
|
}
|
|
}
|
|
}
|
|
catch (LobbyServiceException e)
|
|
{
|
|
Debug.Log(e);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
private async void JoinLobbyThroughID(string lobbyCode, bool shouldUpdateUI) =>
|
|
await JoinPrivateLobbyByID(lobbyCode, shouldUpdateUI);
|
|
|
|
public async Task JoinPrivateLobbyByID(string lobbyCode, bool shouldUpdateUI)
|
|
{
|
|
await _loginSessionManager.LoginUnityServices();
|
|
var player = GetPlayer();
|
|
|
|
try
|
|
{
|
|
LobbyInstance = await LobbyService.Instance.JoinLobbyByIdAsync(lobbyCode, new JoinLobbyByIdOptions()
|
|
{
|
|
Player = player
|
|
});
|
|
|
|
/*if (GameVivoxManager.Instance.ChannelSession?.Parent.State != LoginState.LoggedIn)
|
|
{
|
|
GameVivoxManager.Instance.Login(player.Data["PlayerName"].Value);
|
|
GameVivoxManager.Instance.ChannelName = LobbyInstance.Data["LOBBY_NAME"].Value;
|
|
}*/
|
|
|
|
IsCreatedThroughRelay = !shouldUpdateUI;
|
|
|
|
if (shouldUpdateUI)
|
|
{
|
|
OnLobbyChanged?.Invoke(this, LobbyInstance);
|
|
}
|
|
}
|
|
|
|
catch (LobbyServiceException e)
|
|
{
|
|
OnLobbyFailedToJoin?.Invoke(this, null);
|
|
Debug.Log(e);
|
|
}
|
|
}
|
|
|
|
private async void JoinLobbyThroughCode(string lobbyCode, bool shouldUpdateUI) =>
|
|
await JoinPrivateLobbyByCode(lobbyCode, shouldUpdateUI);
|
|
public async Task JoinPrivateLobbyByCode(string lobbyCode, bool shouldUpdateUI)
|
|
{
|
|
await _loginSessionManager.LoginUnityServices();
|
|
var player = GetPlayer();
|
|
|
|
try
|
|
{
|
|
LobbyInstance = await LobbyService.Instance.JoinLobbyByCodeAsync(lobbyCode, new JoinLobbyByCodeOptions()
|
|
{
|
|
Player = player
|
|
});
|
|
|
|
/*if (GameVivoxManager.Instance.ChannelSession?.Parent.State != LoginState.LoggedIn)
|
|
{
|
|
GameVivoxManager.Instance.Login(player.Data["PlayerName"].Value);
|
|
GameVivoxManager.Instance.ChannelName = LobbyInstance.Data["LOBBY_NAME"].Value;
|
|
}*/
|
|
|
|
IsCreatedThroughRelay = !shouldUpdateUI;
|
|
|
|
if (shouldUpdateUI)
|
|
{
|
|
OnLobbyChanged?.Invoke(this, LobbyInstance);
|
|
}
|
|
}
|
|
|
|
catch (LobbyServiceException e)
|
|
{
|
|
OnLobbyFailedToJoin?.Invoke(this, null);
|
|
Debug.Log(e);
|
|
}
|
|
}
|
|
public async void StartGame()
|
|
{
|
|
if(!IsLobbyHost()) return;
|
|
|
|
string relayCode = default;
|
|
|
|
try
|
|
{
|
|
_gameIsStarted = true;
|
|
OnRelayStarted?.Invoke();
|
|
|
|
relayCode = await GameRelay.Instance.CreateRelay(LobbyInstance.Players.Count);
|
|
|
|
OnRelayCompleted?.Invoke();
|
|
}
|
|
|
|
catch (RelayServiceException e)
|
|
{
|
|
_gameIsStarted = false;
|
|
OnRelayFailed?.Invoke();
|
|
Debug.Log(e);
|
|
}
|
|
|
|
try
|
|
{
|
|
OnUpdateLobby?.Invoke();
|
|
|
|
var lobby = await Lobbies.Instance.UpdateLobbyAsync(LobbyInstance.Id, new UpdateLobbyOptions
|
|
{
|
|
Data = new Dictionary<string, DataObject>
|
|
{
|
|
{"START_GAME", new DataObject(DataObject.VisibilityOptions.Member, relayCode)},
|
|
{"PLAYER_COUNT", new DataObject(DataObject.VisibilityOptions.Member, LobbyInstance.Players.Count.ToString())}
|
|
}
|
|
});
|
|
|
|
LobbyInstance = lobby;
|
|
|
|
OnLobbyUpdated?.Invoke();
|
|
}
|
|
|
|
catch (LobbyServiceException e)
|
|
{
|
|
_gameIsStarted = false;
|
|
OnUpdateLobbyFailed?.Invoke();
|
|
Console.WriteLine(e);
|
|
}
|
|
|
|
}
|
|
public async void LeaveLobby()
|
|
{
|
|
try
|
|
{
|
|
if (IsLobbyHost()) _hostHasLeftLobby = true;
|
|
_isLeavingLobby = true;
|
|
var playerId = AuthenticationService.Instance.PlayerId;
|
|
if (_hostHasLeftLobby)
|
|
{
|
|
OnHostLeftLobby?.Invoke(this, LobbyInstance);
|
|
var lobby = await Lobbies.Instance.UpdateLobbyAsync(LobbyInstance.Id, new UpdateLobbyOptions
|
|
{
|
|
Data = new Dictionary<string, DataObject>
|
|
{
|
|
{"HOST_LIFE", new DataObject(DataObject.VisibilityOptions.Member, "Dead")}
|
|
}
|
|
});
|
|
LobbyInstance = lobby;
|
|
}
|
|
else
|
|
{
|
|
OnLobbyLeaved?.Invoke(this, LobbyInstance);
|
|
}
|
|
|
|
await LobbyService.Instance.RemovePlayerAsync(LobbyInstance.Id, playerId);
|
|
/*
|
|
GameVivoxManager.Instance.LeaveChannel(GameVivoxManager.Instance.ChannelSession?.Channel);
|
|
VivoxUI.LogOutUser?.Invoke();
|
|
*/
|
|
|
|
LobbyInstance = null;
|
|
_hostHasLeftLobby = false;
|
|
_isLeavingLobby = false;
|
|
}
|
|
catch (LobbyServiceException e)
|
|
{
|
|
if (IsLobbyHost()) _hostHasLeftLobby = false;
|
|
_isLeavingLobby = false;
|
|
OnLobbyFailedToLeave?.Invoke(this , LobbyInstance);
|
|
Debug.Log(e);
|
|
}
|
|
}
|
|
public async void KickAPlayer(Player player)
|
|
{
|
|
try
|
|
{
|
|
var lobby = await LobbyService.Instance.UpdateLobbyAsync(LobbyInstance.Id, new UpdateLobbyOptions
|
|
{
|
|
Data = new Dictionary<string, DataObject>
|
|
{
|
|
{"PLAYER_TO_KICK", new DataObject(DataObject.VisibilityOptions.Member, $"{player.Id}")}
|
|
}
|
|
});
|
|
|
|
LobbyInstance = lobby;
|
|
}
|
|
catch (LobbyServiceException e)
|
|
{
|
|
Console.WriteLine(e);
|
|
throw;
|
|
}
|
|
|
|
try
|
|
{
|
|
await LobbyService.Instance.RemovePlayerAsync(LobbyInstance.Id, player.Id);
|
|
OnLobbyChanged?.Invoke(this, LobbyInstance);
|
|
}
|
|
catch (LobbyServiceException e)
|
|
{
|
|
Console.WriteLine(e);
|
|
throw;
|
|
}
|
|
|
|
try
|
|
{
|
|
var lobby = await LobbyService.Instance.UpdateLobbyAsync(LobbyInstance.Id, new UpdateLobbyOptions
|
|
{
|
|
Data = new Dictionary<string, DataObject>
|
|
{
|
|
{"PLAYER_TO_KICK", new DataObject(DataObject.VisibilityOptions.Member, $"None")}
|
|
}
|
|
});
|
|
|
|
LobbyInstance = lobby;
|
|
}
|
|
catch (LobbyServiceException e)
|
|
{
|
|
Console.WriteLine(e);
|
|
throw;
|
|
}
|
|
|
|
}
|
|
|
|
public async void DestroyLobby()
|
|
{
|
|
try
|
|
{
|
|
await LobbyService.Instance.DeleteLobbyAsync(LobbyInstance.Id);
|
|
}
|
|
catch (LobbyServiceException e)
|
|
{
|
|
Debug.Log(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
public struct LobbyData
|
|
{
|
|
public string LobbyName;
|
|
public int MaxPlayers;
|
|
public bool IsPrivate;
|
|
}
|
|
} |