using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Networking; using Networking.Server; using Networking; using UnityEngine.SceneManagement; public class GameManager : MonoBehaviour { #region Inspector Field [Header("Settings")] [SerializeField] private float AnimationTime; [SerializeField] private GameModeReference CurrentGameMode; [Header("References")] [SerializeField] [Tooltip("Prefab of character for players to play")] private Character characterPrefab; [SerializeField] private ServerObject server; [SerializeField] private ClientList ClientList; #endregion Inspector Field #region Private Variables private Dictionary playerData; #endregion Private Variables #region Read Only /// /// Easy access to IEnumerable in playerData so we can Enumerate through it /// private IEnumerable playerDataAsArray { get { return playerData.Values; } } /// /// Easy access to GameMode value in CurrentGameMode reference /// private GameMode gameMode {get { return CurrentGameMode.Value; } } #endregion Read Only public GameObject levelInfo; public blockSpawn bspawn; #region Unity Functions public void Awake() { RegisterHandlers(); SpawnCharacters(); ClientList.ForEach(p => p.ChangeScene("ClientScene")); } private void Start() { StartCoroutine(displayforSeconds(levelInfo, 5.0f)); gameMode.GameStart(playerDataAsArray.ToArray()); StartRound(); } private void Update() { //This is required so that the server can continue to recieve client messages //(it is a unity thing) server.ServerUpdate(); } private void OnDisable() { //Let server know to not send messages this way UnRegisterHandlers(); } #endregion Unity Functions IEnumerator displayforSeconds(GameObject display, float time) { display.SetActive (true); yield return new WaitForSeconds(time); display.SetActive (false); } private void DoRoundRoutine() { Debug.Log("Starting Round"); StartCoroutine(RoundRoutine()); } private void StartRound() { gameMode.RoundStart(playerDataAsArray.ToArray()); LogicProtocols.FloatMsg RoundTime = new LogicProtocols.FloatMsg( gameMode.GetRoundTime()); bspawn.Spawn(); playerDataAsArray.ForEach(p => p.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime)); } private IEnumerator RoundRoutine() { playerDataAsArray.ForEach(p => p.recievedList = false); //Debug.Log("Doing Round Routine"); while (playerDataAsArray.Any(p => !p.blockReader.Finished)) { //Debug.Log("One Move"); foreach (PlayerData player in playerDataAsArray) { Debug.Log(player.client.Name); StartCoroutine(RunOnce(player)); yield return new WaitUntil(() => player.waiting); } //wait until all players have finished //yield return new WaitUntil(() => playerArray.All(p => p.waiting)); gameMode.FinishedMove(playerDataAsArray.ToArray()); playerDataAsArray.ForEach(p => p.client.SendScore()); } if (gameMode.isGameOver(playerDataAsArray.ToArray())) { Debug.Log("Game Over"); SceneManager.LoadScene("ScoreBoards"); } gameMode.RoundEnd(playerDataAsArray.ToArray()); foreach (PlayerData player in playerDataAsArray) { player.blockReader.Reset(); player.waiting = false; player.client.SendInventory(); player.client.ChangeScene("ClientScene"); } //Debug.Log("Finished Moving"); StartRound(); } private void SpawnCharacters() { playerData = new Dictionary(); Block[] SpawnBlocks = FindObjectsOfType().Where(p => p.isSpawnable).ToArray(); int spawnIndex = 0; foreach (ClientData client in ClientList) { Character newChar = Instantiate(characterPrefab); Block startingBlock = SpawnBlocks[(spawnIndex++ % ClientList.ConnectedClients.Count)]; newChar.Initialise(startingBlock, client.Inventory, client.characterAnimal); newChar.transform.forward = startingBlock.SpawnDirection.ToVector(); playerData.Add(client.ID, new PlayerData(newChar,client)); newChar.ClientLink = client; client.playerCharacter = newChar; } } #region Networking Functions /// /// Registers functions which should deal with incoming messages from clients /// private void RegisterHandlers() { server.server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList); } /// /// Clears any functions from server register which the manager would deal with /// private void UnRegisterHandlers() { server.server.UnregisterHandler(LogicProtocols.SendLogicList); } /// /// Called when server recieves moves from client /// /// messages passed by server private void RecieveLogicList(NetworkMessage msg) { //try to read base message as a logic message LogicProtocols.LogicMsg logicMsg; if (!msg.TryRead(out logicMsg)) return; //Debug that we have recieved it Debug.Log("Recieved function from " + ClientList[msg.conn.connectionId].Name); //Update player Data with recieved list playerData[msg.conn.connectionId].blockReader.LogicChain = new List(logicMsg.elements); playerData[msg.conn.connectionId].recievedList = true; //if we have recieved all moves start round if (playerData.All(p => p.Value.recievedList)) DoRoundRoutine(); } #endregion Networking Functions private IEnumerator RunOnce(PlayerData data) { data.waiting = false; bool blockFinished = false; float waitTime; while (!blockFinished && !data.blockReader.Finished) { //Debug.Log(data.client + "Moving once"); if (data.blockReader.CurrentBlock != null && !data.blockReader.CurrentBlock.hasBeenRemoved) { data.client.Inventory.Remove(data.blockReader.CurrentBlock); data.blockReader.CurrentBlock.hasBeenRemoved = true; } blockFinished = data.blockReader.Read(data.character, AnimationTime,out waitTime); //Debug.Log("Waiting: " + waitTime); yield return new WaitForSeconds(waitTime); gameMode.OnePlayerMoved(data); } data.waiting = true; } } public class PlayerData { public Character character; public BlockReader blockReader; public ClientData client; public bool recievedList; public bool waiting; public PlayerData(Character character, ClientData client) { this.character = character; this.client = client; blockReader = new BlockReader(); } }