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.

407 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
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. //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. 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. int order = 1;
  171. foreach (PlayerData data in playerDataAsArray)
  172. {
  173. data.character.runOrder = order;
  174. order++;
  175. }
  176. }
  177. private IEnumerator WaitForPlayerInput()
  178. {
  179. //send round length to players
  180. //#TODO make this only happen after first input
  181. LogicProtocols.FloatMsg RoundTime = new LogicProtocols.FloatMsg(gameMode.GetRoundTime());
  182. foreach (PlayerData player in playerDataAsArray)
  183. {
  184. if (player.client.Lives == 0)
  185. {
  186. //Debug.Log("Remove: " + player.client.characterAnimal);
  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. //Process the move
  227. //blockFinished = data.blockReader.Read(data.character, AnimationTime, out waitTime);
  228. //Wait for the animation to finish
  229. //yield return new WaitForSeconds(waitTime);
  230. yield return StartCoroutine(data.blockReader.Read(data.character, AnimationTime));
  231. }
  232. private void SpawnCharacters()
  233. {
  234. playerData = new Dictionary<int, PlayerData>();
  235. Block[] SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isSpawnable).ToArray();
  236. int blockIndex = 0;
  237. foreach (Block block in SpawnBlocks)
  238. {
  239. ////Debug.Log("Block #" + blockIndex++ + " (" + block.transform.position.x + ", " + block.transform.position.y + ", " + block.transform.position.z + ")");
  240. }
  241. //int spawnIndex = 0;
  242. //If we have an odd number of players, then we start at spawn point 0 (in the middle)
  243. //If we have an even number, then we skip it
  244. //int spawnIndex = ((ClientList.Count() + 1) % 2);
  245. int spawnIndex = 0;
  246. foreach (ClientData client in ClientList)
  247. {
  248. ////Debug.Log("spawnIndex = " + spawnIndex);
  249. Character newChar = Instantiate(characterPrefab);
  250. //Block startingBlock = SpawnBlocks[(spawnIndex++ % ClientList.ConnectedClients.Count)];
  251. Block startingBlock = SpawnBlocks[spawnIndex++];
  252. newChar.Initialise(startingBlock, client.Inventory, client.characterAnimal);
  253. newChar.transform.forward = startingBlock.SpawnDirection.ToVector();
  254. playerData.Add(client.ID, new PlayerData(newChar, client));
  255. newChar.ClientLink = client;
  256. client.playerCharacter = newChar;
  257. }
  258. }
  259. private IEnumerator EnvironmentTurn()
  260. {
  261. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  262. foreach (ActiveBlock block in InitiativeGroup)
  263. StartCoroutine(block.OnEnvironmentTurn(playerDataAsArray));
  264. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  265. InitiativeGroup.ForEach(p => p.Reset());
  266. }
  267. }
  268. private IEnumerator EnvironmentEnd()
  269. {
  270. foreach (var InitiativeGroup in EnvironmentBlocks.GroupBy(p => p.GetInitative())){
  271. foreach (ActiveBlock block in InitiativeGroup)
  272. StartCoroutine(block.OnRoundEnd(playerDataAsArray));
  273. yield return new WaitUntil(() => InitiativeGroup.All(p => p.isFinished));
  274. InitiativeGroup.ForEach(p => p.Reset());
  275. }
  276. }
  277. private ActiveBlock[] GetActiveBlocksOf(int intiative)
  278. {
  279. return EnvironmentBlocks.Where(p => p.GetInitative() == intiative).ToArray();
  280. }
  281. #endregion Class Functions
  282. #region Networking Functions
  283. /// <summary>
  284. /// Registers functions which should deal with incoming messages from clients
  285. /// </summary>
  286. private void RegisterHandlers()
  287. {
  288. server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList);
  289. }
  290. /// <summary>
  291. /// Clears any functions from server register which the manager would deal with
  292. /// </summary>
  293. private void UnRegisterHandlers()
  294. {
  295. server.UnregisterHandler(LogicProtocols.SendLogicList);
  296. }
  297. /// <summary>
  298. /// Called when server recieves moves from client
  299. /// </summary>
  300. /// <param name="msg">messages passed by server</param>
  301. private void RecieveLogicList(NetworkMessage msg)
  302. {
  303. //try to read base message as a logic message
  304. LogicProtocols.LogicMsg logicMsg;
  305. if (!msg.TryRead(out logicMsg))
  306. return;
  307. ////Debug that we have recieved it
  308. ////Debug.Log("Recieved function from " + ClientList[msg.conn.connectionId].Name);
  309. //Update player Data with recieved list
  310. playerData[msg.conn.Hash()].blockReader.LogicChain = new List<LogicBlock>(logicMsg.elements);
  311. playerData[msg.conn.Hash()].recievedList = true;
  312. }
  313. #endregion Networking Functions
  314. }
  315. public class PlayerData
  316. {
  317. public Character character;
  318. public BlockReader blockReader;
  319. public ClientData client;
  320. public bool recievedList;
  321. public bool isDead = false;
  322. public PlayerData(Character character, ClientData client)
  323. {
  324. this.character = character;
  325. this.client = client;
  326. blockReader = new BlockReader();
  327. }
  328. }