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.

286 lines
9.1 KiB

  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 List<ActiveBlock> activeBlocks;
  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. //Find all active blocks
  44. //#TODO don't use the find function
  45. activeBlocks = FindObjectsOfType<ActiveBlock>().ToList();
  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. //Spawn Characters and tell let the GameMode do anything with the characters it might want
  71. SpawnCharacters();
  72. gameMode.GameStart(playerDataAsArray);
  73. //Loop until the GameMode lets us know the game is over
  74. while (!gameMode.isGameOver(playerDataAsArray))
  75. {
  76. //wait until we have recieved all player input
  77. yield return StartCoroutine(WaitForPlayerInput());
  78. //Routine for players movement
  79. yield return StartCoroutine(RoundRoutine()); //it's pretty long so it gets it's own coroutine;
  80. }
  81. //Let the gamemode know that the game is over
  82. gameMode.GameEnd(playerDataAsArray);
  83. }
  84. private IEnumerator RoundRoutine()
  85. {
  86. //Tell the gamemode that we are starting a round
  87. gameMode.RoundStart(playerDataAsArray);
  88. //Loop until all players have finished moving
  89. while (playerDataAsArray.Any(p => !p.blockReader.Finished))
  90. {
  91. //Loop through all players
  92. foreach (PlayerData player in playerDataAsArray)
  93. {
  94. yield return StartCoroutine(MoveRoutine(player));//Move Player
  95. gameMode.PlayerMoved(player);//LetGameModeKnow
  96. }
  97. //Let Gamemode know all players have moved
  98. gameMode.AllPlayersMoved(playerDataAsArray.ToArray());
  99. //Tell each environment block to take a move
  100. activeBlocks.ForEach(p => p.OnEnvironmentTurn(playerDataAsArray));
  101. gameMode.EnvironmentTurn(playerDataAsArray);
  102. playerDataAsArray.ForEach(p => p.client.SendScore()); //Update the players score
  103. //if Game is over break out of loop
  104. if (gameMode.isGameOver(playerDataAsArray))
  105. break;
  106. }
  107. //Let GameMode know that Round is Over
  108. gameMode.RoundEnd(playerDataAsArray.ToArray());
  109. //Reset some player Data
  110. foreach (PlayerData player in playerDataAsArray)
  111. {
  112. player.blockReader.Reset();
  113. player.client.SendInventory();
  114. }
  115. }
  116. private IEnumerator WaitForPlayerInput()
  117. {
  118. //send round length to players
  119. //#TODO make this only happen after first input
  120. LogicProtocols.FloatMsg RoundTime = new LogicProtocols.FloatMsg(gameMode.GetRoundTime());
  121. playerDataAsArray.ForEach(p => p.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime));
  122. //Send players to input Scene
  123. ClientList.ForEach(p => p.ChangeScene("ClientScene"));
  124. //Let gamemode know clients are input-ing
  125. gameMode.InputStart(playerDataAsArray);
  126. //wait for all players to
  127. yield return new WaitUntil(() => playerData.All(p => p.Value.recievedList));
  128. //reset
  129. playerDataAsArray.ForEach(p => p.recievedList = false); //reset all players list
  130. //Let gamemode know all inputs have been recieved
  131. gameMode.InputEnd(playerDataAsArray);
  132. }
  133. private IEnumerator MoveRoutine(PlayerData data)
  134. {
  135. bool blockFinished = false;
  136. float waitTime;
  137. //Loop until the current block indicates or the reader indicates it has finished
  138. while (!blockFinished && !data.blockReader.Finished)
  139. {
  140. //If the current block hasn't already been removed, remove it from the player inventory
  141. //We need to check if it has already been removed so loops don't eat an entire stack
  142. if (data.blockReader.CurrentBlock != null && !data.blockReader.CurrentBlock.hasBeenRemoved)
  143. {
  144. data.client.Inventory.Remove(data.blockReader.CurrentBlock);
  145. data.blockReader.CurrentBlock.hasBeenRemoved = true;
  146. }
  147. //Process the move
  148. blockFinished = data.blockReader.Read(data.character, AnimationTime, out waitTime);
  149. //Wait for the animation to finish
  150. yield return new WaitForSeconds(waitTime);
  151. }
  152. }
  153. private void SpawnCharacters()
  154. {
  155. playerData = new Dictionary<int, PlayerData>();
  156. Block[] SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isSpawnable).ToArray();
  157. int blockIndex = 0;
  158. foreach (Block block in SpawnBlocks)
  159. {
  160. Debug.Log("Block #" + blockIndex++ + " (" + block.transform.position.x + ", " + block.transform.position.y + ", " + block.transform.position.z + ")");
  161. }
  162. //int spawnIndex = 0;
  163. //If we have an odd number of players, then we start at spawn point 0 (in the middle)
  164. //If we have an even number, then we skip it
  165. int spawnIndex = ((ClientList.Count() + 1) % 2);
  166. //int spawnIndex = 0;
  167. foreach (ClientData client in ClientList)
  168. {
  169. //Debug.Log("spawnIndex = " + spawnIndex);
  170. Character newChar = Instantiate(characterPrefab);
  171. //Block startingBlock = SpawnBlocks[(spawnIndex++ % ClientList.ConnectedClients.Count)];
  172. Block startingBlock = SpawnBlocks[spawnIndex++];
  173. newChar.Initialise(startingBlock, client.Inventory, client.characterAnimal);
  174. newChar.transform.forward = startingBlock.SpawnDirection.ToVector();
  175. playerData.Add(client.ID, new PlayerData(newChar, client));
  176. newChar.ClientLink = client;
  177. client.playerCharacter = newChar;
  178. }
  179. }
  180. #endregion Class Functions
  181. #region Networking Functions
  182. /// <summary>
  183. /// Registers functions which should deal with incoming messages from clients
  184. /// </summary>
  185. private void RegisterHandlers()
  186. {
  187. server.server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList);
  188. }
  189. /// <summary>
  190. /// Clears any functions from server register which the manager would deal with
  191. /// </summary>
  192. private void UnRegisterHandlers()
  193. {
  194. server.server.UnregisterHandler(LogicProtocols.SendLogicList);
  195. }
  196. /// <summary>
  197. /// Called when server recieves moves from client
  198. /// </summary>
  199. /// <param name="msg">messages passed by server</param>
  200. private void RecieveLogicList(NetworkMessage msg)
  201. {
  202. //try to read base message as a logic message
  203. LogicProtocols.LogicMsg logicMsg;
  204. if (!msg.TryRead(out logicMsg))
  205. return;
  206. //Debug that we have recieved it
  207. Debug.Log("Recieved function from " + ClientList[msg.conn.connectionId].Name);
  208. //Update player Data with recieved list
  209. playerData[msg.conn.connectionId].blockReader.LogicChain = new List<LogicBlock>(logicMsg.elements);
  210. playerData[msg.conn.connectionId].recievedList = true;
  211. }
  212. #endregion Networking Functions
  213. }
  214. public class PlayerData
  215. {
  216. public Character character;
  217. public BlockReader blockReader;
  218. public ClientData client;
  219. public bool recievedList;
  220. public PlayerData(Character character, ClientData client)
  221. {
  222. this.character = character;
  223. this.client = client;
  224. blockReader = new BlockReader();
  225. }
  226. }