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.

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