using System; using System.Linq; using System.Collections.Generic; using UnityEngine; using Mirror; namespace BetterTee.Server { public class ServerMainController : MonoBehaviour { [Header("Status")] public string lobbyPassword = null; public Dictionary players; public Dictionary viewers; public GamePhase phase = GamePhase.UNINTIALIZED; public GameSettings gameSettings = null; public int? currentActNumber = null; public ActSettings CurrentActSettings { get { if(gameSettings == null) return null; if(currentActNumber == null) return null; return gameSettings.acts[currentActNumber.Value - 1]; } } [Header("Constants")] public const int MAX_CONNECTIONS = 32; #region Unity Methods protected void Start() { ServerStart(); } protected void OnDestroy() { if(NetworkServer.active) NetworkServer.Shutdown(); } #endregion public void ServerStart() { LogFilter.Debug = true; phase = GamePhase.LOBBY; players = new Dictionary(); viewers = new Dictionary(); Transport.activeTransport = GetComponent(); #region Client Messages NetworkServer.RegisterHandler(OnPlayerJoin); NetworkServer.RegisterHandler(OnActResults); #endregion #region Viewer Messages NetworkServer.RegisterHandler(OnGameSettings); NetworkServer.RegisterHandler(OnViewerLink); NetworkServer.RegisterHandler(OnGameStart); #endregion #region Other Messages NetworkServer.RegisterHandler(OnConnect); NetworkServer.RegisterHandler(OnDisconnect); #endregion NetworkServer.Listen(MAX_CONNECTIONS); } public void SendLobbyUpdate() { SendToAllRegistered(new NetMsg.Server.LobbyStatusChange { players = players.Values.ToList().ConvertAll(player => player.Data).ToArray(), viewers = viewers.Values.ToList().ConvertAll(viewer => viewer.Data).ToArray() }); } public void GameStart() { phase = GamePhase.ACTS; currentActNumber = 1; } public void ActInit() { SendToAllRegistered(new NetMsg.Server.ActInit { settings = CurrentActSettings }); } #region SendToAll Methods public void SendToAllPlayers(T message, int channelId = 0) where T: IMessageBase { foreach(NetworkConnection connection in players.Keys) { connection.Send(message, channelId); } } public void SendToAllViewers(T message, int channelId = 0) where T: IMessageBase { foreach(NetworkConnection connection in viewers.Keys) { connection.Send(message, channelId); } } public void SendToAllRegistered(T message, int channelId = 0) where T: IMessageBase { SendToAllPlayers(message, channelId); SendToAllViewers(message, channelId); } #endregion #region Network Events protected void OnConnect(NetworkConnection connection, ConnectMessage message) { //Kick out clients that don't identify in 5 seconds? } protected void OnDisconnect(NetworkConnection connection, DisconnectMessage message) { //How to handle disconnections? try { players.Remove(connection); } catch(KeyNotFoundException) {} try { viewers.Remove(connection); } catch(KeyNotFoundException) {} SendLobbyUpdate(); } protected void OnPlayerJoin(NetworkConnection connection, NetMsg.Client.PlayerJoin message) { if(message.gamePassword != lobbyPassword) { connection.Send(new NetMsg.Server.Error.InvalidPassword()); connection.Disconnect(); return; } if(phase != GamePhase.LOBBY) { connection.Send(new NetMsg.Server.Error.GameAlreadyStarted()); connection.Disconnect(); return; } if(players.Count >= gameSettings.maximumPlayers) { connection.Send(new NetMsg.Server.Error.MaxPlayersCapReached()); connection.Disconnect(); return; } ConnectedPlayer newPlayer = new ConnectedPlayer { name = message.playerName, id = players.Count }; players.Add(connection, newPlayer); Debug.LogFormat("Player {0} joined the game", message.playerName); SendLobbyUpdate(); } protected void OnActResults(NetworkConnection connection, NetMsg.Client.ActResultsMsg message) { //Where should we put act results? } protected void OnGameSettings(NetworkConnection connection, NetMsg.Viewer.Settings message) { Debug.LogFormat("Received GameSettings from {0}", viewers[connection].name); gameSettings = message.settings; } protected void OnViewerLink(NetworkConnection connection, NetMsg.Viewer.ViewerLink message) { if(message.gamePassword != lobbyPassword) { connection.Send(new NetMsg.Server.Error.InvalidPassword()); connection.Disconnect(); return; } ConnectedViewer newViewer = new ConnectedViewer { name = message.viewerName, id = viewers.Count }; viewers.Add(connection, newViewer); Debug.LogFormat("Viewer {0} is now linked to the game", message.viewerName); SendLobbyUpdate(); } protected void OnGameStart(NetworkConnection connection, NetMsg.Viewer.GameStart message) { if(gameSettings == null) { connection.Send(new NetMsg.Server.Error.NoSettings()); connection.Disconnect(); return; } if(players.Count < gameSettings.minimumPlayers) { connection.Send(new NetMsg.Server.Error.NotEnoughPlayers()); connection.Disconnect(); return; } GameStart(); } #endregion } }