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.

290 lines
8.9 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. #endregion Private Variables
  29. #region Read Only
  30. /// <summary>
  31. /// Easy access to IEnumerable in playerData so we can Enumerate through it
  32. /// </summary>
  33. private PlayerData[] playerDataAsArray { get { return playerData.Values.ToArray(); } }
  34. /// <summary>
  35. /// Easy access to GameMode value in CurrentGameMode reference
  36. /// </summary>
  37. private GameMode gameMode {get { return CurrentGameMode.Value; } }
  38. #endregion Read Only
  39. public GameObject levelInfo;
  40. public blockSpawn bspawn;
  41. #region Unity Functions
  42. public void Awake()
  43. {
  44. RegisterHandlers();
  45. SpawnCharacters();
  46. ClientList.ForEach(p => p.ChangeScene("ClientScene"));
  47. }
  48. private void Start()
  49. {
  50. StartCoroutine(displayforSeconds(levelInfo, 5.0f));
  51. gameMode.GameStart(playerDataAsArray.ToArray());
  52. StartRound();
  53. }
  54. private void Update()
  55. {
  56. //This is required so that the server can continue to recieve client messages
  57. //(it is a unity thing)
  58. server.ServerUpdate();
  59. }
  60. private void OnDisable()
  61. {
  62. //Let server know to not send messages this way
  63. UnRegisterHandlers();
  64. }
  65. #endregion Unity 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. IEnumerator displayforSeconds(GameObject display, float time)
  85. {
  86. display.SetActive (true);
  87. yield return new WaitForSeconds(time);
  88. display.SetActive (false);
  89. }
  90. private IEnumerator WaitForPlayerInput()
  91. {
  92. LogicProtocols.FloatMsg RoundTime = new LogicProtocols.FloatMsg(gameMode.GetRoundTime());
  93. playerDataAsArray.ForEach(p => p.client.conn.Send(LogicProtocols.SendRoundTime, RoundTime));
  94. ClientList.ForEach(p => p.ChangeScene("ClientScene"));
  95. gameMode.InputStart(playerDataAsArray);
  96. yield return new WaitUntil(() => playerData.All(p => p.Value.recievedList));
  97. //reset
  98. playerDataAsArray.ForEach(p => p.recievedList = false); //reset all players list
  99. gameMode.InputEnd(playerDataAsArray);
  100. }
  101. private IEnumerator RoundRoutine()
  102. {
  103. //Tell the gamemode that we are starting a round
  104. gameMode.RoundStart(playerDataAsArray);
  105. //Loop until all players have finished moving
  106. while (playerDataAsArray.Any(p => !p.blockReader.Finished))
  107. {
  108. //Loop through all players
  109. foreach (PlayerData player in playerDataAsArray)
  110. {
  111. yield return StartCoroutine(MoveRoutine(player));//Move Player
  112. gameMode.PlayerMoved(player);//LetGameModeKnow
  113. }
  114. //Let Gamemode know all players have moved
  115. gameMode.AllPlayersMoved(playerDataAsArray.ToArray());
  116. playerDataAsArray.ForEach(p => p.client.SendScore()); //Update the players score
  117. //if Game is over break out of loop
  118. if (gameMode.isGameOver(playerDataAsArray))
  119. break;
  120. }
  121. //Let GameMode know that Round is Over
  122. gameMode.RoundEnd(playerDataAsArray.ToArray());
  123. //Reset some player Data
  124. foreach (PlayerData player in playerDataAsArray)
  125. {
  126. player.blockReader.Reset();
  127. player.client.SendInventory();
  128. }
  129. }
  130. private void SpawnCharacters()
  131. {
  132. playerData = new Dictionary<int, PlayerData>();
  133. Block[] SpawnBlocks = FindObjectsOfType<Block>().Where(p => p.isSpawnable).ToArray();
  134. int blockIndex = 0;
  135. foreach (Block block in SpawnBlocks)
  136. {
  137. Debug.Log("Block #" + blockIndex++ + " (" + block.transform.position.x + ", " + block.transform.position.y + ", " + block.transform.position.z + ")");
  138. }
  139. //int spawnIndex = 0;
  140. //If we have an odd number of players, then we start at spawn point 0 (in the middle)
  141. //If we have an even number, then we skip it
  142. int spawnIndex = ((ClientList.Count() + 1) % 2);
  143. //int spawnIndex = 0;
  144. foreach (ClientData client in ClientList)
  145. {
  146. //Debug.Log("spawnIndex = " + spawnIndex);
  147. Character newChar = Instantiate(characterPrefab);
  148. //Block startingBlock = SpawnBlocks[(spawnIndex++ % ClientList.ConnectedClients.Count)];
  149. Block startingBlock = SpawnBlocks[spawnIndex++];
  150. newChar.Initialise(startingBlock, client.Inventory, client.characterAnimal);
  151. newChar.transform.forward = startingBlock.SpawnDirection.ToVector();
  152. playerData.Add(client.ID, new PlayerData(newChar,client));
  153. newChar.ClientLink = client;
  154. client.playerCharacter = newChar;
  155. }
  156. }
  157. #region Networking Functions
  158. /// <summary>
  159. /// Registers functions which should deal with incoming messages from clients
  160. /// </summary>
  161. private void RegisterHandlers()
  162. {
  163. server.server.RegisterHandler(LogicProtocols.SendLogicList, RecieveLogicList);
  164. }
  165. /// <summary>
  166. /// Clears any functions from server register which the manager would deal with
  167. /// </summary>
  168. private void UnRegisterHandlers()
  169. {
  170. server.server.UnregisterHandler(LogicProtocols.SendLogicList);
  171. }
  172. /// <summary>
  173. /// Called when server recieves moves from client
  174. /// </summary>
  175. /// <param name="msg">messages passed by server</param>
  176. private void RecieveLogicList(NetworkMessage msg)
  177. {
  178. //try to read base message as a logic message
  179. LogicProtocols.LogicMsg logicMsg;
  180. if (!msg.TryRead(out logicMsg))
  181. return;
  182. //Debug that we have recieved it
  183. Debug.Log("Recieved function from " + ClientList[msg.conn.connectionId].Name);
  184. //Update player Data with recieved list
  185. playerData[msg.conn.connectionId].blockReader.LogicChain = new List<LogicBlock>(logicMsg.elements);
  186. playerData[msg.conn.connectionId].recievedList = true;
  187. //if we have recieved all moves start round
  188. if (playerData.All(p => p.Value.recievedList))
  189. DoRoundRoutine();
  190. }
  191. #endregion Networking Functions
  192. private IEnumerator MoveRoutine(PlayerData data)
  193. {
  194. bool blockFinished = false;
  195. float waitTime;
  196. //Loop until the current block indicates or the reader indicates it has finished
  197. while (!blockFinished && !data.blockReader.Finished)
  198. {
  199. //If the current block hasn't already been removed, remove it from the player inventory
  200. //We need to check if it has already been removed so loops don't eat an entire stack
  201. if (data.blockReader.CurrentBlock != null && !data.blockReader.CurrentBlock.hasBeenRemoved)
  202. {
  203. data.client.Inventory.Remove(data.blockReader.CurrentBlock);
  204. data.blockReader.CurrentBlock.hasBeenRemoved = true;
  205. }
  206. //Process the move
  207. blockFinished = data.blockReader.Read(data.character, AnimationTime,out waitTime);
  208. //Wait for the animation to finish
  209. yield return new WaitForSeconds(waitTime);
  210. }
  211. }
  212. }
  213. public class PlayerData
  214. {
  215. public Character character;
  216. public BlockReader blockReader;
  217. public ClientData client;
  218. public bool recievedList;
  219. public PlayerData(Character character, ClientData client)
  220. {
  221. this.character = character;
  222. this.client = client;
  223. blockReader = new BlockReader();
  224. }
  225. }