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.

258 lines
8.7 KiB

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. namespace Networking.Server
  7. {
  8. [CreateAssetMenu(menuName = "Major Project/Networking/ClientList", order = 150)]
  9. public class ClientList : ScriptableObject, IEnumerable<ClientData>
  10. {
  11. #if UNITY_EDITOR
  12. [SerializeField]
  13. [Multiline]
  14. private string DevNotes;
  15. #endif
  16. [SerializeField]
  17. private Inventory StartInventory;
  18. #region Public Variables
  19. /// <summary>
  20. /// All Clients which are Currently Connected;
  21. /// </summary>
  22. public List<ClientData> ConnectedClients;
  23. /// <summary>
  24. /// Clients which connected at one point but no longer are
  25. /// Usefull if a client needs to reconnect
  26. /// </summary>
  27. public List<ClientData> DisconnectedClients;
  28. private List<NetworkConnection> PotentialClients = new List<NetworkConnection>();
  29. /// <summary>
  30. /// Called when a client connects or disconnet
  31. /// </summary>
  32. public System.Action<List<ClientData>> OnClientsChange;
  33. #endregion Public Variables
  34. #region Private Variables
  35. public ServerObject server;
  36. #endregion Private Variables
  37. /// <summary>
  38. /// Clears the lists
  39. /// </summary>
  40. public void Reset()
  41. {
  42. ConnectedClients = new List<ClientData>();
  43. DisconnectedClients = new List<ClientData>();
  44. PotentialClients = new List<NetworkConnection>();
  45. }
  46. /// <summary>
  47. /// Resets the client list + registers handlers with the server
  48. /// </summary>
  49. /// <param name="serverObject">Server to register handlers with</param>
  50. public void SetUp(ServerObject serverObject)
  51. {
  52. this.server = serverObject;
  53. Reset();
  54. server.RegisterHandler(MsgType.Connect, OnClientConnect);
  55. server.RegisterHandler(MsgType.Disconnect, OnClientDisconnect);
  56. server.RegisterHandler(LoginProtocols.SendingLoginDetails, OnClientLogin);
  57. }
  58. public void OnClientConnect(NetworkMessage msg)
  59. {
  60. //Debug.Log("newClient: " + msg.conn.address + ", " + msg.conn.Hash() + ", " + msg.conn.hostId);
  61. if (ConnectedClients.Any(p => p.ID == msg.channelId))
  62. {
  63. Debug.LogError("Client[" + msg.channelId + "] already connected");
  64. msg.conn.Send(LoginProtocols.LoginFail, new LoginProtocols.EmptyMsg());
  65. return;
  66. }
  67. if (!PotentialClients.Contains(msg.conn))
  68. PotentialClients.Add(msg.conn);
  69. msg.conn.Send(LoginProtocols.RequestLoginDetails, new LoginProtocols.EmptyMsg());
  70. ConnectedClients.ForEach(p => msg.conn.Send(LoginProtocols.OtherClientConnected, new LoginProtocols.LoginMsg(p.Name, p.Color, p.characterAnimal)));
  71. }
  72. public void OnClientDisconnect(NetworkMessage msg)
  73. {
  74. PotentialClients.RemoveAll(p => p == msg.conn);
  75. if (!ConnectedClients.Any(p => p.ID == msg.conn.Hash()))
  76. {
  77. Debug.LogError("Unknown client disconnect [" + msg.conn.Hash() + "]");
  78. return;
  79. }
  80. ClientData client = ConnectedClients.FirstOrDefault(p => p.ID == msg.conn.Hash());
  81. client.Lives = 0;
  82. if (client.playerCharacter != null)
  83. {
  84. client.playerCharacter.lives = 0;
  85. }
  86. ConnectedClients.Remove(client);
  87. DisconnectedClients.Add(client);
  88. ConnectedClients.ForEach(p => p.conn.Send(LoginProtocols.OtherClientDisconnected, new LoginProtocols.LoginMsg(client.Name, client.Color, client.characterAnimal)));
  89. PotentialClients.ForEach(p => p.Send(LoginProtocols.OtherClientDisconnected, new LoginProtocols.LoginMsg(client.Name, client.Color, client.characterAnimal)));
  90. Debug.Log("Disconnected: " + client.Name);
  91. //somewhere here we need to remove the disconnected client from the client list and update such things
  92. OnClientsChange?.Invoke(ConnectedClients);
  93. }
  94. public void OnClientLogin(NetworkMessage msg)
  95. {
  96. LoginProtocols.LoginMsg loginMsg;
  97. if (!msg.TryRead(out loginMsg))
  98. {
  99. msg.conn.Send(LoginProtocols.LoginFail, new LoginProtocols.EmptyMsg());
  100. return;
  101. }
  102. if (ConnectedClients.Any(p => p.ID == msg.conn.Hash()))
  103. {
  104. Debug.LogError("Client[" + msg.channelId + "] already connected");
  105. msg.conn.Send(LoginProtocols.LoginFail, new LoginProtocols.EmptyMsg());
  106. return;
  107. }
  108. ClientData newClient = DisconnectedClients.FirstOrDefault(p => p.ID == msg.conn.Hash());
  109. if (newClient != default)
  110. {
  111. Debug.Log("Reconnection: " + loginMsg.Name + ((loginMsg.Name != newClient.Name) ? (" (Prev. " + newClient.Name +")") : ""));
  112. DisconnectedClients.Remove(newClient);
  113. }
  114. else
  115. {
  116. //Debug.Log("new Connection: " + loginMsg.Name);
  117. newClient = new ClientData();
  118. newClient.Inventory = Inventory.Clone(StartInventory);
  119. }
  120. newClient.Color = loginMsg.Color;
  121. newClient.characterAnimal = loginMsg.Animal;
  122. newClient.Name = loginMsg.Name;
  123. newClient.conn = msg.conn;
  124. ConnectedClients.Add(newClient);
  125. ConnectedClients.ForEach(p => p.conn.Send(LoginProtocols.OtherClientConnected, new LoginProtocols.LoginMsg(newClient.Name, newClient.Color, newClient.characterAnimal)));
  126. PotentialClients.RemoveAll(p => p == newClient.conn);
  127. PotentialClients.ForEach(p => p.Send(LoginProtocols.OtherClientConnected, new LoginProtocols.LoginMsg(newClient.Name, newClient.Color, newClient.characterAnimal)));
  128. newClient.conn.Send(LoginProtocols.LoginSuccess, new LoginProtocols.LoginMsg(newClient.Name, newClient.Color, newClient.characterAnimal));
  129. OnClientsChange.Invoke(ConnectedClients);
  130. newClient.SendInventory();
  131. newClient.SendLives();
  132. newClient.ChangeScene("LobbyWait");
  133. }
  134. #region IEnumerable Implementation
  135. public IEnumerator<ClientData> GetEnumerator()
  136. {
  137. return ((IEnumerable<ClientData>)ConnectedClients).GetEnumerator();
  138. }
  139. IEnumerator IEnumerable.GetEnumerator()
  140. {
  141. return ((IEnumerable<ClientData>)ConnectedClients).GetEnumerator();
  142. }
  143. #endregion IEnumerable Implementation
  144. /// <summary>
  145. /// Returns client with id
  146. /// </summary>
  147. /// <param name="id">id to find client with</param>
  148. /// <returns>client with provided id else null</returns>
  149. public ClientData this[int id] {
  150. get {
  151. return ConnectedClients.FirstOrDefault(p => p.ID == id);
  152. }
  153. }
  154. }
  155. [System.Serializable]
  156. public class ClientData
  157. {
  158. /// <summary>
  159. /// Client Name
  160. /// </summary>
  161. public string Name;
  162. /// <summary>
  163. /// Color which represents player, picked by player
  164. /// </summary>
  165. public Color Color;
  166. /// <summary>
  167. /// Clients Current Score
  168. /// </summary>
  169. public int Score;
  170. /// <summary>
  171. /// Clients Current Lives
  172. /// </summary>
  173. public int Lives = 3;
  174. /// <summary>
  175. /// Clients character animal - needed for instantiation
  176. /// </summary>
  177. public string characterAnimal = "Bear";
  178. /// <summary>
  179. /// Network connection ID
  180. /// </summary>
  181. public int ID { get { return (conn != null) ? conn.Hash() : -1; }}
  182. /// <summary>
  183. /// Connection to Client
  184. /// </summary>
  185. public NetworkConnection conn;
  186. /// <summary>
  187. /// Current Logic elements held by player
  188. /// </summary>
  189. public Inventory Inventory;
  190. public Character playerCharacter;
  191. public void SendInventory()
  192. {
  193. //Debug.Log("Sending inventory");
  194. conn.SendByChannel(LogicProtocols.SendInventory, new LogicProtocols.InventoryMsg(Inventory), TransportConfigure.ReliableFragmented);
  195. }
  196. public void SendLives()
  197. {
  198. conn.Send(LogicProtocols.SendLives, new LogicProtocols.FloatMsg(Lives));
  199. }
  200. public void ChangeScene(string scene, bool Additive = false)
  201. {
  202. conn.Send(LoginProtocols.SceneChange, new LoginProtocols.SceneMsg(scene,Additive));
  203. }
  204. }
  205. }