You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

373 lines
12 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEngine.Networking;
  6. using Networking.Server;
  7. using Networking;
  8. using UnityEngine.SceneManagement;
  9. public class GameManager : MonoBehaviour
  10. {
  11. #region Inspector Field
  12. [Header("Settings")]
  13. [SerializeField]
  14. private float AnimationTime;
  15. [SerializeField]
  16. private GameModeReference CurrentGameMode;
  17. [Header("References")]
  18. [SerializeField]
  19. [Tooltip("Prefab of character for players to play")]
  20. private Character characterPrefab;
  21. [SerializeField]
  22. private ServerObject server;
  23. [SerializeField]
  24. private ClientList ClientList;
  25. public blockSpawn spawnBlock;
  26. #endregion Inspector Field
  27. #region Private Variables
  28. public Dictionary<int, PlayerData> playerData;
  29. private ActiveBlock[] EnvironmentBlocks;
  30. #endregion Private Variables
  31. #region Read Only
  32. /// <summary>
  33. /// Easy access to IEnumerable in playerData so we can Enumerate through it
  34. /// </summary>
  35. private PlayerData[] playerDataAsArray { get { return playerData.Values.ToArray(); } }
  36. /// <summary>
  37. /// Easy access to GameMode value in CurrentGameMode reference
  38. /// </summary>
  39. private GameMode gameMode { get { return CurrentGameMode.Value; } }
  40. #endregion Read Only
  41. #region Unity Functions
  42. private void Start()
  43. {
  44. spawnBlock = gameObject.GetComponent<blockSpawn>();
  45. StartCoroutine(GameRoutine());
  46. }
  47. private void Update()
  48. {
  49. server.ServerUpdate();
  50. }
  51. private void OnEnable()
  52. {
  53. //Let Server know we want to recieve some messages
  54. RegisterHandlers();
  55. }
  56. private void OnDisable()
  57. {
  58. //Let server know to not send messages this way
  59. UnRegisterHandlers();
  60. }
  61. #endregion Unity Functions
  62. #region Class Functions
  63. private IEnumerator GameRoutine()
  64. {
  65. //Allows game mode to instantiate anything it might need;
  66. gameMode.PreGameStart();
  67. //Spawn Characters and tell let the GameMode do anything with the characters it might want
  68. SpawnCharacters();
  69. playerDataAsArray.ForEach(p => p.client.SendLives());
  70. gameMode.GameStart(playerDataAsArray);
  71. playerData = playerData.OrderBy(unit => unit.Value.character.CurrentBlock.transform.position.x).ToDictionary(unit => unit.Key, unit => unit.Value);
  72. Dictionary<int, PlayerData> filteredPlayers = playerData.Where(p => !p.Value.isDead).ToDictionary(unit => unit.Key, unit => unit.Value);
  73. int order = 1;
  74. foreach (PlayerData data in filteredPlayers.Values)
  75. {
  76. data.character.runOrder = order;
  77. order++;
  78. }
  79. //Loop until the GameMode lets us know the game is over
  80. while (!gameMode.isGameOver(playerDataAsArray))
  81. {
  82. int playersalive_left = 0;
  83. int spotinarray = 0;
  84. int players = 0;
  85. foreach (PlayerData data in playerDataAsArray)
  86. {
  87. players++;
  88. if (data.client.Lives > 0)
  89. {
  90. playersalive_left++;
  91. spotinarray = players;
  92. }
  93. }
  94. if(playersalive_left == 1)
  95. {
  96. GlobalVariables.winneranimal = playerDataAsArray[spotinarray-1].client.characterAnimal;
  97. GlobalVariables.winnername = playerDataAsArray[spotinarray-1].client.Name;
  98. SceneManager.LoadScene("Winner");
  99. }
  100. //wait until we have recieved all player input
  101. yield return StartCoroutine(WaitForPlayerInput());
  102. //I hate having to do this
  103. EnvironmentBlocks = FindObjectsOfType<ActiveBlock>();
  104. //Routine for players movement
  105. yield return StartCoroutine(RoundRoutine()); //it's pretty long so it gets it's own coroutine;
  106. }
  107. //Let the gamemode know that the game is over
  108. gameMode.GameEnd(playerDataAsArray);
  109. }
  110. private void removePlayer(PlayerData player)
  111. {
  112. player.client.ChangeScene("WaitScene");
  113. player.isDead = true;
  114. }
  115. private IEnumerator RoundRoutine()
  116. {
  117. //Tell the gamemode that we are starting a round
  118. gameMode.RoundStart(playerDataAsArray);
  119. //Loop until all players have finished moving
  120. while (playerDataAsArray.Any(p => !p.blockReader.Finished))
  121. {
  122. //Loop through all players
  123. foreach (PlayerData player in playerDataAsArray)
  124. {
  125. yield return StartCoroutine(MoveRoutine(player));//Move Player
  126. gameMode.PlayerMoved(player);//LetGameModeKnow
  127. }
  128. //Let Gamemode know all players have moved
  129. gameMode.AllPlayersMoved(playerDataAsArray);
  130. //I hate having to do this
  131. EnvironmentBlocks = FindObjectsOfType<ActiveBlock>();
  132. //Let the environment take a turn
  133. yield return StartCoroutine(EnvironmentTurn());
  134. gameMode.EnvironmentTurn(playerDataAsArray);
  135. //if Game is over break out of loop
  136. if (gameMode.isGameOver(playerDataAsArray))
  137. break;
  138. }
  139. //decrease lives here!!
  140. foreach (PlayerData player in playerDataAsArray)
  141. {
  142. gameMode.PlayerKilled(player);
  143. }
  144. //Let GameMode know that Round is Over
  145. yield return StartCoroutine(EnvironmentEnd());
  146. gameMode.RoundEnd(playerDataAsArray.ToArray());
  147. playerDataAsArray.ForEach(p => p.client.SendLives()); //Update the players score
  148. //check is anyone has 0 lives remaining
  149. //remove them from the array
  150. //force them back to the waiting for players screen
  151. foreach (PlayerData player in playerDataAsArray)
  152. {
  153. if (player.client.Lives == 0)
  154. {
  155. removePlayer(player);
  156. }
  157. }
  158. //spawn collectible logic blocks
  159. spawnBlock.Spawn();
  160. //Reset some player Data
  161. foreach (PlayerData player in playerDataAsArray)
  162. {
  163. if (player.client.Lives > 0)
  164. {
  165. player.blockReader.Reset();
  166. player.client.SendInventory();
  167. }
  168. }
  169. playerData = playerData.OrderBy(unit => unit.Value.character.CurrentBlock.transform.position.x).ToDictionary(unit => unit.Key, unit => unit.Value);
  170. Dictionary<int,PlayerData> filteredPlayers = playerData.Where(p => !p.Value.isDead).ToDictionary(unit => unit.Key, unit => unit.Value);
  171. int order = 1;
  172. foreach (PlayerData data in filteredPlayers.Values)
  173. {
  174. data.character.runOrder = order;
  175. order++;
  176. }
  177. }
  178. private IEnumerator WaitForPlayerInput()
  179. {
  180. //send round length to players
  181. //#TODO make this only happen after first input
  182. LogicProtocols.FloatMsg RoundTime = new LogicProtocols.FloatMsg(gameMode.GetRoundTime());
  183. foreach (PlayerData player in playerDataAsArray)
  184. {
  185. if (player.client.Lives == 0)
  186. {
  187. removePlayer(player);
  188. }
  189. }
  190. //playerDataAsArray.ForEach(p => p.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime));
  191. foreach (PlayerData player in playerDataAsArray)
  192. {
  193. if (player.client.Lives > 0)
  194. {
  195. player.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime);
  196. }
  197. }
  198. //Send players to input Scene
  199. //ClientList.ForEach(p => p.ChangeScene("ClientScene"));
  200. foreach (ClientData client in ClientList)
  201. {
  202. if (client.Lives > 0) { client.ChangeScene("ClientScene"); }
  203. }
  204. //Let gamemode know clients are input-ing
  205. gameMode.InputStart(playerDataAsArray);
  206. //wait for all players to
  207. yield return new WaitUntil(() => playerData.All(p => p.Value.recievedList || p.Value.isDead || p.Value.character.lives == 0));
  208. //reset
  209. //playerDataAsArray.ForEach(p => p.recievedList = false); //reset all players list
  210. foreach (PlayerData player in playerDataAsArray)
  211. {
  212. if (player.client.Lives > 0) { player.recievedList = false; }
  213. }
  214. //Let gamemode know all inputs have been recieved
  215. gameMode.InputEnd(playerDataAsArray);
  216. }
  217. private IEnumerator MoveRoutine(PlayerData data)
  218. {
  219. //If the current block hasn't already been removed, remove it from the player inventory
  220. //We need to check if it has already been removed so loops don't eat an entire stack
  221. if (data.blockReader.CurrentBlock != null && !data.blockReader.CurrentBlock.hasBeenRemoved)
  222. {
  223. data.client.Inventory.Remove(data.blockReader.CurrentBlock);
  224. data.blockReader.CurrentBlock.hasBeenRemoved = true;
  225. }
  226. yield return StartCoroutine(data.blockReader.Read(data.character, AnimationTime));
  227. }
  228. private void SpawnCharacters()
  229. {
  230. playerData = new Dictionary<int, PlayerData>();
  231. Block[] SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isSpawnable).ToArray();
  232. //int spawnIndex = 0;
  233. //If we have an odd number of players, then we start at spawn point 0 (in the middle)
  234. //If we have an even number, then we skip it
  235. //int spawnIndex = ((ClientList.Count() + 1) % 2);
  236. int spawnIndex = 0;
  237. foreach (ClientData client in ClientList)
  238. {
  239. Character newChar = Instantiate(characterPrefab);
  240. Block startingBlock = SpawnBlocks[spawnIndex++];
  241. newChar.Initialise(startingBlock, client.Inventory, client.characterAnimal);
  242. newChar.transform.forward = startingBlock.SpawnDirection.ToVector();
  243. playerData.Add(client.ID, new PlayerData(newChar, client));
  244. newChar.ClientLink = client;
  245. client.playerCharacter = newChar;
  246. }
  247. }
  248. private IEnumerator EnvironmentTurn()
  249. {
  250. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  251. foreach (ActiveBlock block in InitiativeGroup)
  252. StartCoroutine(block.OnEnvironmentTurn(playerDataAsArray));
  253. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  254. InitiativeGroup.ForEach(p => p.Reset());
  255. }
  256. }
  257. private IEnumerator EnvironmentEnd()
  258. {
  259. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  260. foreach (ActiveBlock block in InitiativeGroup)
  261. StartCoroutine(block.OnRoundEnd(playerDataAsArray));
  262. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  263. InitiativeGroup.ForEach(p => p.Reset());
  264. }
  265. }
  266. private ActiveBlock[] GetActiveBlocksOf(int intiative)
  267. {
  268. return EnvironmentBlocks.Where(p => p.GetInitative() == intiative).ToArray();
  269. }
  270. #endregion Class Functions
  271. #region Networking Functions
  272. /// <summary>
  273. /// Registers functions which should deal with incoming messages from clients
  274. /// </summary>
  275. private void RegisterHandlers()
  276. {
  277. server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList);
  278. }
  279. /// <summary>
  280. /// Clears any functions from server register which the manager would deal with
  281. /// </summary>
  282. private void UnRegisterHandlers()
  283. {
  284. server.UnregisterHandler(LogicProtocols.SendLogicList);
  285. }
  286. /// <summary>
  287. /// Called when server recieves moves from client
  288. /// </summary>
  289. /// <param name="msg">messages passed by server</param>
  290. private void RecieveLogicList(NetworkMessage msg)
  291. {
  292. //try to read base message as a logic message
  293. LogicProtocols.LogicMsg logicMsg;
  294. if (!msg.TryRead(out logicMsg))
  295. return;
  296. //Update player Data with recieved list
  297. playerData[msg.conn.Hash()].blockReader.LogicChain = new List<LogicBlock>(logicMsg.elements);
  298. playerData[msg.conn.Hash()].recievedList = true;
  299. }
  300. #endregion Networking Functions
  301. }
  302. public class PlayerData
  303. {
  304. public Character character;
  305. public BlockReader blockReader;
  306. public ClientData client;
  307. public bool recievedList;
  308. public bool isDead = false;
  309. public PlayerData(Character character, ClientData client)
  310. {
  311. this.character = character;
  312. this.client = client;
  313. blockReader = new BlockReader();
  314. }
  315. }