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.

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