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.

364 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. //Loop until the GameMode lets us know the game is over
  72. while (!gameMode.isGameOver(playerDataAsArray))
  73. {
  74. int playersalive_left = 0;
  75. int spotinarray = 0;
  76. int players = 0;
  77. foreach (PlayerData data in playerDataAsArray)
  78. {
  79. players++;
  80. if (data.client.Lives > 0)
  81. {
  82. playersalive_left++;
  83. spotinarray = players;
  84. }
  85. }
  86. if(playersalive_left == 1)
  87. {
  88. GlobalVariables.winneranimal = playerDataAsArray[spotinarray-1].client.characterAnimal;
  89. GlobalVariables.winnername = playerDataAsArray[spotinarray-1].client.Name;
  90. SceneManager.LoadScene("Winner");
  91. }
  92. //wait until we have recieved all player input
  93. yield return StartCoroutine(WaitForPlayerInput());
  94. //I hate having to do this
  95. EnvironmentBlocks = FindObjectsOfType<ActiveBlock>();
  96. //Routine for players movement
  97. yield return StartCoroutine(RoundRoutine()); //it's pretty long so it gets it's own coroutine;
  98. }
  99. //Let the gamemode know that the game is over
  100. gameMode.GameEnd(playerDataAsArray);
  101. }
  102. private void removePlayer(PlayerData player)
  103. {
  104. player.client.ChangeScene("WaitScene");
  105. player.isDead = true;
  106. }
  107. private IEnumerator RoundRoutine()
  108. {
  109. //Tell the gamemode that we are starting a round
  110. gameMode.RoundStart(playerDataAsArray);
  111. //Loop until all players have finished moving
  112. while (playerDataAsArray.Any(p => !p.blockReader.Finished))
  113. {
  114. //Loop through all players
  115. foreach (PlayerData player in playerDataAsArray)
  116. {
  117. yield return StartCoroutine(MoveRoutine(player));//Move Player
  118. gameMode.PlayerMoved(player);//LetGameModeKnow
  119. }
  120. //Let Gamemode know all players have moved
  121. gameMode.AllPlayersMoved(playerDataAsArray);
  122. //I hate having to do this
  123. EnvironmentBlocks = FindObjectsOfType<ActiveBlock>();
  124. //Let the environment take a turn
  125. yield return StartCoroutine(EnvironmentTurn());
  126. gameMode.EnvironmentTurn(playerDataAsArray);
  127. //if Game is over break out of loop
  128. if (gameMode.isGameOver(playerDataAsArray))
  129. break;
  130. }
  131. //decrease lives here!!
  132. foreach (PlayerData player in playerDataAsArray)
  133. {
  134. gameMode.PlayerKilled(player);
  135. }
  136. //Let GameMode know that Round is Over
  137. yield return StartCoroutine(EnvironmentEnd());
  138. gameMode.RoundEnd(playerDataAsArray.ToArray());
  139. playerDataAsArray.ForEach(p => p.client.SendLives()); //Update the players score
  140. //check is anyone has 0 lives remaining
  141. //remove them from the array
  142. //force them back to the waiting for players screen
  143. foreach (PlayerData player in playerDataAsArray)
  144. {
  145. if (player.client.Lives == 0)
  146. {
  147. removePlayer(player);
  148. }
  149. }
  150. //spawn collectible logic blocks
  151. spawnBlock.Spawn();
  152. //Reset some player Data
  153. foreach (PlayerData player in playerDataAsArray)
  154. {
  155. if (player.client.Lives > 0)
  156. {
  157. player.blockReader.Reset();
  158. player.client.SendInventory();
  159. }
  160. }
  161. playerData = playerData.OrderBy(unit => unit.Value.character.CurrentBlock.transform.position.x).ToDictionary(unit => unit.Key, unit => unit.Value);
  162. //Dictionary<int,PlayerData> filteredPlayers = playerData.Where(p => !p.Value.isDead).ToDictionary(unit => unit.Key, unit => unit.Value);
  163. int order = 1;
  164. foreach (PlayerData data in playerDataAsArray)
  165. {
  166. data.character.runOrder = order;
  167. order++;
  168. }
  169. }
  170. private IEnumerator WaitForPlayerInput()
  171. {
  172. //send round length to players
  173. //#TODO make this only happen after first input
  174. LogicProtocols.FloatMsg RoundTime = new LogicProtocols.FloatMsg(gameMode.GetRoundTime());
  175. foreach (PlayerData player in playerDataAsArray)
  176. {
  177. if (player.client.Lives == 0)
  178. {
  179. removePlayer(player);
  180. }
  181. }
  182. //playerDataAsArray.ForEach(p => p.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime));
  183. foreach (PlayerData player in playerDataAsArray)
  184. {
  185. if (player.client.Lives > 0)
  186. {
  187. player.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime);
  188. }
  189. }
  190. //Send players to input Scene
  191. //ClientList.ForEach(p => p.ChangeScene("ClientScene"));
  192. foreach (ClientData client in ClientList)
  193. {
  194. if (client.Lives > 0) { client.ChangeScene("ClientScene"); }
  195. }
  196. //Let gamemode know clients are input-ing
  197. gameMode.InputStart(playerDataAsArray);
  198. //wait for all players to
  199. yield return new WaitUntil(() => playerData.All(p => p.Value.recievedList || p.Value.isDead || p.Value.character.lives == 0));
  200. //reset
  201. //playerDataAsArray.ForEach(p => p.recievedList = false); //reset all players list
  202. foreach (PlayerData player in playerDataAsArray)
  203. {
  204. if (player.client.Lives > 0) { player.recievedList = false; }
  205. }
  206. //Let gamemode know all inputs have been recieved
  207. gameMode.InputEnd(playerDataAsArray);
  208. }
  209. private IEnumerator MoveRoutine(PlayerData data)
  210. {
  211. //If the current block hasn't already been removed, remove it from the player inventory
  212. //We need to check if it has already been removed so loops don't eat an entire stack
  213. if (data.blockReader.CurrentBlock != null && !data.blockReader.CurrentBlock.hasBeenRemoved)
  214. {
  215. data.client.Inventory.Remove(data.blockReader.CurrentBlock);
  216. data.blockReader.CurrentBlock.hasBeenRemoved = true;
  217. }
  218. yield return StartCoroutine(data.blockReader.Read(data.character, AnimationTime));
  219. }
  220. private void SpawnCharacters()
  221. {
  222. playerData = new Dictionary<int, PlayerData>();
  223. Block[] SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isSpawnable).ToArray();
  224. //int spawnIndex = 0;
  225. //If we have an odd number of players, then we start at spawn point 0 (in the middle)
  226. //If we have an even number, then we skip it
  227. //int spawnIndex = ((ClientList.Count() + 1) % 2);
  228. int spawnIndex = 0;
  229. foreach (ClientData client in ClientList)
  230. {
  231. Character newChar = Instantiate(characterPrefab);
  232. Block startingBlock = SpawnBlocks[spawnIndex++];
  233. newChar.Initialise(startingBlock, client.Inventory, client.characterAnimal);
  234. newChar.transform.forward = startingBlock.SpawnDirection.ToVector();
  235. playerData.Add(client.ID, new PlayerData(newChar, client));
  236. newChar.ClientLink = client;
  237. client.playerCharacter = newChar;
  238. }
  239. }
  240. private IEnumerator EnvironmentTurn()
  241. {
  242. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  243. foreach (ActiveBlock block in InitiativeGroup)
  244. StartCoroutine(block.OnEnvironmentTurn(playerDataAsArray));
  245. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  246. InitiativeGroup.ForEach(p => p.Reset());
  247. }
  248. }
  249. private IEnumerator EnvironmentEnd()
  250. {
  251. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  252. foreach (ActiveBlock block in InitiativeGroup)
  253. StartCoroutine(block.OnRoundEnd(playerDataAsArray));
  254. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  255. InitiativeGroup.ForEach(p => p.Reset());
  256. }
  257. }
  258. private ActiveBlock[] GetActiveBlocksOf(int intiative)
  259. {
  260. return EnvironmentBlocks.Where(p => p.GetInitative() == intiative).ToArray();
  261. }
  262. #endregion Class Functions
  263. #region Networking Functions
  264. /// <summary>
  265. /// Registers functions which should deal with incoming messages from clients
  266. /// </summary>
  267. private void RegisterHandlers()
  268. {
  269. server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList);
  270. }
  271. /// <summary>
  272. /// Clears any functions from server register which the manager would deal with
  273. /// </summary>
  274. private void UnRegisterHandlers()
  275. {
  276. server.UnregisterHandler(LogicProtocols.SendLogicList);
  277. }
  278. /// <summary>
  279. /// Called when server recieves moves from client
  280. /// </summary>
  281. /// <param name="msg">messages passed by server</param>
  282. private void RecieveLogicList(NetworkMessage msg)
  283. {
  284. //try to read base message as a logic message
  285. LogicProtocols.LogicMsg logicMsg;
  286. if (!msg.TryRead(out logicMsg))
  287. return;
  288. //Update player Data with recieved list
  289. playerData[msg.conn.Hash()].blockReader.LogicChain = new List<LogicBlock>(logicMsg.elements);
  290. playerData[msg.conn.Hash()].recievedList = true;
  291. }
  292. #endregion Networking Functions
  293. }
  294. public class PlayerData
  295. {
  296. public Character character;
  297. public BlockReader blockReader;
  298. public ClientData client;
  299. public bool recievedList;
  300. public bool isDead = false;
  301. public PlayerData(Character character, ClientData client)
  302. {
  303. this.character = character;
  304. this.client = client;
  305. blockReader = new BlockReader();
  306. }
  307. }