|
|
- 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;
-
- public blockSpawn spawnBlock;
-
- #endregion Inspector Field
-
- #region Private Variables
- public Dictionary<int, PlayerData> playerData;
- private ActiveBlock[] EnvironmentBlocks;
- #endregion Private Variables
-
- #region Read Only
- /// <summary>
- /// Easy access to IEnumerable in playerData so we can Enumerate through it
- /// </summary>
- private PlayerData[] playerDataAsArray { get { return playerData.Values.ToArray(); } }
-
- /// <summary>
- /// Easy access to GameMode value in CurrentGameMode reference
- /// </summary>
- private GameMode gameMode { get { return CurrentGameMode.Value; } }
- #endregion Read Only
-
- #region Unity Functions
-
- private void Start()
- {
- spawnBlock = gameObject.GetComponent<blockSpawn>();
-
- //Start Game
- StartCoroutine(GameRoutine());
- }
-
- 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 OnEnable()
- {
- //Let Server know we want to recieve some messages
- RegisterHandlers();
- }
-
- private void OnDisable()
- {
- //Let server know to not send messages this way
- UnRegisterHandlers();
- }
- #endregion Unity Functions
-
- #region Class Functions
- private IEnumerator GameRoutine()
- {
-
- //Allows game mode to instantiate anything it might need;
- gameMode.PreGameStart();
-
- //gets list of items to check spawn locations
- //spawnBlock.wakeup();
-
- //Spawn Characters and tell let the GameMode do anything with the characters it might want
- SpawnCharacters();
- playerDataAsArray.ForEach(p => p.client.SendLives());
- gameMode.GameStart(playerDataAsArray);
-
- //Loop until the GameMode lets us know the game is over
- while (!gameMode.isGameOver(playerDataAsArray))
- {
- int playersalive_left = 0;
- int spotinarray = 0;
- int players = 0;
- //check here if one player left
- foreach(PlayerData data in playerDataAsArray)
- {
- players++;
- if (data.character.lives > 0)
- {
- playersalive_left++;
- spotinarray = players;
- }
- }
- /*if(playersalive_left == 1)
- {
- GlobalVariables.winneranimal = playerDataAsArray[spotinarray].client.characterAnimal;
- GlobalVariables.winnername = playerDataAsArray[spotinarray].client.Name;
- SceneManager.LoadScene("Winner");
- }*/
-
- //wait until we have recieved all player input
- yield return StartCoroutine(WaitForPlayerInput());
-
- //I hate having to do this
- EnvironmentBlocks = FindObjectsOfType<ActiveBlock>();
- ////Debug.Log("Active blocks found: " + EnvironmentBlocks.Length);
-
- //Routine for players movement
- yield return StartCoroutine(RoundRoutine()); //it's pretty long so it gets it's own coroutine;
- }
-
- //Let the gamemode know that the game is over
- gameMode.GameEnd(playerDataAsArray);
- }
-
- private void removePlayer(PlayerData player)
- {
- player.client.ChangeScene("WaitScene");
- player.isDead = true;
- }
-
- private IEnumerator RoundRoutine()
- {
- //Tell the gamemode that we are starting a round
- gameMode.RoundStart(playerDataAsArray);
-
-
-
- //Loop until all players have finished moving
- while (playerDataAsArray.Any(p => !p.blockReader.Finished))
- {
-
- //Loop through all players
- foreach (PlayerData player in playerDataAsArray)
- {
- yield return StartCoroutine(MoveRoutine(player));//Move Player
- gameMode.PlayerMoved(player);//LetGameModeKnow
- }
-
- //Let Gamemode know all players have moved
- gameMode.AllPlayersMoved(playerDataAsArray);
-
- //I hate having to do this
- EnvironmentBlocks = FindObjectsOfType<ActiveBlock>();
-
- //Let the environment take a turn
- yield return StartCoroutine(EnvironmentTurn());
- gameMode.EnvironmentTurn(playerDataAsArray);
-
- //if Game is over break out of loop
- if (gameMode.isGameOver(playerDataAsArray))
- break;
- }
- //decrease lives here!!
- foreach (PlayerData player in playerDataAsArray)
- {
- gameMode.PlayerKilled(player);
- }
-
-
-
- //Let GameMode know that Round is Over
- yield return StartCoroutine(EnvironmentEnd());
- gameMode.RoundEnd(playerDataAsArray.ToArray());
-
- playerDataAsArray.ForEach(p => p.client.SendLives()); //Update the players score
-
- //check is anyone has 0 lives remaining
- //remove them from the array
- //force them back to the waiting for players screen
- foreach (PlayerData player in playerDataAsArray)
- {
- if (player.client.Lives == 0)
- {
- //Debug.Log("Remove: " + player.client.characterAnimal);
- removePlayer(player);
- }
- }
- //spawn collectible logic blocks
- spawnBlock.Spawn();
-
-
- //Reset some player Data
- foreach (PlayerData player in playerDataAsArray)
- {
- if (player.client.Lives > 0)
- {
- player.blockReader.Reset();
- player.client.SendInventory();
- }
- }
-
- playerData = playerData.OrderBy(unit => unit.Value.character.CurrentBlock.transform.position.x).ToDictionary(unit => unit.Key, unit => unit.Value);
- Dictionary<int,PlayerData> filteredPlayers = playerData.Where(p => !p.Value.isDead).ToDictionary(unit => unit.Key, unit => unit.Value);
- int order = 1;
- foreach (PlayerData data in filteredPlayers.Values)
- {
- data.character.runOrder = order;
- order++;
- }
- }
-
- private IEnumerator WaitForPlayerInput()
- {
- //send round length to players
- //#TODO make this only happen after first input
- LogicProtocols.FloatMsg RoundTime = new LogicProtocols.FloatMsg(gameMode.GetRoundTime());
-
- foreach (PlayerData player in playerDataAsArray)
- {
- if (player.client.Lives == 0)
- {
- //Debug.Log("Remove: " + player.client.characterAnimal);
- removePlayer(player);
- }
- }
-
- //playerDataAsArray.ForEach(p => p.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime));
- foreach (PlayerData player in playerDataAsArray)
- {
- if (player.client.Lives > 0)
- {
- player.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime);
- }
- }
-
- //Send players to input Scene
- //ClientList.ForEach(p => p.ChangeScene("ClientScene"));
- foreach (ClientData client in ClientList)
- {
- if (client.Lives > 0) { client.ChangeScene("ClientScene"); }
- }
-
- //Let gamemode know clients are input-ing
- gameMode.InputStart(playerDataAsArray);
-
- //wait for all players to
- yield return new WaitUntil(() => playerData.All(p => p.Value.recievedList || p.Value.isDead || p.Value.character.lives == 0));
-
- //reset
- //playerDataAsArray.ForEach(p => p.recievedList = false); //reset all players list
- foreach (PlayerData player in playerDataAsArray)
- {
- if (player.client.Lives > 0) { player.recievedList = false; }
- }
-
- //Let gamemode know all inputs have been recieved
- gameMode.InputEnd(playerDataAsArray);
- }
-
- private IEnumerator MoveRoutine(PlayerData data)
- {
- //If the current block hasn't already been removed, remove it from the player inventory
- //We need to check if it has already been removed so loops don't eat an entire stack
- if (data.blockReader.CurrentBlock != null && !data.blockReader.CurrentBlock.hasBeenRemoved)
- {
- data.client.Inventory.Remove(data.blockReader.CurrentBlock);
- data.blockReader.CurrentBlock.hasBeenRemoved = true;
- }
-
- //Process the move
- //blockFinished = data.blockReader.Read(data.character, AnimationTime, out waitTime);
-
- //Wait for the animation to finish
- //yield return new WaitForSeconds(waitTime);
-
- yield return StartCoroutine(data.blockReader.Read(data.character, AnimationTime));
- }
-
- private void SpawnCharacters()
- {
- playerData = new Dictionary<int, PlayerData>();
- Block[] SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isSpawnable).ToArray();
-
- int blockIndex = 0;
- foreach (Block block in SpawnBlocks)
- {
- ////Debug.Log("Block #" + blockIndex++ + " (" + block.transform.position.x + ", " + block.transform.position.y + ", " + block.transform.position.z + ")");
- }
-
- //int spawnIndex = 0;
- //If we have an odd number of players, then we start at spawn point 0 (in the middle)
- //If we have an even number, then we skip it
- //int spawnIndex = ((ClientList.Count() + 1) % 2);
-
- int spawnIndex = 0;
-
- foreach (ClientData client in ClientList)
- {
- ////Debug.Log("spawnIndex = " + spawnIndex);
- Character newChar = Instantiate(characterPrefab);
- //Block startingBlock = SpawnBlocks[(spawnIndex++ % ClientList.ConnectedClients.Count)];
- Block startingBlock = SpawnBlocks[spawnIndex++];
- 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;
- }
- }
-
- private IEnumerator EnvironmentTurn()
- {
- foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
-
- foreach (ActiveBlock block in InitiativeGroup)
- StartCoroutine(block.OnEnvironmentTurn(playerDataAsArray));
-
- yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
- InitiativeGroup.ForEach(p => p.Reset());
- }
-
- }
-
- private IEnumerator EnvironmentEnd()
- {
- foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
-
- foreach (ActiveBlock block in InitiativeGroup)
- StartCoroutine(block.OnRoundEnd(playerDataAsArray));
-
- yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
- InitiativeGroup.ForEach(p => p.Reset());
- }
- }
-
- private ActiveBlock[] GetActiveBlocksOf(int intiative)
- {
- return EnvironmentBlocks.Where(p => p.GetInitative() == intiative).ToArray();
- }
- #endregion Class Functions
-
- #region Networking Functions
-
- /// <summary>
- /// Registers functions which should deal with incoming messages from clients
- /// </summary>
- private void RegisterHandlers()
- {
- server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList);
- }
-
- /// <summary>
- /// Clears any functions from server register which the manager would deal with
- /// </summary>
- private void UnRegisterHandlers()
- {
- server.UnregisterHandler(LogicProtocols.SendLogicList);
- }
-
- /// <summary>
- /// Called when server recieves moves from client
- /// </summary>
- /// <param name="msg">messages passed by server</param>
- 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.Hash()].blockReader.LogicChain = new List<LogicBlock>(logicMsg.elements);
- playerData[msg.conn.Hash()].recievedList = true;
- }
-
- #endregion Networking Functions
- }
-
- public class PlayerData
- {
- public Character character;
- public BlockReader blockReader;
- public ClientData client;
-
- public bool recievedList;
- public bool isDead = false;
-
- public PlayerData(Character character, ClientData client)
- {
- this.character = character;
- this.client = client;
- blockReader = new BlockReader();
- }
- }
|