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.

376 lines
13 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 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. Dictionary<int,PlayerData> sortedPlayers = filteredPlayers.OrderBy(p => p.Value.character.CurrentBlock.transform.position.x).ToDictionary(unit => unit.Key, unit => unit.Value);
  172. int order = 1;
  173. foreach (PlayerData data in sortedPlayers.Values)
  174. {
  175. data.character.runOrder = order;
  176. order++;
  177. }
  178. playerData = playerData.OrderBy(p => p.Value.character.runOrder).ToDictionary(p => p.Key, p => p.Value);
  179. }
  180. private IEnumerator WaitForPlayerInput()
  181. {
  182. //send round length to players
  183. //#TODO make this only happen after first input
  184. LogicProtocols.FloatMsg RoundTime = new LogicProtocols.FloatMsg(gameMode.GetRoundTime());
  185. foreach (PlayerData player in playerDataAsArray)
  186. {
  187. if (player.client.Lives == 0)
  188. {
  189. removePlayer(player);
  190. }
  191. }
  192. //playerDataAsArray.ForEach(p => p.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime));
  193. foreach (PlayerData player in playerDataAsArray)
  194. {
  195. if (player.client.Lives > 0)
  196. {
  197. player.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime);
  198. }
  199. }
  200. //Send players to input Scene
  201. //ClientList.ForEach(p => p.ChangeScene("ClientScene"));
  202. foreach (ClientData client in ClientList)
  203. {
  204. if (client.Lives > 0) { client.ChangeScene("ClientScene"); }
  205. }
  206. //Let gamemode know clients are input-ing
  207. gameMode.InputStart(playerDataAsArray);
  208. //wait for all players to
  209. yield return new WaitUntil(() => playerData.All(p => p.Value.recievedList || p.Value.isDead || p.Value.character.lives == 0));
  210. //reset
  211. //playerDataAsArray.ForEach(p => p.recievedList = false); //reset all players list
  212. foreach (PlayerData player in playerDataAsArray)
  213. {
  214. if (player.client.Lives > 0) { player.recievedList = false; }
  215. }
  216. //Let gamemode know all inputs have been recieved
  217. gameMode.InputEnd(playerDataAsArray);
  218. }
  219. private IEnumerator MoveRoutine(PlayerData data)
  220. {
  221. //If the current block hasn't already been removed, remove it from the player inventory
  222. //We need to check if it has already been removed so loops don't eat an entire stack
  223. if (data.blockReader.CurrentBlock != null && !data.blockReader.CurrentBlock.hasBeenRemoved)
  224. {
  225. data.client.Inventory.Remove(data.blockReader.CurrentBlock);
  226. data.blockReader.CurrentBlock.hasBeenRemoved = true;
  227. }
  228. yield return StartCoroutine(data.blockReader.Read(data.character, AnimationTime));
  229. }
  230. private void SpawnCharacters()
  231. {
  232. playerData = new Dictionary<int, PlayerData>();
  233. Block[] SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isSpawnable).ToArray();
  234. //int spawnIndex = 0;
  235. //If we have an odd number of players, then we start at spawn point 0 (in the middle)
  236. //If we have an even number, then we skip it
  237. //int spawnIndex = ((ClientList.Count() + 1) % 2);
  238. int spawnIndex = 0;
  239. foreach (ClientData client in ClientList)
  240. {
  241. Character newChar = Instantiate(characterPrefab);
  242. Block startingBlock = SpawnBlocks[spawnIndex++];
  243. newChar.Initialise(startingBlock, client.Inventory, client.characterAnimal);
  244. newChar.transform.forward = startingBlock.SpawnDirection.ToVector();
  245. playerData.Add(client.ID, new PlayerData(newChar, client));
  246. newChar.ClientLink = client;
  247. client.playerCharacter = newChar;
  248. }
  249. }
  250. private IEnumerator EnvironmentTurn()
  251. {
  252. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  253. foreach (ActiveBlock block in InitiativeGroup)
  254. StartCoroutine(block.OnEnvironmentTurn(playerDataAsArray));
  255. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  256. InitiativeGroup.ForEach(p => p.Reset());
  257. }
  258. }
  259. private IEnumerator EnvironmentEnd()
  260. {
  261. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  262. foreach (ActiveBlock block in InitiativeGroup)
  263. StartCoroutine(block.OnRoundEnd(playerDataAsArray));
  264. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  265. InitiativeGroup.ForEach(p => p.Reset());
  266. }
  267. }
  268. private ActiveBlock[] GetActiveBlocksOf(int intiative)
  269. {
  270. return EnvironmentBlocks.Where(p => p.GetInitative() == intiative).ToArray();
  271. }
  272. #endregion Class Functions
  273. #region Networking Functions
  274. /// <summary>
  275. /// Registers functions which should deal with incoming messages from clients
  276. /// </summary>
  277. private void RegisterHandlers()
  278. {
  279. server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList);
  280. }
  281. /// <summary>
  282. /// Clears any functions from server register which the manager would deal with
  283. /// </summary>
  284. private void UnRegisterHandlers()
  285. {
  286. server.UnregisterHandler(LogicProtocols.SendLogicList);
  287. }
  288. /// <summary>
  289. /// Called when server recieves moves from client
  290. /// </summary>
  291. /// <param name="msg">messages passed by server</param>
  292. private void RecieveLogicList(NetworkMessage msg)
  293. {
  294. //try to read base message as a logic message
  295. LogicProtocols.LogicMsg logicMsg;
  296. if (!msg.TryRead(out logicMsg))
  297. return;
  298. //Update player Data with recieved list
  299. playerData[msg.conn.Hash()].blockReader.LogicChain = new List<LogicBlock>(logicMsg.elements);
  300. playerData[msg.conn.Hash()].recievedList = true;
  301. }
  302. #endregion Networking Functions
  303. }
  304. public class PlayerData
  305. {
  306. public Character character;
  307. public BlockReader blockReader;
  308. public ClientData client;
  309. public bool recievedList;
  310. public bool isDead = false;
  311. public PlayerData(Character character, ClientData client)
  312. {
  313. this.character = character;
  314. this.client = client;
  315. blockReader = new BlockReader();
  316. }
  317. }