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.

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