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.

408 lines
13 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
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. //Start Game
  46. StartCoroutine(GameRoutine());
  47. }
  48. private void Update()
  49. {
  50. //This is required so that the server can continue to recieve client messages
  51. //(it is a unity thing)
  52. server.ServerUpdate();
  53. }
  54. private void OnEnable()
  55. {
  56. //Let Server know we want to recieve some messages
  57. RegisterHandlers();
  58. }
  59. private void OnDisable()
  60. {
  61. //Let server know to not send messages this way
  62. UnRegisterHandlers();
  63. }
  64. #endregion Unity Functions
  65. #region Class Functions
  66. private IEnumerator GameRoutine()
  67. {
  68. //Allows game mode to instantiate anything it might need;
  69. gameMode.PreGameStart();
  70. //gets list of items to check spawn locations
  71. spawnBlock.wakeup();
  72. //Spawn Characters and tell let the GameMode do anything with the characters it might want
  73. SpawnCharacters();
  74. playerDataAsArray.ForEach(p => p.client.SendLives());
  75. gameMode.GameStart(playerDataAsArray);
  76. //Loop until the GameMode lets us know the game is over
  77. while (!gameMode.isGameOver(playerDataAsArray))
  78. {
  79. int playersalive_left = 0;
  80. int spotinarray = 0;
  81. int players = 0;
  82. //check here if one player left
  83. foreach(PlayerData data in playerDataAsArray)
  84. {
  85. players++;
  86. if (data.character.lives > 0)
  87. {
  88. playersalive_left++;
  89. spotinarray = players;
  90. }
  91. }
  92. /*if(playersalive_left == 1)
  93. {
  94. GlobalVariables.winneranimal = playerDataAsArray[spotinarray].client.characterAnimal;
  95. GlobalVariables.winnername = playerDataAsArray[spotinarray].client.Name;
  96. SceneManager.LoadScene("Winner");
  97. }*/
  98. //wait until we have recieved all player input
  99. yield return StartCoroutine(WaitForPlayerInput());
  100. //I hate having to do this
  101. EnvironmentBlocks = FindObjectsOfType<ActiveBlock>();
  102. ////Debug.Log("Active blocks found: " + EnvironmentBlocks.Length);
  103. //Routine for players movement
  104. yield return StartCoroutine(RoundRoutine()); //it's pretty long so it gets it's own coroutine;
  105. }
  106. //Let the gamemode know that the game is over
  107. gameMode.GameEnd(playerDataAsArray);
  108. }
  109. private void removePlayer(PlayerData player)
  110. {
  111. player.client.ChangeScene("WaitScene");
  112. player.isDead = true;
  113. }
  114. private IEnumerator RoundRoutine()
  115. {
  116. //Tell the gamemode that we are starting a round
  117. gameMode.RoundStart(playerDataAsArray);
  118. //Loop until all players have finished moving
  119. while (playerDataAsArray.Any(p => !p.blockReader.Finished))
  120. {
  121. //Loop through all players
  122. foreach (PlayerData player in playerDataAsArray)
  123. {
  124. yield return StartCoroutine(MoveRoutine(player));//Move Player
  125. gameMode.PlayerMoved(player);//LetGameModeKnow
  126. }
  127. //Let Gamemode know all players have moved
  128. gameMode.AllPlayersMoved(playerDataAsArray);
  129. //I hate having to do this
  130. EnvironmentBlocks = FindObjectsOfType<ActiveBlock>();
  131. //Let the environment take a turn
  132. yield return StartCoroutine(EnvironmentTurn());
  133. gameMode.EnvironmentTurn(playerDataAsArray);
  134. //if Game is over break out of loop
  135. if (gameMode.isGameOver(playerDataAsArray))
  136. break;
  137. }
  138. //decrease lives here!!
  139. foreach (PlayerData player in playerDataAsArray)
  140. {
  141. gameMode.PlayerKilled(player);
  142. }
  143. playerDataAsArray.ForEach(p => p.client.SendLives()); //Update the players score
  144. //Let GameMode know that Round is Over
  145. yield return StartCoroutine(EnvironmentEnd());
  146. gameMode.RoundEnd(playerDataAsArray.ToArray());
  147. //check is anyone has 0 lives remaining
  148. //remove them from the array
  149. //force them back to the waiting for players screen
  150. foreach (PlayerData player in playerDataAsArray)
  151. {
  152. if (player.client.Lives == 0)
  153. {
  154. //Debug.Log("Remove: " + player.client.characterAnimal);
  155. removePlayer(player);
  156. }
  157. }
  158. //spawn collectible logic blocks
  159. Debug.Log("Spawwn script called from manager");
  160. spawnBlock.Spawn();
  161. //Reset some player Data
  162. foreach (PlayerData player in playerDataAsArray)
  163. {
  164. if (player.client.Lives > 0)
  165. {
  166. player.blockReader.Reset();
  167. player.client.SendInventory();
  168. }
  169. }
  170. playerData = playerData.OrderBy(unit => unit.Value.character.CurrentBlock.transform.position.x).ToDictionary(unit => unit.Key, unit => unit.Value);
  171. int order = 1;
  172. foreach (PlayerData data in playerDataAsArray)
  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. //Debug.Log("Remove: " + player.client.characterAnimal);
  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. //Process the move
  228. //blockFinished = data.blockReader.Read(data.character, AnimationTime, out waitTime);
  229. //Wait for the animation to finish
  230. //yield return new WaitForSeconds(waitTime);
  231. yield return StartCoroutine(data.blockReader.Read(data.character, AnimationTime));
  232. }
  233. private void SpawnCharacters()
  234. {
  235. playerData = new Dictionary<int, PlayerData>();
  236. Block[] SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isSpawnable).ToArray();
  237. int blockIndex = 0;
  238. foreach (Block block in SpawnBlocks)
  239. {
  240. ////Debug.Log("Block #" + blockIndex++ + " (" + block.transform.position.x + ", " + block.transform.position.y + ", " + block.transform.position.z + ")");
  241. }
  242. //int spawnIndex = 0;
  243. //If we have an odd number of players, then we start at spawn point 0 (in the middle)
  244. //If we have an even number, then we skip it
  245. //int spawnIndex = ((ClientList.Count() + 1) % 2);
  246. int spawnIndex = 0;
  247. foreach (ClientData client in ClientList)
  248. {
  249. ////Debug.Log("spawnIndex = " + spawnIndex);
  250. Character newChar = Instantiate(characterPrefab);
  251. //Block startingBlock = SpawnBlocks[(spawnIndex++ % ClientList.ConnectedClients.Count)];
  252. Block startingBlock = SpawnBlocks[spawnIndex++];
  253. newChar.Initialise(startingBlock, client.Inventory, client.characterAnimal);
  254. newChar.transform.forward = startingBlock.SpawnDirection.ToVector();
  255. playerData.Add(client.ID, new PlayerData(newChar, client));
  256. newChar.ClientLink = client;
  257. client.playerCharacter = newChar;
  258. }
  259. }
  260. private IEnumerator EnvironmentTurn()
  261. {
  262. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  263. foreach (ActiveBlock block in InitiativeGroup)
  264. StartCoroutine(block.OnEnvironmentTurn(playerDataAsArray));
  265. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  266. InitiativeGroup.ForEach(p => p.Reset());
  267. }
  268. }
  269. private IEnumerator EnvironmentEnd()
  270. {
  271. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  272. foreach (ActiveBlock block in InitiativeGroup)
  273. StartCoroutine(block.OnRoundEnd(playerDataAsArray));
  274. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  275. InitiativeGroup.ForEach(p => p.Reset());
  276. }
  277. }
  278. private ActiveBlock[] GetActiveBlocksOf(int intiative)
  279. {
  280. return EnvironmentBlocks.Where(p => p.GetInitative() == intiative).ToArray();
  281. }
  282. #endregion Class Functions
  283. #region Networking Functions
  284. /// <summary>
  285. /// Registers functions which should deal with incoming messages from clients
  286. /// </summary>
  287. private void RegisterHandlers()
  288. {
  289. server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList);
  290. }
  291. /// <summary>
  292. /// Clears any functions from server register which the manager would deal with
  293. /// </summary>
  294. private void UnRegisterHandlers()
  295. {
  296. server.UnregisterHandler(LogicProtocols.SendLogicList);
  297. }
  298. /// <summary>
  299. /// Called when server recieves moves from client
  300. /// </summary>
  301. /// <param name="msg">messages passed by server</param>
  302. private void RecieveLogicList(NetworkMessage msg)
  303. {
  304. //try to read base message as a logic message
  305. LogicProtocols.LogicMsg logicMsg;
  306. if (!msg.TryRead(out logicMsg))
  307. return;
  308. ////Debug that we have recieved it
  309. ////Debug.Log("Recieved function from " + ClientList[msg.conn.connectionId].Name);
  310. //Update player Data with recieved list
  311. playerData[msg.conn.Hash()].blockReader.LogicChain = new List<LogicBlock>(logicMsg.elements);
  312. playerData[msg.conn.Hash()].recievedList = true;
  313. }
  314. #endregion Networking Functions
  315. }
  316. public class PlayerData
  317. {
  318. public Character character;
  319. public BlockReader blockReader;
  320. public ClientData client;
  321. public bool recievedList;
  322. public bool isDead = false;
  323. public PlayerData(Character character, ClientData client)
  324. {
  325. this.character = character;
  326. this.client = client;
  327. blockReader = new BlockReader();
  328. }
  329. }